mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-01-26 16:49:11 +03:00
updates to add_ha_classes
This commit is contained in:
@@ -809,9 +809,9 @@ void AnalogSensor::publish_values(const bool force) {
|
||||
std::string topic_str(topic);
|
||||
config["def_ent_id"] = topic_str.substr(0, topic_str.find("/")) + "." + uniq_s;
|
||||
|
||||
// add HA Discovery config
|
||||
Mqtt::add_ha_classes(config.as<JsonObject>(), EMSdevice::DeviceType::ANALOGSENSOR, valueType, sensor.uom());
|
||||
// dev section with model is only created on the 1st sensor
|
||||
Mqtt::add_ha_dev_section(config.as<JsonObject>(), "Analog Sensors", !ha_dev_created);
|
||||
Mqtt::add_ha_dev_section(config.as<JsonObject>(), "Analog Sensors", !ha_dev_created); // dev section with model is only created on the 1st sensor
|
||||
Mqtt::add_ha_avty_section(config.as<JsonObject>(), stat_t, val_cond);
|
||||
|
||||
sensor.ha_registered = Mqtt::queue_ha(topic, config.as<JsonObject>());
|
||||
|
||||
@@ -1687,7 +1687,7 @@ void EMSdevice::get_value_json(JsonObject json, DeviceValue & dv) {
|
||||
}
|
||||
|
||||
// add uom, state class and device class
|
||||
Mqtt::add_ha_classes(json, device_type(), dv.type, dv.uom, dv.short_name, false); // no icon
|
||||
Mqtt::add_ha_classes(json, device_type(), dv.type, dv.uom, dv.short_name, true); // display only
|
||||
|
||||
json["readable"] = dv.type != DeviceValueType::CMD && !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE);
|
||||
json["writeable"] = dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY);
|
||||
|
||||
@@ -47,36 +47,37 @@ class DeviceValue {
|
||||
|
||||
// Unit Of Measurement mapping - maps to DeviceValueUOM_s in emsdevicevalue.cpp. Sequence is important!!
|
||||
// also used with HA as uom
|
||||
// shows also the HA device class being used
|
||||
enum DeviceValueUOM : uint8_t {
|
||||
NONE = 0, // 0
|
||||
DEGREES, // 1 - °C
|
||||
DEGREES_R, // 2 - °C (relative temperature)
|
||||
PERCENT, // 3 - %
|
||||
LMIN, // 4 - l/min
|
||||
KWH, // 5 - kWh
|
||||
WH, // 6 - Wh
|
||||
HOURS, // 7 - h
|
||||
MINUTES, // 8 - m
|
||||
UA, // 9 - µA
|
||||
BAR, // 10 - bar
|
||||
KW, // 11 - kW
|
||||
W, // 12 - W
|
||||
KB, // 13 - kB
|
||||
SECONDS, // 14 - s
|
||||
DBM, // 15 - dBm
|
||||
FAHRENHEIT, // 16 - °F
|
||||
MV, // 17 - mV
|
||||
SQM, // 18 - m²
|
||||
M3, // 19 - m³
|
||||
L, // 20 - L
|
||||
DEGREES, // 1 - °C - temperature
|
||||
DEGREES_R, // 2 - °C (relative temperature) - temperature
|
||||
PERCENT, // 3 - % - power factor
|
||||
LMIN, // 4 - l/min - volume flow rate
|
||||
KWH, // 5 - kWh - energy
|
||||
WH, // 6 - Wh - energy
|
||||
HOURS, // 7 - h - duration
|
||||
MINUTES, // 8 - m - duration
|
||||
UA, // 9 - µA - current
|
||||
BAR, // 10 - bar - pressure
|
||||
KW, // 11 - kW - power
|
||||
W, // 12 - W - power
|
||||
KB, // 13 - kB - data size
|
||||
SECONDS, // 14 - s - duration
|
||||
DBM, // 15 - dBm - signal strength
|
||||
FAHRENHEIT, // 16 - °F - temperature
|
||||
MV, // 17 - mV - voltage
|
||||
SQM, // 18 - m² - area
|
||||
M3, // 19 - m³ - volume
|
||||
L, // 20 - L - volume
|
||||
KMIN, // 21 - K*min
|
||||
K, // 22 - K
|
||||
VOLTS, // 23 - V
|
||||
MBAR, // 24 - mbar
|
||||
LH, // 25 - l/h
|
||||
CTKWH, // 26 - ct/kWh
|
||||
HZ, // 27 - Hz
|
||||
CONNECTIVITY // 28 - used in HA
|
||||
K, // 22 - K - temperature
|
||||
VOLTS, // 23 - V - voltage
|
||||
MBAR, // 24 - mbar - atmospheric pressure
|
||||
LH, // 25 - l/h - volume flow rate
|
||||
CTKWH, // 26 - ct/kWh - monetary
|
||||
HZ, // 27 - Hz - frequency
|
||||
CONNECTIVITY // 28 - used in HA - connectivity
|
||||
};
|
||||
|
||||
// TAG mapping - maps to DeviceValueTAG_s in emsdevicevalue.cpp
|
||||
|
||||
@@ -62,8 +62,6 @@ std::string Mqtt::lastresponse_ = "";
|
||||
|
||||
// Home Assistant specific
|
||||
// icons from https://materialdesignicons.com used with the UOMs (unit of measurements)
|
||||
MAKE_WORD(measurement)
|
||||
MAKE_WORD(total_increasing)
|
||||
// MAKE_WORD_CUSTOM(icondegrees, "mdi:coolant-temperature") // DeviceValueUOM::DEGREES
|
||||
MAKE_WORD_CUSTOM(iconpercent, "mdi:percent-outline") // DeviceValueUOM::PERCENT
|
||||
MAKE_WORD_CUSTOM(iconkb, "mdi:memory") // DeviceValueUOM::KB
|
||||
@@ -1124,18 +1122,29 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
|
||||
return queue_ha(topic, doc.as<JsonObject>());
|
||||
}
|
||||
|
||||
// Add the uom, state class, device class and an optional icon based on the uom
|
||||
void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8_t type, const uint8_t uom, const char * entity, bool is_discovery) {
|
||||
// Add the uom, state class, device class and an optional icon based on the uom (unless display_only is true)
|
||||
// https://developers.home-assistant.io/docs/core/entity/sensor/
|
||||
// Home Assistant tracks the min, max and mean value during the statistics period
|
||||
// For statistics, the sensor must have state_class set to either MEASUREMENT, TOTAL or TOTAL_INCREASING
|
||||
// When set to MEASUREMENT the device_class must cannot be DATE, ENUM, ENERGY, GAS, MONETARY, TIMESTAMP, VOLUME or WATER
|
||||
//
|
||||
void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8_t type, const uint8_t uom, const char * entity, bool display_only) {
|
||||
if (device_type == EMSdevice::DeviceType::SYSTEM) {
|
||||
doc["ent_cat"] = "diagnostic"; // instead of 'config'
|
||||
}
|
||||
|
||||
// for HA discovery we use different namings
|
||||
const char * dc_ha = is_discovery ? "dev_cla" : "device_class"; // device class
|
||||
const char * sc_ha = is_discovery ? "stat_cla" : "state_class"; // state class
|
||||
const char * uom_ha = is_discovery ? "unit_of_meas" : "uom"; // unit of measure
|
||||
// For display_only, we don't use the aliases, also we don't display the icon
|
||||
const char * dc_ha = display_only ? "device_class" : "dev_cla"; // device class, dev_cla
|
||||
const char * sc_ha = display_only ? "state_class" : "stat_cla"; // state class, stat_cla
|
||||
const char * uom_ha = display_only ? "uom" : "unit_of_meas"; // unit of measure, unit_of_meas
|
||||
const char * ic_ha = display_only ? "icon" : "ic"; // icon, ic
|
||||
|
||||
// set uom, unless boolean
|
||||
// state class constants
|
||||
const char * sc_ha_measurement = "measurement";
|
||||
const char * sc_ha_total = "total";
|
||||
const char * sc_ha_total_increasing = "total_increasing";
|
||||
|
||||
// set uom, unless boolean - as HA is fussy with the naming
|
||||
// using HA uom specific codes from https://github.com/home-assistant/core/blob/dev/homeassistant/const.py
|
||||
if (type != DeviceValueType::BOOL) {
|
||||
if (uom == DeviceValueUOM::HOURS) {
|
||||
@@ -1144,6 +1153,8 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8
|
||||
doc[uom_ha] = "min";
|
||||
} else if (uom == DeviceValueUOM::SECONDS) {
|
||||
doc[uom_ha] = "s";
|
||||
} else if (uom == DeviceValueUOM::KB) {
|
||||
doc[uom_ha] = "kB";
|
||||
} else if (uom != DeviceValueUOM::NONE) {
|
||||
doc[uom_ha] = EMSdevice::uom_to_string(uom); // use default
|
||||
} else if (discovery_type() != discoveryType::HOMEASSISTANT) {
|
||||
@@ -1151,99 +1162,136 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8
|
||||
}
|
||||
}
|
||||
|
||||
// set state and device class
|
||||
// also icon, when there is no device class that sets one
|
||||
// set state and device class - always
|
||||
// see https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes
|
||||
switch (uom) {
|
||||
case DeviceValueUOM::DEGREES:
|
||||
case DeviceValueUOM::DEGREES_R:
|
||||
case DeviceValueUOM::K:
|
||||
doc[sc_ha] = F_(measurement);
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "temperature";
|
||||
// override uom if fahrenheit
|
||||
doc[uom_ha] = EMSESP::system_.fahrenheit() ? DeviceValue::DeviceValueUOM_s[DeviceValueUOM::FAHRENHEIT] : DeviceValue::DeviceValueUOM_s[uom];
|
||||
break;
|
||||
case DeviceValueUOM::PERCENT:
|
||||
doc[sc_ha] = F_(measurement);
|
||||
if (display_only) {
|
||||
doc[ic_ha] = F_(iconpercent); // set icon
|
||||
}
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "power_factor";
|
||||
if (is_discovery)
|
||||
doc["ic"] = F_(iconpercent); // icon
|
||||
break;
|
||||
case DeviceValueUOM::SECONDS:
|
||||
case DeviceValueUOM::MINUTES:
|
||||
case DeviceValueUOM::HOURS:
|
||||
if (type == DeviceValueType::TIME) {
|
||||
doc[sc_ha] = F_(total_increasing);
|
||||
doc[sc_ha] = sc_ha_total_increasing;
|
||||
} else {
|
||||
doc[sc_ha] = F_(measurement);
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
}
|
||||
doc[dc_ha] = "duration"; // https://github.com/emsesp/EMS-ESP32/issues/822
|
||||
break;
|
||||
case DeviceValueUOM::KB:
|
||||
if (is_discovery)
|
||||
doc["ic"] = F_(iconkb);
|
||||
if (display_only) {
|
||||
doc[ic_ha] = F_(iconkb);
|
||||
}
|
||||
doc[dc_ha] = "data_size";
|
||||
break;
|
||||
case DeviceValueUOM::LMIN:
|
||||
case DeviceValueUOM::LH:
|
||||
if (is_discovery)
|
||||
doc["ic"] = F_(iconlmin);
|
||||
doc[sc_ha] = F_(measurement);
|
||||
if (display_only) {
|
||||
doc[ic_ha] = F_(iconlmin);
|
||||
}
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "volume_flow_rate";
|
||||
break;
|
||||
case DeviceValueUOM::WH:
|
||||
// https://github.com/emsesp/EMS-ESP32/issues/1796
|
||||
if (entity == FL_(energyToday)[0]) {
|
||||
doc[sc_ha] = F_(total_increasing);
|
||||
doc[sc_ha] = sc_ha_total_increasing;
|
||||
doc[dc_ha] = "energy";
|
||||
} else if (entity == FL_(energyLastHour)[0]) {
|
||||
doc[sc_ha] = "total";
|
||||
doc[sc_ha] = sc_ha_total;
|
||||
doc[dc_ha] = "energy";
|
||||
} else {
|
||||
doc[sc_ha] = F_(measurement);
|
||||
doc[sc_ha] = sc_ha_measurement; // no device class for this
|
||||
}
|
||||
doc[dc_ha] = "energy";
|
||||
break;
|
||||
case DeviceValueUOM::KWH:
|
||||
doc[sc_ha] = F_(total_increasing);
|
||||
doc[sc_ha] = sc_ha_total_increasing;
|
||||
doc[dc_ha] = "energy";
|
||||
break;
|
||||
case DeviceValueUOM::UA:
|
||||
if (is_discovery)
|
||||
doc["ic"] = F_(iconua);
|
||||
doc[sc_ha] = F_(measurement);
|
||||
if (display_only) {
|
||||
doc[ic_ha] = F_(iconua);
|
||||
}
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "current";
|
||||
break;
|
||||
case DeviceValueUOM::BAR:
|
||||
doc[sc_ha] = F_(measurement);
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "pressure";
|
||||
break;
|
||||
case DeviceValueUOM::W:
|
||||
case DeviceValueUOM::KW:
|
||||
doc[sc_ha] = F_(measurement);
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "power";
|
||||
break;
|
||||
case DeviceValueUOM::DBM:
|
||||
doc[sc_ha] = F_(measurement);
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "signal_strength";
|
||||
break;
|
||||
case DeviceValueUOM::CONNECTIVITY:
|
||||
doc[sc_ha] = F_(measurement);
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "connectivity";
|
||||
break;
|
||||
case DeviceValueUOM::NONE:
|
||||
case DeviceValueUOM::MV:
|
||||
case DeviceValueUOM::VOLTS:
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "voltage";
|
||||
break;
|
||||
case DeviceValueUOM::MBAR:
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "atmospheric_pressure";
|
||||
break;
|
||||
case DeviceValueUOM::CTKWH:
|
||||
doc[sc_ha] = sc_ha_total_increasing;
|
||||
doc[dc_ha] = "monetary";
|
||||
break;
|
||||
case DeviceValueUOM::HZ:
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "frequency";
|
||||
break;
|
||||
case DeviceValueUOM::M3:
|
||||
case DeviceValueUOM::L:
|
||||
// this could be Gas or Water, so going with the generic 'volume' for now
|
||||
// state_class can't be a Measurement
|
||||
doc[sc_ha] = sc_ha_total_increasing;
|
||||
doc[dc_ha] = "volume";
|
||||
break;
|
||||
case DeviceValueUOM::SQM:
|
||||
doc[sc_ha] = sc_ha_measurement;
|
||||
doc[dc_ha] = "area";
|
||||
break;
|
||||
default:
|
||||
// DeviceValueUOM::NONE:
|
||||
// DeviceValueUOM::KMIN:
|
||||
// for device entities which have numerical values, with no UOM
|
||||
if ((type != DeviceValueType::STRING)
|
||||
&& (type == DeviceValueType::INT8 || type == DeviceValueType::UINT8 || type == DeviceValueType::INT16 || type == DeviceValueType::UINT16
|
||||
|| type == DeviceValueType::UINT24 || type == DeviceValueType::UINT32)) {
|
||||
if (is_discovery)
|
||||
doc["ic"] = F_(iconnum); // set icon
|
||||
if (display_only) {
|
||||
doc[ic_ha] = F_(iconnum); // set icon
|
||||
}
|
||||
// determine if its a measurement or total increasing
|
||||
// most of the values are measurement. for example Tx Reads will increment but can be reset to 0 after a restart
|
||||
// all the starts are increasing, and they are ULONGs
|
||||
if (type == DeviceValueType::UINT24 || type == DeviceValueType::UINT32) {
|
||||
doc[sc_ha] = F_(total_increasing);
|
||||
doc[sc_ha] = sc_ha_total_increasing;
|
||||
} else {
|
||||
doc[sc_ha] = F_(measurement); // default to measurement
|
||||
doc[sc_ha] = sc_ha_measurement; // default to measurement
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1444,9 +1492,8 @@ std::string Mqtt::tag_to_topic(uint8_t device_type, int8_t tag) {
|
||||
}
|
||||
}
|
||||
|
||||
// add devs section to an existing doc, only for HA
|
||||
// under devs node it will create ids and name and optional mf, mdl, via_device
|
||||
// name could be EMSdevice::device_type_2_device_name(dv.device_type));
|
||||
// adds dev section for HA Discovery to an existing JSON doc
|
||||
// under devs node it will create ids and optional name, mf, mdl, sw and via_device
|
||||
void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const bool create_model, const char * model, const char * brand, const char * version) {
|
||||
// only works for HA
|
||||
if (discovery_type() != discoveryType::HOMEASSISTANT) {
|
||||
@@ -1488,6 +1535,7 @@ void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const bool crea
|
||||
}
|
||||
|
||||
// adds avty section for HA Discovery to an existing JSON doc
|
||||
// also adds LWT (Last Will and Testament)
|
||||
void Mqtt::add_ha_avty_section(JsonObject doc, const char * state_t, const char * cond1, const char * cond2, const char * negcond) {
|
||||
// only works for HA
|
||||
if (discovery_type() != discoveryType::HOMEASSISTANT) {
|
||||
|
||||
@@ -258,7 +258,7 @@ class Mqtt {
|
||||
static std::string tag_to_topic(uint8_t device_type, int8_t tag);
|
||||
|
||||
static void
|
||||
add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8_t type, const uint8_t uom, const char * entity = nullptr, bool is_discovery = true);
|
||||
add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8_t type, const uint8_t uom, const char * entity = nullptr, bool display_only = false);
|
||||
static void add_ha_dev_section(JsonObject doc,
|
||||
const char * name = nullptr,
|
||||
const bool create_model = false,
|
||||
|
||||
Reference in New Issue
Block a user