Move master branch from from mios git repo
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
The Sensor Net Arduino library adds a new layer on top of the RF24 library.
|
||||
It handles radio network routing, relaying and ids.
|
||||
|
||||
Created by Henrik Ekblad <henrik.ekblad@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "Gateway.h"
|
||||
|
||||
Gateway::Gateway(uint8_t _cepin, uint8_t _cspin, uint8_t _inclusion_time) : Relay(_cepin, _cspin) {
|
||||
ledMode = false;
|
||||
inclusionTime = _inclusion_time;
|
||||
}
|
||||
|
||||
Gateway::Gateway(uint8_t _cepin, uint8_t _cspin, uint8_t _inclusion, uint8_t _inclusion_time, uint8_t _rx, uint8_t _tx, uint8_t _er) : Relay(_cepin, _cspin) {
|
||||
ledMode = true;
|
||||
pinInclusion = _inclusion;
|
||||
inclusionTime = _inclusion_time;
|
||||
pinRx = _rx;
|
||||
pinTx = _tx;
|
||||
pinEr = _er;
|
||||
}
|
||||
|
||||
|
||||
void Gateway::begin(uint8_t _radioId) {
|
||||
radioId = 0;
|
||||
distance = 0;
|
||||
inclusionMode = 0;
|
||||
buttonTriggeredInclusion = false;
|
||||
countRx = 0;
|
||||
countTx = 0;
|
||||
countErr = 0;
|
||||
|
||||
if (ledMode) {
|
||||
// Setup led pins
|
||||
pinMode(pinRx, OUTPUT);
|
||||
pinMode(pinTx, OUTPUT);
|
||||
pinMode(pinEr, OUTPUT);
|
||||
digitalWrite(pinRx, LOW);
|
||||
digitalWrite(pinTx, LOW);
|
||||
digitalWrite(pinEr, LOW);
|
||||
|
||||
// Setup digital in that triggers inclusion mode
|
||||
pinMode(pinInclusion, INPUT);
|
||||
digitalWrite(pinInclusion, HIGH);
|
||||
|
||||
// Set initial state of leds
|
||||
digitalWrite(pinRx, HIGH);
|
||||
digitalWrite(pinTx, HIGH);
|
||||
digitalWrite(pinEr, HIGH);
|
||||
|
||||
}
|
||||
|
||||
// Set baudrate of serial link
|
||||
Serial.begin(BAUD_RATE);
|
||||
|
||||
// Start up the radio library
|
||||
setupRadio();
|
||||
RF24::openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID);
|
||||
RF24::startListening();
|
||||
|
||||
// Send startup log message on serial
|
||||
serial(PSTR("0;0;%d;%d;Arduino startup complete.\n"), M_INTERNAL, I_LOG_MESSAGE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
boolean Gateway::isLedMode() {
|
||||
return ledMode;
|
||||
}
|
||||
|
||||
void Gateway::startInclusionInterrupt() {
|
||||
buttonTriggeredInclusion = true;
|
||||
}
|
||||
|
||||
|
||||
void Gateway::checkButtonTriggeredInclusion() {
|
||||
if (buttonTriggeredInclusion) {
|
||||
// Ok, someone pressed the inclusion button on the gateway
|
||||
// start inclusion mode for 1 munute.
|
||||
serial(PSTR("0;0;%d;%d;Inclusion started by button.\n"), M_INTERNAL, I_LOG_MESSAGE);
|
||||
buttonTriggeredInclusion = false;
|
||||
setInclusionMode(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Gateway::checkInclusionFinished() {
|
||||
if (inclusionMode && millis()-inclusionStartTime>60000L*inclusionTime) {
|
||||
// inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode
|
||||
setInclusionMode(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Gateway::parseAndSend(String inputString) {
|
||||
boolean ok;
|
||||
char *str, *p, *value;
|
||||
int i = 0;
|
||||
uint16_t sensorRadioId;
|
||||
uint8_t childId;
|
||||
uint8_t messageType;
|
||||
uint8_t type;
|
||||
// Copy command to char* buffer
|
||||
inputString.toCharArray(commandBuffer, MAX_RECEIVE_LENGTH);
|
||||
|
||||
// Extract command data coming on serial line
|
||||
for (str = strtok_r(commandBuffer, ";", &p); // split using semicolon
|
||||
str && i < 5; // loop while str is not null an max 5 times
|
||||
str = strtok_r(NULL, ";", &p) // get subsequent tokens
|
||||
) {
|
||||
switch (i) {
|
||||
case 0: // Radioid (destination)
|
||||
sensorRadioId = atoi(str);
|
||||
break;
|
||||
case 1: // Childid
|
||||
childId = atoi(str);
|
||||
break;
|
||||
case 2: // Message type
|
||||
messageType = atoi(str);
|
||||
break;
|
||||
case 3: // Data type
|
||||
type = atoi(str);
|
||||
break;
|
||||
case 4: // Variable value
|
||||
value = str;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (sensorRadioId==GATEWAY_ADDRESS && messageType==M_INTERNAL) {
|
||||
// Handle messages directed to gateway
|
||||
if (type == I_VERSION) {
|
||||
// Request for version
|
||||
serial(PSTR("0;0;%d;%d;%s\n"),M_INTERNAL, I_VERSION, LIBRARY_VERSION);
|
||||
} else if (type == I_INCLUSION_MODE) {
|
||||
// Request to change inclusion mode
|
||||
setInclusionMode(atoi(value) == 1);
|
||||
}
|
||||
} else {
|
||||
txBlink(1);
|
||||
ok = sendData(GATEWAY_ADDRESS, sensorRadioId, childId, messageType, type, value, strlen(value), false);
|
||||
if (!ok) {
|
||||
errBlink(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Gateway::setInclusionMode(boolean newMode) {
|
||||
if (newMode != inclusionMode)
|
||||
inclusionMode = newMode;
|
||||
// Send back mode change on serial line to ack command
|
||||
serial(PSTR("0;0;%d;%d;%d\n"), M_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0);
|
||||
|
||||
if (inclusionMode) {
|
||||
inclusionStartTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Override normal validate to add error blink if crc check fails
|
||||
uint8_t Gateway::validate() {
|
||||
uint8_t res = Sensor::validate();
|
||||
if (res == VALIDATE_BAD_CRC) {
|
||||
errBlink(1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void Gateway::processRadioMessage() {
|
||||
if (messageAvailable()) {
|
||||
// A new message was received from one of the sensors
|
||||
message_s msg = getMessage();
|
||||
if (msg.header.messageType == M_PRESENTATION && inclusionMode) {
|
||||
rxBlink(3);
|
||||
} else {
|
||||
rxBlink(1);
|
||||
}
|
||||
// Pass along the message from sensors to serial line
|
||||
serial(msg);
|
||||
}
|
||||
|
||||
checkButtonTriggeredInclusion();
|
||||
checkInclusionFinished();
|
||||
}
|
||||
|
||||
void Gateway::serial(const char *fmt, ... ) {
|
||||
va_list args;
|
||||
va_start (args, fmt );
|
||||
vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args);
|
||||
va_end (args);
|
||||
Serial.print(serialBuffer);
|
||||
}
|
||||
|
||||
void Gateway::serial(message_s msg) {
|
||||
serial(PSTR("%d;%d;%d;%d;%s\n"),msg.header.from, msg.header.childId, msg.header.messageType, msg.header.type, msg.data);
|
||||
}
|
||||
|
||||
|
||||
void Gateway::ledTimersInterrupt() {
|
||||
if(countRx && countRx != 255) {
|
||||
// switch led on
|
||||
digitalWrite(pinRx, LOW);
|
||||
} else if(!countRx) {
|
||||
// switching off
|
||||
digitalWrite(pinRx, HIGH);
|
||||
}
|
||||
if(countRx != 255) { countRx--; }
|
||||
|
||||
if(countTx && countTx != 255) {
|
||||
// switch led on
|
||||
digitalWrite(pinTx, LOW);
|
||||
} else if(!countTx) {
|
||||
// switching off
|
||||
digitalWrite(pinTx, HIGH);
|
||||
}
|
||||
if(countTx != 255) { countTx--; }
|
||||
else if(inclusionMode) { countTx = 8; }
|
||||
|
||||
if(countErr && countErr != 255) {
|
||||
// switch led on
|
||||
digitalWrite(pinEr, LOW);
|
||||
} else if(!countErr) {
|
||||
// switching off
|
||||
digitalWrite(pinEr, HIGH);
|
||||
}
|
||||
if(countErr != 255) { countErr--; }
|
||||
|
||||
}
|
||||
|
||||
void Gateway::rxBlink(uint8_t cnt) {
|
||||
if(countRx == 255) { countRx = cnt; }
|
||||
}
|
||||
void Gateway::txBlink(uint8_t cnt) {
|
||||
if(countTx == 255 && !inclusionMode) { countTx = cnt; }
|
||||
}
|
||||
void Gateway::errBlink(uint8_t cnt) {
|
||||
if(countErr == 255) { countErr = cnt; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
The Sensor Net Arduino library adds a new layer on top of the RF24 library.
|
||||
It handles radio network routing, relaying and ids.
|
||||
|
||||
Created by Henrik Ekblad <henrik.ekblad@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef Gateway_h
|
||||
#define Gateway_h
|
||||
|
||||
#include "Relay.h"
|
||||
|
||||
|
||||
#define MAX_RECEIVE_LENGTH 50 // Max buffersize needed for messages coming from vera
|
||||
#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages coming from vera
|
||||
|
||||
|
||||
class Gateway : public Relay
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Creates a new instance of Gateway class.
|
||||
* If you don't use status leds and/or inclusion mode button on your arduino gateway
|
||||
* you can disable this functionality by calling the 2 argument constructor.
|
||||
*
|
||||
* @param _cepin The pin attached to RF24 Chip Enable on the RF module
|
||||
* @param _cspin The pin attached to RF24 Chip Select
|
||||
* @param _inclusion Digital pin that triggers inclusion mode
|
||||
* @param _inclusion_time Time of inclusion mode (in minutes)
|
||||
* @param _rx Digital pin for receive led
|
||||
* @param _tx Digital pin for transfer led
|
||||
* @param _er Digital pin for error led
|
||||
*
|
||||
*/
|
||||
Gateway(uint8_t _cepin, uint8_t _cspin, uint8_t _inclusion_time);
|
||||
Gateway(uint8_t _cepin, uint8_t _cspin, uint8_t _inclusion, uint8_t _inclusion_time, uint8_t _rx, uint8_t _tx, uint8_t _er);
|
||||
|
||||
void begin(uint8_t _radioId = 0);
|
||||
void processRadioMessage();
|
||||
void parseAndSend(String inputString);
|
||||
boolean isLedMode();
|
||||
void ledTimersInterrupt();
|
||||
void startInclusionInterrupt();
|
||||
|
||||
private:
|
||||
char commandBuffer[MAX_RECEIVE_LENGTH];
|
||||
char serialBuffer[MAX_SEND_LENGTH]; // Buffer for building string when sending data to vera
|
||||
unsigned long inclusionStartTime;
|
||||
boolean inclusionMode; // Keeps track on inclusion mode
|
||||
boolean buttonTriggeredInclusion;
|
||||
volatile uint8_t countRx;
|
||||
volatile uint8_t countTx;
|
||||
volatile uint8_t countErr;
|
||||
boolean ledMode;
|
||||
uint8_t pinInclusion;
|
||||
uint8_t inclusionTime;
|
||||
uint8_t pinRx;
|
||||
uint8_t pinTx;
|
||||
uint8_t pinEr;
|
||||
|
||||
uint8_t validate();
|
||||
void serial(message_s msg);
|
||||
void interruptStartInclusion();
|
||||
void checkButtonTriggeredInclusion();
|
||||
void setInclusionMode(boolean newMode);
|
||||
void serial(const char *fmt, ... );
|
||||
void checkInclusionFinished();
|
||||
void ledTimers();
|
||||
void rxBlink(uint8_t cnt);
|
||||
void txBlink(uint8_t cnt);
|
||||
void errBlink(uint8_t cnt);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
The Sensor Net Arduino library adds a new layer on top of the RF24 library.
|
||||
It handles radio network routing, relaying and ids.
|
||||
|
||||
Created by Henrik Ekblad <henrik.ekblad@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "Relay.h"
|
||||
|
||||
Relay::Relay(uint8_t _cepin, uint8_t _cspin) : Sensor(_cepin, _cspin) {
|
||||
isRelay = true;
|
||||
}
|
||||
|
||||
|
||||
void Relay::begin(uint8_t _radioId) {
|
||||
Sensor::begin(_radioId);
|
||||
|
||||
// Read routing table from EEPROM
|
||||
for (int i=0;i<sizeof(childNodeTable);i++) {
|
||||
childNodeTable[i] = EEPROM.read(EEPROM_ROUTES_ADDRESS+i);
|
||||
}
|
||||
|
||||
// Start listening for incoming messages
|
||||
RF24::startListening();
|
||||
}
|
||||
|
||||
|
||||
boolean Relay::send(message_s message, int length) {
|
||||
bool ok = true;
|
||||
uint8_t route = getChildRoute(msg.header.to);
|
||||
|
||||
if (route>0 && route<255 && message.header.to != GATEWAY_ADDRESS) {
|
||||
debug(PSTR("Routing message.\n"));
|
||||
// Message destination is not gateway and is in routing table for this node.
|
||||
// Send it downstream
|
||||
sendWrite(route, message, length);
|
||||
} else if (radioId != GATEWAY_ADDRESS) {
|
||||
debug(PSTR("Sending message back towards gw.\n"));
|
||||
// Should be routed back to gateway. Sensor code knows how to do this.
|
||||
ok = Sensor::send(message, length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
boolean Relay::messageAvailable() {
|
||||
uint8_t pipe;
|
||||
boolean available = RF24::available(&pipe);
|
||||
if (available) {
|
||||
uint8_t len = RF24::getDynamicPayloadSize()-sizeof(msg.header);
|
||||
readMessage();
|
||||
boolean ok = validate() == VALIDATE_OK;
|
||||
debug(PSTR("Message crc %s.\n"),ok?"ok":"error");
|
||||
if (ok) {
|
||||
if (msg.header.messageType == M_INTERNAL &&
|
||||
msg.header.type == I_PING) {
|
||||
// We always answer ping messages
|
||||
debug(PSTR("Answer ping message.\n"));
|
||||
// Wait a random delay of 0-2 seconds to minimize collision
|
||||
// between ping ack messages from other relaying nodes
|
||||
randomSeed(millis());
|
||||
delay(random(2000));
|
||||
ltoa(distance, convBuffer, 10);
|
||||
uint8_t to = msg.header.from;
|
||||
debug(PSTR("Answer ping message. %d\n"), strlen(convBuffer));
|
||||
buildMsg(radioId, to, NODE_CHILD_ID, M_INTERNAL, I_PING_ACK, convBuffer,strlen(convBuffer), false);
|
||||
sendWrite(to, msg, strlen(convBuffer));
|
||||
} else if (msg.header.to == radioId) {
|
||||
// This message is addressed to this node
|
||||
if (msg.header.messageType == M_INTERNAL) {
|
||||
// Handle all internal messages to this node
|
||||
if (msg.header.type == I_RELAY_NODE && msg.header.to != GATEWAY_ADDRESS) {
|
||||
// Someone at sensor net gateway side wants this node to refresh its relay node
|
||||
findRelay();
|
||||
// Send relay information back to sensor net gateway node device.
|
||||
sendInternal(I_RELAY_NODE, ltoa(relayId, convBuffer, 10));
|
||||
return false;
|
||||
} else if (msg.header.type == I_CHILDREN && msg.header.to != GATEWAY_ADDRESS) {
|
||||
debug(PSTR("Route command received"));
|
||||
if (strncmp(msg.data,"F", 1) == 0) {
|
||||
// Send in as many children we can fit in a message (binary)
|
||||
sendChildren();
|
||||
} else if (strncmp(msg.data,"C", 1) == 0) {
|
||||
// Clears child relay data for this node
|
||||
clearChildRoutes();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Return rest of internal messages back to sketch...
|
||||
return true;
|
||||
} else {
|
||||
// If this is variable message from sensor net gateway. Send ack back.
|
||||
debug(PSTR("Message addressed for this node.\n"));
|
||||
if (msg.header.from == GATEWAY_ADDRESS &&
|
||||
msg.header.messageType == M_SET_VARIABLE) {
|
||||
// Send back ack message to sensor net gateway
|
||||
sendVariableAck();
|
||||
}
|
||||
// Return message to waiting sketch...
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// We should probably try to relay this message
|
||||
relayMessage(len, pipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Relay::relayMessage(uint8_t length, uint8_t pipe) {
|
||||
uint8_t route = getChildRoute(msg.header.to);
|
||||
if (route>0 && route<255) {
|
||||
debug(PSTR("Routing message to child node.\n"));
|
||||
// This message should be forwarded to a child node. If we send message
|
||||
// to this nodes pipe then all children will receive it because the are
|
||||
// all listening to this nodes pipe.
|
||||
//
|
||||
// +----B
|
||||
// -A
|
||||
// +----C------D
|
||||
//
|
||||
// We're node C, Message comes from A and has destination D
|
||||
//
|
||||
// lookup route in table and send message there
|
||||
sendWrite(route, msg, length);
|
||||
} else if (pipe == CURRENT_NODE_PIPE) {
|
||||
// A message comes from a child node and we have no
|
||||
// route for it.
|
||||
//
|
||||
// +----B
|
||||
// -A
|
||||
// +----C------D <-- Message comes from D
|
||||
//
|
||||
// We're node C
|
||||
//
|
||||
// Message should be passed to node A (this nodes relay)
|
||||
|
||||
debug(PSTR("Routing message to relay.\n"));
|
||||
// This message should be routed back towards sensor net gateway
|
||||
sendWrite(relayId, msg, length);
|
||||
// Add this child to our "routing table" if it not already exist
|
||||
addChildRoute(msg.header.from, msg.header.last);
|
||||
} else {
|
||||
// We're snooped a message directed to gateway from another branch
|
||||
// Make sure to remove the sender node from our routing table.
|
||||
//
|
||||
// +-----B <-- Message comes from here
|
||||
// -A
|
||||
// +-----C <-- We're here
|
||||
//
|
||||
// So the sender of message should never be in our
|
||||
// routing table.
|
||||
//
|
||||
// We could also end up in this else-statement if message
|
||||
// destination has no route.
|
||||
// This can happen if a node never has sent any message to
|
||||
// sensor net gateway (which will build up routing information in all nodes
|
||||
// that gets passed).
|
||||
if (radioId == GATEWAY_ADDRESS) {
|
||||
// We should perhaps inform gateway about the no-route situation?!
|
||||
debug(PSTR("Unknown route from GW\n"));
|
||||
|
||||
} else {
|
||||
debug(PSTR("Remove child node from routing table.\n"));
|
||||
removeChildRoute(msg.header.from);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Relay::addChildRoute(uint8_t childId, uint8_t route) {
|
||||
if (childNodeTable[childId] != route) {
|
||||
childNodeTable[childId] = route;
|
||||
EEPROM.write(EEPROM_ROUTES_ADDRESS+childId, route);
|
||||
}
|
||||
}
|
||||
|
||||
void Relay::removeChildRoute(uint8_t childId) {
|
||||
if (childNodeTable[childId] != 0xff) {
|
||||
childNodeTable[childId] = 0xff;
|
||||
EEPROM.write(EEPROM_ROUTES_ADDRESS+childId, 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Relay::getChildRoute(uint8_t childId) {
|
||||
return childNodeTable[childId];
|
||||
}
|
||||
|
||||
void Relay::clearChildRoutes() {
|
||||
debug(PSTR("Clear child routing data\n"));
|
||||
for (int i=0;i< sizeof(childNodeTable); i++) {
|
||||
removeChildRoute(i);
|
||||
}
|
||||
sendInternal(I_CHILDREN, "");
|
||||
}
|
||||
|
||||
void Relay::sendChildren() {
|
||||
// Send in which children that is using this node as an relay.
|
||||
debug(PSTR("Send child info to sensor gateway.\n"));
|
||||
sendInternal(I_CHILDREN, "not implemented");
|
||||
// TODO: Fix this
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
The Sensor Net Arduino library adds a new layer on top of the RF24 library.
|
||||
It handles radio network routing, relaying and ids.
|
||||
|
||||
Created by Henrik Ekblad <henrik.ekblad@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef Relay_h
|
||||
#define Relay_h
|
||||
|
||||
#include "Sensor.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug(x,...) debugPrint(x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define debug(x,...)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define EEPROM_ROUTES_ADDRESS ((uint8_t)3) // Where to start storing routing information in EEPROM. Will allocate 256 bytes.
|
||||
|
||||
|
||||
class Relay : public Sensor
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Creates a new instance of Relay class.
|
||||
*
|
||||
* @param _cepin The pin attached to RF24 Chip Enable on the RF module
|
||||
* @param _cspin The pin attached to RF24 Chip Select
|
||||
*/
|
||||
Relay(uint8_t _cepin, uint8_t _cspin);
|
||||
|
||||
void begin(uint8_t _radioId);
|
||||
boolean messageAvailable();
|
||||
boolean send(message_s message, int length);
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
uint8_t childNodeTable[256]; // Buffer to store child node information. Store this in EEPROM
|
||||
|
||||
uint8_t getChildRoute(uint8_t childId);
|
||||
void addChildRoute(uint8_t childId, uint8_t route);
|
||||
void removeChildRoute(uint8_t childId);
|
||||
void clearChildRoutes();
|
||||
void sendChildren();
|
||||
void relayMessage(uint8_t length, uint8_t pipe);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
The Sensor Net Arduino library adds a new layer on top of the RF24 library.
|
||||
It handles radio network routing, relaying and ids.
|
||||
|
||||
Created by Henrik Ekblad <henrik.ekblad@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "Sensor.h"
|
||||
|
||||
|
||||
Sensor::Sensor(uint8_t _cepin, uint8_t _cspin) : RF24(_cepin, _cspin) {
|
||||
isRelay = false;
|
||||
}
|
||||
|
||||
|
||||
void Sensor::setupRadio() {
|
||||
failedTransmissions = 0;
|
||||
|
||||
// Start up the radio library
|
||||
RF24::begin();
|
||||
RF24::enableDynamicPayloads();
|
||||
|
||||
RF24::setAutoAck(true);
|
||||
RF24::setRetries(15, 15);
|
||||
|
||||
//RF24::setChannel(70);
|
||||
RF24::setDataRate(RF24_1MBPS);
|
||||
RF24::setCRCLength(RF24_CRC_16);
|
||||
|
||||
// All (relaying) nodes listen to broadcast pipe (for PING messages)
|
||||
RF24::openReadingPipe(BROADCAST_PIPE, BASE_RADIO_ID + BROADCAST_ADDRESS);
|
||||
}
|
||||
|
||||
void Sensor::begin(uint8_t _radioId) {
|
||||
radioId = _radioId;
|
||||
|
||||
debug(PSTR("Started %s.\n"), isRelay?"relay":"sensor");
|
||||
|
||||
setupRadio();
|
||||
|
||||
// Fetch relay from EEPROM
|
||||
relayId = EEPROM.read(EEPROM_RELAY_ID_ADDRESS);
|
||||
// Fetch distance from eeprom
|
||||
distance = EEPROM.read(EEPROM_DISTANCE_ADDRESS);
|
||||
if (relayId == 0xff) {
|
||||
// No relay previously fetched and stored in eeprom. Try to find one.
|
||||
findRelay();
|
||||
}
|
||||
debug(PSTR("Relay=%d, distance=%d\n"), relayId, distance);
|
||||
|
||||
initializeRadioId();
|
||||
|
||||
// Open reading pipe for messages directed to this node
|
||||
RF24::openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID+radioId);
|
||||
|
||||
// Send presentation for this radio node
|
||||
sendSensorPresentation(NODE_CHILD_ID, isRelay? S_ARDUINO_RELAY : S_ARDUINO_NODE);
|
||||
|
||||
// Send relay information back to sensor net gateway.
|
||||
sendInternal(I_RELAY_NODE, itoa(relayId, convBuffer, 10));
|
||||
|
||||
// Initialize ack message header
|
||||
ack.header.version = PROTOCOL_VERSION;
|
||||
ack.header.binary = 0;
|
||||
ack.header.from = radioId;
|
||||
ack.header.to = GATEWAY_ADDRESS;
|
||||
ack.header.messageType = M_SET_VARIABLE;
|
||||
}
|
||||
|
||||
|
||||
uint8_t Sensor::getRadioId() {
|
||||
return radioId;
|
||||
}
|
||||
|
||||
void Sensor::initializeRadioId() {
|
||||
if (radioId == AUTO) {
|
||||
radioId = EEPROM.read(EEPROM_RADIO_ID_ADDRESS);
|
||||
if (radioId == 0xFF || radioId == 0) {
|
||||
radioId = AUTO;
|
||||
debug(PSTR("No radio id found in EEPROM fetching one from sensor net gateway\n"));
|
||||
// No radio id has been fetched yet ant EEPROM is unwritten.
|
||||
// Request new id from sensor net gateway. Use radioId 4095 temporarily
|
||||
// to be able to receive my correct nodeId.
|
||||
RF24::openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID+radioId);
|
||||
radioId = atoi(getInternal(I_REQUEST_ID));
|
||||
// Write id to EEPROM
|
||||
if (radioId == AUTO) { // sensor net gateway will return max id if all sensor id are taken
|
||||
debug(PSTR("Sensor network is full! You already have the maximum of sensors!\n"));
|
||||
while (1) {} // Wait here. Nothing else we can do...
|
||||
} else {
|
||||
debug(PSTR("Radio id received: %d\n"), radioId);
|
||||
EEPROM.write(EEPROM_RADIO_ID_ADDRESS, radioId);
|
||||
}
|
||||
}
|
||||
debug(PSTR("Radio id stored in EEPROM was: %d\n"), radioId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Sensor::findRelay() {
|
||||
// This can be improved by using status = read_register(OBSERVE_TX,&observe_tx,1) on the
|
||||
// sending side.. the problem is getting this information here without too much fuss.
|
||||
// Stay in this method until one or more relay nodes answers ping message.
|
||||
if (radioId == GATEWAY_ADDRESS)
|
||||
return; // Gateway has no business here!
|
||||
|
||||
failedTransmissions = 0;
|
||||
|
||||
// Open a reading pipe for current radioId (if it differs from broadcast)
|
||||
if (radioId != BROADCAST_PIPE) {
|
||||
RF24::openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID+radioId);
|
||||
}
|
||||
distance = 255;
|
||||
uint8_t oldRelayId = relayId;
|
||||
while (distance == 255) {
|
||||
// Send ping message to BROADCAST_ADDRESS (to which all nodes listens and should reply to)
|
||||
buildMsg(radioId, BROADCAST_ADDRESS, NODE_CHILD_ID, M_INTERNAL, I_PING, "", 0, false);
|
||||
sendWrite(BROADCAST_ADDRESS, msg, 0);
|
||||
// Wait for replies for max 10 seconds (or when buffer for all relay nodes have been filled up)
|
||||
unsigned long enter = millis();
|
||||
uint8_t neighborDistanceToGW;
|
||||
// Wait for ack responses 5 seconds
|
||||
while (millis() - enter < 5000) {
|
||||
if (messageAvailable()) {
|
||||
if (msg.header.messageType == M_INTERNAL &&
|
||||
msg.header.type == I_PING_ACK &&
|
||||
msg.header.to == radioId) {
|
||||
neighborDistanceToGW = atoi(msg.data);
|
||||
if (neighborDistanceToGW<distance-1) {
|
||||
// Found a neighbor closer to GW than previously found
|
||||
distance = neighborDistanceToGW + 1;
|
||||
relayId = msg.header.from;
|
||||
debug(PSTR("Using relay %d. Distance is %d\n"), msg.header.from, neighborDistanceToGW);
|
||||
if (neighborDistanceToGW == 0) // We found gateway. Search no more.
|
||||
break;
|
||||
} else {
|
||||
debug(PSTR("Discarded relay %d. Distance is %d\n"), msg.header.from, neighborDistanceToGW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (distance == 255) {
|
||||
debug(PSTR("No relay nodes was found. Trying again in 10 seconds.\n"));
|
||||
delay(10000);
|
||||
}
|
||||
}
|
||||
|
||||
// Store new relay address in EEPROM
|
||||
if (relayId != oldRelayId) {
|
||||
EEPROM.write(EEPROM_RELAY_ID_ADDRESS, relayId);
|
||||
EEPROM.write(EEPROM_DISTANCE_ADDRESS, distance);
|
||||
}
|
||||
|
||||
// Always listen to relay pipe (relay broadcasts messages that might be for this
|
||||
// nodes children)
|
||||
RF24::openReadingPipe(RELAY_PIPE, BASE_RADIO_ID + relayId);
|
||||
}
|
||||
|
||||
|
||||
void Sensor::buildMsg(uint8_t from, uint8_t to, uint8_t childId, uint8_t messageType, uint8_t type, const char *data, uint8_t length, boolean binary) {
|
||||
msg.header.version = PROTOCOL_VERSION;
|
||||
msg.header.binary = binary;
|
||||
msg.header.from = from;
|
||||
msg.header.to = to;
|
||||
msg.header.childId = childId;
|
||||
msg.header.messageType = messageType;
|
||||
msg.header.type = type;
|
||||
strncpy(msg.data, data, length);
|
||||
if(length < sizeof(msg.data)-1) {
|
||||
memset(&msg.data[length], 0, sizeof(msg.data) - 1 - length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boolean Sensor::sendData(uint8_t from, uint8_t to, uint8_t childId, uint8_t messageType, uint8_t type, const char *data, uint8_t length, boolean binary) {
|
||||
bool ok = false;
|
||||
if (length < sizeof(msg.data)) {
|
||||
buildMsg(from, to, childId, messageType, type, data, length, binary);
|
||||
return send(msg,length);
|
||||
} else {
|
||||
debug(PSTR("Message too large\n"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean Sensor::sendVariableAck() {
|
||||
ack.header.childId = msg.header.childId;
|
||||
ack.header.type = msg.header.type;
|
||||
strncpy(ack.data, msg.data, sizeof(ack.data)-1); // will terminate properly not exceeding message.data
|
||||
return send(ack,strlen(ack.data));
|
||||
}
|
||||
|
||||
boolean Sensor::send(message_s message, int length) {
|
||||
debug(PSTR("Relaying message back to gateway.\n"));
|
||||
|
||||
// We're a sensor node. Always send messages back to relay node
|
||||
bool ok = sendWrite(relayId, message, length);
|
||||
|
||||
if (!ok && radioId != GATEWAY_ADDRESS) {
|
||||
// Failure when sending to relay node. The relay node might be down and we
|
||||
// need to find another route to gateway. Max 20 retries before giving up.
|
||||
if (failedTransmissions>20) {
|
||||
findRelay();
|
||||
}
|
||||
failedTransmissions++;
|
||||
} else {
|
||||
failedTransmissions = 0;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
boolean Sensor::sendWrite(uint8_t dest, message_s message, int length) {
|
||||
// Add current radioId to last-field and calculate crc
|
||||
message.header.last = radioId;
|
||||
message.header.crc = crc8Message(message);
|
||||
debug(PSTR("Sending: from=%d, to=%d, childId=%d, mtype=%d, type=%d, crc=%d, '%s', sent via %d\n"),
|
||||
message.header.from,message.header.to, message.header.childId, message.header.messageType, message.header.type, message.header.crc, message.data, dest);
|
||||
|
||||
RF24::stopListening();
|
||||
bool ok = false;
|
||||
RF24::openWritingPipe(BASE_RADIO_ID + dest);
|
||||
int retry = 5;
|
||||
do {
|
||||
ok = RF24::write(&message, min(MAX_MESSAGE_LENGTH, sizeof(message.header) + length));
|
||||
}
|
||||
while ( !ok && --retry );
|
||||
RF24::startListening();
|
||||
|
||||
if (ok) {
|
||||
debug(PSTR("Sent successfully\n"));
|
||||
} else {
|
||||
debug(PSTR("Send failed. No ack received.\n"));
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void Sensor::sendInternal(uint8_t variableType, const char *value) {
|
||||
sendData(radioId, GATEWAY_ADDRESS, NODE_CHILD_ID, M_INTERNAL, variableType, value, strlen(value), false);
|
||||
}
|
||||
|
||||
// This will be added in 1.4
|
||||
/*void Sensor::sendVariable(uint8_t childId, uint8_t variableType,
|
||||
const char *value, length) {
|
||||
sendData(radioId, GATEWAY_ADDRESS, childId, M_SET_VARIABLE, variableType, value, length, true);
|
||||
}*/
|
||||
|
||||
|
||||
void Sensor::sendVariable(uint8_t childId, uint8_t variableType,
|
||||
const char *value) {
|
||||
sendData(radioId, GATEWAY_ADDRESS, childId, M_SET_VARIABLE, variableType, value, strlen(value), false);
|
||||
}
|
||||
|
||||
void Sensor::sendVariable(uint8_t childId, uint8_t variableType, double value, int decimals) {
|
||||
sendVariable(childId, variableType, dtostrf(value,2,decimals,convBuffer));
|
||||
}
|
||||
|
||||
void Sensor::sendVariable(uint8_t childId, uint8_t variableType, int value) {
|
||||
sendVariable(childId, variableType, itoa(value, convBuffer, 10));
|
||||
}
|
||||
|
||||
void Sensor::sendVariable(uint8_t childId, uint8_t variableType, long value) {
|
||||
sendVariable(childId, variableType, ltoa(value, convBuffer, 10));
|
||||
}
|
||||
|
||||
void Sensor::sendVariable(uint8_t childId, uint8_t variableType, unsigned long value) {
|
||||
sendVariable(childId, variableType, ltoa(value, convBuffer, 10));
|
||||
}
|
||||
|
||||
void Sensor::sendVariable(uint8_t childId, uint8_t variableType, unsigned int value) {
|
||||
sendVariable(childId, variableType, ltoa(value, convBuffer, 10));
|
||||
}
|
||||
|
||||
void Sensor::sendVariable(uint8_t nodeId, uint8_t childId, uint8_t variableType,
|
||||
const char *value) {
|
||||
sendData(radioId, nodeId, childId, M_SET_VARIABLE, variableType, value, strlen(value), false);
|
||||
}
|
||||
|
||||
void Sensor::sendVariable(uint8_t nodeId, uint8_t childId, uint8_t variableType, double value, int decimals) {
|
||||
sendVariable(nodeId, childId, variableType, dtostrf(value,2,decimals,convBuffer));
|
||||
}
|
||||
|
||||
void Sensor::sendVariable(uint8_t nodeId, uint8_t childId, uint8_t variableType, int value) {
|
||||
sendVariable(nodeId, childId, variableType, itoa(value, convBuffer, 10));
|
||||
}
|
||||
|
||||
void Sensor::sendVariable(uint8_t nodeId, uint8_t childId, uint8_t variableType, long value) {
|
||||
sendVariable(nodeId, childId, variableType, ltoa(value, convBuffer, 10));
|
||||
}
|
||||
|
||||
void Sensor::sendVariable(uint8_t nodeId, uint8_t childId, uint8_t variableType, unsigned long value) {
|
||||
sendVariable(nodeId, childId, variableType, ltoa(value, convBuffer, 10));
|
||||
}
|
||||
|
||||
void Sensor::sendVariable(uint8_t nodeId, uint8_t childId, uint8_t variableType, unsigned int value) {
|
||||
sendVariable(nodeId, childId, variableType, ltoa(value, convBuffer, 10));
|
||||
}
|
||||
|
||||
void Sensor::sendSensorPresentation(uint8_t childId, uint8_t sensorType) {
|
||||
sendData(radioId, GATEWAY_ADDRESS, childId, M_PRESENTATION, sensorType, LIBRARY_VERSION, strlen(LIBRARY_VERSION), false);
|
||||
}
|
||||
|
||||
void Sensor::requestStatus(uint8_t childId, uint8_t variableType) {
|
||||
sendData(radioId, GATEWAY_ADDRESS, childId, M_REQ_VARIABLE, variableType, "", 0, false);
|
||||
}
|
||||
|
||||
void Sensor::requestStatus(uint8_t nodeId, int8_t childId, uint8_t variableType) {
|
||||
sendData(radioId, nodeId, childId, M_REQ_VARIABLE, variableType, "", 0, false);
|
||||
}
|
||||
|
||||
void Sensor::sendBatteryLevel(int value) {
|
||||
sendInternal(I_BATTERY_LEVEL, ltoa(value, convBuffer, 10));
|
||||
}
|
||||
|
||||
char* Sensor::get(uint8_t nodeId, uint8_t childId, uint8_t sendType, uint8_t receiveType, uint8_t variableType) {
|
||||
while (1) {
|
||||
sendData(radioId, nodeId, childId, sendType, variableType, "", 0, false);
|
||||
uint8_t i = 0;
|
||||
while (i < 100) { // 5 seconds timeout before re-sending status request
|
||||
while (messageAvailable()) {
|
||||
// Check that it is right type of message and not a routing message
|
||||
if (msg.header.messageType == receiveType &&
|
||||
msg.header.type == variableType &&
|
||||
msg.header.childId == childId) {
|
||||
return msg.data;
|
||||
}
|
||||
}
|
||||
delay(50);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* Sensor::getStatus(uint8_t childId, uint8_t variableType) {
|
||||
return get(GATEWAY_ADDRESS, childId, M_REQ_VARIABLE, M_ACK_VARIABLE, variableType);
|
||||
}
|
||||
|
||||
char * Sensor::getStatus(uint8_t nodeId, int8_t childId, uint8_t variableType) {
|
||||
return get(nodeId, childId, M_REQ_VARIABLE, M_ACK_VARIABLE, variableType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
char* Sensor::getInternal(uint8_t variableType) {
|
||||
return get(GATEWAY_ADDRESS, NODE_CHILD_ID, M_INTERNAL, M_INTERNAL, variableType);
|
||||
}
|
||||
|
||||
unsigned long Sensor::getTime() {
|
||||
return atol(getInternal(I_TIME));
|
||||
}
|
||||
|
||||
void Sensor::requestTime() {
|
||||
sendData(radioId, GATEWAY_ADDRESS, NODE_CHILD_ID, M_INTERNAL, I_TIME, "", 0, false);
|
||||
}
|
||||
|
||||
|
||||
bool Sensor::isMetricSystem() {
|
||||
return getInternal(I_UNIT)[0] == 'M';
|
||||
}
|
||||
|
||||
void Sensor::requestIsMetricSystem() {
|
||||
sendData(radioId, GATEWAY_ADDRESS, NODE_CHILD_ID, M_INTERNAL, I_UNIT, "", 0, false);
|
||||
}
|
||||
|
||||
|
||||
boolean Sensor::messageAvailable() {
|
||||
if (RF24::available()) {
|
||||
readMessage();
|
||||
boolean ok = validate() == VALIDATE_OK;
|
||||
debug(PSTR("Mess crc %s.\n"),ok?"ok":"error");
|
||||
if (ok && msg.header.to == radioId) {
|
||||
// This message is addressed to this node
|
||||
debug(PSTR("Message addressed for this node.\n"));
|
||||
if (msg.header.from == GATEWAY_ADDRESS &&
|
||||
// If this is variable message from sensor net gateway. Send ack back.
|
||||
msg.header.messageType == M_SET_VARIABLE) {
|
||||
// Send back ack message to sensor net gateway
|
||||
sendVariableAck();
|
||||
}
|
||||
// Return message to waiting sketch...
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
message_s Sensor::waitForMessage() {
|
||||
while (1) {
|
||||
if (messageAvailable()) {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
message_s Sensor::getMessage() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
message_s Sensor::readMessage() {
|
||||
uint8_t len = RF24::getDynamicPayloadSize();
|
||||
bool done = RF24::read(&msg, len);
|
||||
// Make sure string gets terminated ok.
|
||||
msg.data[len - sizeof(header_s) ] = '\0';
|
||||
debug(PSTR("Received: from=%d, to=%d, childId=%d, mtype=%d, type=%d, crc=%d, '%s'\n"),
|
||||
msg.header.from,msg.header.to, msg.header.childId, msg.header.messageType, msg.header.type,msg.header.crc, msg.data);
|
||||
return msg;
|
||||
}
|
||||
|
||||
/*
|
||||
* raw CRC 8 bit calculation
|
||||
*/
|
||||
uint8_t Sensor::crc8Raw ( uint8_t *data_in, uint8_t number_of_bytes_to_read )
|
||||
{
|
||||
uint8_t crc;
|
||||
uint8_t loop_count;
|
||||
uint8_t bit_counter;
|
||||
uint8_t data;
|
||||
uint8_t feedback_bit;
|
||||
|
||||
crc = CRC8INIT;
|
||||
|
||||
for (loop_count = 0; loop_count != number_of_bytes_to_read; loop_count++)
|
||||
{
|
||||
data = data_in[loop_count];
|
||||
|
||||
bit_counter = 8;
|
||||
do {
|
||||
feedback_bit = (crc ^ data) & 0x01;
|
||||
|
||||
if ( feedback_bit == 0x01 ) {
|
||||
crc = crc ^ CRC8POLY;
|
||||
}
|
||||
crc = (crc >> 1) & 0x7F;
|
||||
if ( feedback_bit == 0x01 ) {
|
||||
crc = crc | 0x80;
|
||||
}
|
||||
|
||||
data = data >> 1;
|
||||
bit_counter--;
|
||||
|
||||
} while (bit_counter > 0);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
/*
|
||||
* calculate CRC8 on message_s data taking care of data structure and protocol version
|
||||
*/
|
||||
uint8_t Sensor::crc8Message(message_s var_msg) {
|
||||
// Must set crc to a constant value.
|
||||
var_msg.header.crc = 0;
|
||||
// fill unused space by zeroes for string data only
|
||||
if(!var_msg.header.binary) {
|
||||
uint8_t len = strlen(var_msg.data);
|
||||
if(len < sizeof(var_msg.data)-1) {
|
||||
memset(&var_msg.data[len], 0, sizeof(var_msg.data) - 1 - len);
|
||||
}
|
||||
}
|
||||
return crc8Raw((uint8_t*)&var_msg, (uint8_t)sizeof(var_msg));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
uint8_t Sensor::crc8Message(message_s var_msg) {
|
||||
struct {
|
||||
message_s msg;
|
||||
uint8_t protocol_version;
|
||||
} crc_data;
|
||||
memcpy(&crc_data, &var_msg, sizeof(var_msg));
|
||||
crc_data.protocol_version = PROTOCOL_VERSION;
|
||||
// some clean up needed for repeated result
|
||||
crc_data.msg.header.crc = 0;
|
||||
// fill unused space by zeroes for string data only
|
||||
if(!crc_data.msg.header.binary) {
|
||||
uint8_t len = strlen(crc_data.msg.data);
|
||||
if(len < sizeof(crc_data.msg.data)-1) {
|
||||
memset(&crc_data.msg.data[len], 0, sizeof(crc_data.msg.data) - 1 - len);
|
||||
}
|
||||
}
|
||||
return crc8Raw((uint8_t*)&crc_data, (uint8_t)sizeof(crc_data));
|
||||
} */
|
||||
|
||||
|
||||
/*
|
||||
* true if message is consistent *
|
||||
*/
|
||||
bool Sensor::checkCRC(message_s var_msg) {
|
||||
uint8_t oldCrc = var_msg.header.crc;
|
||||
|
||||
//debug(PSTR("CRC: in %d, calc %d\n"),oldCrc, crc8Message(var_msg));
|
||||
|
||||
return (oldCrc == crc8Message(var_msg))?true:false;
|
||||
}
|
||||
|
||||
uint8_t Sensor::validate() {
|
||||
bool crc_check = checkCRC(msg);
|
||||
bool version_check = (msg.header.version == PROTOCOL_VERSION);
|
||||
if(!version_check) return VALIDATE_BAD_VERSION;
|
||||
if(!crc_check) return VALIDATE_BAD_CRC;
|
||||
return VALIDATE_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void Sensor::debugPrint(const char *fmt, ... ) {
|
||||
char fmtBuffer[300];
|
||||
if (radioId == GATEWAY_ADDRESS) {
|
||||
// prepend debug message to be handled correctly by gw
|
||||
Serial.print("0;0;4;11;");
|
||||
}
|
||||
va_list args;
|
||||
va_start (args, fmt );
|
||||
vsnprintf_P(fmtBuffer, 300, fmt, args);
|
||||
va_end (args);
|
||||
if (radioId == GATEWAY_ADDRESS) {
|
||||
// Truncte message if this is gateway node
|
||||
vsnprintf_P(fmtBuffer, 97, fmt, args);
|
||||
fmtBuffer[96] = '\n';
|
||||
fmtBuffer[97] = '\0';
|
||||
} else {
|
||||
vsnprintf_P(fmtBuffer, 299, fmt, args);
|
||||
}
|
||||
va_end (args);
|
||||
Serial.print(fmtBuffer);
|
||||
//Serial.println(freeRam());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
int Sensor::freeRam (void) {
|
||||
extern int __heap_start, *__brkval;
|
||||
int v;
|
||||
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
The Sensor Net Arduino library adds a new layer on top of the RF24 library.
|
||||
It handles radio network routing, relaying and ids.
|
||||
|
||||
Created by Henrik Ekblad <henrik.ekblad@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef Sensor_h
|
||||
#define Sensor_h
|
||||
|
||||
#include <nRF24L01.h>
|
||||
#include <RF24.h>
|
||||
#include <RF24_config.h>
|
||||
#include <Arduino.h>
|
||||
#include <stddef.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <avr/progmem.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define DEBUG // Turn on/off debug mode by having/removing this define
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug(x,...) debugPrint(x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define debug(x,...)
|
||||
#endif
|
||||
|
||||
#define LIBRARY_VERSION "1.2+"
|
||||
#define PROTOCOL_VERSION 1
|
||||
#define BAUD_RATE 115200
|
||||
|
||||
#define AUTO 0xFF // 0-254. Id 255 is reserved for auto initialization of radioId.
|
||||
#define NODE_CHILD_ID 0xFF // Node child id is always created for when a new sensor is detected
|
||||
#define EEPROM_RADIO_ID_ADDRESS 0 // Where to store radio id in EEPROM
|
||||
#define EEPROM_RELAY_ID_ADDRESS 1 // Where to store relay id in EEPROM
|
||||
#define EEPROM_DISTANCE_ADDRESS 2 // Where to store distance to gateway in EEPROM
|
||||
|
||||
// This is the radioId for sensor net gateway receiver sketch (where all sensors should send their data).
|
||||
// This is also act as base value for sensor radioId
|
||||
#define BASE_RADIO_ID 0xABCDABC000LL
|
||||
#define GATEWAY_ADDRESS ((uint8_t)0)
|
||||
#define BROADCAST_ADDRESS ((uint8_t)0xFF)
|
||||
|
||||
#define MAX_MESSAGE_LENGTH 32
|
||||
|
||||
#define CURRENT_NODE_PIPE ((uint8_t)1)
|
||||
#define BROADCAST_PIPE ((uint8_t)2)
|
||||
#define RELAY_PIPE ((uint8_t)3)
|
||||
|
||||
#define CRC8INIT 0x00
|
||||
#define CRC8POLY 0x18 //0X18 = X^8+X^5+X^4+X^0
|
||||
|
||||
// Message types
|
||||
typedef enum {
|
||||
M_PRESENTATION = 0,
|
||||
M_SET_VARIABLE = 1,
|
||||
M_REQ_VARIABLE = 2,
|
||||
M_ACK_VARIABLE = 3,
|
||||
M_INTERNAL = 4
|
||||
} messageType;
|
||||
|
||||
// Sensor variables that can be used in sketches
|
||||
typedef enum {
|
||||
V_TEMP,V_HUM, V_LIGHT, V_DIMMER, V_PRESSURE, V_FORECAST, V_RAIN,
|
||||
V_RAINRATE, V_WIND, V_GUST, V_DIRECTION, V_UV, V_WEIGHT, V_DISTANCE,
|
||||
V_IMPEDANCE, V_ARMED, V_TRIPPED, V_WATT, V_KWH, V_SCENE_ON, V_SCENE_OFF,
|
||||
V_HEATER, V_HEATER_SW, V_LIGHT_LEVEL, V_VAR1, V_VAR2, V_VAR3, V_VAR4, V_VAR5,
|
||||
V_UP, V_DOWN, V_STOP, V_IR_SEND, V_IR_RECEIVE, V_FLOW, V_VOLUME
|
||||
} variableType;
|
||||
|
||||
// Internal messages
|
||||
typedef enum {
|
||||
I_BATTERY_LEVEL, I_BATTERY_DATE, I_LAST_TRIP, I_TIME, I_VERSION, I_REQUEST_ID,
|
||||
I_INCLUSION_MODE, I_RELAY_NODE, I_LAST_UPDATE, I_PING, I_PING_ACK,
|
||||
I_LOG_MESSAGE, I_CHILDREN, I_UNIT
|
||||
} internalMessageType;
|
||||
|
||||
// Sensor types
|
||||
typedef enum {
|
||||
S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND,
|
||||
S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE,
|
||||
S_ARDUINO_RELAY, S_LOCK, S_IR, S_WATER
|
||||
} sensor;
|
||||
|
||||
// Possible return values by validate() when doing crc check of received message.
|
||||
enum {
|
||||
VALIDATE_OK, VALIDATE_BAD_CRC, VALIDATE_BAD_VERSION
|
||||
};
|
||||
|
||||
// The message structure
|
||||
typedef struct {
|
||||
uint8_t crc : 8; // 8 bits crc
|
||||
uint8_t version : 3; // 3 bits protocol version
|
||||
uint8_t binary : 1; // 1 bit. Data is binary and should be encoded when sent to sensor net gateway
|
||||
uint8_t from : 8; // 8 bits. RadioId of sender node
|
||||
uint8_t to : 8; // 8 bits. RadioId of destination node
|
||||
uint8_t last : 8; // 8 bits. RadioId of last node this message passed
|
||||
uint8_t childId : 8; // 1 byte. Up to MAX_CHILD_DEVICES child sensors per radioId
|
||||
uint8_t messageType : 4; // 4 bits. Type of message. See messageType
|
||||
|
||||
uint8_t type : 8; // 8 bits. variableType or deviceType depending on messageType
|
||||
} header_s;
|
||||
|
||||
typedef struct {
|
||||
header_s header;
|
||||
char data[MAX_MESSAGE_LENGTH - sizeof(header_s) + 1]; // Each message can transfer a payload. Add one extra byte for \0
|
||||
} message_s;
|
||||
|
||||
|
||||
class Sensor : public RF24
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Creates a new instance of Sensor class.
|
||||
*
|
||||
* @param _cepin The pin attached to RF24 Chip Enable on the RF module
|
||||
* @param _cspin The pin attached to RF24 Chip Select
|
||||
*/
|
||||
Sensor(uint8_t _cepin, uint8_t _cspin);
|
||||
|
||||
/**
|
||||
* Begin operation of the sensor net library
|
||||
*
|
||||
* Call this in setup(), before calling any other sensor net library methods.
|
||||
* @param _radioId The unique id (1-254) for this sensor. Specify 255 for auto id mode.
|
||||
*/
|
||||
void begin(uint8_t _radioId);
|
||||
|
||||
|
||||
uint8_t getRadioId();
|
||||
|
||||
/**
|
||||
* The arduino node must send a presentation of all the sensors connected before any
|
||||
* variable changes will be registered on sensor net gateway side.
|
||||
* Usually it's good to present all sensors when arduino starts up (setup).
|
||||
* Note that gateway must be in include mode to register new devices.
|
||||
*
|
||||
* @param childId The unique child id for the different sensors connected to this arduino. 0-254.
|
||||
* @param sensorType Sensor types to create. They will be numbered from 0 up to 127.
|
||||
*/
|
||||
void sendSensorPresentation(uint8_t childId, uint8_t sensorType);
|
||||
|
||||
|
||||
/**
|
||||
* Sends a variable change to sensor net gateway (or another sensor if radioId is specified)
|
||||
*
|
||||
* @param radioId The radioId of other node in radio network (used for communicating between sensors)
|
||||
* @param childId The child id for which to update variable. Value can be 0-254.
|
||||
* @param variableType The variableType to update
|
||||
* @param value New value of the variable
|
||||
*/
|
||||
|
||||
void sendVariable(uint8_t childId, uint8_t variableType, const char *value);
|
||||
void sendVariable(uint8_t childId, uint8_t variableType, double value, int decimals);
|
||||
void sendVariable(uint8_t childId, uint8_t variableType, unsigned long value);
|
||||
void sendVariable(uint8_t childId, uint8_t variableType, long value);
|
||||
void sendVariable(uint8_t childId, uint8_t variableType, unsigned int value);
|
||||
void sendVariable(uint8_t childId, uint8_t variableType, int value);
|
||||
|
||||
void sendVariable(uint8_t radioId, uint8_t childId, uint8_t variableType, const char *value);
|
||||
void sendVariable(uint8_t radioId, uint8_t childId, uint8_t variableType, double value, int decimals);
|
||||
void sendVariable(uint8_t radioId, uint8_t childId, uint8_t variableType, unsigned long value);
|
||||
void sendVariable(uint8_t radioId, uint8_t childId, uint8_t variableType, long value);
|
||||
void sendVariable(uint8_t radioId, uint8_t childId, uint8_t variableType, unsigned int value);
|
||||
void sendVariable(uint8_t radioId, uint8_t childId, uint8_t variableType, int value);
|
||||
|
||||
|
||||
/**
|
||||
* Sends battery status to sensor net gateway for this radio node.
|
||||
* @param value Set a value between 0-100(%)
|
||||
*/
|
||||
void sendBatteryLevel(int value);
|
||||
|
||||
/**
|
||||
* Requests a variable value from sensor net gateway (or another sensor). This method will not wait for an answer.
|
||||
* You should use mesageAvailable/getMessage to pick up the response.
|
||||
*
|
||||
* @param radioId The radioId of other node in radio network (used when fetching from other node)
|
||||
* @param childId The unique child id for the different sensors connected to this arduino. 0-254.
|
||||
* @param variableType The variableType to fetch
|
||||
*/
|
||||
void requestStatus(uint8_t childId, uint8_t variableType);
|
||||
void requestStatus(uint8_t radioId, int8_t childId, uint8_t variableType);
|
||||
|
||||
/**
|
||||
* Requests status for a sensor variable from sensor net gateway. Waits until message arrives.
|
||||
*
|
||||
* @param radioId The radioId of other node in radio network (used when fetching from other node)
|
||||
* @param childId The unique child id for the different sensors connected to this arduino. 0-254.
|
||||
* @param variableType The variableType to fetch
|
||||
* @return The variable value
|
||||
*/
|
||||
char *getStatus(uint8_t childId, uint8_t variableType);
|
||||
char *getStatus(uint8_t radioId, int8_t childId, uint8_t variableType);
|
||||
|
||||
|
||||
/**
|
||||
* Fetches time from sensor net gateway
|
||||
*/
|
||||
void requestTime();
|
||||
unsigned long getTime();
|
||||
|
||||
/**
|
||||
* Fetches unit setting from sensor net gateway. Returns true if metric system has been selected which means
|
||||
* that sensor should report it's information in: celsius, meter, cm, gram, km/h, m/s etc..
|
||||
* If false is returned the sensor should report data in imperial system which means
|
||||
* fahrenheit, feet, gallon, mph etc...
|
||||
*/
|
||||
void requestIsMetricSystem();
|
||||
bool isMetricSystem();
|
||||
|
||||
|
||||
/**
|
||||
* Busy waits until there is a message for this node available to be read
|
||||
*/
|
||||
message_s waitForMessage(void);
|
||||
|
||||
/**
|
||||
* Returns true if there is a message addressed for this node is available to be read
|
||||
*/
|
||||
boolean messageAvailable(void);
|
||||
|
||||
/**
|
||||
* Returns the last received message
|
||||
*/
|
||||
message_s getMessage(void);
|
||||
|
||||
/**
|
||||
* Validates consistency of the message including CRC and protocol version
|
||||
*/
|
||||
uint8_t validate();
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void debugPrint(const char *fmt, ... );
|
||||
int freeRam();
|
||||
#endif
|
||||
|
||||
|
||||
protected:
|
||||
uint8_t failedTransmissions;
|
||||
boolean isRelay;
|
||||
uint8_t radioId;
|
||||
uint8_t distance; // This nodes distance to sensor net gateway (number of hops)
|
||||
uint8_t relayId;
|
||||
message_s msg; // Buffer for incoming messages.
|
||||
char convBuffer[20];
|
||||
|
||||
void setupRadio();
|
||||
void findRelay();
|
||||
boolean send(message_s message, int length);
|
||||
boolean sendWrite(uint8_t dest, message_s message, int length);
|
||||
message_s readMessage(void);
|
||||
void buildMsg(uint8_t from, uint8_t to, uint8_t childId, uint8_t messageType, uint8_t type, const char *data, uint8_t length, boolean binary);
|
||||
void sendInternal(uint8_t variableType, const char *value);
|
||||
boolean sendVariableAck();
|
||||
boolean sendData(uint8_t from, uint8_t to, uint8_t childId, uint8_t messageType, uint8_t type, const char *data, uint8_t length, boolean binaryMessage);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
message_s ack; // Buffer for ack messages.
|
||||
|
||||
void initializeRadioId();
|
||||
uint8_t crc8Raw(uint8_t *data_in, uint8_t number_of_bytes_to_read);
|
||||
uint8_t crc8Message(message_s);
|
||||
bool checkCRC(message_s);
|
||||
char* get(uint8_t nodeId, uint8_t childId, uint8_t sendType, uint8_t receiveType, uint8_t variableType);
|
||||
char *getInternal(uint8_t variableType);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
/* please read copyright-notice at EOF */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define CRC8INIT 0x00
|
||||
#define CRC8POLY 0x18 //0X18 = X^8+X^5+X^4+X^0
|
||||
|
||||
uint8_t crc8( uint8_t *data, uint16_t number_of_bytes_in_data )
|
||||
{
|
||||
uint8_t crc;
|
||||
uint16_t loop_count;
|
||||
uint8_t bit_counter;
|
||||
uint8_t b;
|
||||
uint8_t feedback_bit;
|
||||
|
||||
crc = CRC8INIT;
|
||||
|
||||
for (loop_count = 0; loop_count != number_of_bytes_in_data; loop_count++)
|
||||
{
|
||||
b = data[loop_count];
|
||||
|
||||
bit_counter = 8;
|
||||
do {
|
||||
feedback_bit = (crc ^ b) & 0x01;
|
||||
|
||||
if ( feedback_bit == 0x01 ) {
|
||||
crc = crc ^ CRC8POLY;
|
||||
}
|
||||
crc = (crc >> 1) & 0x7F;
|
||||
if ( feedback_bit == 0x01 ) {
|
||||
crc = crc | 0x80;
|
||||
}
|
||||
|
||||
b = b >> 1;
|
||||
bit_counter--;
|
||||
|
||||
} while (bit_counter > 0);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*
|
||||
This code is from Colin O'Flynn - Copyright (c) 2002
|
||||
only minor changes by M.Thomas 9/2004
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef CRC8_H_
|
||||
#define CRC8_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t crc8( uint8_t* data, uint16_t number_of_bytes_in_data );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
This is based on code from :
|
||||
|
||||
Copyright (c) 2002 Colin O'Flynn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "crc8.c"
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
*
|
||||
* This sketch clears radioId, relayId and routing info in EEPROM
|
||||
*
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
for (int i=0;i<512;i++) {
|
||||
EEPROM.write(i, 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Nothing to do here...
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <Sleep_n0m1.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <DallasTemperature.h>
|
||||
#include <OneWire.h>
|
||||
#include <RF24.h>
|
||||
#include <Sensor.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
|
||||
#define ONE_WIRE_BUS 3 // Pin where dallase sensor is connected
|
||||
|
||||
unsigned long SLEEP_TIME = 30; // Sleep time between reads (in seconds)
|
||||
|
||||
OneWire oneWire(ONE_WIRE_BUS);
|
||||
DallasTemperature sensors(&oneWire);
|
||||
|
||||
Sensor gw(9, 10);
|
||||
Sleep sleep;
|
||||
|
||||
#define MAX_ATTACHED_DS18B20 16
|
||||
|
||||
float lastTemperature[MAX_ATTACHED_DS18B20];
|
||||
int numSensors=0;
|
||||
boolean metric = true;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to type in characters
|
||||
sensors.begin();
|
||||
gw.begin(RADIO_ID);
|
||||
|
||||
// Fetch the number of attached sensors
|
||||
numSensors = sensors.getDeviceCount();
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
for (int i=0; i<numSensors; i++) {
|
||||
gw.sendSensorPresentation(i, S_TEMP);
|
||||
}
|
||||
metric = gw.isMetricSystem();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
sensors.requestTemperatures(); // Fetch temperatures from Dallas
|
||||
delay(100);
|
||||
for (int i=0; i<numSensors; i++) {
|
||||
// Fetch and round temperature to one decimal
|
||||
float temperature = static_cast<float>(static_cast<int>((metric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.;
|
||||
// Only send data if temperature has changed and no error
|
||||
if (lastTemperature[i] != temperature && temperature != -127.00) {
|
||||
gw.powerUp(); // Powerup introduces a small delay (which is missing in radio.write powerup)
|
||||
// Send variable (using registered shortcut) to gw
|
||||
gw.sendVariable(i, V_TEMP, temperature, 1);
|
||||
lastTemperature[i]=temperature;
|
||||
}
|
||||
}
|
||||
// Power down the radio. Note that the radio will get powered back up
|
||||
// on the next write() call.
|
||||
delay(500);
|
||||
gw.powerDown();
|
||||
sleep.pwrDownMode(); //set sleep mode
|
||||
sleep.sleepDelay(SLEEP_TIME * 1000); //sleep for: sleepTime
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#include <Sleep_n0m1.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RF24.h>
|
||||
#include <Sensor.h>
|
||||
#include <NewPing.h>
|
||||
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID 8
|
||||
|
||||
#define TRIGGER_PIN 6 // Arduino pin tied to trigger pin on the ultrasonic sensor.
|
||||
#define ECHO_PIN 5 // Arduino pin tied to echo pin on the ultrasonic sensor.
|
||||
#define MAX_DISTANCE 300 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
|
||||
|
||||
unsigned long SLEEP_TIME = 5; // Sleep time between reads (in seconds)
|
||||
|
||||
Sensor gw(9, 10);
|
||||
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
|
||||
Sleep sleep;
|
||||
|
||||
int lastDist;
|
||||
boolean metric;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to type in characters
|
||||
gw.begin(RADIO_ID);
|
||||
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
gw.sendSensorPresentation(0, S_DISTANCE);
|
||||
metric = gw.isMetricSystem();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
int dist = metric?sonar.ping_cm():sonar.ping_in();
|
||||
|
||||
Serial.print("Ping: ");
|
||||
Serial.print(dist); // Convert ping time to distance in cm and print result (0 = outside set distance range)
|
||||
Serial.println(metric?" cm":" in");
|
||||
|
||||
|
||||
if (dist != lastDist) {
|
||||
gw.sendVariable(0, V_DISTANCE, dist);
|
||||
lastDist = dist;
|
||||
}
|
||||
|
||||
// Power down the radio. Note that the radio will get powered back up
|
||||
// on the next write() call.
|
||||
delay(1000); //delay to allow serial to fully print before sleep
|
||||
gw.powerDown();
|
||||
sleep.pwrDownMode(); //set sleep mode
|
||||
sleep.sleepDelay(SLEEP_TIME * 1000); //sleep for: sleepTime
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
// Use this sensor to measure KWH and Watt of your house meeter
|
||||
// You need to set the correct pulsefactor of your meeter (blinks per KWH).
|
||||
// The sensor starts by fetching current KWH value from gateway.
|
||||
// Reports both KWH and Watt back to gateway.
|
||||
//
|
||||
// Unfortunately millis() won't increment when the Arduino is in
|
||||
// sleepmode. So we cannot make this sensor sleep if we also want
|
||||
// to calculate/report watt-number.
|
||||
|
||||
#include <Sleep_n0m1.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RF24.h>
|
||||
#include <Sensor.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your light sensor. (Only 2 and 3 generates interrupt!)
|
||||
#define PULSE_FACTOR 1000 // Nummber of blinks per KWH of your meeter
|
||||
#define SLEEP_MODE false // Watt-value can only be reported when sleep mode is false.
|
||||
#define MAX_WATT 10000 // Max watt value to report. This filetrs outliers.
|
||||
unsigned long SEND_FREQUENCY = 20; // Minimum time between send (in seconds). We don't wnat to spam the gateway.
|
||||
|
||||
|
||||
#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
|
||||
#define CHILD_ID 5 // Id of the sensor child
|
||||
|
||||
Sensor gw(9,10);
|
||||
|
||||
Sleep sleep;
|
||||
|
||||
//double kwhPerBlink = 1.0/((double)PULSE_FACTOR);
|
||||
double ppwh = ((double)PULSE_FACTOR)/1000; // Pulses per watt hour
|
||||
|
||||
volatile unsigned long pulseCount = 0;
|
||||
volatile unsigned long lastBlink = 0;
|
||||
volatile unsigned long watt = 0;
|
||||
unsigned long oldPulseCount = 0;
|
||||
unsigned long oldWatt = 0;
|
||||
double oldKwh;
|
||||
unsigned long lastSend;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to type in characters
|
||||
gw.begin(RADIO_ID);
|
||||
|
||||
// Register this device as power sensor
|
||||
gw.sendSensorPresentation(CHILD_ID, S_POWER);
|
||||
|
||||
// Fetch last known pulse count value from gw
|
||||
pulseCount = oldPulseCount = atol(gw.getStatus(CHILD_ID, V_VAR1));
|
||||
Serial.print("Last pulse count from gw:");
|
||||
Serial.println(pulseCount);
|
||||
attachInterrupt(INTERRUPT, onPulse, RISING);
|
||||
lastSend=millis();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
unsigned long now = millis();
|
||||
// Only send values at a maximum frequency or woken up from sleep
|
||||
if (SLEEP_MODE || now - lastSend > 1000*SEND_FREQUENCY) {
|
||||
// New watt value has been calculated
|
||||
if (!SLEEP_MODE && watt != oldWatt) {
|
||||
// Check that we dont get unresonable large watt value.
|
||||
// could hapen when long wraps or false interrupt triggered
|
||||
if (watt<((unsigned long)MAX_WATT)) {
|
||||
gw.sendVariable(CHILD_ID, V_WATT, watt); // Send watt value to gw
|
||||
}
|
||||
Serial.print("Watt:");
|
||||
Serial.println(watt);
|
||||
oldWatt = watt;
|
||||
}
|
||||
|
||||
// Pulse cout has changed
|
||||
if (pulseCount != oldPulseCount) {
|
||||
gw.sendVariable(CHILD_ID, V_VAR1, pulseCount); // Send kwh value to gw
|
||||
double kwh = ((double)pulseCount/((double)PULSE_FACTOR));
|
||||
oldPulseCount = pulseCount;
|
||||
//Serial.print("Pulse count:");
|
||||
//Serial.println(pulseCount);
|
||||
if (kwh != oldKwh) {
|
||||
gw.sendVariable(CHILD_ID, V_KWH, kwh, 4); // Send kwh value to gw
|
||||
//Serial.print("KWH:");
|
||||
//Serial.println(kwh);
|
||||
oldKwh = kwh;
|
||||
}
|
||||
}
|
||||
lastSend = now;
|
||||
}
|
||||
|
||||
if (SLEEP_MODE) {
|
||||
delay(300); //delay to allow serial to fully print before sleep
|
||||
gw.powerDown();
|
||||
sleep.pwrDownMode(); //set sleep mode
|
||||
sleep.sleepDelay(SEND_FREQUENCY * 1000); //sleep for: sleepTime
|
||||
}
|
||||
}
|
||||
|
||||
void onPulse()
|
||||
{
|
||||
if (!SLEEP_MODE) {
|
||||
unsigned long newBlink = micros();
|
||||
unsigned long interval = newBlink-lastBlink;
|
||||
if (interval<10000L) { // Sometimes we get interrupt on RISING
|
||||
return;
|
||||
}
|
||||
watt = (3600000000.0 /interval) / ppwh;
|
||||
lastBlink = newBlink;
|
||||
}
|
||||
pulseCount++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include <Sleep_n0m1.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RF24.h>
|
||||
#include <Sensor.h>
|
||||
#include <DHT.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
#define CHILD_ID_HUM 0
|
||||
#define CHILD_ID_TEMP 1
|
||||
#define HUMIDITY_SENSOR_DIGITAL_PIN 3
|
||||
|
||||
unsigned long SLEEP_TIME = 30; // Sleep time between reads (in seconds)
|
||||
|
||||
Sensor gw(9, 10);
|
||||
DHT dht;
|
||||
Sleep sleep;
|
||||
|
||||
float lastTemp;
|
||||
float lastHum;
|
||||
boolean metric = true;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to type in characters
|
||||
gw.begin(RADIO_ID);
|
||||
dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
|
||||
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
gw.sendSensorPresentation(CHILD_ID_HUM, S_HUM);
|
||||
gw.sendSensorPresentation(CHILD_ID_TEMP, S_TEMP);
|
||||
|
||||
metric = gw.isMetricSystem();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(dht.getMinimumSamplingPeriod());
|
||||
|
||||
float temperature = dht.getTemperature();
|
||||
if (isnan(temperature)) {
|
||||
Serial.println("Failed reading temperature from DHT");
|
||||
} else if (temperature != lastTemp) {
|
||||
lastTemp = temperature;
|
||||
if (!metric) {
|
||||
temperature = dht.toFahrenheit(temperature);
|
||||
}
|
||||
gw.sendVariable(CHILD_ID_TEMP, V_TEMP, temperature, 1);
|
||||
Serial.print("T: ");
|
||||
Serial.println(temperature);
|
||||
}
|
||||
|
||||
float humidity = dht.getHumidity();
|
||||
if (isnan(humidity)) {
|
||||
Serial.println("Failed reading humidity from DHT");
|
||||
} else if (humidity != lastHum) {
|
||||
lastHum = humidity;
|
||||
gw.sendVariable(CHILD_ID_HUM, V_HUM, humidity, 1);
|
||||
Serial.print("H: ");
|
||||
Serial.println(humidity);
|
||||
}
|
||||
|
||||
// Power down the radio. Note that the radio will get powered back up
|
||||
// on the next write() call.
|
||||
delay(1000); //delay to allow serial to fully print before sleep
|
||||
gw.powerDown();
|
||||
sleep.pwrDownMode(); //set sleep mode
|
||||
sleep.sleepDelay(SLEEP_TIME * 1000); //sleep for: sleepTime
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
// Example sketch showing how to control ir devices
|
||||
// An IR LED must be connected to Arduino PWM pin 3.
|
||||
// An optional ir receiver can be connected to PWM pin 8.
|
||||
// All receied ir signals will be sent to gateway device stored in VAR_1.
|
||||
// When binary light on is clicked - sketch will send volume up ir command
|
||||
// When binary light off is clicked - sketch will send volume down ir command
|
||||
|
||||
#include <Sensor.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RF24.h>
|
||||
#include <IRremote.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
|
||||
int RECV_PIN = 8;
|
||||
|
||||
#define CHILD_1 3 // childId
|
||||
|
||||
IRsend irsend;
|
||||
IRrecv irrecv(RECV_PIN);
|
||||
decode_results results;
|
||||
|
||||
|
||||
Sensor gw(9,10);
|
||||
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to write debug info
|
||||
|
||||
irrecv.enableIRIn(); // Start the ir receiver
|
||||
gw.begin(RADIO_ID);
|
||||
|
||||
// Register a sensors to gw. Use binary light for test purposes.
|
||||
gw.sendSensorPresentation(CHILD_1, S_LIGHT);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (gw.messageAvailable()) {
|
||||
message_s message = gw.getMessage();
|
||||
|
||||
int incomingRelayStatus = atoi(message.data);
|
||||
if (incomingRelayStatus == 1) {
|
||||
irsend.sendNEC(0x1EE17887, 32); // Vol up yamaha ysp-900
|
||||
} else {
|
||||
irsend.sendNEC(0x1EE1F807, 32); // Vol down yamaha ysp-900
|
||||
}
|
||||
// Start receiving ir again...
|
||||
irrecv.enableIRIn();
|
||||
}
|
||||
|
||||
|
||||
if (irrecv.decode(&results)) {
|
||||
char buffer[10];
|
||||
sprintf(buffer, "%08lx", results.value);
|
||||
dump(&results);
|
||||
// Send ir result to gw
|
||||
gw.sendVariable(CHILD_1, V_VAR1, buffer);
|
||||
irrecv.resume(); // Receive the next value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Dumps out the decode_results structure.
|
||||
// Call this after IRrecv::decode()
|
||||
// void * to work around compiler issue
|
||||
//void dump(void *v) {
|
||||
// decode_results *results = (decode_results *)v
|
||||
void dump(decode_results *results) {
|
||||
int count = results->rawlen;
|
||||
if (results->decode_type == UNKNOWN) {
|
||||
Serial.print("Unknown encoding: ");
|
||||
}
|
||||
else if (results->decode_type == NEC) {
|
||||
Serial.print("Decoded NEC: ");
|
||||
}
|
||||
else if (results->decode_type == SONY) {
|
||||
Serial.print("Decoded SONY: ");
|
||||
}
|
||||
else if (results->decode_type == RC5) {
|
||||
Serial.print("Decoded RC5: ");
|
||||
}
|
||||
else if (results->decode_type == RC6) {
|
||||
Serial.print("Decoded RC6: ");
|
||||
}
|
||||
else if (results->decode_type == PANASONIC) {
|
||||
Serial.print("Decoded PANASONIC - Address: ");
|
||||
Serial.print(results->panasonicAddress,HEX);
|
||||
Serial.print(" Value: ");
|
||||
}
|
||||
else if (results->decode_type == JVC) {
|
||||
Serial.print("Decoded JVC: ");
|
||||
}
|
||||
Serial.print(results->value, HEX);
|
||||
Serial.print(" (");
|
||||
Serial.print(results->bits, DEC);
|
||||
Serial.println(" bits)");
|
||||
Serial.print("Raw (");
|
||||
Serial.print(count, DEC);
|
||||
Serial.print("): ");
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if ((i % 2) == 1) {
|
||||
Serial.print(results->rawbuf[i]*USECPERTICK, DEC);
|
||||
}
|
||||
else {
|
||||
Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC);
|
||||
}
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include <Sleep_n0m1.h>
|
||||
#include <SPI.h>
|
||||
#include <RF24.h>
|
||||
#include <EEPROM.h>
|
||||
#include <Sensor.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
#define CHILD_ID_LIGHT 0
|
||||
#define LIGHT_SENSOR_ANALOG_PIN 0
|
||||
|
||||
unsigned long SLEEP_TIME = 30; // Sleep time between reads (in seconds)
|
||||
|
||||
Sensor gw(9,10);
|
||||
|
||||
int lastLightLevel;
|
||||
Sleep sleep;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to type in characters
|
||||
gw.begin(RADIO_ID);
|
||||
|
||||
// Register all sensors to gateway (they will be created as child devices)
|
||||
gw.sendSensorPresentation(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
int lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23;
|
||||
Serial.println(lightLevel);
|
||||
if (lightLevel != lastLightLevel) {
|
||||
gw.sendVariable(CHILD_ID_LIGHT, V_LIGHT_LEVEL, lightLevel);
|
||||
lastLightLevel = lightLevel;
|
||||
}
|
||||
|
||||
// Power down the radio. Note that the radio will get powered back up
|
||||
// on the next write() call.
|
||||
delay(1000); //delay to allow serial to fully print before sleep
|
||||
gw.powerDown();
|
||||
sleep.pwrDownMode(); //set sleep mode
|
||||
sleep.sleepDelay(SLEEP_TIME * 1000); //sleep for: sleepTime
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <Sleep_n0m1.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RF24.h>
|
||||
#include <Sensor.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
|
||||
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your motion sensor. (Only 2 and 3 generates interrupt!)
|
||||
#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
|
||||
#define CHILD_ID 0 // Id of the sensor child
|
||||
|
||||
Sensor gw(9,10);
|
||||
|
||||
Sleep sleep;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to type in characters
|
||||
gw.begin(RADIO_ID);
|
||||
pinMode(DIGITAL_INPUT_SENSOR, INPUT); // sets the motion sensor digital pin as input
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
gw.sendSensorPresentation(CHILD_ID, S_MOTION);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Read digital motion value
|
||||
boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH;
|
||||
|
||||
Serial.println(tripped);
|
||||
gw.sendVariable(CHILD_ID, V_TRIPPED, tripped?"1":"0"); // Send tripped value to gw
|
||||
|
||||
// Power down the radio. Note that the radio will get powered back up
|
||||
// on the next write() call.
|
||||
delay(200); //delay to allow serial to fully print before sleep
|
||||
gw.powerDown();
|
||||
sleep.pwrDownMode(); //set sleep mode
|
||||
sleep.sleepInterrupt(INTERRUPT,CHANGE);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
#include <Sleep_n0m1.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RF24.h>
|
||||
#include <Sensor.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_BMP085.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
|
||||
#define LIGHT_SENSOR_ANALOG_PIN 0
|
||||
|
||||
unsigned long SLEEP_TIME = 60; // Sleep time between reads (in seconds)
|
||||
|
||||
Adafruit_BMP085 bmp = Adafruit_BMP085(); // Digital Pressure Sensor
|
||||
Sensor gw(9, 10);
|
||||
|
||||
float lastPressure = -1;
|
||||
float lastTemp = -1;
|
||||
int lastForecast = -1;
|
||||
Sleep sleep;
|
||||
char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"};
|
||||
int minutes;
|
||||
float pressureSamples[180];
|
||||
int minuteCount = 0;
|
||||
bool firstRound = true;
|
||||
float pressureAvg[7];
|
||||
float dP_dt;
|
||||
boolean metric;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(BAUD_RATE); // Used to type in characters
|
||||
gw.begin(RADIO_ID);
|
||||
if (!bmp.begin()) {
|
||||
Serial.println("Could not find a valid BMP085 sensor, check wiring!");
|
||||
while (1) { }
|
||||
}
|
||||
|
||||
// Register sensors to gw (they will be created as child devices)
|
||||
gw.sendSensorPresentation(0, S_BARO);
|
||||
gw.sendSensorPresentation(1, S_TEMP);
|
||||
metric = gw.isMetricSystem();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
float pressure = bmp.readPressure();
|
||||
float temperature = bmp.readTemperature();
|
||||
|
||||
if (!metric) {
|
||||
// Convert to fahrenheit
|
||||
temperature = temperature * 9.0 / 5.0 + 32.0;
|
||||
}
|
||||
|
||||
int forecast = sample(pressure);
|
||||
|
||||
Serial.print("Temperature = ");
|
||||
Serial.print(temperature);
|
||||
Serial.println(metric?" *C":" *F");
|
||||
Serial.print("Pressure = ");
|
||||
Serial.print(pressure);
|
||||
Serial.println(" Pa");
|
||||
Serial.println(weather[forecast]);
|
||||
|
||||
|
||||
if (temperature != lastTemp) {
|
||||
gw.sendVariable(1, V_TEMP, temperature,1);
|
||||
lastTemp = temperature;
|
||||
}
|
||||
|
||||
if (pressure != lastPressure) {
|
||||
gw.sendVariable(0, V_PRESSURE, pressure, 0);
|
||||
lastPressure = pressure;
|
||||
}
|
||||
|
||||
if (forecast != lastForecast) {
|
||||
gw.sendVariable(0, V_FORECAST, weather[forecast]);
|
||||
lastForecast = forecast;
|
||||
}
|
||||
|
||||
/*
|
||||
DP/Dt explanation
|
||||
|
||||
0 = "Stable Weather Pattern"
|
||||
1 = "Slowly rising Good Weather", "Clear/Sunny "
|
||||
2 = "Slowly falling L-Pressure ", "Cloudy/Rain "
|
||||
3 = "Quickly rising H-Press", "Not Stable"
|
||||
4 = "Quickly falling L-Press", "Thunderstorm"
|
||||
5 = "Unknown (More Time needed)
|
||||
*/
|
||||
|
||||
// Power down the radio. Note that the radio will get powered back up
|
||||
// on the next write() call.
|
||||
delay(1000); //delay to allow serial to fully print before sleep
|
||||
gw.powerDown();
|
||||
sleep.pwrDownMode(); //set sleep mode
|
||||
sleep.sleepDelay(SLEEP_TIME * 1000); // sleep to conserve power
|
||||
}
|
||||
|
||||
int sample(float pressure) {
|
||||
// Algorithm found here
|
||||
// http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf
|
||||
if (minuteCount > 180)
|
||||
minuteCount = 6;
|
||||
|
||||
pressureSamples[minuteCount] = pressure;
|
||||
minuteCount++;
|
||||
|
||||
if (minuteCount == 5) {
|
||||
// Avg pressure in first 5 min, value averaged from 0 to 5 min.
|
||||
pressureAvg[0] = ((pressureSamples[1] + pressureSamples[2]
|
||||
+ pressureSamples[3] + pressureSamples[4] + pressureSamples[5])
|
||||
/ 5);
|
||||
} else if (minuteCount == 35) {
|
||||
// Avg pressure in 30 min, value averaged from 0 to 5 min.
|
||||
pressureAvg[1] = ((pressureSamples[30] + pressureSamples[31]
|
||||
+ pressureSamples[32] + pressureSamples[33]
|
||||
+ pressureSamples[34]) / 5);
|
||||
float change = (pressureAvg[1] - pressureAvg[0]);
|
||||
if (firstRound) // first time initial 3 hour
|
||||
dP_dt = ((65.0 / 1023.0) * 2 * change); // note this is for t = 0.5hour
|
||||
else
|
||||
dP_dt = (((65.0 / 1023.0) * change) / 1.5); // divide by 1.5 as this is the difference in time from 0 value.
|
||||
} else if (minuteCount == 60) {
|
||||
// Avg pressure at end of the hour, value averaged from 0 to 5 min.
|
||||
pressureAvg[2] = ((pressureSamples[55] + pressureSamples[56]
|
||||
+ pressureSamples[57] + pressureSamples[58]
|
||||
+ pressureSamples[59]) / 5);
|
||||
float change = (pressureAvg[2] - pressureAvg[0]);
|
||||
if (firstRound) //first time initial 3 hour
|
||||
dP_dt = ((65.0 / 1023.0) * change); //note this is for t = 1 hour
|
||||
else
|
||||
dP_dt = (((65.0 / 1023.0) * change) / 2); //divide by 2 as this is the difference in time from 0 value
|
||||
} else if (minuteCount == 95) {
|
||||
// Avg pressure at end of the hour, value averaged from 0 to 5 min.
|
||||
pressureAvg[3] = ((pressureSamples[90] + pressureSamples[91]
|
||||
+ pressureSamples[92] + pressureSamples[93]
|
||||
+ pressureSamples[94]) / 5);
|
||||
float change = (pressureAvg[3] - pressureAvg[0]);
|
||||
if (firstRound) // first time initial 3 hour
|
||||
dP_dt = (((65.0 / 1023.0) * change) / 1.5); // note this is for t = 1.5 hour
|
||||
else
|
||||
dP_dt = (((65.0 / 1023.0) * change) / 2.5); // divide by 2.5 as this is the difference in time from 0 value
|
||||
} else if (minuteCount == 120) {
|
||||
// Avg pressure at end of the hour, value averaged from 0 to 5 min.
|
||||
pressureAvg[4] = ((pressureSamples[115] + pressureSamples[116]
|
||||
+ pressureSamples[117] + pressureSamples[118]
|
||||
+ pressureSamples[119]) / 5);
|
||||
float change = (pressureAvg[4] - pressureAvg[0]);
|
||||
if (firstRound) // first time initial 3 hour
|
||||
dP_dt = (((65.0 / 1023.0) * change) / 2); // note this is for t = 2 hour
|
||||
else
|
||||
dP_dt = (((65.0 / 1023.0) * change) / 3); // divide by 3 as this is the difference in time from 0 value
|
||||
} else if (minuteCount == 155) {
|
||||
// Avg pressure at end of the hour, value averaged from 0 to 5 min.
|
||||
pressureAvg[5] = ((pressureSamples[150] + pressureSamples[151]
|
||||
+ pressureSamples[152] + pressureSamples[153]
|
||||
+ pressureSamples[154]) / 5);
|
||||
float change = (pressureAvg[5] - pressureAvg[0]);
|
||||
if (firstRound) // first time initial 3 hour
|
||||
dP_dt = (((65.0 / 1023.0) * change) / 2.5); // note this is for t = 2.5 hour
|
||||
else
|
||||
dP_dt = (((65.0 / 1023.0) * change) / 3.5); // divide by 3.5 as this is the difference in time from 0 value
|
||||
} else if (minuteCount == 180) {
|
||||
// Avg pressure at end of the hour, value averaged from 0 to 5 min.
|
||||
pressureAvg[6] = ((pressureSamples[175] + pressureSamples[176]
|
||||
+ pressureSamples[177] + pressureSamples[178]
|
||||
+ pressureSamples[179]) / 5);
|
||||
float change = (pressureAvg[6] - pressureAvg[0]);
|
||||
if (firstRound) // first time initial 3 hour
|
||||
dP_dt = (((65.0 / 1023.0) * change) / 3); // note this is for t = 3 hour
|
||||
else
|
||||
dP_dt = (((65.0 / 1023.0) * change) / 4); // divide by 4 as this is the difference in time from 0 value
|
||||
pressureAvg[0] = pressureAvg[5]; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past.
|
||||
firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop.
|
||||
}
|
||||
|
||||
if (minuteCount < 35 && firstRound) //if time is less than 35 min on the first 3 hour interval.
|
||||
return 5; // Unknown, more time needed
|
||||
else if (dP_dt < (-0.25))
|
||||
return 4; // Quickly falling LP, Thunderstorm, not stable
|
||||
else if (dP_dt > 0.25)
|
||||
return 3; // Quickly rising HP, not stable weather
|
||||
else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05)))
|
||||
return 2; // Slowly falling Low Pressure System, stable rainy weather
|
||||
else if ((dP_dt > 0.05) && (dP_dt < 0.25))
|
||||
return 1; // Slowly rising HP stable good weather
|
||||
else if ((dP_dt > (-0.05)) && (dP_dt < 0.05))
|
||||
return 0; // Stable weather
|
||||
else
|
||||
return 5; // Unknown
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
// Example sketch showing how to control physical relays.
|
||||
|
||||
#include <Relay.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RF24.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
|
||||
#define RELAY_1 3 // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
|
||||
#define NUMBER_OF_RELAYS 2
|
||||
|
||||
#define RELAY_ON 0
|
||||
#define RELAY_OFF 1
|
||||
|
||||
Relay gw(9,10);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to write debug info
|
||||
|
||||
gw.begin(RADIO_ID);
|
||||
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
for (int i=0; i<NUMBER_OF_RELAYS;i++) {
|
||||
gw.sendSensorPresentation(RELAY_1+i, S_LIGHT);
|
||||
}
|
||||
|
||||
// Fetch relay status
|
||||
for (int i=0; i<NUMBER_OF_RELAYS;i++) {
|
||||
// Make sure relays are off when starting up
|
||||
digitalWrite(RELAY_1+i, RELAY_OFF);
|
||||
// Then set relay pins in output mode
|
||||
pinMode(RELAY_1+i, OUTPUT);
|
||||
|
||||
// Request/wait for relay status
|
||||
gw.getStatus(RELAY_1+i, V_LIGHT);
|
||||
setRelayStatus(gw.getMessage()); // Wait here until status message arrive from gw
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Example on how to asynchronously check for new messages from gw
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
if (gw.messageAvailable()) {
|
||||
message_s message = gw.getMessage();
|
||||
setRelayStatus(message);
|
||||
}
|
||||
}
|
||||
|
||||
void setRelayStatus(message_s message) {
|
||||
if (message.header.messageType=M_SET_VARIABLE &&
|
||||
message.header.type==V_LIGHT) {
|
||||
int incomingRelayStatus = atoi(message.data);
|
||||
// Change relay state
|
||||
digitalWrite(message.header.childId, incomingRelayStatus==1?RELAY_ON:RELAY_OFF);
|
||||
// Write some debug info
|
||||
Serial.print("Incoming change for relay on pin:");
|
||||
Serial.print(message.header.childId);
|
||||
Serial.print(", New status: ");
|
||||
Serial.println(incomingRelayStatus);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// Example sketch för a "light switch" where you can control light or something
|
||||
// else from both vera and a local physical button (connected between digital
|
||||
// pin 3 and +5V).
|
||||
|
||||
#include <Relay.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RF24.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
#define RELAY_PIN 4 // Arduino Digital I/O pin number for relay
|
||||
#define BUTTON_PIN 3 // Arduino Digital I/O pin number for button (with 10k pulldown)
|
||||
|
||||
#define CHILD_ID 1 // Id of the sensor child
|
||||
|
||||
#define RELAY_ON 0
|
||||
#define RELAY_OFF 1
|
||||
|
||||
int buttVal;
|
||||
int previousVal;
|
||||
int state;
|
||||
int switched = 0;
|
||||
long pressTime = 0; // the last time the button pin was pressed
|
||||
long debounce = 200; // the debounce time, increase if the output flickers
|
||||
|
||||
Relay gw(9,10);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to write debug info
|
||||
|
||||
gw.begin(RADIO_ID);
|
||||
|
||||
// Set buttonPin as Input
|
||||
pinMode(BUTTON_PIN, INPUT);
|
||||
buttVal = digitalRead(BUTTON_PIN); //read initial state
|
||||
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
gw.sendSensorPresentation(CHILD_ID, S_LIGHT);
|
||||
|
||||
// Make sure relays are off when starting up
|
||||
digitalWrite(RELAY_PIN, RELAY_OFF);
|
||||
// Then set relay pins in output mode
|
||||
pinMode(RELAY_PIN, OUTPUT);
|
||||
|
||||
// Request/wait for relay status
|
||||
gw.getStatus(CHILD_ID, V_LIGHT);
|
||||
setRelayStatus(gw.getMessage()); // Wait here until status message arrive from gw
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Example on how to asynchronously check for new messages from gw
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
if (gw.messageAvailable()) {
|
||||
// ot new messsage from gw
|
||||
message_s message = gw.getMessage();
|
||||
setRelayStatus(message);
|
||||
}
|
||||
|
||||
buttVal = digitalRead(BUTTON_PIN); // read input value and store it in val
|
||||
|
||||
if (buttVal == HIGH && previousVal == LOW) {
|
||||
// Start counter from when button was pressed
|
||||
pressTime = millis();
|
||||
switched = 0;
|
||||
}
|
||||
|
||||
if (buttVal == HIGH && switched == 0 && millis() - pressTime > debounce) {
|
||||
// Switch state if button pressed more than 200 msec
|
||||
state = state==1?0:1;
|
||||
gw.sendVariable(CHILD_ID, V_LIGHT, state); // We will receive an ack message
|
||||
switched = 1; // No more switches until button is released
|
||||
}
|
||||
previousVal = buttVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void setRelayStatus(message_s message) {
|
||||
if (message.header.type==V_LIGHT) { // This could be M_ACK_VARIABLE or M_SET_VARIABLE
|
||||
state = atoi(message.data);
|
||||
// Change relay state
|
||||
digitalWrite(RELAY_PIN, state==1?RELAY_ON:RELAY_OFF);
|
||||
// Write some debug info
|
||||
Serial.print(message.header.messageType == M_ACK_VARIABLE ? "Button":"Gateway");
|
||||
Serial.print(" change. New state: ");
|
||||
Serial.println(state == 1 ?"on":"off" );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Example sketch showing how to create a node thay relays messages
|
||||
// from nodes far from gateway back to gateway.
|
||||
// Important here is that node uses Relay-class and calls
|
||||
// gw.messageAvailable() frequently. This sketch should not
|
||||
// sleep.
|
||||
|
||||
#include <Relay.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RF24.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
|
||||
Relay gw(9,10);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to write debug info
|
||||
gw.begin(RADIO_ID);
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (gw.messageAvailable()) {
|
||||
// Incoming message for this node...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Example showing how to create an atuator for a servo.
|
||||
// Connect red to +5V, Black or brown to GND and the last cable to Digital pin 3.
|
||||
// The servo consumes much power and should probably have its own powersource.'
|
||||
// The arduino might spontanally restart if too much power is used (happend
|
||||
// to me when servo tried to pass the extreme positions = full load).
|
||||
|
||||
#include <Sensor.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <Servo.h>
|
||||
#include <RF24.h>
|
||||
|
||||
#define SERVO_DIGITAL_OUT_PIN 3
|
||||
#define SERVO_MIN 30 // Fine tune your servos min. 0-180
|
||||
#define SERVO_MAX 180 // Fine tune your servos max. 0-180
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
#define CHILD_ID 10 // Id of the sensor child
|
||||
|
||||
Sensor gw(9, 10);
|
||||
Servo myservo; // create servo object to control a servo
|
||||
// a maximum of eight servo objects can be created Sensor gw(9,10);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE);
|
||||
gw.begin(RADIO_ID);
|
||||
myservo.attach(SERVO_DIGITAL_OUT_PIN);
|
||||
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
gw.sendSensorPresentation(CHILD_ID, S_COVER);
|
||||
|
||||
// Fetch servo state at startup
|
||||
gw.getStatus(CHILD_ID, V_DIMMER);
|
||||
setRelayStatus(gw.getMessage()); // Wait here until status message arrive from gw
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (gw.messageAvailable()) {
|
||||
// New messsage from gw
|
||||
message_s message = gw.getMessage();
|
||||
setRelayStatus(message);
|
||||
}
|
||||
}
|
||||
|
||||
void setRelayStatus(message_s message) {
|
||||
if (message.header.type==V_DIMMER) { // This could be M_ACK_VARIABLE or M_SET_VARIABLE
|
||||
int val = atoi(message.data);
|
||||
myservo.write(SERVO_MIN + (SERVO_MAX-SERVO_MIN)/100 * val); // sets the servo position 0-180
|
||||
// Write some debug info
|
||||
Serial.print("Servo changed. new state: ");
|
||||
Serial.println(val);
|
||||
} else if (message.header.type==V_UP) {
|
||||
Serial.println("Servo UP command");
|
||||
myservo.write(SERVO_MAX);
|
||||
gw.sendVariable(CHILD_ID, V_DIMMER, 100);
|
||||
} else if (message.header.type==V_DOWN) {
|
||||
Serial.println("Servo DOWN command");
|
||||
myservo.write(SERVO_MIN);
|
||||
gw.sendVariable(CHILD_ID, V_DIMMER, 0);
|
||||
} else if (message.header.type==V_STOP) {
|
||||
Serial.println("Servo STOP command");
|
||||
// Servo is pretty fast.. don't think we have time to send a stop
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include <Sleep_n0m1.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RF24.h>
|
||||
#include <Sensor.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
|
||||
#define DIGITAL_INPUT_SOIL_SENSOR 3 // Digital input did you attach your soil sensor.
|
||||
#define INTERRUPT DIGITAL_INPUT_SOIL_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
|
||||
#define CHILD_ID 0 // Id of the sensor child
|
||||
|
||||
Sensor gw(9, 10);
|
||||
Sleep sleep;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to type in characters
|
||||
gw.begin(RADIO_ID);
|
||||
|
||||
pinMode(DIGITAL_INPUT_SOIL_SENSOR, INPUT); // sets the soil sensor digital pin as input
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
gw.sendSensorPresentation(CHILD_ID, S_MOTION);
|
||||
|
||||
}
|
||||
|
||||
int lastSoilValue = -1;
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Read digital soil value
|
||||
int soilValue = digitalRead(DIGITAL_INPUT_SOIL_SENSOR); // 1 = Not triggered, 0 = In soil with water
|
||||
if (soilValue != lastSoilValue) {
|
||||
Serial.println(soilValue);
|
||||
gw.sendVariable(CHILD_ID, V_TRIPPED, soilValue==0?"1":"0"); // Send the inverse to gw as tripped should be when no water in soil
|
||||
lastSoilValue = soilValue;
|
||||
}
|
||||
// Power down the radio. Note that the radio will get powered back up
|
||||
// on the next write() call.
|
||||
gw.powerDown();
|
||||
sleep.pwrDownMode(); //set sleep mode
|
||||
sleep.sleepInterrupt(INTERRUPT,CHANGE);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
|
||||
// Example sketch showing how to request time from vera
|
||||
// and how to set a cutom variable on a sensor
|
||||
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RF24.h>
|
||||
#include <Sensor.h>
|
||||
#include <Time.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
|
||||
#define CHILD_ID 0 // Id of the sensor child
|
||||
|
||||
Sensor gw(9, 10);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to type in characters
|
||||
gw.begin(RADIO_ID);
|
||||
|
||||
// Register any sensortype. This example we just create a motion sensor.
|
||||
gw.sendSensorPresentation(CHILD_ID, S_MOTION);
|
||||
|
||||
setSyncProvider(getTime);
|
||||
setSyncInterval(3600); // get time from gw every hour
|
||||
}
|
||||
|
||||
unsigned long getTime() {
|
||||
return gw.getTime(); // Vera is time provider
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// long time = gw.getTime();
|
||||
// setTime(time);
|
||||
|
||||
Serial.print(hour());
|
||||
printDigits(minute());
|
||||
printDigits(second());
|
||||
Serial.print(" ");
|
||||
Serial.print(day());
|
||||
Serial.print(" ");
|
||||
Serial.print(month());
|
||||
Serial.print(" ");
|
||||
Serial.print(year());
|
||||
Serial.println();
|
||||
|
||||
// Ok now send time back to gw and store in in Variable1
|
||||
// of the motion sensor device
|
||||
gw.sendVariable(CHILD_ID, V_VAR1, minute());
|
||||
|
||||
// wait 10 seconds...
|
||||
delay(10000);
|
||||
}
|
||||
|
||||
void printDigits(int digits){
|
||||
// utility function for digital clock display: prints preceding colon and leading 0
|
||||
Serial.print(":");
|
||||
if(digits < 10)
|
||||
Serial.print('0');
|
||||
Serial.print(digits);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
//
|
||||
// Use this sensor to measure volume and flow of your house watermeter.
|
||||
// You need to set the correct pulsefactor of your meter (pulses per m3).
|
||||
// The sensor starts by fetching current volume reading from gateway (VAR 1).
|
||||
// Reports both volume and flow back to gateway.
|
||||
//
|
||||
// Unfortunately millis() won't increment when the Arduino is in
|
||||
// sleepmode. So we cannot make this sensor sleep if we also want
|
||||
// to calculate/report flow.
|
||||
//
|
||||
// Sensor on pin 3
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
#include <Relay.h>
|
||||
#include <Sleep_n0m1.h>
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
#include <RF24.h>
|
||||
#include <Sensor.h>
|
||||
|
||||
// Set RADIO_ID to something unique in your sensor network (1-254)
|
||||
// or set to AUTO if you want gw to assign a RADIO_ID for you.
|
||||
#define RADIO_ID AUTO
|
||||
|
||||
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!)
|
||||
#define PULSE_FACTOR 1000 // Nummber of blinks per m3 of your meter (One rotation/liter)
|
||||
#define SLEEP_MODE false // flowvalue can only be reported when sleep mode is false.
|
||||
#define MAX_FLOW 40 // Max flow (l/min) value to report. This filetrs outliers.
|
||||
unsigned long SEND_FREQUENCY = 20; // Minimum time between send (in seconds). We don't want to spam the gateway.
|
||||
#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
|
||||
#define CHILD_ID 5 // Id of the sensor child
|
||||
|
||||
|
||||
|
||||
|
||||
Sensor gw(9,10);
|
||||
|
||||
//enable sleep
|
||||
Sleep sleep;
|
||||
|
||||
double ppl = ((double)PULSE_FACTOR)/1000; // Pulses per liter
|
||||
|
||||
volatile unsigned long pulseCount = 0;
|
||||
volatile unsigned long lastBlink = 0;
|
||||
volatile double flow = 0;
|
||||
unsigned long oldPulseCount = 0;
|
||||
unsigned long newBlink = 0;
|
||||
double oldflow = 0;
|
||||
double volume;
|
||||
double oldvolume;
|
||||
unsigned long lastSend;
|
||||
unsigned long lastPulse;
|
||||
unsigned long currentTime;
|
||||
boolean metric;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUD_RATE); // Used to type in characters
|
||||
gw.begin(RADIO_ID);
|
||||
|
||||
// Register this device as Waterflow sensor
|
||||
gw.sendSensorPresentation(CHILD_ID, S_WATER);
|
||||
|
||||
// Fetch last known pulse count value from gw
|
||||
pulseCount = oldPulseCount = atol(gw.getStatus(CHILD_ID, V_VAR1));
|
||||
//Serial.print("Last pulse count from gw:");
|
||||
//Serial.println(pulseCount);
|
||||
attachInterrupt(INTERRUPT, onPulse, RISING);
|
||||
lastSend = millis();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
currentTime = millis();
|
||||
|
||||
// Only send values at a maximum frequency or woken up from sleep
|
||||
if (SLEEP_MODE || currentTime - lastSend > 1000*SEND_FREQUENCY) {
|
||||
// New flow value has been calculated
|
||||
if (!SLEEP_MODE && flow != oldflow) {
|
||||
// Check that we dont get unresonable large flow value.
|
||||
// could hapen when long wraps or false interrupt triggered
|
||||
if (flow<((unsigned long)MAX_FLOW)) {
|
||||
gw.sendVariable(CHILD_ID, V_FLOW, flow, 2); // Send flow value to gw
|
||||
}
|
||||
//Serial.print("l/min:");
|
||||
//Serial.println(flow);
|
||||
oldflow = flow;
|
||||
}
|
||||
|
||||
// No Pulse count in 2min
|
||||
|
||||
//Serial.print("currentTime");
|
||||
//Serial.println(currentTime);
|
||||
//Serial.print("lastPulse");
|
||||
//Serial.println(lastPulse);
|
||||
|
||||
if(currentTime - lastPulse > 120000){
|
||||
flow = 0;
|
||||
}
|
||||
|
||||
|
||||
// Pulse count has changed
|
||||
if (pulseCount != oldPulseCount) {
|
||||
gw.sendVariable(CHILD_ID, V_VAR1, pulseCount); // Send volumevalue to gw VAR1
|
||||
double volume = ((double)pulseCount/((double)PULSE_FACTOR));
|
||||
oldPulseCount = pulseCount;
|
||||
//Serial.print("Pulse count:");
|
||||
//Serial.println(pulseCount);
|
||||
if (volume != oldvolume) {
|
||||
gw.sendVariable(CHILD_ID, V_VOLUME, volume, 3); // Send volume value to gw
|
||||
//Serial.print("m3:");
|
||||
//Serial.println(volume, 3);
|
||||
oldvolume = volume;
|
||||
}
|
||||
}
|
||||
lastSend = currentTime;
|
||||
}
|
||||
|
||||
if (SLEEP_MODE) {
|
||||
delay(300); //delay to allow serial to fully print before sleep
|
||||
gw.powerDown();
|
||||
sleep.pwrDownMode(); //set sleep mode
|
||||
sleep.sleepDelay(SEND_FREQUENCY * 1000); //sleep for: sleepTime
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void onPulse()
|
||||
{
|
||||
if (!SLEEP_MODE) {
|
||||
unsigned long newBlink = micros();
|
||||
unsigned long interval = newBlink-lastBlink;
|
||||
lastPulse = millis();
|
||||
if (interval<500000L) {
|
||||
// Sometimes we get interrupt on RISING, 500000 = 0.5sek debounce ( max 120 l/min)
|
||||
return;
|
||||
}
|
||||
|
||||
flow = (60000000.0 /interval) / ppl;
|
||||
lastBlink = newBlink;
|
||||
//Serial.println(flow, 4);
|
||||
}
|
||||
pulseCount++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user