/*
  xsns_66_iAQ.ino - Support for iAQ-Core - Indoor Air Quality Sensor Module

  Copyright (C) 2021   Christian Baars and Theo Arends

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifdef USE_I2C
#ifdef USE_IAQ
/*********************************************************************************************\
 * iAQ-Core - Indoor Air Quality Sensor
 *
 * I2C Address: 0x5A
\*********************************************************************************************/

#define XSNS_66            66
#define XI2C_46            46      // See I2CDEVICES.md

#define I2_ADR_IAQ         0x5a    // collides with MLX90614 and maybe others

#define IAQ_STATUS_OK      0x00
#define IAQ_STATUS_BUSY    0x01
#define IAQ_STATUS_WARM    0x10
#define IAQ_STATUS_ERR     0x80
#define IAQ_STATUS_I2C_ERR 0xFF

struct  {
  int32_t   resistance;
  uint16_t  pred;
  uint16_t  Tvoc;
  uint8_t   i2c_address;
  uint8_t   status;
  bool      ready;
} iAQ;

void IAQ_Init(void) {
  if (!I2cSetDevice(I2_ADR_IAQ)) { return; }
  I2cSetActiveFound(I2_ADR_IAQ, "IAQ");
  iAQ.i2c_address = I2_ADR_IAQ;
  iAQ.ready = true;
/*
  for (iAQ.i2c_address = I2_ADR_IAQ; iAQ.i2c_address < I2_ADR_IAQ +5; iAQ.i2c_address++) {
    if (I2cActive(iAQ.i2c_address)) { continue; }
    if (I2cSetDevice(iAQ.i2c_address)) {
      I2cSetActiveFound(iAQ.i2c_address, "IAQ");
      iAQ.ready = true;
      break;
    }
  }
*/
}

void IAQ_Read(void) {
  uint8_t buf[9];
  buf[2] = IAQ_STATUS_I2C_ERR; // populate entry with error code
  Wire.requestFrom(iAQ.i2c_address, sizeof(buf));
  for( uint32_t i=0; i<9; i++ ) {
    buf[i]= Wire.read();
  }
  // AddLog(LOG_LEVEL_DEBUG, "iAQ: buffer %x %x %x %x %x %x %x %x %x ", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]);
  iAQ.pred = (buf[0]<<8) + buf[1];
  iAQ.status = buf[2];
  iAQ.resistance =  ((uint32_t)buf[3]<<24) + ((uint32_t)buf[4]<<16) + ((uint32_t)buf[5]<<8) + (uint32_t)buf[6];
  iAQ.Tvoc =  (buf[7]<<8) + buf[8];
}

/*********************************************************************************************\
 * Presentation
\*********************************************************************************************/

#ifdef USE_WEBSERVER
const char HTTP_SNS_IAQ[] PROGMEM =
  "{s}iAQ-Core " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"     // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
  "{s}iAQ-Core " D_TVOC "{m}%d " D_UNIT_PARTS_PER_BILLION "{e}";

const char HTTP_SNS_IAQ_ERROR[] PROGMEM =
  "{s}iAQ-Core {m} %s {e}";
#endif

void IAQ_Show(uint8_t json)
{
  IAQ_Read();

  if (json) {
    if (iAQ.status!=IAQ_STATUS_OK){
      AddLog(LOG_LEVEL_INFO, PSTR("iAQ: " D_ERROR " %x" ),iAQ.status);
      return;
  }
  else {
    ResponseAppend_P(PSTR(",\"IAQ\":{\"" D_JSON_ECO2 "\":%u,\"" D_JSON_TVOC "\":%u,\"" D_JSON_RESISTANCE "\":%u}"), iAQ.pred, iAQ.Tvoc, iAQ.resistance);
#ifdef USE_DOMOTICZ
      if (0 == TasmotaGlobal.tele_period) DomoticzSensor(DZ_AIRQUALITY, iAQ.pred);
#endif  // USE_DOMOTICZ
  }
#ifdef USE_WEBSERVER
    } else {
      switch(iAQ.status){
        case IAQ_STATUS_OK:
          WSContentSend_PD(HTTP_SNS_IAQ, iAQ.pred, iAQ.Tvoc);
          break;
        case IAQ_STATUS_WARM:
          WSContentSend_PD(HTTP_SNS_IAQ_ERROR, D_START);
          break;
        default:
          WSContentSend_PD(HTTP_SNS_IAQ_ERROR, D_ERROR);
      }
#endif
  }
}

/*********************************************************************************************\
 * Interface
\*********************************************************************************************/

bool Xsns66(byte function)
{
  if (!I2cEnabled(XI2C_46)) { return false; }

  bool result = false;

  if (FUNC_INIT == function) {
    IAQ_Init();
  }
  else if (iAQ.ready) {
    switch (function) {
      case FUNC_JSON_APPEND:
        IAQ_Show(1);
        break;
#ifdef USE_WEBSERVER
      case FUNC_WEB_SENSOR:
        IAQ_Show(0);
        break;
#endif  // USE_WEBSERVER
    }
  }
  return result;
}

#endif  // USE_IAQ
#endif  // USE_I2C