Understanding Low Power(sleep) handling with LMIC

Hello Terry, guys.

I run through LMIC documentation and managed (was not easy for me as I am new to LoRa) to sending packets over Helium (feather M0 + RFM 868Mhz).

Now I am in the stage to start putting it into sleep. But I can not see any commands about sleep in this library.

Q1. What are the power save methods / strategies with LMIC libraries? As soon as a packet is sent, is LoRa put into low power mode? If no, how to put LoRa into sleep pls?

Q2. I have noticed we are waiting for a DW1 and DW2. I need only one way communication. How to turn off waiting and receiving in DW1 and DW2? It would save 2 seconds of LoRa consumption after each packet. I thought this is already solved and it is standard with LoRa simple sensor transmitters to minimize power consumption.


And one finding as I saw some questions about it.

SF Modes are wrongly mapped - when you set DR_SF7 it is actually SF11
DR_SF8 → SF10
DR_SF11 → SF7

So I am using rather constants EU868_DR_SF7 to EU868_DR_SF11 - here it match.

Terry, why is not allowed EU Wide Band 250kHz in your libraries?
It is valid SF mode for Helium, same as SF12 - which is also not possible to set :

Sorry you’re having trouble. The Helium support was added during the Helium switchover from their proprietary LongFi spec to LoRaWAN. At that time, they only supported US. So I only added US. Since that time, they added regions without me having any way to know – I don’t do Discord or the various other channels that they use for rolling out info.

So, EU isn’t directly supported, but if you use “generic” and if Helium is really LoRaWAN compliant, it should work fine.

The DR and SF stuff is very confusing, and it’s possible that there’s a typo in the EU headers, but remember that DRs ascend from a region-specific base spreading factor; as DRs go up, SFs decrease. In particular:

  • DR0 is SF12 in Europe, but DR is SF10 the US. So you can’t portably use DRs to get SFs.
  • The APIs essentially all use DRs, not SFs. So it’s hard to portably inject a spreading factor.
  • The name DR_SF10 is region specific; it is supposed to give you the DR to use to get SF10. It’s equal to 0 in the US region, and equal to 2 in the EU region.
  • I test with LoRaWAN compliance tests, and things pass

In LoRaWAN, devices are supposed to do what the network tells them. If the network tells to be LMIC to use 250kHz, it will do so. It is very much network specific as to what will work if you manually define a channel. And if you manually define a channel and then the network sends a MAC message that overrides it, the LMIC follows the network (per the spec).

In LoRaWAN EU-like regions, you can’t change the default channels (channels 0, 1 and 2 in EU-868) – the spec specifically forbids it. It turns out to be less code to simply nail them down (rather than preventing the network test from changing the channels, but allowing the user to change them).

The library is targeting LoRaWAN compliance (because that’s the only sane way to test and get interoperability). For this reason, there is no way to disable the RX windows in the library, and none is planned. Even if you don’t plan to receive application data, your device is required to listen to network MAC downlink messages. In fact, an OTAA device that doesn’t handle normal downlinks won’t work well on many networks, because the network changes parameters using MAC downlink messages.

Sleep is a big topic, because you have to open the RX1 and Rx2 windows at the right time; and if the network is deciding to send you configuration information, the LMIC has no choice but to (a) reply acknowledging the downlink (b) then open another Rx1/Rx2 pair which the network may use to send additional info. I’ve seen networks send 4 to 5 MAC downlinks in a row.

Therefore the way to handle sleep is to wait for the LMIC to go idle, and then go to sleep. When you wake up, it is a good idea to adjust the Arduino millis() result to reflect the time that has passed, because you really don’t know what the LMIC is doing; it needs to know the time in Europe in order to honor the duty cycle limitations.

On the Adafruit, updating millis() after sleep is hard because the BSP doesn’t support it. MCCI has a modified BSP for the M0 that adds the required API. If you look at our samples for the MCCI Catena 4450 (which uses a Feather M0 LoRa as the base engine), you’ll see how we do it.

This library is hard to use because it has hard-real-time constraints while running in an Arduino environment; the only way to meet the constraints is to write careful code everywhere else and poll the library frequently enough to meet the constraints.

So… very sorry you’re having troubles. I understand how frustrating it is. Feel free to test and file PRs.

Best regards,