/**
* Official proxy code for iTender GPIO Communication
**/
#include <ArduinoJson.h>
#include "HX711.h"

// Define the size of the JSON buffer
#define JSON_BUFFER_SIZE 256

// Create a JSON object for incoming messages
StaticJsonDocument<JSON_BUFFER_SIZE> incomingJson;

// Create a JSON object for outgoing messages
DynamicJsonDocument outgoingJson(JSON_BUFFER_SIZE);

void setup() {
  // Initialize serial communication
  Serial.begin(9600);
}

void (*resetFunc)(void) = 0;  //declare reset function @ address 0

void loop() {
  if (Serial.available()) {
    // Read the incoming JSON message
    DeserializationError error = deserializeJson(incomingJson, Serial);
    if (error) {
      // Handle error
    } else {
      // Extract the "type" and "data" fields from the JSON object
      String id = incomingJson["id"];
      int type = incomingJson["type"];
      JsonVariant data = incomingJson["data"];

      // Create a nested object in the root object
      JsonObject outgoingData = outgoingJson.to<JsonObject>().createNestedObject("data");

      outgoingData["success"] = true;

      // Handle the message based on the "type" field
      switch (type) {
        case 1:
          // Handle SET_PIN message
          pinMode((int)data["pin"], OUTPUT);
          if (data["mode"] == "DIGITAL") {
            digitalWrite((int)data["pin"], data["value"]);
          } else {
            analogWrite((int)data["pin"], (data["value"] == 255) ? HIGH : LOW);
          }
          break;
        case 2:
          // Handle GET_VAL message
          pinMode((int)data["pin"], INPUT);
          int val;
          if (data["mode"] == "DIGITAL") {
            val = digitalRead((int)data["pin"]);
          } else {
            val = analogRead((int)data["pin"]);
          }
          break;
        case 3:
          // Handle GET_SENSOR message

          /*
          (WEIGHT_VAL - NO_WEIGHT_VAL) / Sensitivitätsfaktor = Gewicht in Gramm
          (WEIGHT_VAL - NO_WEIGHT_VAL) / (100g_val /100) ist die Formel zur Berechnung des Gewichts in Gramm nach der Kalibrierung mit einem 100 Gramm Gewicht.
          100g_val /100 gibt den Sensitivitätsfaktor an, der angibt, wie viel sich der Sensorwert ändert, wenn sich das Gewicht um ein Gramm ändert.
          Durch die Division von 100g_val durch 100 wird der Sensitivitätsfaktor berechnet, und durch die Division von (WEIGHT_VAL - NO_WEIGHT_VAL) durch den Sensitivitätsfaktor wird das Gewicht in Gramm berechnet.

          Beispiel:
          (WEIGHT_VAL - NO_WEIGHT_VAL) / (100g_val /100) = Gewicht in Gramm
          (2400 - 2000) / (2450 /100) = 80 Gramm
          */
          // HX711 circuit wiring
          const int LOADCELL_DATA_PIN = (int)data["pin_data"];
          const int LOADCELL_CLOCK_PIN = (int)data["pin_clock"];
          HX711 scale;
          scale.begin(LOADCELL_DATA_PIN, LOADCELL_CLOCK_PIN);

          // Get the weight value from the scale
          long weight_val = scale.get_units();
          outgoingData["value"] = weight_val;
          break;
        case 4:
          resetFunc();  //call reset
          break;
        default:
          // Handle unknown message type
          outgoingData[""] = 0;
          break;
      }

      // Prepare the outgoing JSON message
      outgoingJson["id"] = id;
      outgoingJson["type"] = 0;
      outgoingJson["data"] = outgoingData;

      // Send the outgoing JSON message
      serializeJson(outgoingJson, Serial);
      Serial.println();
    }
  }
}
