/*********
  IR_Bee_GP_OLED_Remote_BME280_4IR_HONEY.ino
  Get temp,humidity,pressure,1,2,3,4    (four bee counters at end)
  sudo /home/pi/lora/WIFI_GPT_lora/send_command_wifi_arg.py HONEY,t
*********/

// Libraries for LoRa
#include <SPI.h>
#include <LoRa.h>

// Libraries for OLED Display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// Libraries for BME280
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

// =====================
// Node identity / protocol
// =====================
const String NODE_ID = "HONEY";

// If true: respond to plain "t" as well as "HONEY,t" etc.
// If false: ONLY respond when message contains NODE_ID + t
#define ALLOW_PLAIN_T false

// BME280 definition
#define SDA 21
#define SCL 13

// LoRa transceiver pins
#define SCK 18
#define MISO 19
#define MOSI 23
#define SS 5
#define RST 14
#define DIO0 2
#define BAND 868E6

// OLED pins
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

// IR Sensor pulse counting
volatile unsigned long beeCount1 = 0;               
volatile unsigned long beeCount2 = 0;
volatile unsigned long beeCount3 = 0;
volatile unsigned long beeCount4 = 0;

TwoWire I2Cone = TwoWire(1);
Adafruit_BME280 bme;
float temperature = 0;
float humidity = 0;
float pressure = 0;

String LoRaData;
String LoRaMessage = "";

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST);

void IRAM_ATTR countBee1() { beeCount1++; }
void IRAM_ATTR countBee2() { beeCount2++; }
void IRAM_ATTR countBee3() { beeCount3++; }
void IRAM_ATTR countBee4() { beeCount4++; }

void startOLED() {
  pinMode(OLED_RST, OUTPUT);
  digitalWrite(OLED_RST, LOW);
  delay(20);
  digitalWrite(OLED_RST, HIGH);
  Wire.begin(OLED_SDA, OLED_SCL);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) {
    Serial.println(F("SSD1306 allocation failed"));
    while (1);
  }
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("LORA REMOTE");
  display.display();
}

void startBME() {
  I2Cone.begin(SDA, SCL, 100000);
  bool status1 = bme.begin(0x76, &I2Cone);
  if (!status1) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

void startLoRA() {
  SPI.begin(SCK, MISO, MOSI, SS);
  LoRa.setPins(SS, RST, DIO0);

  if (!LoRa.begin(BAND)) {
    Serial.println("LoRa init failed!");
    while (true) { delay(1000); }
  }

  LoRa.setSpreadingFactor(9);
  LoRa.setSignalBandwidth(125E3);
  LoRa.setCodingRate4(5);
  LoRa.setTxPower(17);
  LoRa.setPreambleLength(8);
  LoRa.setSyncWord(0x34);

  LoRa.disableCrc();
  LoRa.disableInvertIQ();
}

void getReadings() {
  temperature = bme.readTemperature();
  humidity = bme.readHumidity();
  pressure = bme.readPressure() / 100.0F;
}

// Returns true if this packet is asking THIS node for 't'
bool isRequestForThisNode(const String& msg) {
  String s = msg;
  s.trim();

  // Normalize common separators to commas, and remove spaces
  s.replace(" ", "");
  s.replace(":", ",");
  s.replace(";", ",");
  s.replace("|", ",");
 
  // Accept:
  // 1) "HONEY,t" or "HONEY,t,..."
  // 2) optionally plain "t"
  if (s.length() == 0) return false;

  // plain "t"
  if (ALLOW_PLAIN_T && (s == "t" || s.startsWith("t,"))) {
    return true;
  }

  // Must start with "HONEY,"
  String prefix = NODE_ID + ",";
  if (!s.startsWith(prefix)) return false;

  // After "HONEY," must be 't' (or "t,")
  int idx = prefix.length();
  if (idx >= s.length()) return false;

  char c = s.charAt(idx);
  if (c == 't') return true;

  return false;
}

void setup() {
  Serial.begin(115200);
  startOLED();
  startBME();
  Serial.println("LoRa Receiver Test");
  startLoRA();

  pinMode(34, INPUT);
  pinMode(35, INPUT);
  pinMode(32, INPUT);
  pinMode(33, INPUT);

  attachInterrupt(digitalPinToInterrupt(34), countBee1, RISING);
  attachInterrupt(digitalPinToInterrupt(35), countBee2, RISING);
  attachInterrupt(digitalPinToInterrupt(32), countBee3, RISING);
  attachInterrupt(digitalPinToInterrupt(33), countBee4, RISING);                                          
}

void loop() {
  int packetSize = LoRa.parsePacket();
  if (!packetSize) return;

  Serial.print("Received packet___");

  while (LoRa.available()) {
    LoRaData = LoRa.readString();
  }
  LoRaData.trim();
  Serial.println(LoRaData);

  if (!isRequestForThisNode(LoRaData)) {
    Serial.println("Not for me (or not 't') - no data sent out");
    int rssi = LoRa.packetRssi();
    Serial.print(" with RSSI ");
    Serial.println(rssi);
    return;
  }

  Serial.println("Request matched (HONEY + t)");

  getReadings();

  // Safely read and reset pulse count
  noInterrupts();

  unsigned long beepulses1 = beeCount1;
  unsigned long beepulses2 = beeCount2;
  unsigned long beepulses3 = beeCount3;
  unsigned long beepulses4 = beeCount4;

  beeCount1 = 0;
  beeCount2 = 0;
  beeCount3 = 0;
  beeCount4 = 0;

  interrupts();

  // Create data payload (same as before)
  String dataPayload =
      String(temperature) + "," + String(humidity) + "," + String(pressure) + "," +
      String(beepulses1) + "," + String(beepulses2) + "," +
      String(beepulses3) + "," + String(beepulses4);

  // Now prepend the node ID for the master
  LoRaMessage = NODE_ID + "," + dataPayload;

  Serial.print("LoRaMessage = ");
  Serial.println(LoRaMessage);
  delay(10);

  LoRa.beginPacket();
  LoRa.print(LoRaMessage);
  LoRa.endPacket();

  Serial.println("data packet sent to master TX");

  // Display information on OLED
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("ID: ");
  display.print(NODE_ID);

  display.setCursor(0, 10);
  display.print("Rx: ");
  display.print(LoRaData);

  display.setCursor(0, 20);
  display.print("Tx: ");
  display.print(LoRaMessage); // may wrap; OLED is small

  display.setCursor(0, 50);
  display.print(beepulses1); display.print(" ");
  display.print(beepulses2); display.print(" ");
  display.print(beepulses3); display.print(" ");
  display.print(beepulses4);

  display.display();

  int rssi = LoRa.packetRssi();
  Serial.print(" with RSSI ");
  Serial.println(rssi);
}