Add library status indication & improve error LED feedback (#462)
* Added MyIndication to provide status feedback from the library * Fix: Allow led blinking for hardware errors * Refactor LED blinking implementation to show blink patterns * Refactor LED blinking to show blink pattern
This commit is contained in:
@@ -142,6 +142,8 @@
|
||||
#include "core/MyLeds.h"
|
||||
#endif
|
||||
|
||||
#include "core/MyIndication.cpp"
|
||||
|
||||
|
||||
// INCLUSION MODE
|
||||
#if defined(MY_INCLUSION_MODE_FEATURE)
|
||||
|
||||
@@ -151,6 +151,8 @@ bool gatewayTransportSend(MyMessage &message)
|
||||
bool ret = true;
|
||||
char *_ethernetMsg = protocolFormat(message);
|
||||
|
||||
setIndication(INDICATION_GW_TX);
|
||||
|
||||
_w5100_spi_en(true);
|
||||
#if defined(MY_CONTROLLER_IP_ADDRESS)
|
||||
#if defined(MY_USE_UDP)
|
||||
@@ -267,6 +269,7 @@ bool gatewayTransportAvailable()
|
||||
|
||||
if (packet_size) {
|
||||
//debug(PSTR("UDP packet available. Size:%d\n"), packet_size);
|
||||
setIndication(INDICATION_GW_RX);
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
_ethernetServer.read(inputString[0].string, MY_GATEWAY_MAX_RECEIVE_LENGTH);
|
||||
inputString[0].string[packet_size] = 0;
|
||||
@@ -316,6 +319,7 @@ bool gatewayTransportAvailable()
|
||||
// Loop over clients connect and read available data
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) {
|
||||
if (_readFromClient(i)) {
|
||||
setIndication(INDICATION_GW_RX);
|
||||
_w5100_spi_en(false);
|
||||
return true;
|
||||
}
|
||||
@@ -341,6 +345,7 @@ bool gatewayTransportAvailable()
|
||||
client.stop();
|
||||
} else {
|
||||
if (_readFromClient()) {
|
||||
setIndication(INDICATION_GW_RX);
|
||||
_w5100_spi_en(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,8 @@ MyMessage _mqttMsg;
|
||||
bool gatewayTransportSend(MyMessage &message) {
|
||||
if (!_client.connected())
|
||||
return false;
|
||||
setIndication(INDICATION_GW_TX);
|
||||
|
||||
snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR(MY_MQTT_PUBLISH_TOPIC_PREFIX "/%d/%d/%d/%d/%d"), message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type);
|
||||
debug(PSTR("Sending message on topic: %s\n"), _fmtBuffer);
|
||||
return _client.publish(_fmtBuffer, message.getString(_convBuffer));
|
||||
|
||||
@@ -31,6 +31,7 @@ MyMessage _serialMsg;
|
||||
|
||||
|
||||
bool gatewayTransportSend(MyMessage &message) {
|
||||
setIndication(INDICATION_GW_TX);
|
||||
MY_SERIALDEVICE.print(protocolFormat(message));
|
||||
// Serial print is always successful
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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-2016 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 "MyIndication.h"
|
||||
#ifdef MY_LEDS_BLINKING_FEATURE
|
||||
#include "MyLeds.h"
|
||||
#endif
|
||||
|
||||
void setIndication( const indication_t ind )
|
||||
{
|
||||
#ifdef MY_LEDS_BLINKING_FEATURE
|
||||
if ((INDICATION_TX == ind) || (INDICATION_GW_TX == ind))
|
||||
{
|
||||
ledsBlinkTx(1);
|
||||
} else if ((INDICATION_RX == ind) || (INDICATION_GW_RX == ind))
|
||||
{
|
||||
ledsBlinkRx(1);
|
||||
} else if (ind > INDICATION_ERR_START)
|
||||
{
|
||||
// Number of blinks indicates which error occurred.
|
||||
ledsBlinkErr(ind-INDICATION_ERR_START);
|
||||
}
|
||||
#endif
|
||||
if (indication)
|
||||
indication(ind);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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-2016 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 MyIndication_h
|
||||
#define MyIndication_h
|
||||
|
||||
/**
|
||||
* Indication type
|
||||
*/
|
||||
typedef enum {
|
||||
INDICATION_TX = 0, //!< Sent a message.
|
||||
INDICATION_RX, //!< Received a message.
|
||||
|
||||
INDICATION_GW_TX, //!< Gateway transmit message.
|
||||
INDICATION_GW_RX, //!< Gateway receive message.
|
||||
|
||||
INDICATION_FIND_PARENT, //!< Start finding parent node.
|
||||
INDICATION_GOT_PARENT, //!< Found parent node.
|
||||
INDICATION_REQ_NODEID, //!< Request node ID.
|
||||
INDICATION_GOT_NODEID, //!< Got a node ID.
|
||||
INDICATION_REBOOT, //!< Rebooting node.
|
||||
INDICATION_PRESENT, //!< Presenting node to gateway.
|
||||
INDICATION_CLEAR_ROUTING, //!< Clear rrouting table requested.
|
||||
INDICATION_SLEEP, //!< Node goes to sleep.
|
||||
INDICATION_WAKEUP, //!< Node just woke from sleep.
|
||||
INDICATION_FW_UPDATE_START, //!< Start of OTA firmware update process.
|
||||
INDICATION_FW_UPDATE_RX, //!< Received a piece of firmware data.
|
||||
|
||||
INDICATION_ERR_START = 100,
|
||||
INDICATION_ERR_TX, //!< Failed to transmit message.
|
||||
INDICATION_ERR_INIT_TRANSPORT, //!< MySensors transport hardware (radio) init failure.
|
||||
INDICATION_ERR_FIND_PARENT, //!< Failed to find parent node.
|
||||
INDICATION_ERR_GET_NODEID, //!< Failed to receive node ID.
|
||||
INDICATION_ERR_SIGN, //!< Error signing.
|
||||
INDICATION_ERR_VERSION, //!< Protocol version mismatch.
|
||||
INDICATION_ERR_NET_FULL, //!< Network full. All node ID's are taken.
|
||||
INDICATION_ERR_INIT_GWTRANSPORT, //!< Gateway transport hardware init failure.
|
||||
INDICATION_ERR_LOCKED, //!< Node is locked.
|
||||
INDICATION_ERR_FW_FLASH_INIT, //!< Firmware update flash initialisation failure.
|
||||
INDICATION_ERR_FW_TIMEOUT, //!< Firmware update timeout.
|
||||
INDICATION_ERR_FW_CHECKSUM, //!< Firmware update checksum mismatch.
|
||||
INDICATION_ERR_END
|
||||
} indication_t;
|
||||
|
||||
/**
|
||||
* Function which is called when something changes about the internal state of MySensors.
|
||||
* @param ind Event indication of what happened.
|
||||
*/
|
||||
void setIndication( const indication_t ind );
|
||||
|
||||
/**
|
||||
* Allow user to define their own indication handler.
|
||||
*/
|
||||
void indication( const indication_t ) __attribute__((weak));
|
||||
|
||||
#endif
|
||||
@@ -19,81 +19,64 @@
|
||||
|
||||
#include "MyLeds.h"
|
||||
|
||||
#define LED_ON_OFF_RATIO (4) // Power of 2 please
|
||||
#define LED_PROCESS_INTERVAL_MS (MY_DEFAULT_LED_BLINK_PERIOD/LED_ON_OFF_RATIO)
|
||||
|
||||
// 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 _blink_next_time;
|
||||
static uint8_t countRx;
|
||||
static uint8_t countTx;
|
||||
static uint8_t countErr;
|
||||
static unsigned long prevTime = millis() - LED_PROCESS_INTERVAL_MS; // Substract some, to make sure leds gets updated on first run.
|
||||
|
||||
|
||||
inline void ledsInit()
|
||||
{
|
||||
// initialize counters
|
||||
countRx = 0;
|
||||
countTx = 0;
|
||||
countErr = 0;
|
||||
|
||||
inline void ledsInit() {
|
||||
// Setup led pins
|
||||
pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT);
|
||||
pinMode(MY_DEFAULT_TX_LED_PIN, 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
|
||||
hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF);
|
||||
hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF);
|
||||
hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF);
|
||||
|
||||
// initialize counters
|
||||
_countRx = 0;
|
||||
_countTx = 0;
|
||||
_countErr = 0;
|
||||
ledsProcess();
|
||||
}
|
||||
|
||||
inline void ledsProcess() {
|
||||
void ledsProcess() {
|
||||
// Just return if it is not the time...
|
||||
// http://playground.arduino.cc/Code/TimingRollover
|
||||
if ((long)(hwMillis() - _blink_next_time) < 0)
|
||||
if ((hwMillis() - prevTime) < LED_PROCESS_INTERVAL_MS)
|
||||
return;
|
||||
else
|
||||
_blink_next_time = hwMillis() + MY_DEFAULT_LED_BLINK_PERIOD;
|
||||
|
||||
// do the actual blinking
|
||||
if(_countRx && _countRx != 255) {
|
||||
// switch led on
|
||||
hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_ON);
|
||||
}
|
||||
else if(!_countRx) {
|
||||
// switching off
|
||||
hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, LED_OFF);
|
||||
}
|
||||
if(_countRx != 255)
|
||||
--_countRx;
|
||||
prevTime += LED_PROCESS_INTERVAL_MS;
|
||||
|
||||
if(_countTx && _countTx != 255) {
|
||||
// switch led on
|
||||
hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_ON);
|
||||
}
|
||||
else if(!_countTx) {
|
||||
// switching off
|
||||
hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, LED_OFF);
|
||||
}
|
||||
if(_countTx != 255)
|
||||
--_countTx;
|
||||
uint8_t state;
|
||||
|
||||
if(_countErr && _countErr != 255) {
|
||||
// switch led on
|
||||
hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_ON);
|
||||
}
|
||||
else if(!_countErr) {
|
||||
// switching off
|
||||
hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, LED_OFF);
|
||||
}
|
||||
if(_countErr != 255)
|
||||
--_countErr;
|
||||
// For an On/Off ratio of 4, the pattern repeated will be [on, on, on, off]
|
||||
// until the counter becomes 0.
|
||||
state = (countRx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
|
||||
hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, state);
|
||||
if (countRx) --countRx;
|
||||
|
||||
state = (countTx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
|
||||
hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, state);
|
||||
if (countTx) --countTx;
|
||||
|
||||
state = (countErr & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF;
|
||||
hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, state);
|
||||
if (countErr) --countErr;
|
||||
}
|
||||
|
||||
void ledsBlinkRx(uint8_t cnt) {
|
||||
if(_countRx == 255) { _countRx = cnt; }
|
||||
if (!countRx) { countRx = cnt*LED_ON_OFF_RATIO; }
|
||||
}
|
||||
|
||||
void ledsBlinkTx(uint8_t cnt) {
|
||||
if(_countTx == 255) { _countTx = cnt; }
|
||||
if(!countTx) { countTx = cnt*LED_ON_OFF_RATIO; }
|
||||
}
|
||||
|
||||
void ledsBlinkErr(uint8_t cnt) {
|
||||
if(_countErr == 255) { _countErr = cnt; }
|
||||
if(!countErr) { countErr = cnt*LED_ON_OFF_RATIO; }
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ inline void firmwareOTAUpdateRequest() {
|
||||
unsigned long enter = hwMillis();
|
||||
if (_fwUpdateOngoing && (enter - _fwLastRequestTime > MY_OTA_RETRY_DELAY)) {
|
||||
if (!_fwRetry) {
|
||||
setIndication(INDICATION_ERR_FW_TIMEOUT);
|
||||
debug(PSTR("fw upd fail\n"));
|
||||
// Give up. We have requested MY_OTA_RETRY times without any packet in return.
|
||||
_fwUpdateOngoing = false;
|
||||
@@ -57,11 +58,13 @@ inline bool firmwareOTAUpdateProcess() {
|
||||
NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)_msg.data;
|
||||
// compare with current node configuration, if they differ, start fw fetch process
|
||||
if (memcmp(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) {
|
||||
setIndication(INDICATION_FW_START);
|
||||
debug(PSTR("fw update\n"));
|
||||
// copy new FW config
|
||||
memcpy(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig));
|
||||
// Init flash
|
||||
if (!_flash.initialize()) {
|
||||
setIndication(INDICATION_ERR_FW_FLASH_INIT);
|
||||
debug(PSTR("flash init fail\n"));
|
||||
_fwUpdateOngoing = false;
|
||||
} else {
|
||||
@@ -81,6 +84,7 @@ inline bool firmwareOTAUpdateProcess() {
|
||||
} else if (_msg.type == ST_FIRMWARE_RESPONSE) {
|
||||
if (_fwUpdateOngoing) {
|
||||
// Save block to flash
|
||||
setIndication(INDICATION_FW_RX);
|
||||
debug(PSTR("fw block %d\n"), _fwBlock);
|
||||
// extract FW block
|
||||
ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)_msg.data;
|
||||
@@ -102,6 +106,7 @@ inline bool firmwareOTAUpdateProcess() {
|
||||
hwWriteConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig));
|
||||
hwReboot();
|
||||
} else {
|
||||
setIndication(INDICATION_ERR_FW_CHECKSUM);
|
||||
debug(PSTR("fw checksum fail\n"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,9 @@ void _infiniteLoop() {
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
yield();
|
||||
#endif
|
||||
#if defined (MY_LEDS_BLINKING_FEATURE)
|
||||
ledsProcess();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +82,10 @@ void _begin() {
|
||||
|
||||
debug(PSTR("Starting " MY_NODE_TYPE " (" MY_CAPABILITIES ", " LIBRARY_VERSION ")\n"));
|
||||
|
||||
#if defined(MY_LEDS_BLINKING_FEATURE)
|
||||
ledsInit();
|
||||
#endif
|
||||
|
||||
signerInit();
|
||||
|
||||
#if defined(MY_RADIO_FEATURE)
|
||||
@@ -86,6 +93,7 @@ void _begin() {
|
||||
|
||||
// Setup radio
|
||||
if (!transportInit()) {
|
||||
setIndication(INDICATION_ERR_INIT_TRANSPORT);
|
||||
debug(PSTR("Radio init failed. Check wiring.\n"));
|
||||
// Nothing more we can do
|
||||
_infiniteLoop();
|
||||
@@ -101,6 +109,7 @@ void _begin() {
|
||||
|
||||
// initialize the transport driver
|
||||
if (!gatewayTransportInit()) {
|
||||
setIndication(INDICATION_ERR_INIT_GWTRANSPORT);
|
||||
debug(PSTR("Transport driver init fail\n"));
|
||||
// Nothing more we can do
|
||||
_infiniteLoop();
|
||||
@@ -108,11 +117,6 @@ void _begin() {
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MY_LEDS_BLINKING_FEATURE)
|
||||
ledsInit();
|
||||
#endif
|
||||
|
||||
// Read latest received controller configuration from EEPROM
|
||||
hwReadConfigBlock((void*)&_cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig));
|
||||
if (_cc.isMetric == 0xff) {
|
||||
@@ -141,6 +145,7 @@ void _begin() {
|
||||
// We don't actually know the distance to gw here. Let's pretend it is 1.
|
||||
// If the current node is also repeater, be aware of this.
|
||||
_nc.distance = 1;
|
||||
setIndication(INDICATION_GOT_PARENT);
|
||||
} else if (!isValidParent(_nc.parentNodeId)) {
|
||||
// Auto find parent, but parent in eeprom is invalid. Try find one.
|
||||
transportFindParentNode();
|
||||
@@ -151,6 +156,7 @@ void _begin() {
|
||||
_nc.nodeId = MY_NODE_ID;
|
||||
// Save static id in eeprom
|
||||
hwWriteConfig(EEPROM_NODE_ID_ADDRESS, MY_NODE_ID);
|
||||
setIndication(INDICATION_GOT_NODEID);
|
||||
} else if (_nc.nodeId == AUTO && isValidParent(_nc.parentNodeId)) {
|
||||
// Try to fetch node-id from gateway
|
||||
transportRequestNodeId();
|
||||
@@ -174,6 +180,7 @@ void _begin() {
|
||||
} else {
|
||||
// Disable pullup
|
||||
pinMode(MY_NODE_UNLOCK_PIN, INPUT);
|
||||
setIndication(INDICATION_ERR_LOCKED);
|
||||
nodeLock("LDB"); //Locked during boot
|
||||
}
|
||||
} else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) {
|
||||
@@ -222,7 +229,6 @@ boolean _sendRoute(MyMessage &message) {
|
||||
if (message.destination == _nc.nodeId) {
|
||||
// This is a message sent from a sensor attached on the gateway node.
|
||||
// Pass it directly to the gateway transport layer.
|
||||
ledBlinkTx(1);
|
||||
return gatewayTransportSend(message);
|
||||
}
|
||||
#endif
|
||||
@@ -278,6 +284,7 @@ void _processInternalMessages() {
|
||||
#if !defined(MY_DISABLE_REMOTE_RESET)
|
||||
if (type == I_REBOOT) {
|
||||
// Requires MySensors or other bootloader with watchdogs enabled
|
||||
setIndication(INDICATION_REBOOT);
|
||||
hwReboot();
|
||||
} else
|
||||
#endif
|
||||
@@ -310,6 +317,7 @@ void _processInternalMessages() {
|
||||
#if defined(MY_REPEATER_FEATURE)
|
||||
if (_msg.data[0] == 'C') {
|
||||
// Clears child relay data for this node
|
||||
setIndication(INDICATION_CLEAR_ROUTING);
|
||||
debug(PSTR("clear routing table\n"));
|
||||
uint8_t i = 255;
|
||||
do {
|
||||
@@ -354,6 +362,7 @@ void _processInternalMessages() {
|
||||
for (int i=EEPROM_START;i<EEPROM_LOCAL_CONFIG_ADDRESS;i++) {
|
||||
hwWriteConfig(i,0xFF);
|
||||
}
|
||||
setIndication(INDICATION_REBOOT);
|
||||
hwReboot();
|
||||
}
|
||||
#endif
|
||||
@@ -408,7 +417,10 @@ int8_t sleep(unsigned long ms) {
|
||||
#if defined(MY_RADIO_FEATURE)
|
||||
transportPowerDown();
|
||||
#endif
|
||||
return hwSleep(ms);
|
||||
setIndication(INDICATION_SLEEP);
|
||||
const int8_t res = hwSleep(ms);
|
||||
setIndication(INDICATION_WAKEUP);
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -438,7 +450,10 @@ int8_t sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) {
|
||||
#if defined(MY_RADIO_FEATURE)
|
||||
transportPowerDown();
|
||||
#endif
|
||||
return hwSleep(interrupt, mode, ms);
|
||||
setIndication(INDICATION_SLEEP);
|
||||
const int8_t res = hwSleep(interrupt, mode, ms);
|
||||
setIndication(INDICATION_WAKEUP);
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -470,7 +485,10 @@ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode
|
||||
#if defined(MY_RADIO_FEATURE)
|
||||
transportPowerDown();
|
||||
#endif
|
||||
return hwSleep(interrupt1, mode1, interrupt2, mode2, ms);
|
||||
setIndication(INDICATION_SLEEP);
|
||||
const int8_t res = hwSleep(interrupt1, mode1, interrupt2, mode2, ms);
|
||||
setIndication(INDICATION_WAKEUP);
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -488,6 +506,7 @@ void nodeLock(const char* str) {
|
||||
// Make sure EEPROM is updated to locked status
|
||||
hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, 0);
|
||||
while (1) {
|
||||
setIndication(INDICATION_ERR_LOCKED);
|
||||
debug(PSTR("Node is locked. Ground pin %d and reset to unlock.\n"), MY_NODE_UNLOCK_PIN);
|
||||
#if defined(MY_GATEWAY_ESP8266)
|
||||
yield();
|
||||
@@ -497,7 +516,9 @@ void nodeLock(const char* str) {
|
||||
#if defined(MY_RADIO_FEATURE)
|
||||
transportPowerDown();
|
||||
#endif
|
||||
setIndication(INDICATION_SLEEP);
|
||||
(void)hwSleep((unsigned long)1000*60*30); // Sleep for 30 min before resending LOCKED message
|
||||
setIndication(INDICATION_WAKEUP);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -42,7 +42,7 @@ inline void transportProcess() {
|
||||
|
||||
uint8_t payloadLength = transportReceive((uint8_t *)&_msg);
|
||||
(void)payloadLength; //until somebody makes use of it
|
||||
ledBlinkRx(1);
|
||||
setIndication(INDICATION_RX);
|
||||
|
||||
|
||||
uint8_t command = mGetCommand(_msg);
|
||||
@@ -54,8 +54,8 @@ inline void transportProcess() {
|
||||
|
||||
// Reject massages that do not pass verification
|
||||
if (!signerVerifyMsg(_msg)) {
|
||||
setIndication(INDICATION_ERR_SIGN);
|
||||
debug(PSTR("verify fail\n"));
|
||||
ledBlinkErr(1);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,8 +75,8 @@ inline void transportProcess() {
|
||||
}
|
||||
|
||||
if(!(mGetVersion(_msg) == PROTOCOL_VERSION)) {
|
||||
setIndication(INDICATION_ERR_VERSION);
|
||||
debug(PSTR("ver mismatch\n"));
|
||||
ledBlinkErr(1);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ inline void transportProcess() {
|
||||
distance++;
|
||||
if (isValidDistance(distance) && (distance < _nc.distance)) {
|
||||
// Found a neighbor closer to GW than previously found
|
||||
setIndication(INDICATION_GOT_PARENT);
|
||||
_nc.distance = distance;
|
||||
_nc.parentNodeId = sender;
|
||||
hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, _nc.parentNodeId);
|
||||
@@ -135,11 +136,13 @@ inline void transportProcess() {
|
||||
_nc.nodeId = _msg.getByte();
|
||||
if (_nc.nodeId == AUTO) {
|
||||
// sensor net gateway will return max id if all sensor id are taken
|
||||
setIndication(INDICATION_ERR_NET_FULL);
|
||||
debug(PSTR("full\n"));
|
||||
// Nothing else we can do...
|
||||
_infiniteLoop();
|
||||
|
||||
}
|
||||
setIndication(INDICATION_GOT_NODEID);
|
||||
transportPresentNode();
|
||||
if (presentation)
|
||||
presentation();
|
||||
@@ -214,9 +217,10 @@ boolean transportSendWrite(uint8_t to, MyMessage &message) {
|
||||
mSetVersion(message, PROTOCOL_VERSION);
|
||||
uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message);
|
||||
message.last = _nc.nodeId;
|
||||
ledBlinkTx(1);
|
||||
setIndication(INDICATION_TX);
|
||||
|
||||
bool ok = transportSend(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length));
|
||||
if (!ok) setIndication(INDICATION_ERR_TX);
|
||||
|
||||
debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,st=%s:%s\n"),
|
||||
message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type,
|
||||
@@ -234,23 +238,23 @@ boolean transportSendRoute(MyMessage &message) {
|
||||
|
||||
// If we still don't have any parent id, re-request and skip this message.
|
||||
if (_nc.parentNodeId == AUTO) {
|
||||
transportFindParentNode();
|
||||
ledBlinkErr(1);
|
||||
setIndication(INDICATION_ERR_FIND_PARENT);
|
||||
transportFindParentNode();
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we still don't have any node id, re-request and skip this message.
|
||||
if (_nc.nodeId == AUTO) {
|
||||
setIndication(INDICATION_ERR_GET_NODEID);
|
||||
transportRequestNodeId();
|
||||
ledBlinkErr(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
mSetVersion(message, PROTOCOL_VERSION);
|
||||
|
||||
if (!signerSignMsg(message)) {
|
||||
setIndication(INDICATION_ERR_SIGN);
|
||||
debug(PSTR("sign fail\n"));
|
||||
ledBlinkErr(1);
|
||||
}
|
||||
|
||||
#if !defined(MY_REPEATER_FEATURE)
|
||||
@@ -322,7 +326,6 @@ boolean transportSendRoute(MyMessage &message) {
|
||||
if (!ok) {
|
||||
// Failure when sending to parent node. The parent node might be down and we
|
||||
// need to find another route to gateway.
|
||||
ledBlinkErr(1);
|
||||
_failedTransmissions++;
|
||||
if (_autoFindParent && _failedTransmissions > SEARCH_FAILURES) {
|
||||
transportFindParentNode();
|
||||
@@ -336,6 +339,7 @@ boolean transportSendRoute(MyMessage &message) {
|
||||
|
||||
|
||||
void transportRequestNodeId() {
|
||||
setIndication(INDICATION_REQ_NODEID);
|
||||
debug(PSTR("req id\n"));
|
||||
transportSetAddress(_nc.nodeId);
|
||||
build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set("");
|
||||
@@ -344,6 +348,7 @@ void transportRequestNodeId() {
|
||||
}
|
||||
|
||||
void transportPresentNode() {
|
||||
setIndication(INDICATION_PRESENT);
|
||||
// Open reading pipe for messages directed to this node (set write pipe to same)
|
||||
transportSetAddress(_nc.nodeId);
|
||||
// Present node and request config
|
||||
@@ -386,6 +391,8 @@ void transportFindParentNode() {
|
||||
return;
|
||||
findingParentNode = true;
|
||||
|
||||
setIndication(INDICATION_FIND_PARENT);
|
||||
|
||||
_failedTransmissions = 0;
|
||||
|
||||
// Set distance to max
|
||||
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* 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-2016 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
|
||||
*
|
||||
* Simple binary switch example
|
||||
* Connect button or door/window reed switch between
|
||||
* digitial I/O pin 3 (BUTTON_PIN below) and GND.
|
||||
* A NeoPixel LED will be used to provide visual feedback of the sensor status.
|
||||
* http://www.mysensors.org/build/binary
|
||||
*/
|
||||
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
#include <MsTimer2.h>
|
||||
#include <SPI.h>
|
||||
#include <MySensor.h>
|
||||
#include <Bounce2.h>
|
||||
|
||||
#define LED_CYCLE_MS 30 // Update rate of LEDs, in [ms].
|
||||
#define NEO_PIN 6 // NeoPixels input pin
|
||||
#define CHILD_ID 3
|
||||
#define BUTTON_PIN 3 // Arduino Digital I/O pin for button/reed switch
|
||||
|
||||
Bounce debouncer = Bounce();
|
||||
int oldValue=-1;
|
||||
|
||||
static Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, NEO_PIN, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
// Change to V_LIGHT if you use S_LIGHT in presentation below
|
||||
MyMessage msg(CHILD_ID,V_TRIPPED);
|
||||
|
||||
#define BLINK_TIMES(x) (x<<4)
|
||||
|
||||
static uint8_t ledR = 0;
|
||||
static uint8_t ledG = 0;
|
||||
static uint8_t ledB = 0;
|
||||
|
||||
static void updateLed(void)
|
||||
{
|
||||
// Update the pattern (setting leds).
|
||||
if (ledR > 0) --ledR;
|
||||
if (ledG > 0) --ledG;
|
||||
if (ledB > 0) --ledB;
|
||||
// Determine of each color if it should be on or off.
|
||||
uint8_t r = ((ledR & 0x0F) < 6) ? 0 : 255;
|
||||
uint8_t g = ((ledG & 0x0F) < 6) ? 0 : 255;
|
||||
uint8_t b = ((ledB & 0x0F) < 6) ? 0 : 255;
|
||||
pixels.setPixelColor(0, r, g, b);
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void before()
|
||||
{
|
||||
// Initialize the NeoPixel chain
|
||||
pixels.begin();
|
||||
pixels.show();
|
||||
|
||||
// Configure timer interrupt
|
||||
MsTimer2::set(LED_CYCLE_MS, updateLed);
|
||||
MsTimer2::start();
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Setup the button
|
||||
pinMode(BUTTON_PIN,INPUT);
|
||||
// Activate internal pull-up
|
||||
digitalWrite(BUTTON_PIN,HIGH);
|
||||
|
||||
// After setting up the button, setup debouncer
|
||||
debouncer.attach(BUTTON_PIN);
|
||||
debouncer.interval(5);
|
||||
}
|
||||
|
||||
void presentation() {
|
||||
// Register binary input sensor to gw (they will be created as child devices)
|
||||
// You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage.
|
||||
// If S_LIGHT is used, remember to update variable type you send in. See "msg" above.
|
||||
present(CHILD_ID, S_DOOR);
|
||||
}
|
||||
|
||||
void indication( const indication_t ind )
|
||||
{
|
||||
if ((INDICATION_TX == ind) || (INDICATION_GW_TX == ind))
|
||||
{
|
||||
// Blink Blue 1x
|
||||
ledB = BLINK_TIMES(1);
|
||||
Serial.println(F("TX"));
|
||||
} else if ((INDICATION_RX == ind) || (INDICATION_GW_RX == ind))
|
||||
{
|
||||
// Blink Blue 1x
|
||||
ledB = BLINK_TIMES(1);
|
||||
Serial.println(F("RX"));
|
||||
} else if (INDICATION_FIND_PARENT == ind)
|
||||
{
|
||||
// Blink Green 5x
|
||||
ledG = BLINK_TIMES(5);
|
||||
Serial.println(F("JOIN"));
|
||||
} else if (INDICATION_GOT_PARENT == ind)
|
||||
{
|
||||
// Green off
|
||||
ledG = BLINK_TIMES(0);
|
||||
Serial.println(F("JOINED"));
|
||||
} else if (ind > INDICATION_ERR_START)
|
||||
{
|
||||
// Blink Red, depending on the error number
|
||||
ledR = BLINK_TIMES(ind - INDICATION_ERR_START);
|
||||
Serial.print(F("ERROR")); Serial.println(ind - INDICATION_ERR_START);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if digital input has changed and send in new value
|
||||
void loop()
|
||||
{
|
||||
debouncer.update();
|
||||
// Get the update value
|
||||
int value = debouncer.read();
|
||||
|
||||
if (value != oldValue) {
|
||||
// Send in the new value
|
||||
send(msg.set(value==HIGH ? 1 : 0));
|
||||
oldValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user