Raspberry Pi Pico W LoRa Gateway for Sensors Monitoring using Ubidots
Table of Contents
Raspberry Pi Pico W LoRa Gateway:
Raspberry Pi Pico W LoRa Gateway for Sensors Monitoring using Ubidots IoT Platform- In this tutorial, you will learn how to make Raspberry Pi Pico W LoRa Gateway using a pair of Raspberry Pi Pico boards, a pair of SX1278 LoRa Transceiver modules, a Potentiometer, MQ-9 Gas Sensor, I2C supported 16×2 LCD, and Ubidots IoT platform.
If you already know about LoRa transceiver modules, Raspberry Pi Pico or Raspberry Pi Pico W, and Ubidots IoT platform then you can continue reading this article. You won’t face any issues in building this project. But if you are at a beginner’s level then you should go one step at a time; if you want to learn everything quickly. Because, if you follow this article without the basic knowledge you may get frustrated and this is something that you will never want. You don’t have to be worried, I have done it for you. You only need to follow the steps which I am about to explain.
- As a beginner, the very first thing that you need to start with is the Arduino IDE and Raspberry Pi Pico or Raspberry Pi Pico W. You should know how to install the Raspberry Pi Pico board in the Arduino IDE using the Board Manger URL link. And you should also know how to install the required libraries. I have an article on this, in which I have explained how to install the Raspberry Pi Pico W board in the Arduino IDE and how to use it with the Adafruit Io.
- As a beginner, you should also know how to connect your Raspberry Pi Pico W board with different IoT platforms for monitoring different types of sensors and for controlling different types of electrical devices. So far I have covered Adafruit Io, Ubidots, and Thingspeak with the Raspberry Pi Pico W. As in today’s tutorial, I am using the Ubidots IoT platform, so you should read my article on the Ubidots and Raspberry Pi Pico W.
- In my previous getting started tutorial on the Raspberry Pi Pico W and LoRa; I practically demonstrated how to send data from a normal Raspberry Pi Pico to Raspberry Pi Pico W using LoRa SX1278 Transceiver modules. So, if you are just getting started with the Lora and Raspberry Pi Pico; it doesn’t matter if you are using a pair of normal Raspberry Pi Pico or a pair of Raspberry Pi Pico W then I highly recommend you should read my getting started article because today’s project is entirely based on it; as I will be using the same connections and programming.
So, after reading all the related articles, then I am sure you won’t face any issues. Or maybe you won’t need to read this article, because I am sure you will make it yourself.
Anyway, here is a prototype model of my Raspberry Pi Pico W LoRa Gateway. I have connected everything as per the circuit diagrams which I will explain in a minute.
On the left side is the transmitter, based on the Raspberry Pi Pico, along which a Potentiometer, MQ-9 Gas Sensor, an i2c-supported 16×2 LCD and SX1278 LoRa transceiver module are connected. The Raspberry Pi Pico reads the Potentiometer and MQ-9 Gas Sensor; and display the values on the 16×2 LCD and at the same time the Raspberry Pi Pico also send the sensors readings to the remote side receiver using the Long Range LoRa Transceiver module.
And on the right side is the receiver, based on the Raspberry Pi Pico W. It has been connected with the SX1278 LoRa transceiver module. The Raspberry Pi Pico W takes data from the LoRa and sends the sensors values to the Ubidots IoT platform. Now, let’s go ahead and start our practical demonstration.
Altium Designer + Altium 365 + Octopart:
Altium 365 lets you hold the fastest design reviews ever. Share your designs from anywhere and with anyone with a single click. it’s easy, leave a comment tagging your teammate and they’ll instantly receive an email with a link to the design. Anyone you invite can open the design using a web browser. Using the browser interface, you’re able to comment, markup, cross probe, inspect, and more. Comments are attached directly to the project, making them viewable within Altium designer as well as through the browser interface. Design, share, and manufacture, all in the same space with nothing extra to install or configure. Connect to the platform directly from Altium Designer without changing how you already design electronics. Altium 365 requires no additional licenses and comes included with your subscription plan.
Get real-time component insights as you design with Octopart built into Altium 365. Octopart is the fastest search engine for electronic parts and gives you the most up-to-date part data like specs, datasheets, cad models, and how much the part costs at different amounts etc. Right in the design environment so you can focus on your designs. Start with Altium Designer and Activate Altium 365. Search for electronic parts on Octopart.
Right now the Raspberry Pi Pico W and Laptop both are connected with the WiFi. You can see values on the 16×2 LCD and also on the Gauges. Right now you can see the PoT value is 46 and the Gas sensor value is 687.
By rotating the Knob of the potentiometer I changed value to 715 and I used a lighter to test the gas sensor. The MQ9 LPG Gas sensor detected gas from the lighter. Anyway I was able to monitor these values on the LCD and also on the Ubidots IoT platform. Anyway, again I rotated the Knob of the potentiometer and as you can see in the image below, the value changed to 639. While the Gas sensor values remain approximately the same.
So, using this project, you can transfer sensors values from a remote location (using Long Range LoRa Module) where no internet facility is available to a location where internet is available and then from there with the help of Raspberry Pi Pico W sensors values are sent to an IoT Platform, Ubidots. Since, this is an IoT project, so the sensors can be monitored from any part of the world. I am sure by now, you might have got an idea of how does this system work. So, without any further delay let’s get started!!!
Amazon Links:
Sx1278 LoRa Transceiver modules
Other Tools and Components:
Super Starter kit for Beginners
PCB small portable drill machines
*Please Note: These are affiliate links. I may make a commission if you buy the components through these links. I would appreciate your support in this way!
Lora SX1278 Module:
The SX1276/77/78/79 transceivers feature the LoRa TM long range modem that provides ultra-long range spread spectrum communication and high interference immunity whilst minimizing current consumption.
Using Semtech’s patented LoRa modulation technique SX1276/77/78/79 can achieve a sensitivity of over -148dBm using a low cost crystal and bill of materials. The high sensitivity combined with the integrated +20 dBm power amplifier yields industry leading link budget making it optimal for any application requiring range or robustness.
LoRa also provides significant advantages in both blocking and selectivity over conventional modulation techniques, solving the traditional design compromise between range, interference immunity and energy consumption.
These devices also support high performance (G)FSK modes for systems including WMBus, IEEE802.15.4g. The SX1276/77/78/79 deliver exceptional phase noise, selectivity, receiver linearity and IIP3 for significantly lower current consumption than competing devices.
I have got these three LoRa SX1278 Modules, LoRa (Long-Range) is digital wireless data communication IoT technology. LoRa transmits over license-free megahertz radio frequency bands: 169 MHz, 433 MHz (Asia), 868 MHz (Europe) and 915 MHz (North America). LoRa enables very-long-range wireless data transmission. The type of the LoRa modules I am using supports 433MHz. Each LoRa module is also provided with an Antenna which we will need to solder to the boards to increase the wireless communication range.
The supply voltage is 1.8 to 3.7 volts, so it can be used with 3.3 Volts and 5 volts compatible controller boards without any problem. 3.3V compatible boards e.g. ESP8266, ESP32, Raspberry Pi Pico, etc. The operational temperature range is -40 Celsius to +85 Celsius.
It has a total of 12 via’s or holes which are clearly labeled and out of which we will be using only VCC, MISO, MOSI, SLCK, NSS, and GND.
As a beginner you may get scared when you first look at these LoRa modules which has holes as they are very close to each other because you cannot solder regular male or female headers. But no worries at all, you can simply start by soldering jumper wires, which of course will need some soldering practice.
As you can see I soldered the jumpers wires and the antennas. Next, I checked the short circuits using a digital Multimeter, and then to secure the wires I applied the silicon, this will help to keep the wires in place and will also protect the wires from getting disconnected.
LoRa Applications:
When it comes to the applications, you have almost infinite ways of controlling and monitoring things including,
Automated Meter Reading.
Home and Building Automation
Wireless Alarm and Security System
Industrial Monitoring and Control
Long range Irrigation Systems and so on…
MQ9 sensor:
The MQ-9 Carbon Monoxide, Methane, and LPG Gas Sensor Module can be used to sense Carbon Monoxide and Methane Gas. Sensitive material of the MQ9 gas sensor is SnO2, which has lower conductivity in clean air.
It makes detection by the method of cycle high and low temperature, and detect CO when the low temperature (heated by 1.5V). The sensor’s conductivity is higher along with the gas concentration rising.
When a high temperature (heated by 5.0V), it detects Methane, Propane, etc. combustible gas and cleans the other gases adsorbed under low temperature.
Wire Connections
VCC – Positive pole (5V)
GND – Negative pole
DO – TTL switch signal output
AO – Analog signal output
Applications
- The domestic gas leakage detector
- Industrial gas detector
- Portable gas detector
Features:
- Good sensitivity to CO/Combustible Gas
- High sensitivity to Methane, Propane, and CO
- Long life and low cost
- Simple drive circuit
Raspberry Pi Pico LoRa Tx Circuit:
3.3V and GND pins of the LoRa SX1278 are connected with the Raspberry Pi Pico 3.3V and GND pins. While the NSS, MISO, SCK, and MOSI pins of the LoRa SX1278 Transceiver module are connected with the Raspberry Pi Pico GPIO pins 8, 16, 18, and 19.
The potentiometer is connected with the GP26_A0 analog pin.
Whereas the analog output pin of the MQ9 Gas sensor is connected with the GP27_A1 analog pin.
The VCC pin of the I2C supported 16×2 LCD is connected with the VBUS which is the 5V pin. And obviously the grounds are connected together. The SDA and SCL pins of the I2C supported 16×2 LCD are connected with the GP0 and GP1. As per the Pins layout diagram GP0 is the SDA and GP1 is the SCL.
Raspberry Pi Pico W LoRa Gateway Circuit:
This is the receiver side circuit diagram. You can see the LoRa SX1278 connection with the Raspberry Pi Pico W remains exactly the same. So, that’s all about the receiver side circuit diagram. Now, let’s go ahead and start with the Ubidots IoT Platform.
Ubidots IoT Platform Setup:
First of all, login into your Ubidots account. If you don’t know how to setup your free Ubidots account then you need to read my article on the Raspberry Pi Pico and Ubidots. Anyway, after you have logged into your Ubidots account, then click on the Profile, and click on the API credentials.
Next, copy the Token. And open the Transmitter and Receiver side codes in the Arduino IDE. The codes are given in the programming section below.
Paste this token in the code as you can see in the image below.
Upload the program in the receiver side Raspberry Pi Pico W. We need to do this first, as we want the Raspberry Pi Pico W, Potvalue, and Gasvalue variables to appear in Ubidots. For this, we will need to upload the program, make sure your WiFi router or Hotspot is ON, because once the program is uploaded; Raspberry Pi Pico W will automatically connect with the WiFi.
I uploaded the program and now let’s go back to Ubidots. You can see Raspberry Pi Pico W has been added as a device in Ubidots.
Now, If you click on this device ”raspberrypipicow” you will see the gasvalue and potvalue variable names along with their corresponding readings. Now, you are free to use variables throughout Ubidots.
Anyway, go to the Data menu and click on the Dashboards.
Click on Add new Widget.
Then click on the gauge. If you want you can select any other Gauge.
Click on ADD VARIABLES. Click on raspberry pi pico w which has been added as a device.
Then select the variable and click on the select button.
Then click on the APPEARANCE.
Then in the appearance change the name and limits of the widget and click on the save button.
A Gauge has been added.
Add another gauge for the Potentiometer by following the same exact steps.
The Dashboard is ready and now let’s take a look at the programming.
Required Libraries:
Before, you start downloading all the required libraries, first you will need to install the Raspberry Pi Pico board in the Arduino IDE. For this you can ready my getting started article on the Raspberry Pi Pico and Arduino IDE. After you have successfully installed the Raspberry Pi Pico board in the Arduino IDE then you can start downloading all the required libraries.
Download the liquidCrystal_I2C and unzip the folder. Open the folder and copy the .h and .cpp files and paste them in the receiver side programming folder. The receiver side main code and these .h and .cpp files are need to inside the same folder.
You will also need to download and install the
#include <WiFi.h>
#include <PubSubClient.h>
For this you can read my getting started article on the Nodemcu ESP8266 WiFi module, because this WiFi library is from there. And for the PubSubClient.h read my article on the Ubidots and raspberry pi pico w; link to the article I have already shared above.
Raspberry Pi Pico LoRa Tx Code:
/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
/* Raspberry pi pico transmitter https://www.electroniclinic.com/ */ #include <SPI.h> // include libraries #include <LoRa.h> #include "LiquidCrystal_I2C.h" #include <Wire.h> #define PCF8574 0x27 #define PCF8574A 0x3F TwoWire Wire_00(i2c0, 0,1); // SDA, SCL LiquidCrystal_I2C lcd(&Wire_00, PCF8574, 16, 2); #define nss 8 #define rst 9 #define dio0 7 byte MasterNode = 0xFF; byte Node2 = 0xCC; int pot2=26; // Potentiometer int sensorPin=27; // MQ-9 Gas Sensor int sensorData; String SenderNode = ""; String outgoing; // outgoing message String message1; String message2; byte msgCount = 0; // count of outgoing messages // Tracks the time since last event fired unsigned long previousMillis=0; unsigned long int previoussecs = 0; unsigned long int currentsecs = 0; unsigned long currentMillis = 0; int Secs = 0; long lastSendTime = 0; // last send time int interval = 20; // interval between sends void setup() { Serial.begin(115200); // initialize serial Wire_00.begin(); Wire_00.setClock(100000); // 100kHz lcd.begin(); lcd.backlight(); //lcd.print("Pot Value"); pinMode(pot2,INPUT); pinMode(sensorPin,INPUT); LoRa.setPins(nss, rst, dio0); if (!LoRa.begin(433E6)) { // initialize ratio at 915 MHz Serial.println("LoRa init failed. Check your connections."); while (true); // if failed, do nothing } Serial.println("LoRa init succeeded."); } void loop() { if (millis() - lastSendTime > interval) { int sensor2; sensor2 = analogRead(pot2); Serial.println(sensor2); sensorData = analogRead(sensorPin); Serial.print("Sensor Data:"); Serial.println(sensorData); lcd.clear(); lcd.setCursor(0,0); lcd.print("Pot value:"); lcd.print(sensor2); lcd.setCursor(0,1); lcd.print("Gas value:"); lcd.print(sensorData); message2=message2 + sensor2 +","+sensorData; sendMessage(message2,MasterNode,Node2); delay(50); //Serial.println("Sending " + message); lastSendTime = millis(); // timestamp the message // interval = random(50); message1=""; message2 = ""; delay(1000); } } void sendMessage(String outgoing, byte MasterNode, byte otherNode) { LoRa.beginPacket(); // start packet LoRa.write(otherNode); // add destination address LoRa.write(MasterNode); // add sender address LoRa.write(msgCount); // add message ID LoRa.write(outgoing.length()); // add payload length LoRa.print(outgoing); // add payload LoRa.endPacket(); // finish packet and send it msgCount++; // increment message ID } |
This is the Transmitter side programming and this is the receiver side programming. As usual before you start the programming, first of all, make sure you download all the necessary libraries from my website www.electroniclinic.com. I will provide a link in the description. Let’s first start with the Transmitter side programming.
90% of this code is from my previous tutorial based on the Raspberry Pi Pico and LoRa. I made a few changes in this code. I added code for a Gas sensor, while previously I was using only one sensor. This time I am using 2 sensors, if you want you can add more sensors. Another change that I made is, I shifted the I2C 16×2 LCD on the transmitter side, previously it was on the receiver side. Make sure you save these .h and .cpp files in the same folder with the main programming file.
Raspberry Pi Pico W LoRa Rx Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
/* Raspberry pi pico w receiver https://www.electroniclinic.com/ */ #include <SPI.h> // include libraries #include <LoRa.h> #include <WiFi.h> #include <PubSubClient.h> String outgoing; // outgoing message byte msgCount = 0; // count of outgoing messages byte MasterNode = 0xFF; byte Node2 = 0xCC; #define nss 8 #define rst 9 #define dio0 7 #define WIFISSID "AndroidAP3DEC" // Put your WifiSSID here #define PASSWORD "electroniclinic" // Put your wifi password here #define TOKEN "BBFF-yrh0STxs2bWHPqOFmDPj7UfKKVyLwJ" // Put your Ubidots' TOKEN #define MQTT_CLIENT_NAME "Raspberrypi_MQ9_Monitoring" // MQTT client Name, please enter your own 8-12 alphanumeric character ASCII string; #define VARIABLE_LABEL1 "Potvalue" // Assing the variable label #define VARIABLE_LABEL2 "Gasvalue" // Assing the variable label #define DEVICE_LABEL "RaspberryPiPicoW" char mqttBroker[] = "industrial.api.ubidots.com"; char payload[1000]; char topic1[150]; char topic2[150]; char str_potvalue[10]; char str_gasvalue[10]; WiFiClient ubidots; PubSubClient client(ubidots); void callback(char* topic, byte* payload, unsigned int length) { char p[length + 1]; memcpy(p, payload, length); p[length] = NULL; String message(p); Serial.write(payload, length); Serial.println(topic); } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.println("Attempting MQTT connection..."); // Attemp to connect if (client.connect(MQTT_CLIENT_NAME, TOKEN, "")) { Serial.println("Connected"); } else { Serial.print("Failed, rc="); Serial.print(client.state()); Serial.println(" try again in 2 seconds"); // Wait 2 seconds before retrying delay(2000); } } } void setup() { Serial.begin(115200); LoRa.setPins(nss, rst, dio0); if (!LoRa.begin(433E6)) { // initialize ratio at 915 MHz Serial.println("LoRa init failed. Check your connections."); while (true); // if failed, do nothing } Serial.println("LoRa init succeeded."); WiFi.begin(WIFISSID, PASSWORD); Serial.println(); Serial.print("Waiting for WiFi Connection .............."); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(""); Serial.println("WiFi Connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); client.setServer(mqttBroker, 1883); client.setCallback(callback); } void loop() { if (!client.connected()) { reconnect(); } // parse for a packet, and call onReceive with the result: onReceive(LoRa.parsePacket()); } void onReceive(int packetSize) { if (packetSize == 0) return; // if there's no packet, return // read packet header bytes: int recipient = LoRa.read(); // recipient address byte sender = LoRa.read(); // sender address byte incomingMsgId = LoRa.read(); // incoming msg ID byte incomingLength = LoRa.read(); // incoming msg length String incoming = ""; while (LoRa.available()) { incoming += (char)LoRa.read(); } if (incomingLength != incoming.length()) { // check length for error // Serial.println("error: message length does not match length"); ; return; // skip rest of function } // if the recipient isn't this device or broadcast, if (recipient != Node2 && recipient != MasterNode) { //Serial.println("This message is not for me."); ; return; // skip rest of function } // Serial.println(incoming); // int Val = incoming.toInt(); String q = getValue(incoming, ',', 0); String gas = getValue(incoming, ',', 1); int potvalue = q.toInt(); int gasvalue = gas.toInt(); dtostrf(potvalue, 4, 2, str_potvalue); dtostrf(gasvalue, 4, 2, str_gasvalue); sprintf(topic1, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL1); sprintf(payload, "%s {\"value\": %s}}", payload, str_potvalue); Serial.println("Publishing Potentiometer value to Ubidots Cloud"); client.publish(topic1, payload); sprintf(topic2, "%s%s", "/v1.6/devices/", DEVICE_LABEL); sprintf(payload, "%s", ""); sprintf(payload, "{\"%s\":", VARIABLE_LABEL2); sprintf(payload, "%s {\"value\": %s}}", payload, str_gasvalue); Serial.println("Publishing humidity to Ubidots Cloud"); client.publish(topic2, payload); Serial.println(); client.loop(); delay(5000); Serial.println(potvalue); Serial.println(gasvalue); incoming=""; delay(1000); } String getValue(String data, char separator, int index) { int found = 0; int strIndex[] = { 0, -1 }; int maxIndex = data.length() - 1; for (int i = 0; i <= maxIndex && found <= index; i++) { if (data.charAt(i) == separator || i == maxIndex) { found++; strIndex[0] = strIndex[1] + 1; strIndex[1] = (i == maxIndex) ? i+1 : i; } } return found > index ? data.substring(strIndex[0], strIndex[1]) : ""; } |
Watch Video Tutorial:
Hi Shahzada,
I read your article on this Pico with Lora project and this project is based on C programming. Is there any chance that you have it in micropython code?
Regards,
Clarence