Closed Dardrai closed 4 years ago
The best "low Power" sketch that I had (used around 14% Battery in 6 Day's and sends every 5 min)
if (EV_TXCOMPLETE == message) {
DEBUG_PORT.println(F("EV_TXCOMPLETE"));
delay(SLEEP_DELAY); // SLEEP HERE!
}
void loop() {
// Send every TX_INTERVAL millis
static uint32_t last = 0;
if (0 == last || millis() - last > SLEEP_DELAY) {
last = millis();
send();
}
ttn_loop();
}
Is this also suitable for the lmic Library or what whould be the best way to cut the power consumption in half?
Update: Tried the new Version 3.1.0 again - but the NRF doesn't work well with new Version?
After reverting back to Version 3.0.99 and downgrading the running sketch everything works as expected - NRF goes Online and send his data, Device can be programed and watch via the serial Monitor etc.
Again thank you for your help
Kind regards
David
There were no changes that should affect this. My only suggestion is to use git bisect
to find the commit that broke things.
By the way (everyone) - please do not combine issues in one ticket. @dardrai, please file a new ticket for the 3.1.0 regression, and I'll comment further there. Meanwhile...
For low power, you must use the low power sleep feature of your CPU. Generally, one must avoid using delay()
, as this is a high-power sleep.
Hopefully it is ok to ask about deepsleep in this thread. I am adapting https://github.com/cyberman54/ESP32-Paxcounter to do deepsleep on a TTGOv2, and am successful with sleeping and waking with a new join after sleep (not good practice), but when I try accessing the up and down counters to prep a save and restore for rejoining I get a panic. Reading the forums I see there are some hooks for working with the lorawan parameters. Can you link to a good example I could reference to do such a rejoin? Many thanks for your great code and work. - Mike
It's fine but... generally it's easier to manage (because I know when to close the issue), if we please open new issues for new questions.
If you check https://github.com/mcci-catena/arduino-lorawan, you will see the code that MCCI uses to save and restore the session. It's still somewhat imperfect, but I would rather we all focus on improving that base than re-implementing every time. (If you dig through https://github.com/mcci-catena/Catena-Arduino-Platform, you'll see how we store the session data to FRAM.)
It is a very bad idea to access the LMIC contents directly. When we add class C support, SX1262 support, multicast, etc., the LMIC contents and what you have to save will need to change. Please use a library. I'd merge the arduino-lorawan library with this, but... for now it's separate.
@terrillmoore where would you add the designated code to go to a sleep state? Would you add it somewhere in the switch state (e.g. when the EV_TXCOMPLETE is catched)? Or would you let it run through os_runloop_once(); - let lmic finish everything something like this?
void timer_callback(TimerHandle_t _handle) { send(); for(int i = 0; i < 4000; i++){ os_runloop_once(); } Sleep(5min); }
For low power, you must use the low power sleep feature of your CPU. Generally, one must avoid using
delay()
, as this is a high-power sleep.
In generall yes - for nrf52 with freeRTOS not necessary.
But where have you @terrillmoore added the sleeping codes/function in your sketches that should save as much power as possible?
Hi Lmic team I have a question about the Lmic Lib in connection with the NRF52840 express.
I use atm the: mcci-catena/arduino-lmic version 3.0.99 I couldn't test version 3.1 successfully yet, had some issue with connection to the Lora Backend, but that could be an other problem with TTN or the Gateway
In Short I have a NRF52840 express (Code Runner) FeatherWing RFM95W (LoraWan Module) 2000mAh Battery
One Device should run for around 180 Days with only one charge, but at the moment, the Device is using to much power. How could I Improve the Power consumption on my sketch/template? Full Application here: template_n-NRF52.zip
"Main Class":
include "configuration.h"
include
include
CayenneLPP lpp(51); static osjob_t sendjob; uint32_t count = 0;
// ----------------------------------------------------------------------------- // Application // // Create Send Job // ----------------------------------------------------------------------------- void sendMessage(osjob_t* j) { getSensorDataToLPP();
if LORAWAN_CONFIRMED_EVERY > 0
bool confirmed = (count % LORAWAN_CONFIRMED_EVERY == 0);
else
bool confirmed = false;
endif
ttn_cnt(count); ttn_send(lpp.getBuffer(), lpp.getSize(), LORAWAN_PORT, confirmed);
count++; }
// ----------------------------------------------------------------------------- // Add Sesnor Data to LPP Payload // ----------------------------------------------------------------------------- void getSensorDataToLPP() { float vbat_mv = readVBAT(); lpp.reset(); lpp.addVoltage(0, convertToVoltage(vbat_mv)); lpp.addPercentage(0, mvToPercent(vbat_mv)); lpp.addTemperature(1, getTempData()); lpp.addRelativeHumidity(2, getHumidityData());
ifdef DEBUG_PORT
DEBUG_PORT.print("Volt: "); DEBUG_PORT.println(convertToVoltage(vbat_mv)); DEBUG_PORT.print("Percent: "); DEBUG_PORT.println(mvToPercent(vbat_mv)); DEBUG_PORT.print("Temperature: "); DEBUG_PORT.println(getTempData()); DEBUG_PORT.print("Humidity: "); DEBUG_PORT.println(getHumidityData());
endif
}
// ----------------------------------------------------------------------------- // Shedule Next Send // ----------------------------------------------------------------------------- void scheduleNextSend() { os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), sendMessage); }
// ----------------------------------------------------------------------------- // Callback // ----------------------------------------------------------------------------- void callback(uint8_t message) {
if (EV_TXCOMPLETE == message) {
ifdef DEBUG_PORT
endif
//like delay(sec2osticks(TX_INTERVAL));** }
if (EV_RESPONSE == message) {
ifdef DEBUG_PORT
endif
}
ifdef DEBUG_PORT
if (message != NULL ) { DEBUG_PORT.print("Message Code: "); DEBUG_PORT.println(message); }
endif
}
// ----------------------------------------------------------------------------- // Setup // ----------------------------------------------------------------------------- void setup() { delay(100); initSensor();
ifdef DEBUG_PORT
DEBUG_PORT.begin(SERIAL_BAUD);
endif
// TTN setup if (!ttn_setup()) { delay(MESSAGE_TO_SLEEP_DELAY); }
ttn_register(callback); ttn_join(); ttn_sf(LORAWAN_SF); ttn_adr(LORAWAN_ADR);
sendMessage(&sendjob); }
// ----------------------------------------------------------------------------- // Loop // ----------------------------------------------------------------------------- void loop() { ttn_loop(); }
Important note the NRF52840 express has a FreeRTOS Kernal implemented so if I use a delay() the delay is equal to sleep! Another way to get the NRF52840 in a much more low power state would be if I could change this "main class" to a loopless class like this example (register Callbacks etc): https://github.com/MacGyverNL/Adafruit_nRF52_Arduino/blob/LowPower_examples/libraries/Bluefruit52Lib/examples/LowPower/Blink_loopless/Blink_loopless.ino
But if I try this I'm not shure how i should start the lmic process then and register the callback so the lmic will send again and again.
"Main Class Loopless"
include "configuration.h"
include
include
CayenneLPP lpp(51); static osjob_t sendjob; uint32_t count = 0;
SoftwareTimer lorawan_timer;
// ----------------------------------------------------------------------------- // Application // // Create Send Job // ----------------------------------------------------------------------------- void sendMessage(osjob_t* j) { getSensorDataToLPP();
if LORAWAN_CONFIRMED_EVERY > 0
bool confirmed = (count % LORAWAN_CONFIRMED_EVERY == 0);
else
bool confirmed = false;
endif
ttn_cnt(count); ttn_send(lpp.getBuffer(), lpp.getSize(), LORAWAN_PORT, confirmed);
count++; }
// ----------------------------------------------------------------------------- // Add Sesnor Data to LPP Payload // ----------------------------------------------------------------------------- void getSensorDataToLPP() { float vbat_mv = readVBAT(); lpp.reset(); lpp.addVoltage(0, convertToVoltage(vbat_mv)); lpp.addPercentage(0, mvToPercent(vbat_mv)); lpp.addTemperature(1, getTempData()); lpp.addRelativeHumidity(2, getHumidityData());
ifdef DEBUG_PORT
DEBUG_PORT.print("Volt: "); DEBUG_PORT.println(convertToVoltage(vbat_mv)); DEBUG_PORT.print("Percent: "); DEBUG_PORT.println(mvToPercent(vbat_mv)); DEBUG_PORT.print("Temperature: "); DEBUG_PORT.println(getTempData()); DEBUG_PORT.print("Humidity: "); DEBUG_PORT.println(getHumidityData());
endif
}
// ----------------------------------------------------------------------------- // Shedule Next Send // ----------------------------------------------------------------------------- void scheduleNextSend() { //os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), sendMessage); }
// ----------------------------------------------------------------------------- // Callback // ----------------------------------------------------------------------------- void callback(uint8_t message) {
if (EV_TXCOMPLETE == message) {
ifdef DEBUG_PORT
endif
}
if (EV_RESPONSE == message) {
ifdef DEBUG_PORT
endif
}
ifdef DEBUG_PORT
if (message != NULL ) { DEBUG_PORT.print("Message Code: "); DEBUG_PORT.println(message); }
endif
}
// ----------------------------------------------------------------------------- // Setup // ----------------------------------------------------------------------------- void setup() { delay(100); initSensor();
ifdef DEBUG_PORT
DEBUG_PORT.begin(SERIAL_BAUD);
endif
// TTN setup if (!ttn_setup()) { delay(MESSAGE_TO_SLEEP_DELAY); }
ttn_register(callback); ttn_join(); ttn_sf(LORAWAN_SF); ttn_adr(LORAWAN_ADR);
//sendMessage(&sendjob);
lorawan_timer.begin(1500, timer_callback); lorawan_timer.start();
sendMessage(&sendjob); suspendLoop();
}
// ----------------------------------------------------------------------------- // Loop // ----------------------------------------------------------------------------- void timer_callback(TimerHandle_t _handle) { ttn_loop(); }
void loop (){} If I use the code above (loopless one) I only receive auth request on the TTN Portal, but the NRF don't send any data to the backend.
Thank you for your help and keep up the great work!