5 sensor data transmission using 433 MHz modules

Hello everyone,

(Question in bold below, this is for context)

Once again I have problems with the 433 MHz radio modules. I have made a weather station (although I like to see it as a planet explorer, like the Perseverance rover or the InSight Mars lander), and I would like to send the data of the sensors to a reciever via a 433Mhz radio link. I was clueless on how to do it, and the only viable help I found on the internet was DroneBot's workshop video about 433MHz modules. He uses the Radio Ahead ASK library.

In the video, the author sends the data of a DHT 22 sensor (Humidity and Temperature) via radio using a comma delimited strings. He writes in a single string the temperature reading, then in another string the humidity reading, and then combines both in an output string with a comma in the midle to separate both values. Later in the reciever code he separates both values using the comma as reference point.

The problem is that my project consists of 5 sensors, not just two. It uses two termistors for temperature reading, a DHT 11 for humidity readings (I know it has a temperature reading module, but the termistors have prooven more accurate), an LDR module for light intensity readings and a resistive soil moisture sensor, to read the humidity of the soil. All sensors work, and for now they display their values on an LCD screen with I2C comunication. All but the DHT use analog readings.

AND, using the raw code provided by DroneBot workshop (below), I have managed to send different kinds of values in pairs, both digital and analog. But I need to send the 5 values at the same time.

QUESTION
I don't understand how he separates the two values of the string using commas. In the video, that part is not explained. The auhtor said that more sensors could be added, so it is possible to put 5.

Does anyone know how to send the values via a single comma divided string, or any way to send 5 different values with the module?

Thank you for your time.

Codes:

TRANSMITTER

ad(LDR1);
  LDRp100 = map(LDRV, 0, 1023, 0, 100); //turns values into percentages
  delay(5);
}/*
  433 MHz RF Module Transmitter Demonstration 2
  RF-Xmit-Demo-2.ino
  Demonstrates 433 MHz RF Transmitter Module with DHT-22 Sensor
  Use with Receiver Demonstration 2

  DroneBot Workshop 2018
  https://dronebotworkshop.com
  Slight modification Arduinomaker 1897 June '23
*/

// Include RadioHead Amplitude Shift Keying Library
#include <RH_ASK.h>
// Include dependant SPI Library 
#include <SPI.h> 

#include <DHT.h> //Dht library


// Define Variables

float hum;    // Stores humidity value in percent
float temp;   // Stores temperature value in Celcius

#define DHTPIN 2
#define DHTTYPE DHT11 //DHT
#define TRM1 A0 //Termistor 1
#define TRM2 A1 //Termistor 2
#define LDR1 A2 //LDR
#define MOST A3 //Moisture sensor


int Vo; //required for the termistor equation
int Vo3; //for second termistor
float R1 = 10000;
float R3 = 10000;
float logR2, R2, tKelvin, tCelsius;
float logR23, R23, tKelvin3, tCelsius3;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

int LDRV;//ldr value variable
int LDRp100; //to calculate percentage

int SMoistV = 0; //for the moisture sensor
int per100 = 0; //to calculate percentage
// Define output strings

String str_humid;
String str_ldr;
String str_tp1;
String str_tp2;
String str_smt;
String str_out;

// Create Amplitude Shift Keying Object
RH_ASK rf_driver;

// Initialize DHT sensor for normal 16mhz Arduino
DHT dht(DHTPIN, DHTTYPE);

void setup() {

  // Initialize ASK Object
  rf_driver.init();
  // Start DHT Sensor
  dht.begin();

}

void loop()
{

  delay(2000);  // Delay so DHT-11 sensor can stabalize
   
    hum = dht.readHumidity();  // Get Humidity value

    ldr(); //ldr function
    
    readTemp(); //temperature function
    moisture(); //Soil moisture function
    
    // Convert Humidity to string
    str_humid = String(hum);
    
    // Convert LDR to string
    str_ldr = String(LDRp100);

    //Convert temp1 to string

    str_tp1 = String(tCelsius);

    //temp2 to string

    str_tp2 = String(tCelsius3);

    //soil moisture to string

    str_smt = String(per100);

    // Combine Humidity and Temperature
    str_out = str_humid + "," + str_ldr + str_tp1 + "," + str_tp2 + " + str_smt;
    // Compose output character
    static char *msg = str_out.c_str();
    
    rf_driver.send((uint8_t *)msg, strlen(msg));
    rf_driver.waitPacketSent();
  
} 

