WiFi LoRa 32 V3: Send sensor data via LoRa, then go back to deep sleep

So, I decided to take a look at the LoRaWAN_APP.cpp file: https://github.com/Heltec-Aaron-Lee/WiFi_Kit_series/blob/master/esp32/libraries/LoraWan102/src/LoRaWan_APP.cpp

  • If the LoRaWAN join request was successful, the state is changed to “sleep”. (I can already see that in my code, and it makes sense.)
  • In the sleep function, the following two lines of code are called: Radio.IrqProcess( ); Mcu.sleep(classMode,debugLevel);, which - to my understanding - sends an interrupt process for the radio and then puts the MCU to sleep.
  • In line 757 of the code, there is void LoRaWanClass::displayAck(), which at some point calls display.drawString(28, 50, "Into deep sleep in 2S"); – which tells me that deep sleep should be possible.

However, I’m still unsure how to incorporate any deep sleep resources into my code. Thank you in advance for the help.

Ah, we’re really getting somewhere here! Good research.
You might be able to make your life easy: create a bool at the beginning of your program that is set to false; set it to true when a message is sent (after the LoRaWAN.send()), and in the loop, only go to deepsleep once this boolean is set… would that work?

1 Like

Thank you for your reply.

I added bool messageSent = false; before static void prepareTxFrame( uint8_t port ), then under case DEVICE_STATE_SEND: I added messageSent = true; right after LoRaWAN.send();.

For entering the deep sleep dependent on this parameter, I am thinking of using this if statement:

#if(messageSent == true)
    esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
    esp_deep_sleep_start();
#endif

I added that statement in case DEVICE_STATE_SLEEP: right after LoRaWAN.sleep(loraWanClass); – looking at my TTN live data, the data is going through. I’m just not sure if it’s actually because the device enters deep sleep or if the code is skipping past that statement – if I look at the time stamps on my TTN data, it sends every 15 seconds (duty cycle defined in uint32_t appTxDutyCycle = 15000;) but I do not see the 30 seconds of sleep time defined by #define uS_TO_S_FACTOR 1000000ULL (conversion factor) and #define TIME_TO_SLEEP 30 (sleep time in sec).

Here is what my code looks like now: https://github.com/JuliaSteiwer/IoT-Water-Quality-Monitoring/blob/main/deepSleep_staticValues_v2.ino

Don’t use #if-statements, the # tells that this statement should be checked when your code is actually being compiled - rather than during code execution! You should just use a simple normal if-statement:

if (messageSent == true) {
    esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
    esp_deep_sleep_start();
}
1 Like

Thank you for telling me this; while I know that C++ takes normal if statements, I thought the one with # was merely a different writing style for the Arduino IDE, my bad.

I changed things in the code, I just cannot test it atm because my LoRa gateway is at home, I’m currently at a train station like 25km away, and due to work I will stay at my apartment until perhaps even Saturday (yes, a train strike again) … I might be able to check it tomorrow at work because we have LoRa gateways there as well. I’ll test it and then report back here,

1 Like

@bns I tested the updated code today but the problem persists. The device sends data once when I play the code onto the device, then it (seemingly) enters deep sleep, and does not send any data anymore after (it still prints them out to the serial monitor, they just do not appear in the live data of my application).

Looking at the serial monitor though, the device prints out data, goes to sleep for 30 seconds (as defined), and then wakes up to send data again, before going back to sleep again. Below you can see what the serial monitor prints out.

