mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-09-15 11:05:08 +00:00
[MQTT] Add support for more VTypes, implement more VTypes, small improvements
This commit is contained in:
+6
-2
@@ -18,7 +18,7 @@
|
||||
/** Changelog:
|
||||
* 2024-11-29 tonhuisman: Add Discovery trigger setting
|
||||
* 2024-11-11 tonhuisman: Add AutoDiscovery options
|
||||
* Home Assistant suggested discovery topic: "homeassistant/%devclass%/%sysname%/%tskname%/config"
|
||||
* Home Assistant suggested discovery topic: "homeassistant/%devclass%/%sysname%/%tskname%"
|
||||
* 2023-08-18 tonhuisman: Clean up source for pull request
|
||||
* 2023-03-15 tonhuisman: Add processing of topic endpoint /set to issue a TaskValueSet,taskname,taskvalue,payload command for
|
||||
* topic %sysname%/#/taskname/valuename/set
|
||||
@@ -151,7 +151,11 @@ bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String&
|
||||
// We have received the Discovery request topic
|
||||
// Generate random time-offset in 0.1 sec, range 1..10 seconds
|
||||
mqttDiscoveryTimeout = random(10, 100);
|
||||
addLog(LOG_LEVEL_INFO, strformat(F("C005 : Request for AutoDiscovery received. %d"), mqttDiscoveryTimeout));
|
||||
|
||||
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
|
||||
addLog(LOG_LEVEL_INFO, strformat(F("C005 : Request for AutoDiscovery received. %.1f sec."),
|
||||
mqttDiscoveryTimeout / 10.0f));
|
||||
}
|
||||
|
||||
// FIXME Generate event when request received?
|
||||
} else
|
||||
|
||||
+500
-487
@@ -1,487 +1,500 @@
|
||||
#include "_Plugin_Helper.h"
|
||||
#ifdef USES_P052
|
||||
|
||||
# include "src/PluginStructs/P052_data_struct.h"
|
||||
|
||||
// #######################################################################################################
|
||||
// ############################# Plugin 052: Senseair CO2 Sensors ########################################
|
||||
// #######################################################################################################
|
||||
|
||||
/** Changelog:
|
||||
* 25025-01-03 tonhuisman: Small code size reduction
|
||||
*/
|
||||
|
||||
/*
|
||||
Plugin originally written by: Daniel Tedenljung
|
||||
info__AT__tedenljungconsulting.com
|
||||
Rewritten by: Mikael Trieb mikael__AT__triebconsulting.se
|
||||
|
||||
This plugin reads available values of Senseair Co2 Sensors.
|
||||
Datasheet can be found here:
|
||||
S8: http://www.senseair.com/products/oem-modules/senseair-s8/
|
||||
K30: http://www.senseair.com/products/oem-modules/k30/
|
||||
K70/tSENSE: http://www.senseair.com/products/wall-mount/tsense/
|
||||
|
||||
Circuit wiring
|
||||
GPIO Setting 1 -> RX
|
||||
GPIO Setting 2 -> TX
|
||||
Use 1kOhm in serie on datapins!
|
||||
*/
|
||||
|
||||
# define PLUGIN_052
|
||||
# define PLUGIN_ID_052 52
|
||||
# define PLUGIN_NAME_052 "Gases - CO2 Senseair"
|
||||
|
||||
|
||||
boolean Plugin_052(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_052;
|
||||
dev.Type = DEVICE_TYPE_SERIAL;
|
||||
dev.VType = Sensor_VType::SENSOR_TYPE_SINGLE;
|
||||
dev.FormulaOption = true;
|
||||
dev.ValueCount = 1;
|
||||
dev.SendDataOption = true;
|
||||
dev.TimerOption = true;
|
||||
dev.OutputDataType = Output_Data_type_t::Simple;
|
||||
dev.ExitTaskBeforeSave = false;
|
||||
dev.PluginStats = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME: {
|
||||
string = F(PLUGIN_NAME_052);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES: {
|
||||
for (uint8_t i = 0; i < VARS_PER_TASK; ++i) {
|
||||
if (i < P052_NR_OUTPUT_VALUES) {
|
||||
const uint8_t pconfigIndex = i + P052_QUERY1_CONFIG_POS;
|
||||
uint8_t choice = PCONFIG(pconfigIndex);
|
||||
ExtraTaskSettings.setTaskDeviceValueName(i, P052_data_struct::Plugin_052_valuename(choice, false));
|
||||
} else {
|
||||
ExtraTaskSettings.clearTaskDeviceValueName(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUECOUNT:
|
||||
{
|
||||
event->Par1 = P052_NR_OUTPUT_VALUES;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVTYPE:
|
||||
{
|
||||
event->sensorType = static_cast<Sensor_VType>(PCONFIG(P052_SENSOR_TYPE_INDEX));
|
||||
event->idx = P052_SENSOR_TYPE_INDEX;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEGPIONAMES: {
|
||||
serialHelper_getGpioNames(event);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SHOW_CONFIG:
|
||||
{
|
||||
string += serialHelper_getSerialTypeLabel(event);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_SET_DEFAULTS:
|
||||
{
|
||||
PCONFIG(P052_SENSOR_TYPE_INDEX) = static_cast<int16_t>(Sensor_VType::SENSOR_TYPE_SINGLE);
|
||||
PCONFIG(0) = 1; // "CO2"
|
||||
|
||||
for (uint8_t i = 1; i < VARS_PER_TASK; ++i) {
|
||||
PCONFIG(i) = 0; // "Empty"
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD_OUTPUT_SELECTOR:
|
||||
{
|
||||
const __FlashStringHelper *options[P052_NR_OUTPUT_OPTIONS];
|
||||
|
||||
for (uint8_t i = 0; i < P052_NR_OUTPUT_OPTIONS; ++i) {
|
||||
options[i] = P052_data_struct::Plugin_052_valuename(i, true);
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < P052_NR_OUTPUT_VALUES; ++i) {
|
||||
const uint8_t pconfigIndex = i + P052_QUERY1_CONFIG_POS;
|
||||
sensorTypeHelper_loadOutputSelector(event, pconfigIndex, i, P052_NR_OUTPUT_OPTIONS, options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD: {
|
||||
P052_data_struct *P052_data =
|
||||
static_cast<P052_data_struct *>(getPluginTaskData(event->TaskIndex));
|
||||
|
||||
if ((nullptr != P052_data) && P052_data->isInitialized()) {
|
||||
addFormSubHeader(F("Device Information"));
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
if (P052_data->modbus.detected_device_description.length() > 0) {
|
||||
addRowLabel(F("Detected Device"));
|
||||
addHtml(P052_data->modbus.detected_device_description);
|
||||
}
|
||||
|
||||
if (P052_data->readInputRegister(P052_IR29_FW_REV, value)) {
|
||||
addRowLabel(F("FW rev."));
|
||||
addHtmlInt(value);
|
||||
}
|
||||
|
||||
addRowLabel(F("Sensor ID"));
|
||||
addHtml(formatToHex_decimal(P052_data->getSensorID()));
|
||||
|
||||
|
||||
addRowLabel(F("Checksum (pass/fail/nodata)"));
|
||||
{
|
||||
uint32_t reads_pass, reads_crc_failed, reads_nodata;
|
||||
P052_data->modbus.getStatistics(reads_pass, reads_crc_failed, reads_nodata);
|
||||
addHtml(strformat(F("%d/%d/%d"), reads_pass, reads_crc_failed, reads_nodata));
|
||||
}
|
||||
|
||||
bool hasFactorySettings = false;
|
||||
bool enabledABC = false;
|
||||
|
||||
if (P052_data->readHoldingRegister(P052_HR19_METER_CONTROL, value)) {
|
||||
hasFactorySettings = value == 255;
|
||||
enabledABC = bitRead(value, 1) == 0;
|
||||
addRowLabel(F("Using Factory Settings"));
|
||||
addEnabled(hasFactorySettings);
|
||||
|
||||
if (!hasFactorySettings) {
|
||||
// addRowLabel(F("HR19"));
|
||||
// addHtmlInt(value);
|
||||
addRowLabel(F("nRDY"));
|
||||
addEnabled(bitRead(value, 0) == 0);
|
||||
addRowLabel(F("ABC"));
|
||||
addEnabled(enabledABC);
|
||||
addRowLabel(F("Static IIR filter"));
|
||||
addEnabled(bitRead(value, 2) == 0);
|
||||
addRowLabel(F("Dynamic IIR filter"));
|
||||
addEnabled(bitRead(value, 3) == 0);
|
||||
addRowLabel(F("Pressure Compensation"));
|
||||
addEnabled(bitRead(value, 4) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (P052_data->readInputRegister(P052_IR7_MEASUREMENT_COUNT, value)) {
|
||||
addRowLabel(F("Measurement Count"));
|
||||
addHtmlInt(value);
|
||||
}
|
||||
|
||||
if (P052_data->readInputRegister(P052_IR8_MEASUREMENT_CYCLE_TIME, value)) {
|
||||
addRowLabel(F("Measurement Cycle time"));
|
||||
addHtmlInt(value * 2);
|
||||
addUnit('s');
|
||||
}
|
||||
|
||||
if (P052_data->readInputRegister(P052_IR9_MEASURED_UNFILTERED_CO2, value)) {
|
||||
addRowLabel(F("Unfiltered CO2"));
|
||||
addHtmlInt(value);
|
||||
}
|
||||
|
||||
if (P052_data->readHoldingRegister(P052_HR11_MEASUREMENT_MODE, value)) {
|
||||
addRowLabel(F("Measurement Mode"));
|
||||
addHtml(value == 0 ? F("Continuous") : F("Single Measurement"));
|
||||
}
|
||||
|
||||
if (enabledABC) {
|
||||
if (P052_data->readHoldingRegister(P052_HR14_ABC_PERIOD, value)) {
|
||||
addRowLabel(F("ABC Period"));
|
||||
addHtmlInt(value);
|
||||
addUnit('h');
|
||||
}
|
||||
|
||||
if (P052_data->readHoldingRegister(P052_HR5_ABC_TIME, value)) {
|
||||
addRowLabel(F("Time Since ABC"));
|
||||
addHtmlInt(value);
|
||||
addUnit('h');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
/*
|
||||
if (P052_data->readHoldingRegister(P052_HR11_MEASUREMENT_MODE, value)) {
|
||||
// Disable selector for now, since single measurement not yet supported.
|
||||
|
||||
const __FlashStringHelper *options[2] = { F("Continuous"), F("Single Measurement") };
|
||||
addFormSelector(F("Measurement Mode"), F("mode"), 2, options, nullptr, value);
|
||||
}
|
||||
*/
|
||||
|
||||
if (P052_data->readHoldingRegister(P052_HR12_MEASUREMENT_PERIOD, value)) {
|
||||
addFormNumericBox(F("Measurement Period"), F("period"), value, 2, 65534);
|
||||
addUnit('s');
|
||||
}
|
||||
|
||||
if (P052_data->readHoldingRegister(P052_HR13_NR_OF_SAMPLES, value)) {
|
||||
addFormNumericBox(F("Samples per measurement"), F("samp_meas"), value, 1, 1024);
|
||||
}
|
||||
}
|
||||
{
|
||||
// P052_ABC_PERIOD
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// ABC functionality disabled for now, due to a bug in the firmware.
|
||||
// See https://github.com/letscontrolit/ESPEasy/issues/759
|
||||
uint8_t choiceABCperiod = PCONFIG(4);
|
||||
const __FlashStringHelper * optionsABCperiod[9] = { F("disable"), F("1 h"), F("12 h"), F("1
|
||||
day"), F("2 days"), F("4 days"), F("7 days"), F("14 days"), F("30 days") };
|
||||
addFormSelector(F("ABC period"), F("ABC_period"), 9, optionsABCperiod,
|
||||
nullptr, choiceABCperiod);
|
||||
*/
|
||||
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE: {
|
||||
// Save output selector parameters.
|
||||
for (uint8_t i = 0; i < P052_NR_OUTPUT_VALUES; ++i) {
|
||||
const uint8_t pconfigIndex = i + P052_QUERY1_CONFIG_POS;
|
||||
const uint8_t choice = PCONFIG(pconfigIndex);
|
||||
sensorTypeHelper_saveOutputSelector(event, pconfigIndex, i, P052_data_struct::Plugin_052_valuename(choice, false));
|
||||
}
|
||||
|
||||
P052_data_struct *P052_data =
|
||||
static_cast<P052_data_struct *>(getPluginTaskData(event->TaskIndex));
|
||||
|
||||
if ((nullptr != P052_data) && P052_data->isInitialized()) {
|
||||
bool changed = false;
|
||||
uint16_t mode = getFormItemInt(F("mode"), 65535);
|
||||
|
||||
if (((mode == 0) || (mode == 1))) {
|
||||
uint8_t errorcode;
|
||||
int readVal = P052_data->modbus.readHoldingRegister(0x0A, errorcode);
|
||||
|
||||
if ((errorcode == 0) && (readVal != mode)) {
|
||||
P052_data->modbus.writeMultipleRegisters(0x0A, mode);
|
||||
delay(0);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
uint16_t period = getFormItemInt(F("period"), 0);
|
||||
|
||||
if (period > 1) {
|
||||
uint8_t errorcode;
|
||||
int readVal = P052_data->modbus.readHoldingRegister(0x0B, errorcode);
|
||||
|
||||
if ((errorcode == 0) && (readVal != period)) {
|
||||
P052_data->modbus.writeMultipleRegisters(0x0B, period);
|
||||
delay(0);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
uint16_t samp_meas = getFormItemInt(F("samp_meas"), 0);
|
||||
|
||||
if ((samp_meas > 0) && (samp_meas <= 1024)) {
|
||||
uint8_t errorcode;
|
||||
int readVal = P052_data->modbus.readHoldingRegister(0x0C, errorcode);
|
||||
|
||||
if ((errorcode == 0) && (readVal != samp_meas)) {
|
||||
P052_data->modbus.writeMultipleRegisters(0x0C, samp_meas);
|
||||
delay(0);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
// Restart sensor.
|
||||
P052_data->modbus.writeMultipleRegisters(0x11, 0xFF);
|
||||
|
||||
// FIXME TD-er: Must leave the sensor to boot for a while.
|
||||
delay(35);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// ABC functionality disabled for now, due to a bug in the firmware.
|
||||
// See https://github.com/letscontrolit/ESPEasy/issues/759
|
||||
PCONFIG(4) = getFormItemInt(F("ABC_period"));
|
||||
*/
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT: {
|
||||
const int16_t serial_rx = CONFIG_PIN1;
|
||||
const int16_t serial_tx = CONFIG_PIN2;
|
||||
const ESPEasySerialPort port = static_cast<ESPEasySerialPort>(CONFIG_PORT);
|
||||
|
||||
initPluginTaskData(event->TaskIndex, new (std::nothrow) P052_data_struct());
|
||||
P052_data_struct *P052_data =
|
||||
static_cast<P052_data_struct *>(getPluginTaskData(event->TaskIndex));
|
||||
|
||||
if (nullptr == P052_data) {
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
if (P052_data->init(port, serial_rx, serial_tx)) {
|
||||
/*
|
||||
// ABC functionality disabled for now, due to a bug in the firmware.
|
||||
// See https://github.com/letscontrolit/ESPEasy/issues/759
|
||||
const int periodInHours[9] = {0, 1, 12, (24*1), (24*2), (24*4), (24*7),
|
||||
(24*14), (24*30) };
|
||||
uint8_t choiceABCperiod = PCONFIG(1);
|
||||
|
||||
Plugin_052_setABCperiod(periodInHours[choiceABCperiod]);
|
||||
*/
|
||||
P052_data->modbus.setModbusTimeout(P052_MODBUS_TIMEOUT);
|
||||
|
||||
// P052_data->modbus.writeMultipleRegisters(0x09, 1); // Start Single Measurement
|
||||
// P052_data->modbus.writeMultipleRegisters(0x0B, 16); // Measurement Period
|
||||
// P052_data->modbus.writeMultipleRegisters(0x0C, 8); // Number of samples
|
||||
|
||||
success = true;
|
||||
} else {
|
||||
clearPluginTaskData(event->TaskIndex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_EXIT: {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ: {
|
||||
P052_data_struct *P052_data =
|
||||
static_cast<P052_data_struct *>(getPluginTaskData(event->TaskIndex));
|
||||
|
||||
if ((nullptr != P052_data) && P052_data->isInitialized()) {
|
||||
event->sensorType = static_cast<Sensor_VType>(PCONFIG(P052_SENSOR_TYPE_INDEX));
|
||||
String log = F("Senseair: ");
|
||||
String logPrefix;
|
||||
|
||||
for (int varnr = 0; varnr < P052_NR_OUTPUT_VALUES; ++varnr) {
|
||||
uint8_t errorcode = 0;
|
||||
float value = 0;
|
||||
|
||||
switch (PCONFIG(varnr)) {
|
||||
case 1: {
|
||||
value = P052_data->modbus.readInputRegister(P052_IR4_MEASURED_FILTERED_CO2, errorcode);
|
||||
logPrefix = F("co2=");
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
int temperatureX100 = P052_data->modbus.readInputRegister(P052_IR5_TEMPERATURE, errorcode);
|
||||
|
||||
if (errorcode == 2) {
|
||||
// Exception code: Illegal Data Address
|
||||
// SenseAir S8, not for other modules.
|
||||
temperatureX100 = P052_data->modbus.read_RAM_EEPROM(
|
||||
P052_CMD_READ_RAM, P052_RAM_ADDR_DET_TEMPERATURE, 2, errorcode);
|
||||
}
|
||||
|
||||
if (temperatureX100 >= 32768) {
|
||||
// 2-complement value.
|
||||
temperatureX100 -= 65536;
|
||||
}
|
||||
value = static_cast<float>(temperatureX100) / 100.0f;
|
||||
logPrefix = F("temp=");
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
int rhX100 = P052_data->modbus.readInputRegister(P052_IR6_SPACE_HUMIDITY, errorcode);
|
||||
value = static_cast<float>(rhX100) / 100.0f;
|
||||
logPrefix = F("hum=");
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int status = P052_data->modbus.readInputRegister(P052_IR29_FW_REV, errorcode);
|
||||
|
||||
if (errorcode == 0) {
|
||||
int relayStatus = (status >> 8) & 0x1;
|
||||
UserVar.setFloat(event->TaskIndex, varnr, relayStatus);
|
||||
log += F("relay status=");
|
||||
log += relayStatus;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
int temperatureAdjustment = P052_data->modbus.readInputRegister(P052_IR11_MEASURED_CONCENTRATION_UNFILTERED, errorcode);
|
||||
value = static_cast<float>(temperatureAdjustment);
|
||||
logPrefix = F("temp adj=");
|
||||
break;
|
||||
}
|
||||
|
||||
case 7: {
|
||||
const int errorWord = P052_data->modbus.readInputRegister(P052_IR_ERRORSTATUS, errorcode);
|
||||
|
||||
if (errorcode == 0) {
|
||||
value = errorWord;
|
||||
|
||||
for (size_t i = 0; i < 9; i++) {
|
||||
if (bitRead(errorWord, i)) {
|
||||
log += F("err=");
|
||||
log += i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
value = -1;
|
||||
log += F("err=");
|
||||
log += -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
default: {
|
||||
UserVar.setFloat(event->TaskIndex, varnr, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((errorcode == 0) && (P052_data->modbus.getLastError() == 0)) {
|
||||
success = true;
|
||||
UserVar.setFloat(event->TaskIndex, varnr, value);
|
||||
log += logPrefix;
|
||||
log += value;
|
||||
}
|
||||
}
|
||||
addLogMove(LOG_LEVEL_INFO, log);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
P052_data_struct *P052_data =
|
||||
static_cast<P052_data_struct *>(getPluginTaskData(event->TaskIndex));
|
||||
|
||||
if ((nullptr != P052_data) && P052_data->plugin_write(event, string)) {
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif // USES_P052
|
||||
#include "_Plugin_Helper.h"
|
||||
#ifdef USES_P052
|
||||
|
||||
# include "src/PluginStructs/P052_data_struct.h"
|
||||
|
||||
// #######################################################################################################
|
||||
// ############################# Plugin 052: Senseair CO2 Sensors ########################################
|
||||
// #######################################################################################################
|
||||
|
||||
/** Changelog:
|
||||
* 2025-01-03 tonhuisman: Small code size reduction
|
||||
* 2024-12-05 tonhuisman: Add support for MQTT AutoDiscovery for supported values
|
||||
* 2024-12 tonhuisman: Start changelog
|
||||
*/
|
||||
|
||||
/*
|
||||
Plugin originally written by: Daniel Tedenljung
|
||||
info__AT__tedenljungconsulting.com
|
||||
Rewritten by: Mikael Trieb mikael__AT__triebconsulting.se
|
||||
|
||||
This plugin reads available values of Senseair Co2 Sensors.
|
||||
Datasheet can be found here:
|
||||
S8: http://www.senseair.com/products/oem-modules/senseair-s8/
|
||||
K30: http://www.senseair.com/products/oem-modules/k30/
|
||||
K70/tSENSE: http://www.senseair.com/products/wall-mount/tsense/
|
||||
|
||||
Circuit wiring
|
||||
GPIO Setting 1 -> RX
|
||||
GPIO Setting 2 -> TX
|
||||
Use 1kOhm in serie on datapins!
|
||||
*/
|
||||
|
||||
# define PLUGIN_052
|
||||
# define PLUGIN_ID_052 52
|
||||
# define PLUGIN_NAME_052 "Gases - CO2 Senseair"
|
||||
|
||||
|
||||
boolean Plugin_052(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_052;
|
||||
dev.Type = DEVICE_TYPE_SERIAL;
|
||||
dev.VType = Sensor_VType::SENSOR_TYPE_SINGLE;
|
||||
dev.FormulaOption = true;
|
||||
dev.ValueCount = 1;
|
||||
dev.SendDataOption = true;
|
||||
dev.TimerOption = true;
|
||||
dev.OutputDataType = Output_Data_type_t::Simple;
|
||||
dev.ExitTaskBeforeSave = false;
|
||||
dev.PluginStats = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME: {
|
||||
string = F(PLUGIN_NAME_052);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUENAMES: {
|
||||
for (uint8_t i = 0; i < VARS_PER_TASK; ++i) {
|
||||
if (i < P052_NR_OUTPUT_VALUES) {
|
||||
const uint8_t pconfigIndex = i + P052_QUERY1_CONFIG_POS;
|
||||
uint8_t choice = PCONFIG(pconfigIndex);
|
||||
ExtraTaskSettings.setTaskDeviceValueName(i, P052_data_struct::Plugin_052_valuename(choice, false));
|
||||
} else {
|
||||
ExtraTaskSettings.clearTaskDeviceValueName(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
# if FEATURE_MQTT_DISCOVER
|
||||
case PLUGIN_GET_DISCOVERY_VTYPES:
|
||||
{
|
||||
for (uint8_t i = 0; i < P052_NR_OUTPUT_VALUES; ++i) {
|
||||
event->ParN[i] = P052_data_struct::Plugin_052_valueVType(i);
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
# endif // if FEATURE_MQTT_DISCOVER
|
||||
|
||||
case PLUGIN_GET_DEVICEVALUECOUNT:
|
||||
{
|
||||
event->Par1 = P052_NR_OUTPUT_VALUES;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEVTYPE:
|
||||
{
|
||||
event->sensorType = static_cast<Sensor_VType>(PCONFIG(P052_SENSOR_TYPE_INDEX));
|
||||
event->idx = P052_SENSOR_TYPE_INDEX;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICEGPIONAMES: {
|
||||
serialHelper_getGpioNames(event);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SHOW_CONFIG:
|
||||
{
|
||||
string += serialHelper_getSerialTypeLabel(event);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_SET_DEFAULTS:
|
||||
{
|
||||
PCONFIG(P052_SENSOR_TYPE_INDEX) = static_cast<int16_t>(Sensor_VType::SENSOR_TYPE_SINGLE);
|
||||
PCONFIG(0) = 1; // "CO2"
|
||||
|
||||
for (uint8_t i = 1; i < VARS_PER_TASK; ++i) {
|
||||
PCONFIG(i) = 0; // "Empty"
|
||||
}
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD_OUTPUT_SELECTOR:
|
||||
{
|
||||
const __FlashStringHelper *options[P052_NR_OUTPUT_OPTIONS];
|
||||
|
||||
for (uint8_t i = 0; i < P052_NR_OUTPUT_OPTIONS; ++i) {
|
||||
options[i] = P052_data_struct::Plugin_052_valuename(i, true);
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < P052_NR_OUTPUT_VALUES; ++i) {
|
||||
const uint8_t pconfigIndex = i + P052_QUERY1_CONFIG_POS;
|
||||
sensorTypeHelper_loadOutputSelector(event, pconfigIndex, i, P052_NR_OUTPUT_OPTIONS, options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD: {
|
||||
P052_data_struct *P052_data =
|
||||
static_cast<P052_data_struct *>(getPluginTaskData(event->TaskIndex));
|
||||
|
||||
if ((nullptr != P052_data) && P052_data->isInitialized()) {
|
||||
addFormSubHeader(F("Device Information"));
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
if (P052_data->modbus.detected_device_description.length() > 0) {
|
||||
addRowLabel(F("Detected Device"));
|
||||
addHtml(P052_data->modbus.detected_device_description);
|
||||
}
|
||||
|
||||
if (P052_data->readInputRegister(P052_IR29_FW_REV, value)) {
|
||||
addRowLabel(F("FW rev."));
|
||||
addHtmlInt(value);
|
||||
}
|
||||
|
||||
addRowLabel(F("Sensor ID"));
|
||||
addHtml(formatToHex_decimal(P052_data->getSensorID()));
|
||||
|
||||
|
||||
addRowLabel(F("Checksum (pass/fail/nodata)"));
|
||||
{
|
||||
uint32_t reads_pass, reads_crc_failed, reads_nodata;
|
||||
P052_data->modbus.getStatistics(reads_pass, reads_crc_failed, reads_nodata);
|
||||
addHtml(strformat(F("%d/%d/%d"), reads_pass, reads_crc_failed, reads_nodata));
|
||||
}
|
||||
|
||||
bool hasFactorySettings = false;
|
||||
bool enabledABC = false;
|
||||
|
||||
if (P052_data->readHoldingRegister(P052_HR19_METER_CONTROL, value)) {
|
||||
hasFactorySettings = value == 255;
|
||||
enabledABC = bitRead(value, 1) == 0;
|
||||
addRowLabel(F("Using Factory Settings"));
|
||||
addEnabled(hasFactorySettings);
|
||||
|
||||
if (!hasFactorySettings) {
|
||||
// addRowLabel(F("HR19"));
|
||||
// addHtmlInt(value);
|
||||
addRowLabel(F("nRDY"));
|
||||
addEnabled(bitRead(value, 0) == 0);
|
||||
addRowLabel(F("ABC"));
|
||||
addEnabled(enabledABC);
|
||||
addRowLabel(F("Static IIR filter"));
|
||||
addEnabled(bitRead(value, 2) == 0);
|
||||
addRowLabel(F("Dynamic IIR filter"));
|
||||
addEnabled(bitRead(value, 3) == 0);
|
||||
addRowLabel(F("Pressure Compensation"));
|
||||
addEnabled(bitRead(value, 4) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (P052_data->readInputRegister(P052_IR7_MEASUREMENT_COUNT, value)) {
|
||||
addRowLabel(F("Measurement Count"));
|
||||
addHtmlInt(value);
|
||||
}
|
||||
|
||||
if (P052_data->readInputRegister(P052_IR8_MEASUREMENT_CYCLE_TIME, value)) {
|
||||
addRowLabel(F("Measurement Cycle time"));
|
||||
addHtmlInt(value * 2);
|
||||
addUnit('s');
|
||||
}
|
||||
|
||||
if (P052_data->readInputRegister(P052_IR9_MEASURED_UNFILTERED_CO2, value)) {
|
||||
addRowLabel(F("Unfiltered CO2"));
|
||||
addHtmlInt(value);
|
||||
}
|
||||
|
||||
if (P052_data->readHoldingRegister(P052_HR11_MEASUREMENT_MODE, value)) {
|
||||
addRowLabel(F("Measurement Mode"));
|
||||
addHtml(value == 0 ? F("Continuous") : F("Single Measurement"));
|
||||
}
|
||||
|
||||
if (enabledABC) {
|
||||
if (P052_data->readHoldingRegister(P052_HR14_ABC_PERIOD, value)) {
|
||||
addRowLabel(F("ABC Period"));
|
||||
addHtmlInt(value);
|
||||
addUnit('h');
|
||||
}
|
||||
|
||||
if (P052_data->readHoldingRegister(P052_HR5_ABC_TIME, value)) {
|
||||
addRowLabel(F("Time Since ABC"));
|
||||
addHtmlInt(value);
|
||||
addUnit('h');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
/*
|
||||
if (P052_data->readHoldingRegister(P052_HR11_MEASUREMENT_MODE, value)) {
|
||||
// Disable selector for now, since single measurement not yet supported.
|
||||
|
||||
const __FlashStringHelper *options[2] = { F("Continuous"), F("Single Measurement") };
|
||||
addFormSelector(F("Measurement Mode"), F("mode"), 2, options, nullptr, value);
|
||||
}
|
||||
*/
|
||||
|
||||
if (P052_data->readHoldingRegister(P052_HR12_MEASUREMENT_PERIOD, value)) {
|
||||
addFormNumericBox(F("Measurement Period"), F("period"), value, 2, 65534);
|
||||
addUnit('s');
|
||||
}
|
||||
|
||||
if (P052_data->readHoldingRegister(P052_HR13_NR_OF_SAMPLES, value)) {
|
||||
addFormNumericBox(F("Samples per measurement"), F("samp_meas"), value, 1, 1024);
|
||||
}
|
||||
}
|
||||
{
|
||||
// P052_ABC_PERIOD
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// ABC functionality disabled for now, due to a bug in the firmware.
|
||||
// See https://github.com/letscontrolit/ESPEasy/issues/759
|
||||
uint8_t choiceABCperiod = PCONFIG(4);
|
||||
const __FlashStringHelper * optionsABCperiod[9] = { F("disable"), F("1 h"), F("12 h"), F("1
|
||||
day"), F("2 days"), F("4 days"), F("7 days"), F("14 days"), F("30 days") };
|
||||
addFormSelector(F("ABC period"), F("ABC_period"), 9, optionsABCperiod,
|
||||
nullptr, choiceABCperiod);
|
||||
*/
|
||||
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE: {
|
||||
// Save output selector parameters.
|
||||
for (uint8_t i = 0; i < P052_NR_OUTPUT_VALUES; ++i) {
|
||||
const uint8_t pconfigIndex = i + P052_QUERY1_CONFIG_POS;
|
||||
const uint8_t choice = PCONFIG(pconfigIndex);
|
||||
sensorTypeHelper_saveOutputSelector(event, pconfigIndex, i, P052_data_struct::Plugin_052_valuename(choice, false));
|
||||
}
|
||||
|
||||
P052_data_struct *P052_data =
|
||||
static_cast<P052_data_struct *>(getPluginTaskData(event->TaskIndex));
|
||||
|
||||
if ((nullptr != P052_data) && P052_data->isInitialized()) {
|
||||
bool changed = false;
|
||||
uint16_t mode = getFormItemInt(F("mode"), 65535);
|
||||
|
||||
if (((mode == 0) || (mode == 1))) {
|
||||
uint8_t errorcode;
|
||||
int readVal = P052_data->modbus.readHoldingRegister(0x0A, errorcode);
|
||||
|
||||
if ((errorcode == 0) && (readVal != mode)) {
|
||||
P052_data->modbus.writeMultipleRegisters(0x0A, mode);
|
||||
delay(0);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
uint16_t period = getFormItemInt(F("period"), 0);
|
||||
|
||||
if (period > 1) {
|
||||
uint8_t errorcode;
|
||||
int readVal = P052_data->modbus.readHoldingRegister(0x0B, errorcode);
|
||||
|
||||
if ((errorcode == 0) && (readVal != period)) {
|
||||
P052_data->modbus.writeMultipleRegisters(0x0B, period);
|
||||
delay(0);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
uint16_t samp_meas = getFormItemInt(F("samp_meas"), 0);
|
||||
|
||||
if ((samp_meas > 0) && (samp_meas <= 1024)) {
|
||||
uint8_t errorcode;
|
||||
int readVal = P052_data->modbus.readHoldingRegister(0x0C, errorcode);
|
||||
|
||||
if ((errorcode == 0) && (readVal != samp_meas)) {
|
||||
P052_data->modbus.writeMultipleRegisters(0x0C, samp_meas);
|
||||
delay(0);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
// Restart sensor.
|
||||
P052_data->modbus.writeMultipleRegisters(0x11, 0xFF);
|
||||
|
||||
// FIXME TD-er: Must leave the sensor to boot for a while.
|
||||
delay(35);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// ABC functionality disabled for now, due to a bug in the firmware.
|
||||
// See https://github.com/letscontrolit/ESPEasy/issues/759
|
||||
PCONFIG(4) = getFormItemInt(F("ABC_period"));
|
||||
*/
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT: {
|
||||
const int16_t serial_rx = CONFIG_PIN1;
|
||||
const int16_t serial_tx = CONFIG_PIN2;
|
||||
const ESPEasySerialPort port = static_cast<ESPEasySerialPort>(CONFIG_PORT);
|
||||
|
||||
initPluginTaskData(event->TaskIndex, new (std::nothrow) P052_data_struct());
|
||||
P052_data_struct *P052_data =
|
||||
static_cast<P052_data_struct *>(getPluginTaskData(event->TaskIndex));
|
||||
|
||||
if (nullptr == P052_data) {
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
if (P052_data->init(port, serial_rx, serial_tx)) {
|
||||
/*
|
||||
// ABC functionality disabled for now, due to a bug in the firmware.
|
||||
// See https://github.com/letscontrolit/ESPEasy/issues/759
|
||||
const int periodInHours[9] = {0, 1, 12, (24*1), (24*2), (24*4), (24*7),
|
||||
(24*14), (24*30) };
|
||||
uint8_t choiceABCperiod = PCONFIG(1);
|
||||
|
||||
Plugin_052_setABCperiod(periodInHours[choiceABCperiod]);
|
||||
*/
|
||||
P052_data->modbus.setModbusTimeout(P052_MODBUS_TIMEOUT);
|
||||
|
||||
// P052_data->modbus.writeMultipleRegisters(0x09, 1); // Start Single Measurement
|
||||
// P052_data->modbus.writeMultipleRegisters(0x0B, 16); // Measurement Period
|
||||
// P052_data->modbus.writeMultipleRegisters(0x0C, 8); // Number of samples
|
||||
|
||||
success = true;
|
||||
} else {
|
||||
clearPluginTaskData(event->TaskIndex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_EXIT: {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_READ: {
|
||||
P052_data_struct *P052_data =
|
||||
static_cast<P052_data_struct *>(getPluginTaskData(event->TaskIndex));
|
||||
|
||||
if ((nullptr != P052_data) && P052_data->isInitialized()) {
|
||||
event->sensorType = static_cast<Sensor_VType>(PCONFIG(P052_SENSOR_TYPE_INDEX));
|
||||
String log = F("Senseair: ");
|
||||
String logPrefix;
|
||||
|
||||
for (int varnr = 0; varnr < P052_NR_OUTPUT_VALUES; ++varnr) {
|
||||
uint8_t errorcode = 0;
|
||||
float value = 0;
|
||||
|
||||
switch (PCONFIG(varnr)) {
|
||||
case 1: {
|
||||
value = P052_data->modbus.readInputRegister(P052_IR4_MEASURED_FILTERED_CO2, errorcode);
|
||||
logPrefix = F("co2=");
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
int temperatureX100 = P052_data->modbus.readInputRegister(P052_IR5_TEMPERATURE, errorcode);
|
||||
|
||||
if (errorcode == 2) {
|
||||
// Exception code: Illegal Data Address
|
||||
// SenseAir S8, not for other modules.
|
||||
temperatureX100 = P052_data->modbus.read_RAM_EEPROM(
|
||||
P052_CMD_READ_RAM, P052_RAM_ADDR_DET_TEMPERATURE, 2, errorcode);
|
||||
}
|
||||
|
||||
if (temperatureX100 >= 32768) {
|
||||
// 2-complement value.
|
||||
temperatureX100 -= 65536;
|
||||
}
|
||||
value = static_cast<float>(temperatureX100) / 100.0f;
|
||||
logPrefix = F("temp=");
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
int rhX100 = P052_data->modbus.readInputRegister(P052_IR6_SPACE_HUMIDITY, errorcode);
|
||||
value = static_cast<float>(rhX100) / 100.0f;
|
||||
logPrefix = F("hum=");
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int status = P052_data->modbus.readInputRegister(P052_IR29_FW_REV, errorcode);
|
||||
|
||||
if (errorcode == 0) {
|
||||
int relayStatus = (status >> 8) & 0x1;
|
||||
UserVar.setFloat(event->TaskIndex, varnr, relayStatus);
|
||||
log += F("relay status=");
|
||||
log += relayStatus;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
int temperatureAdjustment = P052_data->modbus.readInputRegister(P052_IR11_MEASURED_CONCENTRATION_UNFILTERED, errorcode);
|
||||
value = static_cast<float>(temperatureAdjustment);
|
||||
logPrefix = F("temp adj=");
|
||||
break;
|
||||
}
|
||||
|
||||
case 7: {
|
||||
const int errorWord = P052_data->modbus.readInputRegister(P052_IR_ERRORSTATUS, errorcode);
|
||||
|
||||
if (errorcode == 0) {
|
||||
value = errorWord;
|
||||
|
||||
for (size_t i = 0; i < 9; i++) {
|
||||
if (bitRead(errorWord, i)) {
|
||||
log += F("err=");
|
||||
log += i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
value = -1;
|
||||
log += F("err=");
|
||||
log += -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
default: {
|
||||
UserVar.setFloat(event->TaskIndex, varnr, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((errorcode == 0) && (P052_data->modbus.getLastError() == 0)) {
|
||||
success = true;
|
||||
UserVar.setFloat(event->TaskIndex, varnr, value);
|
||||
log += logPrefix;
|
||||
log += value;
|
||||
}
|
||||
}
|
||||
addLogMove(LOG_LEVEL_INFO, log);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
P052_data_struct *P052_data =
|
||||
static_cast<P052_data_struct *>(getPluginTaskData(event->TaskIndex));
|
||||
|
||||
if ((nullptr != P052_data) && P052_data->plugin_write(event, string)) {
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif // USES_P052
|
||||
|
||||
@@ -48,6 +48,7 @@ void ControllerSettingsStruct::reset() {
|
||||
VariousBits1.deduplicate = 0;
|
||||
VariousBits1.useLocalSystemTime = 0;
|
||||
VariousBits1.TLStype = 0;
|
||||
VariousBits1.mqttAutoDiscovery = 0;
|
||||
|
||||
safe_strncpy(ClientID, F(CONTROLLER_DEFAULT_CLIENTID), sizeof(ClientID));
|
||||
}
|
||||
|
||||
@@ -69,6 +69,18 @@ uint8_t getValueCountFromSensorType(Sensor_VType sensorType)
|
||||
case Sensor_VType::SENSOR_TYPE_UV_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_UV_INDEX_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_IR_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_WEIGHT_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_VOLTAGE_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_CURRENT_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_POWER_USG_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_POWER_FACT_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_APPRNT_POWER_USG_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_TVOC_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_BARO_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_RED_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_GREEN_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_BLUE_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_TEMP_ONLY:
|
||||
return 1;
|
||||
}
|
||||
#ifndef BUILD_NO_DEBUG
|
||||
@@ -112,22 +124,65 @@ const __FlashStringHelper* getSensorTypeLabel(Sensor_VType sensorType) {
|
||||
case Sensor_VType::SENSOR_TYPE_NONE: return F("None");
|
||||
case Sensor_VType::SENSOR_TYPE_NOT_SET: break;
|
||||
|
||||
// FIXME To be ignored?
|
||||
// FIXME To be ignored?
|
||||
#if FEATURE_MQTT_DISCOVER
|
||||
case Sensor_VType::SENSOR_TYPE_ANALOG_ONLY: return F("Analog");
|
||||
case Sensor_VType::SENSOR_TYPE_TEMP_ONLY: return F("Temp");
|
||||
case Sensor_VType::SENSOR_TYPE_HUM_ONLY: return F("Hum");
|
||||
case Sensor_VType::SENSOR_TYPE_LUX_ONLY: return F("Luc");
|
||||
case Sensor_VType::SENSOR_TYPE_LUX_ONLY: return F("Lux");
|
||||
case Sensor_VType::SENSOR_TYPE_DISTANCE_ONLY: return F("Distance");
|
||||
case Sensor_VType::SENSOR_TYPE_DIRECTION_ONLY: return F("Direction");
|
||||
case Sensor_VType::SENSOR_TYPE_DUSTPM2_5_ONLY: return F("Dust PM2.5");
|
||||
case Sensor_VType::SENSOR_TYPE_DUSTPM1_0_ONLY: return F("Dust PM1.0");
|
||||
case Sensor_VType::SENSOR_TYPE_DUSTPM10_ONLY: return F("Dust PM10");
|
||||
case Sensor_VType::SENSOR_TYPE_MOISTURE_ONLY: return F("Moisture");
|
||||
case Sensor_VType::SENSOR_TYPE_CO2_ONLY: return F("CO2");
|
||||
case Sensor_VType::SENSOR_TYPE_CO2_ONLY: return F("(e)CO2");
|
||||
case Sensor_VType::SENSOR_TYPE_GPS_ONLY: return F("GPS");
|
||||
case Sensor_VType::SENSOR_TYPE_UV_ONLY: return F("UV");
|
||||
case Sensor_VType::SENSOR_TYPE_UV_INDEX_ONLY: return F("UV Index");
|
||||
case Sensor_VType::SENSOR_TYPE_IR_ONLY: return F("IR");
|
||||
case Sensor_VType::SENSOR_TYPE_WEIGHT_ONLY: return F("Weight");
|
||||
case Sensor_VType::SENSOR_TYPE_VOLTAGE_ONLY: return F("Voltage");
|
||||
case Sensor_VType::SENSOR_TYPE_CURRENT_ONLY: return F("Current");
|
||||
case Sensor_VType::SENSOR_TYPE_POWER_USG_ONLY: return F("Power Usage");
|
||||
case Sensor_VType::SENSOR_TYPE_POWER_FACT_ONLY: return F("Power Factor");
|
||||
case Sensor_VType::SENSOR_TYPE_APPRNT_POWER_USG_ONLY: return F("Apparent Power Usage");
|
||||
case Sensor_VType::SENSOR_TYPE_TVOC_ONLY: return F("TVOC");
|
||||
case Sensor_VType::SENSOR_TYPE_BARO_ONLY: return F("Baro");
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_RED_ONLY: return F("Red");
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_GREEN_ONLY: return F("Green");
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_BLUE_ONLY: return F("Blue");
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_TEMP_ONLY: return F("Color temperature");
|
||||
#else // if FEATURE_MQTT_DISCOVER
|
||||
case Sensor_VType::SENSOR_TYPE_ANALOG_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_TEMP_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_HUM_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_LUX_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_DISTANCE_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_DIRECTION_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_DUSTPM2_5_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_DUSTPM1_0_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_DUSTPM10_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_MOISTURE_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_CO2_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_GPS_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_UV_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_UV_INDEX_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_IR_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_WEIGHT_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_VOLTAGE_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_CURRENT_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_POWER_USG_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_POWER_FACT_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_APPRNT_POWER_USG_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_TVOC_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_BARO_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_RED_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_GREEN_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_BLUE_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_TEMP_ONLY:
|
||||
break;
|
||||
#endif // if FEATURE_MQTT_DISCOVER
|
||||
}
|
||||
return F("");
|
||||
}
|
||||
|
||||
@@ -49,6 +49,18 @@ enum class Sensor_VType : uint8_t {
|
||||
SENSOR_TYPE_UV_ONLY = 112,
|
||||
SENSOR_TYPE_UV_INDEX_ONLY = 113,
|
||||
SENSOR_TYPE_IR_ONLY = 114,
|
||||
SENSOR_TYPE_WEIGHT_ONLY = 115,
|
||||
SENSOR_TYPE_VOLTAGE_ONLY = 116,
|
||||
SENSOR_TYPE_CURRENT_ONLY = 117,
|
||||
SENSOR_TYPE_POWER_USG_ONLY = 118,
|
||||
SENSOR_TYPE_POWER_FACT_ONLY = 119,
|
||||
SENSOR_TYPE_APPRNT_POWER_USG_ONLY = 120,
|
||||
SENSOR_TYPE_TVOC_ONLY = 121,
|
||||
SENSOR_TYPE_BARO_ONLY = 122,
|
||||
SENSOR_TYPE_COLOR_RED_ONLY = 123,
|
||||
SENSOR_TYPE_COLOR_GREEN_ONLY = 124,
|
||||
SENSOR_TYPE_COLOR_BLUE_ONLY = 125,
|
||||
SENSOR_TYPE_COLOR_TEMP_ONLY = 126,
|
||||
|
||||
SENSOR_TYPE_NOT_SET = 255
|
||||
};
|
||||
|
||||
@@ -332,10 +332,14 @@ bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIn
|
||||
|
||||
// Translate Device[].VType to usable VType per value for MQTT AutoDiscovery
|
||||
if (MQTT_DiscoveryGetDeviceVType(x, discoveryItems, valueCount)) {
|
||||
const String hostName = Settings.getHostname();
|
||||
const unsigned int groupId = Settings.TaskDeviceID[ControllerIndex][x] & 0x3FFF; // Remove opt. flag bits
|
||||
const String hostName = Settings.getHostname();
|
||||
const unsigned int groupId = Settings.TaskDeviceID[ControllerIndex][x] & 0x3FFF; // Remove opt. flag bits
|
||||
const protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(ControllerIndex);
|
||||
const bool usesControllerIDX = validProtocolIndex(ProtocolIndex) &&
|
||||
getProtocolStruct(ProtocolIndex).usesID;
|
||||
|
||||
// dev = device, ids = identifiers
|
||||
const String deviceElement = groupId != 0 ?
|
||||
const String deviceElement = groupId != 0 && !usesControllerIDX ?
|
||||
strformat(F(",\"dev\":{\"name\":\"Group %u\",\"ids\":[\"group_%u\"]}"), groupId, groupId) :
|
||||
strformat(F(",\"dev\":{\"name\":\"%s %s\",\"ids\":[\"%s_%s\"]}"),
|
||||
hostName.c_str(), taskName.c_str(), hostName.c_str(), taskName.c_str());
|
||||
@@ -349,20 +353,17 @@ bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIn
|
||||
case Sensor_VType::SENSOR_TYPE_SWITCH:
|
||||
|
||||
for (uint8_t v = discoveryItems[s].varIndex; v < varCount; ++v) {
|
||||
const String valuename = getTaskValueName(x, v);
|
||||
|
||||
if (!valuename.isEmpty()) {
|
||||
const String uniqueId = MQTT_TaskValueUniqueName(taskName, valuename);
|
||||
const String publish = MQTT_DiscoveryBuildValueTopic(publish_topic, &TempEvent, v, F("binary_sensor"));
|
||||
const String discovery = MQTT_DiscoveryBuildValueTopic(discovery_topic, &TempEvent, v, F("binary_sensor"));
|
||||
discoveryMessage = strformat(F("{\"~\":\"%s\",\"name\":\"%s %s\",\"uniq_id\":\"%s\","
|
||||
"\"dev_cla\":\"switch\",\"cmd_t\":\"~/set\",\"stat_t\":\"~\""
|
||||
"%s}"), // deviceElement last
|
||||
publish.c_str(), taskName.c_str(), valuename.c_str(), uniqueId.c_str(),
|
||||
deviceElement.c_str());
|
||||
|
||||
success &= MQTT_DiscoveryPublish(ControllerIndex, discovery, discoveryMessage, x, v, taskName);
|
||||
}
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("binary_sensor"),
|
||||
F("switch"),
|
||||
EMPTY_STRING, // No unit of measure
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
true, false);
|
||||
}
|
||||
break;
|
||||
case Sensor_VType::SENSOR_TYPE_TEMP_HUM:
|
||||
@@ -371,6 +372,7 @@ bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIn
|
||||
case Sensor_VType::SENSOR_TYPE_TEMP_EMPTY_BARO:
|
||||
case Sensor_VType::SENSOR_TYPE_TEMP_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_HUM_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_BARO_ONLY:
|
||||
{
|
||||
uint8_t v = discoveryItems[s].varIndex;
|
||||
|
||||
@@ -384,20 +386,17 @@ bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIn
|
||||
}
|
||||
|
||||
for (v = fromV; v < maxV; ++v) {
|
||||
const String valuename = getTaskValueName(x, v);
|
||||
|
||||
if (!valuename.isEmpty()) {
|
||||
const String uniqueId = MQTT_TaskValueUniqueName(taskName, valuename);
|
||||
const String publish = MQTT_DiscoveryBuildValueTopic(publish_topic, &TempEvent, v, F("sensor"));
|
||||
const String discovery = MQTT_DiscoveryBuildValueTopic(discovery_topic, &TempEvent, v, F("sensor"));
|
||||
discoveryMessage = strformat(F("{\"~\":\"%s\",\"name\":\"%s %s\",\"uniq_id\":\"%s\","
|
||||
"\"dev_cla\":\"temperature\",\"unit_of_meas\":\"°C\",\"stat_t\":\"~\""
|
||||
"%s}"), // deviceElement last
|
||||
publish.c_str(), taskName.c_str(), valuename.c_str(), uniqueId.c_str(),
|
||||
deviceElement.c_str());
|
||||
|
||||
success &= MQTT_DiscoveryPublish(ControllerIndex, discovery, discoveryMessage, x, v, taskName);
|
||||
}
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
F("temperature"),
|
||||
F("°C"),
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,44 +412,39 @@ bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIn
|
||||
}
|
||||
|
||||
for (v = fromV; v < maxV; ++v) {
|
||||
const String valuename = getTaskValueName(x, v);
|
||||
|
||||
if (!valuename.isEmpty()) {
|
||||
const String uniqueId = MQTT_TaskValueUniqueName(taskName, valuename);
|
||||
const String publish = MQTT_DiscoveryBuildValueTopic(publish_topic, &TempEvent, v, F("sensor"));
|
||||
const String discovery = MQTT_DiscoveryBuildValueTopic(discovery_topic, &TempEvent, v, F("sensor"));
|
||||
discoveryMessage = strformat(F("{\"~\":\"%s\",\"name\":\"%s %s\",\"uniq_id\":\"%s\","
|
||||
"\"dev_cla\":\"humidity\",\"unit_of_meas\":\"%\",\"stat_t\":\"~\""
|
||||
"%s}"), // deviceElement last
|
||||
publish.c_str(), taskName.c_str(), valuename.c_str(), uniqueId.c_str(),
|
||||
deviceElement.c_str());
|
||||
|
||||
success &= MQTT_DiscoveryPublish(ControllerIndex, discovery, discoveryMessage, x, v, taskName);
|
||||
}
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
F("humidity"),
|
||||
F("%"),
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Barometric pressure
|
||||
if ((Sensor_VType::SENSOR_TYPE_TEMP_BARO == discoveryItems[s].VType) ||
|
||||
(Sensor_VType::SENSOR_TYPE_TEMP_HUM_BARO == discoveryItems[s].VType) ||
|
||||
(Sensor_VType::SENSOR_TYPE_TEMP_EMPTY_BARO == discoveryItems[s].VType)) {
|
||||
(Sensor_VType::SENSOR_TYPE_TEMP_EMPTY_BARO == discoveryItems[s].VType) ||
|
||||
(Sensor_VType::SENSOR_TYPE_BARO_ONLY == discoveryItems[s].VType)) {
|
||||
if (Sensor_VType::SENSOR_TYPE_TEMP_EMPTY_BARO == discoveryItems[s].VType) {
|
||||
v++; // Skip 2nd value = 'EMPTY'
|
||||
}
|
||||
const String valuename = getTaskValueName(x, v);
|
||||
|
||||
if (!valuename.isEmpty()) {
|
||||
const String uniqueId = MQTT_TaskValueUniqueName(taskName, valuename);
|
||||
const String publish = MQTT_DiscoveryBuildValueTopic(publish_topic, &TempEvent, v, F("sensor"));
|
||||
const String discovery = MQTT_DiscoveryBuildValueTopic(discovery_topic, &TempEvent, v, F("sensor"));
|
||||
discoveryMessage = strformat(F("{\"~\":\"%s\",\"name\":\"%s %s\",\"uniq_id\":\"%s\","
|
||||
"\"dev_cla\":\"pressure\",\"unit_of_meas\":\"hPa\",\"stat_t\":\"~\""
|
||||
"%s}"), // deviceElement last
|
||||
publish.c_str(), taskName.c_str(), valuename.c_str(), uniqueId.c_str(),
|
||||
deviceElement.c_str());
|
||||
|
||||
success &= MQTT_DiscoveryPublish(ControllerIndex, discovery, discoveryMessage, x, v, taskName);
|
||||
}
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
F("pressure"),
|
||||
F("hPa"),
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, false);
|
||||
v++;
|
||||
}
|
||||
break;
|
||||
@@ -458,53 +452,206 @@ bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIn
|
||||
case Sensor_VType::SENSOR_TYPE_DISTANCE_ONLY:
|
||||
|
||||
for (uint8_t v = discoveryItems[s].varIndex; v < varCount; ++v) {
|
||||
const String valuename = getTaskValueName(x, v);
|
||||
|
||||
if (!valuename.isEmpty()) {
|
||||
const String uniqueId = MQTT_TaskValueUniqueName(taskName, valuename);
|
||||
const String publish = MQTT_DiscoveryBuildValueTopic(publish_topic, &TempEvent, v, F("sensor"));
|
||||
const String discovery = MQTT_DiscoveryBuildValueTopic(discovery_topic, &TempEvent, v, F("sensor"));
|
||||
discoveryMessage = strformat(F("{\"~\":\"%s\",\"name\":\"%s %s\",\"uniq_id\":\"%s\","
|
||||
"\"dev_cla\":\"distance\",\"unit_of_meas\":\"cm\",\"stat_t\":\"~\""
|
||||
"%s}"), // deviceElement last
|
||||
publish.c_str(), taskName.c_str(), valuename.c_str(), uniqueId.c_str(),
|
||||
deviceElement.c_str());
|
||||
|
||||
success &= MQTT_DiscoveryPublish(ControllerIndex, discovery, discoveryMessage, x, v, taskName);
|
||||
}
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
F("distance"),
|
||||
F("cm"),
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case Sensor_VType::SENSOR_TYPE_DUSTPM2_5_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_DUSTPM1_0_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_DUSTPM10_ONLY:
|
||||
{
|
||||
const __FlashStringHelper*dev = (Sensor_VType::SENSOR_TYPE_DUSTPM2_5_ONLY == discoveryItems[s].VType ? F("pm25") :
|
||||
Sensor_VType::SENSOR_TYPE_DUSTPM1_0_ONLY == discoveryItems[s].VType ? F("pm1") :
|
||||
F("pm10"));
|
||||
|
||||
for (uint8_t v = discoveryItems[s].varIndex; v < varCount; ++v) {
|
||||
const String valuename = getTaskValueName(x, v);
|
||||
|
||||
if (!valuename.isEmpty()) {
|
||||
const String pm = (Sensor_VType::SENSOR_TYPE_DUSTPM2_5_ONLY == discoveryItems[2].VType ? F("pm25") :
|
||||
Sensor_VType::SENSOR_TYPE_DUSTPM1_0_ONLY == discoveryItems[2].VType ? F("pm1") :
|
||||
F("pm10"));
|
||||
const String uniqueId = MQTT_TaskValueUniqueName(taskName, valuename);
|
||||
const String publish = MQTT_DiscoveryBuildValueTopic(publish_topic, &TempEvent, v, F("sensor"));
|
||||
const String discovery = MQTT_DiscoveryBuildValueTopic(discovery_topic, &TempEvent, v, F("sensor"));
|
||||
discoveryMessage = strformat(F("{\"~\":\"%s\",\"name\":\"%s %s\",\"uniq_id\":\"%s\","
|
||||
"\"dev_cla\":\"%s\",\"unit_of_meas\":\"µg/m³\",\"stat_t\":\"~\""
|
||||
"%s}"), // deviceElement last
|
||||
publish.c_str(), taskName.c_str(), valuename.c_str(), uniqueId.c_str(),
|
||||
pm.c_str(),
|
||||
deviceElement.c_str());
|
||||
|
||||
success &= MQTT_DiscoveryPublish(ControllerIndex, discovery, discoveryMessage, x, v, taskName);
|
||||
}
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
dev,
|
||||
F("µg/m³"),
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Sensor_VType::SENSOR_TYPE_CO2_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_TVOC_ONLY:
|
||||
{
|
||||
const __FlashStringHelper*dev = Sensor_VType::SENSOR_TYPE_CO2_ONLY == discoveryItems[s].VType ?
|
||||
F("carbon_dioxide") : F("volatile_organic_compounds");
|
||||
const __FlashStringHelper*uom = Sensor_VType::SENSOR_TYPE_CO2_ONLY == discoveryItems[s].VType ?
|
||||
F("ppm") : F("ppd");
|
||||
|
||||
for (uint8_t v = discoveryItems[s].varIndex; v < varCount; ++v) {
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
dev,
|
||||
uom,
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Sensor_VType::SENSOR_TYPE_WEIGHT_ONLY:
|
||||
|
||||
for (uint8_t v = discoveryItems[s].varIndex; v < varCount; ++v) {
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
F("mdi:scale"), // Icon
|
||||
F("kg"),
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, true);
|
||||
}
|
||||
break;
|
||||
case Sensor_VType::SENSOR_TYPE_MOISTURE_ONLY:
|
||||
|
||||
for (uint8_t v = discoveryItems[s].varIndex; v < varCount; ++v) {
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
F("mdi:cup-water"), // Icon
|
||||
F("%"),
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, true);
|
||||
}
|
||||
break;
|
||||
case Sensor_VType::SENSOR_TYPE_VOLTAGE_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_CURRENT_ONLY:
|
||||
{
|
||||
const __FlashStringHelper*dev = Sensor_VType::SENSOR_TYPE_VOLTAGE_ONLY == discoveryItems[s].VType ?
|
||||
F("voltage") : F("current");
|
||||
const __FlashStringHelper*uom = Sensor_VType::SENSOR_TYPE_VOLTAGE_ONLY == discoveryItems[s].VType ?
|
||||
F("V") : F("A");
|
||||
|
||||
for (uint8_t v = discoveryItems[s].varIndex; v < varCount; ++v) {
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
dev,
|
||||
uom,
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Sensor_VType::SENSOR_TYPE_POWER_FACT_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_POWER_USG_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_APPRNT_POWER_USG_ONLY:
|
||||
{
|
||||
const __FlashStringHelper*dev = Sensor_VType::SENSOR_TYPE_POWER_FACT_ONLY == discoveryItems[s].VType ?
|
||||
F("power_factor") : F("power");
|
||||
const __FlashStringHelper*uom = Sensor_VType::SENSOR_TYPE_POWER_FACT_ONLY == discoveryItems[s].VType ? F("Cos φ") :
|
||||
Sensor_VType::SENSOR_TYPE_POWER_USG_ONLY == discoveryItems[s].VType ? F("kWh") :
|
||||
F("VA");
|
||||
|
||||
for (uint8_t v = discoveryItems[s].varIndex; v < varCount; ++v) {
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
dev,
|
||||
uom,
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Sensor_VType::SENSOR_TYPE_LUX_ONLY:
|
||||
|
||||
for (uint8_t v = discoveryItems[s].varIndex; v < varCount; ++v) {
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
F("illuminance"),
|
||||
F("lux"),
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_RED_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_GREEN_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_BLUE_ONLY:
|
||||
{
|
||||
const __FlashStringHelper*uom = Sensor_VType::SENSOR_TYPE_COLOR_RED_ONLY == discoveryItems[s].VType ? F("R") :
|
||||
Sensor_VType::SENSOR_TYPE_COLOR_GREEN_ONLY == discoveryItems[s].VType ? F("G") :
|
||||
F("B");
|
||||
|
||||
for (uint8_t v = discoveryItems[s].varIndex; v < varCount; ++v) {
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
F("mdi:palette"),
|
||||
uom,
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Sensor_VType::SENSOR_TYPE_COLOR_TEMP_ONLY:
|
||||
|
||||
for (uint8_t v = discoveryItems[s].varIndex; v < varCount; ++v) {
|
||||
success &= MQTT_DiscoveryPublishWithStatusAndSet(x, v, taskName,
|
||||
ControllerIndex,
|
||||
publish_topic,
|
||||
discovery_topic,
|
||||
F("sensor"),
|
||||
F("mdi:temperature-kelvin"),
|
||||
F("K"),
|
||||
&TempEvent,
|
||||
deviceElement,
|
||||
success,
|
||||
false, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case Sensor_VType::SENSOR_TYPE_WIND:
|
||||
case Sensor_VType::SENSOR_TYPE_ANALOG_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_LUX_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_DIRECTION_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_MOISTURE_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_CO2_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_GPS_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_UV_ONLY:
|
||||
case Sensor_VType::SENSOR_TYPE_UV_INDEX_ONLY:
|
||||
@@ -591,7 +738,12 @@ bool MQTT_DiscoveryGetDeviceVType(taskIndex_t TaskIndex,
|
||||
case 144: // Vindriktning / PM1006K
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_DUSTPM2_5_ONLY, valueCount, 0));
|
||||
break;
|
||||
case 47: // Soil Moisture
|
||||
case 27: // INA219
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_VOLTAGE_ONLY, 1, 0));
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_CURRENT_ONLY, 1, 1));
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_POWER_USG_ONLY, 1, 2));
|
||||
break;
|
||||
case 47: // Soil Moisture
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_TEMP_ONLY, 1, 0));
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_MOISTURE_ONLY, 1, 1));
|
||||
|
||||
@@ -613,10 +765,18 @@ bool MQTT_DiscoveryGetDeviceVType(taskIndex_t TaskIndex,
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_DUSTPM2_5_ONLY, 1, 0));
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_DUSTPM10_ONLY, 1, 1));
|
||||
break;
|
||||
case 67: // HX711 Load cell
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_WEIGHT_ONLY, valueCount, 0));
|
||||
break;
|
||||
case 74: // TSL2591
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_LUX_ONLY, 3, 0));
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_UV_ONLY, 1, 3));
|
||||
break;
|
||||
case 83: // SGP30 TVOC/eCO2
|
||||
case 90: // CCS811 TVOC/eCO2
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_TVOC_ONLY, 1, 0));
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_CO2_ONLY, 1, 1));
|
||||
break;
|
||||
case 84: // VEML6070 (UV and Index only)
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_UV_ONLY, 1, 0));
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_UV_INDEX_ONLY, 1, 1));
|
||||
@@ -657,6 +817,10 @@ bool MQTT_DiscoveryGetDeviceVType(taskIndex_t TaskIndex,
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_CO2_ONLY, 1, 0));
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_TEMP_HUM, 1, 1));
|
||||
break;
|
||||
case 151: // Honeywell pressure
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_BARO_ONLY, 1, 0));
|
||||
discoveryItems.push_back(DiscoveryItem(Sensor_VType::SENSOR_TYPE_TEMP_ONLY, 1, 1));
|
||||
break;
|
||||
|
||||
// Deliberately ignored/skipped for now:
|
||||
case 3: // Pulse: Needs special handling/not usable?
|
||||
@@ -669,47 +833,45 @@ bool MQTT_DiscoveryGetDeviceVType(taskIndex_t TaskIndex,
|
||||
VType = Sensor_VType::SENSOR_TYPE_NONE;
|
||||
break;
|
||||
|
||||
// To be reviewed/considered later:
|
||||
// To be reviewed/considered later/custom/special handled:
|
||||
case 8: // RFID Wiegand
|
||||
case 17: // RFID PN532
|
||||
case 27: // INA219
|
||||
case 40: // RFID ID12
|
||||
case 45: // MPU6050
|
||||
case 50: // TCS34725 RGB: Needs special handling
|
||||
case 52: // SensAir: Needs special handling
|
||||
case 64: // APDS9960: Needs special handling
|
||||
case 66: // VEML6040 RGB: Needs special handling
|
||||
case 67: // HX711 Load cell
|
||||
case 71: // Kamstrup Heat
|
||||
case 76: // HLW8012
|
||||
case 77: // CSE7766
|
||||
case 76: // HLW8012: Needs special handling
|
||||
case 77: // CSE7766: Needs special handling
|
||||
case 78: // Eastron: Needs special handling
|
||||
case 82: // GPS: Needs special handling
|
||||
case 83: // SGP30 TVOC/eCO2
|
||||
case 85: // AcuDC243
|
||||
case 90: // CCS811 TVOC/eCO2
|
||||
case 92: // DL-bus
|
||||
case 85: // AcuDC243: Needs special handling
|
||||
case 92: // DL-bus: Needs special handling
|
||||
case 93: // Mitsubishi Heatpump
|
||||
case 102: // PZEM004
|
||||
case 103: // Atlas EZO
|
||||
case 108: // DDS238
|
||||
case 102: // PZEM004: Needs special handling
|
||||
case 103: // Atlas EZO: Needs special handling
|
||||
case 108: // DDS238: Needs special handling
|
||||
case 111: // RFID RC522
|
||||
case 112: // AS7265x: Needs special handling
|
||||
case 115: // MAX1704x
|
||||
case 117: // SCD30 CO2: Needs special handling
|
||||
case 132: // INA3221
|
||||
case 132: // INA3221: Needs special handling
|
||||
case 142: // AS5600 Angle/rotation
|
||||
case 145: // MQxxx gases
|
||||
case 147: // SGP4x
|
||||
case 151: // Honeywell pressure
|
||||
case 159: // LD2410
|
||||
case 163: // RadSens
|
||||
case 164: // ENS160
|
||||
case 164: // ENS160: Needs special handling
|
||||
case 167: // Vindstyrka: Needs special handling
|
||||
case 169: // AS3935 Lightning
|
||||
case 176: // Victron VE.Direct: Needs user-configurable Sensor_VType + Unit_of_measure per value
|
||||
// Reset
|
||||
VType = Sensor_VType::SENSOR_TYPE_NONE;
|
||||
break;
|
||||
|
||||
// Plugin ID numbers not listed in the above switch statement most likely have the correct Sensor_VType value set in DeviceStruct
|
||||
}
|
||||
|
||||
// Use Device VType setting if not overridden or reset
|
||||
@@ -792,20 +954,20 @@ String MQTT_DiscoveryBuildValueTopic(const String & topic,
|
||||
|
||||
bool MQTT_DiscoveryPublish(controllerIndex_t ControllerIndex,
|
||||
const String & topic,
|
||||
String & discoveryMessage,
|
||||
const String & discoveryMessage,
|
||||
taskIndex_t x,
|
||||
uint8_t v,
|
||||
const String & taskName) {
|
||||
bool result = false;
|
||||
|
||||
// TODO Send each discovery message separate
|
||||
// result = MQTTpublish(ControllerIndex, INVALID_TASK_INDEX, concat(topic, F("/config")).c_str(), discoveryMessage.c_str(), false);
|
||||
// Send each discovery message separate
|
||||
result = MQTTpublish(ControllerIndex, INVALID_TASK_INDEX, concat(topic, F("/config")).c_str(), discoveryMessage.c_str(), false);
|
||||
# ifndef BUILD_NO_DEBUG
|
||||
|
||||
// FIXME change this log to DEBUG level
|
||||
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
|
||||
addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery Task %d '%s': disc.topic: %s"),
|
||||
x + 1, taskName.c_str(), concat(topic, F("/config")).c_str()));
|
||||
addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery %d Task %d '%s': disc.topic: %s"),
|
||||
result, x + 1, taskName.c_str(), concat(topic, F("/config")).c_str()));
|
||||
addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery payload: %s"),
|
||||
discoveryMessage.c_str()));
|
||||
}
|
||||
@@ -813,6 +975,43 @@ bool MQTT_DiscoveryPublish(controllerIndex_t ControllerIndex,
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MQTT_DiscoveryPublishWithStatusAndSet(taskIndex_t taskIndex,
|
||||
uint8_t taskValue,
|
||||
String taskName,
|
||||
controllerIndex_t ControllerIndex,
|
||||
String publishTopic,
|
||||
String discoveryTopic,
|
||||
const __FlashStringHelper*componentClass,
|
||||
String deviceClass,
|
||||
String unitOfMeasure,
|
||||
struct EventStruct *event,
|
||||
const String deviceElement,
|
||||
bool success,
|
||||
bool hasSet,
|
||||
bool hasIcon) {
|
||||
const String withSet = hasSet ? F(",\"cmd_t\":\"~/set\"") : EMPTY_STRING;
|
||||
const String devOrIcon = hasIcon ? F("ic") : F("dev_cla");
|
||||
const String withUoM = !unitOfMeasure.isEmpty() ?
|
||||
strformat(F(",\"unit_of_meas\":\"%s\""), unitOfMeasure.c_str()) :
|
||||
EMPTY_STRING;
|
||||
const String valuename = getTaskValueName(taskIndex, taskValue);
|
||||
|
||||
if (!valuename.isEmpty()) {
|
||||
const String uniqueId = MQTT_TaskValueUniqueName(taskName, valuename);
|
||||
const String publish = MQTT_DiscoveryBuildValueTopic(publishTopic, event, taskValue, componentClass);
|
||||
const String discovery = MQTT_DiscoveryBuildValueTopic(discoveryTopic, event, taskValue, componentClass);
|
||||
const String discoveryMessage = strformat(F("{\"~\":\"%s\",\"name\":\"%s %s\",\"uniq_id\":\"%s\",\"schema\":\"basic\","
|
||||
"\"%s\":\"%s\"%s%s,\"stat_t\":\"~\""
|
||||
"%s}"), // deviceElement last
|
||||
publish.c_str(), taskName.c_str(), valuename.c_str(), uniqueId.c_str(),
|
||||
devOrIcon.c_str(), deviceClass.c_str(), withUoM.c_str(), withSet.c_str(),
|
||||
deviceElement.c_str());
|
||||
|
||||
return MQTT_DiscoveryPublish(ControllerIndex, discovery, discoveryMessage, taskIndex, taskValue, taskName);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
# endif // if FEATURE_MQTT_DISCOVER
|
||||
|
||||
#endif // if FEATURE_MQTT
|
||||
|
||||
@@ -38,12 +38,28 @@ String MQTT_DiscoveryBuildValueTopic(const String & topic,
|
||||
struct EventStruct *event,
|
||||
uint8_t taskValueIndex,
|
||||
const __FlashStringHelper*deviceClass);
|
||||
|
||||
bool MQTT_DiscoveryPublish(controllerIndex_t ControllerIndex,
|
||||
const String & topic,
|
||||
String & discoveryMessage,
|
||||
const String & discoveryMessage,
|
||||
taskIndex_t x,
|
||||
uint8_t v,
|
||||
const String & taskName);
|
||||
|
||||
bool MQTT_DiscoveryPublishWithStatusAndSet(taskIndex_t taskIndex,
|
||||
uint8_t taskValue,
|
||||
String taskName,
|
||||
controllerIndex_t ControllerIndex,
|
||||
String publishTopic,
|
||||
String discoveryTopic,
|
||||
const __FlashStringHelper*componentClass,
|
||||
String deviceClass,
|
||||
String unitOfMeasure,
|
||||
struct EventStruct *event,
|
||||
const String deviceElement,
|
||||
bool success,
|
||||
bool hasSet,
|
||||
bool hasIcon);
|
||||
# endif // if FEATURE_MQTT_DISCOVER
|
||||
#endif // if FEATURE_MQTT
|
||||
#endif // ifndef CPLUGIN_HELPER_MQTT_H
|
||||
|
||||
+1621
-1620
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user