diff --git a/interface/src/project/DashboardData.tsx b/interface/src/project/DashboardData.tsx index 0ba5600c5..32edb00ad 100644 --- a/interface/src/project/DashboardData.tsx +++ b/interface/src/project/DashboardData.tsx @@ -51,7 +51,7 @@ import { formatDurationMin, pluralize } from '../utils'; import { AuthenticatedContext } from '../contexts/authentication'; -import { ButtonRow, FormLoader, ValidatedTextField, SectionContent, MessageBox } from '../components'; +import { ButtonRow, ValidatedTextField, SectionContent, MessageBox } from '../components'; import * as EMSESP from './api'; @@ -77,7 +77,6 @@ const DashboardData: FC = () => { const { enqueueSnackbar } = useSnackbar(); - const [errorMessage, setErrorMessage] = useState(); const [coreData, setCoreData] = useState({ devices: [], active_sensors: 0, analog_enabled: false }); const [deviceData, setDeviceData] = useState({ label: '', data: [] }); const [sensorData, setSensorData] = useState({ sensors: [], analogs: [] }); @@ -286,6 +285,11 @@ const DashboardData: FC = () => { } ); + const paul = () => { + console.log('paul'); + sensor_sort.fns.onToggleSort({ sortKey: 'NAME' }); + }; + const device_select = useRowSelect( { nodes: coreData.devices }, { @@ -338,7 +342,8 @@ const DashboardData: FC = () => { const handleDownloadCsv = () => { const columns = [ { accessor: (dv: any) => dv.id.slice(2), name: 'Entity' }, - { accessor: (dv: any) => formatValue(dv.v, dv.u), name: 'Value' } + { accessor: (dv: any) => dv.v, name: 'Value' }, + { accessor: (dv: any) => (dv.u >= 1 && dv.u <= 2 ? 'C' : DeviceValueUOM_s[dv.u]), name: 'UoM' } ]; downloadAsCsv( columns, @@ -366,9 +371,9 @@ const DashboardData: FC = () => { try { setCoreData((await EMSESP.readCoreData()).data); } catch (error: any) { - setErrorMessage(extractErrorMessage(error, 'Failed to fetch core data')); + enqueueSnackbar(extractErrorMessage(error, 'Failed to fetch core data'), { variant: 'error' }); } - }, []); + }, [enqueueSnackbar]); useEffect(() => { fetchCoreData(); @@ -387,7 +392,7 @@ const DashboardData: FC = () => { try { setDeviceData((await EMSESP.readDeviceData({ id: unique_id })).data); } catch (error: any) { - setErrorMessage(extractErrorMessage(error, 'Problem fetching device data')); + enqueueSnackbar(extractErrorMessage(error, 'Problem fetching device data'), { variant: 'error' }); } }; @@ -395,7 +400,7 @@ const DashboardData: FC = () => { try { setSensorData((await EMSESP.readSensorData()).data); } catch (error: any) { - setErrorMessage(extractErrorMessage(error, 'Problem fetching sensor data')); + enqueueSnackbar(extractErrorMessage(error, 'Problem fetching sensor data'), { variant: 'error' }); } }; @@ -448,7 +453,7 @@ const DashboardData: FC = () => { } setDeviceValue(undefined); } catch (error: any) { - setErrorMessage(extractErrorMessage(error, 'Problem writing value')); + enqueueSnackbar(extractErrorMessage(error, 'Problem writing value'), { variant: 'error' }); } finally { refreshData(); setDeviceValue(undefined); @@ -519,7 +524,7 @@ const DashboardData: FC = () => { }; const addAnalogSensor = () => { - setAnalog({ id: '0', i: 0, n: '', u: 0, v: 0, o: 0, t: 0, f: 1 }); + setAnalog({ id: '0', g: 0, n: '', u: 0, v: 0, o: 0, t: 0, f: 1 }); }; const sendSensor = async () => { @@ -539,7 +544,7 @@ const DashboardData: FC = () => { } setSensor(undefined); } catch (error: any) { - setErrorMessage(extractErrorMessage(error, 'Problem updating sensor')); + enqueueSnackbar(extractErrorMessage(error, 'Problem updating sensor'), { variant: 'error' }); } finally { setSensor(undefined); fetchSensorData(); @@ -648,65 +653,59 @@ const DashboardData: FC = () => { } }; - const renderCoreData = () => { - if (!coreData) { - return ; - } + const renderCoreData = () => ( + + {coreData.devices.length === 0 && } - return ( - - {coreData.devices.length === 0 && } - - - {(tableList: any) => ( - <> -
- - - TYPE - DESCRIPTION - ENTITIES - - -
- - {tableList.map((device: Device, index: number) => ( - - - - - {device.t} - {device.n} - {device.e} - - setDeviceDialog(index)}> - - - - - ))} - {(coreData.active_sensors > 0 || coreData.analog_enabled) && ( - - - - - Sensors - Attached EMS-ESP Sensors - {coreData.active_sensors} - - addAnalogSensor()}> - - - - - )} - - - )} -
-
- ); - }; + + {(tableList: any) => ( + <> +
+ + + TYPE + DESCRIPTION + ENTITIES + + +
+ + {tableList.map((device: Device, index: number) => ( + + + + + {device.t} + {device.n} + {device.e} + + setDeviceDialog(index)}> + + + + + ))} + {(coreData.active_sensors > 0 || coreData.analog_enabled) && ( + + + + + Sensors + Attached EMS-ESP Sensors + {coreData.active_sensors} + + addAnalogSensor()}> + + + + + )} + + + )} +
+
+ ); const renderDeviceData = () => { if (!device_select.state.id || device_select.state.id === 'sensor') { @@ -830,7 +829,8 @@ const DashboardData: FC = () => { fullWidth style={{ fontSize: '14px', justifyContent: 'flex-start' }} endIcon={getSortIcon(sensor_sort.state, 'NAME')} - onClick={() => sensor_sort.fns.onToggleSort({ sortKey: 'NAME' })} + // onClick={() => sensor_sort.fns.onToggleSort({ sortKey: 'NAME' })} + onClick={() => paul()} > NAME @@ -950,7 +950,7 @@ const DashboardData: FC = () => { if (analog) { try { const response = await EMSESP.writeAnalog({ - i: analog.i, + gpio: analog.g, name: analog.n, offset: analog.o, factor: analog.f, @@ -978,7 +978,7 @@ const DashboardData: FC = () => { if (analog) { try { const response = await EMSESP.writeAnalog({ - i: analog.i, + gpio: analog.g, name: analog.n, offset: analog.o, factor: analog.f, @@ -1011,9 +1011,9 @@ const DashboardData: FC = () => { = AnalogType::DIGITAL_OUT) && (sensor_.type() != sensor.type || sensor_.offset() != sensor.offset || sensor_.factor() != sensor.factor)) { @@ -94,12 +94,12 @@ void AnalogSensor::reload() { for (const auto & sensor : settings.analogCustomizations) { bool found = false; for (const auto & sensor_ : sensors_) { - if (sensor_.id() == sensor.id) { + if (sensor_.gpio() == sensor.gpio) { found = true; } } if (!found) { - sensors_.emplace_back(sensor.id, sensor.name, sensor.offset, sensor.factor, sensor.uom, sensor.type); + sensors_.emplace_back(sensor.gpio, sensor.name, sensor.offset, sensor.factor, sensor.uom, sensor.type); sensors_.back().ha_registered = false; // this will trigger recrate of the HA config if (sensor.type == AnalogType::COUNTER || sensor.type >= AnalogType::DIGITAL_OUT) { sensors_.back().set_value(sensor.offset); @@ -112,64 +112,64 @@ void AnalogSensor::reload() { }); // sort the list based on GPIO (id) - std::sort(sensors_.begin(), sensors_.end(), [](const Sensor & a, const Sensor & b) { return a.id() < b.id(); }); + // std::sort(sensors_.begin(), sensors_.end(), [](const Sensor & a, const Sensor & b) { return a.id() < b.id(); }); // activate each sensor for (auto & sensor : sensors_) { sensor.ha_registered = false; // force HA configs to be re-created if (sensor.type() == AnalogType::ADC) { - LOG_DEBUG(F("Adding analog ADC sensor on GPIO%d"), sensor.id()); + LOG_DEBUG(F("Adding analog ADC sensor on GPIO%d"), sensor.gpio()); // analogSetPinAttenuation does not work with analogReadMilliVolts sensor.analog_ = 0; // initialize sensor.last_reading_ = 0; } else if (sensor.type() == AnalogType::COUNTER) { - LOG_DEBUG(F("Adding analog I/O Counter sensor on GPIO%d"), sensor.id()); - pinMode(sensor.id(), INPUT_PULLUP); - if (sensor.id() == 25 || sensor.id() == 26) { - dacWrite(sensor.id(), 255); + LOG_DEBUG(F("Adding analog I/O Counter sensor on GPIO%d"), sensor.gpio()); + pinMode(sensor.gpio(), INPUT_PULLUP); + if (sensor.gpio() == 25 || sensor.gpio() == 26) { + dacWrite(sensor.gpio(), 255); } sensor.polltime_ = 0; - sensor.poll_ = digitalRead(sensor.id()); + sensor.poll_ = digitalRead(sensor.gpio()); publish_sensor(sensor); } else if (sensor.type() == AnalogType::TIMER || sensor.type() == AnalogType::RATE) { - LOG_DEBUG(F("Adding analog Timer/Rate sensor on GPIO%d"), sensor.id()); - pinMode(sensor.id(), INPUT_PULLUP); + LOG_DEBUG(F("Adding analog Timer/Rate sensor on GPIO%d"), sensor.gpio()); + pinMode(sensor.gpio(), INPUT_PULLUP); sensor.polltime_ = uuid::get_uptime(); sensor.last_polltime_ = uuid::get_uptime(); - sensor.poll_ = digitalRead(sensor.id()); + sensor.poll_ = digitalRead(sensor.gpio()); sensor.set_offset(0); sensor.set_value(0); publish_sensor(sensor); } else if (sensor.type() == AnalogType::DIGITAL_IN) { - LOG_DEBUG(F("Adding analog Read sensor on GPIO%d"), sensor.id()); - pinMode(sensor.id(), INPUT_PULLUP); - sensor.set_value(digitalRead(sensor.id())); // initial value - sensor.set_uom(0); // no uom, just for safe measures + LOG_DEBUG(F("Adding analog Read sensor on GPIO%d"), sensor.gpio()); + pinMode(sensor.gpio(), INPUT_PULLUP); + sensor.set_value(digitalRead(sensor.gpio())); // initial value + sensor.set_uom(0); // no uom, just for safe measures sensor.polltime_ = 0; - sensor.poll_ = digitalRead(sensor.id()); + sensor.poll_ = digitalRead(sensor.gpio()); publish_sensor(sensor); } else if (sensor.type() == AnalogType::DIGITAL_OUT) { - LOG_DEBUG(F("Adding analog Write sensor on GPIO%d"), sensor.id()); - pinMode(sensor.id(), OUTPUT); - if (sensor.id() == 25 || sensor.id() == 26) { + LOG_DEBUG(F("Adding analog Write sensor on GPIO%d"), sensor.gpio()); + pinMode(sensor.gpio(), OUTPUT); + if (sensor.gpio() == 25 || sensor.gpio() == 26) { if (sensor.offset() > 255) { sensor.set_offset(255); } else if (sensor.offset() < 0) { sensor.set_offset(0); } - dacWrite(sensor.id(), sensor.offset()); + dacWrite(sensor.gpio(), sensor.offset()); sensor.set_value(sensor.offset()); } else { - digitalWrite(sensor.id(), sensor.offset() > 0 ? 1 : 0); - sensor.set_value(digitalRead(sensor.id())); + digitalWrite(sensor.gpio(), sensor.offset() > 0 ? 1 : 0); + sensor.set_value(digitalRead(sensor.gpio())); } sensor.set_uom(0); // no uom, just for safe measures publish_sensor(sensor); } else if (sensor.type() >= AnalogType::PWM_0) { - LOG_DEBUG(F("Adding PWM output sensor on GPIO%d"), sensor.id()); + LOG_DEBUG(F("Adding PWM output sensor on GPIO%d"), sensor.gpio()); uint channel = sensor.type() - AnalogType::PWM_0; ledcSetup(channel, sensor.factor(), 13); - ledcAttachPin(sensor.id(), channel); + ledcAttachPin(sensor.gpio(), channel); if (sensor.offset() > 100) { sensor.set_offset(100); } else if (sensor.offset() < 0) { @@ -193,8 +193,8 @@ void AnalogSensor::measure() { // go through the list of adc sensors for (auto & sensor : sensors_) { if (sensor.type() == AnalogType::ADC) { - uint16_t a = analogReadMilliVolts(sensor.id()); // e.g. ADC1_CHANNEL_0_GPIO_NUM - if (!sensor.analog_) { // init first time + uint16_t a = analogReadMilliVolts(sensor.gpio()); // e.g. ADC1_CHANNEL_0_GPIO_NUM + if (!sensor.analog_) { // init first time sensor.analog_ = a; sensor.sum_ = a * 512; } else { // simple moving average filter @@ -218,7 +218,7 @@ void AnalogSensor::measure() { if (sensor.type() == AnalogType::DIGITAL_IN || sensor.type() == AnalogType::COUNTER || sensor.type() == AnalogType::TIMER || sensor.type() == AnalogType::RATE) { auto old_value = sensor.value(); // remember current value before reading - auto current_reading = digitalRead(sensor.id()); + auto current_reading = digitalRead(sensor.gpio()); if (sensor.poll_ != current_reading) { // check for pinchange sensor.polltime_ = uuid::get_uptime(); // remember time of pinchange sensor.poll_ = current_reading; @@ -258,17 +258,17 @@ void AnalogSensor::loop() { } // update analog information name and offset -bool AnalogSensor::update(uint8_t id, const std::string & name, float offset, float factor, uint8_t uom, int8_t type) { +bool AnalogSensor::update(uint8_t gpio, const std::string & name, float offset, float factor, uint8_t uom, int8_t type) { boolean found_sensor = false; // see if we can find the sensor in our customization list EMSESP::webCustomizationService.update( [&](WebCustomization & settings) { for (auto & AnalogCustomization : settings.analogCustomizations) { - if (AnalogCustomization.id == id) { + if (AnalogCustomization.gpio == gpio) { found_sensor = true; // found the record // see if it's marked for deletion if (type == AnalogType::MARK_DELETED) { - LOG_DEBUG(F("Removing analog sensor ID %d"), id); + LOG_DEBUG(F("Removing analog sensor GPIO %d"), gpio); settings.analogCustomizations.remove(AnalogCustomization); } else { // update existing record @@ -277,7 +277,7 @@ bool AnalogSensor::update(uint8_t id, const std::string & name, float offset, fl AnalogCustomization.factor = factor; AnalogCustomization.uom = uom; AnalogCustomization.type = type; - LOG_DEBUG(F("Customizing existing analog sensor ID %d"), id); + LOG_DEBUG(F("Customizing existing analog GPIO %d"), gpio); } return StateUpdateResult::CHANGED; // persist the change } @@ -288,7 +288,7 @@ bool AnalogSensor::update(uint8_t id, const std::string & name, float offset, fl // if the sensor exists and we're using HA, delete the old HA record if (found_sensor && Mqtt::ha_enabled()) { - remove_ha_topic(id); // id is the GPIO + remove_ha_topic(gpio); // the GPIO } // we didn't find it, it's new, so create and store it @@ -296,14 +296,14 @@ bool AnalogSensor::update(uint8_t id, const std::string & name, float offset, fl EMSESP::webCustomizationService.update( [&](WebCustomization & settings) { auto newSensor = AnalogCustomization(); - newSensor.id = id; + newSensor.gpio = gpio; newSensor.name = name; newSensor.offset = offset; newSensor.factor = factor; newSensor.uom = uom; newSensor.type = type; settings.analogCustomizations.push_back(newSensor); - LOG_DEBUG(F("Adding new customization for analog sensor ID %d"), id); + LOG_DEBUG(F("Adding new customization for analog sensor GPIO %d"), gpio); return StateUpdateResult::CHANGED; // persist the change }, "local"); @@ -339,15 +339,15 @@ void AnalogSensor::publish_sensor(const Sensor & sensor) const { } // send empty config topic to remove the entry from HA -void AnalogSensor::remove_ha_topic(const uint8_t id) const { +void AnalogSensor::remove_ha_topic(const uint8_t gpio) const { if (!Mqtt::ha_enabled()) { return; } #ifdef EMSESP_DEBUG - LOG_DEBUG(F("Removing HA config for analog sensor ID %d"), id); + LOG_DEBUG(F("Removing HA config for analog sensor GPIO %d"), gpio); #endif char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::base().c_str(), id); + snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::base().c_str(), gpio); Mqtt::publish_ha(topic); } @@ -372,7 +372,7 @@ void AnalogSensor::publish_values(const bool force) { if (Mqtt::is_nested() || Mqtt::ha_enabled()) { // nested char s[10]; - JsonObject dataSensor = doc.createNestedObject(Helpers::smallitoa(s, sensor.id())); + JsonObject dataSensor = doc.createNestedObject(Helpers::smallitoa(s, sensor.gpio())); dataSensor["name"] = sensor.name(); switch (sensor.type()) { case AnalogType::COUNTER: @@ -391,7 +391,7 @@ void AnalogSensor::publish_values(const bool force) { // create HA config if (Mqtt::ha_enabled() && (!sensor.ha_registered || force)) { - LOG_DEBUG(F("Recreating HA config for analog sensor ID %d"), sensor.id()); + LOG_DEBUG(F("Recreating HA config for analog sensor GPIO %d"), sensor.gpio()); StaticJsonDocument config; @@ -400,13 +400,13 @@ void AnalogSensor::publish_values(const bool force) { config["stat_t"] = stat_t; char str[50]; - snprintf(str, sizeof(str), "{{value_json['%d'].value}}", sensor.id()); + snprintf(str, sizeof(str), "{{value_json['%d'].value}}", sensor.gpio()); config["val_tpl"] = str; snprintf(str, sizeof(str), "Analog Sensor %s", sensor.name().c_str()); config["name"] = str; - snprintf(str, sizeof(str), "analogsensor_%d", sensor.id()); + snprintf(str, sizeof(str), "analogsensor_%d", sensor.gpio()); config["uniq_id"] = str; JsonObject dev = config.createNestedObject("dev"); @@ -414,7 +414,7 @@ void AnalogSensor::publish_values(const bool force) { ids.add("ems-esp"); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::base().c_str(), sensor.id()); + snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::base().c_str(), sensor.gpio()); Mqtt::publish_ha(topic, config.as()); @@ -437,7 +437,7 @@ void AnalogSensor::publish_values(const bool force) { bool AnalogSensor::get_value_info(JsonObject & output, const char * cmd, const int8_t id) const { for (const auto & sensor : sensors_) { if (strcmp(cmd, sensor.name().c_str()) == 0) { - output["id"] = sensor.id(); + output["gpio"] = sensor.gpio(); output["name"] = sensor.name(); output["type"] = sensor.type(); output["uom"] = sensor.uom(); @@ -460,7 +460,7 @@ bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject for (const auto & sensor : sensors_) { if (id == -1) { // show number and id JsonObject dataSensor = output.createNestedObject(sensor.name()); - dataSensor["id"] = sensor.id(); + dataSensor["gpio"] = sensor.gpio(); dataSensor["type"] = FL_(enum_sensortype)[sensor.type()]; if (sensor.type() == AnalogType::ADC) { dataSensor["uom"] = EMSdevice::uom_to_string(sensor.uom()); @@ -486,8 +486,8 @@ bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject } // this creates the sensor, initializing everything -AnalogSensor::Sensor::Sensor(const uint8_t id, const std::string & name, const float offset, const float factor, const uint8_t uom, const int8_t type) - : id_(id) +AnalogSensor::Sensor::Sensor(const uint8_t gpio, const std::string & name, const float offset, const float factor, const uint8_t uom, const int8_t type) + : gpio_(gpio) , name_(name) , offset_(offset) , factor_(factor) @@ -500,20 +500,20 @@ AnalogSensor::Sensor::Sensor(const uint8_t id, const std::string & name, const f std::string AnalogSensor::Sensor::name() const { if (name_.empty()) { char name[50]; - snprintf(name, sizeof(name), "Analog Sensor GPIO%d", id_); + snprintf(name, sizeof(name), "Analog Sensor GPIO%d", gpio_); return name; } return name_; } // set the counter value, id is gpio-no -bool AnalogSensor::command_setvalue(const char * value, const int8_t id) { +bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) { float val; if (!Helpers::value2float(value, val)) { return false; } for (auto & sensor : sensors_) { - if (sensor.id() == id) { + if (sensor.gpio() == gpio) { if (sensor.type() == AnalogType::COUNTER) { if (val < 0 || value[0] == '+') { // sign corrects values sensor.set_offset(sensor.value() + val); @@ -529,18 +529,18 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t id) { return true; } else if (sensor.type() == AnalogType::DIGITAL_OUT) { uint8_t v = val; - if (sensor.id() == 25 || sensor.id() == 26) { + if (sensor.gpio() == 25 || sensor.gpio() == 26) { sensor.set_offset(v); sensor.set_value(v); - pinMode(sensor.id(), OUTPUT); - dacWrite(sensor.id(), sensor.offset()); + pinMode(sensor.gpio(), OUTPUT); + dacWrite(sensor.gpio(), sensor.offset()); publish_sensor(sensor); return true; } else if (v == 0 || v == 1) { sensor.set_offset(v); sensor.set_value(v); - pinMode(sensor.id(), OUTPUT); - digitalWrite(sensor.id(), sensor.offset() > 0 ? 1 : 0); + pinMode(sensor.gpio(), OUTPUT); + digitalWrite(sensor.gpio(), sensor.offset() > 0 ? 1 : 0); publish_sensor(sensor); return true; } diff --git a/src/analogsensor.h b/src/analogsensor.h index fc7f72ea6..3c10c11c8 100644 --- a/src/analogsensor.h +++ b/src/analogsensor.h @@ -36,7 +36,7 @@ class AnalogSensor { public: class Sensor { public: - Sensor(const uint8_t id, const std::string & name, const float offset, const float factor, const uint8_t uom, const int8_t type); + Sensor(const uint8_t gpio, const std::string & name, const float offset, const float factor, const uint8_t uom, const int8_t type); ~Sensor() = default; void set_offset(const float offset) { @@ -48,8 +48,8 @@ class AnalogSensor { name_ = name; } - uint8_t id() const { - return id_; + uint8_t gpio() const { + return gpio_; } float value() const { @@ -99,7 +99,7 @@ class AnalogSensor { uint32_t last_polltime_ = 0; // for timer private: - uint8_t id_; + uint8_t gpio_; std::string name_; float offset_; float factor_; @@ -157,7 +157,7 @@ class AnalogSensor { return sensors_.size(); } - bool update(uint8_t id, const std::string & name, float offset, float factor, uint8_t uom, int8_t type); + bool update(uint8_t gpio, const std::string & name, float offset, float factor, uint8_t uom, int8_t type); bool get_value_info(JsonObject & output, const char * cmd, const int8_t id) const; #ifdef EMSESP_DEBUG @@ -171,7 +171,7 @@ class AnalogSensor { static uuid::log::Logger logger_; void remove_ha_topic(const uint8_t id) const; - bool command_setvalue(const char * value, const int8_t id); + bool command_setvalue(const char * value, const int8_t gpio); void measure(); bool command_info(const char * value, const int8_t id, JsonObject & output) const; bool command_commands(const char * value, const int8_t id, JsonObject & output); diff --git a/src/dallassensor.cpp b/src/dallassensor.cpp index 3d4be1a15..bb4d3f624 100644 --- a/src/dallassensor.cpp +++ b/src/dallassensor.cpp @@ -149,7 +149,7 @@ void DallasSensor::loop() { // check if we already have this sensor bool found = false; for (auto & sensor : sensors_) { - if (sensor.id() == get_id(addr)) { + if (sensor.internal_id() == get_id(addr)) { t += sensor.offset(); if (t != sensor.temperature_c) { publish_sensor(sensor); @@ -171,7 +171,7 @@ void DallasSensor::loop() { sensors_.back().apply_customization(); publish_sensor(sensors_.back()); // call publish single // sort the sensors based on name - std::sort(sensors_.begin(), sensors_.end(), [](const Sensor & a, const Sensor & b) { return a.name() < b.name(); }); + // std::sort(sensors_.begin(), sensors_.end(), [](const Sensor & a, const Sensor & b) { return a.name() < b.name(); }); } } else { sensorfails_++; @@ -180,12 +180,12 @@ void DallasSensor::loop() { default: sensorfails_++; - LOG_ERROR(F("Unknown dallas sensor %s"), Sensor(addr).id_str().c_str()); + LOG_ERROR(F("Unknown dallas sensor %s"), Sensor(addr).id().c_str()); break; } } else { sensorfails_++; - LOG_ERROR(F("Invalid dallas sensor %s"), Sensor(addr).id_str().c_str()); + LOG_ERROR(F("Invalid dallas sensor %s"), Sensor(addr).id().c_str()); } } else { if (!parasite_) { @@ -229,7 +229,7 @@ bool DallasSensor::temperature_convert_complete() { int16_t DallasSensor::get_temperature_c(const uint8_t addr[]) { #ifndef EMSESP_STANDALONE if (!bus_.reset()) { - LOG_ERROR(F("Bus reset failed before reading scratchpad from %s"), Sensor(addr).id_str().c_str()); + LOG_ERROR(F("Bus reset failed before reading scratchpad from %s"), Sensor(addr).id().c_str()); return EMS_VALUE_SHORT_NOTSET; } YIELD; @@ -241,7 +241,7 @@ int16_t DallasSensor::get_temperature_c(const uint8_t addr[]) { YIELD; if (!bus_.reset()) { - LOG_ERROR(F("Bus reset failed after reading scratchpad from %s"), Sensor(addr).id_str().c_str()); + LOG_ERROR(F("Bus reset failed after reading scratchpad from %s"), Sensor(addr).id().c_str()); return EMS_VALUE_SHORT_NOTSET; } YIELD; @@ -257,7 +257,7 @@ int16_t DallasSensor::get_temperature_c(const uint8_t addr[]) { scratchpad[6], scratchpad[7], scratchpad[8], - Sensor(addr).id_str().c_str()); + Sensor(addr).id().c_str()); return EMS_VALUE_SHORT_NOTSET; } @@ -290,15 +290,15 @@ int16_t DallasSensor::get_temperature_c(const uint8_t addr[]) { } // update dallas information name and offset -bool DallasSensor::update(const std::string & id_str, const std::string & name, int16_t offset) { +bool DallasSensor::update(const std::string & id, const std::string & name, int16_t offset) { // find the sensor for (auto & sensor : sensors_) { - if (sensor.id_str() == id_str) { + if (sensor.id() == id) { // found a match, update the sensor object // if HA is enabled then delete the old record if (Mqtt::ha_enabled()) { - remove_ha_topic(id_str); + remove_ha_topic(id); } sensor.set_name(name); @@ -310,21 +310,21 @@ bool DallasSensor::update(const std::string & id_str, const std::string & name, // look it up to see if it exists bool found = false; for (auto & SensorCustomization : settings.sensorCustomizations) { - if (SensorCustomization.id_str == id_str) { + if (SensorCustomization.id == id) { SensorCustomization.name = name; SensorCustomization.offset = offset; found = true; - LOG_DEBUG(F("Customizing existing sensor ID %s"), id_str.c_str()); + LOG_DEBUG(F("Customizing existing sensor ID %s"), id.c_str()); break; } } if (!found) { SensorCustomization newSensor = SensorCustomization(); - newSensor.id_str = id_str; + newSensor.id = id; newSensor.name = name; newSensor.offset = offset; settings.sensorCustomizations.push_back(newSensor); - LOG_DEBUG(F("Adding new customization for sensor ID %s"), id_str.c_str()); + LOG_DEBUG(F("Adding new customization for sensor ID %s"), id.c_str()); } sensor.ha_registered = false; // it's changed so we may need to recreate the HA config return StateUpdateResult::CHANGED; @@ -361,7 +361,7 @@ bool DallasSensor::command_info(const char * value, const int8_t id, JsonObject for (const auto & sensor : sensors_) { if (id == -1) { // show number and id JsonObject dataSensor = output.createNestedObject(sensor.name()); - dataSensor["id_str"] = sensor.id_str(); + dataSensor["id"] = sensor.id(); if (Helpers::hasValue(sensor.temperature_c)) { dataSensor["temp"] = Helpers::round2((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); } @@ -377,8 +377,8 @@ bool DallasSensor::command_info(const char * value, const int8_t id, JsonObject bool DallasSensor::get_value_info(JsonObject & output, const char * cmd, const int8_t id) { for (const auto & sensor : sensors_) { if (strcmp(cmd, sensor.name().c_str()) == 0) { - output["id_str"] = sensor.id_str(); - output["name"] = sensor.name(); + output["id"] = sensor.id(); + output["name"] = sensor.name(); if (Helpers::hasValue(sensor.temperature_c)) { output["value"] = Helpers::round2((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); } @@ -408,15 +408,15 @@ void DallasSensor::publish_sensor(const Sensor & sensor) { } // send empty config topic to remove the entry from HA -void DallasSensor::remove_ha_topic(const std::string & id_str) { +void DallasSensor::remove_ha_topic(const std::string & id) { if (!Mqtt::ha_enabled()) { return; } #ifdef EMSESP_DEBUG - LOG_DEBUG(F("Removing HA config for temperature sensor ID %s"), id_str.c_str()); + LOG_DEBUG(F("Removing HA config for temperature sensor ID %s"), id.c_str()); #endif // use '_' as HA doesn't like '-' in the topic name - std::string sensorid = id_str; + std::string sensorid = id; std::replace(sensorid.begin(), sensorid.end(), '-', '_'); char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; snprintf(topic, sizeof(topic), "sensor/%s/dallassensor_%s/config", Mqtt::base().c_str(), sensorid.c_str()); @@ -442,7 +442,7 @@ void DallasSensor::publish_values(const bool force) { for (auto & sensor : sensors_) { bool has_value = Helpers::hasValue(sensor.temperature_c); if (Mqtt::is_nested() || Mqtt::ha_enabled()) { - JsonObject dataSensor = doc.createNestedObject(sensor.id_str()); + JsonObject dataSensor = doc.createNestedObject(sensor.id()); dataSensor["name"] = sensor.name(); if (has_value) { dataSensor["temp"] = Helpers::round2((float)(sensor.temperature_c), 10, EMSESP::system_.fahrenheit() ? 2 : 0); @@ -455,7 +455,7 @@ void DallasSensor::publish_values(const bool force) { // to e.g. homeassistant/sensor/ems-esp/dallassensor_28-233D-9497-0C03/config if (Mqtt::ha_enabled()) { if (!sensor.ha_registered || force) { - LOG_DEBUG(F("Recreating HA config for sensor ID %s"), sensor.id_str().c_str()); + LOG_DEBUG(F("Recreating HA config for sensor ID %s"), sensor.id().c_str()); StaticJsonDocument config; config["dev_cla"] = FJSON("temperature"); @@ -467,13 +467,13 @@ void DallasSensor::publish_values(const bool force) { config["unit_of_meas"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); char str[50]; - snprintf(str, sizeof(str), "{{value_json['%s'].temp}}", sensor.id_str().c_str()); + snprintf(str, sizeof(str), "{{value_json['%s'].temp}}", sensor.id().c_str()); config["val_tpl"] = str; snprintf(str, sizeof(str), "Temperature Sensor %s", sensor.name().c_str()); config["name"] = str; - snprintf(str, sizeof(str), "dallasensor_%s", sensor.id_str().c_str()); + snprintf(str, sizeof(str), "dallasensor_%s", sensor.id().c_str()); config["uniq_id"] = str; JsonObject dev = config.createNestedObject("dev"); @@ -482,7 +482,7 @@ void DallasSensor::publish_values(const bool force) { char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; // use '_' as HA doesn't like '-' in the topic name - std::string sensorid = sensor.id_str(); + std::string sensorid = sensor.id(); std::replace(sensorid.begin(), sensorid.end(), '-', '_'); snprintf(topic, sizeof(topic), "sensor/%s/dallassensor_%s/config", Mqtt::base().c_str(), sensorid.c_str()); @@ -500,18 +500,18 @@ void DallasSensor::publish_values(const bool force) { // skip crc from id DallasSensor::Sensor::Sensor(const uint8_t addr[]) - : id_(((uint64_t)addr[0] << 48) | ((uint64_t)addr[1] << 40) | ((uint64_t)addr[2] << 32) | ((uint64_t)addr[3] << 24) | ((uint64_t)addr[4] << 16) - | ((uint64_t)addr[5] << 8) | ((uint64_t)addr[6])) { + : internal_id_(((uint64_t)addr[0] << 48) | ((uint64_t)addr[1] << 40) | ((uint64_t)addr[2] << 32) | ((uint64_t)addr[3] << 24) | ((uint64_t)addr[4] << 16) + | ((uint64_t)addr[5] << 8) | ((uint64_t)addr[6])) { // create ID string - char id[20]; - snprintf(id, - sizeof(id), + char id_str[20]; + snprintf(id_str, + sizeof(id_str), "%02X-%04X-%04X-%04X", - (unsigned int)(id_ >> 48) & 0xFF, - (unsigned int)(id_ >> 32) & 0xFFFF, - (unsigned int)(id_ >> 16) & 0xFFFF, - (unsigned int)(id_)&0xFFFF); - id_str_ = std::string(id); + (unsigned int)(internal_id_ >> 48) & 0xFF, + (unsigned int)(internal_id_ >> 32) & 0xFFFF, + (unsigned int)(internal_id_ >> 16) & 0xFFFF, + (unsigned int)(internal_id_)&0xFFFF); + id_ = std::string(id_str); name_ = std::string{}; // name (alias) is empty offset_ = 0; // 0 degrees offset } @@ -525,7 +525,7 @@ uint64_t DallasSensor::get_id(const uint8_t addr[]) { // if empty, return the ID as a string std::string DallasSensor::Sensor::name() const { if (name_.empty()) { - return id_str_; + return id_; } return name_; } @@ -538,9 +538,9 @@ bool DallasSensor::Sensor::apply_customization() { if (!sensors.empty()) { for (const auto & sensor : sensors) { #if defined(EMSESP_DEBUG) - LOG_DEBUG(F("Loading customization for dallas sensor %s"), sensor.id_str.c_str()); + LOG_DEBUG(F("Loading customization for dallas sensor %s"), sensor.id.c_str()); #endif - if (id_str_ == sensor.id_str) { + if (id_ == sensor.id) { set_name(sensor.name); set_offset(sensor.offset); return true; diff --git a/src/dallassensor.h b/src/dallassensor.h index c9567e32f..009db5fa6 100644 --- a/src/dallassensor.h +++ b/src/dallassensor.h @@ -40,12 +40,12 @@ class DallasSensor { Sensor(const uint8_t addr[]); ~Sensor() = default; - uint64_t id() const { - return id_; + uint64_t internal_id() const { + return internal_id_; } - std::string id_str() const { - return id_str_; + std::string id() const { + return id_; } int16_t offset() const { @@ -67,8 +67,8 @@ class DallasSensor { bool ha_registered = false; private: - uint64_t id_; - std::string id_str_; + uint64_t internal_id_; + std::string id_; std::string name_; int16_t offset_; }; @@ -109,7 +109,7 @@ class DallasSensor { return sensors_.size(); } - bool update(const std::string & id_str, const std::string & name, int16_t offset); + bool update(const std::string & id, const std::string & name, int16_t offset); #ifdef EMSESP_DEBUG void test(); diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 4711ddcbf..fe52772a7 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -656,119 +656,118 @@ void EMSdevice::generate_values_web(JsonObject & output) { output["label"] = to_string_short(); JsonArray data = output.createNestedArray("data"); - // do two passes. First for all entities marked as favorites, then for all others. This sorts the list. - for (int8_t fav = 1; fav >= 0; fav--) { - for (auto & dv : devicevalues_) { - // check conditions: - // 1. full_name cannot be empty - // 2. it must have a valid value, if it is not a command like 'reset' - // 3. show favorites first - bool show = (fav && dv.has_state(DeviceValueState::DV_FAVORITE)) || (!fav && !dv.has_state(DeviceValueState::DV_FAVORITE)); - if (show && !dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.full_name && (dv.hasValue() || (dv.type == DeviceValueType::CMD))) { - JsonObject obj = data.createNestedObject(); // create the object, we know there is a value - uint8_t fahrenheit = 0; + for (auto & dv : devicevalues_) { + // check conditions: + // 1. full_name cannot be empty + // 2. it must have a valid value, if it is not a command like 'reset' + // 3. show favorites first + if (!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.full_name && (dv.hasValue() || (dv.type == DeviceValueType::CMD))) { + JsonObject obj = data.createNestedObject(); // create the object, we know there is a value + uint8_t fahrenheit = 0; - // handle Booleans (true, false), use strings, no native true/false) - if (dv.type == DeviceValueType::BOOL) { - bool value_b = (bool)*(uint8_t *)(dv.value_p); - if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) { - obj["v"] = value_b ? 1 : 0; - } else { - char s[7]; - obj["v"] = Helpers::render_boolean(s, value_b); - } - } - - // handle TEXT strings - else if (dv.type == DeviceValueType::STRING) { - obj["v"] = (char *)(dv.value_p); - } - - // handle ENUMs - else if ((dv.type == DeviceValueType::ENUM) && (*(uint8_t *)(dv.value_p) < dv.options_size)) { - obj["v"] = dv.options[*(uint8_t *)(dv.value_p)]; - } - - // handle numbers - else { - // If a divider is specified, do the division to 2 decimals places and send back as double/float - // otherwise force as an integer whole - // the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler - int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0; - fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; - - if ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(int8_t *)(dv.value_p), divider, fahrenheit); - } else if ((dv.type == DeviceValueType::UINT) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(uint8_t *)(dv.value_p), divider, fahrenheit); - } else if ((dv.type == DeviceValueType::SHORT) && Helpers::hasValue(*(int16_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(int16_t *)(dv.value_p), divider, fahrenheit); - } else if ((dv.type == DeviceValueType::USHORT) && Helpers::hasValue(*(uint16_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(uint16_t *)(dv.value_p), divider, fahrenheit); - } else if ((dv.type == DeviceValueType::ULONG) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(uint32_t *)(dv.value_p), divider, fahrenheit); - } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - uint32_t time_value = *(uint32_t *)(dv.value_p); - obj["v"] = (divider > 0) ? time_value / divider : time_value; // sometimes we need to divide by 60 - } - } - - // add the unit of measure (uom) - obj["u"] = fahrenheit ? (uint8_t)DeviceValueUOM::FAHRENHEIT : dv.uom; - - auto mask = Helpers::hextoa((uint8_t)(dv.state >> 4), false); // create mask to a 2-char string - - // add name, prefixing the tag if it exists - if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) { - obj["n"] = mask + read_flash_string(dv.full_name); - } else if (dv.tag < DeviceValueTAG::TAG_HC1) { - obj["n"] = mask + tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name); + // handle Booleans (true, false), use strings, no native true/false) + if (dv.type == DeviceValueType::BOOL) { + bool value_b = (bool)*(uint8_t *)(dv.value_p); + if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) { + obj["v"] = value_b ? 1 : 0; } else { - obj["n"] = mask + tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name); + char s[7]; + obj["v"] = Helpers::render_boolean(s, value_b); } + } - // add commands and options - if (dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY)) { - // add the name of the Command function - if (dv.tag >= DeviceValueTAG::TAG_HC1) { - obj["c"] = tag_to_mqtt(dv.tag) + "/" + read_flash_string(dv.short_name); - } else { - obj["c"] = dv.short_name; - } - // add the Command options - if (dv.type == DeviceValueType::ENUM || (dv.type == DeviceValueType::CMD && dv.options_size > 1)) { - JsonArray l = obj.createNestedArray("l"); - for (uint8_t i = 0; i < dv.options_size; i++) { - if (!read_flash_string(dv.options[i]).empty()) { - l.add(read_flash_string(dv.options[i])); - } - } - } else if (dv.type == DeviceValueType::BOOL) { - JsonArray l = obj.createNestedArray("l"); - char result[10]; - l.add(Helpers::render_boolean(result, false)); - l.add(Helpers::render_boolean(result, true)); - } - // add command help template - else if (dv.type == DeviceValueType::STRING || dv.type == DeviceValueType::CMD) { - if (dv.options_size == 1) { - obj["h"] = dv.options[0]; + // handle TEXT strings + else if (dv.type == DeviceValueType::STRING) { + obj["v"] = (char *)(dv.value_p); + } + + // handle ENUMs + else if ((dv.type == DeviceValueType::ENUM) && (*(uint8_t *)(dv.value_p) < dv.options_size)) { + obj["v"] = dv.options[*(uint8_t *)(dv.value_p)]; + } + + // handle numbers + else { + // If a divider is specified, do the division to 2 decimals places and send back as double/float + // otherwise force as an integer whole + // the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler + int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0; + fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; + + if ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) { + obj["v"] = Helpers::round2(*(int8_t *)(dv.value_p), divider, fahrenheit); + } else if ((dv.type == DeviceValueType::UINT) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) { + obj["v"] = Helpers::round2(*(uint8_t *)(dv.value_p), divider, fahrenheit); + } else if ((dv.type == DeviceValueType::SHORT) && Helpers::hasValue(*(int16_t *)(dv.value_p))) { + obj["v"] = Helpers::round2(*(int16_t *)(dv.value_p), divider, fahrenheit); + } else if ((dv.type == DeviceValueType::USHORT) && Helpers::hasValue(*(uint16_t *)(dv.value_p))) { + obj["v"] = Helpers::round2(*(uint16_t *)(dv.value_p), divider, fahrenheit); + } else if ((dv.type == DeviceValueType::ULONG) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { + obj["v"] = Helpers::round2(*(uint32_t *)(dv.value_p), divider, fahrenheit); + } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { + uint32_t time_value = *(uint32_t *)(dv.value_p); + obj["v"] = (divider > 0) ? time_value / divider : time_value; // sometimes we need to divide by 60 + } else { + // must have a value for sorting to work + obj["v"] = ""; + } + } + + // add the unit of measure (uom) + obj["u"] = fahrenheit ? (uint8_t)DeviceValueUOM::FAHRENHEIT : dv.uom; + + auto mask = Helpers::hextoa((uint8_t)(dv.state >> 4), false); // create mask to a 2-char string + + // add name, prefixing the tag if it exists. This is the id used for the table sorting + if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) { + obj["id"] = mask + read_flash_string(dv.full_name); + } else if (dv.tag < DeviceValueTAG::TAG_HC1) { + obj["id"] = mask + tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name); + } else { + obj["id"] = mask + tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name); + } + + // add commands and options + if (dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY)) { + // add the name of the Command function + if (dv.tag >= DeviceValueTAG::TAG_HC1) { + obj["c"] = tag_to_mqtt(dv.tag) + "/" + read_flash_string(dv.short_name); + } else { + obj["c"] = dv.short_name; + } + // add the Command options + if (dv.type == DeviceValueType::ENUM || (dv.type == DeviceValueType::CMD && dv.options_size > 1)) { + JsonArray l = obj.createNestedArray("l"); + for (uint8_t i = 0; i < dv.options_size; i++) { + if (!read_flash_string(dv.options[i]).empty()) { + l.add(read_flash_string(dv.options[i])); } } - // add steps to numeric values with divider/multiplier - else { - int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0; - char s[10]; - if (divider > 0) { - obj["s"] = Helpers::render_value(s, (float)1 / divider, 1); - } else if (divider < 0) { - obj["s"] = Helpers::render_value(s, (-1) * divider, 0); - } - int16_t dv_set_min, dv_set_max; - if (dv.get_min_max(dv_set_min, dv_set_max)) { - obj["m"] = Helpers::render_value(s, dv_set_min, 0); - obj["x"] = Helpers::render_value(s, dv_set_max, 0); - } + } else if (dv.type == DeviceValueType::BOOL) { + JsonArray l = obj.createNestedArray("l"); + char result[10]; + l.add(Helpers::render_boolean(result, false)); + l.add(Helpers::render_boolean(result, true)); + } + // add command help template + else if (dv.type == DeviceValueType::STRING || dv.type == DeviceValueType::CMD) { + if (dv.options_size == 1) { + obj["h"] = dv.options[0]; + } + } + // add steps to numeric values with divider/multiplier + else { + int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0; + char s[10]; + if (divider > 0) { + obj["s"] = Helpers::render_value(s, (float)1 / divider, 1); + } else if (divider < 0) { + obj["s"] = Helpers::render_value(s, (-1) * divider, 0); + } + int16_t dv_set_min, dv_set_max; + if (dv.get_min_max(dv_set_min, dv_set_max)) { + obj["m"] = Helpers::render_value(s, dv_set_min, 0); + obj["x"] = Helpers::render_value(s, dv_set_max, 0); } } } @@ -838,19 +837,22 @@ void EMSdevice::generate_values_web_all(JsonArray & output) { obj["v"] = (divider > 0) ? time_value / divider : time_value * factor; // sometimes we need to divide by 60 } } + } else { + // must always have v for sorting to work in web + obj["v"] = ""; } - // add name, prefixing the tag if it exists + // add name, prefixing the tag if it exists as the id (key for table sorting) if (dv.full_name) { if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) { - obj["n"] = dv.full_name; + obj["id"] = dv.full_name; } else { char name[50]; snprintf(name, sizeof(name), "%s %s", tag_to_string(dv.tag).c_str(), read_flash_string(dv.full_name).c_str()); - obj["n"] = name; + obj["id"] = name; } } else { - obj["n"] = ""; + obj["id"] = ""; } // shortname diff --git a/src/emsesp.cpp b/src/emsesp.cpp index f2e8e93b8..4e37ee919 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -432,12 +432,12 @@ void EMSESP::show_sensor_values(uuid::console::Shell & shell) { (fahrenheit == 0) ? 'C' : 'F', COLOR_RESET, Helpers::render_value(s2, sensor.offset(), 10, fahrenheit), - sensor.id_str().c_str()); + sensor.id().c_str()); } else { shell.printfln(F(" %s (offset %s, ID: %s)"), sensor.name().c_str(), Helpers::render_value(s, sensor.offset(), 10, fahrenheit), - sensor.id_str().c_str()); + sensor.id().c_str()); } } shell.println(); diff --git a/src/system.cpp b/src/system.cpp index f2063415f..4eaa88ec0 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -1036,7 +1036,7 @@ bool System::command_customizations(const char * value, const int8_t id, JsonObj JsonArray sensorsJson = node.createNestedArray("sensors"); for (const auto & sensor : settings.sensorCustomizations) { JsonObject sensorJson = sensorsJson.createNestedObject(); - sensorJson["id_str"] = sensor.id_str; // key, is + sensorJson["id"] = sensor.id; // key sensorJson["name"] = sensor.name; // n sensorJson["offset"] = sensor.offset; // o } @@ -1044,7 +1044,7 @@ bool System::command_customizations(const char * value, const int8_t id, JsonObj JsonArray analogJson = node.createNestedArray("analogs"); for (const AnalogCustomization & sensor : settings.analogCustomizations) { JsonObject sensorJson = analogJson.createNestedObject(); - sensorJson["gpio"] = sensor.id; + sensorJson["gpio"] = sensor.gpio; sensorJson["name"] = sensor.name; if (EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX) { sensorJson["type"] = sensor.type; diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp index 3b01c0291..3a0afb88e 100644 --- a/src/web/WebCustomizationService.cpp +++ b/src/web/WebCustomizationService.cpp @@ -61,7 +61,7 @@ void WebCustomization::read(WebCustomization & settings, JsonObject & root) { JsonArray sensorsJson = root.createNestedArray("sensors"); for (const SensorCustomization & sensor : settings.sensorCustomizations) { JsonObject sensorJson = sensorsJson.createNestedObject(); - sensorJson["id_str"] = sensor.id_str; // is + sensorJson["id"] = sensor.id; // is sensorJson["name"] = sensor.name; // n sensorJson["offset"] = sensor.offset; // o } @@ -70,7 +70,7 @@ void WebCustomization::read(WebCustomization & settings, JsonObject & root) { JsonArray analogJson = root.createNestedArray("analogs"); for (const AnalogCustomization & sensor : settings.analogCustomizations) { JsonObject sensorJson = analogJson.createNestedObject(); - sensorJson["id"] = sensor.id; // i + sensorJson["gpio"] = sensor.gpio; // g sensorJson["name"] = sensor.name; // n sensorJson["offset"] = sensor.offset; // o sensorJson["factor"] = sensor.factor; // f @@ -101,7 +101,7 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & for (const JsonObject sensorJson : root["sensors"].as()) { // create each of the sensor, overwritting any previous settings auto sensor = SensorCustomization(); - sensor.id_str = sensorJson["id_str"].as(); + sensor.id = sensorJson["id"].as(); sensor.name = sensorJson["name"].as(); sensor.offset = sensorJson["offset"]; settings.sensorCustomizations.push_back(sensor); // add to list @@ -114,7 +114,7 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & for (const JsonObject analogJson : root["analogs"].as()) { // create each of the sensor, overwritting any previous settings auto sensor = AnalogCustomization(); - sensor.id = analogJson["id"]; + sensor.gpio = analogJson["gpio"]; sensor.name = analogJson["name"].as(); sensor.offset = analogJson["offset"]; sensor.factor = analogJson["factor"]; diff --git a/src/web/WebCustomizationService.h b/src/web/WebCustomizationService.h index 526259dbe..d595c1f43 100644 --- a/src/web/WebCustomizationService.h +++ b/src/web/WebCustomizationService.h @@ -35,14 +35,14 @@ namespace emsesp { // Customization for dallas sensor class SensorCustomization { public: - std::string id_str; + std::string id; std::string name; uint16_t offset; }; class AnalogCustomization { public: - uint8_t id; + uint8_t gpio; std::string name; float offset; float factor; @@ -51,7 +51,7 @@ class AnalogCustomization { // used for removing from a list bool operator==(const AnalogCustomization & a) const { - return id == a.id; + return gpio == a.gpio; } bool operator!=(const AnalogCustomization & a) const { return !operator==(a); diff --git a/src/web/WebDataService.cpp b/src/web/WebDataService.cpp index b4d61dc65..d1df1596e 100644 --- a/src/web/WebDataService.cpp +++ b/src/web/WebDataService.cpp @@ -76,17 +76,18 @@ void WebDataService::core_data(AsyncWebServerRequest * request) { // list is already sorted by device type // Ignore Contoller JsonArray devices = root.createNestedArray("devices"); + char buffer[3]; for (const auto & emsdevice : EMSESP::emsdevices) { if (emsdevice && (emsdevice->device_type() != EMSdevice::DeviceType::CONTROLLER || emsdevice->count_entities() > 0)) { JsonObject obj = devices.createNestedObject(); - obj["i"] = emsdevice->unique_id(); // a unique id - obj["t"] = emsdevice->device_type_name(); // type - obj["b"] = emsdevice->brand_to_string(); // brand - obj["n"] = emsdevice->name(); // name - obj["d"] = emsdevice->device_id(); // deviceid - obj["p"] = emsdevice->product_id(); // productid - obj["v"] = emsdevice->version(); // version - obj["e"] = emsdevice->count_entities(); // number of entities (device values) + obj["id"] = Helpers::smallitoa(buffer, emsdevice->unique_id()); // a unique id as a string + obj["t"] = emsdevice->device_type_name(); // type + obj["b"] = emsdevice->brand_to_string(); // brand + obj["n"] = emsdevice->name(); // name + obj["d"] = emsdevice->device_id(); // deviceid + obj["p"] = emsdevice->product_id(); // productid + obj["v"] = emsdevice->version(); // version + obj["e"] = emsdevice->count_entities(); // number of entities (device values) } } @@ -110,8 +111,8 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) { if (EMSESP::dallassensor_.have_sensors()) { for (const auto & sensor : EMSESP::dallassensor_.sensors()) { JsonObject obj = sensors.createNestedObject(); - obj["is"] = sensor.id_str(); // id - obj["n"] = sensor.name(); // name + obj["id"] = sensor.id(); // id as string + obj["n"] = sensor.name(); // name if (EMSESP::system_.fahrenheit()) { if (Helpers::hasValue(sensor.temperature_c)) { obj["t"] = (float)sensor.temperature_c * 0.18 + 32; @@ -129,14 +130,16 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) { } // analog sensors - // assume list is already sorted by id JsonArray analogs = root.createNestedArray("analogs"); if (EMSESP::analog_enabled() && EMSESP::analogsensor_.have_sensors()) { + uint8_t count = 0; + char buffer[3]; for (const auto & sensor : EMSESP::analogsensor_.sensors()) { // don't send if it's marked for removal if (sensor.type() != AnalogSensor::AnalogType::MARK_DELETED) { JsonObject obj = analogs.createNestedObject(); - obj["i"] = sensor.id(); + obj["id"] = Helpers::smallitoa(buffer, ++count); // needed for sorting table + obj["g"] = sensor.gpio(); obj["n"] = sensor.name(); obj["u"] = sensor.uom(); obj["o"] = sensor.offset(); @@ -145,6 +148,8 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) { if (sensor.type() != AnalogSensor::AnalogType::NOTUSED) { obj["v"] = Helpers::round2(sensor.value(), 0); // is optional and is a float + } else { + obj["v"] = 0; // must have a value for web sorting to work } } } @@ -169,6 +174,12 @@ void WebDataService::device_data(AsyncWebServerRequest * request, JsonVariant & #ifndef EMSESP_STANDALONE JsonObject output = response->getRoot(); emsdevice->generate_values_web(output); +#endif + +#ifdef EMSESP_USE_SERIAL +#ifdef EMSESP_DEBUG + serializeJson(output, Serial); +#endif #endif response->setLength(); request->send(response); @@ -246,8 +257,8 @@ void WebDataService::write_sensor(AsyncWebServerRequest * request, JsonVariant & if (json.is()) { JsonObject sensor = json; - std::string id_str = sensor["id_str"]; // this is the key - std::string name = sensor["name"]; + std::string id = sensor["id"]; // this is the key + std::string name = sensor["name"]; // calculate offset. We'll convert it to an int and * 10 float offset = sensor["offset"]; @@ -255,7 +266,7 @@ void WebDataService::write_sensor(AsyncWebServerRequest * request, JsonVariant & if (EMSESP::system_.fahrenheit()) { offset10 = offset / 0.18; } - ok = EMSESP::dallassensor_.update(id_str, name, offset10); + ok = EMSESP::dallassensor_.update(id, name, offset10); } AsyncWebServerResponse * response = request->beginResponse(ok ? 200 : 204); @@ -268,13 +279,13 @@ void WebDataService::write_analog(AsyncWebServerRequest * request, JsonVariant & if (json.is()) { JsonObject analog = json; - uint8_t id = analog["id"]; // this is the unique key + uint8_t gpio = analog["gpio"]; // this is the unique key, the GPIO std::string name = analog["name"]; float factor = analog["factor"]; float offset = analog["offset"]; uint8_t uom = analog["uom"]; int8_t type = analog["type"]; - ok = EMSESP::analogsensor_.update(id, name, offset, factor, uom, type); + ok = EMSESP::analogsensor_.update(gpio, name, offset, factor, uom, type); } AsyncWebServerResponse * response = request->beginResponse(ok ? 200 : 204);