/*
  LoRa Multi-Sensor Temperature & Humidity Monitor - Sensor
  lora-temp-humid-sensor.ino
  Remote Node for LoRa Temperature and Humidity Monitor
  Uses Arduino Uno, Adafruit RFM9x LoRa Module & DHT22 Temp/Humid sensor
  Sends Temperature and Humidity data to central controller
  Requires LoRa Library by Sandeep Mistry -  https://github.com/sandeepmistry/arduino-LoRa 
  Requires DHTlib Library by Rob Tillaart
 
  DroneBot Workshop 2023
   https://dronebotworkshop.com 
*/


// Include required libraries
#include <SPI.h>
#include <LoRa.h>
#include <dht.h>


// DHT22 Connection
#define DHTPIN 9


// LED connection (if used)
const int ledPin = 5;


// DHT Temp/Humid sensor object
dht DHT;


// Define the pins used by the LoRa module
const int csPin = 4;     // LoRa radio chip select
const int resetPin = 2;  // LoRa radio reset
const int irqPin = 3;    // Must be a hardware interrupt pin


// Outgoing message variable
String outMessage;


// Controller data variable
String inMessage;


// Previous value Controller data variable
String inMessageOld;


// Outgoing Message counter
byte msgCount = 0;


// Source and destination addresses
byte localAddress = 0xAA;  // address of this device (must be unique, 0xAA or 0xBB)
byte destination = 0x01;   // destination to send to (controller = 0x01)


// Receive Callback Function
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 = "";  // payload of packet


  while (LoRa.available()) {        // can't use readString() in callback, so
    incoming += (char)LoRa.read();  // add bytes one by one
  }


  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 we are this far then this message is for us
  // Update the controller data variable
  inMessage = incoming;
}


// Send LoRa Packet
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 setup() {

  Serial.begin(9600);
  while (!Serial)
    ;

  // Set LED as output (if used)
  pinMode(ledPin, OUTPUT);

  // Setup LoRa module
  LoRa.setPins(csPin, resetPin, irqPin);

  // Start LoRa module at local frequency
  // 433E6 for Asia
  // 866E6 for Europe
  // 915E6 for North America
  if (!LoRa.begin(915E6)) {
    Serial.println("Starting LoRa failed!");
    while (1)
      ;
  }

  // Set Receive Call-back function
  LoRa.onReceive(onReceive);

  // Place LoRa in Receive Mode
  LoRa.receive();

  Serial.println("LoRa init succeeded.");
}

void loop() {

  // Run only if requested
  if (inMessage != inMessageOld) {
    // New message variable, take reading and send to controller

    int readData = DHT.read22(DHTPIN);  // Reads the data from the sensor
    float t = DHT.temperature;          // Gets the values of the temperature
    float h = DHT.humidity;             // Gets the values of the humidity

    // Printing the results on the serial monitor
    Serial.print("Temperature = ");
    Serial.print(t);
    Serial.print(" *C ");
    Serial.print("    Humidity = ");
    Serial.print(h);
    Serial.println(" % ");

    // Format the outgoing message string
    String outMsg = "";
    outMsg = outMsg + t + ":" + h;

    // Send data as LoRa packet
    sendMessage(outMsg);

    // Print controller variables
    Serial.print("Old Controller Data = ");
    Serial.println(inMessageOld);
    Serial.print("New Controller Data = ");
    Serial.println(inMessage);

    // Update the"old" data variable
    inMessageOld = inMessage;

    // Place LoRa in Receive Mode
    LoRa.receive();

    // Optional 2-second LED pulse (remark out if LED not used)
    digitalWrite(ledPin, HIGH);
    Serial.println("led on");

    // 2-second delay for DHT sensor
    delay(2000);

    // Optional 2-second LED pulse (remark out if LED not used)
    digitalWrite(ledPin, LOW);
    Serial.println("led off");
  }
}