// #######################################################################################################
// ######################## Plugin 127 CDM7160 I2C CO2 Sensor ############################################
// #######################################################################################################
// development version
// by: V0JT4
// Resolves: https://github.com/letscontrolit/ESPEasy/issues/986
//

/** Changelog:
 * 2025-01-12 tonhuisman: Add support for MQTT AutoDiscovery
 *                        Updated changelog
 * 2022-06-24 tonhuisman: Remove delay from init call, optimize some code
 * 2022-01-13 tonhuisman: Ignore measured values > 15000: unit is still initializing
 *                        Change status from Development to Testing
 * 2021-12-31 tonhuisman: Migrate plugin from ESPEasyPluginPlayground to ESPEasy repository
 *                        - Restructured: Use ESPEasy 'modern' code
 *                        - Restructured: Split into PluginDataStruct
 *                        - Select Plugin ID 127
 */


#include "_Plugin_Helper.h"
#ifdef USES_P127

# include "src/PluginStructs/P127_data_struct.h"

# define PLUGIN_127
# define PLUGIN_ID_127         127
# define PLUGIN_NAME_127       "Gases - CO2 CDM7160"
# define PLUGIN_VALUENAME1_127 "CO2"


boolean Plugin_127_init = false;


boolean Plugin_127(uint8_t function, struct EventStruct *event, String& string)
{
  boolean success = false;

  switch (function) {
    case PLUGIN_DEVICE_ADD:
    {
      auto& dev = Device[++deviceCount];
      dev.Number           = PLUGIN_ID_127;
      dev.Type             = DEVICE_TYPE_I2C;
      dev.VType            = Sensor_VType::SENSOR_TYPE_SINGLE;
      dev.FormulaOption    = true;
      dev.ValueCount       = 1;
      dev.SendDataOption   = true;
      dev.TimerOption      = true;
      dev.GlobalSyncOption = true;
      dev.PluginStats      = true;
      break;
    }

    case PLUGIN_GET_DEVICENAME:
    {
      string = F(PLUGIN_NAME_127);
      break;
    }

    case PLUGIN_GET_DEVICEVALUENAMES:
    {
      strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_127));
      break;
    }

    # if FEATURE_MQTT_DISCOVER
    case PLUGIN_GET_DISCOVERY_VTYPES:
    {
      success = getDiscoveryVType(event, Plugin_QueryVType_CO2, 255, event->Par5);;
      break;
    }
    # endif // if FEATURE_MQTT_DISCOVER

    case PLUGIN_I2C_HAS_ADDRESS:
    case PLUGIN_WEBFORM_SHOW_I2C_PARAMS:
    {
      const uint8_t i2cAddressValues[] = { CDM7160_ADDR_0, CDM7160_ADDR };

      if (function == PLUGIN_WEBFORM_SHOW_I2C_PARAMS) {
        addFormSelectorI2C(F("i2c_addr"), 2, i2cAddressValues, P127_CONFIG_I2C_ADDRESS, CDM7160_ADDR);
        # ifndef LIMIT_BUILD_SIZE
        addFormNote(F("CAD0 High/open=0x69, Low=0x68"));
        # endif // ifndef LIMIT_BUILD_SIZE
      } else {
        success = intArrayContains(2, i2cAddressValues, event->Par1);
      }
      break;
    }

    # if FEATURE_I2C_GET_ADDRESS
    case PLUGIN_I2C_GET_ADDRESS:
    {
      event->Par1 = P127_CONFIG_I2C_ADDRESS;
      success     = true;
      break;
    }
    # endif // if FEATURE_I2C_GET_ADDRESS

    case PLUGIN_SET_DEFAULTS:
    {
      P127_CONFIG_I2C_ADDRESS                      = CDM7160_ADDR;
      ExtraTaskSettings.TaskDeviceValueDecimals[0] = 0; // No decimals needed
      break;
    }

    case PLUGIN_WEBFORM_LOAD:
    {
      addFormNumericBox(F("Altitude"), F("altitude"), P127_CONFIG_ALTITUDE, 0, 2550); // Max. 2550 meter supported
      addUnit('m');

      success = true;
      break;
    }

    case PLUGIN_WEBFORM_SAVE:
    {
      P127_CONFIG_I2C_ADDRESS = getFormItemInt(F("i2c_addr"));
      P127_CONFIG_ALTITUDE    = getFormItemInt(F("altitude"));

      success = true;
      break;
    }
    case PLUGIN_INIT:
    {
      initPluginTaskData(event->TaskIndex, new (std::nothrow) P127_data_struct(P127_CONFIG_I2C_ADDRESS, P127_CONFIG_ALTITUDE));
      P127_data_struct *P127_data = static_cast<P127_data_struct *>(getPluginTaskData(event->TaskIndex));

      success = (nullptr != P127_data) && P127_data->init();

      break;
    }
    case PLUGIN_ONCE_A_SECOND:
    {
      P127_data_struct *P127_data = static_cast<P127_data_struct *>(getPluginTaskData(event->TaskIndex));

      if (nullptr != P127_data) {
        success = P127_data->checkData();
      }

      break;
    }
    case PLUGIN_READ:
    {
      P127_data_struct *P127_data = static_cast<P127_data_struct *>(getPluginTaskData(event->TaskIndex));

      if (nullptr == P127_data) {
        return success;
      }

      UserVar.setFloat(event->TaskIndex, 0, P127_data->readData());

      success = true;

      if (UserVar[event->BaseVarIndex] > 15000) {
        addLog(LOG_LEVEL_ERROR, F("CDM7160: Sensor still initializing, data ignored"));
        success = false; // Do not send out to controllers
      } else if (UserVar[event->BaseVarIndex] > 10000) {
        addLog(LOG_LEVEL_ERROR, F("CDM7160: Sensor saturated! > 10000 ppm"));
      }

      if (loglevelActiveFor(LOG_LEVEL_INFO)) {
        addLogMove(LOG_LEVEL_INFO, strformat(F("CDM7160: Address: 0x%02x: CO2 ppm: %d, alt: %d, comp: %d"),
                                             P127_CONFIG_I2C_ADDRESS,
                                             UserVar[event->BaseVarIndex],
                                             P127_data->getAltitude(),
                                             P127_data->getCompensation()));
      }
      break;
    }
    case PLUGIN_WRITE:
    {
      P127_data_struct *P127_data = static_cast<P127_data_struct *>(getPluginTaskData(event->TaskIndex));

      if (nullptr != P127_data) {
        String command = parseString(string, 1);

        if (equals(command, F("cdmrst"))) {
          addLog(LOG_LEVEL_INFO, F("CDM7160: reset"));
          P127_data->setReset();
          success = true;
        }
      }

      break;
    }

    case PLUGIN_FIFTY_PER_SECOND: // Handle delays
    {
      P127_data_struct *P127_data = static_cast<P127_data_struct *>(getPluginTaskData(event->TaskIndex));

      if (nullptr != P127_data) {
        success = P127_data->plugin_fifty_per_second();
      }

      break;
    }
  }
  return success;
}

#endif // USES_P127
