Arduino LoRa demo sensor

Overview

Arduino_LoRa_Demo_Sensor is a very simple demo sketch for training purpose. The main program, i.e. Arduino_LoRa_Demo_Sensor.ino can be left unchanged by the students. They just have to add/modify code in my_demo_sensor_code.h and my_demo_sensor_code.cpp to adapt the code for a given physical sensor. The provided example reads from either an LM35DZ or a TMP36 analog temperature sensor.

Arduino board with LoRa radio module

We will use an Arduino Nano mounted on a simple PCB which hosts the RFM95 LoRa radio module.

The first one is freely available (Gerber files for the PCB manufacturer) from our github: https://github.com/CongducPham/LowCostLoRaGw#pcbs. You can also find on this github Gerber file of other LoRa components to build a whole device-gateway LoRa solution. We also have the PCB to host an Arduino ProMini if you are using this board.

The other Nano breakout board is the WaziNano board developed within the WAZIUP/WAZIHUB projects. It has an integrated antenna which is realized in collaboration with Pr. F. Ferrero from University of Nice.

There is also the WaziDev board developed within the WAZIUP/WAZIHUB projects that specifically targets integration purpose as the microcontroller is directly integrated into the board. Additionally, the WaziDev has many features compared to other available boards on the market: integrated MOSFET for high power modules (such as GPS), possibility of activate or deactivate various LEDs for energy optimization purposes,...

Code example

For better understanding, we will define some important basic parameters for the LoRa sensor to start with.

In the header file my_demo_sensor_code.h .

We define the PIN to read the value from the sensor. For this example, we will use PIN A0 to read the output of the sensor.

#define PIN_READ  A0

then we define the pin to power up the board. For this example, we selected pin 9. You can also connect the sensor directly to a VCC pin for this simple example but then you will not be able to power down the connected sensor.

#define PIN_POWER 9

also chose appropriate voltage scale for the board, 3300.0 for 3.3V and 5000.0 for 5V. The Arduino Nano is a 5V board. For the ProMini, we advise the 3.3V version but if you have the 5V version, set the voltage scale to 5000.0. The WAZIDev board is a 3.3V board. If you are using a digital sensor you probably don't need the scaling factor.

#define VOLTAGE_SCALE  3300.0

In the file my_demo_sensor_code.cpp .

We start with defining the nomenclature string. Here, you can use a maximum of 3 characters. If you need more characters, just increase the size of the char array (be careful, the number of available characters is the size of the char array minus 1). But we recommend to not go beyond 5 characters because these characters will be sent wirelessly so more characters means longer packets. Here TC is a short way to refer to temperature in celcius. If you use a photoresistor, you can change the nomenclature string to LUM for instance. Note that this nomenclature is a completely user-defined string that will be used in the cloud platform to better identified the sensed value.

char nomenclature_str[4]="TC";

We defined function sensor_Init() for initialization of the input and output pin for the temperature sensor.

void sensor_Init() {
  pinMode(PIN_READ, INPUT);
  pinMode(PIN_POWER, OUTPUT);
}

In function sensor_getValue(), we define the way we read a value from the temperature sensor. In this example, we are using LM35DZ simple analog temperature sensor. You should verify the equation to calculate the sensed value for the sensor you are using. If you want to use one of the sensors you saw in previous examples (for instance the photoresistor or the DHT22), you have to use appropriate copy/paste to adapt the code to the sensor you are using.

double sensor_getValue() {

  //power up the sensor
  digitalWrite(PIN_POWER, HIGH );
  //wait a bit 
  delay(500);

  //read the raw sensor value
  int value = analogRead(PIN_READ);

  //power down the sensor
  digitalWrite(PIN_POWER, LOW);
  Serial.print(F("Reading "));
  Serial.println(value);

  double sensor_value; 
  //change here how the temperature should be computed depending on your sensor type
  sensor_value = (value*VOLTAGE_SCALE/1024.0)/10;
    
  return sensor_value;
}

Here is the WAZINano board with the analog LM35DZ temperature sensor that will be used


Let's now move on to the main program, the sketch named Arduino_LoRa_Demo_Sensor.ino.

The LoRa communication library to drive the LoRa radio module is referred to as the SX12XX library. It is originally written by Sturt Robinson and can support several LoRa chips versions: SX1261/62/68, SX1272/76/77/78/79 and SX1280/81. We modified it for our own purposes and added advanced functionalities. You will need to copy the library into your sketch/libraries folder. Our modified SX12XX library can be downloaded from our github repository: github:https://github.com/CongducPham/LowCostLoRaGw/tree/master/Arduino/libraries/SX12XX/src.

The SX12XX library is already included in the .zip archive that contains all the examples of this online tutorial with all the required libraries. If you haven't done it yet, you can download the .zip archive here. Unzip the archive to get a sketch folder that will be used later on with the Arduino programming environment.

The sketch starts by defining which LoRa chip family we are using. Here we used the HopeRF RFM95W radio module which is based on the SX1276 so we uncomment only the corresponding #define statement.

//#define SX126X
#define SX127X
//#define SX128X

