Soil moisture sensor

I finally got the Raspberry Pi Pico running but due to the decision to use CircuitPython the deep sleep mode is not (not yet, acc. to Adafruit) available. As Nick also stated, 900uA might be still to high for a battery powered node.

I also got a ready made unit from a friend of mine to get it up and running:
A Lora Soil Moisture Sensor from Makerfabs Link
It runs on a Atmega328P in combination with RFM95W.
I got it running with their firmware: Lora-Soil-Moisture-Sensor/LoraTransmitterADCAHT10 at master · Makerfabs/Lora-Soil-Moisture-Sensor · GitHub
but without connection to TTS

or
with the LMIC-node (My first experience with platformio :slight_smile: )
with OTAA connection established to TTS !

My challenge now is to get them both together.
I have tried to extend the LMIC-node.cpp but I was not successful

Any thoughts / hints / helpful examples to get this done?

Thanks
Eckhard

We could suggest, but it would be simpler if you told us what you tried just in case you had a near miss.

Fundamentally you need to fish out the sensor reading bits from the first sketch and drop that in to the LMIC-node.

I have taken this from the Makerfabs Code and put it into the first USER CODE section:

#include <SPI.h>
#include "I2C_AHT10.h"
#include <Wire.h>
AHT10 humiditySensor;

int sensorPin = A2;    // select the input pin for the potentiometer
int sensorValue = 0;  // variable to store the value coming from the sensor
int sensorPowerCtrlPin = 5;

void sensorPowerOn(void)
{
  digitalWrite(sensorPowerCtrlPin, HIGH);//Sensor power on 
}
void sensorPowerOff(void)
{
  digitalWrite(sensorPowerCtrlPin, LOW);//Sensor power on 
}

The next USER CODE Section seems to be my Problem Child. I don’t know how to get the Sensor data collected and prepared to be uploaded to the TTS:

// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
//float humidity = 6.18;//dht.readHumidity();
// Read temperature as Celsius (the default)

sensorPowerOn();//
delay(100);
sensorValue = analogRead(sensorPin);
delay(200);

if (humiditySensor.available() == true)
{
    //Get the new temperature and humidity value
    temperature = humiditySensor.getTemperature();
    humidity = humiditySensor.getHumidity();

    //Print the results
    Serial.print("Temperature: ");
    Serial.print(temperature, 2);
    Serial.print(" C\t");
    Serial.print("Humidity: ");
    Serial.print(humidity, 2);
    Serial.println("% RH");

}
    // Check if any reads failed and exit early (to try again).
if (isnan(humidity) || isnan(temperature)) {
    Serial.println(F("Failed to read from AHT sensor!"));
    //return;
}

delay(100);
//sensorPowerOff();

Serial.print(F("Moisture ADC : "));
Serial.println(sensorValue);


//Serial.print(F("Humidity: "));
//Serial.print(humidity);
//Serial.print(F("%  Temperature: "));
//Serial.print(temperature);
//Serial.println("Humidity is " + (String)humidity);
//Serial.println("Temperature is " + (String)temperature);

String message = "#"+(String)packetnum+" Humidity:"+(String)humidity+"% Temperature:"+(String)temperature+"C"+" ADC:"+(String)sensorValue;
Serial.println(message);
packetnum++;
    Serial.println("Transmit: Sending to rf95_server");

// Send a message to rf95_server

uint8_t radioPacket[message.length()+1];
message.toCharArray(radioPacket, message.length()+1);

radioPacket[message.length()+1]= '\0';

The last USER CODE portion (Init section) is:

  //digitalWrite(sensorPowerCtrlPin, LOW);//Sensor power on 
  sensorPowerOn();
    
    Wire.begin(); //Join I2C bus
    //Check if the AHT10 will acknowledge
    if (humiditySensor.begin() == false)
    {
        Serial.println("AHT10 not detected. Please check wiring. Freezing.");
        //while (1);
    }
    else
        Serial.println("AHT10 acknowledged.");

Platformio seems not have a loop section where I could put the respective code and LMIC seems to arrange the data for sending different than Radiohead.
So my data I am looking for is in the variables

  • SensorValue
  • humidity
  • temperature

And the update is done by (I assume):

  • temperature = humiditySensor.getTemperature();
    
  • humidity = humiditySensor.getHumidity();
    
  • sensorValue = analogRead(sensorPin);

Any thoughts?

Read this:

https://www.thethingsnetwork.org/docs/devices/bytes/

and look the code related to the payloadBuffer:

Thanks Nick,
will read that. That will hopefully answer the question about how to combine 3 variables to be loaded to the payloadBuffer.

But where do I have to put the code that updates the sensor measurements inside the cpp?

Have you read the extensive instructions that were created with the specially setup sections for adding code?

Thanks Nick for supporting me! I will try to work through the documents more detailed as you proposed.

While doing that I recognized that I might have additional problems upfront:

