From 756ea4e264c0c395e1765f5cbd398c734560c060 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 12 Feb 2018 01:47:11 +0100 Subject: [PATCH 01/53] bugfix and features - Added Hardware Reset of lora module at startup - Fixed push button duration bug - Set IRQ var to be volatile --- src/TheThingsNode.cpp | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/TheThingsNode.cpp b/src/TheThingsNode.cpp index 85ce12c..9cc2b9a 100644 --- a/src/TheThingsNode.cpp +++ b/src/TheThingsNode.cpp @@ -11,6 +11,7 @@ #define TTN_GREEN_LED 5 #define TTN_BLUE_LED 6 #define TTN_BUTTON 16 +#define TTN_LORA_RESET 21 #define TTN_VBAT_MEAS_EN A2 #define TTN_VBAT_MEAS 1 #define TTN_TEMPERATURE_SENSOR_ADDRESS 0x18 @@ -41,12 +42,12 @@ Hackscribble_MCP9804 TTN_TEMPERATURE_SENSOR(TTN_TEMPERATURE_SENSOR_ADDRESS); -bool TTN_TEMPERATURE = false; -bool TTN_MOTION_START = false; -bool TTN_MOTION_STOP = false; -bool TTN_BUTTON_PRESS = false; -bool TTN_BUTTON_RELEASE = false; -uint32_t TTN_INTERVAL = 0; +volatile bool TTN_TEMPERATURE = false; +volatile bool TTN_MOTION_START = false; +volatile bool TTN_MOTION_STOP = false; +volatile bool TTN_BUTTON_PRESS = false; +volatile bool TTN_BUTTON_RELEASE = false; +volatile uint32_t TTN_INTERVAL = 0; void TTN_TEMPERATURE_FN() { @@ -72,9 +73,12 @@ void TTN_BUTTON_FN() uint8_t trigger = getPinChangeInterruptTrigger(digitalPinToPCINT(TTN_BUTTON)); if (trigger == FALLING) { + //Serial.println(F("IPRESS")); TTN_BUTTON_PRESS = true; } - else if (trigger == RISING) + + // Be sure main loop ACK press button before rising the release + if (TTN_BUTTON_PRESS == false && trigger == RISING ) { TTN_BUTTON_RELEASE = true; } @@ -217,8 +221,16 @@ void TheThingsNode::loop() } else { - Serial.flush(); - deepSleep(); + // Don't go to sleep mode while button is still pressed + // because if so, timer of ms will be stopped and duration + // of pressed button will not work + if ( this->buttonPressed ) { + delay(100); + TTN_INTERVAL = TTN_INTERVAL + 100; + } else { + Serial.flush(); + deepSleep(); + } } } @@ -737,6 +749,15 @@ TheThingsNode::TheThingsNode() pinMode(TTN_BLUE_LED, OUTPUT); setColor(TTN_BLACK); + // set pin mode every time to avoid constraining the user about when the pin is initialized + #ifdef TTN_LORA_RESET + pinMode(TTN_LORA_RESET, OUTPUT); + digitalWrite(TTN_LORA_RESET, LOW); + delay(100); + digitalWrite(TTN_LORA_RESET, HIGH); + #endif + + // TODO: Can we enable/disable this at will to save memory? USBCON |= (1 << OTGPADE); From 32dbe9769636e62fc7f50968e4f67854b54014c9 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 12 Feb 2018 01:50:59 +0100 Subject: [PATCH 02/53] Added Low Power Example --- docs/TheThingsNode.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/TheThingsNode.md b/docs/TheThingsNode.md index 623a364..9dc38c5 100644 --- a/docs/TheThingsNode.md +++ b/docs/TheThingsNode.md @@ -81,6 +81,9 @@ void sleep() { } ``` +Pay attention, this internal sleep method of the library does not put the Lora module (RN2483) into sleep mode and thus your node may consume 3mA even in sleep mode. You need to manually set the lora module to sleep and wake. +Check the example [BatteryMonitorLPP](https://github.com/TheThingsNetwork/arduino-node-lib/tree/master/examples/BatteryMonitorLPP/) + ## Interval Instead of using your `loop()` function, use `configInterval()` and `onInterval()` to set a function to be called on a certain interval: From 0b21e93d4c712ebee857a5b776556924dc1e75ee Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 12 Feb 2018 02:02:38 +0100 Subject: [PATCH 03/53] Creation --- .../BatteryMonitorLPP/BatteryMonitorLPP.ino | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 examples/BatteryMonitorLPP/BatteryMonitorLPP.ino diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino new file mode 100644 index 0000000..b87b71c --- /dev/null +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -0,0 +1,172 @@ +// ********************************************************************************** +// Ultra Low Power BatteryMonitorLPP for TheThingsNode device +// ********************************************************************************** +// +// This program just send lora packet containing Battery info to myDevices portal +// if button is pressed the batterey packet is send and the push button duration +// is also added +// +// This example also take into account of setting Lora Module to sleep mode this +// allow to reduce consumption in sleep mode from 3.2mA to 280µA +// +// Written by Charles-Henri Hallard (CH2i) +// +// History : V1.00 2018-02-11 - First release based on TTN CayenneLPP example code +// V1.01 2018-02-12 - Added Hard reset of Lora module at startup +// - Fixed issue https://github.com/TheThingsNetwork/arduino-node-lib/issues/9 +// - Enable Low Power of Lora Module +// +// ********************************************************************************** + +#include +#include + +// Set your AppEUI and AppKey +const char *appEui = "0000000000000000"; +const char *appKey = "00000000000000000000000000000000"; + +// Replace REPLACE_ME with TTN_FP_EU868 or TTN_FP_US915 +#define freqPlan REPLACE_ME + +#define loraSerial Serial1 +#define debugSerial Serial + +TheThingsNetwork ttn(loraSerial, debugSerial, freqPlan); +TheThingsNode *node; +CayenneLPP lpp(16); + +#define PORT_SETUP 1 +#define PORT_INTERVAL 2 +#define PORT_MOTION 3 +#define PORT_BUTTON 4 + +// Interval between send in seconds, so 300s = 5min +#define CONFIG_INTERVAL 300 + +void sendData(uint8_t port=PORT_SETUP, uint32_t duration=0); + +// This is called on each interval we defined so mainly +// this is where we need to do our job +void interval() +{ + node->setColor(TTN_BLUE); + debugSerial.println(F("-- SEND: INTERVAL")); + sendData(PORT_INTERVAL); +} + +// This is called on each wake, every 8S or by an sensor/button interrupt +// if it's watchdog, we mainly do nothing (core IRQ, we don't have choice) +// but if it's an interupt it will ne bone ine loop +void wake() +{ + debugSerial.println(F("-- WAKE")); + + // Just if you want to see this IRQ with a LED, remove for LOW power + //node->setColor(TTN_GREEN); + //delay(50); + //node->setColor(TTN_BLACK); + //delay(100); +} + +void sleep() +{ + node->setColor(TTN_BLACK); + + // Just in case, disable all sensors + // this couldn't hurt except time to do job + node->configMotion(false); + node->configLight(false); + node->configTemperature(false); +} + +void onButtonRelease(unsigned long duration) +{ + uint16_t adc_value; + uint32_t timepressed = (uint32_t) duration; + + node->setColor(TTN_BLUE); + + debugSerial.print(F("-- SEND: BUTTON ")); + debugSerial.print(timepressed); + debugSerial.println(F(" ms")); + + sendData(PORT_BUTTON, timepressed); +} + +void sendData(uint8_t port, uint32_t value) +{ + // Wake RN2483 + ttn.wake(); + + // Read battery voltage + uint16_t vbat = node->getBattery(); + + debugSerial.print(F("Battery:\t")); + debugSerial.print(vbat); + debugSerial.println(F("mV")); + + // Just send battery voltage + lpp.reset(); + lpp.addAnalogInput(4, vbat/1000.0); + + // If button pressed, send press duration + // please myDeviceCayenne add counter value type to + // avoid us using analog values to send counters + if (port == PORT_BUTTON) { + debugSerial.print(F("Button:\t")); + debugSerial.print(value); + debugSerial.println(F("ms")); + lpp.addAnalogInput(7, value/1000.0); + } + + ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); + + // Set RN2483 to sleep mode + ttn.sleep( (uint32_t) (CONFIG_INTERVAL*1000) ); + + // This one is not optionnal, remove it + // and say bye bye to RN2983 sleep mode + delay(50); +} + +void setup() +{ + loraSerial.begin(57600); + debugSerial.begin(9600); + + // Wait a maximum of 10s for Serial Monitor + while (!debugSerial && millis() < 10000) + ; + + // Config Node, Disable all sensors + // Check node schematics here + // https://github.com/TheThingsProducts/node + node = TheThingsNode::setup(); + + // Each interval + node->configInterval(true, CONFIG_INTERVAL*1000); + node->onWake(wake); + node->onInterval(interval); + node->onSleep(sleep); + + // We monitor just button release + node->onButtonRelease(onButtonRelease); + + // Test sensors and set LED to GREEN if it works + node->showStatus(); + node->setColor(TTN_GREEN); + + debugSerial.println(F("-- TTN: STATUS")); + ttn.showStatus(); + + debugSerial.println(F("-- TTN: JOIN")); + ttn.join(appEui, appKey); + + debugSerial.println(F("-- SEND: SETUP")); + sendData(PORT_SETUP); +} + +void loop() +{ + node->loop(); +} From 4ba708be3938c01db818a7b442ff904a661b0a65 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 12 Feb 2018 02:07:17 +0100 Subject: [PATCH 04/53] Added Lora Module Sleep Mode --- examples/Basic/Basic.ino | 10 ++++++++++ examples/CayenneLPP/CayenneLPP.ino | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/examples/Basic/Basic.ino b/examples/Basic/Basic.ino index b2f9f38..cb34996 100644 --- a/examples/Basic/Basic.ino +++ b/examples/Basic/Basic.ino @@ -118,6 +118,9 @@ void onButtonRelease(unsigned long duration) void sendData(uint8_t port) { + // Wake RN2483 + ttn.wake(); + ttn.showStatus(); node->showStatus(); @@ -140,4 +143,11 @@ void sendData(uint8_t port) payload[5] = bytes[0]; ttn.sendBytes(payload, sizeof(payload), port); + + // Set RN2483 to sleep mode + ttn.sleep( 60000 ); + + // This one is not optionnal, remove it + // and say bye bye to RN2983 sleep mode + delay(50); } diff --git a/examples/CayenneLPP/CayenneLPP.ino b/examples/CayenneLPP/CayenneLPP.ino index 8a0355a..6922b0d 100644 --- a/examples/CayenneLPP/CayenneLPP.ino +++ b/examples/CayenneLPP/CayenneLPP.ino @@ -97,6 +97,10 @@ void onButtonRelease(unsigned long duration) void sendData(uint8_t port) { + + // Wake RN2483 + ttn.wake(); + printSensors(); lpp.reset(); @@ -112,6 +116,9 @@ void sendData(uint8_t port) lpp.addAccelerometer(7, x, y, z); ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); + + // Set RN2483 to sleep mode + ttn.sleep( 60000 ); } void printSensors() From 6b736c6e6f0ffa84cdbc509f8cba59270d9d46de Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 12 Feb 2018 02:10:05 +0100 Subject: [PATCH 05/53] Fixed link --- docs/TheThingsNode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/TheThingsNode.md b/docs/TheThingsNode.md index 9dc38c5..83e0889 100644 --- a/docs/TheThingsNode.md +++ b/docs/TheThingsNode.md @@ -82,7 +82,7 @@ void sleep() { ``` Pay attention, this internal sleep method of the library does not put the Lora module (RN2483) into sleep mode and thus your node may consume 3mA even in sleep mode. You need to manually set the lora module to sleep and wake. -Check the example [BatteryMonitorLPP](https://github.com/TheThingsNetwork/arduino-node-lib/tree/master/examples/BatteryMonitorLPP/) +Check the example [BatteryMonitorLPP](../examples/BatteryMonitorLPP/) ## Interval Instead of using your `loop()` function, use `configInterval()` and `onInterval()` to set a function to be called on a certain interval: From 6bed71f942fe31c57eead8a86556fa0d2d0d1b7c Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 12 Feb 2018 02:14:46 +0100 Subject: [PATCH 06/53] bump to version 2.0.3 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 51cef02..a988efa 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TheThingsNode -version=2.0.2 +version=2.0.3 author=The Things Network maintainer=Johan Stokking sentence=The Things Node Arduino Library. From c9869a72c8fab3e3083b75a97ce7fd4cf0cfc0ec Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 12 Feb 2018 11:28:34 +0100 Subject: [PATCH 07/53] force cast of CONFIG_INTERVAL #define --- examples/BatteryMonitorLPP/BatteryMonitorLPP.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino index b87b71c..82d67e8 100644 --- a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -41,7 +41,7 @@ CayenneLPP lpp(16); #define PORT_BUTTON 4 // Interval between send in seconds, so 300s = 5min -#define CONFIG_INTERVAL 300 +#define CONFIG_INTERVAL ((uint32_t) 300) void sendData(uint8_t port=PORT_SETUP, uint32_t duration=0); @@ -122,7 +122,7 @@ void sendData(uint8_t port, uint32_t value) ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); // Set RN2483 to sleep mode - ttn.sleep( (uint32_t) (CONFIG_INTERVAL*1000) ); + ttn.sleep( CONFIG_INTERVAL*1000 ); // This one is not optionnal, remove it // and say bye bye to RN2983 sleep mode From 939b98331d65c825546fe748a8c2d3b60ff02aa6 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 12 Feb 2018 16:40:33 +0100 Subject: [PATCH 08/53] Only TTN Core team allowed to increase version --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index a988efa..51cef02 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TheThingsNode -version=2.0.3 +version=2.0.2 author=The Things Network maintainer=Johan Stokking sentence=The Things Node Arduino Library. From 8dfc171d6833978f3d63cf62188583ba8893328a Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 12 Feb 2018 16:40:51 +0100 Subject: [PATCH 09/53] Cosmetic --- docs/TheThingsNode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/TheThingsNode.md b/docs/TheThingsNode.md index 83e0889..7fd8b47 100644 --- a/docs/TheThingsNode.md +++ b/docs/TheThingsNode.md @@ -81,7 +81,7 @@ void sleep() { } ``` -Pay attention, this internal sleep method of the library does not put the Lora module (RN2483) into sleep mode and thus your node may consume 3mA even in sleep mode. You need to manually set the lora module to sleep and wake. +Pay attention, this internal sleep method of the library does not put the LoRa module (RN2483 or RN2903) into sleep mode and thus your node may consume 3mA even in sleep mode. You need to manually set the LoRa module to sleep and wake. Check the example [BatteryMonitorLPP](../examples/BatteryMonitorLPP/) ## Interval From c9c05eadea55483cebcc44f5254fb17aff42e393 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 13 Feb 2018 16:04:35 +0100 Subject: [PATCH 10/53] cosmetic formating --- examples/Basic/Basic.ino | 2 +- .../BatteryMonitorLPP/BatteryMonitorLPP.ino | 28 +++---------------- src/TheThingsNode.cpp | 5 ++-- 3 files changed, 7 insertions(+), 28 deletions(-) diff --git a/examples/Basic/Basic.ino b/examples/Basic/Basic.ino index cb34996..97e6259 100644 --- a/examples/Basic/Basic.ino +++ b/examples/Basic/Basic.ino @@ -145,7 +145,7 @@ void sendData(uint8_t port) ttn.sendBytes(payload, sizeof(payload), port); // Set RN2483 to sleep mode - ttn.sleep( 60000 ); + ttn.sleep(60000); // This one is not optionnal, remove it // and say bye bye to RN2983 sleep mode diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino index 82d67e8..5f0a551 100644 --- a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -1,23 +1,3 @@ -// ********************************************************************************** -// Ultra Low Power BatteryMonitorLPP for TheThingsNode device -// ********************************************************************************** -// -// This program just send lora packet containing Battery info to myDevices portal -// if button is pressed the batterey packet is send and the push button duration -// is also added -// -// This example also take into account of setting Lora Module to sleep mode this -// allow to reduce consumption in sleep mode from 3.2mA to 280µA -// -// Written by Charles-Henri Hallard (CH2i) -// -// History : V1.00 2018-02-11 - First release based on TTN CayenneLPP example code -// V1.01 2018-02-12 - Added Hard reset of Lora module at startup -// - Fixed issue https://github.com/TheThingsNetwork/arduino-node-lib/issues/9 -// - Enable Low Power of Lora Module -// -// ********************************************************************************** - #include #include @@ -113,10 +93,10 @@ void sendData(uint8_t port, uint32_t value) // please myDeviceCayenne add counter value type to // avoid us using analog values to send counters if (port == PORT_BUTTON) { - debugSerial.print(F("Button:\t")); - debugSerial.print(value); - debugSerial.println(F("ms")); - lpp.addAnalogInput(7, value/1000.0); + debugSerial.print(F("Button:\t")); + debugSerial.print(value); + debugSerial.println(F("ms")); + lpp.addAnalogInput(7, value/1000.0); } ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); diff --git a/src/TheThingsNode.cpp b/src/TheThingsNode.cpp index 9cc2b9a..b1ce333 100644 --- a/src/TheThingsNode.cpp +++ b/src/TheThingsNode.cpp @@ -73,7 +73,6 @@ void TTN_BUTTON_FN() uint8_t trigger = getPinChangeInterruptTrigger(digitalPinToPCINT(TTN_BUTTON)); if (trigger == FALLING) { - //Serial.println(F("IPRESS")); TTN_BUTTON_PRESS = true; } @@ -224,7 +223,7 @@ void TheThingsNode::loop() // Don't go to sleep mode while button is still pressed // because if so, timer of ms will be stopped and duration // of pressed button will not work - if ( this->buttonPressed ) { + if (this->buttonPressed) { delay(100); TTN_INTERVAL = TTN_INTERVAL + 100; } else { @@ -749,7 +748,7 @@ TheThingsNode::TheThingsNode() pinMode(TTN_BLUE_LED, OUTPUT); setColor(TTN_BLACK); - // set pin mode every time to avoid constraining the user about when the pin is initialized + // hardware reset of LoRa module, so module is reset on sketch upload #ifdef TTN_LORA_RESET pinMode(TTN_LORA_RESET, OUTPUT); digitalWrite(TTN_LORA_RESET, LOW); From 54ef0987709e40d814759272c96ce343c28bba0b Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 13 Feb 2018 16:10:25 +0100 Subject: [PATCH 11/53] Added missing include --- examples/BatteryMonitorLPP/BatteryMonitorLPP.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino index 5f0a551..13acef4 100644 --- a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -1,4 +1,5 @@ #include +#include #include // Set your AppEUI and AppKey From 5738e06f0d4e940105b7c524a0b60a945b1da6e2 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 13 Feb 2018 16:48:19 +0100 Subject: [PATCH 12/53] Requires TheThingsNode library 2.5.6 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 939e9c0..d1f465c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ before_install: - sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino install: - ln -s $PWD /usr/local/share/arduino/libraries/TheThingsNode - - arduino --install-library "DHT sensor library:1.3.0,Adafruit Unified Sensor:1.0.2,TheThingsNetwork:2.3.1" + - arduino --install-library "DHT sensor library:1.3.0,Adafruit Unified Sensor:1.0.2,TheThingsNetwork:2.5.6" - git clone https://github.com/sparkfun/arduino_boards /tmp/sparkfun - mv /tmp/sparkfun/sparkfun /usr/local/share/arduino/hardware/sparkfun before_script: From 193cfbde098f5cdaef4346561d6076944ff6feb7 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 20 Feb 2018 01:14:49 +0100 Subject: [PATCH 13/53] Added option to wake by lora module Moved #include definition here Added wakeStatus to wakeCallback to get what waked us Added pointer to TheThingsNetwork object to enable Lora module sleep/wake up --- src/TheThingsNode.h | 59 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/src/TheThingsNode.h b/src/TheThingsNode.h index ee60f5f..4fd3467 100644 --- a/src/TheThingsNode.h +++ b/src/TheThingsNode.h @@ -16,6 +16,58 @@ #include #include "TheThingsNetwork.h" +#define TTN_LDR_INPUT 10 +#define TTN_LDR_GAIN1 12 +#define TTN_LDR_GAIN2 4 +#define TTN_RED_LED 13 +#define TTN_GREEN_LED 5 +#define TTN_BLUE_LED 6 +#define TTN_BUTTON 16 +#define TTN_LORA_RESET 21 /* Hardware reset pin of LoRa module */ +#define TTN_LORA_SERIAL_RX_INT INT2 /* Serial RX Interrupt number (to be waked by RN2483 or RN2903 module) */ +#define TTN_VBAT_MEAS_EN A2 +#define TTN_VBAT_MEAS 1 +#define TTN_TEMPERATURE_SENSOR_ADDRESS 0x18 +#define TTN_TEMPERATURE_ALERT 14 +#define TTN_ACCELEROMETER_INT2 9 + +#define TTN_ADDR_ACC 0x1D +#define TTN_DR 5 // active data rate +#define TTN_SR 3 // sleep data rate +#define TTN_SC 4 // sleep delay +#define TTN_MT 4 // 0.063g/LSB +#define TTN_MDC 2 // debounce delay in samples +#define TTN_SYSMOD 0x0B +#define TTN_FF_MT_CFG 0x15 +#define TTN_FF_MT_SRC 0x16 +#define TTN_FF_MT_THS 0x17 +#define TTN_FF_MT_COUNT 0x18 +#define TTN_TRANSIENT_CFG 0x1D +#define TTN_TRANSIENT_SRC 0x1E +#define TTN_TRANSIENT_THS 0x1F +#define TTN_TRANSIENT_COUNT 0x20 +#define TTN_ASLP_CNT 0x29 +#define TTN_CTRL_REG1 0x2A +#define TTN_CTRL_REG2 0x2B +#define TTN_CTRL_REG3 0x2C +#define TTN_CTRL_REG4 0x2D +#define TTN_CTRL_REG5 0x2E + +#define TTN_WAKE_TEMPERATURE 0x0001 +#define TTN_WAKE_MOTION_START 0x0002 +#define TTN_WAKE_MOTION_STOP 0x0004 +#define TTN_WAKE_BTN_PRESS 0x0008 +#define TTN_WAKE_BTN_RELEASE 0x0010 +#define TTN_WAKE_LORA 0x0020 +#define TTN_WAKE_WATCHDOG 0x0040 +#define TTN_WAKE_INTERVAL 0x0080 + +#define TTN_WAKE_ANY ( TTN_WAKE_TEMPERATURE | \ + TTN_WAKE_MOTION_START | TTN_WAKE_MOTION_STOP | \ + TTN_WAKE_BTN_PRESS | TTN_WAKE_BTN_RELEASE | \ + TTN_WAKE_LORA | \ + TTN_WAKE_WATCHDOG ) + enum ttn_color : byte { TTN_RED, @@ -35,6 +87,8 @@ class TheThingsNode TheThingsNode(TheThingsNode const &); void operator=(TheThingsNode const &); + TheThingsNetwork *ttn; + bool intervalEnabled; uint32_t intervalMs; uint32_t intervalSince; @@ -52,7 +106,7 @@ class TheThingsNode bool USBDeepSleep; bool wdtStarted; - void (*wakeCallback)(void); + void (*wakeCallback)(uint8_t wakeStatus); void (*sleepCallback)(void); void (*temperatureCallback)(void); void (*motionStartCallback)(void); @@ -78,7 +132,7 @@ class TheThingsNode return &node; }; - void onWake(void (*callback)(void)); + void onWake(void (*callback)(uint8_t wakeStatus)); void loop(); void onSleep(void (*callback)(void)); @@ -87,6 +141,7 @@ class TheThingsNode void onInterval(void (*callback)(void)); void configInterval(bool enabled, uint32_t ms); void configInterval(bool enabled); + void configInterval(TheThingsNetwork *ttn, uint32_t ms); void configLight(bool enabled, uint8_t gain); void configLight(bool enabled); From 67f5969f1f827f56be4a798795bf957ae34e1567 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 20 Feb 2018 01:22:55 +0100 Subject: [PATCH 14/53] added option to wake by lora module removed #include definition (in .h now) Added wakeStatus bit field to wakeCallback to get what waked us Added pointer to TheThingsNetwork object to enable Lora module sleep/wake up Added IRQ for INT2 (Lora Serial Module) Added new configInterval method Optimized Light Sensor Changed deepSleep to support wake by lora module --- src/TheThingsNode.cpp | 216 +++++++++++++++++++++++++----------------- 1 file changed, 131 insertions(+), 85 deletions(-) diff --git a/src/TheThingsNode.cpp b/src/TheThingsNode.cpp index b1ce333..1617c56 100644 --- a/src/TheThingsNode.cpp +++ b/src/TheThingsNode.cpp @@ -4,67 +4,30 @@ #include #include -#define TTN_LDR_INPUT 10 -#define TTN_LDR_GAIN1 12 -#define TTN_LDR_GAIN2 4 -#define TTN_RED_LED 13 -#define TTN_GREEN_LED 5 -#define TTN_BLUE_LED 6 -#define TTN_BUTTON 16 -#define TTN_LORA_RESET 21 -#define TTN_VBAT_MEAS_EN A2 -#define TTN_VBAT_MEAS 1 -#define TTN_TEMPERATURE_SENSOR_ADDRESS 0x18 -#define TTN_TEMPERATURE_ALERT 14 -#define TTN_ACCELEROMETER_INT2 9 - -#define TTN_ADDR_ACC 0x1D -#define TTN_DR 5 // active data rate -#define TTN_SR 3 // sleep data rate -#define TTN_SC 4 // sleep delay -#define TTN_MT 4 // 0.063g/LSB -#define TTN_MDC 2 // debounce delay in samples -#define TTN_SYSMOD 0x0B -#define TTN_FF_MT_CFG 0x15 -#define TTN_FF_MT_SRC 0x16 -#define TTN_FF_MT_THS 0x17 -#define TTN_FF_MT_COUNT 0x18 -#define TTN_TRANSIENT_CFG 0x1D -#define TTN_TRANSIENT_SRC 0x1E -#define TTN_TRANSIENT_THS 0x1F -#define TTN_TRANSIENT_COUNT 0x20 -#define TTN_ASLP_CNT 0x29 -#define TTN_CTRL_REG1 0x2A -#define TTN_CTRL_REG2 0x2B -#define TTN_CTRL_REG3 0x2C -#define TTN_CTRL_REG4 0x2D -#define TTN_CTRL_REG5 0x2E - Hackscribble_MCP9804 TTN_TEMPERATURE_SENSOR(TTN_TEMPERATURE_SENSOR_ADDRESS); -volatile bool TTN_TEMPERATURE = false; -volatile bool TTN_MOTION_START = false; -volatile bool TTN_MOTION_STOP = false; -volatile bool TTN_BUTTON_PRESS = false; -volatile bool TTN_BUTTON_RELEASE = false; +volatile uint16_t wakeStatus; volatile uint32_t TTN_INTERVAL = 0; void TTN_TEMPERATURE_FN() { - TTN_TEMPERATURE = true; + wakeStatus |= TTN_WAKE_TEMPERATURE; TTN_TEMPERATURE_SENSOR.clearAlert(); } void TTN_MOTION_FN() { uint8_t trigger = getPinChangeInterruptTrigger(digitalPinToPCINT(TTN_ACCELEROMETER_INT2)); + // Reset according bits + wakeStatus &= ~ (TTN_WAKE_MOTION_START|TTN_WAKE_MOTION_STOP); + if (trigger == RISING) { - TTN_MOTION_START = true; + wakeStatus |= TTN_WAKE_MOTION_START; } else if (trigger == FALLING) { - TTN_MOTION_STOP = true; + wakeStatus |= TTN_WAKE_MOTION_STOP; } } @@ -73,18 +36,30 @@ void TTN_BUTTON_FN() uint8_t trigger = getPinChangeInterruptTrigger(digitalPinToPCINT(TTN_BUTTON)); if (trigger == FALLING) { - TTN_BUTTON_PRESS = true; + wakeStatus |= TTN_WAKE_BTN_PRESS; } // Be sure main loop ACK press button before rising the release - if (TTN_BUTTON_PRESS == false && trigger == RISING ) + if (trigger == RISING /*&& !(wakeStatus&TTN_WAKE_BTN_PRESS)*/) { - TTN_BUTTON_RELEASE = true; + wakeStatus |= TTN_WAKE_BTN_RELEASE; } } +void TTN_SERIAL_LORA_FN() +{ + if ( digitalRead(0) == 0 ) { + wakeStatus |= TTN_WAKE_LORA; + } + // Just used to wake up we can now + // mask this interrupt because serial + // will become verbose + EIMSK &= ~(1 << INT2); +} + ISR(WDT_vect) { + wakeStatus |= TTN_WAKE_WATCHDOG; TTN_INTERVAL = TTN_INTERVAL + 8000; } @@ -92,7 +67,7 @@ ISR(WDT_vect) * PUBLIC *****************************************************************************/ -void TheThingsNode::onWake(void (*callback)(void)) +void TheThingsNode::onWake(void (*callback)(uint8_t wakeStatus)) { this->wakeCallback = callback; } @@ -127,12 +102,16 @@ void TheThingsNode::loop() } } + if (TTN_INTERVAL >= this->intervalMs) { + wakeStatus |= TTN_WAKE_INTERVAL; + } + if (this->wakeCallback) { - this->wakeCallback(); + this->wakeCallback(wakeStatus); } - if (TTN_BUTTON_PRESS) + if (wakeStatus & TTN_WAKE_BTN_PRESS) { if (!this->buttonPressed) { @@ -143,10 +122,11 @@ void TheThingsNode::loop() } this->buttonPressed = true; } - TTN_BUTTON_PRESS = false; - } - - if (TTN_BUTTON_RELEASE) + // ACK our interrupt + wakeStatus &= ~TTN_WAKE_BTN_PRESS; + } + // At least one loop instance between press and release so else if here + else if (wakeStatus & TTN_WAKE_BTN_RELEASE) { if (this->buttonPressed) { @@ -156,10 +136,11 @@ void TheThingsNode::loop() } this->buttonPressed = false; } - TTN_BUTTON_RELEASE = false; + // ACK our interrupt + wakeStatus &= ~TTN_WAKE_BTN_RELEASE; } - if (TTN_MOTION_START) + if (wakeStatus & TTN_WAKE_MOTION_START) { if (!this->motionStarted) { @@ -170,10 +151,11 @@ void TheThingsNode::loop() } this->motionStarted = true; } - TTN_MOTION_START = false; + // ACK our interrupt + wakeStatus &= ~TTN_WAKE_MOTION_START; } - if (TTN_MOTION_STOP) + if (wakeStatus & TTN_WAKE_MOTION_STOP) { if (this->motionStarted) { @@ -183,49 +165,66 @@ void TheThingsNode::loop() } this->motionStarted = false; } - TTN_MOTION_STOP = false; + // ACK our interrupt + wakeStatus &= ~TTN_WAKE_MOTION_STOP; } - if (TTN_TEMPERATURE) + if (wakeStatus & TTN_WAKE_TEMPERATURE) { if (this->temperatureEnabled && this->temperatureCallback) { this->temperatureCallback(); } - TTN_TEMPERATURE = false; + // ACK our interrupt + wakeStatus &= ~TTN_WAKE_TEMPERATURE; } - if (TTN_INTERVAL >= this->intervalMs) + if (wakeStatus & TTN_WAKE_INTERVAL) { if (this->intervalEnabled && this->intervalCallback) { this->intervalCallback(); } + // Ack our watchdog and interval interrupt + wakeStatus &= ~(TTN_WAKE_WATCHDOG|TTN_WAKE_INTERVAL); TTN_INTERVAL = 0; } + if (wakeStatus & TTN_WAKE_LORA) + { + if (this->intervalEnabled && this->intervalCallback) + { + this->intervalCallback(); + } + // ACK our interrupt + wakeStatus &= ~TTN_WAKE_LORA; + } + if (this->sleepCallback) { this->sleepCallback(); } + // If button pushed manage loop faster + uint16_t dly = this->buttonPressed ? 10 : 100; + if (this->isUSBConnected() && !this->USBDeepSleep) { - while (!TTN_BUTTON_PRESS && !TTN_BUTTON_RELEASE && !TTN_MOTION_START && !TTN_MOTION_STOP && !TTN_TEMPERATURE && TTN_INTERVAL < this->intervalMs) + while (!(wakeStatus&TTN_WAKE_ANY) && TTN_INTERVAL < this->intervalMs) { - delay(100); - TTN_INTERVAL = TTN_INTERVAL + 100; + delay(dly); + TTN_INTERVAL = TTN_INTERVAL + dly; } } else { // Don't go to sleep mode while button is still pressed // because if so, timer of ms will be stopped and duration - // of pressed button will not work + // of pressed button will not work, this acting like a debounce if (this->buttonPressed) { - delay(100); - TTN_INTERVAL = TTN_INTERVAL + 100; + delay(dly); + TTN_INTERVAL = TTN_INTERVAL + dly; } else { Serial.flush(); deepSleep(); @@ -293,12 +292,19 @@ void TheThingsNode::showStatus() void TheThingsNode::configInterval(bool enabled, uint32_t ms) { this->intervalMs = ms; - configInterval(enabled); } +void TheThingsNode::configInterval(TheThingsNetwork *ttn, uint32_t ms) +{ + this->intervalMs = ms; + this->ttn = ttn; + this->intervalEnabled = true; +} + void TheThingsNode::configInterval(bool enabled) { + this->ttn = NULL; this->intervalEnabled = enabled; } @@ -327,7 +333,23 @@ void TheThingsNode::configLight(bool enabled) return; } - if (enabled) + // Ok be sure to set it to low power mode + if (!enabled) + { + digitalWrite(TTN_LDR_GAIN1, LOW); + digitalWrite(TTN_LDR_GAIN2, LOW); + // Just to be sure, see datasheet, at least 1.5ms to enable Low Power + delay(2); + } + + this->lightEnabled = enabled; +} + +uint16_t TheThingsNode::getLight() +{ + uint16_t value = 0; + + if ( this->lightEnabled) { switch (this->lightGain) { @@ -348,21 +370,20 @@ void TheThingsNode::configLight(bool enabled) digitalWrite(TTN_LDR_GAIN2, HIGH); break; } - } - else - { + // Wait to settle + delay(1); + + // Read value + value = analogRead(TTN_LDR_INPUT); + + // Go back to sleep mode digitalWrite(TTN_LDR_GAIN1, LOW); digitalWrite(TTN_LDR_GAIN2, LOW); + // Just to be sure, see datasheet, at least 1.5ms to enable Low Power + delay(2); } - this->lightEnabled = enabled; -} - -uint16_t TheThingsNode::getLight() -{ - // TODO: if (this->lightEnabled) - - return analogRead(TTN_LDR_INPUT); + return value; } /****************************************************************************** @@ -748,13 +769,13 @@ TheThingsNode::TheThingsNode() pinMode(TTN_BLUE_LED, OUTPUT); setColor(TTN_BLACK); - // hardware reset of LoRa module, so module is reset on sketch upload - #ifdef TTN_LORA_RESET + // reset RN2483 module, this allow to reset module on sketch upload also +#ifdef TTN_LORA_RESET pinMode(TTN_LORA_RESET, OUTPUT); digitalWrite(TTN_LORA_RESET, LOW); delay(100); digitalWrite(TTN_LORA_RESET, HIGH); - #endif +#endif // TODO: Can we enable/disable this at will to save memory? @@ -864,7 +885,7 @@ void TheThingsNode::WDT_start() cli(); MCUSR &= ~(1 << WDRF); WDTCSR |= (1 << WDCE) | (1 << WDE); - WDTCSR = 1 << WDP0 | 0 << WDP1 | 0 << WDP2 | 1 << WDP3; /* 2.0 seconds */ + WDTCSR = 1 << WDP0 | 0 << WDP1 | 0 << WDP2 | 1 << WDP3; /* 8.0 seconds */ WDTCSR |= _BV(WDIE); sei(); @@ -890,6 +911,31 @@ void TheThingsNode::WDT_stop() void TheThingsNode::deepSleep(void) { + // We want to be awake by LoRa module ? + if (this->ttn) { + // watchdog Not needed, avoid wake every 8S + WDT_stop(); + + // Set LoRa module sleep mode + // ttn.sleep( CONFIG_INTERVAL*1000 ); + this->ttn->sleep(this->intervalMs); + // This one is not optionnal, remove it + // and say bye bye to RN2483 or RN2903 sleep mode + delay(50); + + // Module need to wake us with interrupt + attachInterrupt(TTN_LORA_SERIAL_RX_INT, TTN_SERIAL_LORA_FN, FALLING); + + // switch all interrupts off while messing with their settings + cli(); + bitSet(EIFR,INTF2); // clear any pending interrupts for serial RX pin (INT2 D0) + sei(); + + } else { + // watchdog needed for wakeup + WDT_start(); + } + ADCSRA &= ~_BV(ADEN); set_sleep_mode(SLEEP_MODE_PWR_DOWN); MCUCR |= (1 << JTD); From 0f7bcab313f7336a04fa01ff556d90269e10cec9 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 20 Feb 2018 01:23:09 +0100 Subject: [PATCH 15/53] Fix Lora Module Sleep --- examples/CayenneLPP/CayenneLPP.ino | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/CayenneLPP/CayenneLPP.ino b/examples/CayenneLPP/CayenneLPP.ino index 6922b0d..92241f6 100644 --- a/examples/CayenneLPP/CayenneLPP.ino +++ b/examples/CayenneLPP/CayenneLPP.ino @@ -118,7 +118,11 @@ void sendData(uint8_t port) ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); // Set RN2483 to sleep mode - ttn.sleep( 60000 ); + ttn.sleep(60000); + + // This one is not optionnal, remove it + // and say bye bye to RN2483 or RN2903 sleep mode + delay(50); } void printSensors() From e599abbafb300ce00992783133c1c79999edf032 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 20 Feb 2018 03:02:28 +0100 Subject: [PATCH 16/53] Fix IRQ problem on Serial Wake not detected --- src/TheThingsNode.cpp | 19 ++++++++----------- src/TheThingsNode.h | 2 +- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/TheThingsNode.cpp b/src/TheThingsNode.cpp index 1617c56..d4627c9 100644 --- a/src/TheThingsNode.cpp +++ b/src/TheThingsNode.cpp @@ -48,12 +48,9 @@ void TTN_BUTTON_FN() void TTN_SERIAL_LORA_FN() { - if ( digitalRead(0) == 0 ) { - wakeStatus |= TTN_WAKE_LORA; - } - // Just used to wake up we can now - // mask this interrupt because serial - // will become verbose + // Just used to wake up we can now mask this + // interrupt because serial will become verbose + wakeStatus |= TTN_WAKE_LORA; EIMSK &= ~(1 << INT2); } @@ -192,7 +189,7 @@ void TheThingsNode::loop() if (wakeStatus & TTN_WAKE_LORA) { - if (this->intervalEnabled && this->intervalCallback) + if (this->pttn && this->intervalCallback) { this->intervalCallback(); } @@ -298,13 +295,13 @@ void TheThingsNode::configInterval(bool enabled, uint32_t ms) void TheThingsNode::configInterval(TheThingsNetwork *ttn, uint32_t ms) { this->intervalMs = ms; - this->ttn = ttn; + this->pttn = ttn; this->intervalEnabled = true; } void TheThingsNode::configInterval(bool enabled) { - this->ttn = NULL; + this->pttn = NULL; this->intervalEnabled = enabled; } @@ -912,13 +909,13 @@ void TheThingsNode::WDT_stop() void TheThingsNode::deepSleep(void) { // We want to be awake by LoRa module ? - if (this->ttn) { + if (this->pttn) { // watchdog Not needed, avoid wake every 8S WDT_stop(); // Set LoRa module sleep mode // ttn.sleep( CONFIG_INTERVAL*1000 ); - this->ttn->sleep(this->intervalMs); + this->pttn->sleep(this->intervalMs); // This one is not optionnal, remove it // and say bye bye to RN2483 or RN2903 sleep mode delay(50); diff --git a/src/TheThingsNode.h b/src/TheThingsNode.h index 4fd3467..39550e9 100644 --- a/src/TheThingsNode.h +++ b/src/TheThingsNode.h @@ -87,7 +87,7 @@ class TheThingsNode TheThingsNode(TheThingsNode const &); void operator=(TheThingsNode const &); - TheThingsNetwork *ttn; + TheThingsNetwork *pttn; bool intervalEnabled; uint32_t intervalMs; From c0941a14f60a6c7f2ff30af3f5bf2a29d8e50da8 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 20 Feb 2018 03:12:04 +0100 Subject: [PATCH 17/53] Added new sleep mode with LoRa module --- docs/TheThingsNode.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/TheThingsNode.md b/docs/TheThingsNode.md index 7fd8b47..addbdf5 100644 --- a/docs/TheThingsNode.md +++ b/docs/TheThingsNode.md @@ -116,12 +116,14 @@ void onInterval(void(*callback)(void)); ```c void configInterval(bool enabled, uint32_t ms); void configInterval(bool enabled); +void configInterval(TheThingsNetwork *pttn, uint32_t ms); ``` - `bool enabled`: Enable or disable the interval callback. Enabled automatically by `onInterval()`, but you can use this method to temporarily disable it. Defaults to `false`. +- `TheThingsNetwork * pttn`: This enable the interval callback but in this mode, the interval is passed to RN2483 or RN2903 module (this is why we need to pass pointer to object) with `sys sleep` command and then it's the LoRa module that wake up the node. - `uint32_t ms`: Minimal time between calling the interval callback. Defaults to `60000` or 60 seconds. -> If the Node has no USB data connection or is configured to also sleep in that case, it will only wake up every 8 seconds to check if the interval callback should run. This means setting `ms` to less than `8000` makes no sense. It also means that the maximum time between calls can be up to 8 seconds longer than `ms` if it wakes up to handle button or sensor interaction in between. +> If the Node has no USB data connection or is configured to also sleep in that case, it will only wake up every 8 seconds to check if the interval callback should run. This means setting `ms` to less than `8000` makes no sense. It also means that the maximum time between calls can be up to 8 seconds longer than `ms` if it wakes up to handle button or sensor interaction in between. This does not apply when wake up by LoRa module. ## Method: showStatus Writes information about the device and sensors to `Serial`. From a3a83ca9f1ca6aae6d81ad140cd5abe7a6f54aa0 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 20 Feb 2018 03:12:14 +0100 Subject: [PATCH 18/53] cosmetic --- src/TheThingsNode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TheThingsNode.h b/src/TheThingsNode.h index 39550e9..2486696 100644 --- a/src/TheThingsNode.h +++ b/src/TheThingsNode.h @@ -141,7 +141,7 @@ class TheThingsNode void onInterval(void (*callback)(void)); void configInterval(bool enabled, uint32_t ms); void configInterval(bool enabled); - void configInterval(TheThingsNetwork *ttn, uint32_t ms); + void configInterval(TheThingsNetwork *pttn, uint32_t ms); void configLight(bool enabled, uint8_t gain); void configLight(bool enabled); From 1a56e3bf0d116f72c269c491088543052b76b8a1 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 20 Feb 2018 03:14:29 +0100 Subject: [PATCH 19/53] Updated to new Ultra Low Power Sleep Mode (with LoRa module wake) --- .../BatteryMonitorLPP/BatteryMonitorLPP.ino | 118 +++++++++++++----- 1 file changed, 89 insertions(+), 29 deletions(-) diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino index 13acef4..67e7f78 100644 --- a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -12,17 +12,17 @@ const char *appKey = "00000000000000000000000000000000"; #define loraSerial Serial1 #define debugSerial Serial -TheThingsNetwork ttn(loraSerial, debugSerial, freqPlan); -TheThingsNode *node; -CayenneLPP lpp(16); - #define PORT_SETUP 1 #define PORT_INTERVAL 2 #define PORT_MOTION 3 #define PORT_BUTTON 4 +TheThingsNetwork ttn(loraSerial, debugSerial, freqPlan); +TheThingsNode *node; +CayenneLPP lpp(16); + // Interval between send in seconds, so 300s = 5min -#define CONFIG_INTERVAL ((uint32_t) 300) +#define CONFIG_INTERVAL ((uint32_t)300) void sendData(uint8_t port=PORT_SETUP, uint32_t duration=0); @@ -38,15 +38,63 @@ void interval() // This is called on each wake, every 8S or by an sensor/button interrupt // if it's watchdog, we mainly do nothing (core IRQ, we don't have choice) // but if it's an interupt it will ne bone ine loop -void wake() +void wake(uint8_t wakeReason) { - debugSerial.println(F("-- WAKE")); + debugSerial.print(F("-- WAKE 0x")); + debugSerial.print(wakeReason, HEX); + uint8_t ledcolor = TTN_BLACK; + uint8_t ledblink = 0 ; + + if (wakeReason&(TTN_WAKE_WATCHDOG|TTN_WAKE_INTERVAL)) { + ledcolor = TTN_YELLOW; + ledblink = 1; + if (wakeReason&TTN_WAKE_WATCHDOG) { + debugSerial.print(F(" Watchdog")); + } + if (wakeReason&TTN_WAKE_INTERVAL) { + debugSerial.print(F(" INTERVAL")); + ledblink++; + } + } + + if (wakeReason&TTN_WAKE_LORA) { + debugSerial.print(F(" LoRa")); + ledblink = 1; + ledcolor = TTN_GREEN; + } + + if (wakeReason&TTN_WAKE_BTN_PRESS) { + debugSerial.print(F(" PRESS")); + } + + if (wakeReason&TTN_WAKE_BTN_RELEASE) { + debugSerial.print(F(" RELEASE")); + } + + if (wakeReason&TTN_WAKE_MOTION_START) { + ledblink = 1; + ledcolor = TTN_RED; + debugSerial.print(F(" MOTION_START")); + } + if (wakeReason&TTN_WAKE_MOTION_STOP) { + ledblink = 2; + ledcolor = TTN_RED; + debugSerial.print(F(" MOTION_STOP")); + } + + if (wakeReason&TTN_WAKE_TEMPERATURE) { + debugSerial.print(F(" TEMPERATURE")); + } + + debugSerial.println(); // Just if you want to see this IRQ with a LED, remove for LOW power - //node->setColor(TTN_GREEN); - //delay(50); - //node->setColor(TTN_BLACK); - //delay(100); + while (ledblink--) { + node->setColor(ledcolor); + delay(50); + node->setColor(TTN_BLACK); + delay(333); + } } void sleep() @@ -94,20 +142,13 @@ void sendData(uint8_t port, uint32_t value) // please myDeviceCayenne add counter value type to // avoid us using analog values to send counters if (port == PORT_BUTTON) { - debugSerial.print(F("Button:\t")); - debugSerial.print(value); - debugSerial.println(F("ms")); - lpp.addAnalogInput(7, value/1000.0); + debugSerial.print(F("Button:\t")); + debugSerial.print(value); + debugSerial.println(F("ms")); + lpp.addAnalogInput(7, value/1000.0); } ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); - - // Set RN2483 to sleep mode - ttn.sleep( CONFIG_INTERVAL*1000 ); - - // This one is not optionnal, remove it - // and say bye bye to RN2983 sleep mode - delay(50); } void setup() @@ -115,17 +156,20 @@ void setup() loraSerial.begin(57600); debugSerial.begin(9600); - // Wait a maximum of 10s for Serial Monitor - while (!debugSerial && millis() < 10000) - ; + // Wait a maximum of 5s for Serial Monitor + while (!debugSerial && millis() < 5000) { + node->setColor(TTN_RED); + delay(20); + node->setColor(TTN_BLACK); + delay(480); + }; // Config Node, Disable all sensors // Check node schematics here // https://github.com/TheThingsProducts/node node = TheThingsNode::setup(); - // Each interval - node->configInterval(true, CONFIG_INTERVAL*1000); + node->onWake(wake); node->onInterval(interval); node->onSleep(sleep); @@ -135,16 +179,32 @@ void setup() // Test sensors and set LED to GREEN if it works node->showStatus(); - node->setColor(TTN_GREEN); debugSerial.println(F("-- TTN: STATUS")); ttn.showStatus(); + // Each interval (with watchdog) + //node->configInterval(true, CONFIG_INTERVAL*1000); + + // Each interval (with Lora Module and Serial IRQ) + // Take care this one need to be called after any + // first call to ttn.* so object has been instancied + // if not &ttn will be null and watchdog + node->configInterval(&ttn, CONFIG_INTERVAL*1000); + debugSerial.println(F("-- TTN: JOIN")); - ttn.join(appEui, appKey); + node->setColor(TTN_MAGENTA); + if (ttn.join(appEui, appKey)) { + node->setColor(TTN_GREEN); + } else { + node->setColor(TTN_RED); + } debugSerial.println(F("-- SEND: SETUP")); sendData(PORT_SETUP); + + // Enable USB deepsleep + //node->configUSB(true); } void loop() From d650ce8c7ee7fd52ce46c66ffa0bb8b6ae394121 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 20 Feb 2018 03:20:20 +0100 Subject: [PATCH 20/53] Detailled Low Power Mode --- docs/TheThingsNode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/TheThingsNode.md b/docs/TheThingsNode.md index addbdf5..d49e395 100644 --- a/docs/TheThingsNode.md +++ b/docs/TheThingsNode.md @@ -120,7 +120,7 @@ void configInterval(TheThingsNetwork *pttn, uint32_t ms); ``` - `bool enabled`: Enable or disable the interval callback. Enabled automatically by `onInterval()`, but you can use this method to temporarily disable it. Defaults to `false`. -- `TheThingsNetwork * pttn`: This enable the interval callback but in this mode, the interval is passed to RN2483 or RN2903 module (this is why we need to pass pointer to object) with `sys sleep` command and then it's the LoRa module that wake up the node. +- `TheThingsNetwork * pttn`: This enable the interval callback but in this mode, the interval is passed to RN2483 or RN2903 module (this is why we need to pass pointer to object) with the command `sys sleep ms` and then it's the LoRa module that wake up the node. This is the most advanced Low Power Mode. In this mode, the watchdog is disabled and consuption again reduced. - `uint32_t ms`: Minimal time between calling the interval callback. Defaults to `60000` or 60 seconds. > If the Node has no USB data connection or is configured to also sleep in that case, it will only wake up every 8 seconds to check if the interval callback should run. This means setting `ms` to less than `8000` makes no sense. It also means that the maximum time between calls can be up to 8 seconds longer than `ms` if it wakes up to handle button or sensor interaction in between. This does not apply when wake up by LoRa module. From e58ab86d4d87991b17470417092070acc4aac783 Mon Sep 17 00:00:00 2001 From: Charles Date: Wed, 21 Feb 2018 19:13:54 +0100 Subject: [PATCH 21/53] Added getVCC() using with ADC Low Noise Feature --- src/TheThingsNode.cpp | 112 +++++++++++++++++++++++++++++++++++++++++- src/TheThingsNode.h | 2 + 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/src/TheThingsNode.cpp b/src/TheThingsNode.cpp index 36fc383..6945c16 100644 --- a/src/TheThingsNode.cpp +++ b/src/TheThingsNode.cpp @@ -8,6 +8,7 @@ Hackscribble_MCP9804 TTN_TEMPERATURE_SENSOR(TTN_TEMPERATURE_SENSOR_ADDRESS); volatile uint16_t wakeStatus; volatile uint32_t TTN_INTERVAL = 0; +volatile uint8_t adcIRQCnt; void TTN_TEMPERATURE_FN() { @@ -60,6 +61,15 @@ ISR(WDT_vect) TTN_INTERVAL = TTN_INTERVAL + 8000; } +ISR(ADC_vect) +{ + // Increment ADC counter + adcIRQCnt++; +} + + + + /****************************************************************************** * PUBLIC *****************************************************************************/ @@ -710,6 +720,102 @@ void TheThingsNode::setColor(ttn_color color) /****************************************************************************** * BATTERY */ +uint16_t TheThingsNode::readADCLowNoise(bool average) +{ + uint8_t low, high; + uint16_t sum = 0; + + // Start 1st Conversion, but ignore it, can be hazardous + ADCSRA |= _BV(ADSC); + + // wait for first dummy conversion + while (bit_is_set(ADCSRA,ADSC)); + + // Init our measure counter + adcIRQCnt = 0; + + // We want to have a interrupt when the conversion is done + ADCSRA |= _BV( ADIE ); + + // Loop thru samples + // 8 samples (we don't take the 1st one) + do { + // Enable Noise Reduction Sleep Mode + set_sleep_mode( SLEEP_MODE_ADC ); + sleep_enable(); + + // Wait until conversion is finished + do { + // enabled IRQ before sleeping + sei(); + sleep_cpu(); + cli(); + } + // Check is done with interrupts disabled to avoid a race condition + while (bit_is_set(ADCSRA,ADSC)); + + // No more sleeping + sleep_disable(); + sei(); + + // read low first + low = ADCL; + high = ADCH; + + // Sum the total + sum += ((high << 8) | low); + } + while (adcIRQCnt<8); + + // No more interrupts needed for this + // we finished the job + ADCSRA &= ~ _BV( ADIE ); + + // Return the average divided by 8 (8 samples) + return ( average ? sum >> 3 : sum ); +} + +/* ====================================================================== +Function: getVcc +Purpose : Read and Calculate V powered, the Voltage on Arduino VCC pin +Input : - +Output : value readed +Comments: ADC Channel input is modified +====================================================================== */ +uint16_t TheThingsNode::getVcc() +{ + uint16_t value; + uint16_t vcc; + + // Enable ADC (just in case going out of low power) + power_adc_enable(); + ADCSRA |= _BV(ADEN) ; + + // Read 1.1V reference against AVcc + // REFS1 REFS0 --> 0 1, AVcc internal ref. -Selects AVcc external reference + // MUX4 MUX3 MUX2 MUX1 MUX0 --> 011110 1.1V (VBG) -Selects channel 14, bandgap voltage, to measure + ADMUX = (0< 5500 ) vcc = 5500 ; + + // Vcc in millivolts + return ( vcc ); +} + uint16_t TheThingsNode::getBattery() { @@ -720,6 +826,10 @@ uint16_t TheThingsNode::getBattery() return batteryVoltage; } + + + + /****************************************************************************** * USB */ @@ -949,4 +1059,4 @@ void TheThingsNode::deepSleep(void) //USBCON |= (1 << USBE); USBCON &= ~_BV(FRZCLK); ADCSRA |= (1 << ADEN); -} \ No newline at end of file +} diff --git a/src/TheThingsNode.h b/src/TheThingsNode.h index 2486696..d828800 100644 --- a/src/TheThingsNode.h +++ b/src/TheThingsNode.h @@ -181,6 +181,8 @@ class TheThingsNode void configUSB(bool deepSleep); uint16_t getBattery(); + uint16_t readADCLowNoise(bool average); + uint16_t getVcc(); }; #endif From 348990c132cb8f0ffec818ebb6b88c4b1829bbb6 Mon Sep 17 00:00:00 2001 From: Charles Date: Wed, 21 Feb 2018 19:18:38 +0100 Subject: [PATCH 22/53] Get VCC of ATMega with getVCC() --- .../BatteryMonitorLPP/BatteryMonitorLPP.ino | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino index 1ed7e6b..67a5d8e 100644 --- a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -90,12 +90,15 @@ void wake(uint8_t wakeReason) debugSerial.println(); // Just if you want to see this IRQ with a LED, remove for LOW power + /* while (ledblink--) { node->setColor(ledcolor); delay(50); node->setColor(TTN_BLACK); delay(333); } + */ + } void sleep() @@ -131,10 +134,26 @@ void sendData(uint8_t port, uint32_t value) // Read battery voltage uint16_t vbat = node->getBattery(); - debugSerial.print(F("Battery:\t")); + debugSerial.print(F("Bat: ")); debugSerial.print(vbat); debugSerial.println(F("mV")); + // This one is usefull when battery < 2.5V below reference ADC 2.52V + // because in this case reading are wrong, but you can use it + // as soon as VCC < 3.3V, + // when above 3.3V; since regulator fix 3.3V you should read 3300mV + uint16_t vcc = node->getVcc(); + debugSerial.print(F("Vcc: ")); + debugSerial.print(vcc); + debugSerial.println(F("mV")); + +/* + uint16_t vrn = ttn.getVDD(); + debugSerial.print(F("VRN: ")); + debugSerial.print(vrn); + debugSerial.println(F("mV")); + */ + // Just send battery voltage lpp.reset(); lpp.addAnalogInput(4, vbat/1000.0); From bda7d59ed1e74ab3d262b25f52fa7169091dbb20 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 22 Feb 2018 12:56:51 +0100 Subject: [PATCH 23/53] Fixed button release bug --- src/TheThingsNode.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/TheThingsNode.cpp b/src/TheThingsNode.cpp index 6945c16..033ba85 100644 --- a/src/TheThingsNode.cpp +++ b/src/TheThingsNode.cpp @@ -41,7 +41,7 @@ void TTN_BUTTON_FN() } // Be sure main loop ACK press button before rising the release - if (trigger == RISING /*&& !(wakeStatus&TTN_WAKE_BTN_PRESS)*/) + if (trigger == RISING && !(wakeStatus&TTN_WAKE_BTN_PRESS)) { wakeStatus |= TTN_WAKE_BTN_RELEASE; } @@ -129,7 +129,6 @@ void TheThingsNode::loop() } this->buttonPressed = true; } - // ACK our interrupt wakeStatus &= ~TTN_WAKE_BTN_PRESS; } // At least one loop instance between press and release so else if here @@ -143,7 +142,6 @@ void TheThingsNode::loop() } this->buttonPressed = false; } - // ACK our interrupt wakeStatus &= ~TTN_WAKE_BTN_RELEASE; } @@ -238,6 +236,8 @@ void TheThingsNode::loop() deepSleep(); } } + + } void TheThingsNode::onSleep(void (*callback)(void)) From b9200a356a14f8e92c54ec4e505489be4f7872cc Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 22 Feb 2018 13:10:33 +0100 Subject: [PATCH 24/53] send all VDD/VCC/VRN values --- .../BatteryMonitorLPP/BatteryMonitorLPP.ino | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino index 67a5d8e..3770a92 100644 --- a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -19,7 +19,7 @@ const char *appKey = "00000000000000000000000000000000"; TheThingsNetwork ttn(loraSerial, debugSerial, freqPlan); TheThingsNode *node; -CayenneLPP lpp(16); +CayenneLPP lpp(24); // Interval between send in seconds, so 300s = 5min #define CONFIG_INTERVAL ((uint32_t)300) @@ -90,15 +90,14 @@ void wake(uint8_t wakeReason) debugSerial.println(); // Just if you want to see this IRQ with a LED, remove for LOW power - /* +/* while (ledblink--) { node->setColor(ledcolor); delay(50); node->setColor(TTN_BLACK); delay(333); } - */ - +*/ } void sleep() @@ -134,29 +133,29 @@ void sendData(uint8_t port, uint32_t value) // Read battery voltage uint16_t vbat = node->getBattery(); - debugSerial.print(F("Bat: ")); + debugSerial.print(F("Bat:\t")); debugSerial.print(vbat); debugSerial.println(F("mV")); // This one is usefull when battery < 2.5V below reference ADC 2.52V // because in this case reading are wrong, but you can use it // as soon as VCC < 3.3V, - // when above 3.3V; since regulator fix 3.3V you should read 3300mV + // when above 3.3V, since regulator fix 3.3V you should read 3300mV uint16_t vcc = node->getVcc(); - debugSerial.print(F("Vcc: ")); + debugSerial.print(F("Vcc:\t")); debugSerial.print(vcc); debugSerial.println(F("mV")); -/* uint16_t vrn = ttn.getVDD(); - debugSerial.print(F("VRN: ")); + debugSerial.print(F("VRN:\t")); debugSerial.print(vrn); debugSerial.println(F("mV")); - */ // Just send battery voltage lpp.reset(); lpp.addAnalogInput(4, vbat/1000.0); + lpp.addAnalogInput(5, vcc/1000.0); + lpp.addAnalogInput(6, vrn/1000.0); // If button pressed, send press duration // please myDeviceCayenne add counter value type to From a005ef8f702a8c80c9b0137167f534567d57ae76 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 22 Feb 2018 17:56:47 +0100 Subject: [PATCH 25/53] Added The Thing Network Library 2.5.7 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d1f465c..930c7a4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ before_install: - sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino install: - ln -s $PWD /usr/local/share/arduino/libraries/TheThingsNode - - arduino --install-library "DHT sensor library:1.3.0,Adafruit Unified Sensor:1.0.2,TheThingsNetwork:2.5.6" + - arduino --install-library "DHT sensor library:1.3.0,Adafruit Unified Sensor:1.0.2,TheThingsNetwork:2.5.7" - git clone https://github.com/sparkfun/arduino_boards /tmp/sparkfun - mv /tmp/sparkfun/sparkfun /usr/local/share/arduino/hardware/sparkfun before_script: From 72108dbb9fd2ebe9cc58e87f5c4b303dec67081e Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 22 Feb 2018 19:29:11 +0100 Subject: [PATCH 26/53] use of sprintf_p and some cosmetics --- .../BatteryMonitorLPP/BatteryMonitorLPP.ino | 89 +++++++++---------- 1 file changed, 42 insertions(+), 47 deletions(-) diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino index 3770a92..3ac5f7d 100644 --- a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -17,16 +17,16 @@ const char *appKey = "00000000000000000000000000000000"; #define PORT_MOTION 3 #define PORT_BUTTON 4 +// Interval between send in seconds, so 300s = 5min +#define CONFIG_INTERVAL ((uint32_t)300) + TheThingsNetwork ttn(loraSerial, debugSerial, freqPlan); TheThingsNode *node; CayenneLPP lpp(24); - -// Interval between send in seconds, so 300s = 5min -#define CONFIG_INTERVAL ((uint32_t)300) +char buf[24]; // For printf void sendData(uint8_t port=PORT_SETUP, uint32_t duration=0); - // This is called on each interval we defined so mainly // this is where we need to do our job void interval() @@ -41,11 +41,12 @@ void interval() // but if it's an interupt it will ne bone ine loop void wake(uint8_t wakeReason) { - debugSerial.print(F("-- WAKE 0x")); - debugSerial.print(wakeReason, HEX); uint8_t ledcolor = TTN_BLACK; uint8_t ledblink = 0 ; + snprintf_P(buf, sizeof(buf), PSTR("-- WAKE 0x%02X"), wakeReason); + debugSerial.println(buf); + if (wakeReason&(TTN_WAKE_WATCHDOG|TTN_WAKE_INTERVAL)) { ledcolor = TTN_YELLOW; ledblink = 1; @@ -57,21 +58,17 @@ void wake(uint8_t wakeReason) ledblink++; } } - if (wakeReason&TTN_WAKE_LORA) { - debugSerial.print(F(" LoRa")); + debugSerial.print(F(" LoRa RNxxxx")); ledblink = 1; ledcolor = TTN_GREEN; } - if (wakeReason&TTN_WAKE_BTN_PRESS) { debugSerial.print(F(" PRESS")); } - if (wakeReason&TTN_WAKE_BTN_RELEASE) { debugSerial.print(F(" RELEASE")); } - if (wakeReason&TTN_WAKE_MOTION_START) { ledblink = 1; ledcolor = TTN_RED; @@ -82,22 +79,21 @@ void wake(uint8_t wakeReason) ledcolor = TTN_RED; debugSerial.print(F(" MOTION_STOP")); } - if (wakeReason&TTN_WAKE_TEMPERATURE) { debugSerial.print(F(" TEMPERATURE")); } debugSerial.println(); - // Just if you want to see this IRQ with a LED, remove for LOW power -/* - while (ledblink--) { - node->setColor(ledcolor); - delay(50); - node->setColor(TTN_BLACK); - delay(333); - } -*/ + // Just if you want to see this IRQ with a LED + // just uncomment, but take care, not LOW power + //while (ledblink--) { + // node->setColor(ledcolor); + // delay(50); + // node->setColor(TTN_BLACK); + // delay(333); + //} + } void sleep() @@ -118,55 +114,53 @@ void onButtonRelease(unsigned long duration) node->setColor(TTN_BLUE); - debugSerial.print(F("-- SEND: BUTTON ")); - debugSerial.print(timepressed); - debugSerial.println(F(" ms")); + sprintf_P(buf, PSTR("-- SEND: BUTTON %d ms"), timepressed); + debugSerial.println(buf); sendData(PORT_BUTTON, timepressed); } void sendData(uint8_t port, uint32_t value) { + uint16_t volt; + // Wake RN2483 ttn.wake(); - // Read battery voltage - uint16_t vbat = node->getBattery(); + // Prepare cayenne payload + lpp.reset(); - debugSerial.print(F("Bat:\t")); - debugSerial.print(vbat); - debugSerial.println(F("mV")); + // Read battery voltage + volt = node->getBattery(); + sprintf_P(buf, PSTR("Bat:\t %dmV"), volt); + debugSerial.println(buf); + lpp.addAnalogInput(4, volt/1000.0); // This one is usefull when battery < 2.5V below reference ADC 2.52V // because in this case reading are wrong, but you can use it // as soon as VCC < 3.3V, // when above 3.3V, since regulator fix 3.3V you should read 3300mV - uint16_t vcc = node->getVcc(); - debugSerial.print(F("Vcc:\t")); - debugSerial.print(vcc); - debugSerial.println(F("mV")); + volt = node->getVcc(); + sprintf_P(buf, PSTR("Vcc:\t %dmV"), volt); + debugSerial.println(buf); + lpp.addAnalogInput(5, volt/1000.0); - uint16_t vrn = ttn.getVDD(); - debugSerial.print(F("VRN:\t")); - debugSerial.print(vrn); - debugSerial.println(F("mV")); - - // Just send battery voltage - lpp.reset(); - lpp.addAnalogInput(4, vbat/1000.0); - lpp.addAnalogInput(5, vcc/1000.0); - lpp.addAnalogInput(6, vrn/1000.0); + // Read value returned by RN2483 module + volt = ttn.getVDD(); + sprintf_P(buf, PSTR("Vrn:\t %dmV"), volt); + debugSerial.println(buf); + lpp.addAnalogInput(6, volt/1000.0); // If button pressed, send press duration // please myDeviceCayenne add counter value type to // avoid us using analog values to send counters if (port == PORT_BUTTON) { - debugSerial.print(F("Button:\t")); - debugSerial.print(value); - debugSerial.println(F("ms")); + sprintf_P(buf, PSTR("Btn:\t %dms"), value); + debugSerial.println(buf); lpp.addAnalogInput(7, value/1000.0); } + // Send data ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); } @@ -207,9 +201,10 @@ void setup() // Each interval (with Lora Module and Serial IRQ) // Take care this one need to be called after any // first call to ttn.* so object has been instancied - // if not &ttn will be null and watchdog + // if not &ttn will be null and watchdog will wake us node->configInterval(&ttn, CONFIG_INTERVAL*1000); + // Magenta during join, is joined then green else red debugSerial.println(F("-- TTN: JOIN")); node->setColor(TTN_MAGENTA); if (ttn.join(appEui, appKey)) { From ef70b2733dd5b8ec856c5073663342b60474b3dc Mon Sep 17 00:00:00 2001 From: Charles Date: Sat, 24 Feb 2018 18:18:47 +0100 Subject: [PATCH 27/53] Disable USB Regulator on deep sleeep --- src/TheThingsNode.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/TheThingsNode.cpp b/src/TheThingsNode.cpp index 033ba85..ff33413 100644 --- a/src/TheThingsNode.cpp +++ b/src/TheThingsNode.cpp @@ -1049,6 +1049,7 @@ void TheThingsNode::deepSleep(void) USBCON |= (1 << FRZCLK); //USBCON &= ~_BV(USBE); PLLCSR &= ~_BV(PLLE); + UHWCON &= ~_BV(UVREGE); // Disable USB Regulator sleep_enable(); sleep_mode(); //Sweet dreams! @@ -1056,6 +1057,7 @@ void TheThingsNode::deepSleep(void) sleep_disable(); PLLCSR |= (1 << PLLE); power_all_enable(); + UHWCON |= (1< Date: Mon, 26 Feb 2018 01:35:45 +0100 Subject: [PATCH 28/53] Added Ultra Low Power mode --- examples/CayenneLPP/CayenneLPP.ino | 33 +++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/examples/CayenneLPP/CayenneLPP.ino b/examples/CayenneLPP/CayenneLPP.ino index 92241f6..44a2db1 100644 --- a/examples/CayenneLPP/CayenneLPP.ino +++ b/examples/CayenneLPP/CayenneLPP.ino @@ -20,6 +20,9 @@ CayenneLPP lpp(51); #define PORT_MOTION 3 #define PORT_BUTTON 4 +// Interval between send in seconds, so 300s = 5min +#define CONFIG_INTERVAL ((uint32_t)300) + void setup() { loraSerial.begin(57600); @@ -40,15 +43,29 @@ void setup() node->onMotionStart(onMotionStart); node->onButtonRelease(onButtonRelease); - // Test sensors and set LED to GREEN if it works + // Test sensors node->showStatus(); - node->setColor(TTN_GREEN); debugSerial.println("-- TTN: STATUS"); ttn.showStatus(); - debugSerial.println("-- TTN: JOIN"); - ttn.join(appEui, appKey); + // Each interval (with watchdog) + //node->configInterval(true, CONFIG_INTERVAL*1000); + + // Each interval (with Lora Module and Serial IRQ) + // Take care this one need to be called after any + // first call to ttn.* so object has been instancied + // if not &ttn will be null and watchdog will wake us + node->configInterval(&ttn, CONFIG_INTERVAL*1000); + + // Magenta during join, if joined then green else red + debugSerial.println(F("-- TTN: JOIN")); + node->setColor(TTN_MAGENTA); + if (ttn.join(appEui, appKey)) { + node->setColor(TTN_GREEN); + } else { + node->setColor(TTN_RED); + } debugSerial.println("-- SEND: SETUP"); sendData(PORT_SETUP); @@ -97,7 +114,6 @@ void onButtonRelease(unsigned long duration) void sendData(uint8_t port) { - // Wake RN2483 ttn.wake(); @@ -116,13 +132,6 @@ void sendData(uint8_t port) lpp.addAccelerometer(7, x, y, z); ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); - - // Set RN2483 to sleep mode - ttn.sleep(60000); - - // This one is not optionnal, remove it - // and say bye bye to RN2483 or RN2903 sleep mode - delay(50); } void printSensors() From 868672af317172d80869e317416954ad6469afa8 Mon Sep 17 00:00:00 2001 From: Charles Date: Wed, 28 Feb 2018 22:23:06 +0100 Subject: [PATCH 29/53] send wakeSatus to intervall callback --- src/TheThingsNode.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TheThingsNode.h b/src/TheThingsNode.h index d828800..030a313 100644 --- a/src/TheThingsNode.h +++ b/src/TheThingsNode.h @@ -113,7 +113,7 @@ class TheThingsNode void (*motionStopCallback)(unsigned long duration); void (*buttonPressCallback)(void); void (*buttonReleaseCallback)(unsigned long duration); - void (*intervalCallback)(void); + void (*intervalCallback)(uint8_t wakeStatus); void wakeTemperature(); void sleepTemperature(); @@ -138,7 +138,7 @@ class TheThingsNode void showStatus(); - void onInterval(void (*callback)(void)); + void onInterval(void (*callback)(uint8_t wakeStatus)); void configInterval(bool enabled, uint32_t ms); void configInterval(bool enabled); void configInterval(TheThingsNetwork *pttn, uint32_t ms); From f46fffef02145c7dbbaca2d9a9fe3e10f21c22a6 Mon Sep 17 00:00:00 2001 From: Charles Date: Wed, 28 Feb 2018 22:37:12 +0100 Subject: [PATCH 30/53] Low Power optimization and bug fixes Refactored Interrupt Refactored button management improove deep sleep mode disable USB VREG on sleep --- src/TheThingsNode.cpp | 124 +++++++++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 44 deletions(-) diff --git a/src/TheThingsNode.cpp b/src/TheThingsNode.cpp index ff33413..777fc9d 100644 --- a/src/TheThingsNode.cpp +++ b/src/TheThingsNode.cpp @@ -39,9 +39,7 @@ void TTN_BUTTON_FN() { wakeStatus |= TTN_WAKE_BTN_PRESS; } - - // Be sure main loop ACK press button before rising the release - if (trigger == RISING && !(wakeStatus&TTN_WAKE_BTN_PRESS)) + else if (trigger == RISING) { wakeStatus |= TTN_WAKE_BTN_RELEASE; } @@ -109,11 +107,9 @@ void TheThingsNode::loop() } } - if (TTN_INTERVAL >= this->intervalMs) { - wakeStatus |= TTN_WAKE_INTERVAL; - } - - if (this->wakeCallback) + // We sure to be called only once when button still pressed + // Button management will start only below this code + if (this->wakeCallback && !this->buttonPressed) { this->wakeCallback(wakeStatus); } @@ -122,17 +118,36 @@ void TheThingsNode::loop() { if (!this->buttonPressed) { - this->buttonPressedAt = millis(); - if (this->buttonEnabled && this->buttonPressCallback) + this->buttonPressed = true; + + // Check still pressed for at least 10ms + for (uint8_t i=0; i<10; i++) { - this->buttonPressCallback(); + // Soft debouncing + if (digitalRead(TTN_BUTTON)==HIGH) + { + this->buttonPressed = false; + // just in case, this is a bad press + wakeStatus &= ~TTN_WAKE_BTN_RELEASE; + } + delay(1); + } + + if (this->buttonPressed) + { + this->buttonPressedAt = millis(); + if (this->buttonEnabled && this->buttonPressCallback) + { + this->buttonPressCallback(); + } } - this->buttonPressed = true; } + // ACK our IRQ press, now all is in this-> wakeStatus &= ~TTN_WAKE_BTN_PRESS; } + // At least one loop instance between press and release so else if here - else if (wakeStatus & TTN_WAKE_BTN_RELEASE) + if (wakeStatus & TTN_WAKE_BTN_RELEASE) { if (this->buttonPressed) { @@ -140,6 +155,7 @@ void TheThingsNode::loop() { this->buttonReleaseCallback(millis() - this->buttonPressedAt); } + this->buttonPressedAt = 0; this->buttonPressed = false; } wakeStatus &= ~TTN_WAKE_BTN_RELEASE; @@ -184,38 +200,42 @@ void TheThingsNode::loop() wakeStatus &= ~TTN_WAKE_TEMPERATURE; } - if (wakeStatus & TTN_WAKE_INTERVAL) + if (wakeStatus & TTN_WAKE_LORA) { - if (this->intervalEnabled && this->intervalCallback) - { - this->intervalCallback(); - } - // Ack our watchdog and interval interrupt - wakeStatus &= ~(TTN_WAKE_WATCHDOG|TTN_WAKE_INTERVAL); - TTN_INTERVAL = 0; + // This is mainly our interval + wakeStatus |= TTN_WAKE_INTERVAL; + + // ACK our interrupt + wakeStatus &= ~TTN_WAKE_LORA; } - if (wakeStatus & TTN_WAKE_LORA) + if (wakeStatus & TTN_WAKE_WATCHDOG) { - if (this->pttn && this->intervalCallback) - { - this->intervalCallback(); + if (TTN_INTERVAL >= this->intervalMs) { + wakeStatus |= TTN_WAKE_INTERVAL; } // ACK our interrupt - wakeStatus &= ~TTN_WAKE_LORA; + wakeStatus &= ~TTN_WAKE_WATCHDOG; } - if (this->sleepCallback) + if (wakeStatus & TTN_WAKE_INTERVAL) { - this->sleepCallback(); + if (this->intervalEnabled && this->intervalCallback) + { + this->intervalCallback(wakeStatus); + } + // Ack our interval interrupt + wakeStatus &= ~TTN_WAKE_INTERVAL; + TTN_INTERVAL = 0; } // If button pushed manage loop faster uint16_t dly = this->buttonPressed ? 10 : 100; + // USB is connected and so sleep on USB if (this->isUSBConnected() && !this->USBDeepSleep) { - + // Loop until pseudo wake event (because we're not sleeping) or interval while (!(wakeStatus&TTN_WAKE_ANY) && TTN_INTERVAL < this->intervalMs) { delay(dly); @@ -230,8 +250,14 @@ void TheThingsNode::loop() if (this->buttonPressed) { delay(dly); TTN_INTERVAL = TTN_INTERVAL + dly; + } + else + { + if (this->sleepCallback) + { + this->sleepCallback(); + } - } else { Serial.flush(); deepSleep(); } @@ -316,7 +342,7 @@ void TheThingsNode::configInterval(bool enabled) this->intervalEnabled = enabled; } -void TheThingsNode::onInterval(void (*callback)(void)) +void TheThingsNode::onInterval(void (*callback)(uint8_t wakeStatus)) { this->intervalCallback = callback; @@ -1023,8 +1049,7 @@ void TheThingsNode::deepSleep(void) // watchdog Not needed, avoid wake every 8S WDT_stop(); - // Set LoRa module sleep mode - // ttn.sleep( CONFIG_INTERVAL*1000 ); + // Set LoRa module sleep mode this->pttn->sleep(this->intervalMs); // This one is not optionnal, remove it // and say bye bye to RN2483 or RN2903 sleep mode @@ -1043,22 +1068,33 @@ void TheThingsNode::deepSleep(void) WDT_start(); } - ADCSRA &= ~_BV(ADEN); + bitClear(ADCSRA, ADEN); + bitSet(MCUCR, JTD); + bitSet(USBCON,FRZCLK); // Disable USB clock + bitClear(PLLCSR, PLLE); // Disable USB PLL + bitClear(USBCON, USBE); // Disable USB + bitClear(UHWCON, UVREGE); // Disable USB Regulator set_sleep_mode(SLEEP_MODE_PWR_DOWN); - MCUCR |= (1 << JTD); - USBCON |= (1 << FRZCLK); - //USBCON &= ~_BV(USBE); - PLLCSR &= ~_BV(PLLE); - UHWCON &= ~_BV(UVREGE); // Disable USB Regulator sleep_enable(); sleep_mode(); //Sweet dreams! //wake up, after ISR we arrive here -> sleep_disable(); - PLLCSR |= (1 << PLLE); power_all_enable(); - UHWCON |= (1< Date: Wed, 28 Feb 2018 22:42:17 +0100 Subject: [PATCH 31/53] Optimized Low Power --- .../BatteryMonitorLPP/BatteryMonitorLPP.ino | 76 ++++++++++++++----- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino index 3ac5f7d..8f89245 100644 --- a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -1,3 +1,11 @@ +// This sketch use advanced Ultra Low Power techniques +// for this it disable all uneede peripherals during sleep mode, including +// USB Management, this mean you won't be able to upload anymore if the node is sleeping +// when wake up, Lora transmission is aprox 3s (including receive windows) this means +// that you have 3 seconds windows to upload, so unless you're lucky, it's almost impossible +// to sync Arduino compilation and upload. But to avoid this, you can press the node button +// for more than 2s, then the led will yellow blink quickly for 60s, letting you time to upload + #include #include #include @@ -12,10 +20,15 @@ const char *appKey = "00000000000000000000000000000000"; #define loraSerial Serial1 #define debugSerial Serial -#define PORT_SETUP 1 -#define PORT_INTERVAL 2 -#define PORT_MOTION 3 -#define PORT_BUTTON 4 +#define PORT_SETUP 1 +#define PORT_BTN_PRESS 10 +#define PORT_BTN_RELEASE 11 +#define PORT_MOTION_START 20 +#define PORT_MOTION_END 21 +#define PORT_WATCHDOG 30 +#define PORT_INTERVAL 31 +#define PORT_LORA 32 +#define PORT_TEMPERATURE 33 // Interval between send in seconds, so 300s = 5min #define CONFIG_INTERVAL ((uint32_t)300) @@ -23,17 +36,27 @@ const char *appKey = "00000000000000000000000000000000"; TheThingsNetwork ttn(loraSerial, debugSerial, freqPlan); TheThingsNode *node; CayenneLPP lpp(24); + +uint8_t fport = PORT_SETUP; // LoRaWAN port used + char buf[24]; // For printf void sendData(uint8_t port=PORT_SETUP, uint32_t duration=0); // This is called on each interval we defined so mainly // this is where we need to do our job -void interval() +void interval(uint8_t wakeReason) { - node->setColor(TTN_BLUE); - debugSerial.println(F("-- SEND: INTERVAL")); - sendData(PORT_INTERVAL); + uint8_t fport = PORT_INTERVAL; + snprintf_P(buf, sizeof(buf), PSTR("-- SEND: INTERVAL 0x%02X"), wakeReason); + debugSerial.println(buf); + + if (wakeReason&TTN_WAKE_LORA) + { + fport = PORT_LORA; + } + + sendData(fport); } // This is called on each wake, every 8S or by an sensor/button interrupt @@ -41,9 +64,12 @@ void interval() // but if it's an interupt it will ne bone ine loop void wake(uint8_t wakeReason) { - uint8_t ledcolor = TTN_BLACK; + ttn_color ledcolor = TTN_BLACK; uint8_t ledblink = 0 ; + //node->setColor(TTN_MAGENTA); + //delay(5000); + snprintf_P(buf, sizeof(buf), PSTR("-- WAKE 0x%02X"), wakeReason); debugSerial.println(buf); @@ -93,7 +119,6 @@ void wake(uint8_t wakeReason) // node->setColor(TTN_BLACK); // delay(333); //} - } void sleep() @@ -112,18 +137,31 @@ void onButtonRelease(unsigned long duration) uint16_t adc_value; uint32_t timepressed = (uint32_t) duration; - node->setColor(TTN_BLUE); - sprintf_P(buf, PSTR("-- SEND: BUTTON %d ms"), timepressed); debugSerial.println(buf); - sendData(PORT_BUTTON, timepressed); + // If button was pressed for more then 2 seconds + if (timepressed > 2000) { + // blink yellow led for 60 seconds + // this will let us to upload new sketch if needed + for (uint8_t i=0 ; i<60 ; i++) { + node->setColor(TTN_YELLOW); + delay(30); + node->setColor(TTN_BLACK); + delay(470); + } + } + + // then send data + sendData(PORT_BTN_RELEASE, timepressed); } void sendData(uint8_t port, uint32_t value) { uint16_t volt; + node->setColor(TTN_CYAN); + // Wake RN2483 ttn.wake(); @@ -154,13 +192,15 @@ void sendData(uint8_t port, uint32_t value) // If button pressed, send press duration // please myDeviceCayenne add counter value type to // avoid us using analog values to send counters - if (port == PORT_BUTTON) { + if (value) { sprintf_P(buf, PSTR("Btn:\t %dms"), value); debugSerial.println(buf); lpp.addAnalogInput(7, value/1000.0); } + node->setColor(TTN_BLUE); // Send data + //ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); } @@ -189,7 +229,7 @@ void setup() // We monitor just button release node->onButtonRelease(onButtonRelease); - // Test sensors and set LED to GREEN if it works + // Test sensors node->showStatus(); debugSerial.println(F("-- TTN: STATUS")); @@ -206,7 +246,7 @@ void setup() // Magenta during join, is joined then green else red debugSerial.println(F("-- TTN: JOIN")); - node->setColor(TTN_MAGENTA); + node->setColor(TTN_BLUE); if (ttn.join(appEui, appKey)) { node->setColor(TTN_GREEN); } else { @@ -216,8 +256,8 @@ void setup() debugSerial.println(F("-- SEND: SETUP")); sendData(PORT_SETUP); - // Enable USB deepsleep - //node->configUSB(true); + // Enable sleep even connected with USB cable + node->configUSB(true); } void loop() From cf311e2c3de90fc183bf682a3dcb186eaacacdf2 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 1 Mar 2018 12:22:27 +0100 Subject: [PATCH 32/53] Updated for Ultra Low Power --- docs/TheThingsNode.md | 98 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 12 deletions(-) diff --git a/docs/TheThingsNode.md b/docs/TheThingsNode.md index d49e395..a6d4938 100644 --- a/docs/TheThingsNode.md +++ b/docs/TheThingsNode.md @@ -38,14 +38,41 @@ This will: > Don't add any other code in your `loop()` function, but use [`onWake()`](#method-onwake), [`onInterval()`](#method-oninterval) and [`onSleep()`](#method-onsleep) instead, to prevent unpredictable behavior. ## Method: onWake -Set a callback that will run first thing every time the Node wakes up, which is when an interrupt changes because of interaction with the button, motion sensor or temperature sensor. The device also wakes up every 8 seconds, which is the longest we can make it sleep. +Set a callback that will run first thing every time the Node wakes up, which is when an interrupt changes because of interaction with the button, motion sensor, temperature sensor or LoRa device wake. + +Depending on [`configInterval()`](#method-configInterval) setup, this method can be called: + +- When you instructed the LoRa RN2xxx device to wake up after the specific interval. +- Every 8 seconds (Watchdog), which is the longest we can make it sleep. + +the parameter wakeReason is indicating what waked the node and can be a bit field of the following description + +| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +| :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | +| Wake by | Interval | Watchdog | LoRa | Btn Release | Btn Press | Motion Stop | Motion Start | Temperature | + +Is declared into the library as follow: +``` +#define TTN_WAKE_TEMPERATURE 0x01 +#define TTN_WAKE_MOTION_START 0x02 +#define TTN_WAKE_MOTION_STOP 0x04 +#define TTN_WAKE_BTN_PRESS 0x08 +#define TTN_WAKE_BTN_RELEASE 0x10 +#define TTN_WAKE_LORA 0x20 +#define TTN_WAKE_WATCHDOG 0x40 +#define TTN_WAKE_INTERVAL 0x80 +``` + +Note that of course, wake by TTN_WAKE_LORA also setup the TTN_WAKE_INTERVAL because we program the LoRa module to wake at the specified interval. + ```c -void onWake(void(*callback)(void)); +void onWake(void(*callback)(uint8_t wakeReason)); ``` Usage: + ```c void setup() { node = TheThingsNode::setup(); @@ -53,8 +80,34 @@ void setup() { node->onWake(wake); } -void wake() { - node->setColor(TTN_GREEN); +void wake(uint8_t wakeReason) { + debugSerial.print(F("Wake Reason:0x")); + debugSerial.println(wakeReason,HEX); + + if (wakeReason&TTN_WAKE_WATCHDOG) { + debugSerial.print(F("Watchdog ")); + } + if (wakeReason&TTN_WAKE_INTERVAL) { + debugSerial.print(F("Interval ")); + } + if (wakeReason&TTN_WAKE_LORA) { + debugSerial.print(F("LoRa_RN2xxx ")); + } + if (wakeReason&TTN_WAKE_BTN_PRESS) { + debugSerial.print(F("Button_Press ")); + } + if (wakeReason&TTN_WAKE_BTN_RELEASE) { + debugSerial.print(F("Button_release ")); + } + if (wakeReason&TTN_WAKE_MOTION_START) { + debugSerial.print(F("Motion_Start ")); + } + if (wakeReason&TTN_WAKE_MOTION_STOP) { + debugSerial.print(F("Motion_Stop ")); + } + if (wakeReason&TTN_WAKE_TEMPERATURE) { + debugSerial.print(F("Temperature ")); + } } ``` @@ -81,12 +134,10 @@ void sleep() { } ``` -Pay attention, this internal sleep method of the library does not put the LoRa module (RN2483 or RN2903) into sleep mode and thus your node may consume 3mA even in sleep mode. You need to manually set the LoRa module to sleep and wake. -Check the example [BatteryMonitorLPP](../examples/BatteryMonitorLPP/) - ## Interval Instead of using your `loop()` function, use `configInterval()` and `onInterval()` to set a function to be called on a certain interval: + ```c void setup() { node = TheThingsNode::setup(); @@ -97,19 +148,22 @@ void setup() { node->onInterval(interval); } -void interval() { +void interval(uint8_t wakeReason) { node->showStatus(); } ``` +See [`onWake()`](#method-onWake) for definition of wakeReason: ### Method: onInterval Set a callback that will run on a certain interval. This will automatically enable the interval. ```c -void onInterval(void(*callback)(void)); +void onInterval(void(*callback)(uint8_t wakeReason)); ``` -- `void(*callback)(void)`: Function to be called, with no arguments nor return value. +- `void(*callback)(uint8_t wakeReason)`: Function to be called. + +See [`onWake()`](#method-onWake) for definition of wakeReason: ### Method: configInterval @@ -459,9 +513,29 @@ When disabled, the [`loop()`](#method-loop) method will delay 100ms until an int > When the Node goes into sleep, the Serial Monitor will loose its connection. The Node will try to reopen the connection when it wakes up, but Serial Monitor might not always be able to pick it up. -## Method: getBattery -Returns the battery level in millivolt (mV) as a unsigned integer of 2 bytes. +## Battery +Different methods to get battery level + +### Method: getBattery +Returns the battery level in millivolt (mV) as a unsigned integer of 2 bytes. This method measure battery with a resistor voltage divider (located before 3.3V ob board regulator.) and connected to an analog input pin. The ADC pin as voltage reference of 2.52V ```c uint16_t getBattery(); ``` + +### Method: getVcc +Returns the AT32U4 chip measured VCC voltage millivolt (mV) using the 1.1V internal Analog Reference voltage. This method is prefered when voltage before regulator comes to and below 3.3V. Moreover, if voltage is below 2.52V, using the method `getBattery` could return wrong values due to the main voltage < ADC reference voltage. + +```c +uint16_t getVcc(); +``` + +### Alternative Method: getVDD +You can also use the getVDD from TheThingNetworkLibrary. + +Returns the voltage in millivolt (mV) measured by the RN2xxx LoRa module. It's for information only since we don't know how it's measured. + +```c +uint16_t bat = ttn.getVDD(); +``` + From b62b6f05a5f4fb291748418fbf6471645ef8beaa Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 1 Mar 2018 12:33:51 +0100 Subject: [PATCH 33/53] fix Link --- docs/TheThingsNode.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/TheThingsNode.md b/docs/TheThingsNode.md index a6d4938..08d28cc 100644 --- a/docs/TheThingsNode.md +++ b/docs/TheThingsNode.md @@ -40,7 +40,7 @@ This will: ## Method: onWake Set a callback that will run first thing every time the Node wakes up, which is when an interrupt changes because of interaction with the button, motion sensor, temperature sensor or LoRa device wake. -Depending on [`configInterval()`](#method-configInterval) setup, this method can be called: +Depending on [`configInterval()`](#method-configinterval) setup, this method can be called: - When you instructed the LoRa RN2xxx device to wake up after the specific interval. - Every 8 seconds (Watchdog), which is the longest we can make it sleep. @@ -152,7 +152,8 @@ void interval(uint8_t wakeReason) { node->showStatus(); } ``` -See [`onWake()`](#method-onWake) for definition of wakeReason: +See [`onWake()`](#method-onwake) for definition of wakeReason: + ### Method: onInterval Set a callback that will run on a certain interval. This will automatically enable the interval. @@ -163,7 +164,7 @@ void onInterval(void(*callback)(uint8_t wakeReason)); - `void(*callback)(uint8_t wakeReason)`: Function to be called. -See [`onWake()`](#method-onWake) for definition of wakeReason: +See [`onWake()`](#method-onwake) for definition of wakeReason: ### Method: configInterval @@ -531,7 +532,7 @@ uint16_t getVcc(); ``` ### Alternative Method: getVDD -You can also use the getVDD from TheThingNetworkLibrary. +You can also use the getVDD from [TTN Device Library](https://github.com/TheThingsNetwork/arduino-device-lib). Returns the voltage in millivolt (mV) measured by the RN2xxx LoRa module. It's for information only since we don't know how it's measured. From f08d648e0b31747a3301f4b958a8cce8fd682894 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 1 Mar 2018 12:35:31 +0100 Subject: [PATCH 34/53] fix code dispkay --- docs/TheThingsNode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/TheThingsNode.md b/docs/TheThingsNode.md index 08d28cc..3e9f756 100644 --- a/docs/TheThingsNode.md +++ b/docs/TheThingsNode.md @@ -52,7 +52,7 @@ the parameter wakeReason is indicating what waked the node and can be a bit fiel | Wake by | Interval | Watchdog | LoRa | Btn Release | Btn Press | Motion Stop | Motion Start | Temperature | Is declared into the library as follow: -``` +```c #define TTN_WAKE_TEMPERATURE 0x01 #define TTN_WAKE_MOTION_START 0x02 #define TTN_WAKE_MOTION_STOP 0x04 From 05f454dde57b889ef4ab099e0491daca6b2a4b2d Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 1 Mar 2018 13:19:49 +0100 Subject: [PATCH 35/53] Updated for Ultra Low Power --- examples/CayenneLPP/CayenneLPP.ino | 93 +++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 22 deletions(-) diff --git a/examples/CayenneLPP/CayenneLPP.ino b/examples/CayenneLPP/CayenneLPP.ino index 44a2db1..3ff236d 100644 --- a/examples/CayenneLPP/CayenneLPP.ino +++ b/examples/CayenneLPP/CayenneLPP.ino @@ -1,3 +1,11 @@ +// This sketch use advanced Ultra Low Power techniques +// for this it disable all unneeded peripherals during sleep mode, including +// USB Management, this mean you won't be able to upload anymore if the node is sleeping +// when wake up, Lora transmission is approx 3s (including receive windows) this means +// that you have 3 seconds windows to upload, so unless you're lucky, it's almost impossible +// to sync Arduino compilation and upload. But to avoid this, you can press the node button +// for more than 2s, then the led will yellow blink quickly for 60s, letting you time to upload + #include #include @@ -5,16 +13,18 @@ const char *appEui = "0000000000000000"; const char *appKey = "00000000000000000000000000000000"; -#define loraSerial Serial1 -#define debugSerial Serial - // Replace REPLACE_ME with TTN_FP_EU868 or TTN_FP_US915 #define freqPlan REPLACE_ME +#define loraSerial Serial1 +#define debugSerial Serial + TheThingsNetwork ttn(loraSerial, debugSerial, freqPlan); TheThingsNode *node; CayenneLPP lpp(51); +char buf[24]; // For printf + #define PORT_SETUP 1 #define PORT_INTERVAL 2 #define PORT_MOTION 3 @@ -23,19 +33,24 @@ CayenneLPP lpp(51); // Interval between send in seconds, so 300s = 5min #define CONFIG_INTERVAL ((uint32_t)300) +void sendData(uint8_t port=PORT_SETUP, uint32_t duration=0); + void setup() { loraSerial.begin(57600); debugSerial.begin(9600); // Wait a maximum of 10s for Serial Monitor - while (!debugSerial && millis() < 10000) - ; + while (!debugSerial && millis() < 10000) { + node->setColor(TTN_RED); + delay(20); + node->setColor(TTN_BLACK); + delay(480); + }; // Config Node node = TheThingsNode::setup(); node->configLight(true); - node->configInterval(true, 60000); node->configTemperature(true); node->onWake(wake); node->onInterval(interval); @@ -49,9 +64,6 @@ void setup() debugSerial.println("-- TTN: STATUS"); ttn.showStatus(); - // Each interval (with watchdog) - //node->configInterval(true, CONFIG_INTERVAL*1000); - // Each interval (with Lora Module and Serial IRQ) // Take care this one need to be called after any // first call to ttn.* so object has been instancied @@ -69,6 +81,9 @@ void setup() debugSerial.println("-- SEND: SETUP"); sendData(PORT_SETUP); + + // Enable sleep even connected with USB cable + node->configUSB(true); } void loop() @@ -76,16 +91,17 @@ void loop() node->loop(); } -void interval() +void interval(uint8_t wakeReason) { - node->setColor(TTN_BLUE); - - debugSerial.println("-- SEND: INTERVAL"); + snprintf_P(buf, sizeof(buf), PSTR("-- SEND: INTERVAL 0x%02X"), wakeReason); + debugSerial.println(buf); sendData(PORT_INTERVAL); } -void wake() +void wake(uint8_t wakeReason) { + snprintf_P(buf, sizeof(buf), PSTR("-- WAKE 0x%02X"), wakeReason); + debugSerial.println(buf); node->setColor(TTN_GREEN); } @@ -96,7 +112,7 @@ void sleep() void onMotionStart() { - node->setColor(TTN_BLUE); + node->setColor(TTN_RED); debugSerial.print("-- SEND: MOTION"); sendData(PORT_MOTION); @@ -104,16 +120,39 @@ void onMotionStart() void onButtonRelease(unsigned long duration) { - node->setColor(TTN_BLUE); - - debugSerial.print("-- SEND: BUTTON"); - debugSerial.println(duration); + uint32_t timepressed = (uint32_t) duration; + + snprintf_P(buf, sizeof(buf), PSTR("-- SEND: BUTTON %d ms"), timepressed); + debugSerial.println(buf); + + // If button was pressed for more then 2 seconds + if (timepressed > 2000) { + // blink yellow led for 60 seconds + // this will let us to upload new sketch if needed + for (uint8_t i=0 ; i<60 ; i++) { + node->setColor(TTN_YELLOW); + delay(30); + node->setColor(TTN_BLACK); + delay(470); + } + } - sendData(PORT_BUTTON); + // then send data + sendData(PORT_BUTTON, timepressed); } -void sendData(uint8_t port) +void sendData(uint8_t port, uint32_t duration) { + uint16_t bat = node->getBattery(); + + // when battery < 3.3V (regulator does not regule output, so + // we use another method to read VCC of the device and this will + // also avoid error if VCC < ADC reference (2.52V) + if (bat <= 3300) + { + bat = node->getVcc(); + } + // Wake RN2483 ttn.wake(); @@ -123,14 +162,24 @@ void sendData(uint8_t port) lpp.addDigitalInput(1, node->isButtonPressed()); lpp.addDigitalInput(2, node->isUSBConnected()); lpp.addDigitalInput(3, node->isMoving()); - lpp.addAnalogInput(4, node->getBattery()/1000.0); + lpp.addAnalogInput(4, bat/1000.0); lpp.addTemperature(5, node->getTemperatureAsFloat()); lpp.addLuminosity(6, node->getLight()); float x,y,z; node->getAcceleration(&x, &y, &z); lpp.addAccelerometer(7, x, y, z); + + // If button pressed, send press duration + // please myDeviceCayenne add counter value type to + // avoid us using analog values to send counters + if (duration) { + snprintf_P(buf, sizeof(buf), PSTR("Btn:\t %dms"), duration); + debugSerial.println(buf); + lpp.addAnalogInput(10, duration/1000.0); + } + node->setColor(TTN_BLUE); ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); } From 940f4a2aac5f58bbaf08fd10d966b2be550e9fab Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 1 Mar 2018 13:21:19 +0100 Subject: [PATCH 36/53] secrure printf and set channel 10 for button duration --- .../BatteryMonitorLPP/BatteryMonitorLPP.ino | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino index 8f89245..e603c61 100644 --- a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -1,7 +1,7 @@ // This sketch use advanced Ultra Low Power techniques -// for this it disable all uneede peripherals during sleep mode, including +// for this it disable all unneeded peripherals during sleep mode, including // USB Management, this mean you won't be able to upload anymore if the node is sleeping -// when wake up, Lora transmission is aprox 3s (including receive windows) this means +// when wake up, Lora transmission is approx 3s (including receive windows) this means // that you have 3 seconds windows to upload, so unless you're lucky, it's almost impossible // to sync Arduino compilation and upload. But to avoid this, you can press the node button // for more than 2s, then the led will yellow blink quickly for 60s, letting you time to upload @@ -67,9 +67,6 @@ void wake(uint8_t wakeReason) ttn_color ledcolor = TTN_BLACK; uint8_t ledblink = 0 ; - //node->setColor(TTN_MAGENTA); - //delay(5000); - snprintf_P(buf, sizeof(buf), PSTR("-- WAKE 0x%02X"), wakeReason); debugSerial.println(buf); @@ -134,10 +131,9 @@ void sleep() void onButtonRelease(unsigned long duration) { - uint16_t adc_value; uint32_t timepressed = (uint32_t) duration; - sprintf_P(buf, PSTR("-- SEND: BUTTON %d ms"), timepressed); + snprintf_P(buf, sizeof(buf), PSTR("-- SEND: BUTTON %d ms"), timepressed); debugSerial.println(buf); // If button was pressed for more then 2 seconds @@ -160,8 +156,6 @@ void sendData(uint8_t port, uint32_t value) { uint16_t volt; - node->setColor(TTN_CYAN); - // Wake RN2483 ttn.wake(); @@ -170,7 +164,7 @@ void sendData(uint8_t port, uint32_t value) // Read battery voltage volt = node->getBattery(); - sprintf_P(buf, PSTR("Bat:\t %dmV"), volt); + snprintf_P(buf, sizeof(buf), PSTR("Bat:\t %dmV"), volt); debugSerial.println(buf); lpp.addAnalogInput(4, volt/1000.0); @@ -179,13 +173,13 @@ void sendData(uint8_t port, uint32_t value) // as soon as VCC < 3.3V, // when above 3.3V, since regulator fix 3.3V you should read 3300mV volt = node->getVcc(); - sprintf_P(buf, PSTR("Vcc:\t %dmV"), volt); + snprintf_P(buf, sizeof(buf), PSTR("Vcc:\t %dmV"), volt); debugSerial.println(buf); lpp.addAnalogInput(5, volt/1000.0); // Read value returned by RN2483 module volt = ttn.getVDD(); - sprintf_P(buf, PSTR("Vrn:\t %dmV"), volt); + snprintf_P(buf, sizeof(buf), PSTR("Vrn:\t %dmV"), volt); debugSerial.println(buf); lpp.addAnalogInput(6, volt/1000.0); @@ -193,9 +187,9 @@ void sendData(uint8_t port, uint32_t value) // please myDeviceCayenne add counter value type to // avoid us using analog values to send counters if (value) { - sprintf_P(buf, PSTR("Btn:\t %dms"), value); + snprintf_P(buf, sizeof(buf), PSTR("Btn:\t %dms"), value); debugSerial.println(buf); - lpp.addAnalogInput(7, value/1000.0); + lpp.addAnalogInput(10, value/1000.0); } node->setColor(TTN_BLUE); From d5f613a26563797712b9a61a340e4695edd172ee Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 1 Mar 2018 13:43:28 +0100 Subject: [PATCH 37/53] updated onInterval method() --- examples/Basic/Basic.ino | 2 +- test/TheThingsNode/TheThingsNode.ino | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Basic/Basic.ino b/examples/Basic/Basic.ino index 97e6259..a49bb85 100644 --- a/examples/Basic/Basic.ino +++ b/examples/Basic/Basic.ino @@ -80,7 +80,7 @@ void loop() node->loop(); } -void interval() +void interval(int8_t wakeStatus) { node->setColor(TTN_BLUE); diff --git a/test/TheThingsNode/TheThingsNode.ino b/test/TheThingsNode/TheThingsNode.ino index f010173..bfa1766 100644 --- a/test/TheThingsNode/TheThingsNode.ino +++ b/test/TheThingsNode/TheThingsNode.ino @@ -44,7 +44,7 @@ void loop() { node->loop(); } -void onInterval() { +void onInterval(uint8_t wakeStatus) { node->showStatus(); uint16_t light = node->getLight(); int8_t tempFloat = node->getTemperatureAsFloat(); From 1f4003880472adc59b1e82dde7660204eb1d48c0 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 1 Mar 2018 13:50:20 +0100 Subject: [PATCH 38/53] fixed wake with wakeReason parameter --- test/TheThingsNode/TheThingsNode.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/TheThingsNode/TheThingsNode.ino b/test/TheThingsNode/TheThingsNode.ino index bfa1766..4b1e10f 100644 --- a/test/TheThingsNode/TheThingsNode.ino +++ b/test/TheThingsNode/TheThingsNode.ino @@ -4,7 +4,7 @@ TheThingsNode *node; void setup() { node = TheThingsNode::setup(); - node->onWake(voidFn); + node->onWake(wakeFn); node->onSleep(voidFn); node->onInterval(onInterval); node->configInterval(false, 60000); @@ -37,6 +37,7 @@ void setup() { } void voidFn() {} +void wakeFn(uint8_t wakeStatus) {} void durationFn(unsigned long duration) {} From 6b5c7bb1cd26832c468bb2f32ccde505ab21c5d6 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 1 Mar 2018 13:53:27 +0100 Subject: [PATCH 39/53] fixed call of wake and interval --- examples/Basic/Basic.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Basic/Basic.ino b/examples/Basic/Basic.ino index a49bb85..ee66362 100644 --- a/examples/Basic/Basic.ino +++ b/examples/Basic/Basic.ino @@ -80,7 +80,7 @@ void loop() node->loop(); } -void interval(int8_t wakeStatus) +void interval(int8_t wakeReason) { node->setColor(TTN_BLUE); @@ -88,7 +88,7 @@ void interval(int8_t wakeStatus) sendData(PORT_INTERVAL); } -void wake() +void wake(uint8_t wakeReason) { node->setColor(TTN_GREEN); } From 60bfe4b5f6a066d3b42ffe07f1f395f88407fabd Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 1 Mar 2018 14:02:48 +0100 Subject: [PATCH 40/53] fix var name error --- examples/Basic/Basic.ino | 2 +- src/TheThingsNode.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/Basic/Basic.ino b/examples/Basic/Basic.ino index ee66362..a880eba 100644 --- a/examples/Basic/Basic.ino +++ b/examples/Basic/Basic.ino @@ -80,7 +80,7 @@ void loop() node->loop(); } -void interval(int8_t wakeReason) +void interval(uint8_t wakeReason) { node->setColor(TTN_BLUE); diff --git a/src/TheThingsNode.h b/src/TheThingsNode.h index 030a313..20d2cb8 100644 --- a/src/TheThingsNode.h +++ b/src/TheThingsNode.h @@ -106,14 +106,14 @@ class TheThingsNode bool USBDeepSleep; bool wdtStarted; - void (*wakeCallback)(uint8_t wakeStatus); + void (*wakeCallback)(uint8_t wakeReason); void (*sleepCallback)(void); void (*temperatureCallback)(void); void (*motionStartCallback)(void); void (*motionStopCallback)(unsigned long duration); void (*buttonPressCallback)(void); void (*buttonReleaseCallback)(unsigned long duration); - void (*intervalCallback)(uint8_t wakeStatus); + void (*intervalCallback)(uint8_t wakeReason); void wakeTemperature(); void sleepTemperature(); @@ -132,13 +132,13 @@ class TheThingsNode return &node; }; - void onWake(void (*callback)(uint8_t wakeStatus)); + void onWake(void (*callback)(uint8_t wakeReason)); void loop(); void onSleep(void (*callback)(void)); void showStatus(); - void onInterval(void (*callback)(uint8_t wakeStatus)); + void onInterval(void (*callback)(uint8_t wakeReason)); void configInterval(bool enabled, uint32_t ms); void configInterval(bool enabled); void configInterval(TheThingsNetwork *pttn, uint32_t ms); From 71b9c68f0ac47fdea098be7919eff63da292b20e Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 4 Mar 2018 16:01:10 +0100 Subject: [PATCH 41/53] renamed getVcc to getVCC --- src/TheThingsNode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TheThingsNode.h b/src/TheThingsNode.h index 20d2cb8..0c55542 100644 --- a/src/TheThingsNode.h +++ b/src/TheThingsNode.h @@ -182,7 +182,7 @@ class TheThingsNode uint16_t getBattery(); uint16_t readADCLowNoise(bool average); - uint16_t getVcc(); + uint16_t getVCC(); }; #endif From 03cc19ec795c7fad9bfad0f5299a132bb097066a Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 4 Mar 2018 16:01:25 +0100 Subject: [PATCH 42/53] renamed getVcc to getVCC and cosmetic --- docs/TheThingsNode.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/TheThingsNode.md b/docs/TheThingsNode.md index 3e9f756..c5c6fc4 100644 --- a/docs/TheThingsNode.md +++ b/docs/TheThingsNode.md @@ -81,31 +81,31 @@ void setup() { } void wake(uint8_t wakeReason) { - debugSerial.print(F("Wake Reason:0x")); - debugSerial.println(wakeReason,HEX); + debugSerial.print(F("Wake Reason: 0x")); + debugSerial.println(wakeReason, HEX); - if (wakeReason&TTN_WAKE_WATCHDOG) { + if (wakeReason & TTN_WAKE_WATCHDOG) { debugSerial.print(F("Watchdog ")); } - if (wakeReason&TTN_WAKE_INTERVAL) { + if (wakeReason & TTN_WAKE_INTERVAL) { debugSerial.print(F("Interval ")); } - if (wakeReason&TTN_WAKE_LORA) { + if (wakeReason & TTN_WAKE_LORA) { debugSerial.print(F("LoRa_RN2xxx ")); } - if (wakeReason&TTN_WAKE_BTN_PRESS) { + if (wakeReason & TTN_WAKE_BTN_PRESS) { debugSerial.print(F("Button_Press ")); } - if (wakeReason&TTN_WAKE_BTN_RELEASE) { + if (wakeReason & TTN_WAKE_BTN_RELEASE) { debugSerial.print(F("Button_release ")); } - if (wakeReason&TTN_WAKE_MOTION_START) { + if (wakeReason & TTN_WAKE_MOTION_START) { debugSerial.print(F("Motion_Start ")); } - if (wakeReason&TTN_WAKE_MOTION_STOP) { + if (wakeReason & TTN_WAKE_MOTION_STOP) { debugSerial.print(F("Motion_Stop ")); } - if (wakeReason&TTN_WAKE_TEMPERATURE) { + if (wakeReason & TTN_WAKE_TEMPERATURE) { debugSerial.print(F("Temperature ")); } } @@ -175,7 +175,7 @@ void configInterval(TheThingsNetwork *pttn, uint32_t ms); ``` - `bool enabled`: Enable or disable the interval callback. Enabled automatically by `onInterval()`, but you can use this method to temporarily disable it. Defaults to `false`. -- `TheThingsNetwork * pttn`: This enable the interval callback but in this mode, the interval is passed to RN2483 or RN2903 module (this is why we need to pass pointer to object) with the command `sys sleep ms` and then it's the LoRa module that wake up the node. This is the most advanced Low Power Mode. In this mode, the watchdog is disabled and consuption again reduced. +- `TheThingsNetwork * pttn`: This enable the interval callback but in this mode, the interval is passed to RN2483 or RN2903 module (this is why we need to pass pointer to object) with the command `sys sleep ms` and then it's the LoRa module that wake up the node. This is the most advanced Low Power Mode. In this mode, the watchdog is disabled and consumption again reduced. - `uint32_t ms`: Minimal time between calling the interval callback. Defaults to `60000` or 60 seconds. > If the Node has no USB data connection or is configured to also sleep in that case, it will only wake up every 8 seconds to check if the interval callback should run. This means setting `ms` to less than `8000` makes no sense. It also means that the maximum time between calls can be up to 8 seconds longer than `ms` if it wakes up to handle button or sensor interaction in between. This does not apply when wake up by LoRa module. @@ -524,11 +524,11 @@ Returns the battery level in millivolt (mV) as a unsigned integer of 2 bytes. Th uint16_t getBattery(); ``` -### Method: getVcc +### Method: getVCC Returns the AT32U4 chip measured VCC voltage millivolt (mV) using the 1.1V internal Analog Reference voltage. This method is prefered when voltage before regulator comes to and below 3.3V. Moreover, if voltage is below 2.52V, using the method `getBattery` could return wrong values due to the main voltage < ADC reference voltage. ```c -uint16_t getVcc(); +uint16_t getVCC(); ``` ### Alternative Method: getVDD From 14c691d3a5142bd8d8113407aa71f49f81709ebf Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 4 Mar 2018 16:02:36 +0100 Subject: [PATCH 43/53] renamed getVcc to getVCC --- examples/CayenneLPP/CayenneLPP.ino | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/CayenneLPP/CayenneLPP.ino b/examples/CayenneLPP/CayenneLPP.ino index 3ff236d..6675af8 100644 --- a/examples/CayenneLPP/CayenneLPP.ino +++ b/examples/CayenneLPP/CayenneLPP.ino @@ -1,4 +1,5 @@ -// This sketch use advanced Ultra Low Power techniques +// This sketch sends sensors dta tp Cayenne with LPP format +// but it use advanced Ultra Low Power techniques // for this it disable all unneeded peripherals during sleep mode, including // USB Management, this mean you won't be able to upload anymore if the node is sleeping // when wake up, Lora transmission is approx 3s (including receive windows) this means @@ -150,7 +151,7 @@ void sendData(uint8_t port, uint32_t duration) // also avoid error if VCC < ADC reference (2.52V) if (bat <= 3300) { - bat = node->getVcc(); + bat = node->getVCC(); } // Wake RN2483 From b7f84aec6977dccc2d2cf8341a6813bffcaeeb2a Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 4 Mar 2018 16:02:53 +0100 Subject: [PATCH 44/53] renamed getVcc to getVCC --- examples/BatteryMonitorLPP/BatteryMonitorLPP.ino | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino index e603c61..502c38c 100644 --- a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -133,8 +133,9 @@ void onButtonRelease(unsigned long duration) { uint32_t timepressed = (uint32_t) duration; - snprintf_P(buf, sizeof(buf), PSTR("-- SEND: BUTTON %d ms"), timepressed); - debugSerial.println(buf); + debugSerial.print(F("-- SEND: BUTTON" )); + debugSerial.print(timepressed); + debugSerial.println(F(" ms")); // If button was pressed for more then 2 seconds if (timepressed > 2000) { @@ -172,7 +173,7 @@ void sendData(uint8_t port, uint32_t value) // because in this case reading are wrong, but you can use it // as soon as VCC < 3.3V, // when above 3.3V, since regulator fix 3.3V you should read 3300mV - volt = node->getVcc(); + volt = node->getVCC(); snprintf_P(buf, sizeof(buf), PSTR("Vcc:\t %dmV"), volt); debugSerial.println(buf); lpp.addAnalogInput(5, volt/1000.0); @@ -186,15 +187,15 @@ void sendData(uint8_t port, uint32_t value) // If button pressed, send press duration // please myDeviceCayenne add counter value type to // avoid us using analog values to send counters - if (value) { - snprintf_P(buf, sizeof(buf), PSTR("Btn:\t %dms"), value); + if (value) + { + snprintf_P(buf, sizeof(buf), PSTR("Button:\t %dms"), value); debugSerial.println(buf); lpp.addAnalogInput(10, value/1000.0); } node->setColor(TTN_BLUE); // Send data - //ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port); } From 080d0a2203a60da26ac8ce13b021fe9659efe428 Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 4 Mar 2018 16:03:11 +0100 Subject: [PATCH 45/53] costemic requested by johan --- src/TheThingsNode.cpp | 48 ++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/TheThingsNode.cpp b/src/TheThingsNode.cpp index 777fc9d..83974bd 100644 --- a/src/TheThingsNode.cpp +++ b/src/TheThingsNode.cpp @@ -20,7 +20,7 @@ void TTN_MOTION_FN() { uint8_t trigger = getPinChangeInterruptTrigger(digitalPinToPCINT(TTN_ACCELEROMETER_INT2)); // Reset according bits - wakeStatus &= ~ (TTN_WAKE_MOTION_START|TTN_WAKE_MOTION_STOP); + wakeStatus &= ~ (TTN_WAKE_MOTION_START | TTN_WAKE_MOTION_STOP); if (trigger == RISING) { @@ -236,7 +236,7 @@ void TheThingsNode::loop() if (this->isUSBConnected() && !this->USBDeepSleep) { // Loop until pseudo wake event (because we're not sleeping) or interval - while (!(wakeStatus&TTN_WAKE_ANY) && TTN_INTERVAL < this->intervalMs) + while (!(wakeStatus & TTN_WAKE_ANY) && this->intervalMs > TTN_INTERVAL) { delay(dly); TTN_INTERVAL = TTN_INTERVAL + dly; @@ -326,7 +326,8 @@ void TheThingsNode::showStatus() void TheThingsNode::configInterval(bool enabled, uint32_t ms) { this->intervalMs = ms; - configInterval(enabled); + this->pttn = NULL; + this->intervalEnabled = enabled; } void TheThingsNode::configInterval(TheThingsNetwork *ttn, uint32_t ms) @@ -755,19 +756,21 @@ uint16_t TheThingsNode::readADCLowNoise(bool average) ADCSRA |= _BV(ADSC); // wait for first dummy conversion - while (bit_is_set(ADCSRA,ADSC)); + while (bit_is_set(ADCSRA,ADSC)) + { + }; // Init our measure counter adcIRQCnt = 0; // We want to have a interrupt when the conversion is done - ADCSRA |= _BV( ADIE ); + ADCSRA |= _BV(ADIE); // Loop thru samples // 8 samples (we don't take the 1st one) do { // Enable Noise Reduction Sleep Mode - set_sleep_mode( SLEEP_MODE_ADC ); + set_sleep_mode(SLEEP_MODE_ADC); sleep_enable(); // Wait until conversion is finished @@ -778,7 +781,7 @@ uint16_t TheThingsNode::readADCLowNoise(bool average) cli(); } // Check is done with interrupts disabled to avoid a race condition - while (bit_is_set(ADCSRA,ADSC)); + while (bit_is_set(ADCSRA, ADSC)); // No more sleeping sleep_disable(); @@ -798,24 +801,17 @@ uint16_t TheThingsNode::readADCLowNoise(bool average) ADCSRA &= ~ _BV( ADIE ); // Return the average divided by 8 (8 samples) - return ( average ? sum >> 3 : sum ); + return (average ? sum >> 3 : sum); } -/* ====================================================================== -Function: getVcc -Purpose : Read and Calculate V powered, the Voltage on Arduino VCC pin -Input : - -Output : value readed -Comments: ADC Channel input is modified -====================================================================== */ -uint16_t TheThingsNode::getVcc() +uint16_t TheThingsNode::getVCC() { uint16_t value; uint16_t vcc; // Enable ADC (just in case going out of low power) power_adc_enable(); - ADCSRA |= _BV(ADEN) ; + ADCSRA |= _BV(ADEN); // Read 1.1V reference against AVcc // REFS1 REFS0 --> 0 1, AVcc internal ref. -Selects AVcc external reference @@ -832,14 +828,21 @@ uint16_t TheThingsNode::getVcc() value = readADCLowNoise(true); // Vcc reference in millivolts - vcc = ( 1023L * 1100L) / value ; + vcc = (1023L * 1100L) / value; // Operating range of ATMega - if (vcc < 1800 ) vcc = 1800 ; - if (vcc > 5500 ) vcc = 5500 ; + if (vcc < 1800) + { + vcc = 1800; + } + + if (vcc > 5500) + { + vcc = 5500; + } // Vcc in millivolts - return ( vcc ); + return vcc; } @@ -903,7 +906,7 @@ TheThingsNode::TheThingsNode() pinMode(TTN_BLUE_LED, OUTPUT); setColor(TTN_BLACK); - // reset RN2483 module, this allow to reset module on sketch upload also + // reset RN2xx3 module, this allow to reset module on sketch upload also #ifdef TTN_LORA_RESET pinMode(TTN_LORA_RESET, OUTPUT); digitalWrite(TTN_LORA_RESET, LOW); @@ -1062,7 +1065,6 @@ void TheThingsNode::deepSleep(void) cli(); bitSet(EIFR,INTF2); // clear any pending interrupts for serial RX pin (INT2 D0) sei(); - } else { // watchdog needed for wakeup WDT_start(); From 8766972061b700e0abe33745a9f5de8ddac08c88 Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 4 Mar 2018 16:09:33 +0100 Subject: [PATCH 46/53] removed all printf reference --- examples/CayenneLPP/CayenneLPP.ino | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/examples/CayenneLPP/CayenneLPP.ino b/examples/CayenneLPP/CayenneLPP.ino index 6675af8..cd6fc99 100644 --- a/examples/CayenneLPP/CayenneLPP.ino +++ b/examples/CayenneLPP/CayenneLPP.ino @@ -24,8 +24,6 @@ TheThingsNetwork ttn(loraSerial, debugSerial, freqPlan); TheThingsNode *node; CayenneLPP lpp(51); -char buf[24]; // For printf - #define PORT_SETUP 1 #define PORT_INTERVAL 2 #define PORT_MOTION 3 @@ -94,15 +92,17 @@ void loop() void interval(uint8_t wakeReason) { - snprintf_P(buf, sizeof(buf), PSTR("-- SEND: INTERVAL 0x%02X"), wakeReason); - debugSerial.println(buf); + debugSerial.print(F("-- SEND: INTERVAL 0x")); + debugSerial.print(wakeReason, HEX); + debugSerial.println(F("ms")); sendData(PORT_INTERVAL); } void wake(uint8_t wakeReason) { - snprintf_P(buf, sizeof(buf), PSTR("-- WAKE 0x%02X"), wakeReason); - debugSerial.println(buf); + debugSerial.print(F("-- WAKE: 0x")); + debugSerial.print(wakeReason, HEX); + debugSerial.println(F("ms")); node->setColor(TTN_GREEN); } @@ -123,8 +123,9 @@ void onButtonRelease(unsigned long duration) { uint32_t timepressed = (uint32_t) duration; - snprintf_P(buf, sizeof(buf), PSTR("-- SEND: BUTTON %d ms"), timepressed); - debugSerial.println(buf); + debugSerial.print(F("-- SEND: BUTTON ")); + debugSerial.print(timepressed); + debugSerial.println(F("ms")); // If button was pressed for more then 2 seconds if (timepressed > 2000) { @@ -174,9 +175,11 @@ void sendData(uint8_t port, uint32_t duration) // If button pressed, send press duration // please myDeviceCayenne add counter value type to // avoid us using analog values to send counters - if (duration) { - snprintf_P(buf, sizeof(buf), PSTR("Btn:\t %dms"), duration); - debugSerial.println(buf); + if (duration) + { + debugSerial.print(F("Button pressed for ")); + debugSerial.print(duration); + debugSerial.println(F("ms")); lpp.addAnalogInput(10, duration/1000.0); } From d5c4d39b0ef6431e1561e5702685819bff413753 Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 4 Mar 2018 16:19:02 +0100 Subject: [PATCH 47/53] removed printf reference requested by johan --- .../BatteryMonitorLPP/BatteryMonitorLPP.ino | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino index 502c38c..d7413ab 100644 --- a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -39,8 +39,6 @@ CayenneLPP lpp(24); uint8_t fport = PORT_SETUP; // LoRaWAN port used -char buf[24]; // For printf - void sendData(uint8_t port=PORT_SETUP, uint32_t duration=0); // This is called on each interval we defined so mainly @@ -48,8 +46,10 @@ void sendData(uint8_t port=PORT_SETUP, uint32_t duration=0); void interval(uint8_t wakeReason) { uint8_t fport = PORT_INTERVAL; - snprintf_P(buf, sizeof(buf), PSTR("-- SEND: INTERVAL 0x%02X"), wakeReason); - debugSerial.println(buf); + + debugSerial.print(F("-- SEND: INTERVAL 0x")); + debugSerial.print(wakeReason, HEX); + debugSerial.println(F("ms")); if (wakeReason&TTN_WAKE_LORA) { @@ -67,42 +67,43 @@ void wake(uint8_t wakeReason) ttn_color ledcolor = TTN_BLACK; uint8_t ledblink = 0 ; - snprintf_P(buf, sizeof(buf), PSTR("-- WAKE 0x%02X"), wakeReason); - debugSerial.println(buf); - - if (wakeReason&(TTN_WAKE_WATCHDOG|TTN_WAKE_INTERVAL)) { + debugSerial.print(F("-- WAKE: 0x")); + debugSerial.print(wakeReason, HEX); + debugSerial.println(F("ms")); + + if (wakeReason & (TTN_WAKE_WATCHDOG | TTN_WAKE_INTERVAL)) { ledcolor = TTN_YELLOW; ledblink = 1; - if (wakeReason&TTN_WAKE_WATCHDOG) { + if (wakeReason & TTN_WAKE_WATCHDOG) { debugSerial.print(F(" Watchdog")); } - if (wakeReason&TTN_WAKE_INTERVAL) { + if (wakeReason & TTN_WAKE_INTERVAL) { debugSerial.print(F(" INTERVAL")); ledblink++; } } - if (wakeReason&TTN_WAKE_LORA) { + if (wakeReason & TTN_WAKE_LORA) { debugSerial.print(F(" LoRa RNxxxx")); ledblink = 1; ledcolor = TTN_GREEN; } - if (wakeReason&TTN_WAKE_BTN_PRESS) { + if (wakeReason & TTN_WAKE_BTN_PRESS) { debugSerial.print(F(" PRESS")); } - if (wakeReason&TTN_WAKE_BTN_RELEASE) { + if (wakeReason & TTN_WAKE_BTN_RELEASE) { debugSerial.print(F(" RELEASE")); } - if (wakeReason&TTN_WAKE_MOTION_START) { + if (wakeReason & TTN_WAKE_MOTION_START) { ledblink = 1; ledcolor = TTN_RED; debugSerial.print(F(" MOTION_START")); } - if (wakeReason&TTN_WAKE_MOTION_STOP) { + if (wakeReason & TTN_WAKE_MOTION_STOP) { ledblink = 2; ledcolor = TTN_RED; debugSerial.print(F(" MOTION_STOP")); } - if (wakeReason&TTN_WAKE_TEMPERATURE) { + if (wakeReason & TTN_WAKE_TEMPERATURE) { debugSerial.print(F(" TEMPERATURE")); } @@ -133,7 +134,7 @@ void onButtonRelease(unsigned long duration) { uint32_t timepressed = (uint32_t) duration; - debugSerial.print(F("-- SEND: BUTTON" )); + debugSerial.print(F("-- SEND: BUTTON: " )); debugSerial.print(timepressed); debugSerial.println(F(" ms")); @@ -165,8 +166,9 @@ void sendData(uint8_t port, uint32_t value) // Read battery voltage volt = node->getBattery(); - snprintf_P(buf, sizeof(buf), PSTR("Bat:\t %dmV"), volt); - debugSerial.println(buf); + debugSerial.print(F("Bat:\t")); + debugSerial.print(volt); + debugSerial.println(F("mV")); lpp.addAnalogInput(4, volt/1000.0); // This one is usefull when battery < 2.5V below reference ADC 2.52V @@ -174,14 +176,16 @@ void sendData(uint8_t port, uint32_t value) // as soon as VCC < 3.3V, // when above 3.3V, since regulator fix 3.3V you should read 3300mV volt = node->getVCC(); - snprintf_P(buf, sizeof(buf), PSTR("Vcc:\t %dmV"), volt); - debugSerial.println(buf); + debugSerial.print(F("Vcc:\t")); + debugSerial.print(volt); + debugSerial.println(F("mV")); lpp.addAnalogInput(5, volt/1000.0); // Read value returned by RN2483 module volt = ttn.getVDD(); - snprintf_P(buf, sizeof(buf), PSTR("Vrn:\t %dmV"), volt); - debugSerial.println(buf); + debugSerial.print(F("Vcc:\t")); + debugSerial.print(volt); + debugSerial.println(F("mV")); lpp.addAnalogInput(6, volt/1000.0); // If button pressed, send press duration @@ -189,8 +193,9 @@ void sendData(uint8_t port, uint32_t value) // avoid us using analog values to send counters if (value) { - snprintf_P(buf, sizeof(buf), PSTR("Button:\t %dms"), value); - debugSerial.println(buf); + debugSerial.print(F("Button pressed for ")); + debugSerial.print(value); + debugSerial.println(F("ms")); lpp.addAnalogInput(10, value/1000.0); } From 58c20047b058f320ca165ec1f27446f1a56fa1cc Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 4 Mar 2018 17:23:24 +0100 Subject: [PATCH 48/53] Clarification about sensor working mode see https://www.thethingsnetwork.org/forum/t/the-things-node-whats-this-3-2ma-sleep-mode-set-to-30ua-now/12521/160 --- docs/TheThingsNode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/TheThingsNode.md b/docs/TheThingsNode.md index c5c6fc4..920ef82 100644 --- a/docs/TheThingsNode.md +++ b/docs/TheThingsNode.md @@ -253,7 +253,7 @@ void configTemperature(bool enabled, MCP9804_Resolution resolution); void configTemperature(bool enabled); ``` -- `bool enabled `: Enable or disable the temperature sensor. Enabled automatically by `onTemperature()`, but you can use this method to temporarily disable the sensor and therefore the alerts. Defaults to `false`. +- `bool enabled `: Enable or disable the temperature sensor ALERTS. Enabled automatically by `onTemperature()`, but you can use this method to temporarily disable the alerts. Defaults to `false`. - `MCP9804_Resolution resolution = R_DEGREES_0_0625 `: Set the resolution (precision) of the sensor. One of: - `R_DEGREES_0_5000`: +0.5 C - `R_DEGREES_0_2500`: +0.25 C From 070e3c06a7a3c95808f1b6ed3fde5a742d186ab9 Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 4 Mar 2018 17:30:35 +0100 Subject: [PATCH 49/53] Updated temp sensor to Low Power --- examples/CayenneLPP/CayenneLPP.ino | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/CayenneLPP/CayenneLPP.ino b/examples/CayenneLPP/CayenneLPP.ino index cd6fc99..8c59e83 100644 --- a/examples/CayenneLPP/CayenneLPP.ino +++ b/examples/CayenneLPP/CayenneLPP.ino @@ -50,7 +50,13 @@ void setup() // Config Node node = TheThingsNode::setup(); node->configLight(true); - node->configTemperature(true); + node->configTemperature(false); // Just read temp, no alert monitoring (Low Power) + + // If you want alerts (200uA to 400uA more consumption) + // node->configTemperature(true); // Alerts below 0C and over 30C and critical to 55C + // node->configTemperature(true, R_DEGREES_0_0625, 15, 25, 50); // Alerts below 15C and over 25C and critical to 50C + // node->onTemperatureAlert(yourAlertCallback); // Your alert callback + node->onWake(wake); node->onInterval(interval); node->onSleep(sleep); From 2f79a3282242c7ff2643f216c7ab2540a3cca852 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 5 Mar 2018 21:45:08 +0100 Subject: [PATCH 50/53] Added delay on wake if temp sensor was in power down mode --- src/TheThingsNode.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/TheThingsNode.cpp b/src/TheThingsNode.cpp index 83974bd..7850225 100644 --- a/src/TheThingsNode.cpp +++ b/src/TheThingsNode.cpp @@ -947,6 +947,14 @@ void TheThingsNode::wakeTemperature() TTN_TEMPERATURE_SENSOR.setMode(MODE_CONTINUOUS); + // If was in powerdown mode, let time to convert temperature + if (!this->temperatureEnabled) + { + // See datasheet 5.2.4 (added 5ms each for security) + uint8_t dly[4] = { 35, 70, 135, 255}; + delay( dly[TTN_TEMPERATURE_SENSOR.getResolution()]); + } + this->temperatureSleep = false; } From 43fd0135d7f9bb4bf60a2a90c98d361471fbab0d Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 6 Mar 2018 14:52:02 +0100 Subject: [PATCH 51/53] fix push button debouncing in IRQ --- src/TheThingsNode.cpp | 49 ++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/TheThingsNode.cpp b/src/TheThingsNode.cpp index 7850225..96b2108 100644 --- a/src/TheThingsNode.cpp +++ b/src/TheThingsNode.cpp @@ -34,15 +34,31 @@ void TTN_MOTION_FN() void TTN_BUTTON_FN() { - uint8_t trigger = getPinChangeInterruptTrigger(digitalPinToPCINT(TTN_BUTTON)); - if (trigger == FALLING) + uint16_t i=2000; // approx 16ms (measured) + int16_t btn=0; + + // This loop duration is about 16 ms + // we are in IRQ, no millis() please, but as this IRQ just wake us + // it does not mind if we take some time, do go for software debouncing + while (i-- > 0 ) + { + // If button read as press we add 1 else we remove 1 + btn += (digitalRead(TTN_BUTTON) == LOW) ? 1 : -1 ; + } + + // Assume button ok if we have enouhgt press/release + if (btn > 500) { wakeStatus |= TTN_WAKE_BTN_PRESS; } - else if (trigger == RISING) + else if (btn < 500) { wakeStatus |= TTN_WAKE_BTN_RELEASE; } + else + { + // Bad press, bounce, interference, ... + } } void TTN_SERIAL_LORA_FN() @@ -120,26 +136,10 @@ void TheThingsNode::loop() { this->buttonPressed = true; - // Check still pressed for at least 10ms - for (uint8_t i=0; i<10; i++) + this->buttonPressedAt = millis(); + if (this->buttonEnabled && this->buttonPressCallback) { - // Soft debouncing - if (digitalRead(TTN_BUTTON)==HIGH) - { - this->buttonPressed = false; - // just in case, this is a bad press - wakeStatus &= ~TTN_WAKE_BTN_RELEASE; - } - delay(1); - } - - if (this->buttonPressed) - { - this->buttonPressedAt = millis(); - if (this->buttonEnabled && this->buttonPressCallback) - { - this->buttonPressCallback(); - } + this->buttonPressCallback(); } } // ACK our IRQ press, now all is in this-> @@ -184,6 +184,7 @@ void TheThingsNode::loop() { this->motionStopCallback(millis() - this->motionStartedAt); } + this->motionStartedAt = 0; this->motionStarted = false; } // ACK our interrupt @@ -235,6 +236,10 @@ void TheThingsNode::loop() // USB is connected and so sleep on USB if (this->isUSBConnected() && !this->USBDeepSleep) { + if (!this->buttonPressed) { + setColor(TTN_BLACK); + } + // Loop until pseudo wake event (because we're not sleeping) or interval while (!(wakeStatus & TTN_WAKE_ANY) && this->intervalMs > TTN_INTERVAL) { From b53521df8614e2c2ada8cf2086c2a47cd8416f26 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 6 Mar 2018 15:00:32 +0100 Subject: [PATCH 52/53] Disable Sleep mode in USB --- examples/CayenneLPP/CayenneLPP.ino | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/examples/CayenneLPP/CayenneLPP.ino b/examples/CayenneLPP/CayenneLPP.ino index 8c59e83..339e60d 100644 --- a/examples/CayenneLPP/CayenneLPP.ino +++ b/examples/CayenneLPP/CayenneLPP.ino @@ -88,7 +88,7 @@ void setup() sendData(PORT_SETUP); // Enable sleep even connected with USB cable - node->configUSB(true); + // node->configUSB(true); } void loop() @@ -107,8 +107,7 @@ void interval(uint8_t wakeReason) void wake(uint8_t wakeReason) { debugSerial.print(F("-- WAKE: 0x")); - debugSerial.print(wakeReason, HEX); - debugSerial.println(F("ms")); + debugSerial.println(wakeReason, HEX); node->setColor(TTN_GREEN); } @@ -121,8 +120,18 @@ void onMotionStart() { node->setColor(TTN_RED); - debugSerial.print("-- SEND: MOTION"); - sendData(PORT_MOTION); + // This move has already been detected + // We need to detect stop motion before sending any new motion + // this avoid flooding network when the device is all time moving + if (node->isMoving()) + { + debugSerial.print("-- STILL MOVING"); + } + else + { + debugSerial.print("-- SEND: START MOTION"); + sendData(PORT_MOTION); + } } void onButtonRelease(unsigned long duration) @@ -161,7 +170,7 @@ void sendData(uint8_t port, uint32_t duration) bat = node->getVCC(); } - // Wake RN2483 + // Wake Lora Module ttn.wake(); printSensors(); From f326e60b9021c5b253f1b5aa126390a116a05fa4 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 6 Mar 2018 15:02:13 +0100 Subject: [PATCH 53/53] Disabled sleep mode in USB --- examples/BatteryMonitorLPP/BatteryMonitorLPP.ino | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino index d7413ab..f50b709 100644 --- a/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino +++ b/examples/BatteryMonitorLPP/BatteryMonitorLPP.ino @@ -49,7 +49,6 @@ void interval(uint8_t wakeReason) debugSerial.print(F("-- SEND: INTERVAL 0x")); debugSerial.print(wakeReason, HEX); - debugSerial.println(F("ms")); if (wakeReason&TTN_WAKE_LORA) { @@ -68,8 +67,7 @@ void wake(uint8_t wakeReason) uint8_t ledblink = 0 ; debugSerial.print(F("-- WAKE: 0x")); - debugSerial.print(wakeReason, HEX); - debugSerial.println(F("ms")); + debugSerial.println(wakeReason, HEX); if (wakeReason & (TTN_WAKE_WATCHDOG | TTN_WAKE_INTERVAL)) { ledcolor = TTN_YELLOW; @@ -257,7 +255,7 @@ void setup() sendData(PORT_SETUP); // Enable sleep even connected with USB cable - node->configUSB(true); + // node->configUSB(true); } void loop()