When defining the correct LoRa chip model, the example template will include the corresponding header file: SX126X_RadioSettings.h or SX127X_RadioSettings.h or SX128X_RadioSettings.h. Each header file will define some LoRa parameters needed to run the LoRa rado module. You do not need to worry much about most of the parameters and you can just for the moment leave them as they are defined by default. We are however going to describe some of the parameters to better understand the configuration of the LoRa transmission.

First, there are 2 important parameters that define the LoRa BW and SF parameters (see the Introduction to LoRa section).

const uint8_t Bandwidth = LORA_BW_125;
const uint8_t SpreadingFactor = LORA_SF12;

Second, it is necessary to indicate in which frequency band you will be transmitting. Here we are using the 868MHz band. Note that the frequency band mostly depends on regulations defined for each country or region. For a given frequency band, it may be necessary to have a different LoRa chip. For instance SX1272/76 support well the 868MHz and 900MHz frequency band. If you want to use the 433MHz frequency band you may need to use a radio module based on the SX1278/79 to have better performances. For now, let's just use to 868MHz band with the RFM95W which is based on the SX1276.

#define BAND868
//#define BAND900
//#define BAND433

For each frequency band, several frequencies/channels will be defined and a default frequency will be used. For 868MHz band, we have 15 channels, from CH_04_868 to CH_18_868, and the default frequency is set to CH_10_868 which value is 865.2MHz.

const uint32_t DEFAULT_CHANNEL=CH_10_868;

Now, let's go back to the main sketch Arduino_LoRa_Demo_Sensor.ino.

You can change the LoRa node address here. It is important if you are working in several groups that each physical device has a different address. So coordinate with the other students to use a different address for each device. The address is a numeric value between 2 and 255 as address 1 is reserved for the gateway.

const uint8_t node_addr 9

In the setup() function, we set up and initialize all the required parameters. Initialisation of depends on the LoRa chip so there are codes dedicated to either SX126X, SX127X or SX128X. You normally do not have to change anything in the setup() function. Note the call to sensor_init() function to run the physical sensor specific initialisation.

  sensor_Init();

Then we move on to the loop() function, which is supposed to run in a loop forever. First we call the function sensor_getValue() which we defined in my_demo_sensor_code.cpp to get the sensed value.

  sensor_value = sensor_getValue();

Here we write the message that will be sent. We use the following format \!TC/22.5 for instance. The \! prefix will trigger at the gateway the upload of the received data to remote clouds. Remember that nomenclature_str is defined previously in my_demo_sensor_code.h as "TC".

  uint8_t r_size;
  char float_str[10];

  //the recommended format  \!TC/22.5
  //convert the floating value into a string
  ftoa(float_str,sensor_value,2);	
  r_size=sprintf((char *)message, "\\!%s/%d" , nomenclature_str, (int)sensor_value);

Then we check for a free radio medium prior to transmitting the packet.

  LT.CarrierSense();

The transmission of the packet is realized with the LT.transmitAddressed() function that takes 8 parameters: the buffer message to be sent, the number of bytes to be sent, the packet type (here it is PKT_TYPE_DATA), the destination address (here it is DEFAULT_DEST_ADDR which is defined as 1 for the gateway), the source address, a timeout value (here it is set to 10000ms), the transmission power in dBm (here MAX_DBM is defined as 14dBm in SX127X_RadioSettings.h) and finally WAIT_TX which indicates that we will wait for the transmission to finish before we return from the LT.transmitAddressed() function.

  LT.transmitAddressed(message, r_size, PKT_TYPE_DATA, DEFAULT_DEST_ADDR, LT.readDevAddr(), 10000, MAX_DBM, WAIT_TX)

The function return 0 if there is an error. It returns the number of bytes transmitted otherwise.

After transmission, we remain idle for 1 minute

  nextTransmissionTime=millis()+60000; 

If you open the Arduino IDE's Serial Monitor window, you should see something similar to the following output:

Simple LoRa sensor demo
Arduino Pro Mini detected
ATmega328P detected
LoRa Device found

SX1276,865200000hz,SF12,BW125000,CR4:5,LDRO_On,SyncWord_0x1424,IQNormal,Preamble_8
SX1276,PacketMode_LoRa,Explicit,LNAgain_Boosted

Setting Power: 14
node addr: 9
SX127X successfully configured
Reading 323
Sensor value is 20.50
Sending \!TC/20.50
Real payload size is 10
\!TC/20.50
--> CS1
--> CAD 160
OK1
CRC,A808
LoRa pkt size 10
LoRa pkt seq 0
LoRa Sent in 1317

The raw source of the sketch example is visible here.

For more examples, you can refer to our Arduino LoRa example github page.

The SX12XX communication library

You can have a look at the original SX12XX communication library github repository, especially at the section on library functions.

Pre-defined LoRa modes and Pre-defined frequency channels

Table 1: Pre-defined LoRa modes (from initial Libelium SX1272.h)
mode BW SF
1 125 12
2 250 12
3 125 10
4 500 12
5 250 10
6 500 11
7 250 9
8 500 9
9 500 8
10 500 7

