#include <WiFi.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <esp_system.h>
#include <Ticker.h>
#include "Adafruit_SHT31.h"

Adafruit_SHT31 sht31 = Adafruit_SHT31();

const char* ssid = "Wokwi-GUEST";
const char* password = "";
int ModbusTCP_port = 502;

#define maxInputRegister 20
#define maxHoldingRegister 20

#define MB_FC_NONE 0
#define MB_FC_READ_REGISTERS 3
#define MB_FC_WRITE_REGISTER 6
#define MB_FC_WRITE_MULTIPLE_REGISTERS 16

#define MB_EC_NONE 0
#define MB_EC_ILLEGAL_FUNCTION 1
#define MB_EC_ILLEGAL_DATA_ADDRESS 2
#define MB_EC_ILLEGAL_DATA_VALUE 3
#define MB_EC_SLAVE_DEVICE_FAILURE 4

#define MB_TCP_TID 0
#define MB_TCP_PID 2
#define MB_TCP_LEN 4
#define MB_TCP_UID 6
#define MB_TCP_FUNC 7
#define MB_TCP_REGISTER_START 8
#define MB_TCP_REGISTER_NUMBER 10

byte ByteArray[260];
int MBHoldingRegister[maxHoldingRegister];

WiFiServer MBServer(ModbusTCP_port);

// Statische IP-instellingen
IPAddress local_IP(192, 168, 1, 50);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(8, 8, 8, 8);
IPAddress secondaryDNS(8, 8, 4, 4);

Ticker resetTimer;
bool ledState = false;
unsigned long previousMillis = 0;
const long interval = 2000; // Interval voor 2 seconden

void restartESP() {
  Serial.println("Geen verbinding gedurende 5 minuten, herstarten...");
  esp_restart();
}

void setup() {
  pinMode(13, OUTPUT);
  pinMode(2, OUTPUT); // GPIO 2 als uitgang voor de LED

  Serial.begin(9600);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Verbinden met WiFi...");
  }

  if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
    Serial.println("Fout bij het configureren van een statisch IP-adres.");
  }

  WiFi.disconnect();
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Opnieuw verbinden met WiFi...");
  }

  Serial.println("Verbonden met WiFi");
  Serial.print("IP-adres: ");
  Serial.println(WiFi.localIP());

  MBServer.begin();
  Serial.println("Connected ");
  Serial.print("ESP32 Slave Modbus TCP/IP ");
  Serial.print(WiFi.localIP());
  Serial.print(":");
  Serial.println(String(ModbusTCP_port));
  Serial.println("Modbus TCP/IP Online");

  if (!sht31.begin(0x44)) {
    Serial.println("Couldn't find SHT31");
    while (1) delay(1);
  }

  Serial.println("SHT31 test");

  resetTimer.attach(900, restartESP);
}

void loop() {
  unsigned long currentMillis = millis();
  
  // Controleer of 2 seconden zijn verstreken
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    ledState = !ledState; // Wissel de LED-toestand
    digitalWrite(2, ledState); // Zet de LED aan of uit
  }

  WiFiClient client = MBServer.available();

  if (client) {
    resetTimer.detach();

    boolean flagClientConnected = 0;
    byte byteFN = MB_FC_NONE;
    int Start;
    int WordDataLength;
    int ByteDataLength;
    int MessageLength;

    while (client.connected()) {
      if (client.available()) {
        flagClientConnected = 1;
        int i = 0;
        while (client.available()) {
          ByteArray[i] = client.read();
          i++;
          yield();
        }

        client.flush();

        float temperature = sht31.readTemperature();
        float humidity = sht31.readHumidity();

        int AM_TEMPm = (temperature * 100);
        int RHm = (humidity * 100);

        MBHoldingRegister[0] = random(0, 9999);
        MBHoldingRegister[1] = AM_TEMPm;
        MBHoldingRegister[2] = RHm;
        MBHoldingRegister[3] = 1;
        MBHoldingRegister[4] = 1;
        MBHoldingRegister[5] = 1;
        MBHoldingRegister[6] = random(0, 12);
        MBHoldingRegister[7] = random(0, 12);
        MBHoldingRegister[8] = random(0, 12);
        MBHoldingRegister[9] = random(0, 12);

        int Temporal[10];
        Temporal[0] = MBHoldingRegister[10];
        Temporal[1] = MBHoldingRegister[11];
        Temporal[2] = MBHoldingRegister[12];
        Temporal[3] = MBHoldingRegister[13];
        Temporal[4] = MBHoldingRegister[14];
        Temporal[5] = MBHoldingRegister[15];
        Temporal[6] = MBHoldingRegister[16];
        Temporal[7] = MBHoldingRegister[17];
        Temporal[8] = MBHoldingRegister[18];
        Temporal[9] = MBHoldingRegister[19];

        digitalWrite(14, MBHoldingRegister[14]);

        Serial.println("R/W:ok");

        byteFN = ByteArray[MB_TCP_FUNC];
        Start = word(ByteArray[MB_TCP_REGISTER_START], ByteArray[MB_TCP_REGISTER_START + 1]);
        WordDataLength = word(ByteArray[MB_TCP_REGISTER_NUMBER], ByteArray[MB_TCP_REGISTER_NUMBER + 1]);
      }

      switch (byteFN) {
        case MB_FC_NONE:
          break;
        case MB_FC_READ_REGISTERS:
          ByteDataLength = WordDataLength * 2;
          ByteArray[5] = ByteDataLength + 3;
          ByteArray[8] = ByteDataLength;
          for (int i = 0; i < WordDataLength; i++) {
            ByteArray[9 + i * 2] = highByte(MBHoldingRegister[Start + i]);
            ByteArray[10 + i * 2] = lowByte(MBHoldingRegister[Start + i]);
            yield();
          }
          MessageLength = ByteDataLength + 9;
          client.write((const uint8_t *)ByteArray, MessageLength);
          byteFN = MB_FC_NONE;
          yield();
          break;
        case MB_FC_WRITE_REGISTER:
          MBHoldingRegister[Start] = word(ByteArray[MB_TCP_REGISTER_NUMBER], ByteArray[MB_TCP_REGISTER_NUMBER + 1]);
          ByteArray[5] = 6;
          MessageLength = 12;
          client.write((const uint8_t *)ByteArray, MessageLength);
          byteFN = MB_FC_NONE;
          yield();
          break;
        case MB_FC_WRITE_MULTIPLE_REGISTERS:
          ByteDataLength = WordDataLength * 2;
          ByteArray[5] = ByteDataLength + 3;
          for (int i = 0; i < WordDataLength; i++) {
            MBHoldingRegister[Start + i] = word(ByteArray[13 + i * 2], ByteArray[14 + i * 2]);
            yield();
          }
          MessageLength = 12;
          client.write((const uint8_t *)ByteArray, MessageLength);
          byteFN = MB_FC_NONE;
          yield();
          break;
      }
    }

    if (!client.connected()) {
      Serial.println("Client disconnected, ESP herstarten...");
      esp_restart();
    }
  } else {
    if (!resetTimer.active()) {
      resetTimer.attach(900, restartESP);
    }
  }
}