Appliance Control from Smartphone Using Arduino and LoRa
In this project, we design a long-range appliance control system that can be controlled from mobile phone using Arduino and the Reyax RYLR999 LoRa + BLE module.
Devices & Components
1
16x2 LCD display with I²C interface
2
Arduino Nano
1
40 colored male-female jumper wires
1
Logic Level Converter Bi-Directional 3.3V-5V Shifter Module
1
2 Channel DC 5V Relay Module
1
RYLR999 Module
Software & Tools
Arduino IDE
Project description
Code
Arduino Code for Controller
cpp
LoRa communication on Controller side
1/* 2Code to receive commands fom Mobile device using blutooth functionality of RLY999 module and 3send these commands from one Arduino to another Arduino using LORA functionality of RYL999 Module and Display 4complete communication on I2C LCD by platwithcircuit.com 5*/ 6#include <LiquidCrystal_I2C.h> 7#include <SoftwareSerial.h> 8 9// below MACROS are for LORA communication 10#define REPLY_TIMEOUT_IN_MS 300 11#define REPLY_END_CHAR '\n' 12#define SELF_ADDRESS 0 13#define RECEIVERS_ADDRESS 1 14#define MIN_CHAR_TO_RCV 1 15#define WAIT_FOR_RECIVERS_REPLY 3000 16 17// below MACROS and strings are for Bluetooth communication 18#define START_CHAR_BT_COMM '*' 19#define END_CHAR_BT_COMM '#' 20#define START_CHAR_TIME_OUT_BT_COMM (3000U) // time in ms 21#define END_CHAR_TIME_OUT_BT_COMM (300U) // time in ms 22 23// these four strings can be received from bluetooth Rx pin which are transmitted by the mobile application 24String sCMDLampON = "L1"; 25String sCMDLampOFF = "L0"; 26String sCMDFanON = "F1"; 27String sCMDFanOFF = "F0"; 28 29// save received command in this global string object 30String receivedCommand; 31 32// initialize softserial port at pin 3(Rx) and 2(Tx) 33SoftwareSerial btSerial(3, 2); 34 35// Init LCD at 0x27, 16x2 36LiquidCrystal_I2C lcd(0x27, 16, 2); 37 38void setup() { 39 boolean boRetVal = false; 40 // begin serial communication at baud 115200,n,8,1 41 // to communicate with the LORA functionality of module 42 Serial.begin(115200); 43 // begin soft serial communicatio at baud 115200,n,8,1 44 // to communicate with the Bluetooth functionality of module 45 btSerial.begin(115200); 46 btSerial.setTimeout(END_CHAR_TIME_OUT_BT_COMM); // set time out for readStringUntil() function 47 48 // Initialize the LCD 49 lcd.init(); 50 // Turn ON the Backlight 51 lcd.backlight(); 52 // Clear the display buffer 53 lcd.clear(); 54 55 receivedCommand.reserve(50); // prevents fragmentation, as multiple times data shall be received in this string 56 57 // clear receive buffer of LORA 58 flushBuffer(); // clear rx data 59 60 // Reset settings to factory defaults for LORA functionality 61 boRetVal = boRestoreFactoryDefaults(); 62 63 // setting the address of LORA 64 if (boRetVal == true) { 65 flushBuffer(); // clear rx data 66 boRetVal = boSetAddress(); 67 } 68 69 if (boRetVal == true) { 70 lcd.clear(); 71 lcd.setCursor(0, 0); 72 lcd.print("Module Init"); 73 lcd.setCursor(0, 1); 74 lcd.print("Successful"); 75 delay(1000); 76 } else { 77 lcd.clear(); 78 lcd.setCursor(0, 0); 79 lcd.print("Module Init"); 80 lcd.setCursor(0, 1); 81 lcd.print("Failed"); 82 while (1) 83 ; 84 } 85} 86 87void loop() { 88 String expected_reply = "DONE"; 89 bool boRetVal = false; 90 91 flushBuffer(); // clear rx data 92 93 // get commands using BT funtionality using Mobile Application 94 boRetVal = rcvCommand(START_CHAR_TIME_OUT_BT_COMM); 95 96 if (boRetVal == false) { 97 // Displaying Failed Msg 98 lcd.clear(); 99 lcd.setCursor(0, 0); 100 lcd.print("No BT Command"); 101 lcd.setCursor(0, 1); 102 lcd.print("Received"); 103 } else { 104 // check if valid command is received 105 if ((receivedCommand == sCMDLampON) || (receivedCommand == sCMDLampOFF) || (receivedCommand == sCMDFanON) || (receivedCommand == sCMDFanOFF)) { 106 // tranmits receivedCommand 107 boRetVal = boSendData(receivedCommand); 108 if (boRetVal == true) { 109 // Displaying Sent Msg 110 lcd.clear(); 111 lcd.setCursor(0, 0); 112 lcd.print("Cmd Rcvd & Sent"); 113 lcd.setCursor(0, 1); 114 lcd.print(receivedCommand); 115 delay(1000); 116 boRetVal = chkReply(expected_reply, REPLY_END_CHAR, WAIT_FOR_RECIVERS_REPLY); 117 118 if (boRetVal == true) { 119 // Displaying received Msg 120 lcd.clear(); 121 lcd.setCursor(0, 0); 122 lcd.print("Reply Received:"); 123 lcd.setCursor(0, 1); 124 lcd.print(expected_reply); 125 } else { 126 lcd.clear(); 127 lcd.setCursor(0, 0); 128 lcd.print("No Reply"); 129 lcd.setCursor(0, 1); 130 lcd.print("Received"); 131 } 132 } else { 133 // Displaying Failed Msg 134 lcd.clear(); 135 lcd.setCursor(0, 0); 136 lcd.print("Command"); 137 lcd.setCursor(0, 1); 138 lcd.print("Sending Failed"); 139 } 140 } else { 141 // Displaying Invalid Msg 142 lcd.clear(); 143 lcd.setCursor(0, 0); 144 lcd.print("Invalid: "); 145 lcd.print(receivedCommand); 146 lcd.setCursor(0, 1); 147 lcd.print("Command Received"); 148 } 149 } 150} 151/******************************************** Function Defenition Related to LORA Functionality ***********************/ 152 153void sendCrLf(void) { 154 Serial.write(0x0D); // Carriage Return 155 Serial.write(0x0A); // Line Feed 156} 157 158// clear receive buffer of LORA 159void flushBuffer(void) { 160 while (Serial.available() > 0) { 161 Serial.read(); 162 } 163} 164 165// check data on rx pin of LORA functionality 166bool chkReply(String chkString, char receiveUntil, unsigned int timeout) { 167 String receivedString; // save received data in this string object 168 bool boReturnValue = false; // function's return value 169 170 // wait for reply 171 do { 172 timeout--; 173 delay(1); // delay of 1 ms 174 } while ((Serial.available() < MIN_CHAR_TO_RCV) && (timeout > 0)); 175 176 if (timeout) { 177 // if timeout is left then a reply is received check for the string in the reply 178 receivedString = Serial.readStringUntil(receiveUntil); 179 if (receivedString.indexOf(chkString) != -1) { 180 boReturnValue = true; 181 } else { 182 boReturnValue = false; 183 } 184 } else { 185 boReturnValue = false; 186 } 187 188 // return result 189 return boReturnValue; 190} 191 192// Reset settings to factory defaults for LORA functionality 193bool boRestoreFactoryDefaults(void) { 194 const char factoryDefaultCmd[] = "AT+FACTORY"; // command to be sent 195 bool boReturnValue = false; // function's return value 196 char downCounter = 100; // Down counter to wait for reply 197 String receivedString; // save received data in this string object 198 199 String chkRcvString1 = "+FACTORY"; 200 String chkRcvString2 = "+READY"; 201 202 // send command 203 Serial.print(factoryDefaultCmd); 204 sendCrLf(); 205 206 // check first string in reply 207 boReturnValue = chkReply(chkRcvString1, REPLY_END_CHAR, REPLY_TIMEOUT_IN_MS); 208 if (boReturnValue == true) { 209 // check second string in reply 210 boReturnValue = chkReply(chkRcvString2, REPLY_END_CHAR, REPLY_TIMEOUT_IN_MS); 211 } 212 213 // return result 214 return boReturnValue; 215} 216 217// setting the address of LORA 218bool boSetAddress(void) { 219 const char setAddressCmd[] = "AT+ADDRESS="; // command to be sent 220 bool boReturnValue = false; // function's return value 221 String chkRcvString = "+OK"; 222 223 // send command 224 Serial.print(setAddressCmd); 225 Serial.print(SELF_ADDRESS); 226 sendCrLf(); 227 228 // check reply 229 boReturnValue = chkReply(chkRcvString, REPLY_END_CHAR, REPLY_TIMEOUT_IN_MS); 230 231 // return result 232 return boReturnValue; 233} 234 235// Send data to LORA in command form 236bool boSendData(String data) { 237 const char sendDataCmd[] = "AT+SEND="; // command to be sent 238 bool boReturnValue = false; // function's return value 239 String chkRcvString = "+OK"; 240 241 // send command 242 Serial.print(sendDataCmd); 243 Serial.print(RECEIVERS_ADDRESS); 244 Serial.print(','); 245 Serial.print(data.length()); 246 Serial.print(','); 247 Serial.print(data); 248 sendCrLf(); 249 250 // check reply 251 boReturnValue = chkReply(chkRcvString, REPLY_END_CHAR, REPLY_TIMEOUT_IN_MS); 252 253 // return result 254 return boReturnValue; 255} 256 257/******************************************** Function Defenition Related to BT Functionality *************************/ 258 259// Receive Command from Rx pin of Bluetooth functionality 260bool rcvCommand(unsigned int timeout) { 261 bool boReturnValue = false; // function's return value 262 unsigned long startTime; 263 264 // wait for reply 265 do { 266 timeout--; 267 delay(1); // delay of 1 ms 268 if (((btSerial.available() >= MIN_CHAR_TO_RCV) && (btSerial.read() == START_CHAR_BT_COMM)) || (timeout == 0)) { 269 break; 270 } 271 } while (1); 272 273 // if start cracter is receved within time then timeout will be greater tahn or equal to 1 274 if (timeout) { 275 startTime = millis(); 276 receivedCommand = btSerial.readStringUntil(END_CHAR_BT_COMM); 277 if ((millis() - startTime) <= END_CHAR_TIME_OUT_BT_COMM) { 278 boReturnValue = true; // it means in readStringUntil() function '#' is received 279 } else { 280 boReturnValue = false; // it means in readStringUntil() function timeout has occured 281 } 282 } else { 283 boReturnValue = false; // it means get character timeout has occured 284 } 285 286 // return result 287 return boReturnValue; 288}
Arduino Code for Target
cpp
Arduino Code for Target
1/* 2Code to receieve commands to control the appliances from another Arduino using RLYR999 Module 3and send "DONE" in reply after implementing the required task and display the communication and tasks over I2C LCD. 4The appliances Lamp and Fan are connected to relay which will be turne ON and OFF based on commands received 5by platwithcircuit.com 6*/ 7#include <LiquidCrystal_I2C.h> 8 9// below MACROS are for LORA communication 10#define REPLY_TIMEOUT_IN_MS 300 11#define REPLY_END_CHAR '\n' 12#define CMD_END_CHAR '\n' 13#define MODULE_ADDRESS 1 14#define TRANSMITTER_ADDRESS 0 15#define MIN_CHAR_TO_RCV 1 16#define WAIT_FOR_REQUEST 3000 17 18// these four commands can be received from controller module 19String sCMDLampON = "L1"; 20String sCMDLampOFF = "L0"; 21String sCMDFanON = "F1"; 22String sCMDFanOFF = "F0"; 23 24// save received command in this global string object 25String receivedCommand; 26 27// Init LCD at 0x27, 16x2 28LiquidCrystal_I2C lcd(0x27, 16, 2); 29 30// Appliance Control MACROS 31#define LAMP_CTRL_PIN 11 32#define FAN_CTRL_PIN 12 33 34#define LAMP_ON() digitalWrite(LAMP_CTRL_PIN, 0) 35#define LAMP_OFF() digitalWrite(LAMP_CTRL_PIN, 1) 36#define FAN_ON() digitalWrite(FAN_CTRL_PIN, 0) 37#define FAN_OFF() digitalWrite(FAN_CTRL_PIN, 1) 38 39void setup() { 40 boolean boRetVal = false; 41 // begin serial commmunicatio at baud 115200,n,8,1 42 // to comunicate with the RF module 43 Serial.begin(115200); 44 45 // Initialize the LCD 46 lcd.init(); 47 // Turn ON the Backlight 48 lcd.backlight(); 49 // Clear the display buffer 50 lcd.clear(); 51 52 // initialize applinaces pins and turn off 53 pinMode(LAMP_CTRL_PIN, OUTPUT); 54 pinMode(FAN_CTRL_PIN, OUTPUT); 55 LAMP_OFF(); 56 FAN_OFF(); 57 58 receivedCommand.reserve(50); // prevents fragmentation, as multiple times data shall be received in this string 59 60 delay(1000); 61 62 flushBuffer(); // clear rx data 63 64 // Reset settings to factory defaults 65 boRetVal = boRestoreFactoryDefaults(); 66 67 // setting the address if reset successfull 68 if (boRetVal == true) { 69 flushBuffer(); // clear rx data 70 boRetVal = boSetAddress(); 71 } 72 73 if (boRetVal == true) { 74 lcd.clear(); 75 lcd.setCursor(0, 0); 76 lcd.print("Module Init"); 77 lcd.setCursor(0, 1); 78 lcd.print("Successful"); 79 delay(1000); 80 } else { 81 lcd.clear(); 82 lcd.setCursor(0, 0); 83 lcd.print("Module Init"); 84 lcd.setCursor(0, 1); 85 lcd.print("Failed"); 86 while (1) 87 ; 88 } 89} 90 91void loop() { 92 String expected_reply = "DONE"; 93 bool boRetVal = false; 94 95 // check string sent by Initiator 96 boRetVal = rcvCommand(CMD_END_CHAR, WAIT_FOR_REQUEST); 97 98 if (boRetVal == false) { 99 // Displaying Failed Msg 100 lcd.clear(); 101 lcd.setCursor(0, 0); 102 lcd.print("No Command"); 103 lcd.setCursor(0, 1); 104 lcd.print("Received"); 105 } else { 106 // check if valid command is received 107 if ((receivedCommand == sCMDLampON) || (receivedCommand == sCMDLampOFF) || (receivedCommand == sCMDFanON) || (receivedCommand == sCMDFanOFF)) { 108 // Implement receivedCommand 109 vImplementTask(receivedCommand); 110 // Displaying Sent Msg 111 lcd.clear(); 112 lcd.setCursor(0, 0); 113 lcd.print("Command Received"); 114 lcd.setCursor(0, 1); 115 lcd.print("Task Done"); 116 delay(1000); 117 // tranmits receivedCommand 118 boRetVal = boSendData(expected_reply); 119 if (boRetVal == true) { 120 // Displaying Sent Msg 121 lcd.clear(); 122 lcd.setCursor(0, 0); 123 lcd.print("Reply Sent"); 124 } else { 125 // Displaying Failed Msg 126 lcd.clear(); 127 lcd.setCursor(0, 0); 128 lcd.print("Reply"); 129 lcd.setCursor(0, 1); 130 lcd.print("Sending Failed"); 131 } 132 delay(1000); 133 } else { 134 // Displaying Invalid Msg 135 lcd.clear(); 136 lcd.setCursor(0, 0); 137 lcd.print("Invalid: "); 138 lcd.print(receivedCommand); 139 lcd.setCursor(0, 1); 140 lcd.print("Command Received"); 141 } 142 } 143} 144 145void sendCrLf(void) { 146 Serial.write(0x0D); // Carriage Return 147 Serial.write(0x0A); // Line Feed 148} 149 150void flushBuffer(void) { 151 while (Serial.available() > 0) { 152 Serial.read(); 153 } 154} 155 156bool rcvCommand(char receiveUntil, unsigned int timeout) { 157 bool boReturnValue = false; // function's return value 158 unsigned long startTime; 159 int firstComma; 160 int secondComma; 161 int thirdComma; 162 String data; 163 // wait for reply 164 do { 165 timeout--; 166 delay(1); // delay of 1 ms 167 } while ((Serial.available() < MIN_CHAR_TO_RCV) && (timeout > 0)); 168 169 if (timeout) { 170 startTime = millis(); 171 // if timeout is left then a reply is received check for the string in the reply 172 data = Serial.readStringUntil(receiveUntil); 173 if ((millis() - startTime) <= timeout) { 174 boReturnValue = true; // it means in readStringUntil() function receiveUntil character is received 175 // as the data will be in form of "+RCV=0,2,F1,-88,11" we need to extract command between second and third comma 176 firstComma = data.indexOf(','); 177 secondComma = data.indexOf(',', firstComma + 1); 178 thirdComma = data.indexOf(',', secondComma + 1); 179 // extract value between 2nd and 3rd comma 180 receivedCommand = data.substring(secondComma + 1, thirdComma); 181 } else { 182 boReturnValue = false; // it means in readStringUntil() function timeout has occured 183 } 184 } else { 185 boReturnValue = false; // it means get character timeout has occured 186 } 187 188 // return result 189 return boReturnValue; 190} 191 192bool chkReply(String chkString, char receiveUntil, unsigned int timeout) { 193 String receivedString; // save received data in this string object 194 bool boReturnValue = false; // function's return value 195 196 // wait for reply 197 do { 198 timeout--; 199 delay(1); // delay of 1 ms 200 } while ((Serial.available() < MIN_CHAR_TO_RCV) && (timeout > 0)); 201 202 if (timeout) { 203 // if timeout is left then a reply is received check for the string in the reply 204 receivedString = Serial.readStringUntil(receiveUntil); 205 if (receivedString.indexOf(chkString) != -1) { 206 boReturnValue = true; 207 } else { 208 boReturnValue = false; 209 } 210 } else { 211 boReturnValue = false; 212 } 213 214 // return result 215 return boReturnValue; 216} 217 218bool boRestoreFactoryDefaults(void) { 219 const char factoryDefaultCmd[] = "AT+FACTORY"; // command to be sent 220 bool boReturnValue = false; // function's return value 221 char downCounter = 100; // Down counter to wait for reply 222 String receivedString; // save received data in this string object 223 224 String chkRcvString1 = "+FACTORY"; 225 String chkRcvString2 = "+READY"; 226 227 // send command 228 Serial.print(factoryDefaultCmd); 229 sendCrLf(); 230 231 // check first string in reply 232 boReturnValue = chkReply(chkRcvString1, REPLY_END_CHAR, REPLY_TIMEOUT_IN_MS); 233 if (boReturnValue == true) { 234 // check second string in reply 235 boReturnValue = chkReply(chkRcvString2, REPLY_END_CHAR, REPLY_TIMEOUT_IN_MS); 236 } 237 238 // return result 239 return boReturnValue; 240} 241 242bool boSetAddress(void) { 243 const char setAddressCmd[] = "AT+ADDRESS="; // command to be sent 244 bool boReturnValue = false; // function's return value 245 String chkRcvString = "+OK"; 246 247 // send command 248 Serial.print(setAddressCmd); 249 Serial.print(MODULE_ADDRESS); 250 sendCrLf(); 251 252 // check reply 253 boReturnValue = chkReply(chkRcvString, REPLY_END_CHAR, REPLY_TIMEOUT_IN_MS); 254 255 // return result 256 return boReturnValue; 257} 258 259bool boSendData(String data) { 260 const char sendDataCmd[] = "AT+SEND="; // command to be sent 261 bool boReturnValue = false; // function's return value 262 String chkRcvString = "+OK"; 263 264 // send command 265 Serial.print(sendDataCmd); 266 Serial.print(TRANSMITTER_ADDRESS); 267 Serial.print(','); 268 Serial.print(data.length()); 269 Serial.print(','); 270 Serial.print(data); 271 sendCrLf(); 272 273 // check reply 274 boReturnValue = chkReply(chkRcvString, REPLY_END_CHAR, REPLY_TIMEOUT_IN_MS); 275 276 // return result 277 return boReturnValue; 278} 279 280// this funtion is used to control the relay which controls the appliances using digital pins 281void vImplementTask(String data) { 282 if (receivedCommand == sCMDLampON) { 283 LAMP_ON(); 284 } else if (receivedCommand == sCMDLampOFF) { 285 LAMP_OFF(); 286 } else if (receivedCommand == sCMDFanON) { 287 FAN_ON(); 288 } else if (receivedCommand == sCMDFanOFF) { 289 FAN_OFF(); 290 } 291}
Comments
Only logged in users can leave comments