Hi, readers in this post we are making a project that is very innovative.
Why do I say innovative?
It’s because we are using LoRa, So what is this, and why we are using this in farming?
Long Range (LoRa) technology, a low-power, wide-area networking protocol, has emerged as a game-changer in the realm of agriculture.
With its exceptional range and energy efficiency, LoRa enables seamless connectivity over vast distances, bridging the gap between farmers and their fields like never before.
This groundbreaking innovation has opened up a world of possibilities, revolutionizing the way we grow, monitor, and sustain our crops.
So what LoRa in farming can do?
IoT LoRa-based smart agriculture and remote monitoring system. The system can be used for a variety of applications, including crop monitoring, soil moisture monitoring, and temperature humidity monitoring.
The system consists of a LoRa which allows us to wirelessly monitor humidity and temperature levels in our fields so that we can make sure that our crops are getting the optimal conditions for growth.
LoRa is a technology that lets devices talk to each other over really long distances without using a lot of power.
Required Material
- Arduino Nano
- 1.8 Inch TFT LCD Module
- Reyax RYLR998 LoRa Module
- DS1307 RTC Module
- DHT11 Sensor
- A capacitive Soil moisture sensor
- Solar panel
- 5V Battery
- Buzzer
RYLR998 Lora Module
The RYLR998 LoRa module is a device that enables long-range (LoRa) wireless communication over several kilometers with low power consumption, making it ideal for IoT, smart agriculture, and remote monitoring applications. It has excellent interference resistance, and high sensitivity, and can be controlled easily using AT commands.
Check out Introduction to LoRa Communication and How to Use it with Arduino. You can learn more about the RYLR998 module and download datasheets.
Capacitive Soil Moisture Sensor
A capacitive soil moisture sensor measures the moisture level in the soil. It uses capacitance to precisely determine the amount of water in the soil. The sensor has two electrodes that accurately detect changes in capacitance as the soil moisture changes.
DHT11 sensor
The DHT11 sensor is a low-cost digital temperature and humidity sensor. It is easy to use and provides temperature and humidity readings for various applications. It is commonly used in home automation, weather monitoring, and HVAC systems.
DS1307 RTC Clock Module
The DS1307 RTC (Real-Time Clock) module is a small electronic module that provides accurate timekeeping functions. It uses an I2C interface to communicate with microcontrollers and has a built-in battery backup to maintain time even without power.
1.8-inch TFT LCD Display
1.8-inch TFT LCD module is a tiny, and compact display screen that uses TFT technology to render images and text with vibrant colors and a resolution of 128×160 pixels. I. It is frequently embedded in small electronic devices like wearables, cameras, and portable gaming consoles.
Transmitter & Reciever Schematics – LoRa-Based Smart Agriculture
To build my system, I used an Arduino board as the main component. I also use a 1.8-inch TFT SPI display, a TP4056 module for battery charging and protection, a lithium battery, and a solar panel for charging the battery.
Transmitter Part Design & Schematic
Fritzing Circuit – LoRa-Based Smart Agriculture
I used a solar panel because sensor nodes are often placed in remote locations where accessing the power grids is not feasible. By using a solar panel and a Li-ion battery, I can provide continuous power to my sensor node.
Receiver Part Design & Schematic
The transmitter is portable and uses the RYLR998 LoRa module for communication. Here is a complete schematic for the Receiver part.
Fritzing Circuit – LoRa-Based Smart Agriculture
Assemble Transmitter
Assemble the transmitter parts by following the provided instructions and securing the components in their designated positions.
PCB Design & Gerber file for Transmitter
The above schematics have been created using EasyEDA, and they can be easily converted into a PCB layout using the same software.
Soldering All Your Components Onto the Board
Soldering all the components onto the board is the process of attaching the electronic components to their designated positions on the circuit board using solder.
Final Transmitter Hardware Assembly
Integrate circuit hardware into a 3D-printed enclosure for a complete system. Assemble by inserting the Solar panel, battery circuit, and soil moisture sensor into the 3D printed enclosure in designated positions, connect them to the circuit board, arrange the wiring neatly, and confirm the function of the system.
Assemble Receiver
PCB Design & Gerber file for Receiver
Assemble the transmitter by following the provided instructions, attaching the antenna, connecting buttons and connectors, and ensuring secure connections for proper functionality.
Soldering All Your Components Onto the Board
Solder all components (Arduino, display, RTC, etc.) onto the receiver board using a soldering iron,
Final Receiver Hardware Assembly
Assemble the receiver by placing the circuit board in an enclosure, connecting the antennas and cables, and performing testing for functionality and performance. Make sure all components are securely assembled before proceeding.
Communication Using RYLR896 LoRa Transceiver
To establish communication between two LoRa modules, they need unique addresses within a network. Each module can be assigned a network id and an address., allowing communication within the same network. and a module with address 0 can receive data from all devices on the network.
Default values exist for frequency, network ID (18), and address (0), which can be changed using AT commands if needed, refer to the datasheet for details. For the current demo project, no changes are necessary.
Sample Code For Test AT Command and Change Baudrate
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 |
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 01_Test_AT_Command_and_Change_Baudrate /* * In this project Arduino Uno uses serial software to communicate with the Reyax RYLR998 LoRa module. * The Reyax RYLR998 module's default baud rate is 115200, * the Baud rate had to be changed because the serial software didn't work properly at a baud rate of 115200 (this happened to my Arduino Uno module, * i don't know if all Arduino Uno modules have the same problem). * So in this session, the Reyax RYLR998 module baud rate is changed to 9600 so that it can work properly with serial software on Arduino Uno. * This session also made changes to the Reyax RYLR998 module address. Baudrate : 9600 - AT+IPR=9600 Address : 1 || 2 - AT+ADDRESS= NETWORKID : 18 - AT+NETWORKID=18 */ #include <SoftwareSerial.h> SoftwareSerial ReyaxLoRa(5, 4); //--> RX, TX void setup() { // put your setup code here, to run once: // set the data rate for the HardwareSerial port Serial.begin(9600); Serial.println(); delay(2000); // set the data rate for the SoftwareSerial port //ReyaxLoRa.begin(9600); ReyaxLoRa.begin(9600); //--> 115200 is the Reyax RYLR998 LoRa default baud rate. delay(100); ReyaxLoRa.print("AT\r\n"); Serial.print("AT\r\n"); } void loop() { // put your main code here, to run repeatedly: if (ReyaxLoRa.available()) Serial.println(ReyaxLoRa.readString()); if (Serial.available()) ReyaxLoRa.print(Serial.readString()); } //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
Source Code & Librires
Download and install the required libraries
- Adafruit_GFX : https://github.com/adafruit/Adafruit-GFX-Library
- Adafruit_ST7735 : https://github.com/adafruit/Adafruit-ST7735-Library
- RTClib: https://github.com/adafruit/RTClib
- LowPower: https://github.com/rocketscream/Low-Power
- Adafruit_Sensor : https://github.com/adafruit/Adafruit_Sensor
- DHT: https://github.com/adafruit/DHT-sensor-library
Code For Transmitter
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 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
/* Slaver/Receiver Baudrate : 9600 - AT+IPR=9600 Address : 2 - AT+ADDRESS=2 NETWORKID : 18 - AT+NETWORKID=18 Set RF Frequency: AT+BAND=915000000 (default) *** Library ***** - LowPower : https://github.com/rocketscream/Low-Power - Adafruit_Sensor : https://github.com/adafruit/Adafruit_Sensor - DHT : https://github.com/adafruit/DHT-sensor-library */ // xin chao pro //=========== Including the libraries. #include <Arduino.h> #include "LowPower.h" #include <SoftwareSerial.h> #include <Wire.h> #include "Adafruit_Sensor.h" #include "DHT.h" #define DHTPIN 6 // what digital pin we're connected to #define LEDPIN 7 // what digital pin we're connected t #define DHTTYPE DHT11 // DHT 11 DHT dht(DHTPIN, DHTTYPE); #define MoisturePin A0 #define VoltagePin A1 float VBAT = 0.0000, VSEN = 0.0000; uint8_t avgCount = 2; // Giá trị độ ẩm đất uint16_t MoistureValue = 0; const uint16_t MoistureValueMin = 239; // wet const uint16_t MoistureValueMax = 700; // dry // Giá trị điện áp pin float Vref = 5.33; float VoltageValue = 0; uint8_t BateryPercent = 0; // Giá trị độ ẩm không khí uint8_t HumidityValue = 0; uint8_t TemperatureValue = 0; // Blink LED báo trạng thái #define LEDPIN 7 // Chân của LED int ledState = LOW; // Trạng thái của LED (ban đầu tắt) // Defines the slave/destination address. #define slave_Address 02 #define master_Address 01 SoftwareSerial ReyaxLoRa(5, 4); //--> RYLR998_RX, RYLR998_TX void ReadMoistureValue() { VSEN = 0.000; for(int i = 0; i<avgCount; i++){ VSEN = VSEN + analogRead(MoisturePin);; } uint16_t RawValue = (VSEN/avgCount); if(RawValue < MoistureValueMin) RawValue = MoistureValueMin; if(RawValue > MoistureValueMax) RawValue = MoistureValueMax; MoistureValue = map(RawValue, MoistureValueMin, MoistureValueMax, 100, 0); } void ReadVoltageValue() { VBAT = 0.000; for(int i = 0; i<avgCount; i++){ VBAT = VBAT + analogRead(VoltagePin);; } float RawValue = (VBAT/avgCount); VoltageValue = (RawValue*Vref)/1024.0; uint16_t IntVoltageValue = VoltageValue*100; // 3.7*100 = 370 if(IntVoltageValue < 350.0) IntVoltageValue = 350.0; if(IntVoltageValue > 420.0) IntVoltageValue = 420.0; BateryPercent = map(IntVoltageValue, 350.0, 420.0, 0, 100); } void ReadDHT11() { HumidityValue = dht.readHumidity(); TemperatureValue = dht.readTemperature(); } //_______________ getValue()_______________ // String function to split data based on certain characters. // Reference : https://www.electroniclinic.com/reyax-lora-based-multiple-sensors-monitoring-using-arduino/ // 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]) : ""; // } // void Serial_Print() // { // Serial.print("VoltageValue: "); Serial.print(VoltageValue); // Serial.print(" - MoistureValue: "); Serial.print(MoistureValue); // Serial.print(F(" - Humidity: ")); Serial.print(HumidityValue); // Serial.print(F("% - Temperature: ")); Serial.print(TemperatureValue); // Serial.print("- BateryPercent: "); Serial.println(BateryPercent); // delay(500); // } //________ReyaxLoRa_Send()_________ // Subroutine for sending data. void ReyaxLoRa_Send(int addr, String data_send) { String str_Send; // AT commands to transmit data. // For more details see the document "LoRa_AT_Command_RYLR998_RYLR498_EN.pdf" in the "AT+SEND" section. str_Send = "AT+SEND=" + String(addr) + "," + String(data_send.length()) + "," + data_send + "\r\n"; ReyaxLoRa.print(str_Send); Serial.println(); Serial.print("Send to Receiver : "); Serial.print(str_Send); Serial.flush(); } //__________ ReyaxLoRa_Receive()__________ // Subroutine to receive data. // void ReyaxLoRa_Receive() { // if (ReyaxLoRa.available() > 0 ) { // String rcv_Data_String = ReyaxLoRa.readString(); // if(rcv_Data_String.indexOf("OK") > 0 || rcv_Data_String.indexOf("ERR") > 0) { // Serial.println(); // Serial.print(F("LoRa Reyax Module Response : ")); // Serial.println(rcv_Data_String); // return; // } else { // // Print received data or messages. // Serial.println(F("Received from Sender : ")); // Serial.println(rcv_Data_String); // Serial.flush(); // //---------------------------------------- Process incoming data. // // For more details see the document "LoRa_AT_Command_RYLR998_RYLR498_EN.pdf" in the section "+RCV". // //String _addr = getValue(rcv_Data_String, ',', 0); //--> address // //_addr = _addr.substring(5); // //String _length = getValue(rcv_Data_String, ',', 1); //--> data length // String _message = getValue(rcv_Data_String, ',', 2); //--> data/message // //String _rssi = getValue(rcv_Data_String, ',', 3); //--> RSSI // //String _snr = getValue(rcv_Data_String, ',', 4); //--> SNR // //Serial.println(); // //Serial.println(F("Received from Master.")); // //Serial.print(F("-Addr : ")); // //Serial.println(_addr); // //Serial.print(F("-Length : ")); // //Serial.println(_length); // //Serial.print(F("-Message : ")); // //Serial.println(_message); // //Serial.print(F("-RSSI : ")); // //Serial.println(_rssi); // //Serial.print(F("-SNR : ")); // //Serial.println(_snr); // //Serial.flush(); // ReadDHT11(); // ReadMoistureValue(); // ReadVoltageValue(); // Serial_Print(); // delay(100); // // Sends the state of LED_1 and LED_2 to the master. // ReyaxLoRa_Send(master_Address, String(TemperatureValue) + "|" + String(HumidityValue) + "|" + String(MoistureValue) + "|" + String(BateryPercent)); // } // } // } void LoRaSleepMode() { ReyaxLoRa.print("AT+MODE=1\r\n"); // Sleep Mode delay(300); } void LoRaTransceiverMode() { ReyaxLoRa.print("AT+MODE=0\r\n"); // Transceiver mode delay(300); } void setup() { Serial.begin(9600); ReyaxLoRa.begin(9600); pinMode(LEDPIN, OUTPUT); // khởi tạo DHT dht.begin(); LoRaSleepMode(); } void loop() { LoRaTransceiverMode(); // Chuyển sang chế độ Transceiver ReadDHT11(); ReadMoistureValue(); ReadVoltageValue(); delay(100); ReyaxLoRa_Send(master_Address, String(TemperatureValue) + "|" + String(HumidityValue) + "|" + String(MoistureValue) + "|" + String(BateryPercent)); delay(500); LoRaSleepMode(); // Chuyển sang chế độ Sleep //LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF); // sleep 8s LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); //Serial_Print(); // debug } |
Copy the code into the Arduino IDE, connect the Arduino board via USB, and upload the code.
Code For Reciever
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 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 |
/* **** Master/Sender **** Baudrate : 9600 - AT+IPR=9600 Address : 1 - AT+ADDRESS=1 NETWORKID : 18 - AT+NETWORKID=18 *** Library ***** - Adafruit_GFX : https://github.com/adafruit/Adafruit-GFX-Library - Adafruit_ST7735 : https://github.com/adafruit/Adafruit-ST7735-Library - RTClib : https://github.com/adafruit/RTClib Date : 16/05/2023 Update: */ //==================Including the libraries================== #include <Arduino.h> #include <SoftwareSerial.h> #include <Adafruit_GFX.h> // Core graphics library #include <Adafruit_ST7735.h> // Hardware-specific library for ST7735 #include <SPI.h> #include <icon.h> #include "RTClib.h" #include <EEPROM.h> #define ONBuzzer 1 #define OFFBuzzer 0 // Information #define Model "Model: 4E0523GSDA " #define SeriaNumber "S/N : SN01 " #define FirmwareVision "FW : V1.0 328P " #define Author " 4E Projects " #define SDT " 036.788.0317 " #define Origin " Made in VietNam " // Defines the slave/destination address. #define slave_Address 02 #define master_Address 01 // Initialize "SoftwareSerial" and set the PIN used for RX and TX. SoftwareSerial ReyaxLoRa(5, 4); //--> RX, TX #define Down_Pin A0 #define Enter_Pin A1 #define Up_Pin A2 #define Buzzer_Pin A3 const unsigned long TIMEOUT = 20000; // Thời gian chờ tối đa (20 giây) unsigned long lastSerialTime = -20000; // Lưu thời gian gửi tin nhắn gần nhất const unsigned long interval1On = 500; // Thời gian sáng LED thứ nhất (1 giây) const unsigned long interval1Off = 60000; // Thời gian tắt LED thứ nhất (60 giây) const unsigned long interval2On = 1000; // Thời gian sáng LED thứ hai (1 giây) const unsigned long interval2Off = 1000; // Thời gian tắt LED thứ hai (1 giây) unsigned long previousMillis1 = 0; // Lưu trữ thời gian millis() gần nhất cho LED thứ nhất unsigned long previousMillis2 = 0; // Lưu trữ thời gian millis() gần nhất cho LED thứ hai bool ledState1 = false; // Trạng thái hiện tại của LED thứ nhất bool textState = false; // Trạng thái hiện tại của LED thứ hai // initialize RTC library RTC_DS1307 rtc; DateTime now; // For LCD 1.8inch ST7735 #define TFT_CS 10 #define TFT_RST 8 // Or set to -1 and connect to Arduino RESET pin #define TFT_DC 9 // LED-3.3V ; SCK-D13 ; SDA-D11 Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); // color definitions const uint16_t Display_Color_Black = 0x0000; const uint16_t Display_Color_Backgroup = 0x0000; // Black const uint16_t Display_Color_Blue = 0x023e; const uint16_t Display_Color_Red = 0xF800; const uint16_t Display_Color_Green = 0x07E0; const uint16_t Display_Color_Cyan = 0x07FF; const uint16_t Display_Color_Magenta = 0xF81F; const uint16_t Display_Color_Yellow = 0xFFE0; const uint16_t Display_Color_White = 0xFFFF; String TemperatureValue; String HumidityValue; String MoistureValue; String BateryPercent; int w_BateryPercent = 1; // 1->22 px uint16_t BatteryColor; unsigned long previousMillisDisplay = -20000; //unsigned long currentMillisDisplay = 0; const uint16_t timeDisplay = 20000; int8_t BuzzerState = 0; String _rssi; int16_t state = 0, pre_state = 1; // Vị trí Text TimeSet DaySet | Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc 11-22-2023 uint8_t day_x_pos = 64; uint8_t month_x_pos = day_x_pos + 6*3; uint8_t year_x_pos = day_x_pos + 6*8; uint8_t hour_x_pos = 70; uint8_t minute_x_pos = hour_x_pos + 6*3; uint8_t buzzer_x_pos = 64; uint8_t date_y_pos = 30; uint8_t time_y_pos = 40; uint8_t buzzer_y_pos = 50; uint8_t addr_slave_y_pos = 60; uint8_t addr_master_y_pos = 70; void EEPROM_SaveSetting() { EEPROM.update(0, BuzzerState); } void EEPROM_LoadSetting() { EEPROM.get(0, BuzzerState); } void RTC_display() { char _buffer[11]; char dow_matrix[7][10] = {" SUNDAY ", " MONDAY ", " TUESDAY ", "WEDNESDAY", " THURSDAY", " FRIDAY ", " SATURDAY"}; // print time tft.setTextSize(2); sprintf( _buffer, "%02u:%02u:%02u", now.hour(), now.minute(), now.second() ); tft.setCursor(0, 7); tft.setTextColor(ST7735_RED, Display_Color_Backgroup); tft.print(_buffer); // print date sprintf( _buffer, "%02u/%02u/%04u", now.day(), now.month(), now.year() ); tft.setTextSize(1); tft.setFont(); tft.setTextColor(ST7735_YELLOW, Display_Color_Backgroup); tft.setCursor(99, 14); tft.print(_buffer); // print day of the week tft.setCursor(102, 4); tft.print( dow_matrix[now.dayOfTheWeek()] ); } void Screen1Data() { RTC_display(); // Hiển thị thời gian, ngày tháng - display time, date tft.setTextSize(1); tft.setTextColor(ST7735_WHITE, Display_Color_Blue); // Giá trị nhiệt độ môi trường tft.setCursor(14, 47); tft.print(TemperatureValue); tft.drawCircle(30, 48, 1, ST7735_WHITE); // print degree symbol ( ° ) tft.setCursor(34, 47); tft.print("C"); // Giá trị độ ẩm môi trường tft.setCursor(87, 47); tft.print(HumidityValue); tft.print("% "); // Giá trị độ ẩm đất tft.setCursor(14, 85); tft.print(MoistureValue); tft.print("% "); // Giá trị phần trăm pin tft.setCursor(87, 85); tft.print(BateryPercent); tft.print("% "); w_BateryPercent = map(BateryPercent.toInt(), 0, 100, 1, 22); if(w_BateryPercent < 1) w_BateryPercent = 1; if(w_BateryPercent > 22) w_BateryPercent = 22; if(BateryPercent.toInt() > 70) BatteryColor = ST7735_GREEN; else if(BateryPercent.toInt() <= 70 && BateryPercent.toInt() > 30 ) BatteryColor = ST7735_YELLOW; else if(BateryPercent.toInt() <= 30) BatteryColor = ST7735_RED; tft.fillRect(121, 81, w_BateryPercent, 13, BatteryColor); tft.fillRect(121 + w_BateryPercent, 81, 22 - w_BateryPercent, 13, Display_Color_Backgroup); // RSSI tft.setTextColor(ST7735_GREEN, Display_Color_Backgroup); tft.setCursor(127, 113); tft.print(":"); tft.print(_rssi); } void Screen1_display() { if(state != pre_state) { tft.fillScreen(Display_Color_Backgroup); pre_state = state; tft.drawLine(0,27,160,27,ST7735_WHITE); // Nhiệt độ tft.fillRect(10, 33, 69, 35, Display_Color_Blue); tft.setTextSize(1); tft.setTextColor(ST7735_WHITE); tft.setCursor(14, 37); tft.print("Temp"); tft.drawBitmap(55, 35, TempIcon, 16, 28, ST7735_WHITE); // Độ ẩm Không khí tft.fillRect(82, 33, 69, 35, Display_Color_Blue); tft.setTextSize(1); tft.setTextColor(ST7735_WHITE); tft.setCursor(87, 37); tft.print("Hum"); tft.drawBitmap(126, 35, HumIcon, 18, 25, ST7735_WHITE); // Độ ẩm Đất tft.fillRect(10, 71, 69, 35, Display_Color_Blue); tft.setTextSize(1); tft.setTextColor(ST7735_WHITE); tft.setCursor(14, 75); tft.print("Soil"); tft.drawBitmap(48, 73, SoilIcon, 26, 26, ST7735_WHITE); // Phần trăm pin tft.fillRect(82, 71, 69, 35, Display_Color_Blue); tft.setTextSize(1); tft.setTextColor(ST7735_WHITE); tft.setCursor(87, 75); tft.print("Bat"); tft.drawBitmap(118, 78, BatteryIcon, 30, 19, ST7735_WHITE); // Cường độ tín hiệu tft.drawBitmap(105, 110, SignalIcon, 18, 13, ST7735_GREEN); } Screen1Data(); } // a small function for button1 (B1) debounce bool debounce () { byte count = 0; for(byte i = 0; i < 6; i++) { if ( !digitalRead(Enter_Pin) ) count++; delay(10); } if(count > 2) return 1; else return 0; } byte edit(int8_t parameter) { static byte i = 0, y_pos, x_pos[6] = {day_x_pos, month_x_pos, year_x_pos, hour_x_pos, minute_x_pos, buzzer_x_pos }; char text[3]; sprintf(text,"%02u", parameter); if(i < 3) { tft.setTextColor(ST7735_YELLOW, ST7735_BLUE); // set text color to green and black background y_pos = date_y_pos; } if(i > 2 && i < 4){ tft.setTextColor(ST7735_YELLOW, ST7735_BLUE); // set text color to yellow and black background y_pos = time_y_pos; } if(i > 4 ){ tft.setTextColor(ST7735_YELLOW, ST7735_BLUE); // set text color to yellow and black background y_pos = buzzer_y_pos; } while( debounce() ); // call debounce function (wait for B1 to be released) while(true) { while( !digitalRead(Up_Pin) && digitalRead(Down_Pin) ) { // while B2 is pressed parameter++; if(i == 0 && parameter > 31) // if day > 31 ==> day = 1 parameter = 1; if(i == 1 && parameter > 12) // If month > 12 ==> month = 1 parameter = 1; if(i == 2 && parameter > 99) // If year > 99 ==> year = 0 parameter = 0; if(i == 3 && parameter > 23) // if hours > 23 ==> hours = 0 parameter = 0; if(i == 4 && parameter > 59) // if minutes > 59 ==> minutes = 0 parameter = 0; if(i == 5 && parameter > 1) // if minutes > 59 ==> minutes = 0 parameter = 0; sprintf(text,"%02u", parameter); tft.setCursor(x_pos[i], y_pos); tft.print(text); delay(200); // wait 200ms } while( !digitalRead(Down_Pin) && digitalRead(Up_Pin) ) { // while B2 is pressed parameter--; if(i == 0 && parameter < 01) // if day < 01 ==> day = 31 parameter = 31; if(i == 1 && parameter < 01) // If month < 01 ==> month = 12 parameter = 12; if(i == 2 && parameter < 00) // If year < 00 > ==> year = 99 parameter = 99; if(i == 3 && parameter < 00) // if hours < 00 ==> hours = 23 parameter = 23; if(i == 4 && parameter < 00) // if minutes < 00 ==> minutes = 59 parameter = 5; if(i == 5 && parameter < 00) // if minutes < 00 ==> minutes = 59 parameter = 1; sprintf(text,"%02u", parameter); tft.setCursor(x_pos[i], y_pos); tft.print(text); delay(200); // wait 200ms } tft.fillRect(x_pos[i], y_pos, 12, 9, ST7735_BLUE); // fill nhấp nháy ô được chọn unsigned long previous_m = millis(); while( (millis() - previous_m < 250) && digitalRead(Enter_Pin) && digitalRead(Up_Pin) && digitalRead(Down_Pin)) ; tft.setCursor(x_pos[i], y_pos); tft.print(text); previous_m = millis(); while( (millis() - previous_m < 250) && digitalRead(Enter_Pin) && digitalRead(Up_Pin) && digitalRead(Down_Pin)) ; if(!digitalRead(Enter_Pin)) { // if button B1 is pressed i = (i + 1) % 6; // increment 'i' for the next parameter return parameter; // return parameter value and exit } } } void RTC_Setting_display() { char _buffer[11]; // print date sprintf( _buffer, "%02u-%02u-%04u", now.day(), now.month(), now.year() ); tft.setCursor(4, date_y_pos); tft.setTextColor(ST7735_YELLOW, ST7735_BLUE); // set text color to yellow and black background tft.print("> Set Day:"); tft.print(_buffer); // print time sprintf( _buffer, "%02u:%02u:%02u", now.hour(), now.minute(), now.second() ); tft.setCursor(4, time_y_pos); tft.setTextColor(ST7735_YELLOW, ST7735_BLUE); // set text color to green and black background tft.print("> Set Time:"); tft.print(_buffer); // sprintf( _buffer, "%02u", BuzzerState ); tft.setCursor(4, buzzer_y_pos ); tft.setTextColor(ST7735_YELLOW, ST7735_BLUE); // set text color to green and black background tft.print("> Buzzer: "); tft.print(_buffer); // tft.setCursor(4, addr_slave_y_pos); tft.setTextColor(ST7735_YELLOW, ST7735_BLUE); // set text color to green and black background tft.print("> Slave Address: "); tft.print(slave_Address); tft.setCursor(4, addr_master_y_pos); tft.setTextColor(ST7735_YELLOW, ST7735_BLUE); // set text color to green and black background tft.print("> Master Address: "); tft.print(master_Address); // sprintf( _buffer, "%02u", BuzzerState ); tft.setCursor(4, buzzer_y_pos ); tft.setTextColor(ST7735_YELLOW, ST7735_BLUE); // set text color to green and black background tft.print("> Buzzer: "); tft.print(_buffer); } void Screen2_display() { digitalWrite(Buzzer_Pin, LOW); if(state != pre_state) { pre_state = state; tft.fillScreen(ST7735_BLUE); tft.drawLine(0, 25, 160, 25,ST7735_WHITE); tft.setTextSize(2); tft.setTextColor(ST7735_YELLOW); tft.setCursor(13, 4); tft.print("Information"); tft.fillRect(0, 88, 160, 40, ST7735_WHITE); tft.setTextSize(1); tft.setTextColor(ST7735_BLACK); tft.setCursor(4, 90); tft.print(Model); tft.setCursor(4, 99); tft.print(SeriaNumber); tft.setCursor(4, 108); tft.print(FirmwareVision); tft.setCursor(4, 117); tft.setTextColor(ST7735_RED); tft.print(Author); } tft.setTextSize(1); if( !digitalRead(Enter_Pin) ) // if B1 is pressed if( debounce() ) // call debounce function (make sure B1 is pressed) { while( debounce() ); // call debounce function (wait for B1 to be released) //DateTime now = rtc.now(); byte day = edit( now.day() ); // edit date byte month = edit( now.month() ); // edit month byte year = edit( now.year() - 2000 ); // edit year byte hour = edit( now.hour() ); // edit hours byte minute = edit( now.minute() ); // edit minutes BuzzerState = edit(BuzzerState); EEPROM_SaveSetting(); // write time & date data to the RTC chip rtc.adjust(DateTime(2000 + year, month, day, hour, minute, 0)); while(debounce()); // call debounce function (wait for button B1 to be released) } RTC_Setting_display(); } void ButtonHandle() { if (!digitalRead(Down_Pin)) { if (state == 2) state = 0; else state += 1; delay(200); } } //___________ getValue() ___________ 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]) : ""; } //___________ ReyaxLoRa_Send() ___________ void ReyaxLoRa_Send(int addr, String data_send) { String str_Send; // AT commands to transmit data. // For more details see the document "LoRa_AT_Command_RYLR998_RYLR498_EN.pdf" in the "AT+SEND" section. str_Send = "AT+SEND=" + String(addr) + "," + String(data_send.length()) + "," + data_send + "\r\n"; ReyaxLoRa.print(str_Send); Serial.println(); Serial.print("Send to Slave : "); Serial.print(str_Send); Serial.flush(); } //___________ ReyaxLoRa_Receive() ___________ void ReyaxLoRa_Receive() { if (ReyaxLoRa.available() > 0 ) { lastSerialTime = millis(); // Lưu thời gian gần nhất nhận được tín hiệu String rcv_Data_String = ReyaxLoRa.readString(); if(rcv_Data_String.indexOf("OK") > 0 || rcv_Data_String.indexOf("ERR") > 0) { Serial.println(); Serial.print(F("LoRa Reyax Module Response : ")); Serial.println(rcv_Data_String); Serial.flush(); return; } else { // Print received data or messages. Serial.println(F("Received from Sender : ")); Serial.println(rcv_Data_String); Serial.flush(); //---------------------------------------- Process incoming data. // For more details see the document "LoRa_AT_Command_RYLR998_RYLR498_EN.pdf" in the section "+RCV". //String _addr = getValue(rcv_Data_String, ',', 0); //--> address //_addr = _addr.substring(5); //String _length = getValue(rcv_Data_String, ',', 1); //--> data length String _message = getValue(rcv_Data_String, ',', 2); //--> data/message _rssi = getValue(rcv_Data_String, ',', 3); //--> RSSI Serial.print(F("RSSI : ")); Serial.println(_rssi); //String _snr = getValue(rcv_Data_String, ',', 4); //--> SNR //Serial.println(); //Serial.println(F("Received from Sender.")); //Serial.print(F("-Addr : ")); //Serial.println(_addr); //Serial.print(F("-Length : ")); //Serial.println(_length); //Serial.print(F("-Message : ")); //Serial.println(_message); //Serial.print(F("-RSSI : ")); //Serial.println(_rssi); //Serial.print(F("-SNR : ")); //Serial.println(_snr); //Serial.flush();. TemperatureValue = getValue(_message, '|', 0); HumidityValue = getValue(_message, '|', 1); MoistureValue = getValue(_message, '|', 2); BateryPercent = getValue(_message, '|', 3); } } } void AllowBuzzer(uint8_t BuzzerValue, uint8_t value) { if(value) digitalWrite(Buzzer_Pin, BuzzerValue); else digitalWrite(Buzzer_Pin, LOW); } // Thông báo mất tín hiệu - Signal loss notification void SignalLoss() { tft.setTextSize(1); tft.setCursor(10, 113); tft.setTextColor(ST7735_WHITE, Display_Color_Backgroup); if (millis() - lastSerialTime > TIMEOUT) { // Nếu thời gian chờ tối đa đã vượt quá unsigned long currentMillis = millis(); // Lấy thời gian millis() hiện tại // LED thứ nhất if (ledState1 == false && currentMillis - previousMillis1 >= interval1Off) { ledState1 = true; previousMillis1 = currentMillis; } else if (ledState1 == true && currentMillis - previousMillis1 >= interval1On) { ledState1 = false; previousMillis1 = currentMillis; } AllowBuzzer(ledState1, BuzzerState); // LED thứ hai if (textState == false && currentMillis - previousMillis2 >= interval2Off) { textState = true; previousMillis2 = currentMillis; tft.setTextColor(ST7735_WHITE, ST7735_RED); tft.print("Signal Loss"); } else if (textState == true && currentMillis - previousMillis2 >= interval2On) { textState = false; previousMillis2 = currentMillis; tft.setTextColor(ST7735_WHITE, Display_Color_Backgroup); tft.print(" "); } // if (millis() - lastBlinkTime > 1000) { // Nếu đã đủ thời gian để nhấp nháy LED // buzzerState = !buzzerState; // Đảo trạng thái của LED // // AllowBuzzer(buzzerState, BuzzerState); // if(buzzerState == 0) { // tft.setTextColor(ST7735_WHITE, ST7735_RED); // tft.print("Signal Loss"); // } // if(buzzerState == 1) { // tft.setTextColor(ST7735_WHITE, Display_Color_Backgroup); // tft.print(" "); // } // lastBlinkTime = millis(); // Lưu thời gian nhấp nháy gần nhất // } } else { tft.print(" "); digitalWrite(Buzzer_Pin, LOW); // Tắt đèn LED nếu còn nhận được tín hiệu // lastBlinkTime = millis(); // Lưu thời gian nhấp nháy gần nhất } } //_____________ VOID SETUP() _____________ void setup() { pinMode(Buzzer_Pin, OUTPUT); pinMode(Up_Pin, INPUT_PULLUP); pinMode(Enter_Pin, INPUT_PULLUP); pinMode(Down_Pin, INPUT_PULLUP); Serial.begin(9600); // set the data rate for the SoftwareSerial port. ReyaxLoRa.begin(9600); // initialize RTC chip rtc.begin(); //rtc.adjust(DateTime(2023, 5, 14, 12, 23, 0)); // Use this initializer if using a 1.8" TFT screen: tft.initR(INITR_BLACKTAB); // Init ST7735S chip, black tab tft.setRotation(1); // 0->3 // tft.fillScreen(ST7735_BLACK); // fill screen with black color tft.fillScreen(Display_Color_Backgroup); EEPROM_LoadSetting(); } //________________VOID LOOP()_______________ void loop() { ButtonHandle(); now = rtc.now(); // read current time and date from the RTC chip switch (state) { case 0: Screen1_display(); SignalLoss(); ReyaxLoRa_Receive(); break; case 1: Screen2_display(); break; } //Serial.println(debounce()); } |
Icon.h
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 |
// 'TempIcon 30px', 16x28px const unsigned char TempIcon[] PROGMEM = { 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1c, 0x38, 0x1c, 0x38, 0x1c, 0x18, 0x1c, 0x18, 0x1c, 0x18, 0x1d, 0x98, 0x1d, 0x98, 0x1d, 0x98, 0x1d, 0x98, 0x1d, 0x98, 0x1d, 0x98, 0x1d, 0x98, 0x39, 0x9c, 0x39, 0x9c, 0x77, 0xee, 0x67, 0xe6, 0x6e, 0x76, 0x6e, 0x76, 0x6f, 0xf6, 0x77, 0xee, 0x73, 0xce, 0x38, 0x1c, 0x1f, 0xf8, 0x0f, 0xf0, 0x03, 0xc0 }; // 'HumIcon 30px', 18x25px const unsigned char HumIcon[] PROGMEM = { 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x01, 0xe0, 0x00, 0x03, 0xf0, 0x00, 0x03, 0xf0, 0x00, 0x07, 0xf8, 0x00, 0x0f, 0xfc, 0x00, 0x0f, 0xfc, 0x00, 0x1f, 0xfe, 0x00, 0x3f, 0xff, 0x00, 0x3f, 0xff, 0x00, 0x7f, 0xff, 0x80, 0x77, 0xff, 0x80, 0x63, 0xff, 0x80, 0xe1, 0xff, 0xc0, 0xe0, 0xff, 0xc0, 0xe0, 0x7f, 0xc0, 0xe0, 0x3f, 0xc0, 0x60, 0x1f, 0x80, 0x70, 0x0f, 0x80, 0x38, 0x07, 0x00, 0x3e, 0x1f, 0x00, 0x1f, 0xfe, 0x00, 0x07, 0xf8, 0x00, 0x01, 0xe0, 0x00 }; // 'SoilIcon30px', 26x26px const unsigned char SoilIcon[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x3c, 0x1e, 0x0f, 0x00, 0x70, 0x00, 0x03, 0x80, 0x60, 0x00, 0x01, 0x80, 0xfc, 0x0c, 0x0f, 0xc0, 0xfc, 0x1e, 0x0f, 0xc0, 0xfc, 0x7f, 0x8f, 0xc0, 0x1c, 0xff, 0xce, 0x00, 0x1f, 0xfd, 0xfe, 0x00, 0x1f, 0x9c, 0x7e, 0x00, 0x1f, 0x1c, 0x3e, 0x00, 0x0c, 0x1c, 0x0c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x07, 0xc0, 0xf0, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 'BatteryIcon', 30x19px const unsigned char BatteryIcon[] PROGMEM = { 0x3f, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xe0, 0xe0, 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xe0, 0x00, 0x00, 0xf8, 0xe0, 0x00, 0x00, 0xf8, 0xe0, 0x00, 0x00, 0xf8, 0xe0, 0x00, 0x00, 0xf8, 0xe0, 0x00, 0x00, 0xf8, 0xe0, 0x00, 0x00, 0xf8, 0xe0, 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0x80 }; // 'SignalIcon', 18x13px const unsigned char SignalIcon [] PROGMEM = { 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x30, 0xc3, 0x00, 0x6c, 0xcd, 0x80, 0xd8, 0x06, 0xc0, 0xd8, 0x06, 0xc0, 0x90, 0xc2, 0x40, 0xd8, 0x06, 0xc0, 0xd8, 0x06, 0xc0, 0x6c, 0xcd, 0x80, 0x30, 0xc3, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00 }; |
Copy the code into the Arduino IDE, connect the Arduino board via USB, and upload the code.
Download the Full LoRa Based Smart Agriculture and Remote Monitoring System
Testing
Now our device is ready for real field testing.
So I would like to conclude this innovative project by saying that, the adoption of a LoRa-based smart agriculture and remote monitoring system offers immense benefits to farmers, ranging from increased productivity and efficiency to sustainable farming practices.
As this technology continues to evolve and become more accessible, it holds the potential to transform the agricultural landscape, and productive farming industry for the future.
If you have any questions about this project you can ask me in the comments, Thank you.