void readTemp(){ //reads termistor value using the following equation
  Vo = analogRead(TRM1);
  R2 = R1 * (1023.0 / (float)Vo - 1.0); // resistance of the Thermistor
  logR2 = log(R2);
  tKelvin = (1.0 / (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));
  tCelsius = tKelvin - 273.15;

  Vo3 = analogRead(TRM2);
  R23 = R3 * (1023.0 / (float)Vo3 - 1.0); // resistance of the Thermistor
  logR23 = log(R23);
  tKelvin3 = (1.0 / (c1 + c2 * logR23 + c3 * logR23 * logR23 * logR23));
  tCelsius3 = tKelvin3 - 273.15;
  delay(5);

}

void moisture(){ //reads soil moisture

  SMoistV = analogRead(A3);
  per100 = map(SMoistV, 0, 1023, 100, 0); //turns values into percentages
  delay(5);
}


void ldr(){ //reads light intensity
  LDRV = analogRead(LDR1);
  LDRp100 = map(LDRV, 0, 1023, 0, 100); //turns values into percentages
  delay(5);
}

RECIEVER (Incomplete because I don't understand the code provided):

/*
  433 MHz RF Module Receiver Demonstration 2
  RF-Rcv-Demo-2.ino
  Demonstrates 433 MHz RF Receiver Module with DHT-22 Sensor
  Use with Transmitter Demonstration 2

  DroneBot Workshop 2018
  https://dronebotworkshop.com
  Slight modification  by Arduinomaker 1897 June '23
*/

// Include RadioHead Amplitude Shift Keying Library
#include <RH_ASK.h>
// Include dependant SPI Library 
#include <SPI.h> 

// Define output strings

String str_humid;   //air humidity
String str_ldr;   //ldr value
String str_tp1;   //temperature 1
String str_tp2;   //temperature 2
String str_smt;   //soil moisture
String str_out;   //output string

// Create Amplitude Shift Keying Object
RH_ASK rf_driver;

void setup()
{
    // Initialize ASK Object
    rf_driver.init();
    // Setup Serial Monitor
    Serial.begin(9600);
}

void loop()
{
    // Set buffer to character size of expected message
    uint8_t buf[8];
    uint8_t buflen = sizeof(buf);
    // Check if received packet is correct size
    if (rf_driver.recv(buf, &buflen))
    {
      
      // Message received with valid checksum
      // Get values from string
      
      // Convert received data into string
      str_out = String((char*)buf);
      
      // Split string into two values
      //This is the part I don't understand
      for (int i = 0; i < str_out.length(); i++) {
		  if (str_out.substring(i, i+1) == ",") {
			str_humid = str_out.substring(0, i);
			str_ldr = str_out.substring(i+1);
			break;
		  }

      
		}
      
      // Print values to Serial Monitor
      Serial.print("Humidity: ");
      Serial.print(str_humid);
      Serial.print("  - LDR: ");
      Serial.println(str_ldr);
               
    }
    delay(1500);
}

The part I don't understand

      for (int i = 0; i < str_out.length(); i++) {
		  if (str_out.substring(i, i+1) == ",") {
			str_humid = str_out.substring(0, i);
			str_ldr = str_out.substring(i+1);
			break;
		  }

Again, thank you very much. Any help is appreciated.

Kind regards,
Arduino 1897

this looking for ',' in the string and use its position as divider. first piece associate to humidity, last one to LDR

The above is where they are combined as noted in the comments.
be sure to convert them to string before combining

str_out = str_humid + "," + str_ldr + "," + str_anotherSensor + "," + str_andAnother;

Thank you for your answer.

Although that's not my question (the problem is at the reciever code), you are right pointing that out. I have edited it and it is now fixed.

Thanks for your answer.

Ok, it looks for the comma and then it divides it. However, I don't understand the process to divide them. It uses a variable, i, but I don't understand how or why it is used.

If you could explain it I would very much appreciate it.

Thanks!

variable i is used as index for whole range of character string. first character has index 0, the last is

str_out.length()-1

if current character equal ',' then this index is end of first substring and i+1 is start of last substring
if not then next character will checked

Alright, I seem to get it. When you get to i+1, you get to a new substring. So, the end of this substring would be another comma, and the start of the third substring would be i+2?

Sorry if I am making any error.

You don't get it. 'i' indexes individual characters, not fields of characters or strings.

You might find it easier to assign a letter to each measurement.

i.e.
a = sensor 1 temp
b = sensor 2 humidity
.
.
.
f = sensor x temp
and so on.

Upon receiving test the first char (now you know which measurement you've received).
Remove the 1st char and convert the remainder to a number.

no problem. if you more comfortable with numbers, you can compose a message from them and this bring some performance profit due to String are RAM expensive.

for example

struct Message {
  uint8_t Humi;
  uint16_t Temp;
  uint8_t LDR;
  uint8_t Moisture;
} mesage;

void setup() {
  mesage.Humi = uint8_t(dht.readHumidity());
  mesage.Temp = uint16_t(dht.readTemperature() * 10.0);
  mesage.Moisture = uint8_t(analogRead(A0) / 4);
  mesage.LDR = uint8_t(analogRead(LDR1) / 4);
  rf_driver.send((uint8_t *)mesage, sizeof(mesage));
}

rather than attempting to transmit a number of sensor values as comma seperated text try transmitting a complete structure as binary
this saves encoding the data as comma seperated text at the transmitter and decoding it at the receiver
e.g. an example transmitter transmitting integer, float and text data

// 433MHz transmitter test 1

#include <RH_ASK.h>     // Include RadioHead Amplitude Shift Keying Library
#include <SPI.h>        // Include dependant SPI Library

RH_ASK rf_driver;       // Create Amplitude Shift Keying Object

#define nodeID 1  //  <<< set up required node ID

struct __attribute__((packed)) Struct1 {
  byte StructureID;  // identifies the structure type
  byte NodeID;       // ID of transmitting node
  int16_t seq;       // sequence number
  int16_t x;
  float y;
  char z[10];
};

Struct1 struct1 = { 1, nodeID, 0, 1, 4.5, "hello" };

void setup() {
  Serial.begin(115200);
  rf_driver.init();       // Initialize ASK Object
  Serial.println("Transmitter: rf_driver initialised");
}

// transmit packet every 5 seconds
void loop() {
  Serial.print("Transmitting ");
  struct1.seq++;  // increment packet sequence number
  struct1.x += 1;
  struct1.y += 1;
  struct1.z[0] += 1;
  const char *msg = "Hello World";
 // rf_driver.send((uint8_t *)msg, strlen(msg));
  rf_driver.send((uint8_t *)&struct1, sizeof(struct1));
  rf_driver.waitPacketSent();
   Serial.print(" StructureID ");
  Serial.print(struct1.StructureID);
  Serial.print(" Node ");
  Serial.print(nodeID);
  Serial.print(" seq number ");
  Serial.print(" seq number ");
  Serial.print(struct1.seq);
  Serial.print(" x = ");
  Serial.print(struct1.x);
  Serial.print(" y = ");
  Serial.print(struct1.y);
  Serial.print(" z = ");
  Serial.println(struct1.z);
  delay(5000);      // to generate errors lower delay to 1000mSec
}

receiver

// 433MHz receiver test 1

#include <RH_ASK.h>  // Include RadioHead Amplitude Shift Keying Library
#include <SPI.h>     // Include dependant SPI Library

RH_ASK rf_driver;  // Create Amplitude Shift Keying Object

struct __attribute__((packed)) Struct1 {
  byte StructureID;  // identifies the structure type
  byte NodeID;       // ID of transmitting node
  int16_t seq;       // sequence number
  int16_t x;
  float y;
  char z[10];
} struct1;

void setup() {
  rf_driver.init();  // Initialize ASK Object
  Serial.begin(115200);
  Serial.println("Receiver: rf_driver initialised");
}

void loop() {

  uint8_t buf[100];  // Set buffer to size of expected message
  // Check if received packet is correct size
  if (rf_driver.recv((uint8_t *)&struct1, sizeof(struct1))) {
    // Message received with valid checksum
    Serial.print("Received: ");
    Serial.print(" StructureID ");
    Serial.print(struct1.StructureID);
    Serial.print(" from Node ");
    Serial.print(struct1.NodeID);
    Serial.print(" seq number ");
    Serial.print(struct1.seq);
    Serial.print(" x = ");
    Serial.print(struct1.x);
    Serial.print(" y = ");
    Serial.print(struct1.y);
    Serial.print(" z = ");
    Serial.println(struct1.z);
  }
}

transmitter serial monitor

Transmitter: rf_driver initialised
Transmitting  StructureID 1 Node 1 seq number  seq number 1 x = 2 y = 5.50 z = iello
Transmitting  StructureID 1 Node 1 seq number  seq number 2 x = 3 y = 6.50 z = jello
Transmitting  StructureID 1 Node 1 seq number  seq number 3 x = 4 y = 7.50 z = kello
Transmitting  StructureID 1 Node 1 seq number  seq number 4 x = 5 y = 8.50 z = lello
Transmitting  StructureID 1 Node 1 seq number  seq number 5 x = 6 y = 9.50 z = mello
Transmitting  StructureID 1 Node 1 seq number  seq number 6 x = 7 y = 10.50 z = nello
Transmitting  StructureID 1 Node 1 seq number  seq number 7 x = 8 y = 11.50 z = oello
Transmitting  StructureID 1 Node 1 seq number  seq number 8 x = 9 y = 12.50 z = pello

receiver serial minitor

Receiver: rf_driver initialised
Received:  StructureID 1 from Node 1 seq number 1 x = 2 y = 5.50 z = iello
Received:  StructureID 1 from Node 1 seq number 1 x = 2 y = 5.50 z = iello
Received:  StructureID 1 from Node 1 seq number 2 x = 3 y = 6.50 z = jello
Received:  StructureID 1 from Node 1 seq number 3 x = 4 y = 7.50 z = kello
Received:  StructureID 1 from Node 1 seq number 4 x = 5 y = 8.50 z = lello
Received:  StructureID 1 from Node 1 seq number 5 x = 6 y = 9.50 z = mello
Received:  StructureID 1 from Node 1 seq number 6 x =  y = 10.50 z = nello

the above tests were carried out using UNOs as hosts
if the transmitter and receiver are different microcontroller one has to take care that the data types are the same size and endianness

Thanks kolaha.

Your code, from what I understand, makes a structure called Message which combines all of the values from the sensors, and then converts them to binary using the "uint8_t" function (I don't know if that's the appropiate name of it). After that, it sends them with the "rf_driver.send" function. However, isn't that function already converting the values in binary? And, how do I distinguish the values at the recieving end?

Sorry if I am confused. As you can see, I am not a very good programmer.

So 'i' searches for individual characters, up to the comma. Thanks for the clarification

It is an interesting way to send the data. From what I understand, the "struct" function englobes all of the sensor's inputs (or the examples) into a single piece of data, which is transmitted and then recieved as one. And, since the data is in a "structure" it is easier to separate, according to the name given on the transmitter code.

I'll look into it. Thanks you very much for taking your time writing the code

have a look at thread decimals-strings-and-lora for example code transmitting structures with multiple data mebers between nodes over LoRa using RA-02 modules

Hello everyone.

After several weeks of work I decided to give up on this modules. I will use NRF24l01 radio modules, which are a bit more expensive, but are easier to use, have far greater range (up to 1km vs the 5m of the 433 MHz modules) and many more improvements over the modules.

Anyway, thank you to all those who tried to help me during the development.

Arduinomaker 1897

True, that. There are many better choices than those simplistic modules.

However, I have to say that they would normally do better than 5m.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.