15:54:41.779 -> going to sleep
15:55:11.754 -> ESP-ROM:esp32s3-20210327
15:55:11.754 -> Build:Mar 27 2021
15:55:11.754 -> rst:0x5 (DSLEEP),boot:0x29 (SPI_FAST_FLASH_BOOT)
15:55:11.754 -> pro cpu reset by JTAG
15:55:11.754 -> SPIWP:0xee
15:55:11.754 -> mode:DIO, clock div:1
15:55:11.754 -> load:0x3fce3808,len:0x43c
15:55:11.786 -> load:0x403c9700,len:0xbec
15:55:11.786 -> load:0x403cc700,len:0x2a3c
15:55:11.786 -> SHA-256 comparison failed:
15:55:11.786 -> Calculated: dcde8d8a4817d9bf5d5d69a7247667264e4e10ac7493514868b61f5aa6146539
15:55:11.786 -> Expected: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
15:55:11.786 -> Attempting to boot anyway...
15:55:11.786 -> entry 0x403c98d8
15:55:12.215 -> temperature: 22.55 | humidity: 72.50
15:55:12.215 -> confirmed uplink sending ...
15:55:12.248 -> sent data
15:55:12.248 -> enter sleep state. zzz
15:55:12.248 -> going to sleep

However, in TTN, I cannot see the new data. There, I only get data once (when the code is played to the device or when I hit the reset button), and then never again.

I tried adding a delay before changing to the sleep state in case the time is too short for sending, but that does not work. Going into light sleep instead of deep sleep does not fix the issue either. What I did notice though is that, as of right now, I only set the boolean for the sent message to true just like that, instead of checking if LoRaWAN.send() was actually successful or not. Also, I feel that something in the LoRaWAN_APP.h library bites itself with the esp_ commands.

Below is what I found regarding ESP in the LoRaWAN library:
For void LoRaWanClass::generateDeveuiByChipID() (line 483), there is

#if defined(ESP_PLATFORM)
	uint64_t id = getID();
	uniqueId[0]=(uint32_t)(id>>32);
	uniqueId[1]=(uint32_t)id;
#endif

In line 678, there is #ifndef ESP_PLATFORM, which apparently skips join when the saved network info is okay. The header file for the library also calls the libraries ESP32_Mcu.h and ESP32_LoRaWan_102.h. There is a cross-call to the esp_sleep.h library, but there I do not find anything that could cause issues with LoRaWAN.

Do you have any idea why this happens and how I could fix this issue?

Thank you in advance for your reply!

Two options:

  1. we try to get this working, which means we need to get access to a gateway console on TTN that shows data passing through. It may now be the case that your device is actually uplinking but e.g. with resetting frame counter. We’ll also need to know what version you set your device to on the TTN console.
  2. we switch to RadioLib which I know by heart (since I built its LoRaWAN stack lol).
1 Like

Hi Steven,

on my GitHub repo, user FritzOS opened an issue where he provided me with his code for communicating with TTN and sending the device to deep sleep (you can find the issue here). I tested it with some static data, and that worked just fine.

On the weekend, I will test it with my sensors, just to see if that behaves as expected or if there might be some unexpected errors. I will post an update here when that works.

Thank you so much for the help you have been offering; it has pushed both me and my knowledge of the subject further and I am truly thankful!

1 Like

@jsteiwer Thank you so much for that link, I really appreciate it. This solved so many of the issues I was having. Between this and what @bns put together I’ve finally got payloads coming through.

Steps I took:
Updating to 0.0.9
Manually configure the pinmap
Configure the channelmask

The link you posted Works on Chirpstack LNS as well once I made some adjustments.

You’re both a huge help! Thanks again! I don’t think @nmcc can bully me here so I’m safe to discuss :wink:

1 Like

No one was bullying you - you just weren’t able to follow the TTN forum guidelines - but I can flag your post for being an inappropriate personal attack because here I’m a user which has nothing to do with being a moderator on TTN which is a distinct and separate role. Without this, the technical forums would disintegrate rather quickly.

1 Like

Yeah, the wink was to indicate a light hearted joke but you do you…

Sure, be a winker, but I burn through hours every week just moderating - @bns teaches, I mentor - that’s where the fun is, getting people to success - being a forum cop is frankly draining.

@jsteiwer, sorry for this detour. I’d highly recommend you take RadioLib 6.3.0, do nothing other than get a TTN connection going as @colinmcmahon has, party :partying_face:, and then add in the sensor code, one sensor at a time. You may also find that https://www.thethingsnetwork.org/docs/lorawan/ will fill in any gaps in the LoRaWAN side of things - takes a couple hours to read - don’t watch Johan’s video until you’ve read the material and even then, don’t watch it all in one go.

