Raspberry Pi Pico

LoRa and Raspberry Pi Pico W based Home Automation Project with Feedback

LoRa and Raspberry Pi Pico:

 

LoRa and Raspberry Pi Pico W based Home Automation Project with Feedback– In this tutorial, you will learn how to make a Long Range Radio controlled wireless Home automation project using a pair of Raspberry Pi Pico boards, and it doesn’t matter if you use normal Raspberry Pi Pico boards or Raspberry Pi Pico W boards. You will also need a pair of SX1278 Lora Transceiver modules, an I2C-supported 16×2 LCD, some switches, a relay module, and 110/220Vac light bulbs. 

Ever since I have started this website, since then I have built many home automation projects using different controller boards like Arduino Mega, Arduino Uno, Arduino Nano, Nodemcu ESP8266, ESP32 WiFi + Bluetooth Module, Raspberry Pi Pico and so on; with these controller boards I used desktop applications, android cell phone applications designed in Android Studio, different IoT platforms like Blynk application, Ubidots, Thingspeak, Arduino IoT Cloud, Google Spreadsheet, InfluxDB, Cayenne, Adafruit Io, and so many other IoT platforms. Just go ahead and check different categories. 




Anyway, recently I built a Home automation project using Raspberry Pi Pico and HC-05 Bluetooth module. I used my designed android application for controlling 220Vac light bulbs. This Home automation project was insanely fast and personally, I never had such an amazing experience with any other controller board. This was absolutely error-free, there was no false triggering, and it won’t freeze.

So, keeping in mind this speed and performance, I decided to convert one of my previously designed Arduino and LoRa based Home automation project into Raspberry Pi Pico and LoRa based Home automation project with feedback message.

Anyway, here is a prototype model of my Raspberry Pi Pico and LoRa based Home automation project. I have connected everything as per the circuit diagrams which I will explain in a minute.

LoRa and Raspberry Pi Pico

You can see 4 buttons on the transmitter side. Using these very 4 buttons, I am going to control certain loads on the receiver side. For demonstration purposes, I have put 4 bulbs on the receiver’s side, which are connected to 4 relays. Besides lights, you can use any other 110/220Vac loads or use any other DC type loads.

If you want to use 110/220Vac supply, you must not forget to use protective gloves, because 110/220Vac can prove fatal. So, as far as possible you must ensure the presence of a friend or any companion while carrying on work on such projects. When the AC supply is ON, do not touch the relay module.

I am using the same SX1278 Lora Transceiver modules on the receiver as well as the transmitter side.

The reason I am using this 16×2 LCD on the transmitter side is to display the loads status. This way I know exactly which loads are ON and which loads are OFF. So, whenever I turn ON/OFF any button on the transmitter side, the receiver side sends me a feedback whether that load has turned ON or not. You will find this feedback functionality quite handy in situations when you are away and the loads are not visible to you. Let’s go ahead and start a practical demonstration so that you can see everything for yourself.



Altium Designer + Altium 365 + Octopart:

Arduino LoRa Free SMS

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.

LoRa and Raspberry Pi Pico

I can randomly turn ON and turn OFF any light and it is working quite superbly. This small delay occurs because I have used timers on the transmitter and receiver sides. You can increase or decrease the timer value if you want.

This Raspberry Pi Pico and Lora based automation system presents quite a practical look. Whenever I turn ON/OFF any button on the transmitter side, the receiver side sends me a feedback whether that load has turned ON or not.

Now even if I do not see electrical appliances or loads, there is no problem, because I keep on receiving feedback from the receiver’s side. Now, if there is some issue on the receiver side, I’ll not receive any kind of feedback. Or if I get out of the range, even then I’ll receive no feedback. To explain this point, I am going to turn OFF the receiver side.

LoRa and Raspberry Pi Pico

Now you can see, that I am not receiving any type of feedback. It’s still displaying the same message. While if you take a look at the switches; you can see switch2 and switch3 are ON. But on the LCD it shows that D1 and D2 are ON as this is the old message.  Now if I turn ON the receiver side once again, I will start receiving the feedback. I have been testing this project and it is working exceptionally well. For the step-by-step explanation and practical demonstration watch my video tutorial available on Electronic Clinic or you can click on the video link given at the end of this article. 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:

Raspberry Pi Pico

Raspberry Pi Pico W

Raspberry Pi Pico W Kit

I2C supported 16×2 LCD

Sx1278 LoRa Transceiver modules

Relay Module

Other Tools and Components:

Top Arduino Sensors:

Super Starter kit for Beginners

Digital Oscilloscopes

Variable Supply

Digital Multimeter

Soldering iron kits

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.

LoRa and Raspberry Pi Pico

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.

LoRa and Raspberry Pi Pico

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…

RPI Pico & LoRa Tx Circuit:

LoRa and Raspberry Pi Pico

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.

4 switches are connected with the GPIO pins 2, 4, 6, and 15.

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.

