#ifndef _TEMPERATURE_H_
#define _TEMPERATURE_H_


mqttValueTiming timing_temperature_reservoir;
mqttValueTiming timing_temperature_case;

#include <OneWire.h>
#include <DallasTemperature.h>

void printAddress(DeviceAddress deviceAddress);

//first address: 28FF6C1C7216058B
//second address: 

//#define ONE_WIRE_BUS_PIN 18 //GPIO pin moved to platformio.ini
#define TEMPERATURE_PRECISION 12 //max is 12
#define READINTERVAL_DS18B20 1000 //ms

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS_PIN);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);


#define TEMPMEAN_SIZE 16
uint16_t tempCmean_pos=0;
// arrays to hold device addresses

//DeviceAddress thermometerAir={0x28,0xFF,0x6C,0x1C,0x72,0x16,0x05,0x8B};
//DeviceAddress thermometerReservoirA={0x28,0xFF,0x6F,0x19,0x72,0x16,0x05,0x44}; //NFT
//DeviceAddress thermometerReservoirB={0x28,0xFF,0x30,0xBA,0x85,0x16,0x03,0xB5}; //DB
DeviceAddress thermometerReservoir=THERMOMETER_ADDR_RESERVOIR;
float tempC_reservoir; //last reading
float tempCmean_reservoir_array[TEMPMEAN_SIZE];
float tempCmean_reservoir=DEVICE_DISCONNECTED_C;


DeviceAddress thermometerCase=THERMOMETER_ADDR_CASE;
float tempC_case; //last reading
float tempCmean_case_array[TEMPMEAN_SIZE];
float tempCmean_case=DEVICE_DISCONNECTED_C;




void temperature_setup() {
  timing_temperature_reservoir.minchange=0.0;
  timing_temperature_reservoir.maxchange=0.5;
  timing_temperature_reservoir.mintime=2*1000;
  timing_temperature_reservoir.maxtime=60*60*1000;


  timing_temperature_case.minchange=0.0;
  timing_temperature_case.maxchange=0.5;
  timing_temperature_case.mintime=2*1000;
  timing_temperature_case.maxtime=60*60*1000;

  //initialize mean array
  for (uint16_t i=0;i<TEMPMEAN_SIZE;i++) {
    tempCmean_reservoir_array[i]=-127;
    tempCmean_case_array[i]=-127;
  }

  sensors.begin();
  delay(1000);


  Serial.print("Locating devices...");
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  delay(1000);

  //Serial.print("Parasite power is: ");
  //if (sensors.isParasitePowerMode()) Serial.println("ON");
  //else Serial.println("OFF");

  delay(1000);


  //Just search for devices. Only needed when connecting a new sensor to find the address
  oneWire.reset_search();
  
  for (uint8_t i=0;i<sensors.getDeviceCount();i++){
    DeviceAddress _addr;
    if (!oneWire.search(_addr)) {
      Serial.print("Error: Device not found");
      String _text="Error: Device not found. id=";
      _text.concat(i);
      publishInfo("error/temperature",_text);
    }else{
      Serial.print("Found device. Address:");
      printAddress(_addr);
    }
    Serial.println();
      
  }

  sensors.setResolution(thermometerReservoir, TEMPERATURE_PRECISION);
  sensors.setResolution(thermometerCase, TEMPERATURE_PRECISION);
}


void temperature_loop(unsigned long loopmillis) {

  static unsigned long last_read_ds18b20=0;
  static bool flag_requestTemperatures=false;
  if (loopmillis>last_read_ds18b20+READINTERVAL_DS18B20) { 
    if (loopmillis>last_read_ds18b20+READINTERVAL_DS18B20*10) { //timeout
      Serial.println("Warn: Request Temperatures Timeout!");
      if (mqtt) {
        publishInfo("error/temperature","Warn: Request Temperatures Timeout!");
      }
      flag_requestTemperatures=false;
      last_read_ds18b20=loopmillis;
    }
    if (!flag_requestTemperatures) {
      sensors.setWaitForConversion(false); //make async
      sensors.requestTemperatures(); //this takes ~600ms in non async mode. about 2ms in async mode
      sensors.setWaitForConversion(true);
      flag_requestTemperatures=true;
    }
    if (sensors.isConversionComplete()) {
      flag_requestTemperatures=false;
      last_read_ds18b20=loopmillis;
      
      tempC_reservoir = sensors.getTempC(thermometerReservoir);
      if (tempC_reservoir == DEVICE_DISCONNECTED_C)
      {
        Serial.print(" Error reading: ");  printAddress(thermometerReservoir); Serial.println();
        publishInfo("error/temperature","Error reading thermometerReservoir");
      }else{
        tempCmean_reservoir_array[tempCmean_pos]=tempC_reservoir;
        if (isValueArrayOKf(tempCmean_reservoir_array,TEMPMEAN_SIZE,DEVICE_DISCONNECTED_C)) {
          tempCmean_reservoir=getMeanf(tempCmean_reservoir_array,TEMPMEAN_SIZE);
        }else{
          tempCmean_reservoir=DEVICE_DISCONNECTED_C;
        }
      }


      tempC_case = sensors.getTempC(thermometerCase);
      if (tempC_case == DEVICE_DISCONNECTED_C)
      {
        Serial.print(" Error reading: ");  printAddress(thermometerCase);
        publishInfo("error/temperature","Error reading thermometerCase");
      }else{
        tempCmean_case_array[tempCmean_pos]=tempC_case;
        if (isValueArrayOKf(tempCmean_case_array,TEMPMEAN_SIZE,DEVICE_DISCONNECTED_C)) {
          tempCmean_case=getMeanf(tempCmean_case_array,TEMPMEAN_SIZE);
        }else{
          tempCmean_case=DEVICE_DISCONNECTED_C;
        }
      }

      tempCmean_pos++;
      tempCmean_pos%=TEMPMEAN_SIZE;
    }
    
  }
}


void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    // zero pad the address if necessary
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}
#endif