#include <Wire.h>
#include "esp8266_mqtt_setup.h"
#define responseLength 32

const int wireDelayTime = 1000;
char response[responseLength];

const char* topicWaterFlow = "aquaponics/water/flow";

const char* clientName = "FlowmeterClient";

const int flowmeterAddress = 104;

bool takingFlowMeasurement = false;
int flowMeasurementDelay;
unsigned long int flowMeasurementLastMillis;

const int MEASUREMENT_PERIOD = 5000;
unsigned long lastMeasurement = 0;

void sendCommand(const int address, const char* command) {
  Serial.print("Sending command ");
  Serial.print(command);
  Serial.print(" to ");
  Serial.println(address);
  Wire.beginTransmission(address);
  Wire.write(command);
  Wire.endTransmission();
}

void requestResponse(const int address) {
  Wire.requestFrom(address, responseLength, 1);
  int code = Wire.read();
  Serial.print(code);
  Serial.print(" ");

  switch (code) {
    case 1:
      Serial.println("Success");
      break;

    case 2:
      Serial.println("Failed");
      break;

    case 254:
      Serial.println("Pending");
      break;

    case 255:
      Serial.println("No Data");
      break;

    default:
      Serial.println("???");
      break;
  }
  
  int i = 0;
  while (Wire.available()) {
    char inchar = Wire.read();
    response[i] = inchar;
    i++;
    if (inchar == 0) {
      break;
    }
  }

  for (int j = i; j < responseLength; j++) {
    response[j] = ' ';
  }
}

void setup() {
  Serial.begin(115200);
  Wire.begin();
  delay(1000);

  sendCommand(flowmeterAddress, "C,0");
  delay(wireDelayTime);
  requestResponse(flowmeterAddress);

  sendCommand(flowmeterAddress, "Frp,h");
  delay(wireDelayTime);
  requestResponse(flowmeterAddress);

  sendCommand(flowmeterAddress, "O,TV,0");
  delay(wireDelayTime);
  requestResponse(flowmeterAddress);

  sendCommand(flowmeterAddress, "O,FR,1");
  delay(wireDelayTime);
  requestResponse(flowmeterAddress);

  sendCommand(flowmeterAddress, "O,?");
  delay(wireDelayTime);
  requestResponse(flowmeterAddress);
  Serial.println(response);

  setup_wifi();
  setup_mqtt();
}

void loop() {
  if (!mqttClient.connected()) {
    reconnect(clientName);
  }
  mqttClient.loop();

  unsigned long currentMillis = millis();
  if (currentMillis - lastMeasurement >= MEASUREMENT_PERIOD) {
    lastMeasurement = currentMillis;
    RestartFlowMeasurement();
  }

  if (takingFlowMeasurement) {
    TakeFlowMeasurement();
  }
}

void RestartFlowMeasurement() {
  flowMeasurementDelay = 0;
  flowMeasurementLastMillis = millis();

  sendCommand(flowmeterAddress, "R");

  takingFlowMeasurement = true;
}

void TakeFlowMeasurement() {
  if (flowMeasurementDelay < wireDelayTime) {
    unsigned long int currentMillis = millis();
    flowMeasurementDelay += currentMillis - flowMeasurementLastMillis;
    flowMeasurementLastMillis = currentMillis;
    return;
  }

  requestResponse(flowmeterAddress);

  Serial.print("Water flow I2C output: ");
  Serial.println(response);

  if (isdigit(response[0])) {
    float flow = atof(response);
    Serial.print("Water flow: ");
    Serial.print(flow);
    Serial.println(" l/h");

    mqttClient.publish(topicWaterFlow, String(flow).c_str());
  }
  Serial.println();

  takingFlowMeasurement = false;
}