Merge remote-tracking branch 'upstream/development' into

gateway-refactoring

# Conflicts:
#	libraries/MySensors/MyConfig.h
#	libraries/MySensors/MySensor.cpp
This commit is contained in:
Henrik Ekblad
2015-09-11 10:56:19 +02:00
102 changed files with 4463 additions and 974 deletions
+8
View File
@@ -4,3 +4,11 @@ Arduino
MySensors Arduino Library v1.5
Please visit www.mysensors.org for more information
Current build status of master branch: [![Build Status](http://ci.mysensors.org/job/MySensorsArduino/branch/master/badge/icon)](http://ci.mysensors.org/job/MySensorsArduino/branch/master/)
Current build status of development branch: [![Build Status](http://ci.mysensors.org/job/MySensorsArduino/branch/development/badge/icon)](http://ci.mysensors.org/job/MySensorsArduino/branch/development/)
Current build status of master branch (nightly build of Arduino IDE): [![Build Status](http://ci.mysensors.org/job/MySensorsArduinoNightly/branch/master/badge/icon)](http://ci.mysensors.org/job/MySensorsArduinoNightly/branch/master/)
Current build status of development branch (nightly build of Arduino IDE): [![Build Status](http://ci.mysensors.org/job/MySensorsArduinoNightly/branch/development/badge/icon)](http://ci.mysensors.org/job/MySensorsArduinoNightly/branch/development/)
+9 -3
View File
@@ -11,17 +11,23 @@ version=1.6.0
# AVR compile variables
# ---------------------
compiler.warning_flags=-w
compiler.warning_flags.none=-w
compiler.warning_flags.default=
compiler.warning_flags.more=-Wall
compiler.warning_flags.all=-Wall -Wextra
# Default "compiler.path" is correct, change only if you want to overidde the initial value
compiler.path={runtime.tools.avr-gcc.path}/bin/
compiler.c.cmd=avr-gcc
compiler.c.flags=-c -g -Os -w -ffunction-sections -fdata-sections -MMD
compiler.c.flags=-c -g -Os {compiler.warning_flags} -ffunction-sections -fdata-sections -MMD
# -w flag added to avoid printing a wrong warning http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59396
# This is fixed in gcc 4.8.3 and will be removed as soon as we update the toolchain
compiler.c.elf.flags=-w -Os -Wl,--gc-sections
compiler.c.elf.flags={compiler.warning_flags} -Os -Wl,--gc-sections
compiler.c.elf.cmd=avr-gcc
compiler.S.flags=-c -g -x assembler-with-cpp
compiler.cpp.cmd=avr-g++
compiler.cpp.flags=-c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD
compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD
compiler.ar.cmd=avr-ar
compiler.ar.flags=rcs
compiler.objcopy.cmd=avr-objcopy
+2 -2
View File
@@ -18,7 +18,7 @@ Bounce::Bounce() {
void Bounce::attach(int pin) {
this->pin = pin;
debouncedState = unstableState = digitalRead(pin);
#ifdef BOUNCE_LOCK-OUT
#ifdef BOUNCE_LOCK_OUT
previous_millis = 0;
#else
previous_millis = millis();
@@ -37,7 +37,7 @@ void Bounce::interval(unsigned long interval_millis)
bool Bounce::update()
{
#ifdef BOUNCE_LOCK-OUT
#ifdef BOUNCE_LOCK_OUT
stateChanged = false;
// Ignore everything if we are locked out
if (millis() - previous_millis >= interval_millis) {
+1 -1
View File
@@ -24,7 +24,7 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Uncomment the following line for "LOCK-OUT" debounce method
//#define BOUNCE_LOCK-OUT
//#define BOUNCE_LOCK_OUT
#ifndef Bounce2_h
+3 -3
View File
@@ -142,9 +142,9 @@ void DHT::readSensor()
// - Then 40 bits: RISING and then a FALLING edge per bit
// To keep our code simple, we accept any HIGH or LOW reading if it's max 85 usecs long
word rawHumidity;
word rawTemperature;
word data;
word rawHumidity = 0;
word rawTemperature = 0;
word data = 0;
for ( int8_t i = -3 ; i < 2 * 40; i++ ) {
byte age;
@@ -700,6 +700,7 @@ void DallasTemperature::setAlarmHandler(AlarmHandler *handler)
// The default alarm handler
void DallasTemperature::defaultAlarmHandler(const uint8_t* deviceAddress)
{
(void)deviceAddress;
}
#endif
-1
View File
@@ -50,7 +50,6 @@
*/
bool I2cMasterBase::transfer(uint8_t addrRW,
void *buf, size_t nbytes, uint8_t option) {
uint8_t* p = reinterpret_cast<uint8_t*>(buf);
if (_state != STATE_REP_START) {
start();
}
+2 -2
View File
@@ -132,7 +132,7 @@ class SoftI2cMaster : public I2cMasterBase {
//----------------------------------------------------------------------------
void sclDelay(uint8_t n) {_delay_loop_1(n);}
//----------------------------------------------------------------------------
bool writeScl(bool value) {
void writeScl(bool value) {
uint8_t s = SREG;
noInterrupts();
if (value == LOW) {
@@ -145,7 +145,7 @@ class SoftI2cMaster : public I2cMasterBase {
SREG = s;
}
//----------------------------------------------------------------------------
bool writeSda(bool value) {
void writeSda(bool value) {
uint8_t s = SREG;
noInterrupts();
if (value == LOW) {
+9 -3
View File
@@ -649,7 +649,7 @@ bool IRdecodeRC6::decode(void) {
* Hopefully this code is unique for each button.
*/
#define FNV_PRIME_32 16777619
#define FNV_BASIS_32 2166136261
#define FNV_BASIS_32 2166136261UL
// Compare two tick values, returning 0 if newval is shorter,
// 1 if newval is equal, and 2 if newval is longer
int IRdecodeHash::compare(unsigned int oldval, unsigned int newval) {
@@ -730,12 +730,12 @@ void IRrecvBase::resume() {
bool IRrecvLoop::GetResults(IRdecodeBase *decoder) {
bool Finished=false;
byte OldState=HIGH;byte NewState;
unsigned long StartTime, DeltaTime, EndTime;
unsigned long StartTime, DeltaTime=0, EndTime=0;
StartTime=micros();
while(irparams.rawlen<RAWBUF) { //While the buffer not overflowing
while(OldState==(NewState=digitalRead(irparams.recvpin))) { //While the pin hasn't changed
if( (DeltaTime = (EndTime=micros()) - StartTime) > 10000) { //If it's a very long wait
if(Finished=irparams.rawlen) break; //finished unless it's the opening gap
if((Finished=irparams.rawlen)) break; //finished unless it's the opening gap
}
}
if(Finished) break;
@@ -798,6 +798,9 @@ void IRrecvPCI_Handler(){
case STATE_IDLE:
if(digitalRead(irparams.recvpin)) return; else irparams.rcvstate=STATE_RUNNING;
break;
default:
// what of STATE_UNKNOWN, STATE_MARK and STATE_SPACE?
break;
};
irparams.rawbuf[irparams.rawlen]=DeltaTime;
irparams.timer=ChangeTime;
@@ -982,6 +985,9 @@ ISR(TIMER_INTR_NAME)
irparams.timer = 0;
}
break;
default:
// what of STATE_UNKNOWN and STATE_RUNNING?
break;
}
do_Blink();
}
+1 -1
View File
@@ -48,7 +48,7 @@
#define RAWBUF 100 // Length of raw duration buffer (cannot exceed 255)
typedef char IRTYPES; //formerly was an enum
typedef unsigned char IRTYPES; //formerly was an enum
#define UNKNOWN 0
#define NEC 1
#define SONY 2
+8 -6
View File
@@ -90,6 +90,8 @@ inline static void waitUsec ( uint16_t uSec )
{
#ifndef FAST_MODE
delayMicroseconds ( uSec );
#else
(void)uSec;
#endif // FAST_MODE
}
@@ -481,7 +483,7 @@ public:
@param value: pin associated to backlight control.
@param pol: backlight polarity control (POSITIVE, NEGATIVE)
*/
virtual void setBacklightPin ( uint8_t value, t_backlighPol pol ) { };
virtual void setBacklightPin ( uint8_t /*value*/, t_backlighPol /*pol*/ ) { };
/*!
@function
@@ -500,7 +502,7 @@ public:
BACKLIGHT_OFF will be interpreted as off and BACKLIGHT_ON will drive the
backlight on.
*/
virtual void setBacklight ( uint8_t value ) { };
virtual void setBacklight ( uint8_t /*value*/ ) { };
/*!
@function
@@ -514,9 +516,9 @@ public:
@param value[in] Value to write to the LCD.
*/
#if (ARDUINO < 100)
virtual void write(uint8_t value);
virtual void write(uint8_t /*value*/);
#else
virtual size_t write(uint8_t value);
virtual size_t write(uint8_t /*value*/);
#endif
#if (ARDUINO < 100)
@@ -566,9 +568,9 @@ private:
the LCD.
*/
#if (ARDUINO < 100)
virtual void send(uint8_t value, uint8_t mode) { };
virtual void send(uint8_t /*value*/, uint8_t /*mode*/) { };
#else
virtual void send(uint8_t value, uint8_t mode) = 0;
virtual void send(uint8_t /*value*/, uint8_t /*mode*/) = 0;
#endif
};
@@ -38,7 +38,7 @@
LiquidCrystal_I2C_ByVac::LiquidCrystal_I2C_ByVac( uint8_t lcd_Addr )
{
_Addr = lcd_Addr;
_polarity == NEGATIVE;
_polarity = NEGATIVE;
}
// PUBLIC METHODS
+4 -2
View File
@@ -110,6 +110,8 @@ LiquidCrystal_SR::LiquidCrystal_SR (uint8_t srdata, uint8_t srclock,
void LiquidCrystal_SR::init(uint8_t srdata, uint8_t srclock, uint8_t enable,
uint8_t lines, uint8_t font)
{
(void)lines;
(void)font;
// Initialise private variables
_two_wire = 0;
@@ -200,10 +202,10 @@ void LiquidCrystal_SR::send(uint8_t value, uint8_t mode)
//
// setBacklightPin
void LiquidCrystal_SR::setBacklightPin ( uint8_t pin, t_backlighPol pol )
{ }
{ (void)pin; (void)pol; }
//
// setBacklight
void LiquidCrystal_SR::setBacklight ( uint8_t mode )
{ }
{ (void)mode; }
@@ -49,6 +49,8 @@ LiquidCrystal_SR1W::LiquidCrystal_SR1W (uint8_t srdata, t_sr1w_circuitType circu
// init
void LiquidCrystal_SR1W::init(uint8_t srdata, t_sr1w_circuitType circuitType, t_backlighPol blpol, uint8_t lines, uint8_t font)
{
(void)lines;
(void)font;
_srRegister = fio_pinToOutputRegister(srdata);
_srMask = fio_pinToBit(srdata);
+1 -1
View File
@@ -154,7 +154,7 @@
// | | | / | 1k
// | +--8-|GND Q'H|--9-----+ |
// | | +---------+ | | (GND)--(LCD RW)
// | | 0.1uF | \
/* | | 0.1uF | \ */
// | (GND)-----||----(VCC) +------)--------------(LCD EN)
// | | /
// |----|<|----+--[ Resistor ]--| |
@@ -47,6 +47,8 @@ LiquidCrystal_SR2W::LiquidCrystal_SR2W (uint8_t srdata, uint8_t srclock, t_backl
// init
void LiquidCrystal_SR2W::init(uint8_t srdata, uint8_t srclock, t_backlighPol blpol, uint8_t lines, uint8_t font)
{
(void)lines;
(void)font;
_srDataRegister = fio_pinToOutputRegister(srdata);
_srDataMask = fio_pinToBit(srdata);
_srClockRegister = fio_pinToOutputRegister(srclock);
+25 -8
View File
@@ -24,11 +24,15 @@
// Enable debug flag for debug prints. This will add a lot to the size of the final sketch but good
// to see what is actually is happening when developing
#define DEBUG
#define MY_DEBUG
// Disable this line, If you are using TX(1), RX(0) as normal I/O pin
#define MY_ENABLED_SERIAL
// Serial output baud rate (for debug prints and serial gateway)
#ifndef MY_BAUD_RATE
#define MY_BAUD_RATE 115200
#endif
/**********************************
* Over the air firmware updates
@@ -40,10 +44,13 @@
// requires the MYSBootloader and disabled MY_OTA_FIRMWARE_FEATURE
//#define MY_OTA_FIRMWARE_FEATURE
// Slave select pin for external flash
#ifdef MY_OTA_FLASH_SS
#define MY_OTA_FLASH_SS 8
#endif
// Flash jdecid
#ifdef MY_OTA_FLASH_JDECID
#define MY_OTA_FLASH_JDECID 0x1F65
#endif
/**********************************
* Information LEDs blinking
@@ -63,23 +70,30 @@
// default LEDs blinking period in milliseconds
#ifndef MY_DEFAULT_LED_BLINK_PERIOD
#define MY_DEFAULT_LED_BLINK_PERIOD 300
#endif
// The RX LED default pin
#ifndef MY_DEFAULT_RX_LED_PIN
#define MY_DEFAULT_RX_LED_PIN 6
#endif
// The TX LED default pin
#ifndef MY_DEFAULT_TX_LED_PIN
#define MY_DEFAULT_TX_LED_PIN 5
#endif
// The Error LED default pin
#ifndef MY_DEFAULT_ERR_LED_PIN
#define MY_DEFAULT_ERR_LED_PIN 4
#endif
/**********************************************
* Gateway inclusion button/mode configuration
**********************************************/
// Enabled inclusion mode feature
#define MY_INCLUSION_MODE_FEATURE
//#define MY_INCLUSION_MODE_FEATURE
// Enables inclusion-mode button feature on the gateway device
#define MY_INCLUSION_BUTTON_FEATURE
//#define MY_INCLUSION_BUTTON_FEATURE
// Disable inclusion mode button if inclusion mode feature is not enabled
#ifndef MY_INCLUSION_MODE_FEATURE
@@ -87,9 +101,13 @@
#endif
// The default input pin used for the inclusion mode button
#ifndef MY_INCLUSION_MODE_BUTTON_PIN
#define MY_INCLUSION_MODE_BUTTON_PIN 3
#endif
// Number of seconds (default one minute) inclusion mode should be enabled
#ifndef MY_INCLUSION_MODE_DURATION
#define MY_INCLUSION_MODE_DURATION 60
#endif
/**********************************
* Message Signing Settings
@@ -122,7 +140,6 @@
// Key to use for HMAC calculation in MySigningAtsha204Soft (32 bytes)
#define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
/**********************************
* NRF24L01 Driver Defaults
***********************************/
@@ -170,6 +187,6 @@
//#define IP_ADDRESS_DHCP
// Enable to use UDP instead of plain Ethernet
#define USE_UDP
#define MY_USE_UDP
#endif
-184
View File
@@ -1,184 +0,0 @@
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* 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 "MyGateway.h"
// Inline function and macros
static inline MyMessage& build(MyMessage &msg, uint8_t type) {
msg.sender = GATEWAY_ADDRESS;
msg.destination = GATEWAY_ADDRESS;
msg.sensor = 0;
msg.type = type;
mSetCommand(msg, C_INTERNAL);
mSetRequestAck(msg, false);
mSetAck(msg, false);
return msg;
}
MyGateway::MyGateway(MyGatewayTransport &_transport, MyTransport &_radio,
MyHw &_hw
#ifdef MY_SIGNING_FEATURE
, MySigning &_signer
#endif
#ifdef MY_LEDS_BLINKING_FEATURE
, uint8_t _rx, uint8_t _tx, uint8_t _er, unsigned long _blink_period
#endif
) :
transport(_transport), MySensor(_radio, _hw
#ifdef MY_SIGNING_FEATURE
, _signer
#endif
#ifdef MY_LEDS_BLINKING_FEATURE
, _rx, _tx, _er, _blink_period
#endif
)
{
#ifdef MY_INCLUSION_MODE_FEATURE
inclusionMode = false;
#endif
}
void MyGateway::begin(void (*_msgCallback)(const MyMessage &)
#ifdef MY_INCLUSION_MODE_FEATURE
, int _inclusionModeDuration
#ifdef MY_INCLUSION_BUTTON_FEATURE
, uint8_t _inclusionModeButtonPin
#endif
#endif
) {
// Setup digital in that triggers inclusion mode
#ifdef MY_INCLUSION_MODE_FEATURE
inclusionDuration = _inclusionModeDuration*1000;
#ifdef MY_INCLUSION_BUTTON_FEATURE
inclusionButtonPin = _inclusionModeButtonPin;
pinMode(inclusionButtonPin, INPUT);
digitalWrite(inclusionButtonPin, HIGH);
#endif
#endif
// initialize the transport driver
if (!transport.begin()) {
debug(PSTR("transport driver init fail\n"));
while(1); // Nothing more we can do
}
// Start MySensors in repeater mode
MySensor::begin(_msgCallback, GATEWAY_ADDRESS, true, GATEWAY_ADDRESS);
// Startup complete
transport.send(build(msg, I_GATEWAY_READY).set("Gateway startup complete."));
}
boolean MyGateway::sendRoute(MyMessage &message) {
if (message.destination == GATEWAY_ADDRESS) {
// This is a message sent from a sensor attached on the gateway node.
// Pass it directly to the gateway transport layer.
transport.send(message);
} else {
MySensor::sendRoute(message);
}
}
boolean MyGateway::process() {
#ifdef MY_INCLUSION_MODE_FEATURE
checkInclusionMode();
#endif
bool newMessage = false;
if (transport.available()) {
MyMessage &gmsg = transport.receive();
if (msg.destination == GATEWAY_ADDRESS) {
// Check if sender requests an ack back.
if (mGetRequestAck(gmsg)) {
// Copy message
tmpMsg = gmsg;
mSetRequestAck(tmpMsg, false); // Reply without ack flag (otherwise we would end up in an eternal loop)
mSetAck(tmpMsg, true);
tmpMsg.sender = nc.nodeId;
tmpMsg.destination = msg.sender;
transport.send(tmpMsg);
}
if (mGetCommand(gmsg) == C_INTERNAL) {
if (msg.type == I_VERSION) {
// Request for version. Create the response
transport.send(build(msg, I_VERSION).set(LIBRARY_VERSION));
#ifdef MY_INCLUSION_MODE_FEATURE
} else if (msg.type == I_INCLUSION_MODE) {
// Request to change inclusion mode
setInclusionMode(atoi(msg.data) == 1);
#endif
} else {
processInternalMessages(gmsg);
}
} else {
// Call incoming message callback if available
if (msgCallback != NULL) {
msgCallback(msg);
}
newMessage = true;
}
}
}
// new message from sensor node
if (MySensor::process()) {
MyMessage &msg = MySensor::getLastMessage();
newMessage = true;
transport.send(msg);
}
return newMessage;
}
#ifdef MY_INCLUSION_MODE_FEATURE
void MyGateway::setInclusionMode(boolean newMode) {
if (newMode != inclusionMode) {
inclusionMode = newMode;
// Send back mode change to controller
transport.send(build(msg, I_INCLUSION_MODE).set(inclusionMode?1:0));
if (inclusionMode) {
inclusionStartTime = hw_millis();
Serial.println(inclusionStartTime);
Serial.println(inclusionDuration);
}
}
}
void MyGateway::checkInclusionMode() {
#ifdef MY_INCLUSION_BUTTON_FEATURE
if (!inclusionMode && digitalRead(inclusionButtonPin) == LOW) {
// Start inclusion mode
setInclusionMode(true);
}
#endif
if (inclusionMode && hw_millis()-inclusionStartTime>inclusionDuration) {
// inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode
setInclusionMode(false);
}
}
#endif
-114
View File
@@ -1,114 +0,0 @@
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* 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 MyGateway_h
#define MyGateway_h
#include "MyConfig.h"
#include "MySensor.h"
#include "MyHw.h"
#include "MyTransport.h"
#include "MyTransportNRF24.h"
#ifdef MY_SIGNING_FEATURE
#include "MySigning.h"
#include "MySigningNone.h"
#endif
#include "MyMessage.h"
#ifdef MY_OTA_FIRMWARE_FEATURE
#include "utility/SPIFlash.h"
#endif
#include "MyProtocol.h"
#include "MyGatewayTransport.h"
#include "MyGatewayTransportSerial.h"
#include <stddef.h>
#include <stdarg.h>
class MyGateway : public MySensor
{
public:
// MyProtocolSerial constructor
MyGateway(MyGatewayTransport &transport=*new MyGatewayTransportSerial(), MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver()
#ifdef MY_SIGNING_FEATURE
, MySigning &signer=*new MySigningNone()
#endif
#ifdef MY_LEDS_BLINKING_FEATURE
, uint8_t _rx=MY_DEFAULT_RX_LED_PIN
, uint8_t _tx=MY_DEFAULT_TX_LED_PIN
, uint8_t _er=MY_DEFAULT_ERR_LED_PIN
, unsigned long _blink_period=MY_DEFAULT_LED_BLINK_PERIOD
#endif
);
/**
* Begin operation of the MySensors library
*
* Call this in setup(), before calling any other sensor net library methods.
* @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. Default is NULL.
* @param inclusionModeDuration Number of milliseconds inclusion mode should be enabled
* @param inclusionModeButtonPin Button pin used for enabling inclusion mode
*/
void begin(void (* msgCallback)(const MyMessage &)=NULL
#ifdef MY_INCLUSION_MODE_FEATURE
, int inclusionModeDuration=MY_INCLUSION_MODE_DURATION
#ifdef MY_INCLUSION_BUTTON_FEATURE
, uint8_t inclusionModeButtonPin=MY_INCLUSION_MODE_BUTTON_PIN
#endif
#endif
);
/**
* See MySensor.h
*
* Overloaded to handle local sensor data sent to controller.
*/
boolean sendRoute(MyMessage &message);
/**
* Processes incoming messages to this node.
* Returns true if there is a message addressed for this node was received.
* Preferred way of handling incoming messages is to use the callback defined in begin().
*/
boolean process();
private:
MyGatewayTransport &transport;
#ifdef MY_INCLUSION_MODE_FEATURE
void setInclusionMode(bool newMode);
void checkInclusionMode();
unsigned long inclusionStartTime;
bool inclusionMode;
unsigned long inclusionDuration;
#ifdef MY_INCLUSION_BUTTON_FEATURE
uint8_t inclusionButtonPin;
#endif
#endif
};
#endif
@@ -58,7 +58,7 @@ bool MyGatewayTransportEthernet::begin() {
// TODO: use HW delay
delay(1000);
#ifdef USE_UDP
#ifdef MY_USE_UDP
server = new EthernetUDP();
server->begin(gatewayPort);
#else
@@ -78,7 +78,7 @@ bool MyGatewayTransportEthernet::send(MyMessage &message)
}
else {
msg = protocol.format(message);
#ifdef USE_UDP
#ifdef MY_USE_UDP
server->beginPacket(controllerIP, controllerPort);
server->write(msg, strlen(msg));
// returns 1 if the packet was sent successfully
@@ -107,7 +107,7 @@ bool MyGatewayTransportEthernet::available()
renewIP();
#endif
#ifdef USE_UDP
#ifdef MY_USE_UDP
int packet_size = server->parsePacket();
if (server->available()) {
@@ -26,17 +26,17 @@
#include "MyGatewayTransport.h"
#include "MyProtocolDefault.h"
#include <IPAddress.h>
#include "drivers/Ethernet_W5100/IPAddress.h"
// Use this if you have attached a Ethernet ENC28J60 shields
//#include <UIPEthernet.h>
// Use this fo WizNET W5100 module and Arduino Ethernet Shield
#include <Ethernet.h>
#include "drivers/Ethernet_W5100/Ethernet.h"
#ifdef USE_UDP
#include <EthernetUdp.h>
#endif /* USE_UDP */
#ifdef MY_USE_UDP
#include "drivers/Ethernet_W5100/EthernetUdp.h"
#endif /* MY_USE_UDP */
#define CONTROLLER_PORT 5003
#define IP_RENEWAL_INTERVAL 60000 // in milliseconds
@@ -86,11 +86,11 @@ protected:
IPAddress gatewayIP;
uint16_t gatewayPort;
#ifndef USE_UDP
#ifdef MY_USE_UDP
EthernetUDP *server;
#else
EthernetServer *server;
uint8_t inputPos;
#else
EthernetUDP *server;
#endif
char inputBuffer[MAX_RECEIVE_LENGTH]; // A buffer for incoming commands from serial interface
+1 -1
View File
@@ -45,7 +45,7 @@ public:
virtual void sleep(unsigned long ms) = 0;
virtual bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) = 0;
virtual uint8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) = 0;
#ifdef DEBUG
#ifdef MY_DEBUG
virtual void debugPrint(bool isGW, const char *fmt, ... ) = 0;
#endif
+13 -4
View File
@@ -17,6 +17,8 @@
* version 2 as published by the Free Software Foundation.
*/
#ifdef ARDUINO_ARCH_AVR
#include "MyHw.h"
#include "MyHwATMega328.h"
@@ -119,7 +121,9 @@ void powerDown(period_t period) {
void MyHwATMega328::internalSleep(unsigned long ms) {
// Let serial prints finish (debug, log etc)
Serial.flush();
#ifdef MY_ENABLED_SERIAL
Serial.flush();
#endif
pinIntTrigger = 0;
while (!pinIntTrigger && ms >= 8000) { powerDown(SLEEP_8S); ms -= 8000; }
if (!pinIntTrigger && ms >= 4000) { powerDown(SLEEP_4S); ms -= 4000; }
@@ -148,7 +152,9 @@ bool MyHwATMega328::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) {
pinTriggeredWakeup = false;
}
} else {
Serial.flush();
#ifdef MY_ENABLED_SERIAL
Serial.flush();
#endif
powerDown(SLEEP_FOREVER);
}
detachInterrupt(interrupt);
@@ -166,7 +172,9 @@ inline uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t i
retVal = -1;
}
} else {
Serial.flush();
#ifdef MY_ENABLED_SERIAL
Serial.flush();
#endif
powerDown(SLEEP_FOREVER);
}
detachInterrupt(interrupt1);
@@ -182,7 +190,7 @@ inline uint8_t MyHwATMega328::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t i
#ifdef DEBUG
#ifdef MY_DEBUG
void MyHwATMega328::debugPrint(bool isGW, const char *fmt, ... ) {
char fmtBuffer[300];
if (isGW) {
@@ -209,3 +217,4 @@ void MyHwATMega328::debugPrint(bool isGW, const char *fmt, ... ) {
}
#endif
#endif // #ifdef ARDUINO_ARCH_AVR
+4 -1
View File
@@ -20,6 +20,8 @@
#ifndef MyHwATMega328_h
#define MyHwATMega328_h
#ifdef ARDUINO_ARCH_AVR
#include "MyHw.h"
#include "MyConfig.h"
#include "MyMessage.h"
@@ -109,10 +111,11 @@ public:
void sleep(unsigned long ms);
bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms);
uint8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms);
#ifdef DEBUG
#ifdef MY_DEBUG
void debugPrint(bool isGW, const char *fmt, ... );
#endif
private:
void internalSleep(unsigned long ms);
};
#endif
#endif // #ifdef ARDUINO_ARCH_AVR
+184
View File
@@ -0,0 +1,184 @@
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* 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.
*/
#ifdef ARDUINO_ARCH_ESP8266
#include "MyHw.h"
#include "MyHwESP8266.h"
#include <EEPROM.h>
/*
int8_t pinIntTrigger = 0;
void wakeUp() //place to send the interrupts
{
pinIntTrigger = 1;
}
void wakeUp2() //place to send the second interrupts
{
pinIntTrigger = 2;
}
// Watchdog Timer interrupt service routine. This routine is required
// to allow automatic WDIF and WDIE bit clearance in hardware.
ISR (WDT_vect)
{
// WDIE & WDIF is cleared in hardware upon entering this ISR
wdt_disable();
}
*/
static void hw_initConfigBlock( size_t length = 1024 /*ATMega328 has 1024 bytes*/ )
{
static bool initDone = false;
if (!initDone)
{
EEPROM.begin(length);
initDone = true;
}
}
void hw_readConfigBlock(void* buf, void* adr, size_t length)
{
hw_initConfigBlock();
uint8_t* dst = static_cast<uint8_t*>(buf);
int offs = reinterpret_cast<int>(adr);
while (length-- > 0)
{
*dst++ = EEPROM.read(offs++);
}
}
void hw_writeConfigBlock(void* buf, void* adr, size_t length)
{
hw_initConfigBlock();
uint8_t* src = static_cast<uint8_t*>(buf);
int offs = reinterpret_cast<int>(adr);
while (length-- > 0)
{
EEPROM.write(offs++, *src++);
}
EEPROM.commit();
}
uint8_t hw_readConfig(int adr)
{
uint8_t value;
hw_readConfigBlock(&value, reinterpret_cast<void*>(adr), 1);
return value;
}
void hw_writeConfig(int adr, uint8_t value)
{
uint8_t curr = hw_readConfig(adr);
if (curr != value)
{
hw_writeConfigBlock(&value, reinterpret_cast<void*>(adr), 1);
}
}
MyHwESP8266::MyHwESP8266() : MyHw()
{
}
/*
// The following was redifined as macros to save space
inline uint8_t MyHwATMega328::readConfig(uint8_t pos) {
return eeprom_read_byte((uint8_t*)pos);
}
inline void MyHwATMega328::writeConfig(uint8_t pos, uint8_t value) {
eeprom_update_byte((uint8_t*)pos, value);
}
inline void MyHwATMega328::readConfigBlock(void* buf, void * pos, size_t length) {
eeprom_read_block(buf, (void*)pos, length);
}
inline void MyHwATMega328::writeConfigBlock(void* pos, void* buf, size_t length) {
eeprom_write_block((void*)pos, (void*)buf, length);
}
inline void MyHwATMega328::init() {
Serial.begin(BAUD_RATE);
}
inline void MyHwATMega328::watchdogReset() {
wdt_reset();
}
inline void MyHwATMega328::reboot() {
wdt_enable(WDTO_15MS); for (;;);
}
inline unsigned long MyHwATMega328::millis() {
return ::millis();
}
*/
void MyHwESP8266::sleep(unsigned long ms) {
// TODO: Not supported!
}
bool MyHwESP8266::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) {
// TODO: Not supported!
return false;
}
inline uint8_t MyHwESP8266::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) {
// TODO: Not supported!
return 0;
}
#ifdef MY_DEBUG
void MyHwESP8266::debugPrint(bool isGW, const char *fmt, ... ) {
char fmtBuffer[300];
if (isGW) {
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
snprintf_P(fmtBuffer, 299, PSTR("0;0;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE);
Serial.print(fmtBuffer);
}
va_list args;
va_start (args, fmt );
va_end (args);
if (isGW) {
// Truncate message if this is gateway node
vsnprintf_P(fmtBuffer, 60, fmt, args);
fmtBuffer[59] = '\n';
fmtBuffer[60] = '\0';
} else {
vsnprintf_P(fmtBuffer, 299, fmt, args);
}
va_end (args);
Serial.print(fmtBuffer);
Serial.flush();
//Serial.write(freeRam());
}
#endif
#endif // #ifdef ARDUINO_ARCH_ESP8266
+86
View File
@@ -0,0 +1,86 @@
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* 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.
*/
#ifdef ARDUINO_ARCH_ESP8266
#ifndef MyHwESP8266_h
#define MyHwESP8266_h
#include "MyHw.h"
#include "MyConfig.h"
#include "MyMessage.h"
#ifdef __cplusplus
#include <Arduino.h>
#include <SPI.h>
#endif
// Define these as macros to save valuable space
#define hw_digitalWrite(__pin, __value) (digitalWrite(__pin, __value))
#define hw_init() Serial.begin(BAUD_RATE)
#define hw_watchdogReset() wdt_reset()
#define hw_reboot() wdt_enable(WDTO_15MS); while (1)
#define hw_millis() millis()
void hw_readConfigBlock(void* buf, void* adr, size_t length);
void hw_writeConfigBlock(void* buf, void* adr, size_t length);
void hw_writeConfig(int adr, uint8_t value);
uint8_t hw_readConfig(int adr);
enum period_t
{
SLEEP_15Ms,
SLEEP_30MS,
SLEEP_60MS,
SLEEP_120MS,
SLEEP_250MS,
SLEEP_500MS,
SLEEP_1S,
SLEEP_2S,
SLEEP_4S,
SLEEP_8S,
SLEEP_FOREVER
};
class MyHwESP8266 : public MyHw
{
public:
MyHwESP8266();
/* void init();
void watchdogReset();
void reboot();
unsigned long millis();
uint8_t readConfig(uint8_t pos);
void writeConfig(uint8_t pos, uint8_t value);
void readConfigBlock(void* buf, void * pos, size_t length);
void writeConfigBlock(void* pos, void* buf, size_t length); */
void sleep(unsigned long ms);
bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms);
uint8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms);
#ifdef MY_DEBUG
void debugPrint(bool isGW, const char *fmt, ... );
#endif
};
#endif
#endif // #ifdef ARDUINO_ARCH_ESP8266
+48 -42
View File
@@ -58,7 +58,7 @@ typedef enum {
S_UV, // Uv sensor, V_UV
S_WEIGHT, // Personal scale sensor, V_WEIGHT, V_IMPEDANCE
S_POWER, // Power meter, V_WATT, V_KWH
S_HEATER, // Header device, V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE
S_HEATER, // Header device, V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP
S_DISTANCE, // Distance sensor, V_DISTANCE
S_LIGHT_LEVEL, // Light level sensor, V_LIGHT_LEVEL (uncalibrated in percentage), V_LEVEL (light level in lux)
S_ARDUINO_NODE, // Used (internally) for presenting a non-repeating Arduino node
@@ -73,53 +73,56 @@ typedef enum {
S_RGB_LIGHT, // RGB light. Send color component data using V_RGB. Also supports V_WATT
S_RGBW_LIGHT, // RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT
S_COLOR_SENSOR, // Color sensor, send color information using V_RGB
S_HVAC, // Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT, V_HVAC_SETPOINT_COLD, V_HVAC_FLOW_STATE, V_HVAC_FLOW_MODE
S_HVAC, // Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT, V_HVAC_SETPOINT_COLD, V_HVAC_FLOW_STATE, V_HVAC_FLOW_MODE, V_TEMP
S_MULTIMETER, // Multimeter device, V_VOLTAGE, V_CURRENT, V_IMPEDANCE
S_SPRINKLER, // Sprinkler, V_STATUS (turn on/off), V_TRIPPED (if fire detecting device)
S_WATER_LEAK, // Water leak sensor, V_TRIPPED, V_ARMED
S_SOUND, // Sound sensor, V_TRIPPED, V_ARMED, V_LEVEL (sound level in dB)
S_VIBRATION, // Vibration sensor, V_TRIPPED, V_ARMED, V_LEVEL (vibration in Hz)
S_MOISTURE, // Moisture sensor, V_TRIPPED, V_ARMED, V_LEVEL (water content or moisture in percentage?)
S_INFO, // LCD text device / Simple information device on controller, V_TEXT
S_GAS, // Gas meter, V_FLOW, V_VOLUME
} mysensor_sensor;
// Type of sensor data (for set/req/ack messages)
typedef enum {
V_TEMP, // S_TEMP
V_HUM, // S_HUM
V_STATUS, // S_LIGHT, S_DIMMER, S_SPRINKLER, S_HVAC, S_HEATER. Used for setting binary (on/off) status. 1=on, 0=off
V_TEMP, // S_TEMP. Temperature S_TEMP, S_HEATER, S_HVAC
V_HUM, // S_HUM. Humidity
V_STATUS, // S_LIGHT, S_DIMMER, S_SPRINKLER, S_HVAC, S_HEATER. Used for setting/reporting binary (on/off) status. 1=on, 0=off
V_LIGHT=2, // Same as V_STATUS
V_PERCENTAGE, // S_DIMMER. Used for sending a percentage value (0-100).
V_PERCENTAGE, // S_DIMMER. Used for sending a percentage value 0-100 (%).
V_DIMMER=3, // S_DIMMER. Same as V_PERCENTAGE.
V_PRESSURE, // S_BARO
V_FORECAST, // S_BARO
V_RAIN, // S_RAIN
V_RAINRATE, // S_RAIN
V_WIND, // S_WIND
V_GUST, // S_WIND
V_DIRECTION, // S_WIND
V_UV, // S_UV
V_WEIGHT, // S_WEIGHT
V_DISTANCE, // S_DISTANCE
V_IMPEDANCE, // S_MULTIMETER, S_WEIGHT
V_ARMED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER
V_TRIPPED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER (for sprinklers with fire detection)
V_WATT, // S_POWER, S_LIGHT, S_DIMMER
V_KWH, // S_POWER
V_SCENE_ON, // S_SCENE_CONTROLLER
V_SCENE_OFF, // S_SCENE_CONTROLLER
V_PRESSURE, // S_BARO. Atmospheric Pressure
V_FORECAST, // S_BARO. Whether forecast. string of "stable", "sunny", "cloudy", "unstable", "thunderstorm" or "unknown"
V_RAIN, // S_RAIN. Amount of rain
V_RAINRATE, // S_RAIN. Rate of rain
V_WIND, // S_WIND. Wind speed
V_GUST, // S_WIND. Gust
V_DIRECTION, // S_WIND. Wind direction 0-360 (degrees)
V_UV, // S_UV. UV light level
V_WEIGHT, // S_WEIGHT. Weight(for scales etc)
V_DISTANCE, // S_DISTANCE. Distance
V_IMPEDANCE, // S_MULTIMETER, S_WEIGHT. Impedance value
V_ARMED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER. Armed status of a security sensor. 1 = Armed, 0 = Bypassed
V_TRIPPED, // S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER, S_WATER_LEAK, S_SOUND, S_VIBRATION, S_MOISTURE. Tripped status of a security sensor. 1 = Tripped, 0
V_WATT, // S_POWER, S_LIGHT, S_DIMMER, S_RGB, S_RGBW. Watt value for power meters
V_KWH, // S_POWER. Accumulated number of KWH for a power meter
V_SCENE_ON, // S_SCENE_CONTROLLER. Turn on a scene
V_SCENE_OFF, // S_SCENE_CONTROLLER. Turn of a scene
V_HEATER, // Deprecated. Use V_HVAC_FLOW_STATE instead.
V_HVAC_FLOW_STATE=21, // HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver"). S_HEATER, S_HVAC
V_HVAC_SPEED, // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto")
V_LIGHT_LEVEL, // Used for sending light level in uncalibrated percentage. See also V_LEVEL (light level in lux). S_LIGHT_LEVEL
V_HVAC_FLOW_STATE=21, // S_HEATER, S_HVAC. HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver")
V_HVAC_SPEED, // S_HVAC, S_HEATER. HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto")
V_LIGHT_LEVEL, // S_LIGHT_LEVEL. Uncalibrated light level. 0-100%. Use V_LEVEL for light level in lux
V_VAR1, V_VAR2, V_VAR3, V_VAR4, V_VAR5,
V_UP, // S_COVER
V_DOWN, // S_COVER
V_STOP, // S_COVER
V_IR_SEND, // S_IR
V_IR_RECEIVE, // S_IR
V_FLOW, // S_WATER
V_VOLUME, // S_WATER
V_LOCK_STATUS, // S_LOCK
V_UP, // S_COVER. Window covering. Up
V_DOWN, // S_COVER. Window covering. Down
V_STOP, // S_COVER. Window covering. Stop
V_IR_SEND, // S_IR. Send out an IR-command
V_IR_RECEIVE, // S_IR. This message contains a received IR-command
V_FLOW, // S_WATER. Flow of water (in meter)
V_VOLUME, // S_WATER. Water volume
V_LOCK_STATUS, // S_LOCK. Set or get lock status. 1=Locked, 0=Unlocked
V_LEVEL, // S_DUST, S_AIR_QUALITY, S_SOUND (dB), S_VIBRATION (hz), S_LIGHT_LEVEL (lux)
V_VOLTAGE, // S_MULTIMETER
V_CURRENT, // S_MULTIMETER
@@ -128,16 +131,17 @@ typedef enum {
// Sent as ASCII hex: RRGGBB (RR=red, GG=green, BB=blue component)
V_RGBW, // S_RGBW_LIGHT
// Used for sending color information to multi color LED lighting.
// Sent as ASCII hex: RRGGBBWW (WW=while component)
// Sent as ASCII hex: RRGGBBWW (WW=white component)
V_ID, // S_TEMP
// Used for sending in sensors hardware ids (i.e. OneWire DS1820b).
V_UNIT_PREFIX, // Allows sensors to send in a string representing the
// unit prefix to be displayed in GUI, not parsed by controller! E.g. cm, m, km, inch.
// Can be used for S_DISTANCE or gas concentration (S_DUST, S_AIR_QUALITY)
V_HVAC_SETPOINT_COOL, // HVAC cool setpoint (Integer between 0-100). S_HVAC
V_HVAC_SETPOINT_HEAT, // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC
V_HVAC_FLOW_MODE, // Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn"). S_HVAC
V_UNIT_PREFIX, // S_DUST, S_AIR_QUALITY
// Allows sensors to send in a string representing the
// unit prefix to be displayed in GUI, not parsed by controller! E.g. cm, m, km, inch.
// Can be used for S_DISTANCE or gas concentration
V_HVAC_SETPOINT_COOL, // S_HVAC. HVAC cool setpoint (Integer between 0-100)
V_HVAC_SETPOINT_HEAT, // S_HEATER, S_HVAC. HVAC/Heater setpoint (Integer between 0-100)
V_HVAC_FLOW_MODE, // S_HVAC. Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn")
V_TEXT, // S_INFO. Text message to display on LCD or controller device
} mysensor_data;
@@ -163,7 +167,9 @@ typedef enum {
#ifndef BIT
#define BIT(n) ( 1<<(n) )
#endif
// Create a bitmask of length len.
#define BIT_MASK(len) ( BIT(len)-1 )
// Create a bitfield mask of length starting at bit 'start'.
+189 -22
View File
@@ -18,8 +18,29 @@
*/
#include "MySensor.h"
#include "drivers/RF24/RF24.cpp"
#include "drivers/RFM69/RFM69.cpp"
#include "drivers/ATSHA204/ATSHA204.cpp"
#include "drivers/ATSHA204/sha256.cpp"
#include "drivers/SPIFlash/SPIFlash.cpp"
#include "drivers/Ethernet_W5100/utility/socket.cpp"
#include "drivers/Ethernet_W5100/utility/w5100.cpp"
#include "drivers/Ethernet_W5100/DNS.cpp"
#include "drivers/Ethernet_W5100/Ethernet.cpp"
#include "drivers/Ethernet_W5100/EthernetUdp.cpp"
#include "drivers/Ethernet_W5100/IPAddress.cpp"
#define DISTANCE_INVALID (0xFF)
#ifdef MY_SIGNING_FEATURE
@@ -52,9 +73,6 @@ static inline bool isValidDistance( const uint8_t distance ) {
MySensor::MySensor(MyTransport &_radio, MyHw &_hw
#ifdef MY_SIGNING_FEATURE
, MySigning &_signer
#endif
#ifdef MY_LEDS_BLINKING_FEATURE
, uint8_t _rx, uint8_t _tx, uint8_t _er, unsigned long _blink_period
#endif
)
:
@@ -62,9 +80,6 @@ MySensor::MySensor(MyTransport &_radio, MyHw &_hw
#ifdef MY_SIGNING_FEATURE
signer(_signer),
#endif
#ifdef MY_LEDS_BLINKING_FEATURE
pinRx(_rx), pinTx(_tx), pinEr(_er), ledBlinkPeriod(_blink_period),
#endif
#ifdef MY_OTA_FIRMWARE_FEATURE
flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID),
#endif
@@ -95,45 +110,45 @@ bool MySensor::isValidFirmware() {
#ifdef MY_LEDS_BLINKING_FEATURE
void MySensor::handleLedsBlinking() {
static unsigned long next_time = hw_millis() + ledBlinkPeriod;
static unsigned long next_time = hw_millis() + MY_DEFAULT_LED_BLINK_PERIOD;
// Just return if it is not the time...
// http://playground.arduino.cc/Code/TimingRollover
if ((long)(hw_millis() - next_time) < 0)
if ((long)(hw_millis() - blink_next_time) < 0)
return;
else
next_time = hw_millis() + ledBlinkPeriod;
blink_next_time = hw_millis() + ledBlinkPeriod;
// do the actual blinking
if(countRx && countRx != 255) {
// switch led on
hw_digitalWrite(pinRx, LED_ON);
hw_digitalWrite(MY_DEFAULT_RX_LED_PIN, LED_ON);
}
else if(!countRx) {
// switching off
hw_digitalWrite(pinRx, LED_OFF);
hw_digitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF);
}
if(countRx != 255)
--countRx;
if(countTx && countTx != 255) {
// switch led on
hw_digitalWrite(pinTx, LED_ON);
hw_digitalWrite(MY_DEFAULT_TX_LED_PIN, LED_ON);
}
else if(!countTx) {
// switching off
hw_digitalWrite(pinTx, LED_OFF);
hw_digitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF);
}
if(countTx != 255)
--countTx;
if(countErr && countErr != 255) {
// switch led on
hw_digitalWrite(pinEr, LED_ON);
hw_digitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_ON);
}
else if(!countErr) {
// switching off
hw_digitalWrite(pinEr, LED_OFF);
hw_digitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF);
}
if(countErr != 255)
--countErr;
@@ -153,7 +168,9 @@ void MySensor::errBlink(uint8_t cnt) {
#endif
void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, boolean _repeaterMode, uint8_t _parentNodeId) {
hw_init();
#ifdef MY_ENABLED_SERIAL
hw_init();
#endif
repeaterMode = _repeaterMode;
msgCallback = _msgCallback;
failedTransmissions = 0;
@@ -174,14 +191,14 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b
#ifdef MY_LEDS_BLINKING_FEATURE
// Setup led pins
pinMode(pinRx, OUTPUT);
pinMode(pinTx, OUTPUT);
pinMode(pinEr, OUTPUT);
pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT);
pinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT);
pinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT);
// Set initial state of leds
hw_digitalWrite(pinRx, LED_OFF);
hw_digitalWrite(pinTx, LED_OFF);
hw_digitalWrite(pinEr, LED_OFF);
hw_digitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF);
hw_digitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF);
hw_digitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF);
// initialize counters
countRx = 0;
@@ -397,6 +414,10 @@ boolean MySensor::sendRoute(MyMessage &message) {
#endif
if (dest == GATEWAY_ADDRESS || !repeaterMode) {
// Store this address in routing table (if repeater)
if (repeaterMode) {
hw_writeConfig(EEPROM_ROUTES_ADDRESS+sender, last);
}
// If destination is the gateway or if we aren't a repeater, let
// our parent take care of the message
ok = sendWrite(nc.parentNodeId, message);
@@ -555,6 +576,7 @@ boolean MySensor::process() {
#endif
uint8_t len = radio.receive((uint8_t *)&msg);
(void)len; //until somebody makes use of 'len'
#ifdef MY_LEDS_BLINKING_FEATURE
rxBlink(1);
#endif
@@ -887,3 +909,148 @@ int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, ui
#endif
}
// Inline function and macros
static inline MyMessage& buildGw(MyMessage &msg, uint8_t type) {
msg.sender = GATEWAY_ADDRESS;
msg.destination = GATEWAY_ADDRESS;
msg.sensor = 0;
msg.type = type;
mSetCommand(msg, C_INTERNAL);
mSetRequestAck(msg, false);
mSetAck(msg, false);
return msg;
}
MyGateway::MyGateway(MyGatewayTransport &_transport, MyTransport &_radio,
MyHw &_hw
#ifdef MY_SIGNING_FEATURE
, MySigning &_signer
#endif
) :
transport(_transport), MySensor(_radio, _hw
#ifdef MY_SIGNING_FEATURE
, _signer
#endif
)
{
#ifdef MY_INCLUSION_MODE_FEATURE
inclusionMode = false;
#endif
}
void MyGateway::begin(void (*_msgCallback)(const MyMessage &)) {
// Setup digital in that triggers inclusion mode
#ifdef MY_INCLUSION_MODE_FEATURE
#ifdef MY_INCLUSION_BUTTON_FEATURE
pinMode(MY_INCLUSION_MODE_BUTTON_PIN, INPUT);
digitalWrite(MY_INCLUSION_MODE_BUTTON_PIN, HIGH);
#endif
#endif
// initialize the transport driver
if (!transport.begin()) {
debug(PSTR("transport driver init fail\n"));
while(1); // Nothing more we can do
}
// Start MySensors in repeater mode
MySensor::begin(_msgCallback, GATEWAY_ADDRESS, true, GATEWAY_ADDRESS);
// Startup complete
transport.send(buildGw(msg, I_GATEWAY_READY).set("Gateway startup complete."));
}
boolean MyGateway::sendRoute(MyMessage &message) {
if (message.destination == GATEWAY_ADDRESS) {
// This is a message sent from a sensor attached on the gateway node.
// Pass it directly to the gateway transport layer.
transport.send(message);
} else {
MySensor::sendRoute(message);
}
}
boolean MyGateway::process() {
#ifdef MY_INCLUSION_MODE_FEATURE
checkInclusionMode();
#endif
bool newMessage = false;
if (transport.available()) {
MyMessage &gmsg = transport.receive();
if (msg.destination == GATEWAY_ADDRESS) {
// Check if sender requests an ack back.
if (mGetRequestAck(gmsg)) {
// Copy message
tmpMsg = gmsg;
mSetRequestAck(tmpMsg, false); // Reply without ack flag (otherwise we would end up in an eternal loop)
mSetAck(tmpMsg, true);
tmpMsg.sender = nc.nodeId;
tmpMsg.destination = msg.sender;
transport.send(tmpMsg);
}
if (mGetCommand(gmsg) == C_INTERNAL) {
if (msg.type == I_VERSION) {
// Request for version. Create the response
transport.send(buildGw(msg, I_VERSION).set(LIBRARY_VERSION));
#ifdef MY_INCLUSION_MODE_FEATURE
} else if (msg.type == I_INCLUSION_MODE) {
// Request to change inclusion mode
setInclusionMode(atoi(msg.data) == 1);
#endif
} else {
processInternalMessages(gmsg);
}
} else {
// Call incoming message callback if available
if (msgCallback != NULL) {
msgCallback(msg);
}
newMessage = true;
}
}
}
// new message from sensor node
if (MySensor::process()) {
MyMessage &msg = MySensor::getLastMessage();
newMessage = true;
transport.send(msg);
}
return newMessage;
}
#ifdef MY_INCLUSION_MODE_FEATURE
void MyGateway::setInclusionMode(boolean newMode) {
if (newMode != inclusionMode) {
inclusionMode = newMode;
// Send back mode change to controller
transport.send(buildGw(msg, I_INCLUSION_MODE).set(inclusionMode?1:0));
if (inclusionMode) {
inclusionStartTime = hw_millis();
}
}
}
void MyGateway::checkInclusionMode() {
#ifdef MY_INCLUSION_BUTTON_FEATURE
if (!inclusionMode && digitalRead(MY_INCLUSION_MODE_BUTTON_PIN) == LOW) {
// Start inclusion mode
setInclusionMode(true);
}
#endif
if (inclusionMode && hw_millis()-inclusionStartTime>MY_INCLUSION_MODE_DURATION*1000L) {
// inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode
setInclusionMode(false);
}
}
#endif
+70 -19
View File
@@ -32,20 +32,29 @@
#endif
#include "MyMessage.h"
#ifdef MY_OTA_FIRMWARE_FEATURE
#include "utility/SPIFlash.h"
#include "drivers/SPIFlash/SPIFlash.h"
#endif
#include "MyGatewayTransport.h"
#include "MyGatewayTransportSerial.h"
#include <stddef.h>
#include <stdarg.h>
// Set the hardware driver to use (initialized by MySensor-class)
//#if defined __AVR_ATmega328P__
#if defined(ARDUINO_ARCH_ESP8266)
#include "MyHwESP8266.h"
typedef MyHwESP8266 MyHwDriver;
#elif defined(ARDUINO_ARCH_AVR)
#include "MyHwATMega328.h"
typedef MyHwATMega328 MyHwDriver;
#endif
//#endif
#ifdef DEBUG
#ifdef MY_DEBUG
#define debug(x,...) hw.debugPrint(isGateway, x, ##__VA_ARGS__)
#else
#define debug(x,...)
@@ -152,12 +161,6 @@ class MySensor
MySensor(MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver()
#ifdef MY_SIGNING_FEATURE
, MySigning &signer=*new MySigningNone()
#endif
#ifdef MY_LEDS_BLINKING_FEATURE
, uint8_t _rx=MY_DEFAULT_RX_LED_PIN,
uint8_t _tx=MY_DEFAULT_TX_LED_PIN,
uint8_t _er=MY_DEFAULT_ERR_LED_PIN,
unsigned long _blink_period=MY_DEFAULT_LED_BLINK_PERIOD
#endif
);
@@ -349,32 +352,28 @@ class MySensor
MyMessage msg; // Buffer for incoming messages.
MyMessage tmpMsg ; // Buffer for temporary messages (acks and nonces among others).
#ifdef MY_SIGNING_FEATURE
uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication
MyMessage msgSign; // Buffer for message to sign.
MySigning& signer;
#endif
#ifdef MY_LEDS_BLINKING_FEATURE
uint8_t pinRx; // Rx led pin
uint8_t pinTx; // Tx led pin
uint8_t pinEr; // Err led pin
// these variables don't need to be volatile, since we are not using interrupts
uint8_t countRx;
uint8_t countTx;
uint8_t countErr;
unsigned long ledBlinkPeriod;
void handleLedsBlinking(); // do the actual blinking
unsigned long blink_next_time;
#endif
MyTransport& radio;
#ifdef MY_SIGNING_FEATURE
uint16_t doSign[16]; // Bitfield indicating which sensors require signed communication
MyMessage msgSign; // Buffer for message to sign.
MySigning& signer;
#endif
MyHw& hw;
boolean sendWrite(uint8_t dest, MyMessage &message);
void processInternalMessages(MyMessage &msg);
#ifdef DEBUG
#ifdef MY_DEBUG
char convBuf[MAX_PAYLOAD*2+1];
#endif
uint8_t failedTransmissions;
@@ -396,4 +395,56 @@ class MySensor
};
#endif
class MyGateway : public MySensor
{
public:
// MyProtocolSerial constructor
MyGateway(MyGatewayTransport &transport=*new MyGatewayTransportSerial(), MyTransport &radio =*new MyTransportNRF24(), MyHw &hw=*new MyHwDriver()
#ifdef MY_SIGNING_FEATURE
, MySigning &signer=*new MySigningNone()
#endif
);
/**
* Begin operation of the MySensors library
*
* Call this in setup(), before calling any other sensor net library methods.
* @param incomingMessageCallback Callback function for incoming messages from other nodes or controller and request responses. Default is NULL.
* @param inclusionModeDuration Number of milliseconds inclusion mode should be enabled
* @param inclusionModeButtonPin Button pin used for enabling inclusion mode
*/
void begin(void (* msgCallback)(const MyMessage &)=NULL);
/**
* See MySensor.h
*
* Overloaded to handle local sensor data sent to controller.
*/
boolean sendRoute(MyMessage &message);
/**
* Processes incoming messages to this node.
* Returns true if there is a message addressed for this node was received.
* Preferred way of handling incoming messages is to use the callback defined in begin().
*/
boolean process();
private:
MyGatewayTransport& transport;
#ifdef MY_INCLUSION_MODE_FEATURE
void setInclusionMode(bool newMode);
void checkInclusionMode();
unsigned long inclusionStartTime;
bool inclusionMode;
#endif
};
#endif
@@ -24,10 +24,13 @@
* HMAC-SHA256 authentication with a readout-protected key.
*
*/
#if defined(ARDUINO_ARCH_AVR)
#include "MySigning.h"
#include "MySigningAtsha204.h"
#define SIGNING_IDENTIFIER (1)
// Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected)
//#define DEBUG_SIGNING
@@ -264,3 +267,4 @@ uint8_t* MySigningAtsha204::sha256(const uint8_t* data, size_t sz) {
DEBUG_SIGNING_PRINTBUF(F("SHA:"), &rx_buffer[SHA204_BUFFER_POS_DATA], 32);
return &rx_buffer[SHA204_BUFFER_POS_DATA];
}
#endif // #if defined(ARDUINO_ARCH_AVR)
+1 -3
View File
@@ -30,11 +30,9 @@
#include "MyConfig.h"
#include "MySigning.h"
#include "utility/ATSHA204.h"
#include "drivers/ATSHA204/ATSHA204.h"
#include <stdint.h>
#define SIGNING_IDENTIFIER (1)
#ifdef MY_SECURE_NODE_WHITELISTING
typedef struct {
uint8_t nodeId;
@@ -31,7 +31,9 @@
#include "MyConfig.h"
#include "MySigning.h"
#include "MySigningAtsha204Soft.h"
#include "utility/sha256.h"
#include "drivers/ATSHA204/sha256.h"
#define SIGNING_IDENTIFIER (1)
// Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected)
//#define DEBUG_SIGNING
@@ -72,15 +74,14 @@ MySigningAtsha204Soft::MySigningAtsha204Soft(bool requestSignatures,
uint8_t randomseedPin)
:
MySigning(requestSignatures),
rndPin(randomseedPin),
#ifdef MY_SECURE_NODE_WHITELISTING
whitlist_sz(nof_whitelist_entries),
whitelist(the_whitelist),
node_serial_info(the_serial),
#endif
Sha256(),
verification_ongoing(false),
Sha256()
rndPin(randomseedPin)
{
}
+2 -4
View File
@@ -33,12 +33,10 @@
#include "MyConfig.h"
#include "MySigning.h"
#include "utility/ATSHA204.h"
#include "utility/sha256.h"
#include "drivers/ATSHA204/ATSHA204.h"
#include "drivers/ATSHA204/sha256.h"
#include <stdint.h>
#define SIGNING_IDENTIFIER (1)
#ifdef MY_SECURE_NODE_WHITELISTING
typedef struct {
uint8_t nodeId;
+4
View File
@@ -29,6 +29,8 @@
#include "MySigning.h"
#include "MySigningNone.h"
#define SIGNING_IDENTIFIER (0)
// Uncomment this to get some useful serial debug info (Serial.print and Serial.println expected)
//#define DEBUG_SIGNING
@@ -61,6 +63,7 @@ MySigningNone::MySigningNone() : MySigning() {
}
bool MySigningNone::getNonce(MyMessage &msg) {
(void)msg;
return true;
}
@@ -69,6 +72,7 @@ bool MySigningNone::checkTimer() {
}
bool MySigningNone::putNonce(MyMessage &msg) {
(void)msg;
return true;
}
-2
View File
@@ -32,8 +32,6 @@
#include "MySigning.h"
#include <stdint.h>
#define SIGNING_IDENTIFIER (0)
// The "none" signing driver that can be used for nodes
// not requiring signing
// It does check SIGNING_IDENTIFIER byte to avoid illegal mixing of signing back-ends in
+1
View File
@@ -74,6 +74,7 @@ bool MyTransportNRF24::send(uint8_t to, const void* data, uint8_t len) {
bool MyTransportNRF24::available(uint8_t *to) {
uint8_t pipe = 255;
boolean avail = rf24.available(&pipe);
(void)avail; //until somebody makes use of 'avail'
if (pipe == CURRENT_NODE_PIPE)
*to = _address;
else if (pipe == BROADCAST_PIPE)
+2 -2
View File
@@ -23,8 +23,8 @@
#include "MyConfig.h"
#include "MyTransport.h"
#include <stdint.h>
#include "utility/RF24.h"
#include "utility/RF24_config.h"
#include "drivers/RF24/RF24.h"
#include "drivers/RF24/RF24_config.h"
#define TO_ADDR(x) (RF24_BASE_RADIO_ID + x)
+1 -1
View File
@@ -33,7 +33,7 @@ bool MyTransportRFM69::init() {
// Start up the radio library (_address will be set later by the MySensors library)
radio.initialize(_freqBand, _address, _networkId);
#ifdef RFM69_ENABLE_ENCRYPTION
radio.encrypt(ENCRYPTKEY);
radio.encrypt(RFM69_ENCRYPTKEY);
#endif
return true;
}
+1 -1
View File
@@ -23,7 +23,7 @@
#include "MyConfig.h"
#include "MyTransport.h"
#include <stdint.h>
#include "utility/RFM69.h"
#include "drivers/RFM69/RFM69.h"
#include <SPI.h>
@@ -1,3 +1,5 @@
#if defined(ARDUINO_ARCH_AVR)
#include "Arduino.h"
#include "ATSHA204.h"
@@ -463,7 +465,8 @@ uint8_t ATSHA204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t
uint8_t poll_delay, poll_timeout, response_size;
uint8_t *p_buffer;
uint8_t len;
(void)tx_size;
// Supply delays and response size.
switch (op_code)
{
@@ -571,3 +574,5 @@ uint8_t ATSHA204Class::sha204c_check_crc(uint8_t *response)
return (crc[0] == response[count] && crc[1] == response[count + 1])
? SHA204_SUCCESS : SHA204_BAD_CRC;
}
#endif // defined(ARDUINO_ARCH_AVR)
@@ -1,6 +1,10 @@
#include <string.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#if defined(__AVR__)
#include <avr/pgmspace.h>
#define PRIPSTR "%S"
#elif defined(ESP8266)
#include <pgmspace.h>
#endif
#include "sha256.h"
@@ -41,7 +41,7 @@ void RF24::csn(bool mode)
delayMicroseconds(11); // allow csn to settle
}
}
#else if !defined (__arm__) || defined (CORE_TEENSY)
#elif !defined (__arm__) || defined (CORE_TEENSY)
digitalWrite(csn_pin,mode);
#endif
@@ -422,7 +422,7 @@ void RF24::printDetails(void)
print_byte_register(PSTR("EN_RXADDR"),EN_RXADDR);
print_byte_register(PSTR("RF_CH"),RF_CH);
print_byte_register(PSTR("RF_SETUP"),RF_SETUP);
print_byte_register(PSTR("CONFIG"),CONFIG);
print_byte_register(PSTR("CONFIG"),NRF_CONFIG);
print_byte_register(PSTR("DYNPD/FEATURE"),DYNPD,2);
#if defined(__arm__)
@@ -498,7 +498,7 @@ void RF24::begin(void)
// Reset current status
// Notice reset and flush is the last thing we do
write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
write_register(RF24_STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
// Set up default configuration. Callers can always change it later.
// This channel should be universally safe and not bleed over into adjacent
@@ -513,7 +513,7 @@ void RF24::begin(void)
// Enable PTX, do not write CE high so radio will remain in standby I mode ( 130us max to transition to RX or TX instead of 1500us from powerUp )
// PTX should use only 22uA of power
write_register(CONFIG, ( read_register(CONFIG) ) & ~_BV(PRIM_RX) );
write_register(NRF_CONFIG, ( read_register(NRF_CONFIG) ) & ~_BV(PRIM_RX) );
}
@@ -524,8 +524,8 @@ void RF24::startListening(void)
#if !defined (RF24_TINY)
powerUp();
#endif
write_register(CONFIG, read_register(CONFIG) | _BV(PRIM_RX));
write_register(STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
write_register(NRF_CONFIG, read_register(NRF_CONFIG) | _BV(PRIM_RX));
write_register(RF24_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
// Restore the pipe0 adddress, if exists
if (pipe0_reading_address[0] > 0){
@@ -546,36 +546,49 @@ void RF24::startListening(void)
}
/****************************************************************************/
static const uint8_t child_pipe_enable[] PROGMEM =
static uint8_t get_child_pipe_mask(const uint8_t idx)
{
ERX_P0, ERX_P1, ERX_P2, ERX_P3, ERX_P4, ERX_P5
};
#ifdef ESP8266
static const uint8_t child_pipe_enable[] =
{
_BV(ERX_P0), _BV(ERX_P1), _BV(ERX_P2), _BV(ERX_P3), _BV(ERX_P4), _BV(ERX_P5)
};
return child_pipe_enable[idx];
#else
static const uint8_t child_pipe_enable[] PROGMEM =
{
_BV(ERX_P0), _BV(ERX_P1), _BV(ERX_P2), _BV(ERX_P3), _BV(ERX_P4), _BV(ERX_P5)
};
return pgm_read_byte(&child_pipe_enable[idx]);
#endif
}
void RF24::stopListening(void)
{
ce(LOW);
#if defined(__arm__)
delayMicroseconds(300);
#endif
delayMicroseconds(130);
if(read_register(FEATURE) & _BV(EN_ACK_PAY)){
flush_tx();
}
//flush_rx();
write_register(CONFIG, ( read_register(CONFIG) ) & ~_BV(PRIM_RX) );
write_register(NRF_CONFIG, ( read_register(NRF_CONFIG) ) & ~_BV(PRIM_RX) );
#if defined (RF24_TINY)
// for 3 pins solution TX mode is only left with additonal powerDown/powerUp cycle
if (ce_pin == csn_pin) {
powerDown();
powerUp();
powerUp();
}
#endif
write_register(EN_RXADDR,read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[0]))); // Enable RX on pipe0
write_register(EN_RXADDR,read_register(EN_RXADDR) | get_child_pipe_mask(0)); // Enable RX on pipe0
delayMicroseconds(100);
}
/****************************************************************************/
@@ -583,7 +596,7 @@ void RF24::stopListening(void)
void RF24::powerDown(void)
{
ce(LOW); // Guarantee CE is low on powerDown
write_register(CONFIG,read_register(CONFIG) & ~_BV(PWR_UP));
write_register(NRF_CONFIG,read_register(NRF_CONFIG) & ~_BV(PWR_UP));
}
/****************************************************************************/
@@ -591,11 +604,11 @@ void RF24::powerDown(void)
//Power up now. Radio will not power down unless instructed by MCU for config changes etc.
void RF24::powerUp(void)
{
uint8_t cfg = read_register(CONFIG);
uint8_t cfg = read_register(NRF_CONFIG);
// if not powered up then power up and wait for the radio to initialize
if (!(cfg & _BV(PWR_UP))){
write_register(CONFIG,read_register(CONFIG) | _BV(PWR_UP));
write_register(NRF_CONFIG,read_register(NRF_CONFIG) | _BV(PWR_UP));
// For nRF24L01+ to go from power down mode to TX or RX mode it must first pass through stand-by mode.
// There must be a delay of Tpd2stby (see Table 16.) after the nRF24L01+ leaves power down mode before
@@ -636,7 +649,7 @@ bool RF24::write( const void* buf, uint8_t len, const bool multicast )
ce(LOW);
uint8_t status = write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
uint8_t status = write_register(RF24_STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
//Max retries exceeded
if( status & _BV(MAX_RT)){
@@ -686,7 +699,7 @@ bool RF24::writeBlocking( const void* buf, uint8_t len, uint32_t timeout )
/****************************************************************************/
void RF24::reUseTX(){
write_register(STATUS,_BV(MAX_RT) ); //Clear max retry flag
write_register(RF24_STATUS,_BV(MAX_RT) ); //Clear max retry flag
spiTrans( REUSE_TX_PL );
ce(LOW); //Re-Transfer packet
ce(HIGH);
@@ -709,7 +722,7 @@ bool RF24::writeFast( const void* buf, uint8_t len, const bool multicast )
if( get_status() & _BV(MAX_RT)){
//reUseTX(); //Set re-transmit
write_register(STATUS,_BV(MAX_RT) ); //Clear max retry flag
write_register(RF24_STATUS,_BV(MAX_RT) ); //Clear max retry flag
return 0; //Return 0. The previous payload has been retransmitted
//From the user perspective, if you get a 0, just keep trying to send the same payload
}
@@ -777,7 +790,7 @@ bool RF24::txStandBy(){
#endif
while( ! (read_register(FIFO_STATUS) & _BV(TX_EMPTY)) ){
if( get_status() & _BV(MAX_RT)){
write_register(STATUS,_BV(MAX_RT) );
write_register(RF24_STATUS,_BV(MAX_RT) );
ce(LOW);
flush_tx(); //Non blocking, flush the data
return 0;
@@ -802,7 +815,7 @@ bool RF24::txStandBy(uint32_t timeout){
while( ! (read_register(FIFO_STATUS) & _BV(TX_EMPTY)) ){
if( get_status() & _BV(MAX_RT)){
write_register(STATUS,_BV(MAX_RT) );
write_register(RF24_STATUS,_BV(MAX_RT) );
ce(LOW); //Set re-transmit
ce(HIGH);
if(millis() - start >= timeout){
@@ -826,7 +839,7 @@ bool RF24::txStandBy(uint32_t timeout){
void RF24::maskIRQ(bool tx, bool fail, bool rx){
write_register(CONFIG, ( read_register(CONFIG) ) | fail << MASK_MAX_RT | tx << MASK_TX_DS | rx << MASK_RX_DR );
write_register(NRF_CONFIG, ( read_register(NRF_CONFIG) ) | fail << MASK_MAX_RT | tx << MASK_TX_DS | rx << MASK_RX_DR );
}
/****************************************************************************/
@@ -891,7 +904,7 @@ void RF24::read( void* buf, uint8_t len ){
read_payload( buf, len );
//Clear the two possible interrupt flags with one command
write_register(STATUS,_BV(RX_DR) | _BV(MAX_RT) | _BV(TX_DS) );
write_register(RF24_STATUS,_BV(RX_DR) | _BV(MAX_RT) | _BV(TX_DS) );
}
@@ -901,7 +914,7 @@ void RF24::whatHappened(bool& tx_ok,bool& tx_fail,bool& rx_ready)
{
// Read the status & reset the status in one easy call
// Or is that such a good idea?
uint8_t status = write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
uint8_t status = write_register(RF24_STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );
// Report to the user what happened
tx_ok = status & _BV(TX_DS);
@@ -972,7 +985,7 @@ void RF24::openReadingPipe(uint8_t child, uint64_t address)
// Note it would be more efficient to set all of the bits for all open
// pipes at once. However, I thought it would make the calling code
// more simple to do it this way.
write_register(EN_RXADDR,read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[child])));
write_register(EN_RXADDR,read_register(EN_RXADDR) | get_child_pipe_mask(child));
}
}
@@ -1009,7 +1022,7 @@ void RF24::openReadingPipe(uint8_t child, const uint8_t *address)
// Note it would be more efficient to set all of the bits for all open
// pipes at once. However, I thought it would make the calling code
// more simple to do it this way.
write_register(EN_RXADDR,read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[child])));
write_register(EN_RXADDR,read_register(EN_RXADDR) | get_child_pipe_mask(child));
}
}
@@ -1018,7 +1031,7 @@ void RF24::openReadingPipe(uint8_t child, const uint8_t *address)
void RF24::closeReadingPipe( uint8_t pipe )
{
write_register(EN_RXADDR,read_register(EN_RXADDR) & ~_BV(pgm_read_byte(&child_pipe_enable[pipe])));
write_register(EN_RXADDR,read_register(EN_RXADDR) & ~get_child_pipe_mask(pipe));
}
/****************************************************************************/
@@ -1268,7 +1281,7 @@ rf24_datarate_e RF24::getDataRate( void )
void RF24::setCRCLength(rf24_crclength_e length)
{
uint8_t config = read_register(CONFIG) & ~( _BV(CRCO) | _BV(EN_CRC)) ;
uint8_t config = read_register(NRF_CONFIG) & ~( _BV(CRCO) | _BV(EN_CRC)) ;
// switch uses RAM (evil!)
if ( length == RF24_CRC_DISABLED )
@@ -1284,7 +1297,7 @@ void RF24::setCRCLength(rf24_crclength_e length)
config |= _BV(EN_CRC);
config |= _BV( CRCO );
}
write_register( CONFIG, config ) ;
write_register( NRF_CONFIG, config ) ;
}
/****************************************************************************/
@@ -1293,7 +1306,7 @@ rf24_crclength_e RF24::getCRCLength(void)
{
rf24_crclength_e result = RF24_CRC_DISABLED;
uint8_t config = read_register(CONFIG) & ( _BV(CRCO) | _BV(EN_CRC)) ;
uint8_t config = read_register(NRF_CONFIG) & ( _BV(CRCO) | _BV(EN_CRC)) ;
uint8_t AA = read_register(EN_AA);
if ( config & _BV(EN_CRC ) || AA)
@@ -1311,8 +1324,8 @@ rf24_crclength_e RF24::getCRCLength(void)
void RF24::disableCRC( void )
{
uint8_t disable = read_register(CONFIG) & ~_BV(EN_CRC) ;
write_register( CONFIG, disable ) ;
uint8_t disable = read_register(NRF_CONFIG) & ~_BV(EN_CRC) ;
write_register( NRF_CONFIG, disable ) ;
}
/****************************************************************************/
@@ -87,7 +87,7 @@
// Avoid spurious warnings
// Arduino DUE is arm and uses traditional PROGMEM constructs
#if 1
#if ! defined( NATIVE ) && defined( ARDUINO ) && ! defined(__arm__) && ! defined( CORE_TEENSY3 )
#if ! defined( NATIVE ) && defined( ARDUINO ) && ! defined(__arm__) && ! defined( CORE_TEENSY3 ) && ! defined(ESP8266)
#undef PROGMEM
#define PROGMEM __attribute__(( section(".progmem.data") ))
#undef PSTR
@@ -97,18 +97,21 @@
// Progmem is Arduino-specific
// Arduino DUE is arm and does not include avr/pgmspace
#if defined(ARDUINO) && ! defined(__arm__)
#if defined(__AVR__)
#include <avr/pgmspace.h>
#define PRIPSTR "%S"
#else
#if defined(ESP8266)
#include <pgmspace.h>
#else
#if ! defined(ARDUINO) // This doesn't work on Arduino DUE
typedef char const char;
#else // Fill in pgm_read_byte that is used, but missing from DUE
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
#endif
#if !defined ( CORE_TEENSY )
#if !defined ( CORE_TEENSY ) && ! defined(ESP8266)
typedef uint16_t prog_uint16_t;
#define PSTR(x) (x)
#define printf_P printf
@@ -24,14 +24,14 @@
*/
/* Memory Map */
#define CONFIG 0x00
#define NRF_CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define SETUP_RETR 0x04
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define RF24_STATUS 0x07
#define OBSERVE_TX 0x08
#define CD 0x09
#define RX_ADDR_P0 0x0A
@@ -55,9 +55,9 @@ bool RFM69::initialize(byte freqBand, byte nodeID, byte networkID)
/* 0x05 */ { REG_FDEVMSB, RF_FDEVMSB_50000}, //default:5khz, (FDEV + BitRate/2 <= 500Khz)
/* 0x06 */ { REG_FDEVLSB, RF_FDEVLSB_50000},
/* 0x07 */ { REG_FRFMSB, (freqBand==RF69_315MHZ ? RF_FRFMSB_315 : (freqBand==RF69_433MHZ ? RF_FRFMSB_433 : (freqBand==RF69_868MHZ ? RF_FRFMSB_868 : RF_FRFMSB_915))) },
/* 0x08 */ { REG_FRFMID, (freqBand==RF69_315MHZ ? RF_FRFMID_315 : (freqBand==RF69_433MHZ ? RF_FRFMID_433 : (freqBand==RF69_868MHZ ? RF_FRFMID_868 : RF_FRFMID_915))) },
/* 0x09 */ { REG_FRFLSB, (freqBand==RF69_315MHZ ? RF_FRFLSB_315 : (freqBand==RF69_433MHZ ? RF_FRFLSB_433 : (freqBand==RF69_868MHZ ? RF_FRFLSB_868 : RF_FRFLSB_915))) },
/* 0x07 */ { REG_FRFMSB, (freqBand==RF69_315MHZ ? (const byte)RF_FRFMSB_315 : (freqBand==RF69_433MHZ ? (const byte)RF_FRFMSB_433 : (freqBand==RF69_868MHZ ? (const byte)RF_FRFMSB_868 : (const byte)RF_FRFMSB_915))) },
/* 0x08 */ { REG_FRFMID, (freqBand==RF69_315MHZ ? (const byte)RF_FRFMID_315 : (freqBand==RF69_433MHZ ? (const byte)RF_FRFMID_433 : (freqBand==RF69_868MHZ ? (const byte)RF_FRFMID_868 : (const byte)RF_FRFMID_915))) },
/* 0x09 */ { REG_FRFLSB, (freqBand==RF69_315MHZ ? (const byte)RF_FRFLSB_315 : (freqBand==RF69_433MHZ ? (const byte)RF_FRFLSB_433 : (freqBand==RF69_868MHZ ? (const byte)RF_FRFLSB_868 : (const byte)RF_FRFLSB_915))) },
// looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm
// +17dBm and +20dBm are possible on RFM69HW
@@ -384,8 +384,10 @@ void RFM69::writeReg(byte addr, byte value)
void RFM69::select() {
noInterrupts();
//save current SPI settings
#ifndef ESP8266
_SPCR = SPCR;
_SPSR = SPSR;
#endif
//set RFM69 SPI settings
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST);
@@ -397,8 +399,10 @@ void RFM69::select() {
void RFM69::unselect() {
digitalWrite(_slaveSelectPin, HIGH);
//restore SPI settings to what they were before talking to RFM69
#ifndef ESP8266
SPCR = _SPCR;
SPSR = _SPSR;
#endif
interrupts();
}
@@ -40,17 +40,20 @@
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
#define RF69_IRQ_PIN 2
#define RF69_IRQ_NUM 0
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2560__)
#define RF69_IRQ_PIN 2
#define RF69_IRQ_NUM 2
#elif defined(__AVR_ATmega32U4__)
#define RF69_IRQ_PIN 3
#define RF69_IRQ_NUM 0
#else
// ESP8266 should fall into this category now
// TODO !! Untested code! Entering unknown territory...
#define RF69_IRQ_PIN 2
#define RF69_IRQ_NUM 0
#endif
#define CSMA_LIMIT -90 // upper RX signal sensitivity threshold in dBm for carrier sense access
#define RF69_MODE_SLEEP 0 // XTAL OFF
#define RF69_MODE_STANDBY 1 // XTAL ON
@@ -32,7 +32,7 @@
// Please maintain this license information along with authorship
// and copyright notices in any redistribution of this code
#include <SPIFlash.h>
#include "SPIFlash.h"
uint8_t SPIFlash::UNIQUEID[8];
@@ -56,8 +56,10 @@ void SPIFlash::select() {
#ifndef SPI_HAS_TRANSACTION
noInterrupts();
#endif
#ifndef ESP8266
_SPCR = SPCR;
_SPSR = SPSR;
#endif
#ifdef SPI_HAS_TRANSACTION
SPI.beginTransaction(_settings);
@@ -80,15 +82,19 @@ void SPIFlash::unselect() {
#else
interrupts();
#endif
#ifndef ESP8266
SPCR = _SPCR;
SPSR = _SPSR;
#endif
}
/// setup SPI, read device ID etc...
boolean SPIFlash::initialize()
{
#ifndef ESP8266
_SPCR = SPCR;
_SPSR = SPSR;
#endif
pinMode(_slaveSelectPin, OUTPUT);
#ifdef SPI_HAS_TRANSACTION
_settings = SPISettings(4000000, MSBFIRST, SPI_MODE0);
@@ -290,4 +296,4 @@ void SPIFlash::wakeup() {
/// cleanup
void SPIFlash::end() {
SPI.end();
}
}
@@ -30,8 +30,6 @@
#include <SPI.h>
#include <MySensor.h>
#define DEBUG 1 // Debug enables Serial.print 1 = Yes 0 = No
int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point
MySensor gw;
@@ -41,7 +39,11 @@ int oldBatteryPcnt = 0;
void setup()
{
// use the 1.1 V internal reference
#if defined(__AVR_ATmega2560__)
analogReference(INTERNAL1V1);
#else
analogReference(INTERNAL);
#endif
gw.begin();
// Send the sketch version information to the gateway and Controller
@@ -52,7 +54,7 @@ void loop()
{
// get the battery Voltage
int sensorValue = analogRead(BATTERY_SENSE_PIN);
#if DEBUG > 0
#ifdef DEBUG
Serial.println(sensorValue);
#endif
@@ -63,7 +65,7 @@ void loop()
float batteryV = sensorValue * 0.003363075;
int batteryPcnt = sensorValue / 10;
#if DEBUG > 0
#ifdef DEBUG
Serial.print("Battery Voltage: ");
Serial.print(batteryV);
Serial.println(" V");
@@ -75,7 +75,7 @@ void setup()
digitalWrite(SECONDARY_BUTTON_PIN, HIGH);
// Send the sketch version information to the gateway and Controller
sensor_node.sendSketchInfo(SKETCH_NAME, SKETCH_MAJOR_VER"."SKETCH_MINOR_VER);
sensor_node.sendSketchInfo(SKETCH_NAME, SKETCH_MAJOR_VER "." SKETCH_MINOR_VER);
// Register binary input sensor to sensor_node (they will be created as child devices)
// You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage.
@@ -0,0 +1,100 @@
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* 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.
*
*******************************
*
* DESCRIPTION
*
* MH-Z14 CO2 sensor
*
* Wiring:
* Pad 1, Pad 5: Vin (Voltage input 4.5V-6V)
* Pad 2, Pad 3, Pad 12: GND
* Pad 6: PWM output ==> pin 6
*
* From: http://davidegironi.blogspot.fr/2014/01/co2-meter-using-ndir-infrared-mh-z14.html
* MH-Z14 has a PWM output, with a sensitivity range of 0ppm to 2000ppm CO2, an accurancy of ±200ppm.
* The cycle is 1004ms±5%, given the duty cicle Th (pulse high), Tl is 1004-Th, we can convert it to CO2 value using the formula:
* CO2ppm = 2000 * (Th - 2ms) /(Th + Tl - 4ms)
* From: http://airqualityegg.wikispaces.com/Sensor+Tests
* - response time is less than 30 s
* - 3 minute warm up time
* datasheet: http://www.futurlec.com/Datasheet/Sensor/MH-Z14.pdf
* Contributor: epierre
**/
#include <MySensor.h>
#include <SPI.h>
#define CHILD_ID_AIQ 0
#define AIQ_SENSOR_ANALOG_PIN 6
unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds)
float valAIQ =0.0;
float lastAIQ =0.0;
MySensor gw;
MyMessage msg(CHILD_ID_AIQ, V_LEVEL);
MyMessage msg2(CHILD_ID_AIQ, V_UNIT_PREFIX);
void setup()
{
gw.begin();
// Send the sketch version information to the gateway and Controller
gw.sendSketchInfo("AIQ Sensor CO2 MH-Z14", "1.0");
// Register all sensors to gateway (they will be created as child devices)
gw.present(CHILD_ID_AIQ, S_AIR_QUALITY);
gw.send(msg2.set("ppm"));
gw.sleep(SLEEP_TIME);
pinMode(AIQ_SENSOR_ANALOG_PIN, INPUT);
}
void loop() {
//unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH);
while(digitalRead(AIQ_SENSOR_ANALOG_PIN) == HIGH) {;}
//wait for the pin to go HIGH and measure HIGH time
unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH);
//Serial.print(duration/1000); Serial.println(" ms ");
//from datasheet
//CO2 ppm = 2000 * (Th - 2ms) / (Th + Tl - 4ms)
// given Tl + Th = 1004
// Tl = 1004 - Th
// = 2000 * (Th - 2ms) / (Th + 1004 - Th -4ms)
// = 2000 * (Th - 2ms) / 1000 = 2 * (Th - 2ms)
long co2ppm = 2 * ((duration/1000) - 2);
//Serial.print(co2ppm);
if ((co2ppm != lastAIQ)&&(abs(co2ppm-lastAIQ)>=10)) {
gw.send(msg.set((long)ceil(co2ppm)));
lastAIQ = ceil(co2ppm);
}
//Serial.println();
// Power down the radio. Note that the radio will get powered back up
// on the next write() call.
gw.sleep(SLEEP_TIME); //sleep for: sleepTime
}
@@ -133,7 +133,7 @@ void incomingMessage(const MyMessage &message)
newLevel = loadLevelState(EEPROM_DIM_LEVEL_SAVE);
}
// Send dimmer level back to controller with ack enabled
gw.send(dimmerMsg.set(0), true);
gw.send(dimmerMsg.set(newLevel), true);
// We do not change any levels here until ack comes back from gateway
return;
} else if (message.type == V_DIMMER) {
@@ -51,7 +51,7 @@ void setup()
// Register all sensors to gw (they will be created as child devices)
gw.present(CHILD_ID, S_DISTANCE);
boolean metric = gw.getConfig().isMetric;
metric = gw.getConfig().isMetric;
}
void loop()
@@ -0,0 +1,144 @@
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* 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.
*
*******************************
*
* DESCRIPTION
*
* Dust Sensor for SamYoung DSM501
* connect the sensor as follows :
* Pin 2 of dust sensor PM1 -> Digital 3 (PMW)
* Pin 3 of dust sensor -> +5V
* Pin 4 of dust sensor PM2.5 -> Digital 6 (PWM)
* Pin 5 of dust sensor -> Ground
* Datasheet: http://www.samyoungsnc.com/products/3-1%20Specification%20DSM501.pdf
* Contributor: epierre
**/
#include <MySensor.h>
#include <SPI.h>
#define CHILD_ID_DUST_PM10 0
#define CHILD_ID_DUST_PM25 1
#define DUST_SENSOR_DIGITAL_PIN_PM10 6
#define DUST_SENSOR_DIGITAL_PIN_PM25 3
unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds)
//VARIABLES
int val = 0; // variable to store the value coming from the sensor
float valDUSTPM25 =0.0;
float lastDUSTPM25 =0.0;
float valDUSTPM10 =0.0;
float lastDUSTPM10 =0.0;
unsigned long duration;
unsigned long starttime;
unsigned long endtime;
unsigned long sampletime_ms = 30000;
unsigned long lowpulseoccupancy = 0;
float ratio = 0;
long concentrationPM25 = 0;
long concentrationPM10 = 0;
MySensor gw;
MyMessage dustMsgPM10(CHILD_ID_DUST_PM10, V_LEVEL);
MyMessage msgPM10(CHILD_ID_DUST_PM10, V_UNIT_PREFIX);
MyMessage dustMsgPM25(CHILD_ID_DUST_PM25, V_LEVEL);
MyMessage msgPM25(CHILD_ID_DUST_PM25, V_UNIT_PREFIX);
void setup()
{
gw.begin();
// Send the sketch version information to the gateway and Controller
gw.sendSketchInfo("Dust Sensor DSM501", "1.4");
// Register all sensors to gateway (they will be created as child devices)
gw.present(CHILD_ID_DUST_PM10, S_DUST);
gw.send(msgPM10.set("ppm"));
gw.present(CHILD_ID_DUST_PM25, S_DUST);
gw.send(msgPM25.set("ppm"));
pinMode(DUST_SENSOR_DIGITAL_PIN_PM10,INPUT);
pinMode(DUST_SENSOR_DIGITAL_PIN_PM25,INPUT);
}
void loop()
{
//get PM 2.5 density of particles over 2.5 μm.
concentrationPM25=(long)getPM(DUST_SENSOR_DIGITAL_PIN_PM25);
Serial.print("PM25: ");
Serial.println(concentrationPM25);
Serial.print("\n");
if ((concentrationPM25 != lastDUSTPM25)&&(concentrationPM25>0)) {
gw.send(dustMsgPM25.set((long)ceil(concentrationPM25)));
lastDUSTPM25 = ceil(concentrationPM25);
}
//get PM 1.0 - density of particles over 1 μm.
concentrationPM10=getPM(DUST_SENSOR_DIGITAL_PIN_PM10);
Serial.print("PM10: ");
Serial.println(concentrationPM10);
Serial.print("\n");
//ppmv=mg/m3 * (0.08205*Tmp)/Molecular_mass
//0.08205 = Universal gas constant in atm·m3/(kmol·K)
int temp=20; //external temperature, if you can replace this with a DHT11 or better
long ppmv=(concentrationPM10*0.0283168/100/1000) * (0.08205*temp)/0.01;
if ((ceil(concentrationPM10) != lastDUSTPM10)&&((long)concentrationPM10>0)) {
gw.send(dustMsgPM10.set((long)ppmv));
lastDUSTPM10 = ceil(concentrationPM10);
}
//sleep to save on radio
gw.sleep(SLEEP_TIME);
}
long getPM(int DUST_SENSOR_DIGITAL_PIN) {
starttime = millis();
while (1) {
duration = pulseIn(DUST_SENSOR_DIGITAL_PIN, LOW);
lowpulseoccupancy += duration;
endtime = millis();
if ((endtime-starttime) > sampletime_ms)
{
ratio = (lowpulseoccupancy-endtime+starttime)/(sampletime_ms*10.0); // Integer percentage 0=>100
long concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve
//Serial.print("lowpulseoccupancy:");
//Serial.print(lowpulseoccupancy);
//Serial.print("\n");
//Serial.print("ratio:");
//Serial.print(ratio);
//Serial.print("\n");
//Serial.print("DSM501A:");
//Serial.println(concentration);
//Serial.print("\n");
lowpulseoccupancy = 0;
return(concentration);
}
}
}
@@ -0,0 +1,265 @@
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* 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.
*
*******************************
*
* REVISION HISTORY
* Version 1.0 - Henrik EKblad
* Contribution by a-lurker and Anticimex,
* Contribution by Norbert Truchsess <norbert.truchsess@t-online.de>
* Contribution by Ivo Pullens (ESP8266 support)
*
* DESCRIPTION
* The EthernetGateway sends data received from sensors to the WiFi link.
* The gateway also accepts input on ethernet interface, which is then sent out to the radio network.
*
* VERA CONFIGURATION:
* Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin.
* E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003
*
* LED purposes:
* - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h
* - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
* - ERR (red) - fast blink on error during transmission error or recieve crc error
*
* See http://www.mysensors.org/build/ethernet_gateway for wiring instructions.
* The ESP8266 however requires different wiring:
* nRF24L01+ ESP8266
* VCC VCC
* CE GPIO4
* CSN/CS GPIO15
* SCK GPIO14
* MISO GPIO12
* MOSI GPIO13
*
* Not all ESP8266 modules have all pins available on their external interface.
* This code has been tested on an ESP-12 module.
* The ESP8266 requires a certain pin configuration to download code, and another one to run code:
* - Connect REST (reset) via 10K pullup resistor to VCC, and via switch to GND ('reset switch')
* - Connect GPIO15 via 10K pulldown resistor to GND
* - Connect CH_PD via 10K resistor to VCC
* - Connect GPIO2 via 10K resistor to VCC
* - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch')
*
* Inclusion mode button:
* - Connect GPIO5 via switch to GND ('inclusion switch')
*
* Hardware SHA204 signing is currently not supported!
*
* Make sure to fill in your ssid and WiFi password below for ssid & pass.
*/
#define NO_PORTB_PINCHANGES
#include <SPI.h>
#include <MySigningNone.h>
#include <MySigningAtsha204Soft.h>
#include <MyTransportNRF24.h>
#include <MyTransportRFM69.h>
#include <EEPROM.h>
#include <MyHwESP8266.h>
#include <ESP8266WiFi.h>
#include <MyParserSerial.h>
#include <MySensor.h>
#include <stdarg.h>
#include "GatewayUtil.h"
const char *ssid = "MySSID"; // cannot be longer than 32 characters!
const char *pass = "MyVerySecretPassword"; //
#define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled
#define INCLUSION_MODE_PIN 5 // Digital pin used for inclusion mode button
#define RADIO_CE_PIN 4 // radio chip enable
#define RADIO_SPI_SS_PIN 15 // radio SPI serial select
#ifdef WITH_LEDS_BLINKING
#define RADIO_ERROR_LED_PIN 7 // Error led pin
#define RADIO_RX_LED_PIN 8 // Receive led pin
#define RADIO_TX_LED_PIN 9 // the PCB, on board LED
#endif
// NRFRF24L01 radio driver (set low transmit power by default)
MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW);
//MyTransportRFM69 transport;
// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h)
#ifdef MY_SIGNING_FEATURE
MySigningNone signer;
//MySigningAtsha204Soft signer;
#endif
// Hardware profile
MyHwESP8266 hw;
// Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h)
// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h
MySensor gw(transport, hw
#ifdef MY_SIGNING_FEATURE
, signer
#endif
#ifdef WITH_LEDS_BLINKING
, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN
#endif
);
#define IP_PORT 5003 // The port you want to open
#define MAX_SRV_CLIENTS 5 // how many clients should be able to telnet to this ESP8266
// a R/W server on the port
static WiFiServer server(IP_PORT);
static WiFiClient clients[MAX_SRV_CLIENTS];
static bool clientsConnected[MAX_SRV_CLIENTS];
static inputBuffer inputString[MAX_SRV_CLIENTS];
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
void output(const char *fmt, ... )
{
char serialBuffer[MAX_SEND_LENGTH];
va_list args;
va_start (args, fmt );
vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args);
va_end (args);
Serial.print(serialBuffer);
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
{
if (clients[i] && clients[i].connected())
{
// Serial.print("Client "); Serial.print(i); Serial.println(" write");
clients[i].write((uint8_t*)serialBuffer, strlen(serialBuffer));
}
}
}
void setup()
{
// Setup console
hw_init();
Serial.println(); Serial.println();
Serial.println("ESP8266 MySensors Gateway");
Serial.print("Connecting to "); Serial.println(ssid);
(void)WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("Connected!");
Serial.print("IP: "); Serial.println(WiFi.localIP());
Serial.flush();
setupGateway(INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output);
// Initialize gateway at maximum PA level, channel 70 and callback for write operations
gw.begin(incomingMessage, 0, true, 0);
// start listening for clients
server.begin();
server.setNoDelay(true);
}
void loop() {
gw.process();
checkButtonTriggeredInclusion();
checkInclusionFinished();
// Go over list of clients and stop any that are no longer connected.
// If the server has a new client connection it will be assigned to a free slot.
bool allSlotsOccupied = true;
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
{
if (!clients[i].connected())
{
if (clientsConnected[i])
{
Serial.print("Client "); Serial.print(i); Serial.println(" disconnected");
clients[i].stop();
}
//check if there are any new clients
if (server.hasClient())
{
clients[i] = server.available();
inputString[i].idx = 0;
Serial.print("Client "); Serial.print(i); Serial.println(" connected");
output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY);
}
}
bool connected = clients[i].connected();
clientsConnected[i] = connected;
allSlotsOccupied &= connected;
}
if (allSlotsOccupied && server.hasClient())
{
//no free/disconnected spot so reject
Serial.println("No free slot available");
WiFiClient c = server.available();
c.stop();
}
// Loop over clients connect and read available data
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
{
while(clients[i].connected() && clients[i].available())
{
char inChar = clients[i].read();
if ( inputString[i].idx < MAX_RECEIVE_LENGTH - 1 )
{
// if newline then command is complete
if (inChar == '\n')
{
// a command was issued by the client
// we will now try to send it to the actuator
inputString[i].string[inputString[i].idx] = 0;
// echo the string to the serial port
Serial.print("Client "); Serial.print(i); Serial.print(": "); Serial.println(inputString[i].string);
parseAndSend(gw, inputString[i].string);
// clear the string:
inputString[i].idx = 0;
// Finished with this client's message. Next loop() we'll see if there's more to read.
break;
} else {
// add it to the inputString:
inputString[i].string[inputString[i].idx++] = inChar;
}
} else {
// Incoming message too long. Throw away
Serial.print("Client "); Serial.print(i); Serial.println(": Message too long");
inputString[i].idx = 0;
// Finished with this client's message. Next loop() we'll see if there's more to read.
break;
}
}
}
}
@@ -0,0 +1,136 @@
#ifndef __GATEWAYUTIL_H__
#define __GATEWAYUTIL_H__
#ifdef ARDUINO
static uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled
static uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode
#define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller
#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller
typedef struct
{
char string[MAX_RECEIVE_LENGTH];
uint8_t idx;
} inputBuffer;
static volatile boolean buttonTriggeredInclusion;
static boolean inclusionMode; // Keeps track on inclusion mode
bool inclusionButtonSupported = false;
void (*serial)(const char *fmt, ... );
MyParserSerial parser;
void setInclusionMode(boolean newMode);
char convBuf[MAX_PAYLOAD*2+1];
unsigned long inclusionStartTime;
void startInclusionInterrupt() {
buttonTriggeredInclusion = true;
}
void setupGateway(uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) {
inclusionMode = 0;
buttonTriggeredInclusion = false;
serial = _serial;
inclusionTime = _incTime;
inclusionButtonSupported = (_inc != 255);
if (inclusionButtonSupported)
{
pinInclusion = _inc;
// Setup digital in that triggers inclusion mode
pinMode(pinInclusion, INPUT_PULLUP);
// Add interrupt for inclusion button to pin
attachInterrupt(pinInclusion, startInclusionInterrupt, FALLING);
}
}
void incomingMessage(const MyMessage &message) {
// if (mGetCommand(message) == C_PRESENTATION && inclusionMode) {
// gw.rxBlink(3);
// } else {
// gw.rxBlink(1);
// }
// Pass along the message from sensors to serial line
serial(PSTR("%d;%d;%d;%d;%d;%s\n"),message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(convBuf));
}
void checkButtonTriggeredInclusion() {
if (inclusionButtonSupported)
{
if (buttonTriggeredInclusion) {
// Ok, someone pressed the inclusion button on the gateway
// start inclusion mode for 1 munute.
#ifdef DEBUG
serial(PSTR("0;0;%d;0;%d;Inclusion started by button.\n"), C_INTERNAL, I_LOG_MESSAGE);
#endif
buttonTriggeredInclusion = false;
setInclusionMode(true);
}
}
}
void checkInclusionFinished() {
if (inclusionMode && millis()-inclusionStartTime>60000UL*inclusionTime) {
// inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode
setInclusionMode(false);
}
}
void parseAndSend(MySensor &gw, char *commandBuffer) {
boolean ok;
MyMessage &msg = gw.getLastMessage();
if (parser.parse(msg, commandBuffer)) {
uint8_t command = mGetCommand(msg);
if (msg.destination==GATEWAY_ADDRESS && command==C_INTERNAL) {
// Handle messages directed to gateway
if (msg.type == I_VERSION) {
// Request for version
serial(PSTR("0;0;%d;0;%d;%s\n"), C_INTERNAL, I_VERSION, LIBRARY_VERSION);
} else if (msg.type == I_INCLUSION_MODE) {
// Request to change inclusion mode
setInclusionMode(atoi(msg.data) == 1);
}
} else {
#ifdef WITH_LEDS_BLINKING
gw.txBlink(1);
#endif
ok = gw.sendRoute(msg);
if (!ok) {
#ifdef WITH_LEDS_BLINKING
gw.errBlink(1);
#endif
}
}
}
}
void setInclusionMode(boolean newMode) {
if (newMode != inclusionMode) {
inclusionMode = newMode;
// Send back mode change on serial line to ack command
serial(PSTR("0;0;%d;0;%d;%d\n"), C_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0);
if (inclusionMode) {
inclusionStartTime = millis();
}
}
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif
@@ -59,32 +59,38 @@
#include <DigitalIO.h> // This include can be removed when using UIPEthernet module
#include <SPI.h>
#include <MySigningNone.h>
#include <MySigningAtsha204.h>
#include <MySigningAtsha204Soft.h>
#include <MyTransportRFM69.h>
#include <MyTransportNRF24.h>
#include <MyHwATMega328.h>
//#include <MySigningNone.h>
//#include <MySigningAtsha204.h>
//#include <MySigningAtsha204Soft.h>
//#include <MyTransportRFM69.h>
//#include <MyTransportNRF24.h>
//#include <MyHwATMega328.h>
#include <MyGateway.h>
#include <MyProtocolDefault.h>
#include <MyGatewayTransportEthernet.h>
// needed due to Arduino IDE
#include <Ethernet.h>
#define MY_WITH_LEDS_BLINKING
#define MY_INCLUSION_MODE_FEATURE
#define MY_INCLUSION_BUTTON_FEATURE
#define INCLUSION_MODE_TIME 60 // Number of minutes inclusion mode is enabled
#define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button
#define MY_DEFAULT_LED_BLINK_PERIOD 300
#define MY_INCLUSION_MODE_DURATION 60 // Number of minutes inclusion mode is enabled
#define MY_INCLUSION_MODE_BUTTON_PIN 3 // Digital pin used for inclusion mode button
#define MY_DEFAULT_ERR_LED_PIN 7 // Error led pin
#define MY_DEFAULT_RX_LED_PIN 8 // Receive led pin
#define MY_DEFAULT_TX_LED_PIN 9 // the PCB, on board LED
#define RADIO_CE_PIN 5 // radio chip enable
#define RADIO_SPI_SS_PIN 6 // radio SPI serial select
#define RADIO_ERROR_LED_PIN 7 // Error led pin
#define RADIO_RX_LED_PIN 8 // Receive led pin
#define RADIO_TX_LED_PIN 9 // the PCB, on board LED
#include <MySensor.h>
#include <MyProtocolDefault.h>
#include <MyGatewayTransportEthernet.h>
#define IP_PORT 5003 // The port you want to open
#ifndef IP_ADDRESS_DHCP
#define MY_IP_PORT 5003 // The port you want to open
#ifndef MY_IP_ADDRESS_DHCP
// Gateway IP address if not using DHCP
IPAddress myIp (192, 168, 178, 66); // Configure your static ip-address here COMPILE ERROR HERE? Use Arduino IDE 1.5.7 or later!
#endif /* IP_ADDRESS_DHCP */
@@ -122,22 +128,11 @@ MyGatewayTransportEthernet ctrlTransport(protocol, mac, myIp, /* gw port */ CONT
// Construct MyGateway library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h)
// To use LEDs blinking, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h
#ifdef MY_WITH_LEDS_BLINKING
MyGateway gw(ctrlTransport, transport, hw /*, signer*/, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN);
#else
MyGateway gw(ctrlTransport, transport, hw /*, signer*/);
#endif
void setup()
{
gw.begin(NULL
#ifdef MY_INCLUSION_MODE_FEATURE
, INCLUSION_MODE_TIME
#ifdef MY_INCLUSION_BUTTON_FEATURE
, INCLUSION_MODE_PIN
#endif
#endif
);
gw.begin(NULL);
}
void loop() {
@@ -191,7 +191,7 @@ void setup()
//check for saved date in EEPROM
DEBUG_PRINTLN(F("Checking EEPROM for stored date:"));
delay(500);
if (gw.loadState(0) == 0xFF); // EEPROM flag
if (gw.loadState(0) == 0xFF) // EEPROM flag
{
DEBUG_PRINTLN(F("Retreiving last run time from EEPROM..."));
for (int i = 0; i < 4 ; i++)
@@ -439,7 +439,7 @@ void loop()
state = STAND_BY_ALL_OFF;
}
}
else if (state = ZONE_SELECT_MENU)
else if (state == ZONE_SELECT_MENU)
{
displayMenu();
}
@@ -771,6 +771,9 @@ void updateDisplay()
lcd.print(totalTimeRan);
lcd.print(" Minutes ");
}
default:
// what of ZONE_SELECT_MENU?
break;
}
lastUpdateTime = millis();
}
@@ -1,81 +1,9 @@
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* 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.
*
*******************************
*
* REVISION HISTORY
* Version 1.0 - idefix
*
* DESCRIPTION
* Arduino BH1750FVI Light sensor
* communicate using I2C Protocol
* this library enable 2 slave device addresses
* Main address 0x23
* secondary address 0x5C
* connect the sensor as follows :
*
* VCC >>> 5V
* Gnd >>> Gnd
* ADDR >>> NC or GND
* SCL >>> A5
* SDA >>> A4
* http://www.mysensors.org/build/light
*/
#include <MySensor.h>
#include <SPI.h>
#include <MySensor.h>
#include <BH1750.h>
#include <Wire.h>
#define CHILD_ID_LIGHT 0
unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
MyTransportNRF24 transport;
MyHwATMega328 hw;
MySensor gw(transport, hw);
BH1750 lightSensor;
MySensor gw;
// V_LIGHT_LEVEL should only be used for uncalibrated light level 0-100%.
// If your controller supports the new V_LEVEL variable, use this instead for
// transmitting LUX light level.
MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
// MyMessage msg(CHILD_ID_LIGHT, V_LEVEL);
uint16_t lastlux;
void setup()
{
gw.begin();
// Send the sketch version information to the gateway and Controller
gw.sendSketchInfo("Light Lux Sensor", "1.0");
// Register all sensors to gateway (they will be created as child devices)
gw.present(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
lightSensor.begin();
}
void loop()
{
uint16_t lux = lightSensor.readLightLevel();// Get Lux value
Serial.println(lux);
if (lux != lastlux) {
gw.send(msg.set(lux));
lastlux = lux;
}
gw.sleep(SLEEP_TIME);
}
void setup() {}
void loop() {}
@@ -42,7 +42,6 @@ void setup()
// Register all sensors to gw (they will be created as child devices)
gw.present(CHILD_ID_DISTANCE, S_DISTANCE);
gw.present(CHILD_ID_INTENSITY, S_CUSTOM);
boolean metric = gw.getConfig().isMetric;
Serial.begin(115200);
Serial.println("Playing With Fusion: AS3935 Lightning Sensor, SEN-39001");
@@ -118,4 +117,4 @@ void loop()
void AS3935_ISR()
{
AS3935_ISR_Trig = 1;
}␍
}
@@ -0,0 +1,614 @@
/* MyMQTT Client Gateway 0.1b
Created by Norbert Truchsess <norbert.truchsess@t-online.de>
Based on MyMQTT-broker gateway created by Daniel Wiegert <daniel.wiegert@gmail.com>
Based on MySensors Ethernet Gateway by Henrik Ekblad <henrik.ekblad@gmail.com>
http://www.mysensors.org
Changes by Thomas Krebs <thkrebs@gmx.de>
- Add signing support from MySensors 1.5 and update for MySensors 1.5;
- Restructured code back to a C like implementation following the existing MQTTGateway
Requires MySensors lib 1.5
* Change below; TCP_IP, TCP_PORT, TCP_MAC
This will listen on your selected TCP_IP:TCP_PORT below, Please change TCP_MAC your liking also.
*1 -> NOTE: Keep first byte at x2, x6, xA or xE (replace x with any hex value) for using Local Ranges.
*2 You can use standard pin set-up as MySensors recommends or if you own a IBOARD you may change
the radio-pins below if you hardware mod your iBoard. see [URL BELOW] for more details.
http://forum.mysensors.org/topic/224/iboard-cheap-single-board-ethernet-arduino-with-radio/5
* Don't forget to look at the definitions in libraries\MySensors\MyMQTT.h!
define TCPDUMP and connect serial interface if you have problems, please write on
http://forum.mysensors.org/ and explain your problem, include serial output. Don't forget to
turn on DEBUG in libraries\MySensors\MyConfig.h also.
MQTT_FIRST_SENSORID is for 'DHCP' server in MyMQTT. You may limit the ID's with FIRST and LAST definition.
If you want your manually configured below 20 set MQTT_FIRST_SENSORID to 20.
To disable: set MQTT_FIRST_SENSORID to 255.
MQTT_BROKER_PREFIX is the leading prefix for your nodes. This can be only one char if like.
MQTT_SEND_SUBSCRIPTION is if you want the MyMQTT to send a empty payload message to your nodes.
This can be useful if you want to send latest state back to the MQTT client. Just check if incoming
message has any length or not.
Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things.
* Address-layout is : [MQTT_BROKER_PREFIX]/[NodeID]/[SensorID]/V_[SensorType][/set | /get]
NodeID and SensorID is uint8 (0-255) number.
Segment after SensorID is translation of the sensor type, look inside MyMQTT.cpp for the definitions.
User can change this to their needs. We have also left some space for custom types.
Special: (sensor 255 reserved for special commands)
The last seqment is a command to to be send down to the sensor. The gateway is subscribed to topics which have
a command present! This is to avoid that a publish by the gateway will end up in the gateway via it subsription.
You can receive a node sketch name with MyMQTT/20/255/V_Sketch_name (or version with _version)
So far tested in openhab and MyMQTT for Android (Not my creation)
- http://www.openhab.org/
* How to set-up Openhab and MQTTGateway:
http://forum.mysensors.org/topic/303/mqtt-broker-gateway
*/
#include <SPI.h>
#include <MySensor.h>
#include <MyTransport.h>
#include <PubSubClient.h>
#include <Ethernet.h>
#include <DigitalIO.h>
#include <MsTimer2.h>
#include <Time.h>
#include "MyMQTTClient.h"
#ifdef MY_SIGNING_FEATURE
#include <MySigningNone.h>
#include <MySigningAtsha204Soft.h>
#include <MySigningAtsha204.h>
#endif
//#define DSRTC
#ifdef DSRTC
#include <Wire.h>
#include <DS1307RTC.h> // a basic DS1307 library that returns time as a time_t
#endif
/*
* To configure MQTTClientGateway.ino to use an ENC28J60 based board include
* 'UIPEthernet.h' (SPI.h required for MySensors anyway). The UIPEthernet-library can be downloaded
* from: https://github.com/ntruchsess/arduino_uip
*/
//#include <UIPEthernet.h>
/*
* To execute MQTTClientGateway.ino on Yun uncomment Bridge.h and YunClient.h.
* Do not include Ethernet.h or SPI.h in this case.
* On Yun there's no need to configure local_ip and mac in the sketch
* as this is configured on the linux-side of Yun.
*/
//#include <Bridge.h>
//#include <YunClient.h>
// * Use this for IBOARD modded to use standard MISO/MOSI/SCK, see note *1 above!
/*
#define RADIO_CE_PIN 3 // radio chip enable
#define RADIO_SPI_SS_PIN 8 // radio SPI serial select
#define RADIO_ERROR_LED_PIN A2 // Error led pin
#define RADIO_RX_LED_PIN A1 // Receive led pin
#define RADIO_TX_LED_PIN A0 // the PCB, on board LED*/
// * Use this for default configured pro mini / nano etc :
//
//#define RADIO_CE_PIN 5 // radio chip enable
//#define RADIO_SPI_SS_PIN 6 // radio SPI serial select
//#define RADIO_ERROR_LED_PIN 7 // Error led pin
//#define RADIO_RX_LED_PIN 8 // Receive led pin
//#define RADIO_TX_LED_PIN 9 // the PCB, on board LED*/
// CE_PIN and SPI_SS_PIN for Mega
#define RADIO_CE_PIN 48 // radio chip enable
#define RADIO_SPI_SS_PIN 49 // radio SPI serial select
#define RADIO_ERROR_LED_PIN A2 // Error led pin
#define RADIO_RX_LED_PIN A1 // Receive led pin
#define RADIO_TX_LED_PIN A0 // the PCB, on board LED*/
//replace with ip of server you want to connect to, comment out if using 'remote_host'
uint8_t remote_ip[] = { 192, 168, 178, 74 }; // Mosquitto broker
//replace with hostname of server you want to connect to, comment out if using 'remote_ip'
//char* remote_ip = "server.local";
//replace with the port that your server is listening on
#define remote_port 1883
//replace with arduinos ip-address. Comment out if Ethernet-startup should use dhcp. Is ignored on Yun
uint8_t local_ip[] = {192, 168, 178, 11};
//replace with ethernet shield mac. It's mandatory every device is assigned a unique mac. Is ignored on Yun
uint8_t mac[] = { 0xA2, 0xAE, 0xAD, 0xA0, 0xA0, 0xA2 };
#if defined remote_ip && defined remote_host
#error "cannot define both remote_ip and remote_host at the same time!"
#endif
#ifdef _YUN_CLIENT_H_
YunClient ethClient;
#else
EthernetClient ethClient;
#endif
////////////////////////////////////////////////////////////////
// NRFRF24L01 radio driver (set low transmit power by default)
MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW);
//MyTransportRFM69 transport;
// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h)
//MySigningNone signer;
//MySigningAtsha204Soft signer(true);
//MySigningAtsha204 signer;
// Hardware profile
MyHwATMega328 hw;
MyMessage msg;
char convBuf[MAX_PAYLOAD * 2 + 1];
uint8_t buffsize;
char buffer[MQTT_MAX_PACKET_SIZE];
char user[sizeof(MQTT_USER)]; // introduced the bufs to get rid of compiler warnings
char pwd[sizeof(MQTT_PWD)]; // see above
char connID[sizeof(MQTT_CONN_ID)]; // see above
char mqttTopicMask[sizeof(MQTT_TOPIC_MASK)]; // see above
////////////////////////////////////////////////////////////////
volatile uint8_t countRx;
volatile uint8_t countTx;
volatile uint8_t countErr;
////////////////////////////////////////////////////////////////
void processMQTTMessages(char* topic, byte* payload, unsigned int length);
PubSubClient client(remote_ip, remote_port, processMQTTMessages, ethClient);
////////////////////////////////////////////////////////////////
// Declare and initialize MySensor instance
// Construct MyMQTTClient (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h, if signing
// feature not to be used, uncomment)
// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h
MySensor gw(transport, hw
#ifdef MY_SIGNING_FEATURE
, signer
#endif
#ifdef WITH_LEDS_BLINKING
, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN
#endif
);
/*
* setup
*/
void setup()
{
strcpy(connID,MQTT_CONN_ID);
strcpy(mqttTopicMask,MQTT_TOPIC_MASK);
countRx = 0;
countTx = 0;
countErr = 0;
Ethernet.begin(mac, local_ip);
//Bridge.begin();
delay(1000); // Wait for Ethernet to get configured.
begin();
}
/*
* loop
*/
void loop()
{
if (!client.connected())
{
boolean ret;
#ifdef MQTT_AUTH_REQUIRED
strcpy(user, MQTT_USER);
strcpy(pwd, MQTT_PWD);
ret = client.connect(connID, user,pwd);
#else
ret = client.connect(connID);
#endif
if (ret) {
Serial.println("Connected to MQTT broker");
} else {
Serial.println("Connection to MQTT broker failed");
}
client.subscribe(mqttTopicMask);
}
client.loop();
gw.process();
}
/*
* processRadioMessage
*
* Receives radio message, parses it and forwards it to the MQTT broker
*/
void processRadioMessage(const MyMessage &message)
{
rxBlink(1);
sendMQTT(message);
}
/*
* sendMQTT
* Handles processing of radio messages and eventually publishes it to the MQTT broker
*/
void sendMQTT(const MyMessage &inMsg)
{
MyMessage msg = inMsg;
buffsize = 0;
if (!client.connected())
return; //We have no connections - return
if (msg.isAck())
{
#ifdef DEBUG
Serial.println("msg is ack!");
#endif
if (msg.sender == 255 && mGetCommand(msg) == C_INTERNAL
&& msg.type == I_ID_REQUEST)
{
// TODO: sending ACK request on id_response fucks node up. doesn't work.
// The idea was to confirm id and save to EEPROM_LATEST_NODE_ADDRESS.
}
}
else
{
// we have to check every message if its a newly assigned id or not.
// Ack on I_ID_RESPONSE does not work, and checking on C_PRESENTATION isn't reliable.
uint8_t newNodeID = gw.loadState(EEPROM_LATEST_NODE_ADDRESS) + 1;
if (newNodeID <= MQTT_FIRST_SENSORID)
newNodeID = MQTT_FIRST_SENSORID;
if (msg.sender == newNodeID)
{
gw.saveState(EEPROM_LATEST_NODE_ADDRESS, newNodeID);
}
if (mGetCommand(msg) == C_INTERNAL)
{
if (msg.type == I_CONFIG)
{
txBlink(1);
if (!gw.sendRoute(
build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL,
I_CONFIG, 0).set("M")))
errBlink(1);
}
else if (msg.type == I_TIME)
{
#ifdef DEBUG
Serial.println("I_TIME requested!");
#endif
txBlink(1);
if (!gw.sendRoute(
build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL,
I_TIME, 0).set(now())))
errBlink(1);
}
else if (msg.type == I_ID_REQUEST && msg.sender == 255)
{
uint8_t newNodeID = gw.loadState(EEPROM_LATEST_NODE_ADDRESS) + 1;
if (newNodeID <= MQTT_FIRST_SENSORID)
newNodeID = MQTT_FIRST_SENSORID;
if (newNodeID >= MQTT_LAST_SENSORID)
return; // Sorry no more id's left :(
txBlink(1);
if (!gw.sendRoute(
build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL,
I_ID_RESPONSE, 0).set(newNodeID)))
errBlink(1);
}
else if (msg.type == I_BATTERY_LEVEL)
{
strcpy_P(buffer, mqtt_prefix);
buffsize += strlen_P(mqtt_prefix);
buffsize += sprintf(&buffer[buffsize], "/%i/255/BATTERY_LEVEL", msg.sender );
msg.getString(convBuf);
#ifdef DEBUG
Serial.print("publish: ");
Serial.print((char*) buffer);
Serial.print(" ");
Serial.println((char*) convBuf);
#endif
client.publish(buffer, convBuf);
}
else if (msg.type == I_SKETCH_NAME)
{
strcpy_P(buffer, mqtt_prefix);
buffsize += strlen_P(mqtt_prefix);
buffsize += sprintf(&buffer[buffsize], "/%i/255/SKETCH_NAME", msg.sender );
msg.getString(convBuf);
#ifdef DEBUG
Serial.print("publish: ");
Serial.print((char*) buffer);
Serial.print(" ");
Serial.println((char*) convBuf);
#endif
client.publish(buffer, convBuf);
}
else if (msg.type == I_SKETCH_VERSION)
{
strcpy_P(buffer, mqtt_prefix);
buffsize += strlen_P(mqtt_prefix);
buffsize += sprintf(&buffer[buffsize], "/%i/255/SKETCH_VERSION", msg.sender );
msg.getString(convBuf);
#ifdef DEBUG
Serial.print("publish: ");
Serial.print((char*) buffer);
Serial.print(" ");
Serial.println((char*) convBuf);
#endif
client.publish(buffer, convBuf);
}
}
else if (mGetCommand(msg) != 0)
{
if (mGetCommand(msg) == 3)
msg.type = msg.type + (S_FIRSTCUSTOM - 10); //Special message
if (msg.type > VAR_TOTAL)
msg.type = VAR_TOTAL; // If type > defined types set to unknown.
strcpy_P(buffer, mqtt_prefix);
buffsize += strlen_P(mqtt_prefix);
buffsize += sprintf(&buffer[buffsize], "/%i/%i/V_%s", msg.sender,
msg.sensor, getType(convBuf, &VAR_Type[msg.type]));
msg.getString(convBuf);
#ifdef DEBUG
Serial.print("publish: ");
Serial.print((char*) buffer);
Serial.print(" ");
Serial.println((char*) convBuf);
#endif
client.publish(buffer, convBuf);
}
}
}
/*
* build
* Constructs a radio message
*/
inline MyMessage& build(MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor,
uint8_t command, uint8_t type, bool enableAck)
{
msg.destination = destination;
msg.sender = sender;
msg.sensor = sensor;
msg.type = type;
mSetCommand(msg, command);
mSetRequestAck(msg, enableAck);
mSetAck(msg, false);
return msg;
}
/*
* getType
*/
char *getType(char *b, const char **index)
{
char *q = b;
char *p = (char *) pgm_read_word(index);
while (*q++ = pgm_read_byte(p++))
;
*q = 0;
return b;
}
/*
* begin
* wraps MySensors begin method; setup of RTC and led timers interrupt
*/
void begin()
{
#ifdef DEBUG
Serial.begin(BAUD_RATE);
#endif
#ifdef DSRTC
// Attach RTC
setSyncProvider(RTC.get); // the function to get the time from the RTC
setSyncInterval(60);
#endif
gw.begin(processRadioMessage, 0, true, 0);
MsTimer2::set(200, ledTimersInterrupt);
MsTimer2::start();
#ifdef DEBUG
Serial.print(getType(convBuf, &VAR_Type[S_FIRSTCUSTOM]));
#endif
}
/*
* processMQTTMessages
* message handler for the PubSubClient
*/
void processMQTTMessages(char* topic, byte* payload, unsigned int length)
{
processMQTTMessage(topic, payload, length);
}
/*
* processMQTTMessage
* processes MQTT messages, parses the topic, extracts radio address out of topic and sends them
* to the respective radio
*/
void processMQTTMessage(char* topic, byte* payload,
unsigned int length)
{
char *str, *p;
uint8_t i = 0;
buffer[0] = 0;
buffsize = 0;
int8_t cmd = -1;
for (str = strtok_r(topic, "/", &p); str && i < 5;
str = strtok_r(NULL, "/", &p))
{
switch (i)
{
case 0:
{
if (strcmp_P(str, mqtt_prefix) != 0)
{ //look for MQTT_PREFIX
return; //Message not for us or malformatted!
}
break;
}
case 1:
{
msg.destination = atoi(str); //NodeID
break;
}
case 2:
{
msg.sensor = atoi(str); //SensorID
break;
}
case 3:
{
char match = 0; //SensorType
//strcpy(str,(char*)&str[2]); //Strip VAR_
for (uint8_t j = 0;
strcpy_P(convBuf, (char*) pgm_read_word(&(VAR_Type[j]))); j++)
{
if (strcmp((char*) &str[2], convBuf) == 0)
{ //Strip VAR_ and compare
match = j;
break;
}
if (j >= VAR_TOTAL)
{ // No match found!
match = VAR_TOTAL; // last item.
break;
}
}
msg.type = match;
break;
}
case 4:
{
// support the command get and set; get will be mapped to a C_REQ and set to C_SET
if (strcmp(str,MQTT_CMD_SET) == 0)
{
cmd = C_SET;
}
else if (strcmp(str,MQTT_CMD_GET) == 0) {
cmd = C_REQ;
}
else {
#ifdef DEBUG
Serial.print("Received unsupported command - ignore: ");
Serial.println(str);
#endif
}
}
}
i++;
} //Check if packge has payload
if (cmd != -1) {
char* ca;
ca = (char *)payload;
ca += length;
*ca = '\0';
msg.set((const char*)payload); //Payload
txBlink(1);
// inject time
if ((msg.destination == 0) && (msg.sensor == 199)) {
unsigned long epoch = atol((char*)payload);
if (epoch > 10000) {
#ifdef DSRTC
RTC.set(epoch); // this sets the RTC to the time from controller - which we do want periodically
#endif
setTime(epoch);
}
#ifdef DEBUG
Serial.print("Time received ");
Serial.println(epoch);
#endif
}
//
if (!gw.sendRoute(
build(msg, GATEWAY_ADDRESS, msg.destination, msg.sensor, C_SET, msg.type,
0)))
errBlink(1);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Led handling
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
* ledTimersIntterupt
*/
void ledTimersInterrupt() {
if (countRx && countRx != 255) {
// switch led on
digitalWrite(RADIO_RX_LED_PIN, LOW);
} else if (!countRx) {
// switching off
digitalWrite(RADIO_RX_LED_PIN, HIGH);
}
if (countRx != 255) {
countRx--;
}
if (countTx && countTx != 255) {
// switch led on
digitalWrite(RADIO_TX_LED_PIN, LOW);
} else if (!countTx) {
// switching off
digitalWrite(RADIO_TX_LED_PIN, HIGH);
}
if (countTx != 255) {
countTx--;
}
if (countErr && countErr != 255) {
// switch led on
digitalWrite(RADIO_ERROR_LED_PIN, LOW);
} else if (!countErr) {
// switching off
digitalWrite(RADIO_ERROR_LED_PIN, HIGH);
}
if (countErr != 255) {
countErr--;
}
}
void rxBlink(uint8_t cnt)
{
if (countRx == 255)
{
countRx = cnt;
}
}
void txBlink(uint8_t cnt)
{
if (countTx == 255)
{
countTx = cnt;
}
}
void errBlink(uint8_t cnt)
{
if (countErr == 255)
{
countErr = cnt;
}
}
@@ -0,0 +1,129 @@
/*
The MySensors 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>
Modified by Daniel Wiegert
Modified by Norbert Truchsess <norbert.truchsess@t-online.de>
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 MyMQTTClient_h
#define MyMQTTClient_h
//////////////////////////////////////////////////////////////////
#ifdef DEBUG
#define TCPDUMP // Dump TCP packages.
#endif
#define MQTT_FIRST_SENSORID 20 // If you want manually configured nodes below this value. 255 = Disable
#define MQTT_LAST_SENSORID 254 // 254 is max! 255 reserved.
#define MQTT_PREFIX "MyMQTT" // First prefix in MQTT tree, keep short!
#define MQTT_TOPIC_MASK "MyMQTT/+/+/+/+" // Topic mask the client will subscribe to. This ensures that it will not receive any sensor data send by sensors
// the following topic structure is assumed: MyMQTT/<node-id>/<child_id>/<sensor-type>/<cmd>
#define MQTT_SEND_SUBSCRIPTION 1 // Send empty payload (request) to node upon MQTT client subscribe request.
#define MQTT_CMD_SET "set" // command (see MQTT_TOPIC_MASK); mapped to C_SET command type of sensor network
#define MQTT_CMD_GET "get" // command (see MQTT_TOPIC_MASK); mapped to C_REQ command type of sensor network
#define MQTT_AUTH_REQUIRED // if your broker has anonymous access uncomment
#define MQTT_USER "user" // username on MQTT broker
#define MQTT_PWD "pwd" // password for MQTT username above
#define MQTT_CONN_ID "MySensors" // passed as id to the MQTT broker
// NOTE above : Beware to check if there is any length on payload in your incommingMessage code:
// Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things.
//////////////////////////////////////////////////////////////////
char VAR_0[] PROGMEM = "TEMP"; //V_TEMP
char VAR_1[] PROGMEM = "HUM"; //V_HUM
char VAR_2[] PROGMEM = "LIGHT"; //V_LIGHT
char VAR_3[] PROGMEM = "DIMMER"; //V_DIMMER
char VAR_4[] PROGMEM = "PRESSURE"; //V_PRESSURE
char VAR_5[] PROGMEM = "FORECAST"; //V_FORECAST
char VAR_6[] PROGMEM = "RAIN"; //V_RAIN
char VAR_7[] PROGMEM = "RAINRATE"; //V_RAINRATE
char VAR_8[] PROGMEM = "WIND"; //V_WIND
char VAR_9[] PROGMEM = "GUST"; //V_GUST
char VAR_10[] PROGMEM = "DIRECTON"; //V_DIRECTON
char VAR_11[] PROGMEM = "UV"; //V_UV
char VAR_12[] PROGMEM = "WEIGHT"; //V_WEIGHT
char VAR_13[] PROGMEM = "DISTANCE"; //V_DISTANCE
char VAR_14[] PROGMEM = "IMPEDANCE"; //V_IMPEDANCE
char VAR_15[] PROGMEM = "ARMED"; //V_ARMED
char VAR_16[] PROGMEM = "TRIPPED"; //V_TRIPPED
char VAR_17[] PROGMEM = "WATT"; //V_WATT
char VAR_18[] PROGMEM = "KWH"; //V_KWH
char VAR_19[] PROGMEM = "SCENE_ON"; //V_SCENE_ON
char VAR_20[] PROGMEM = "SCENE_OFF"; //V_SCENE_OFF
char VAR_21[] PROGMEM = "HEATER"; //V_HEATER
char VAR_22[] PROGMEM = "HEATER_SW"; //V_HEATER_SW
char VAR_23[] PROGMEM = "LIGHT_LEVEL"; //V_LIGHT_LEVEL
char VAR_24[] PROGMEM = "VAR1"; //V_VAR1
char VAR_25[] PROGMEM = "VAR2"; //V_VAR2
char VAR_26[] PROGMEM = "VAR3"; //V_VAR3
char VAR_27[] PROGMEM = "VAR4"; //V_VAR4
char VAR_28[] PROGMEM = "VAR5"; //V_VAR5
char VAR_29[] PROGMEM = "UP"; //V_UP
char VAR_30[] PROGMEM = "DOWN"; //V_DOWN
char VAR_31[] PROGMEM = "STOP"; //V_STOP
char VAR_32[] PROGMEM = "IR_SEND"; //V_IR_SEND
char VAR_33[] PROGMEM = "IR_RECEIVE"; //V_IR_RECEIVE
char VAR_34[] PROGMEM = "FLOW"; //V_FLOW
char VAR_35[] PROGMEM = "VOLUME"; //V_VOLUME
char VAR_36[] PROGMEM = "LOCK_STATUS"; //V_LOCK_STATUS
char VAR_37[] PROGMEM = "LEVEL"; // S_DUST, S_LIGHT_LEVEL, ...
char VAR_38[] PROGMEM = "VOLTAGE"; //V_VOLTAGE
char VAR_39[] PROGMEM = "CURRENT"; //V_CURRENT
char VAR_40[] PROGMEM = "RGB"; //V_RGB
char VAR_41[] PROGMEM = ""; //
char VAR_42[] PROGMEM = ""; //
char VAR_43[] PROGMEM = ""; //
char VAR_44[] PROGMEM = ""; //
char VAR_45[] PROGMEM = ""; //
char VAR_46[] PROGMEM = ""; //
char VAR_47[] PROGMEM = ""; //
char VAR_48[] PROGMEM = ""; //
char VAR_49[] PROGMEM = ""; //
char VAR_50[] PROGMEM = ""; //
char VAR_51[] PROGMEM = ""; //
char VAR_52[] PROGMEM = ""; //
char VAR_53[] PROGMEM = ""; //
char VAR_54[] PROGMEM = ""; //
char VAR_55[] PROGMEM = ""; //
char VAR_56[] PROGMEM = ""; //
char VAR_57[] PROGMEM = ""; //
char VAR_58[] PROGMEM = ""; //
char VAR_59[] PROGMEM = ""; //
char VAR_60[] PROGMEM = "Started!\n"; //Custom for MQTTGateway
char VAR_61[] PROGMEM = "SKETCH_NAME"; //Custom for MQTTGateway
char VAR_62[] PROGMEM = "SKETCH_VERSION"; //Custom for MQTTGateway
char VAR_63[] PROGMEM = "UNKNOWN"; //Custom for MQTTGateway
//////////////////////////////////////////////////////////////////
PROGMEM const char *VAR_Type[] =
{ VAR_0, VAR_1, VAR_2, VAR_3, VAR_4, VAR_5, VAR_6, VAR_7, VAR_8, VAR_9, VAR_10, VAR_11, VAR_12, VAR_13,
VAR_14, VAR_15, VAR_16, VAR_17, VAR_18, VAR_19, VAR_20, VAR_21, VAR_22, VAR_23, VAR_24, VAR_25,
VAR_26, VAR_27, VAR_28, VAR_29, VAR_30, VAR_31, VAR_32, VAR_33, VAR_34, VAR_35, VAR_36, VAR_37,
VAR_38, VAR_39, VAR_40, VAR_41, VAR_42, VAR_43, VAR_44, VAR_45, VAR_46, VAR_47, VAR_48, VAR_49,
VAR_50, VAR_51, VAR_52, VAR_53, VAR_54, VAR_55, VAR_56, VAR_57, VAR_58, VAR_59, VAR_60, VAR_61,
VAR_62, VAR_63
};
char mqtt_prefix[] PROGMEM = MQTT_PREFIX;
#define S_FIRSTCUSTOM 60
#define TYPEMAXLEN 20
#define VAR_TOTAL (sizeof(VAR_Type)/sizeof(char *))-1
#define EEPROM_LATEST_NODE_ADDRESS ((uint8_t)EEPROM_LOCAL_CONFIG_ADDRESS)
//#define DSRTC // RTC Dallas support -> disable debug and use isp programmer to free memory
#endif
@@ -279,6 +279,7 @@ void processMQTTMessage(char *inputString, uint8_t inputPos) {
uint8_t i = 0;
buffer[0]= 0;
buffsize = 0;
(void)inputPos;
if ((uint8_t)inputString[0] >> 4 == MQTTCONNECT) {
buffer[buffsize++] = MQTTCONNACK << 4;
@@ -336,7 +337,7 @@ void processMQTTMessage(char *inputString, uint8_t inputPos) {
} else if (i==2) {
msg.sensor = atoi(str); //SensorID
} else if (i==3) {
char match=255; //SensorType
unsigned char match=255; //SensorType
#ifdef MQTT_TRANSLATE_TYPES
for (uint8_t j=0; strcpy_P(convBuf, (char*)pgm_read_word(&(vType[j]))) ; j++) {
@@ -348,7 +349,7 @@ void processMQTTMessage(char *inputString, uint8_t inputPos) {
}
#endif
if ( atoi(str)!=0 || str=="0" ) {
if ( atoi(str)!=0 || (str[0]=='0' && str[1] =='\0') ) {
match=atoi(str);
}
File diff suppressed because it is too large Load Diff
@@ -3,13 +3,38 @@ Arduino sketch to fake sensor for the MySensors Library
This skecth is intended to crate fake sensors which register and respond to the controller
Barduino 2015
Barduino, GizMoCuz 2015
-----------------
Comment/Uncomment the sensors you would like to test
Arduino Uno R3 can support about 12 sensors before it runs out of memory.
You probably need to turn of the MySensor Lib debug to save some memory
(turning off the MySensors debug helps if you are memory limited)
Nest step will be to remove the read/write to the eprom
and extend to support the v1.5 sensors
With a Mega you can have them all
Changes Log
-----------------
2015-09-07
Five more sensors
S_RGB_LIGHT
S_RGBW_LIGHT
S_COLOR_SENSOR
S_HVAC
S_MULTIMETER
Consolidated HVAC and HEATER incoming message
2015-09-06
Merge with Gizmocuz (implementation of S_HEATER & S_MOISTURE
Implementation of S_COVER, S_IR, S_SCENE_CONTROLLER
2015-08-19
Removed the load/save to eeprom
Touched the heater sensor
Created a pseudo sensor to handle the V_ARMED message.
All sensors which support V_ARMED will arm/disarm at the same time
@@ -56,6 +56,8 @@
#define PANIC_DISTANCE 5 // Mix distance we red warning indication should be active (in cm)
#define PARKED_DISTANCE 20 // Distance when "parked signal" should be sent to controller (in cm)
#define PARK_OFF_TIMEOUT 20000 // Number of milliseconds until turning off light when parked.
// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
// example for more information on possible values.
@@ -67,17 +69,18 @@ NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and
#define CHILD_ID 1
MySensor gw;
MyMessage msg(CHILD_ID,V_TRIPPED);
int oldParkedStatus=-1;
int sendInterval = 5000; // Send park status at maximum every 5 second.
unsigned long lastSend;
#endif
unsigned long sendInterval = 5000; // Send park status at maximum every 5 second.
unsigned long lastSend;
int blinkInterval = 100; // blink interval (milliseconds)
int oldParkedStatus=-1;
unsigned long blinkInterval = 100; // blink interval (milliseconds)
unsigned long lastBlinkPeriod;
bool blinkColor = true;
// To make a fading motion on the led ring/tape we only move one pixel/distDebounce time
int distDebounce = 30;
unsigned long distDebounce = 30;
unsigned long lastDebouncePeriod;
int numLightPixels=0;
int skipZero=0;
@@ -109,7 +112,6 @@ void loop() {
if (now-lastDebouncePeriod > distDebounce) {
lastDebouncePeriod = now;
#ifdef SEND_STATUS_TO_CONTROLLER
// Update parked status
int parked = displayDist != 0 && displayDist<PARKED_DISTANCE;
if (parked != oldParkedStatus && now-lastSend > sendInterval) {
@@ -117,47 +119,55 @@ void loop() {
Serial.println("Car Parked");
else
Serial.println("Car Gone");
#ifdef SEND_STATUS_TO_CONTROLLER
gw.send(msg.set(parked));
#endif
oldParkedStatus = parked;
lastSend = now;
}
#endif
if (displayDist == 0) {
// No reading from sensor, assume no object found
numLightPixels--;
} else {
skipZero = 0;
int newLightPixels = NUMPIXELS - (NUMPIXELS*(displayDist-PANIC_DISTANCE)/MAX_DISTANCE);
if (newLightPixels>numLightPixels) {
// Fast raise
numLightPixels += max((newLightPixels - numLightPixels) / 2, 1);
} else if (newLightPixels<numLightPixels) {
// Slow decent
numLightPixels--;
}
}
if (numLightPixels>=NUMPIXELS) {
// Do some intense red blinking
if (now-lastBlinkPeriod > blinkInterval) {
blinkColor = !blinkColor;
lastBlinkPeriod = now;
}
for(int i=0;i<numLightPixels;i++){
pixels.setPixelColor(i, pixels.Color(blinkColor?255*MAX_INTESITY/100:0,0,0));
}
} else {
for(int i=0;i<numLightPixels;i++){
int r = 255 * i/NUMPIXELS;
int g = 255 - r;
// pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
pixels.setPixelColor(i, pixels.Color(r*MAX_INTESITY/100,g*MAX_INTESITY/100,0));
}
// Turn off the rest
for(int i=numLightPixels;i<NUMPIXELS;i++){
if (parked && now-lastSend > PARK_OFF_TIMEOUT) {
// We've been parked for a while now. Turn off all pixels
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(0,0,0));
}
} else {
if (displayDist == 0) {
// No reading from sensor, assume no object found
numLightPixels--;
} else {
skipZero = 0;
int newLightPixels = NUMPIXELS - (NUMPIXELS*(displayDist-PANIC_DISTANCE)/MAX_DISTANCE);
if (newLightPixels>numLightPixels) {
// Fast raise
numLightPixels += max((newLightPixels - numLightPixels) / 2, 1);
} else if (newLightPixels<numLightPixels) {
// Slow decent
numLightPixels--;
}
}
if (numLightPixels>=NUMPIXELS) {
// Do some intense red blinking
if (now-lastBlinkPeriod > blinkInterval) {
blinkColor = !blinkColor;
lastBlinkPeriod = now;
}
for(int i=0;i<numLightPixels;i++){
pixels.setPixelColor(i, pixels.Color(blinkColor?255*MAX_INTESITY/100:0,0,0));
}
} else {
for(int i=0;i<numLightPixels;i++){
int r = 255 * i/NUMPIXELS;
int g = 255 - r;
// pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
pixels.setPixelColor(i, pixels.Color(r*MAX_INTESITY/100,g*MAX_INTESITY/100,0));
}
// Turn off the rest
for(int i=numLightPixels;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(0,0,0));
}
}
}
pixels.show(); // This sends the updated pixel color to the hardware.
}
@@ -0,0 +1,305 @@
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* 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.
*
*******************************
*
* REVISION HISTORY
* Version 1.0 - Created by vil1driver
*
* DESCRIPTION
* RGB led strip controled with three dimmers + one On/Off for run/stop rgb color cycle :p
*
*/
#define SN "RGB Led strip 3D"
#define SV "v1"
// Load mysensors library
#include <MySensor.h>
// Load Serial Peripheral Interface library
#include <SPI.h>
// Arduino pin attached to MOSFET Gate pin
#define RED_PIN 3
#define GREEN_PIN 5
#define BLUE_PIN 6
MySensor gw;
// Define message name and type to send sensor info
MyMessage RedStatus(RED_PIN, V_DIMMER);
MyMessage GreenStatus(GREEN_PIN, V_DIMMER);
MyMessage BlueStatus(BLUE_PIN, V_DIMMER);
MyMessage Status(1, V_DIMMER);
MyMessage rgbShowState(0, V_LIGHT);
// Serial.print translate sensor id to sensor name
char color[][6] = {"","","","RED","","GREEN","BLUE"};
// Vars for rgbShow function
int redval = 0;
int greenval = 0;
int blueval = 0;
long time=0;
int isShow;
void setup()
{
// Initializes the sensor node (Callback function for incoming messages, node id, is repeater)
gw.begin(incomingMessage, 31, true);
// Present sketch (name, version)
gw.sendSketchInfo(SN, SV);
// Register sensors (id, type, description, ack back)
gw.present(RED_PIN, S_DIMMER, "present RED light", false);
gw.present(GREEN_PIN, S_DIMMER, "present GREEN light", false);
gw.present(BLUE_PIN, S_DIMMER, "present BLUE light", false);
gw.present(0, S_LIGHT, "present Show button", false);
// Define pin mode (pin number, type)
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
// Correct saved RGB value for first start
gw.saveState(RED_PIN, constrain((int8_t)gw.loadState(RED_PIN), 0, 100));
gw.saveState(GREEN_PIN, constrain((int8_t)gw.loadState(GREEN_PIN), 0, 100));
gw.saveState(BLUE_PIN, constrain((int8_t)gw.loadState(BLUE_PIN), 0, 100));
// Get value from eeprom and write to output
analogWrite(RED_PIN, 255 * gw.loadState(RED_PIN) / 100);
analogWrite(GREEN_PIN, 255 * gw.loadState(GREEN_PIN) / 100);
analogWrite(BLUE_PIN, 255 * gw.loadState(BLUE_PIN) / 100);
// Write some debug info
Serial.print("Load from eeprom RED: ");
Serial.print(gw.loadState(RED_PIN));
Serial.println("%");
Serial.print("Load from eeprom GREEN: ");
Serial.print(gw.loadState(GREEN_PIN));
Serial.println("%");
Serial.print("Load from eeprom BLUE: ");
Serial.print(gw.loadState(BLUE_PIN));
Serial.println("%");
// Send RGB value to controler (request ack back: true/false)
Serial.println("Send eeprom value to controler");
gw.send( RedStatus.set(gw.loadState(RED_PIN)), false );
gw.send( GreenStatus.set(gw.loadState(GREEN_PIN)), false );
gw.send( BlueStatus.set(gw.loadState(BLUE_PIN)), false );
// Correct RGB show state for first start and load it (set to 'On' at first start)
gw.saveState(0, constrain((int8_t)gw.loadState(0), 0, 1));
isShow=gw.loadState(0);
// Send RGB show state to controler (request ack back: true/false)
gw.send( rgbShowState.set(isShow), false);
if (isShow==1){Serial.println("RGB show running..."); }
Serial.println("Ready to receive messages...");
}
void loop()
{
// Process incoming messages (like config and light state from controller)
gw.process();
// Run RGB show if is set
if (isShow==1)
{
rgbShow();
analogWrite(RED_PIN, redval);
analogWrite(GREEN_PIN, greenval);
analogWrite(BLUE_PIN, blueval);
}
}
void incomingMessage(const MyMessage &message)
{
if (message.isAck())
{
Serial.println("Got ack from gateway");
}
if (message.type == V_LIGHT)
{
// Incoming on/off command sent from controller ("1" or "0")
int lightState = message.getString()[0] == '1';
// if receive RGB Show On commands, start the show
if (message.sensor==0 && lightState==1){ rgbShowOn(); }
// if receive RGB Show Off commands, stop the show
else if (message.sensor==0 && lightState==0){ rgbShowOff(); }
// if receive RGB switch On command
else if (lightState==1)
{
// Write some debug info
Serial.print("Incoming change for ");
Serial.print(color[message.sensor]);
Serial.println(": On");
Serial.print("Load from eeprom: ");
if ( gw.loadState(message.sensor) == 0)
{
// Pick up last saved dimmer level from the eeprom
analogWrite(message.sensor, 255 * gw.loadState(10*message.sensor) / 100);
// Save loaded value to current
gw.saveState(message.sensor, gw.loadState(10*message.sensor));
Serial.print(gw.loadState(10*message.sensor));
Serial.println("%");
// Send value to controler
Serial.println("Send value to controler");
gw.send(Status.setSensor(message.sensor).set(gw.loadState(10*message.sensor)),false);
}
else
{
// Pick up last saved dimmer level from the eeprom
analogWrite(message.sensor, 255 * gw.loadState(message.sensor) / 100);
Serial.print(gw.loadState(message.sensor));
Serial.println("%");
// Send value to controler
Serial.println("Send value to controler");
gw.send(Status.setSensor(message.sensor).set(gw.loadState(message.sensor)),false);
}
// Stop the show if it's running
if (isShow==1){ rgbShowStop(message.sensor); }
}
// if recieve switch Off command
else if (lightState==0)
{
// Write output to 0 (Off)
analogWrite(message.sensor, 0);
// Save old value to eeprom if it'was not zero
if ( gw.loadState(message.sensor) != 0 )
{
gw.saveState(10*message.sensor, constrain((int8_t)gw.loadState(message.sensor), 0, 100));
}
// Save new value to eeprom
gw.saveState(message.sensor, 0);
// Write some debug info
Serial.print("Incoming change for ");
Serial.print(color[message.sensor]);
Serial.print(": ");
Serial.println("Off");
Serial.print("Store old value: ");
Serial.print(gw.loadState(10*message.sensor));
Serial.println("%");
// Send value to controler
Serial.println("Send value to controler");
gw.send(Status.setSensor(message.sensor).set(gw.loadState(message.sensor)),false);
// Stop the show if it's running
if (isShow==1){ rgbShowStop(message.sensor); }
}
}
else if (message.type == V_DIMMER)
{
uint8_t incomingDimmerStatus = message.getByte();
// limits range of sensor values to between 0 and 100
incomingDimmerStatus = constrain((int8_t)incomingDimmerStatus, 0, 100);
// Change Dimmer level
analogWrite(message.sensor, 255 * incomingDimmerStatus / 100);
//Save value to eeprom
gw.saveState(message.sensor, incomingDimmerStatus);
// Write some debug info
Serial.print("Incoming change for ");
Serial.print(color[message.sensor]);
Serial.print(": ");
Serial.print(incomingDimmerStatus);
Serial.println("%");
// Send value to controler
Serial.println("Send value to controler");
gw.send(Status.setSensor(message.sensor).set(gw.loadState(message.sensor)),false);
// Stop the show if it's running
if (isShow==1){ rgbShowStop(message.sensor); }
}
}
void rgbShow()
{
time = millis();
redval = 128+250*cos(2*PI/300000*time);
greenval = 128+250*cos(2*PI/300000*time-222);
blueval = 128+250*cos(2*PI/300000*time-111);
// limits range of sensor values to between 0 and 255
redval = constrain(redval, 0, 255);
greenval = constrain(greenval, 0, 255);
blueval = constrain(blueval, 0, 255);
}
void rgbShowOn()
{
// define show On
isShow=1;
// Save state
gw.saveState(0, 1);
// Write some debug info
Serial.println("Show must go on");
}
void rgbShowOff()
{
// define show Off
isShow=0;
// Save state
gw.saveState(0, 0);
// Save RGB value to eeprom
gw.saveState(RED_PIN, 100 * redval / 255);
gw.saveState(GREEN_PIN, 100 * greenval / 255);
gw.saveState(BLUE_PIN, 100 * blueval / 255);
// Write some debug info
Serial.println("Stop the show");
// Send actual RGB value and state to controler and request ack back (true/false)
Serial.println("Send eeprom value to controler");
gw.send( RedStatus.set(gw.loadState(RED_PIN)), false );
gw.send( GreenStatus.set(gw.loadState(GREEN_PIN)), false );
gw.send( BlueStatus.set(gw.loadState(BLUE_PIN)), false );
gw.send( rgbShowState.set(0), false);
}
void rgbShowStop(int sensor)
{
// define show Off
isShow=0;
// Save state
gw.saveState(0, 0);
// Write some debug info
Serial.println("Stop the show");
// Send actual RGB value and state to controler and request ack back (true/false)
Serial.println("Send eeprom value to controler");
if (sensor != RED_PIN)
{
gw.saveState(RED_PIN, 100 * redval / 255);
gw.send( RedStatus.set(gw.loadState(RED_PIN)), false );
}
if (sensor != GREEN_PIN)
{
gw.saveState(GREEN_PIN, 100 * greenval / 255);
gw.send( GreenStatus.set(gw.loadState(GREEN_PIN)), false );
}
if (sensor != BLUE_PIN)
{
gw.saveState(BLUE_PIN, 100 * blueval / 255);
gw.send( BlueStatus.set(gw.loadState(BLUE_PIN)), false );
}
gw.send( rgbShowState.set(0), false);
}
@@ -123,7 +123,7 @@ volatile int wasTippedBuffer = 0;
int rainSensorThreshold = 50; //default rain sensor sensitivity in hundredths. Will be overwritten with msgTrippedVar2.
byte state = 0;
byte oldState = -1;
int lastRainRate = 0;
unsigned int lastRainRate = 0;
int lastMeasure = 0;
boolean gotTime = false;
byte lastHour;
@@ -88,8 +88,8 @@ void loop()
// If no time has been received yet, request it every 10 second from controller
// When time has been received, request update every hour
if ((!timeReceived && now-lastRequest > 10*1000)
|| (timeReceived && now-lastRequest > 60*1000*60)) {
if ((!timeReceived && (now-lastRequest) > (10UL*1000UL))
|| (timeReceived && (now-lastRequest) > (60UL*1000UL*60UL))) {
// Request time from controller.
Serial.println("requesting time");
gw.requestTime(receiveTime);
@@ -298,7 +298,6 @@ boolean validateKnock(){
// reads the secret knock from EEPROM. (if any.)
void readSecretKnock(){
byte reading;
int i;
reading = gw.loadState(1);
if (reading == eepromValid){ // only read EEPROM if the signature byte is correct.
for (int i=0; i < maximumKnocks ;i++){
@@ -71,7 +71,7 @@ MySigningAtsha204 signer;
#endif
MySensor gw(radio, hw, signer);
#else
#error SecureActuator cannot possibly be secure without signing enabled
// WARNING! SecureActuator cannot possibly be secure without signing enabled
MySensor gw(radio, hw);
#endif
@@ -85,7 +85,7 @@ void setup()
// Fetch lock status
for (int lock=1, pin=LOCK_1; lock<=NOF_LOCKS;lock++, pin++) {
// Register all locks to gw (they will be created as child devices)
gw.present(lock, S_LOCK, false);
gw.present(lock, S_LOCK, "SecureActuator", false);
// Then set lock pins in output mode
pinMode(pin, OUTPUT);
// Set lock to last known state (using eeprom storage)
@@ -0,0 +1,48 @@
// Sensebender Micro board
// Simple blinking FW to test OTA updates
#include <MySensor.h>
#include <SPI.h>
#include "utility/SPIFlash.h"
#define SketchName "Sensebender Blink"
#define SketchVersion "20150721"
#define NODE_ID AUTO
#define CHILD_ID_COUNTER 0
#define LED_PIN A2
#define BLINK_INTERVAL 500
#define REPORT_TIME 5000L
unsigned long lastUpdate = 0;
boolean LED_STATUS = false;
SPIFlash flash(8, 0x1F65);
MySensor gw;
MyMessage msgCounter(CHILD_ID_COUNTER, V_VAR1);
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LED_STATUS);
// repeater mode on
gw.begin(NULL,NODE_ID,true);
gw.sendSketchInfo(SketchName, SketchVersion);
gw.present(CHILD_ID_COUNTER, S_CUSTOM,"Millis()");
}
void loop() {
gw.wait(BLINK_INTERVAL);
LED_STATUS ^= true;
digitalWrite(LED_PIN, LED_STATUS);
if (millis()-lastUpdate > REPORT_TIME) {
gw.send(msgCounter.set( millis() ));
lastUpdate = millis();
}
}
@@ -80,14 +80,7 @@ MyGateway gw(ctrlTransport, transport, hw /*, signer*/);
void setup()
{
gw.begin(NULL
#ifdef MY_INCLUSION_MODE_FEATURE
, INCLUSION_MODE_TIME
#ifdef MY_INCLUSION_BUTTON_FEATURE
, INCLUSION_MODE_PIN
#endif
#endif
);
gw.begin(NULL);
}
@@ -237,7 +237,6 @@ void write_key(uint8_t* key)
void dump_configuration()
{
uint8_t config_word[4];
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;
@@ -682,6 +681,8 @@ void setup()
uint8_t lockConfig = 0;
uint8_t lockValue = 0;
uint16_t crc;
(void)crc;
Serial.begin(115200);
Serial.println(F("ATSHA204 personalization sketch for MySensors usage."));
@@ -18,48 +18,168 @@
*
*******************************
*
* REVISION HISTORY
* Version 1.0 - Henrik Ekblad
*
* DESCRIPTION
* Example sketch sending soil moisture alarm to controller
* http://www.mysensors.org/build/moisture
*/
*
* Arduino soil moisture based on gypsum sensor/resistive sensor to avoid electric catalyse in soil
* Required to interface the sensor: 2 * 4.7kOhm + 2 * 1N4148
*
* Gypsum sensor and calibration:
* DIY: See http://vanderleevineyard.com/1/category/vinduino/1.html
* Built: Davis / Watermark 200SS
* http://www.cooking-hacks.com/watermark-soil-moisture-sensor?_bksrc=item2item&_bkloc=product
* http://www.irrometer.com/pdf/supportmaterial/sensors/voltage-WM-chart.pdf
* cb (centibar) http://www.irrometer.com/basics.html
* 0-10 Saturated Soil. Occurs for a day or two after irrigation
* 10-20 Soil is adequately wet (except coarse sands which are drying out at this range)
* 30-60 Usual range to irrigate or water (except heavy clay soils).
* 60-100 Usual range to irrigate heavy clay soils
* 100-200 Soil is becoming dangerously dry for maximum production. Proceed with caution.
*
* Connection:
* D6, D7: alternative powering to avoid sensor degradation
* A0, A1: alternative resistance mesuring
*
* Based on:
* "Vinduino" portable soil moisture sensor code V3.00
* Date December 31, 2012
* Reinier van der Lee and Theodore Kaskalis
* www.vanderleevineyard.com
* Contributor: epierre
**/
// Copyright (C) 2015, Reinier van der Lee
// www.vanderleevineyard.com
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include <math.h> // Conversion equation from resistance to %
#include <SPI.h>
#include <MySensor.h>
#include <MySensor.h>
#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
// Setting up format for reading 3 soil sensors
#define NUM_READS 10 // Number of sensor reads for filtering
#define CHILD_ID 0
MySensor gw;
MyMessage msg(CHILD_ID, V_TRIPPED);
int lastSoilValue = -1;
MySensor gw; // Arduino initialization
MyMessage msg(CHILD_ID, V_LEVEL);
unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
void setup()
{
long buffer[NUM_READS];
int index;
typedef struct { // Structure to be used in percentage and resistance values matrix to be filtered (have to be in pairs)
int moisture;
long resistance;
} values;
const long knownResistor = 4700; // Constant value of known resistor in Ohms
int supplyVoltage; // Measured supply voltage
int sensorVoltage; // Measured sensor voltage
values valueOf[NUM_READS]; // Calculated moisture percentages and resistances to be sorted and filtered
int i; // Simple index variable
void setup() {
// initialize serial communications at 9600 bps:
Serial.begin(115200);
gw.begin();
gw.sendSketchInfo("Soil Moisture Sensor Reverse Polarity", "1.0");
gw.present(CHILD_ID, S_HUM);
// initialize the digital pins as an output.
// Pin 6,7 is for sensor 1
// initialize the digital pin as an output.
// Pin 6 is sense resistor voltage supply 1
pinMode(6, OUTPUT);
// initialize the digital pin as an output.
// Pin 7 is sense resistor voltage supply 2
pinMode(7, OUTPUT);
// Send the sketch version information to the gateway and Controller
gw.sendSketchInfo("Soil Moisture Sensor", "1.0");
// sets the soil sensor digital pin as input
pinMode(DIGITAL_INPUT_SOIL_SENSOR, INPUT);
// Register all sensors to gw (they will be created as child devices)
gw.present(CHILD_ID, S_MOTION);
}
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.send(msg.set(soilValue==0?1:0)); // Send the inverse to gw as tripped should be when no water in soil
lastSoilValue = soilValue;
void loop() {
measure(6,7,1);
Serial.print ("\t");
Serial.println (average());
long read1 = average();
measure(7,6,0);
Serial.print ("\t");
Serial.println (average());
long read2= average();
long sensor1 = (read1 + read2)/2;
Serial.print ("resistance bias =" );
Serial.println (read1-read2);
Serial.print ("sensor bias compensated value = ");
Serial.println (sensor1);
Serial.println ();
//send back the values
gw.send(msg.set((long int)ceil(sensor1)));
// delay until next measurement (msec)
gw.sleep(SLEEP_TIME);
}
void measure (int phase_b, int phase_a, int analog_input)
{
// read sensor, filter, and calculate resistance value
// Noise filter: median filter
for (i=0; i<NUM_READS; i++) {
// Read 1 pair of voltage values
digitalWrite(phase_a, HIGH); // set the voltage supply on
delayMicroseconds(25);
supplyVoltage = analogRead(analog_input); // read the supply voltage
delayMicroseconds(25);
digitalWrite(phase_a, LOW); // set the voltage supply off
delay(1);
digitalWrite(phase_b, HIGH); // set the voltage supply on
delayMicroseconds(25);
sensorVoltage = analogRead(analog_input); // read the sensor voltage
delayMicroseconds(25);
digitalWrite(phase_b, LOW); // set the voltage supply off
// Calculate resistance
// the 0.5 add-term is used to round to the nearest integer
// Tip: no need to transform 0-1023 voltage value to 0-5 range, due to following fraction
long resistance = (knownResistor * (supplyVoltage - sensorVoltage ) / sensorVoltage) ;
delay(1);
addReading(resistance);
Serial.print (resistance);
Serial.print ("\t");
}
// Power down the radio and arduino until digital input changes.
gw.sleep(INTERRUPT,CHANGE);
}
// Averaging algorithm
void addReading(long resistance){
buffer[index] = resistance;
index++;
if (index >= NUM_READS) index = 0;
}
long average(){
long sum = 0;
for (int i = 0; i < NUM_READS; i++){
sum += buffer[i];
}
return (long)(sum / NUM_READS);
}
@@ -59,8 +59,8 @@ void loop()
// If no time has been received yet, request it every 10 second from controller
// When time has been received, request update every hour
if ((!timeReceived && now-lastRequest > 10*1000)
|| (timeReceived && now-lastRequest > 60*1000*60)) {
if ((!timeReceived && (now-lastRequest) > (10UL*1000UL))
|| (timeReceived && (now-lastRequest) > (60UL*1000UL*60UL))) {
// Request time from controller.
Serial.println("requesting time");
gw.requestTime(receiveTime);
@@ -77,17 +77,19 @@ int RESEND_DEBOUNCE = 2000; // Number of millisecons interval between sending of
// Add your buttons here. Max is 5 if you still want time at the top.
char *buttons[] = {
"Good Morning",
"Clean Up!",
"All Lights Off",
"Music On/Off"
(char *)"Good Morning",
(char *)"Clean Up!",
(char *)"All Lights Off",
(char *)"Music On/Off"
};
const int buttonCount = sizeof(buttons)/sizeof(char *);
const int padding = 10;
const int topBarHeight = 60;
MySensor gw(17,18);
MyTransportNRF24 radio; // NRFRF24L01 radio driver
MyHwATMega328 hw; // Select AtMega328 hardware profile
MySensor gw(radio, hw);
MyMessage on(CHILD_ID, V_SCENE_ON);
MyMessage off(CHILD_ID, V_SCENE_OFF);
@@ -142,13 +144,12 @@ void loop()
unsigned long now = millis();
if (myTouch.dataAvailable()) {
unsigned long startPress = millis();
int pressedButton = myButtons.checkButtons();
if (pressedButton>=0) {
bool longPress = millis()-now>LONG_PRESS;
bool longPress = millis()-now>(unsigned long)LONG_PRESS;
if (pressedButton != lastPressedButton || now-lastPressedButtonTime > RESEND_DEBOUNCE) {
if (pressedButton != lastPressedButton || now-lastPressedButtonTime > (unsigned long)RESEND_DEBOUNCE) {
if (longPress) {
gw.send(off.set(pressedButton));
Serial.print("Long pressed: ");
@@ -165,8 +166,8 @@ void loop()
// If no time has been received yet, request it every 10 second from controller
// When time has been received, request update every hour
if ((!timeReceived && now-lastRequest > 10*1000)
|| (timeReceived && now-lastRequest > 60*1000*60)) {
if ((!timeReceived && now-lastRequest > (unsigned long)10*1000)
|| (timeReceived && now-lastRequest > (unsigned long)60*1000*60)) {
// Request time from controller.
Serial.println("requesting time");
gw.requestTime(receiveTime);
@@ -53,7 +53,7 @@ MyMessage uvMsg(CHILD_ID_UV, V_UV);
unsigned long lastSend =0;
float uvIndex;
float lastUV = -1;
int uvIndexValue [12] = { 50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170};
uint16_t uvIndexValue [12] = { 50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170};
void setup()
{
@@ -98,7 +98,7 @@ void loop()
//Serial.println(uvIndex,2);
//Send value to gateway if changed, or at least every 5 minutes
if ((uvIndex != lastUV)||(currentTime-lastSend >= 5*60*1000)) {
if ((uvIndex != lastUV)||(currentTime-lastSend >= 5UL*60UL*1000UL)) {
lastSend=currentTime;
gw.send(uvMsg.set(uvIndex,2));
lastUV = uvIndex;
@@ -0,0 +1,94 @@
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* 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.
*
*******************************
*
* DESCRIPTION
*
* Vibration Sensor
*
* connect the sensor as follows :
*
* VCC >>> 5V
* S >>> D3
* GND >>> GND
*
* Based on: http://www.dfrobot.com/wiki/index.php/DFRobot_Digital_Vibration_Sensor_V2_SKU:DFR0027
* Contributor: epierre
**/
#include <MySensor.h>
#include <SPI.h>
#include <Wire.h>
#define CHILD_ID_VIBRATION 0
#define VIBRATION_SENSOR_DIGITAL_PIN 3
#define SensorLED 13
unsigned long SLEEP_TIME = 10*1000; // Sleep time between reads (in seconds)
//VARIABLES
int val = 0; // variable to store the value coming from the sensor
float valVIBRATION =0.0;
float lastVIBRATION =0.0;
unsigned char state = 0;
MySensor gw;
MyMessage vibrationMsg(CHILD_ID_VIBRATION, V_LEVEL);
void setup()
{
gw.begin();
// Send the sketch version information to the gateway and Controller
gw.sendSketchInfo("VIBRATION Sensor", "1.0");
// Register all sensors to gateway (they will be created as child devices)
gw.present(CHILD_ID_VIBRATION, S_VIBRATION);
pinMode(VIBRATION_SENSOR_DIGITAL_PIN, INPUT);
attachInterrupt(1, blink, FALLING);// Trigger the blink function when the falling edge is detected
pinMode(SensorLED, OUTPUT);
}
void loop()
{
if(state>=40){ // basically below 40 so ignire basic level
gw.send(vibrationMsg.set(int(state)));
state = 0;
digitalWrite(SensorLED,HIGH);
} else {
state = 0;
digitalWrite(SensorLED,LOW);
}
// 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.sleep(SLEEP_TIME); //sleep for: sleepTime
}
void blink()//Interrupts function
{
state++;
}
@@ -20,6 +20,7 @@
*
* REVISION HISTORY
* Version 1.0 - Henrik Ekblad
* Version 1.1 - GizMoCuz
*
* DESCRIPTION
* Use this sensor to measure volume and flow of your house watermeter.
@@ -33,8 +34,8 @@
* http://www.mysensors.org/build/pulse_water
*/
#include <SPI.h>
#include <MySensor.h>
#include <SPI.h>
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!)
#define SENSOR_INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
@@ -47,7 +48,7 @@
#define CHILD_ID 1 // Id of the sensor child
unsigned long SEND_FREQUENCY = 20000; // Minimum time between send (in milliseconds). We don't want to spam the gateway.
unsigned long SEND_FREQUENCY = 30000; // Minimum time between send (in milliseconds). We don't want to spam the gateway.
MySensor gw;
MyMessage flowMsg(CHILD_ID,V_FLOW);
@@ -72,8 +73,11 @@ void setup()
{
gw.begin(incomingMessage);
// initialize our digital pins internal pullup resistor so one pulse switches from high to low (less distortion)
pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP);
// Send the sketch version information to the gateway and Controller
gw.sendSketchInfo("Water Meter", "1.2");
gw.sendSketchInfo("Water Meter", "1.1");
// Register this device as Waterflow sensor
gw.present(CHILD_ID, S_WATER);
@@ -85,7 +89,7 @@ void setup()
lastSend = lastPulse = millis();
attachInterrupt(SENSOR_INTERRUPT, onPulse, RISING);
attachInterrupt(SENSOR_INTERRUPT, onPulse, FALLING);
}
@@ -93,7 +97,7 @@ void loop()
{
gw.process();
unsigned long currentTime = millis();
// Only send values at a maximum frequency or woken up from sleep
if (SLEEP_MODE || (currentTime - lastSend > SEND_FREQUENCY))
{
@@ -124,7 +128,7 @@ void loop()
}
// Pulse count has changed
if (pulseCount != oldPulseCount) {
if ((pulseCount != oldPulseCount)||(!SLEEP_MODE)) {
oldPulseCount = pulseCount;
Serial.print("pulsecount:");
@@ -133,7 +137,7 @@ void loop()
gw.send(lastCounterMsg.set(pulseCount)); // Send pulsecount value to gw in VAR1
double volume = ((double)pulseCount/((double)PULSE_FACTOR));
if (volume != oldvolume) {
if ((volume != oldvolume)||(!SLEEP_MODE)) {
oldvolume = volume;
Serial.print("volume:");
@@ -152,6 +156,7 @@ void incomingMessage(const MyMessage &message) {
if (message.type==V_VAR1) {
unsigned long gwPulseCount=message.getULong();
pulseCount += gwPulseCount;
flow=oldflow=0;
Serial.print("Received last pulse count from gw:");
Serial.println(pulseCount);
pcReceived = true;
@@ -178,4 +183,3 @@ void onPulse()
}
pulseCount++;
}
+5 -3
View File
@@ -61,6 +61,7 @@ void PN532::begin()
/**************************************************************************/
void PN532::PrintHex(const uint8_t *data, const uint32_t numBytes)
{
(void)data;
for (uint8_t i = 0; i < numBytes; i++) {
DMSG("0x");
DMSG_HEX(data[i]);
@@ -86,11 +87,11 @@ void PN532::PrintHexChar(const uint8_t *data, const uint32_t numBytes)
}
DMSG(" ");
for (uint8_t i = 0; i < numBytes; i++) {
char c = data[i];
uint8_t c = data[i];
if (c <= 0x1f || c > 0x7f) {
DMSG('.');
} else {
DMSG(c);
DMSG((char)c);
}
}
@@ -548,7 +549,7 @@ uint8_t PN532::mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIden
// in NDEF records
// Setup the sector buffer (w/pre-formatted TLV wrapper and NDEF message)
uint8_t sectorbuffer1[16] = {0x00, 0x00, 0x03, len + 5, 0xD1, 0x01, len + 1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t sectorbuffer1[16] = {0x00, 0x00, 0x03, (uint8_t)(len + 5), 0xD1, 0x01, (uint8_t)(len + 1), 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
@@ -653,6 +654,7 @@ uint8_t PN532::mifareultralight_ReadPage (uint8_t page, uint8_t *buffer)
bool PN532::inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength)
{
uint8_t i;
(void)i;
pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE;
pn532_packetbuffer[1] = inListedTag;
+4 -1
View File
@@ -37,6 +37,7 @@ int8_t LLCP::activate(uint16_t timeout)
int8_t LLCP::waitForConnection(uint16_t timeout)
{
uint8_t type;
(void)timeout;
sequence = 0;
@@ -76,6 +77,7 @@ int8_t LLCP::waitForConnection(uint16_t timeout)
int8_t LLCP::waitForDisconnection(uint16_t timeout)
{
uint8_t type;
(void)timeout;
// Get DISC PDU
DMSG("wait for a DISC PDU\n");
@@ -113,6 +115,7 @@ int8_t LLCP::waitForDisconnection(uint16_t timeout)
int8_t LLCP::connect(uint16_t timeout)
{
uint8_t type;
(void)timeout;
sequence = 0;
@@ -165,6 +168,7 @@ int8_t LLCP::connect(uint16_t timeout)
int8_t LLCP::disconnect(uint16_t timeout)
{
uint8_t type;
(void)timeout;
// try to get a SYMM PDU
if (2 > link.read(headerBuf, headerBufLen)) {
@@ -207,7 +211,6 @@ int8_t LLCP::disconnect(uint16_t timeout)
bool LLCP::write(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
{
uint8_t type;
uint8_t buf[3];
if (2 != link.read(buf, sizeof(buf))) {
+1 -1
View File
@@ -79,7 +79,7 @@ int16_t SNEP::read(uint8_t *buf, uint8_t len, uint16_t timeout)
}
// check message's length
uint32_t length = (buf[2] << 24) + (buf[3] << 16) + (buf[4] << 8) + buf[5];
uint32_t length = ((uint32_t)buf[2] << 24) + ((uint32_t)buf[3] << 16) + (buf[4] << 8) + buf[5];
// length should not be more than 244 (header + body < 255, header = 6 + 3 + 2)
if (length > (status - 6)) {
DMSG("The SNEP message is too large\n");
@@ -78,15 +78,8 @@ uint8_t PWF_AS3935::_sing_reg_read(uint8_t RegAdd)
void PWF_AS3935::_sing_reg_write(uint8_t RegAdd, uint8_t DataMask, uint8_t RegData)
{
// start by reading original register data (only modifying what we need to)
uint8_t OrigRegData = _sing_reg_read(RegAdd);
// calculate new register data... 'delete' old targeted data, replace with new data
// note: 'DataMask' must be bits targeted for replacement
// add'l note: this function does NOT shift values into the proper place... they need to be there already
uint8_t NewRegData = ((OrigRegData & ~DataMask) | (RegData & DataMask));
// now configure and write the updated register value
(void)DataMask;
// Configure and write the updated register value
digitalWrite(_cs, LOW); // set pin low to start talking to IC
// next pack command byte, send AS3935.... structure is shown below
// MODE Register Address/Direct Cmd
@@ -228,7 +221,7 @@ uint32_t PWF_AS3935::AS3935_GetStrikeEnergyRaw(void)
{
uint32_t nrgy_raw = ((_sing_reg_read(0x06) & 0x1F) << 8); // MMSB, shift 8 bits left, make room for MSB
nrgy_raw |= _sing_reg_read(0x05); // read MSB
nrgy_raw <= 8; // shift 8 bits left, make room for LSB
nrgy_raw <<= 8; // shift 8 bits left, make room for LSB
nrgy_raw |= _sing_reg_read(0x04); // read LSB, add to others
return nrgy_raw;
+2 -1
View File
@@ -474,7 +474,8 @@ void PCintPort::detachInterrupt(uint8_t arduinoPin)
// there isn't really a good way to back-map ports and masks to pins.
void PCintPort::PCint() {
uint8_t thisChangedPin; //MIKE
(void)thisChangedPin;
#ifdef FLASH
if (*led_port & led_mask) *led_port&=not_led_mask;
else *led_port|=led_mask;
+47
View File
@@ -0,0 +1,47 @@
1.9
* Do not split MQTT packets over multiple calls to _client->write()
* API change: All constructors now require an instance of Client
to be passed in.
* Fixed example to match 1.8 api changes - dpslwk
* Added username/password support - WilHall
* Added publish_P - publishes messages from PROGMEM - jobytaffey
1.8
* KeepAlive interval is configurable in PubSubClient.h
* Maximum packet size is configurable in PubSubClient.h
* API change: Return boolean rather than int from various functions
* API change: Length parameter in message callback changed
from int to unsigned int
* Various internal tidy-ups around types
1.7
* Improved keepalive handling
* Updated to the Arduino-1.0 API
1.6
* Added the ability to publish a retained message
1.5
* Added default constructor
* Fixed compile error when used with arduino-0021 or later
1.4
* Fixed connection lost handling
1.3
* Fixed packet reading bug in PubSubClient.readPacket
1.2
* Fixed compile error when used with arduino-0016 or later
1.1
* Reduced size of library
* Added support for Will messages
* Clarified licensing - see LICENSE.txt
1.0
* Only Quality of Service (QOS) 0 messaging is supported
* The maximum message size, including header, is 128 bytes
* The keepalive interval is set to 30 seconds
* No support for Will messages
+20
View File
@@ -0,0 +1,20 @@
Copyright (c) 2008-2012 Nicholas O'Leary
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.
+427
View File
@@ -0,0 +1,427 @@
/*
PubSubClient.cpp - A simple client for MQTT.
Nicholas O'Leary
http://knolleary.net
*/
#include "PubSubClient.h"
#include <string.h>
PubSubClient::PubSubClient() {
this->_client = NULL;
this->stream = NULL;
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, void (*callback)(char*,uint8_t*,unsigned int), Client& client) {
this->_client = &client;
this->callback = callback;
this->ip = ip;
this->port = port;
this->domain = NULL;
this->stream = NULL;
}
PubSubClient::PubSubClient(char* domain, uint16_t port, void (*callback)(char*,uint8_t*,unsigned int), Client& client) {
this->_client = &client;
this->callback = callback;
this->domain = domain;
this->port = port;
this->stream = NULL;
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, void (*callback)(char*,uint8_t*,unsigned int), Client& client, Stream& stream) {
this->_client = &client;
this->callback = callback;
this->ip = ip;
this->port = port;
this->domain = NULL;
this->stream = &stream;
}
PubSubClient::PubSubClient(char* domain, uint16_t port, void (*callback)(char*,uint8_t*,unsigned int), Client& client, Stream& stream) {
this->_client = &client;
this->callback = callback;
this->domain = domain;
this->port = port;
this->stream = &stream;
}
boolean PubSubClient::connect(char *id) {
return connect(id,NULL,NULL,0,0,0,0);
}
boolean PubSubClient::connect(char *id, char *user, char *pass) {
return connect(id,user,pass,0,0,0,0);
}
boolean PubSubClient::connect(char *id, char* willTopic, uint8_t willQos, uint8_t willRetain, char* willMessage)
{
return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage);
}
boolean PubSubClient::connect(char *id, char *user, char *pass, char* willTopic, uint8_t willQos, uint8_t willRetain, char* willMessage) {
if (!connected()) {
int result = 0;
if (domain != NULL) {
result = _client->connect(this->domain, this->port);
} else {
result = _client->connect(this->ip, this->port);
}
if (result) {
nextMsgId = 1;
uint8_t d[9] = {0x00,0x06,'M','Q','I','s','d','p',MQTTPROTOCOLVERSION};
// Leave room in the buffer for header and variable length field
uint16_t length = 5;
unsigned int j;
for (j = 0;j<9;j++) {
buffer[length++] = d[j];
}
uint8_t v;
if (willTopic) {
v = 0x06|(willQos<<3)|(willRetain<<5);
} else {
v = 0x02;
}
if(user != NULL) {
v = v|0x80;
if(pass != NULL) {
v = v|(0x80>>1);
}
}
buffer[length++] = v;
buffer[length++] = ((MQTT_KEEPALIVE) >> 8);
buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF);
length = writeString(id,buffer,length);
if (willTopic) {
length = writeString(willTopic,buffer,length);
length = writeString(willMessage,buffer,length);
}
if(user != NULL) {
length = writeString(user,buffer,length);
if(pass != NULL) {
length = writeString(pass,buffer,length);
}
}
write(MQTTCONNECT,buffer,length-5);
lastInActivity = lastOutActivity = millis();
while (!_client->available()) {
unsigned long t = millis();
if (t-lastInActivity > MQTT_KEEPALIVE*1000UL) {
_client->stop();
return false;
}
}
uint8_t llen;
uint16_t len = readPacket(&llen);
if (len == 4 && buffer[3] == 0) {
lastInActivity = millis();
pingOutstanding = false;
return true;
}
}
_client->stop();
}
return false;
}
uint8_t PubSubClient::readByte() {
while(!_client->available()) {}
return _client->read();
}
uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
uint16_t len = 0;
buffer[len++] = readByte();
bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH;
uint32_t multiplier = 1;
uint16_t length = 0;
uint8_t digit = 0;
uint16_t skip = 0;
uint8_t start = 0;
do {
digit = readByte();
buffer[len++] = digit;
length += (digit & 127) * multiplier;
multiplier *= 128;
} while ((digit & 128) != 0);
*lengthLength = len-1;
if (isPublish) {
// Read in topic length to calculate bytes to skip over for Stream writing
buffer[len++] = readByte();
buffer[len++] = readByte();
skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2];
start = 2;
if (buffer[0]&MQTTQOS1) {
// skip message id
skip += 2;
}
}
for (uint16_t i = start;i<length;i++) {
digit = readByte();
if (this->stream) {
if (isPublish && len-*lengthLength-2>skip) {
this->stream->write(digit);
}
}
if (len < MQTT_MAX_PACKET_SIZE) {
buffer[len] = digit;
}
len++;
}
if (!this->stream && len > MQTT_MAX_PACKET_SIZE) {
len = 0; // This will cause the packet to be ignored.
}
return len;
}
boolean PubSubClient::loop() {
if (connected()) {
unsigned long t = millis();
if ((t - lastInActivity > MQTT_KEEPALIVE*1000UL) || (t - lastOutActivity > MQTT_KEEPALIVE*1000UL)) {
if (pingOutstanding) {
_client->stop();
return false;
} else {
buffer[0] = MQTTPINGREQ;
buffer[1] = 0;
_client->write(buffer,2);
lastOutActivity = t;
lastInActivity = t;
pingOutstanding = true;
}
}
if (_client->available()) {
uint8_t llen;
uint16_t len = readPacket(&llen);
uint16_t msgId = 0;
uint8_t *payload;
if (len > 0) {
lastInActivity = t;
uint8_t type = buffer[0]&0xF0;
if (type == MQTTPUBLISH) {
if (callback) {
uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2];
char topic[tl+1];
for (uint16_t i=0;i<tl;i++) {
topic[i] = buffer[llen+3+i];
}
topic[tl] = 0;
// msgId only present for QOS>0
if ((buffer[0]&0x06) == MQTTQOS1) {
msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1];
payload = buffer+llen+3+tl+2;
callback(topic,payload,len-llen-3-tl-2);
buffer[0] = MQTTPUBACK;
buffer[1] = 2;
buffer[2] = (msgId >> 8);
buffer[3] = (msgId & 0xFF);
_client->write(buffer,4);
lastOutActivity = t;
} else {
payload = buffer+llen+3+tl;
callback(topic,payload,len-llen-3-tl);
}
}
} else if (type == MQTTPINGREQ) {
buffer[0] = MQTTPINGRESP;
buffer[1] = 0;
_client->write(buffer,2);
} else if (type == MQTTPINGRESP) {
pingOutstanding = false;
}
}
}
return true;
}
return false;
}
boolean PubSubClient::publish(char* topic, char* payload) {
return publish(topic,(uint8_t*)payload,strlen(payload),false);
}
boolean PubSubClient::publish(char* topic, uint8_t* payload, unsigned int plength) {
return publish(topic, payload, plength, false);
}
boolean PubSubClient::publish(char* topic, uint8_t* payload, unsigned int plength, boolean retained) {
if (connected()) {
// Leave room in the buffer for header and variable length field
uint16_t length = 5;
length = writeString(topic,buffer,length);
uint16_t i;
for (i=0;i<plength;i++) {
buffer[length++] = payload[i];
}
uint8_t header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
return write(header,buffer,length-5);
}
return false;
}
boolean PubSubClient::publish_P(char* topic, uint8_t* payload, unsigned int plength, boolean retained) {
uint8_t llen = 0;
uint8_t digit;
unsigned int rc = 0;
uint16_t tlen;
unsigned int pos = 0;
unsigned int i;
uint8_t header;
unsigned int len;
if (!connected()) {
return false;
}
tlen = strlen(topic);
header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
buffer[pos++] = header;
len = plength + 2 + tlen;
do {
digit = len % 128;
len = len / 128;
if (len > 0) {
digit |= 0x80;
}
buffer[pos++] = digit;
llen++;
} while(len>0);
pos = writeString(topic,buffer,pos);
rc += _client->write(buffer,pos);
for (i=0;i<plength;i++) {
rc += _client->write((char)pgm_read_byte_near(payload + i));
}
lastOutActivity = millis();
return rc == tlen + 4 + plength;
}
boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
uint8_t lenBuf[4];
uint8_t llen = 0;
uint8_t digit;
uint8_t pos = 0;
uint8_t rc;
uint8_t len = length;
do {
digit = len % 128;
len = len / 128;
if (len > 0) {
digit |= 0x80;
}
lenBuf[pos++] = digit;
llen++;
} while(len>0);
buf[4-llen] = header;
for (int i=0;i<llen;i++) {
buf[5-llen+i] = lenBuf[i];
}
rc = _client->write(buf+(4-llen),length+1+llen);
lastOutActivity = millis();
return (rc == 1+llen+length);
}
boolean PubSubClient::subscribe(char* topic) {
return subscribe(topic, 0);
}
boolean PubSubClient::subscribe(char* topic, uint8_t qos) {
if (qos > 1)
return false;
if (connected()) {
// Leave room in the buffer for header and variable length field
uint16_t length = 5;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
}
buffer[length++] = (nextMsgId >> 8);
buffer[length++] = (nextMsgId & 0xFF);
length = writeString(topic, buffer,length);
buffer[length++] = qos;
return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5);
}
return false;
}
boolean PubSubClient::unsubscribe(char* topic) {
if (connected()) {
uint16_t length = 5;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
}
buffer[length++] = (nextMsgId >> 8);
buffer[length++] = (nextMsgId & 0xFF);
length = writeString(topic, buffer,length);
return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5);
}
return false;
}
void PubSubClient::disconnect() {
buffer[0] = MQTTDISCONNECT;
buffer[1] = 0;
_client->write(buffer,2);
_client->stop();
lastInActivity = lastOutActivity = millis();
}
uint16_t PubSubClient::writeString(char* string, uint8_t* buf, uint16_t pos) {
char* idp = string;
uint16_t i = 0;
pos += 2;
while (*idp) {
buf[pos++] = *idp++;
i++;
}
buf[pos-i-2] = (i >> 8);
buf[pos-i-1] = (i & 0xFF);
return pos;
}
boolean PubSubClient::connected() {
boolean rc;
if (_client == NULL ) {
rc = false;
} else {
rc = (int)_client->connected();
if (!rc) _client->stop();
}
return rc;
}
+81
View File
@@ -0,0 +1,81 @@
/*
PubSubClient.h - A simple client for MQTT.
Nicholas O'Leary
http://knolleary.net
*/
#ifndef PubSubClient_h
#define PubSubClient_h
#include <Arduino.h>
#include "Client.h"
#include "Stream.h"
// MQTT_MAX_PACKET_SIZE : Maximum packet size
#define MQTT_MAX_PACKET_SIZE 128
// MQTT_KEEPALIVE : keepAlive interval in Seconds
#define MQTT_KEEPALIVE 15
#define MQTTPROTOCOLVERSION 3
#define MQTTCONNECT 1 << 4 // Client request to connect to Server
#define MQTTCONNACK 2 << 4 // Connect Acknowledgment
#define MQTTPUBLISH 3 << 4 // Publish message
#define MQTTPUBACK 4 << 4 // Publish Acknowledgment
#define MQTTPUBREC 5 << 4 // Publish Received (assured delivery part 1)
#define MQTTPUBREL 6 << 4 // Publish Release (assured delivery part 2)
#define MQTTPUBCOMP 7 << 4 // Publish Complete (assured delivery part 3)
#define MQTTSUBSCRIBE 8 << 4 // Client Subscribe request
#define MQTTSUBACK 9 << 4 // Subscribe Acknowledgment
#define MQTTUNSUBSCRIBE 10 << 4 // Client Unsubscribe request
#define MQTTUNSUBACK 11 << 4 // Unsubscribe Acknowledgment
#define MQTTPINGREQ 12 << 4 // PING Request
#define MQTTPINGRESP 13 << 4 // PING Response
#define MQTTDISCONNECT 14 << 4 // Client is Disconnecting
#define MQTTReserved 15 << 4 // Reserved
#define MQTTQOS0 (0 << 1)
#define MQTTQOS1 (1 << 1)
#define MQTTQOS2 (2 << 1)
class PubSubClient {
private:
Client* _client;
uint8_t buffer[MQTT_MAX_PACKET_SIZE];
uint16_t nextMsgId;
unsigned long lastOutActivity;
unsigned long lastInActivity;
bool pingOutstanding;
void (*callback)(char*,uint8_t*,unsigned int);
uint16_t readPacket(uint8_t*);
uint8_t readByte();
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
uint16_t writeString(char* string, uint8_t* buf, uint16_t pos);
uint8_t *ip;
char* domain;
uint16_t port;
Stream* stream;
public:
PubSubClient();
PubSubClient(uint8_t *, uint16_t, void(*)(char*,uint8_t*,unsigned int),Client& client);
PubSubClient(uint8_t *, uint16_t, void(*)(char*,uint8_t*,unsigned int),Client& client, Stream&);
PubSubClient(char*, uint16_t, void(*)(char*,uint8_t*,unsigned int),Client& client);
PubSubClient(char*, uint16_t, void(*)(char*,uint8_t*,unsigned int),Client& client, Stream&);
boolean connect(char *);
boolean connect(char *, char *, char *);
boolean connect(char *, char *, uint8_t, uint8_t, char *);
boolean connect(char *, char *, char *, char *, uint8_t, uint8_t, char*);
void disconnect();
boolean publish(char *, char *);
boolean publish(char *, uint8_t *, unsigned int);
boolean publish(char *, uint8_t *, unsigned int, boolean);
boolean publish_P(char *, uint8_t *, unsigned int, boolean);
boolean subscribe(char *);
boolean subscribe(char *, uint8_t qos);
boolean unsubscribe(char *);
boolean loop();
boolean connected();
};
#endif
+39
View File
@@ -0,0 +1,39 @@
/*
Basic MQTT example with Authentication
- connects to an MQTT server, providing username
and password
- publishes "hello world" to the topic "outTopic"
- subscribes to the topic "inTopic"
*/
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
byte server[] = { 172, 16, 0, 2 };
byte ip[] = { 172, 16, 0, 100 };
void callback(char* topic, byte* payload, unsigned int length) {
// handle message arrived
}
EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);
void setup()
{
Ethernet.begin(mac, ip);
if (client.connect("arduinoClient", "testuser", "testpass")) {
client.publish("outTopic","hello world");
client.subscribe("inTopic");
}
}
void loop()
{
client.loop();
}
+38
View File
@@ -0,0 +1,38 @@
/*
Basic MQTT example
- connects to an MQTT server
- publishes "hello world" to the topic "outTopic"
- subscribes to the topic "inTopic"
*/
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
byte server[] = { 172, 16, 0, 2 };
byte ip[] = { 172, 16, 0, 100 };
void callback(char* topic, byte* payload, unsigned int length) {
// handle message arrived
}
EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);
void setup()
{
Ethernet.begin(mac, ip);
if (client.connect("arduinoClient")) {
client.publish("outTopic","hello world");
client.subscribe("inTopic");
}
}
void loop()
{
client.loop();
}
@@ -0,0 +1,61 @@
/*
Publishing in the callback
- connects to an MQTT server
- subscribes to the topic "inTopic"
- when a message is received, republishes it to "outTopic"
This example shows how to publish messages within the
callback function. The callback function header needs to
be declared before the PubSubClient constructor and the
actual callback defined afterwards.
This ensures the client reference in the callback function
is valid.
*/
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
byte server[] = { 172, 16, 0, 2 };
byte ip[] = { 172, 16, 0, 100 };
// Callback function header
void callback(char* topic, byte* payload, unsigned int length);
EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);
// Callback function
void callback(char* topic, byte* payload, unsigned int length) {
// In order to republish this payload, a copy must be made
// as the orignal payload buffer will be overwritten whilst
// constructing the PUBLISH packet.
// Allocate the correct amount of memory for the payload copy
byte* p = (byte*)malloc(length);
// Copy the payload to the new buffer
memcpy(p,payload,length);
client.publish("outTopic", p, length);
// Free the memory
free(p);
}
void setup()
{
Ethernet.begin(mac, ip);
if (client.connect("arduinoClient")) {
client.publish("outTopic","hello world");
client.subscribe("inTopic");
}
}
void loop()
{
client.loop();
}
@@ -0,0 +1,58 @@
/*
Example of using a Stream object to store the message payload
Uses SRAM library: https://github.com/ennui2342/arduino-sram
but could use any Stream based class such as SD
- connects to an MQTT server
- publishes "hello world" to the topic "outTopic"
- subscribes to the topic "inTopic"
*/
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <SRAM.h>
// Update these with values suitable for your network.
byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
byte server[] = { 172, 16, 0, 2 };
byte ip[] = { 172, 16, 0, 100 };
SRAM sram(4, SRAM_1024);
void callback(char* topic, byte* payload, unsigned int length) {
sram.seek(1);
// do something with the message
for(uint8_t i=0; i<length; i++) {
Serial.write(sram.read());
}
Serial.println();
// Reset position for the next message to be stored
sram.seek(1);
}
EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient, sram);
void setup()
{
Ethernet.begin(mac, ip);
if (client.connect("arduinoClient")) {
client.publish("outTopic","hello world");
client.subscribe("inTopic");
}
sram.begin();
sram.seek(1);
Serial.begin(9600);
}
void loop()
{
client.loop();
}
+25
View File
@@ -0,0 +1,25 @@
#######################################
# Syntax Coloring Map For Ultrasound
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
PubSubClient KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
connect KEYWORD2
disconnect KEYWORD2
publish KEYWORD2
subscribe KEYWORD2
loop KEYWORD2
connected KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
@@ -230,6 +230,7 @@ unsigned long KaKuTransmitter::getTelegram(char address, byte device, boolean on
}
void KaKuTransmitter::sendSignal(char address, byte group, byte device, boolean on) {
(void)device;
sendTelegram(getTelegram(address, group, on), _pin);
}
+6 -6
View File
@@ -854,8 +854,8 @@ void UTFT::printChar(byte c, int x, int y)
{
setXY(x,y,x+cfont.x_size-1,y+cfont.y_size-1);
temp=((c-cfont.offset)*((cfont.x_size/8)*cfont.y_size))+4;
for(j=0;j<((cfont.x_size/8)*cfont.y_size);j++)
temp=(word)((c-cfont.offset)*((cfont.x_size/8)*cfont.y_size))+4;
for(j=0;j<(word)((cfont.x_size/8)*cfont.y_size);j++)
{
ch=pgm_read_byte(&cfont.font[temp]);
for(i=0;i<8;i++)
@@ -876,7 +876,7 @@ void UTFT::printChar(byte c, int x, int y)
{
temp=((c-cfont.offset)*((cfont.x_size/8)*cfont.y_size))+4;
for(j=0;j<((cfont.x_size/8)*cfont.y_size);j+=(cfont.x_size/8))
for(j=0;j<(word)((cfont.x_size/8)*cfont.y_size);j+=(cfont.x_size/8))
{
setXY(x,y+(j/(cfont.x_size/8)),x+cfont.x_size-1,y+(j/(cfont.x_size/8)));
for (int zz=(cfont.x_size/8)-1; zz>=0; zz--)
@@ -1080,7 +1080,7 @@ void UTFT::printNumF(double num, byte dec, int x, int y, char divider, int lengt
if (divider != '.')
{
for (int i=0; i<sizeof(st); i++)
for (unsigned int i=0; i<sizeof(st); i++)
if (st[i]=='.')
st[i]=divider;
}
@@ -1090,13 +1090,13 @@ void UTFT::printNumF(double num, byte dec, int x, int y, char divider, int lengt
if (neg)
{
st[0]='-';
for (int i=1; i<sizeof(st); i++)
for (unsigned int i=1; i<sizeof(st); i++)
if ((st[i]==' ') || (st[i]=='-'))
st[i]=filler;
}
else
{
for (int i=0; i<sizeof(st); i++)
for (unsigned int i=0; i<sizeof(st); i++)
if (st[i]==' ')
st[i]=filler;
}

Some files were not shown because too many files have changed in this diff Show More