LoRa and Raspberry Pi Pico



RPI Pico & LoRa Rx Circuit:

LoRa and Raspberry Pi Pico

This is the receiver side circuit diagram. You can see the LoRa SX1278 connection with the Raspberry Pi Pico remains exactly the same. The 4 channels relay module inputs are connected with the Raspberry Pi Pico GPIO pins 2, 3, 4, and 5. If you are using a 5v relay module then you can connect the VCC of the relay module with the VBUS pin of the Raspberry Pi Pico to supply 5 volts. And if you are using a 12V relay module then you will need to connect an external 12v power supply. So, that’s all about the receiver side circuit diagram. Now, let’s go ahead and 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 read 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.

LoRa.h

LiquidCrystal_I2C

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.

LoRa and Raspberry Pi Pico

LoRa & Raspberry Pi Pico Tx Code:

/*
  Transmitter code
  Home Automation project by 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


int sw1 = 2; 
int sw2 = 4; 
int sw3 = 6; 
 int sw4 = 15;
 int Sensor1 = 0; 
int Sensor2 = 0; 
int Sensor3 = 0;  
int Sensor4 = 0;  
boolean bflag = false;
String outgoing;              // outgoing message

byte msgCount = 0;            // count of outgoing messages
byte localAddress = 0xBB;     // address of this device
byte destination = 0xFF;      // destination to send to
long lastSendTime = 0;        // last send time
int interval = 50;          // interval between sends


String Mymessage = "";
void setup() {
  Serial.begin(9600);                   // initialize serial
   LoRa.setPins(nss, rst, dio0);
  Wire_00.begin();
  Wire_00.setClock(100000); // 100kHz
  lcd.begin();
  lcd.backlight();
 
    pinMode(sw1, INPUT_PULLUP);
  pinMode(sw2, INPUT_PULLUP); 
  pinMode(sw3, INPUT_PULLUP); 
 pinMode(sw4, INPUT_PULLUP);

  Serial.println("LoRa Duplex");

  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) {
   Sensor1 = digitalRead(sw1);
    Sensor2 = digitalRead(sw2); 
    Sensor3 = digitalRead(sw3);
       Sensor4 = digitalRead(sw4);
    Mymessage = Mymessage + Sensor1 +"," + Sensor2 + "," + Sensor3 +"," + Sensor4;  
    Serial.println(Mymessage);
    sendMessage(Mymessage);
    Mymessage = "";
    
    //Serial.println("Sending " + message);
    lastSendTime = millis();            // timestamp the message
    interval = random(50) + 100;  
    
    }

      // parse for a packet, and call onReceive with the result:
  onReceive(LoRa.parsePacket());
  }

void sendMessage(String outgoing) {
  LoRa.beginPacket();                   // start packet
  LoRa.write(destination);              // add destination address
  LoRa.write(localAddress);             // 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
}

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 != localAddress && recipient != 0xFF) {
   // Serial.println("This message is not for me.");
    ;
    return;                             // skip rest of function
  }
  // if message is for this device, or broadcast, print details:
  //Serial.println("Received from: 0x" + String(sender, HEX));
  //Serial.println("Sent to: 0x" + String(recipient, HEX));
  //Serial.println("Message ID: " + String(incomingMsgId));
 // Serial.println("Message length: " + String(incomingLength));
  Serial.println("Message: " + incoming);
//  Serial.println("RSSI: " + String(LoRa.packetRssi()));
//  Serial.println("Snr: " + String(LoRa.packetSnr()));
//  Serial.println();
  String device1 = getValue(incoming, ',', 0); 
    String device2 = getValue(incoming, ',', 1); 
      String device3 = getValue(incoming, ',', 2); 
    String device4 = getValue(incoming, ',', 3);
     int d1 = device1.toInt();
     int d2 = device2.toInt();
     int d3 = device3.toInt();
     int d4 = device4.toInt();

    //clear display
  lcd.clear();
     lcd.setCursor(0,0);   
  lcd.print("D1:");
  lcd.print(d1);
   lcd.print(" D2:");
  lcd.print(d2);
  lcd.setCursor(0,1);
  
   lcd.print("D3:");
  lcd.print(d3);
   
   lcd.print(" D4:");
  lcd.print(d4);
incoming = "";

}
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]) : "";
}



LoRa & Raspberry Pi Pico Rx Code:

/*
 Receiver code
 Home Automation project by https://www.electroniclinic.com/

*/
#include <SPI.h>              // include libraries
#include <LoRa.h>

 #define nss 8
#define rst 9
#define dio0 7

boolean flag1 = false;
boolean flag2 = false;

boolean flag3 = false;
boolean flag4 = false; 

int RLY1=2;
int RLY2=3;
int RLY3=4;
int RLY4=5;

int Sensor1 = 0; 
int Sensor2 = 0; 
int Sensor3 = 0; 
int Sensor4 = 0; 

