// EnergySensor.h

#ifndef _ENERGYSENSOR_h
#define _ENERGYSENSOR_h
#include "Arduino.h"

#include <UrsTime.h>
#include <IPAddress.h>
#include "Globals.h"
#include "PZEMSerial.h"

class EnergyData {
public:
  float power;          // aktuelle Leistung in W
  float energy;         // Energie (Gesamtverbrauch)
  float energyRaw;      // abgelesener Gesamtverbrauchswert
  bool isValid = false; // Die zurück gelieferten Messwerte sind valide
  time_t timeStamp;     // Zeitstempel der Messwerterfassung
  uint32_t secondsSinceStart; // Sekunden seit Start der aktuellen Messreihe 
  bool isTimeStampValid = false; // Der Zeitstempel enthält UNIX-Zeitstempel. Bei false enthält timeStamp den Wert von millis()/1000
  String toString();
};

// Event-Handler. Ereignis: Verbrauchszähler wurde zurück gesetzt
typedef std::function<void(float startValue, time_t startTime)> EnergySensorResetHandlerFunction;

class EnergySensorClass{
protected:
  uint8_t _RxPin;
  uint8_t _TxPin;
  IPAddress _pzemAddress;       // Adresse des PZEM-004T
  uint8_t _CoilTurns = 1;       // Anzahl der Windungen durch den Stromtransformator

  bool _isRunning = false;      // gibt an, ob die Kommunikation mit dem Sensor gestartet werden konnte.
  float _StartValue = -1;       // Wert der Energiemessung zu Beginn des Messintervalls.
  time_t _StartTime = 0;        // Uhrzeit des Beginns des Messintervalls
 
  Print * _LogDevice = &Serial; // Gerät zur Ausgabe von Statusmeldungen

  // Kommunikation mit dem PZEM-004T
  PZEMSerial* _serial = NULL;                // Kommunikationsschnittstelle
  static const uint32_t _readTimeOut = 1000; // Timeout in ms für die Antwort des PZEM-004T
  static const uint32_t _ErrorDelay  =  300; // Länge der Pause in ms nach einem fehlerhaften Leseversuch
  void send(const IPAddress &addr, uint8_t cmd, uint8_t data = 0); // Sendet Kommando an PZEM-000T
  bool recieve(uint8_t resp, uint8_t *data = 0); // Empfängt die Anwort
  uint8_t crc(uint8_t *data, uint8_t sz);        // Berechnet die Checksumme
 
  float power(const IPAddress &addr);   // liest den aktuellen Leistungswert aus
  float energy(const IPAddress &addr);  // liest den aktuellen Gesamtverbrauch aus
  bool setAddress(const IPAddress &newAddr); // setzt die Kommunikationsadresse des PZEM-004T

  EnergyData lastReading;      // letzter eingelesener Sensorwert
  uint16_t _interval;          // Zeitraum zwischen zwei Messungen in Sekunden
  uint32_t lastSensorRead;     // Zeitpunkt der letzten Sensorlesung (millis())

  EnergySensorResetHandlerFunction _SensorReset = NULL;

  // ToDo: Sensor-auslesen nicht mit millis sondern mit Zeitserver synchronisieren

public:
  // (RX,TX) connect to TX,RX of PZEM
  // Pins für ESP8266: 4 (D2), 5 (D1), 12 (D6), 13 (D7), 14 (D5), 15 (D8)
  EnergySensorClass(uint8_t rxPin, uint8_t txPin, uint8_t coilTurns = 1, uint16_t interval = 2);

  bool begin(float startValue, time_t StartTime, Print* logDevice = NULL); // initialisiert die Kommunikation mit dem PZEM-004T

  void handle(bool noDelay = false); // liest die aktuellen Messwerte aus; noDelay = true: Ablauf der Zeitschleide nicht abwarten
  void reset();                      // setzt den Verbrauchszähler auf 0
  EnergyData getLastReading() { return lastReading; } // Ruft die zuletzt vom PZEM ausgelesenen Messwerte ab. 
  void setInterval(uint16_t interval) { _interval = interval; } // Legt den Zeitabstand in Sekunden zwischen zwei Ablesungen des PZEM fest.
  void onEnergySensorReset(EnergySensorResetHandlerFunction f) { _SensorReset = f; } // Event "Verbrauchzähler zurückgesetzt".

};

extern EnergySensorClass EnergySensor;

#endif

  