Pre-defined channels in 868MHz, 915MHz and 433MHz band (most of them from initial Libelium SX1272.h, except those marked with *). Frequencies in bold are those used by default in each band.

Table 2: Pre-defined frequency channels
ch F(MHz) ch F(MHz) ch F(MHz)
04 863.2* 00 903.08 00 433.3* (default)
05 863.5* 01 905.24 01 433.6*
06 863.8* 02 907.40 02 433.9*
07 864.1* 03 909.56 03 434.3*
08 864.4* 04 911.72 - -
09 864.7* 05 913.88 (default) - -
10 865.2 (default) 06 916.04 - -
11 865.5 07 918.20 - -
12 865.8 08 920.36 - -
13 866.1 09 922.52 - -
14 866.4 10 924.68 - -
15 867.7 11 926.84 - -
16 867.0 12 915.00 - -
17 868.0 - - - -
18 868.1* - - - -

Next step: Gateway and WAZIUP data platform

LoRa devices send data to a LoRa gateway. It is beyond the scope of this online tutorial to describe all the steps to build a low-cost LoRa gateway but you can find all the necessary information from the following links.

Here is the tutorial video from our YouTube channel for the gateway part.

We assume that a gateway is available for the training or you built such gateway. Note that with the simple PCB (WAZIHat for instance) to host the LoRa radio module for the gateway, it is very easy to build the gateway with a regular Raspberry PI3 and the SD card image provided on our web page describing how to build a low-cost LoRa gateways.

With the WAZIHat With the RFM95 breakout freely available from our github: https://github.com/CongducPham/LowCostLoRaGw#pcbs

If you have the default configuration for both the device and gateway (i.e. LoRa mode 1 and CH_10_868=865.2MHz) then both components can communicate: the gateway is receiving data sent by the demo device, for instance \!TC/22.5.


Configuring the gateway

If you are working in groups where a gateway has been installed, do not perform these steps unless instructed by the instructor

Connect your gateway to a DHCP network to have Internet connectivity

Your gateway also acts as a WiFi access point. Search for WAZIUP_PI_GW_XXXXXXXXXX

Connect to this WiFi, password is loragateway

Use a web browser (you can use a smartphone or tablet for instance) and open http://192.168.200.1/admin

Login: admin and Password: loragateway

Go to the Cloud menu and select the Cloud WAZIUP tab


First, enable the WAZIUP cloud if needed

Leave project_name as waziup. If you are deploying for another project, you can enter here your project name.

Set organization_name to WAZIUP_TRAINING for instance

Set service_tree to -DEMO for instance

Leave the other fields unchanged

Last step is to reboot the gateway for changes to take effects. Wait about 1 minute, then power your LoRa demo end-device. With the provided configuration, the gateway will upload the demo device's temperature on the WAZIUP cloud.


The WAZIUP data cloud platform

To see your data on the WAZIUP data cloud platform, go to https://dashboard.waziup.io and log in as guest

Login: guest and Password: guest

It is important to understand that the name of end-devices is set by the gateway when receiving data from the end-device and when upload data to clouds. The gateway retrieves the numeric address of an end-device (between 2 and 255) and will build a more comprehensive name, depending on the naming configuration for each cloud defined on the gateway.

With the above gateway configuration for the WAZIUP cloud, the name of your device is WAZIUP_TRAINING-DEMO_Sensor9_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx as the device's address is 9. You can see that the device name is defined as organization_name+service_tree+"_Sensor"+device_address. Also, as you are using the WAZIUP guest account, the base name WAZIUP_TRAINING-DEMO_Sensor9 is appended with the MD5 hash of your gateway id. The MD5 hash can be found on the gateway's web admin interface in the Gateway Configuration menu and Gateway tab.


Here, our gateway id is 00000027EB5A71F7 and therefore the MD5 hash is 3304d293a4f5524e3d058929cf6583fb . The gateway id is automatically determined from the gateway's network MAC address so you do not need to modify it. We advise you to use the default gateway id based on the gateway network MAC address.

Therefore, in our setting, we can search on the WAZIUP dashboard the device WAZIUP_TRAINING-DEMO_Sensor9_3304d293a4f5524e3d058929cf6583fb. In your case, you will have a different MD5 hash value but the base name will be the same.


The final step is to create an account on the WAZIUP dashboard. Go to https://dashboard.waziup.io and follow procedure to create an account with a user name and a password. Use only letters and numbers for user name and password.

Once you have your user name and password, go on the gateway's web admin interface, select Cloud menu and the Cloud WAZIUP tab to enter these information into the corresponding field.

Reboot the gateway for changes to take effects. Wait about 1 minute, then power your LoRa demo end-device.

Then go again to https://dashboard.waziup.io and log in with your user name and password. You should see your device, this time without the gateway's id MD5 hash because you have been identified as a registered user.


If you want to recover data points from the WAZIUP platform in order to develop new IoT applications, you can have a look at the WAZIUP API tutorial pages. If your application is written in Javascript, you can use the WAZIUP library instead of using directly the API.

You can also have a look at the following video that shows how to set up an operational gateway in less than 5mins.

Enjoy!