The serial log looks like:

Device-id:     pro-mini
LMIC library:  Classic [Deprecated]
Activation:    OTAA
Interval:      60 seconds

Clock Error:   30000 ppm (1965)
000000000773:  Event: EV_JOINING

000000000837:  doWork job started

000003750842:  doWork job started

000007500850:  doWork job started
...

And It seems not to get any " Event: EV_TXSTART" nor “Event: EV_JOINED”

The TTS console is telling: “Accept join-request” several times without any Data preview?!

Another problem I assume.

Any thoughts?

You’ve correctly identified that your device isn’t getting the Join Accept so no EV_JOINED.

How far apart is the device & gateway - too close & it can overload the input circuitry which scrambles the message - ideally 3 to 5m and a brick wall between them.

Actually it was 5m away with one brick wall in between, I have extended it now to 10m, 3 walls - no change :frowning:

Be aware thay CircuitPython for LoRaWAN uses the TinyLora library under the hood.
TinyLora is not LoRaWAN compliant and cannot handle downlinks and MAC commands and shall therefore not be used with TTN V3.

Only the MCCI LMIC library generates those events. Classic LMIC does not. LMIC-node uses Classic LMIC for 8-bit AVR MCU (see README.md). This explains why you do not see these events.

If the join fails, check if DIO1 is properly connected (see the board’s BSF for details).

Do you have tried to get it working with ABP already? Latter does not depend on DIO1 (only on DIO0).

About the RPI Pico - my plan is to change to Platformio like the Atmega 328p as I would like to use the deep sleep functionality.

About the Atmega328p - I tried ABP before with the LMIC-Node but compiling failed with an error message:

src/LMIC-node.h:110:6: error: #error Do NOT use ABP activation when using the deprecated IBM LMIC framework library. On The Things Network V3 this will cause a downlink message for EVERY uplink message because it does properly handle MAC commands.

?!

Ah, typo in the error message: “it does properly handle MAC commands” should read “it does NOT properly handle MAC commands” instead.

LMIC-node for 8-bit AVR MCU’s, due to their limited memory, does not support MCCI LMIC, only Classic LMIC (IBM LMIC Framework).
Unfortunately latter has its shortcomings, it is no longer maintained and is now deprecated. It should not be used with ABP for TTN V3.

So sorry, for 8-bit AVR MCU, LMIC-node cannot be used for ABP (was not a good suggestion for your AVR board).

RTFM.

Thanks bluejedi for the answer!
Your comment about the BSF brought me the following:

Scheme form my board:Link
Screen Shot 2021-07-06 at 7.42.59 PM

while the BSF for Atmega328p Link
is calling out:

*                SPI/LoRa module     GPIO
 *                ----                ----
 *                MOSI  <――――――――――>  11  (MOSI)
 *                MISO  <――――――――――>  12  (MISO)
 *                SCK   <――――――――――>  13  (SCK)
 *                NSS   <――――――――――>  10  (SS)
 *                RST   <――――――――――>   7
 *                DIO0  <――――――――――>   8
 *                DIO1  <――――――――――>   9
 *                DIO2                 -  Not needed for LoRa.

So I have to change the BSF.h right?

Thanks Guys! That was the problem!

I changed the bsf_pro8mhzatmega328.h to:

const lmic_pinmap lmic_pins = {
    .nss = 10,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 4,
    .dio = { /*dio0*/ 2, /*dio1*/ 6, /*dio2*/ LMIC_UNUSED_PIN }

and now it works!

LMIC-node

Device-id:     pro-mini
LMIC library:  Classic [Deprecated]
Activation:    OTAA
Interval:      60 seconds

Clock Error:   30000 ppm (1965)
000000000813:  Event: EV_JOINING

000000000877:  doWork job started
000000346684:  Event: EV_JOINED

000000346756:  doWork job started
000000349951:  Input data collected
               COUNTER value: 1
000000350053:  Packet queued
000000668286:  Event: EV_TXCOMPLETE
               Up: 1,  Down: 1
               Downlink received
               RSSI: -72 dBm,  SNR: 9.7 dB
               Port: 0

Now I will try to change the code to get the sensor data integrated . Will report when successful.

Soil sensor now working!

I currently measure 5.5mA power consumption - to high for a battery powered node.

Any thoughts on that how to incorporate deep sleep?

The Supplier of the soil sensor is offering something under : Link but it does not use the LMIC-node?!

Thanks
Eckhard

You can use the low power library for Arduino:

That’s a good start. Low Power can get interesting with LMIC so it may be a good thing for us all to collaborate on a template for LMIC-node

1 Like

It’s a hardware thing. I remember with ATmega328 and RFM95 were 5µA possible with external Interrupt 1µA. How low can a ATmega4808 with RFM95 go? I see you have a nice test build on your workbench.

About the same, a 4808 has a newer core but it’s basically the same beast. I’ll measure it over the next few days.