Moderators: happy to drop the flag, let’s move on to making something great.

3 Likes

@nmcc This is probably a good example of everyone being at the redline all at the same time. If you’re smashing your face against the screen moderating, and I’m smashing my face against the screen trying to debug code, nobody is at their best. I was just sad because I finally found the handful of people in the world working with the the same hardware/software as me and all I wanted to do was help :confused: I’ve spent more time and money than I care to admit trying to prove a concept I feel is going to change the world so I’m absolutely not carrying myself as well as I should. @jsteiwer I’m sorry as well for the drama :sweat_smile: I’m sure whoever comes across this soap opera will have a wholesome giggle.

also this ↓ ↓

Hi, thank you very much for the suggestions.

I actually already have a working code that sends my sensor data to TTN, my main issue was just that I couldn’t get the deep sleep to work properly. Now that @/FritzOS from GitHub has provided me with a working code that continues sending after waking up from deep sleep, I should be able to make everything work just by adding my sensor code in. With static values, it already works, and the key differences between the static values and the sensor data are some libraries, some parameter definitions, and then function calls – I think it is manageable.

Once I got it working, I will report back here, so everyone knows that/if it also works with a sensor suite. I will also upload that code to my GitHub again so all users can profit of that.

2 Likes

Okay kings, I have tested the code with my sensors, and it works fine! I will test it with a 2200mAh battery later, to see how long it will now last me. Anyways, here is the code:

The only thing that is bothering me right now is the electrical conductivity (EC) sensor. DFRobot (the manufacturer) provides a library for calculating the EC value based on voltage and temperature. Currently, the sensor only ever shows 0.00 - on an Arduino UNO, it shows the right values. I have printed out the result from analogRead and the calculated voltage, and for both I get reasonable values, so I assume there is an issue with the calculation in the EC library.

According to their GitHub repo (find it here), they have not yet tested compatibility for the Heltec WiFi LoRa V3 board, or any board from Heltec for that matter. I checked the .cpp file, and there’s this line executed during compilation that says #if ARDUINO >= 100 (line 15 in the code). However, I could not yet figure out what exactly in the code clashes with my board. If any of you has an idea how this issue could be fixed, I’d appreciate it a lot if you could share these ideas.

Okay, looking a little deeper into the code:

float DFRobot_EC::readEC(float voltage, float temperature)
{
    float value = 0,valueTemp = 0;
    this->_rawEC = 1000*voltage/RES2/ECREF;
    valueTemp = this->_rawEC * this->_kvalue;
    //automatic shift process
    //First Range:(0,2); Second Range:(2,20)
    if(valueTemp > 2.5){
        this->_kvalue = this->_kvalueHigh;
    }else if(valueTemp < 2.0){
        this->_kvalue = this->_kvalueLow;
    }

    value = this->_rawEC * this->_kvalue;             //calculate the EC value after automatic shift
    value = value / (1.0+0.0185*(temperature-25.0));  //temperature compensation
    this->_ecvalue = value;                           //store the EC value for Serial CMD calibration
    return value;
}

Above is the code that is called with the function .readEC() (defined in the .cpp file). We got #define RES2 820.0 and #define ECREF 200.0 to set _rawEC. I also found this->_kvalue = 1.0;. Lets see if I can do something with that.

Thank you in advance for your replies!

Update: It’s working properly now! :blush:
Update 2: Now with the battery it’s not working anymore :frowning:

They haven’t tested a few hundred potential boards, so I wouldn’t worry about the absence of your particular board - Arduino eco system is mostly compatible across the board at a basic level like this.

If it works OK on USB power but not battery, you are probably suffering from power droop where the sensor is not getting enough volts &/or current. How are you powering on battery?