int relay1Status;
int relay2Status;
int relay3Status;
int relay4Status;

String outgoing;              // outgoing message

byte msgCount = 0;            // count of outgoing messages
byte localAddress = 0xFF;     // address of this device
byte destination = 0xBB;      // destination to send to
long lastSendTime = 0;        // last send time
int interval = 50;          // interval between sends

String statusmessage = "";

void setup() {
  Serial.begin(9600);                   // initialize serial


 pinMode(RLY1,OUTPUT);
  pinMode(RLY2,OUTPUT);
    pinMode(RLY3,OUTPUT);
      pinMode(RLY4,OUTPUT);
 LoRa.setPins(nss, rst, dio0);
  Serial.println("LoRa Duplex");

  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) {
  relay1Status = digitalRead(RLY1);
       relay2Status = digitalRead(RLY2);
        relay3Status = digitalRead(RLY3);
         relay4Status = digitalRead(RLY4);
        statusmessage = statusmessage + relay1Status + "," + relay2Status + "," + relay3Status + "," + relay4Status;
        sendMessage(statusmessage); 
delay(10);
statusmessage = "";
    lastSendTime = millis();            // timestamp the message
    interval = random(50) + 100;    // 2-3 seconds
  }
  

  // parse for a packet, and call onReceive with the result:
  onReceive(LoRa.parsePacket());
}

void sendMessage(String outgoing) {
  LoRa.beginPacket();                   // start packet
  LoRa.write(destination);              // add destination address
  LoRa.write(localAddress);             // 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
}

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 != localAddress && recipient != 0xFF) {
    //Serial.println("This message is not for me.");
    ;
    return;                             // skip rest of function
  }

  // if message is for this device, or broadcast, print details:
 // Serial.println("Received from: 0x" + String(sender, HEX));
 // Serial.println("Sent to: 0x" + String(recipient, HEX));
  //Serial.println("Message ID: " + String(incomingMsgId));
 // Serial.println("Message length: " + String(incomingLength));
  Serial.println("Message: " + incoming);
  //Serial.println("RSSI: " + String(LoRa.packetRssi()));
  //Serial.println("Snr: " + String(LoRa.packetSnr()));
  Serial.println();
   String q = getValue(incoming, ',', 0); 
String r = getValue(incoming, ',', 1); 
String s = getValue(incoming, ',', 2); 
String t = getValue(incoming, ',', 3); 
Sensor1 = q.toInt();
Sensor2 = r.toInt();
Sensor3 = s.toInt();
Sensor4 = t.toInt();
if((Sensor1 == 0)&&(flag1==true))
{
 
  digitalWrite(RLY1,HIGH);
   relay1Status = 1;
  Serial.println("Relay 1 is turned on");
  flag1=false;
}

if((Sensor1 == 1)&&(flag1 ==false))
{

  digitalWrite(RLY1,LOW);
   relay1Status = 0;
  Serial.println("Relay 1 is turned off");
  flag1=true;
}
if((Sensor2 == 0)&&(flag2==true))
{
 
  digitalWrite(RLY2,HIGH);
   relay2Status = 0;
  Serial.println("Relay 2 is turned on");
  flag2=false;
}

if((Sensor2 == 1)&&(flag2 ==false))
{

  digitalWrite(RLY2,LOW);
  relay2Status = 0;
  Serial.println("Relay 2 is turned off");
  flag2=true;
}
if((Sensor3 == 0)&&(flag3==true))
{
 
  digitalWrite(RLY3,HIGH);
  relay3Status = 1;
  Serial.println("Relay 3 is turned on");
  flag3=false;
}

if((Sensor3 == 1)&&(flag3 ==false))
{

  digitalWrite(RLY3,LOW);
  relay3Status = 0;
  Serial.println("Relay 3 is turned off");
  flag3=true;
}

if((Sensor4 == 0)&&(flag4==true))
{
 
  digitalWrite(RLY4,HIGH);
  relay4Status = 1;
  Serial.println("Relay 4 is turned on");
  flag4=false;
}

if((Sensor4 == 1)&&(flag4 ==false))
{

  digitalWrite(RLY4,LOW);
  relay4Status = 0;
  Serial.println("Relay 4 is turned off");
  flag4=true;
}

incoming = "";
  
}
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]) : "";
}

90% of the transmitter and receiver code is from my Arduino and LoRa based automation project. I made a few changes in the code, on the transmitter side I am using a 16×2 LCD instead of using an Oled display and the other changes are I am using different pin numbers. While everything else remains exactly the same. So, that’s all about the programming.




Watch Video Tutorial:

 

Engr Fahad

My name is Shahzada Fahad and I am an Electrical Engineer. I have been doing Job in UAE as a site engineer in an Electrical Construction Company. Currently, I am running my own YouTube channel "Electronic Clinic", and managing this Website. My Hobbies are * Watching Movies * Music * Martial Arts * Photography * Travelling * Make Sketches and so on...

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button