Skip to content

Commit 187e12d

Browse files
Merge pull request #13 from TheThingsNetwork/feature/low-power-mode
Low power mode example
2 parents 832a9b5 + 2c46b25 commit 187e12d

File tree

6 files changed

+203
-10
lines changed

6 files changed

+203
-10
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ before_install:
1111
- sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino
1212
install:
1313
- ln -s $PWD /usr/local/share/arduino/libraries/TheThingsNode
14-
- arduino --install-library "DHT sensor library:1.3.0,Adafruit Unified Sensor:1.0.2,TheThingsNetwork:2.3.1"
14+
- arduino --install-library "DHT sensor library:1.3.0,Adafruit Unified Sensor:1.0.2,TheThingsNetwork:2.5.6"
1515
- git clone https://github.com/sparkfun/arduino_boards /tmp/sparkfun
1616
- mv /tmp/sparkfun/sparkfun /usr/local/share/arduino/hardware/sparkfun
1717
before_script:

docs/TheThingsNode.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ void sleep() {
8181
}
8282
```
8383

84+
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.
85+
Check the example [BatteryMonitorLPP](../examples/BatteryMonitorLPP/)
86+
8487
## Interval
8588
Instead of using your `loop()` function, use `configInterval()` and `onInterval()` to set a function to be called on a certain interval:
8689

examples/Basic/Basic.ino

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ void onButtonRelease(unsigned long duration)
118118

119119
void sendData(uint8_t port)
120120
{
121+
// Wake RN2483
122+
ttn.wake();
123+
121124
ttn.showStatus();
122125
node->showStatus();
123126

@@ -140,4 +143,11 @@ void sendData(uint8_t port)
140143
payload[5] = bytes[0];
141144

142145
ttn.sendBytes(payload, sizeof(payload), port);
146+
147+
// Set RN2483 to sleep mode
148+
ttn.sleep(60000);
149+
150+
// This one is not optionnal, remove it
151+
// and say bye bye to RN2983 sleep mode
152+
delay(50);
143153
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#include <TheThingsNode.h>
2+
#include <TheThingsNetwork.h>
3+
#include <CayenneLPP.h>
4+
5+
// Set your AppEUI and AppKey
6+
const char *appEui = "0000000000000000";
7+
const char *appKey = "00000000000000000000000000000000";
8+
9+
// Replace REPLACE_ME with TTN_FP_EU868 or TTN_FP_US915
10+
#define freqPlan REPLACE_ME
11+
12+
#define loraSerial Serial1
13+
#define debugSerial Serial
14+
15+
TheThingsNetwork ttn(loraSerial, debugSerial, freqPlan);
16+
TheThingsNode *node;
17+
CayenneLPP lpp(16);
18+
19+
#define PORT_SETUP 1
20+
#define PORT_INTERVAL 2
21+
#define PORT_MOTION 3
22+
#define PORT_BUTTON 4
23+
24+
// Interval between send in seconds, so 300s = 5min
25+
#define CONFIG_INTERVAL ((uint32_t) 300)
26+
27+
void sendData(uint8_t port = PORT_SETUP, uint32_t duration = 0);
28+
29+
// This is called on each interval we defined so mainly
30+
// this is where we need to do our job
31+
void interval()
32+
{
33+
node->setColor(TTN_BLUE);
34+
debugSerial.println(F("-- SEND: INTERVAL"));
35+
sendData(PORT_INTERVAL);
36+
}
37+
38+
// This is called on each wake, every 8S or by an sensor/button interrupt
39+
// if it's watchdog, we mainly do nothing (core IRQ, we don't have choice)
40+
// but if it's an interupt it will ne bone ine loop
41+
void wake()
42+
{
43+
debugSerial.println(F("-- WAKE"));
44+
45+
// Just if you want to see this IRQ with a LED, remove for LOW power
46+
//node->setColor(TTN_GREEN);
47+
//delay(50);
48+
//node->setColor(TTN_BLACK);
49+
//delay(100);
50+
}
51+
52+
void sleep()
53+
{
54+
node->setColor(TTN_BLACK);
55+
56+
// Just in case, disable all sensors
57+
// this couldn't hurt except time to do job
58+
node->configMotion(false);
59+
node->configLight(false);
60+
node->configTemperature(false);
61+
}
62+
63+
void onButtonRelease(unsigned long duration)
64+
{
65+
uint16_t adc_value;
66+
uint32_t timepressed = (uint32_t) duration;
67+
68+
node->setColor(TTN_BLUE);
69+
70+
debugSerial.print(F("-- SEND: BUTTON "));
71+
debugSerial.print(timepressed);
72+
debugSerial.println(F(" ms"));
73+
74+
sendData(PORT_BUTTON, timepressed);
75+
}
76+
77+
void sendData(uint8_t port, uint32_t value)
78+
{
79+
// Wake RN2483
80+
ttn.wake();
81+
82+
// Read battery voltage
83+
uint16_t vbat = node->getBattery();
84+
85+
debugSerial.print(F("Battery:\t"));
86+
debugSerial.print(vbat);
87+
debugSerial.println(F("mV"));
88+
89+
// Just send battery voltage
90+
lpp.reset();
91+
lpp.addAnalogInput(4, vbat/1000.0);
92+
93+
// If button pressed, send press duration
94+
// please myDeviceCayenne add counter value type to
95+
// avoid us using analog values to send counters
96+
if (port == PORT_BUTTON) {
97+
debugSerial.print(F("Button:\t"));
98+
debugSerial.print(value);
99+
debugSerial.println(F("ms"));
100+
lpp.addAnalogInput(7, value / 1000.0);
101+
}
102+
103+
ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port);
104+
105+
// Set RN2483 to sleep mode
106+
ttn.sleep(CONFIG_INTERVAL * 1000);
107+
108+
// This one is not optionnal, remove it
109+
// and say bye bye to RN2983 sleep mode
110+
delay(50);
111+
}
112+
113+
void setup()
114+
{
115+
loraSerial.begin(57600);
116+
debugSerial.begin(9600);
117+
118+
// Wait a maximum of 10s for Serial Monitor
119+
while (!debugSerial && millis() < 10000)
120+
;
121+
122+
// Config Node, Disable all sensors
123+
// Check node schematics here
124+
// https://github.com/TheThingsProducts/node
125+
node = TheThingsNode::setup();
126+
127+
// Each interval
128+
node->configInterval(true, CONFIG_INTERVAL*1000);
129+
node->onWake(wake);
130+
node->onInterval(interval);
131+
node->onSleep(sleep);
132+
133+
// We monitor just button release
134+
node->onButtonRelease(onButtonRelease);
135+
136+
// Test sensors and set LED to GREEN if it works
137+
node->showStatus();
138+
node->setColor(TTN_GREEN);
139+
140+
debugSerial.println(F("-- TTN: STATUS"));
141+
ttn.showStatus();
142+
143+
debugSerial.println(F("-- TTN: JOIN"));
144+
ttn.join(appEui, appKey);
145+
146+
debugSerial.println(F("-- SEND: SETUP"));
147+
sendData(PORT_SETUP);
148+
}
149+
150+
void loop()
151+
{
152+
node->loop();
153+
}

examples/CayenneLPP/CayenneLPP.ino

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ void onButtonRelease(unsigned long duration)
9797

9898
void sendData(uint8_t port)
9999
{
100+
101+
// Wake RN2483
102+
ttn.wake();
103+
100104
printSensors();
101105

102106
lpp.reset();
@@ -112,6 +116,9 @@ void sendData(uint8_t port)
112116
lpp.addAccelerometer(7, x, y, z);
113117

114118
ttn.sendBytes(lpp.getBuffer(), lpp.getSize(), port);
119+
120+
// Set RN module to sleep mode
121+
ttn.sleep(60000);
115122
}
116123

117124
void printSensors()

src/TheThingsNode.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define TTN_GREEN_LED 5
1212
#define TTN_BLUE_LED 6
1313
#define TTN_BUTTON 16
14+
#define TTN_LORA_RESET 21
1415
#define TTN_VBAT_MEAS_EN A2
1516
#define TTN_VBAT_MEAS 1
1617
#define TTN_TEMPERATURE_SENSOR_ADDRESS 0x18
@@ -41,12 +42,12 @@
4142

4243
Hackscribble_MCP9804 TTN_TEMPERATURE_SENSOR(TTN_TEMPERATURE_SENSOR_ADDRESS);
4344

44-
bool TTN_TEMPERATURE = false;
45-
bool TTN_MOTION_START = false;
46-
bool TTN_MOTION_STOP = false;
47-
bool TTN_BUTTON_PRESS = false;
48-
bool TTN_BUTTON_RELEASE = false;
49-
uint32_t TTN_INTERVAL = 0;
45+
volatile bool TTN_TEMPERATURE = false;
46+
volatile bool TTN_MOTION_START = false;
47+
volatile bool TTN_MOTION_STOP = false;
48+
volatile bool TTN_BUTTON_PRESS = false;
49+
volatile bool TTN_BUTTON_RELEASE = false;
50+
volatile uint32_t TTN_INTERVAL = 0;
5051

5152
void TTN_TEMPERATURE_FN()
5253
{
@@ -74,7 +75,9 @@ void TTN_BUTTON_FN()
7475
{
7576
TTN_BUTTON_PRESS = true;
7677
}
77-
else if (trigger == RISING)
78+
79+
// Be sure main loop ACK press button before rising the release
80+
if (TTN_BUTTON_PRESS == false && trigger == RISING )
7881
{
7982
TTN_BUTTON_RELEASE = true;
8083
}
@@ -217,8 +220,16 @@ void TheThingsNode::loop()
217220
}
218221
else
219222
{
220-
Serial.flush();
221-
deepSleep();
223+
// Don't go to sleep mode while button is still pressed
224+
// because if so, timer of ms will be stopped and duration
225+
// of pressed button will not work
226+
if (this->buttonPressed) {
227+
delay(100);
228+
TTN_INTERVAL = TTN_INTERVAL + 100;
229+
} else {
230+
Serial.flush();
231+
deepSleep();
232+
}
222233
}
223234
}
224235

@@ -737,6 +748,15 @@ TheThingsNode::TheThingsNode()
737748
pinMode(TTN_BLUE_LED, OUTPUT);
738749
setColor(TTN_BLACK);
739750

751+
// hardware reset of LoRa module, so module is reset on sketch upload
752+
#ifdef TTN_LORA_RESET
753+
pinMode(TTN_LORA_RESET, OUTPUT);
754+
digitalWrite(TTN_LORA_RESET, LOW);
755+
delay(100);
756+
digitalWrite(TTN_LORA_RESET, HIGH);
757+
#endif
758+
759+
740760
// TODO: Can we enable/disable this at will to save memory?
741761
USBCON |= (1 << OTGPADE);
742762

0 commit comments

Comments
 (0)