I have a breadboard where I have my battery, sensors, and controller board connected to. I wanted to check if the issue might be on the technical side, so I measured the voltage.

It appears that the issue might have been caused by the water just being “too clean” (we have very hard water here but otherwise it’s free of salts or pollutants). At the 5V pin of the sensor converter board, I measured 5V, and at the analog pin I measured 0.2V for tap water. I then created a salty solution (literally smells like sea water :woozy_face:) and put the sensor in there, that got me 3.24V on the analog pin (max output of the sensor is 3.4V).

Below you can find an image that shows the last measured value of my sensor (when I put it in the salty solution) with the spike in the measurements.

So it seems that my setup is okay, the sensor is getting full power, the code is correct, and the issue was entirely because of the water not having enough ions. I hope this was the only reason and that there isn’t some hidden issue somewhere left that gets me at a later point.

Thank you for taking your time to reply!


Sometimes, the EC will still only show 0.00, even when in the saline solution. I don’t know if this is because the salt fell out to the bottom or if it’s a sensor issue – I know that this sensor is more lab grade which means technically it’s not supposed to be in the water all the time, but this behavior is still odd.

Next week (KW4) we will supposedly have positive temperatures even at night, then I should try the sensor suite in one of our ponds, maybe there the EC won’t fall to 0.00 – in the meantime, I’m happy for any ideas why I might get these weird results.

@nmcc @colinmcmahon @bns

Sorry to tag you this directly, but I tested the code again, this time by powering the sensors via the Ve pin.

The setup is like this:
The Heltec board is powered via USB-C cable from the Laptop (-> I face the same issue when powering with a battery), and the outputs of the sensors are connected to the pins on the Heltec board. The GND and Ve pin of the Heltec board are connected to a step-up converter that increases the 3.3V input of the board to an output of 5V to supply the sensors. The GND and 5V output connections of the step-up are connected to a breadboard where the GND and 5V pins of the sensors are plugged into.

Now, I face the following problem: The board does not go into deep sleep at all.
Right after the display tells me “Into deep sleep in 2s”, the screen turns black for maybe a second before trying to join TTN again. The sensors also remain powered on the whole time, while I had hoped that powering them with Ve would mean they also turn off during deep sleep.

Even when I only power the board without any sensors, the behavior remains.

I am still using the same code as last time, so technically this should not be happening.

I honestly have no idea why this is happening; regardless of how I power the device, it connects to TTN every few seconds instead of going into deep sleep.

If any of you have an idea what the issue might be, I’d be more than willing to test your suggestions. Thank you already in advance!

This tells us it’s not the sensors, so that helps narrow it down.

Deep down, under the grumpy old engineer who is a pedant for the scientific process, I’m a pussy cat with a soft spot for those the try. So please excuse me if I’m a bit blunt, it’s just me.

When you say “the same code”, the thread says that you were using HeltecV3_LoRaWAN_deepSleep_allSensors_5V.ino but are now using workingCode.ino. I can see that you’ve turned off the EC sensor but still have some of the processing code around line 280 which shouldn’t make any difference but none the less, you aren’t using the same code. So it may be worth using your HeltecV3_LoRaWAN_deepSleep_allSensors_5V.ino code as a quick sanity test.

I’d suspect that the board is resetting - which you can verify via the serial log - @bns loves big logs, he cannot lie, so if you do post one, please use the </> tool to format it.

I have a water quality rig, as an IoT peep commissioned by a client, I’m not a marine bod. It sports some very fancy Ion Specific Membrane sensors (Nitrates & Ammonia) along with most of the ones you have. I wanted to make an autonomous raft to survey a very large lake last summer (denied! no budget), so you have my attention & admiration.

Let me get my WiFi LoRa 32 V3 out the office and I can have a proper poke at the code. But first it’s time for me to cook supper.

1 Like

Shush you, @jsteiwer: he’s leaving out the fact that he supplied me with a 400MB log, generated in 16 hours by crashing a device 30,000 times. Which was partially my fault, before he starts complaining about that.

1 Like