Merge remote-tracking branch 'upstream/development' into
gateway-refactoring # Conflicts: # libraries/MySensors/MyConfig.h # libraries/MySensors/MySensor.cpp
This commit is contained in:
@@ -4,3 +4,11 @@ Arduino
|
||||
MySensors Arduino Library v1.5
|
||||
|
||||
Please visit www.mysensors.org for more information
|
||||
|
||||
Current build status of master branch: [](http://ci.mysensors.org/job/MySensorsArduino/branch/master/)
|
||||
|
||||
Current build status of development branch: [](http://ci.mysensors.org/job/MySensorsArduino/branch/development/)
|
||||
|
||||
Current build status of master branch (nightly build of Arduino IDE): [](http://ci.mysensors.org/job/MySensorsArduinoNightly/branch/master/)
|
||||
|
||||
Current build status of development branch (nightly build of Arduino IDE): [](http://ci.mysensors.org/job/MySensorsArduinoNightly/branch/development/)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// Uncomment the following line for "LOCK-OUT" debounce method
|
||||
//#define BOUNCE_LOCK-OUT
|
||||
//#define BOUNCE_LOCK_OUT
|
||||
|
||||
|
||||
#ifndef Bounce2_h
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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'.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
|
||||
+6
-1
@@ -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)
|
||||
+6
-2
@@ -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 ) ;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
+7
-4
@@ -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
|
||||
+2
-2
@@ -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
|
||||
+8
-2
@@ -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
|
||||
}
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
+11
-10
@@ -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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Executable
+47
@@ -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
|
||||
|
||||
Executable
+20
@@ -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.
|
||||
Executable
+427
@@ -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;
|
||||
}
|
||||
|
||||
Executable
+81
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
+61
@@ -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();
|
||||
}
|
||||
|
||||
Executable
+25
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user