diff --git a/interface/src/project/DashboardData.tsx b/interface/src/project/DashboardData.tsx index 36614e0f0..19047073c 100644 --- a/interface/src/project/DashboardData.tsx +++ b/interface/src/project/DashboardData.tsx @@ -59,7 +59,8 @@ import { DeviceValue, DeviceValueUOM, DeviceValueUOM_s, - AnalogTypes, + AnalogType, + AnalogTypeNames, Sensor, Analog } from './types'; @@ -715,7 +716,7 @@ const DashboardData: FC = () => { ))} - {analog.t === 3 && ( + {analog.t >= AnalogType.COUNTER && analog.t <= AnalogType.RATE && ( <> @@ -726,22 +727,37 @@ const DashboardData: FC = () => { ))} - - - mV - }} - /> - + {analog.t === AnalogType.ADC && ( + + mV + }} + /> + + )} + {analog.t === AnalogType.COUNTER && ( + + + + )} { )} + {analog.t === AnalogType.DIGITAL_OUT && (analog.i === 25 || analog.i === 26) && ( + <> + + + + + )} + {analog.t === AnalogType.DIGITAL_OUT && analog.i !== 25 && analog.i !== 26 && ( + <> + + + + + )} + {analog.t >= AnalogType.PWM_0 && ( + <> + + Hz + }} + /> + + + % + }} + + /> + + + )} Warning: be careful when assigning a GPIO! diff --git a/interface/src/project/types.ts b/interface/src/project/types.ts index 1c0871691..b5f3a9497 100644 --- a/interface/src/project/types.ts +++ b/interface/src/project/types.ts @@ -176,7 +176,9 @@ export enum DeviceValueUOM { DBM, FAHRENHEIT, MV, - SQM + SQM, + M3, + L } export const DeviceValueUOM_s = [ @@ -199,10 +201,36 @@ export const DeviceValueUOM_s = [ '°F', 'mV', 'sqm', - "o'clock" + "m3", + "l" +]; + +export enum AnalogType { + NOTUSED = 0, + DIGITAL_IN, + COUNTER, + ADC, + TIMER, + RATE, + DIGITAL_OUT, + PWM_0, + PWM_1, + PWM_2 +} + +export const AnalogTypeNames = [ + '(disabled)', + 'Digital in', + 'Counter', + 'ADC', + 'Timer', + 'Rate', + 'Digital out', + 'PWM 0', + 'PWM 1', + 'PWM 2' ]; -export const AnalogTypes = ['(disabled)', 'Digital in', 'Counter', 'ADC']; type BoardProfiles = { [name: string]: string; diff --git a/src/analogsensor.cpp b/src/analogsensor.cpp index 734b9e441..5ea7dffac 100644 --- a/src/analogsensor.cpp +++ b/src/analogsensor.cpp @@ -27,7 +27,7 @@ void AnalogSensor::start() { reload(); // fetch the list of sensors from our customization service if (analog_enabled_) { - analogSetAttenuation(ADC_2_5db); // for all channels + analogSetAttenuation(ADC_2_5db); // for all channels 1.5V } LOG_INFO(F("Starting Analog sensor service")); @@ -40,10 +40,15 @@ void AnalogSensor::start() { F_(info_cmd)); Command::add( EMSdevice::DeviceType::ANALOGSENSOR, - F_(counter), - [&](const char * value, const int8_t id) { return command_counter(value, id); }, - F("set counter value"), + F_(setvalue), + [&](const char * value, const int8_t id) { return command_setvalue(value, id); }, + F("set io value"), CommandFlag::ADMIN_ONLY); + Command::add( + EMSdevice::DeviceType::ANALOGSENSOR, + F_(commands), + [&](const char * value, const int8_t id, JsonObject & output) { return command_commands(value, id, output); }, + F_(commands_cmd)); } // load settings from the customization file, sorts them and initializes the GPIOs @@ -58,11 +63,47 @@ void AnalogSensor::reload() { // and store them locally and then activate them EMSESP::webCustomizationService.read([&](WebCustomization & settings) { auto sensors = settings.analogCustomizations; - sensors_.clear(); // start with an empty list - if (sensors.size() != 0) { - for (auto & sensor : sensors) { + auto it = sensors_.begin(); + for (auto & sensor_ : sensors_) { + // update existing sensors + bool found = false; + for (auto & sensor : sensors) { //search customlist + if (sensor_.id() == sensor.id) { + // for output sensors set value to new start-value + if ((sensor.type == AnalogType::COUNTER || sensor.type >= AnalogType::DIGITAL_OUT) + && (sensor_.type() != sensor.type || sensor_.offset() != sensor.offset || sensor_.factor() != sensor.factor)) { + sensor_.set_value(sensor.offset); + } + sensor_.set_name(sensor.name); + sensor_.set_type(sensor.type); + sensor_.set_offset(sensor.offset); + sensor_.set_factor(sensor.factor); + sensor_.set_uom(sensor.uom); + sensor_.ha_registered = false; + found = true; + } + } + if (!found) { + sensors_.erase(it); + } + it++; + } + // add new sensors from list + for (auto & sensor : sensors) { + bool found = false; + for (auto & sensor_ : sensors_) { + if (sensor_.id() == sensor.id) { + found = true; + } + } + if (!found) { sensors_.emplace_back(sensor.id, 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); + } else { + sensors_.back().set_value(0); // reset value only for new sensors + } } } return true; @@ -82,11 +123,21 @@ void AnalogSensor::reload() { } 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); - sensor.set_value(0); // reset count - sensor.set_uom(0); // no uom, just for safe measures + if (sensor.id() == 25 || sensor.id() == 26) { + dacWrite(sensor.id(), 255); + } sensor.polltime_ = 0; sensor.poll_ = digitalRead(sensor.id()); 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); + sensor.polltime_ = uuid::get_uptime(); + sensor.last_polltime_ = uuid::get_uptime(); + sensor.poll_ = digitalRead(sensor.id()); + 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); @@ -95,18 +146,49 @@ void AnalogSensor::reload() { sensor.polltime_ = 0; sensor.poll_ = digitalRead(sensor.id()); 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) { + if (sensor.offset() > 255) { + sensor.set_offset(255); + } else if (sensor.offset() < 0) { + sensor.set_offset(0); + } + dacWrite(sensor.id(), sensor.offset()); + sensor.set_value(sensor.offset()); + } else { + digitalWrite(sensor.id(), sensor.offset() > 0 ? 1 : 0); + sensor.set_value(digitalRead(sensor.id())); + } + 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()); + uint channel = sensor.type() - AnalogType::PWM_0; + ledcSetup(channel, sensor.factor(), 13); + ledcAttachPin(sensor.id(), channel); + if (sensor.offset() > 100) { + sensor.set_offset(100); + } else if (sensor.offset() < 0) { + sensor.set_offset(0); + } + ledcWrite(channel, (uint32_t)(sensor.offset() * 8191 / 100)); + sensor.set_value(sensor.offset()); + sensor.set_uom(DeviceValueUOM::PERCENT); + publish_sensor(sensor); } } } -// measure and moving average adc +// measure input sensors and moving average adc void AnalogSensor::measure() { static uint32_t measure_last_ = 0; - // measure interval 500ms for analog sensors + // measure interval 500ms for adc sensors if (!measure_last_ || (uuid::get_uptime() - measure_last_) >= MEASURE_ANALOG_INTERVAL) { measure_last_ = uuid::get_uptime(); - // go through the list of ADC sensors + // 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 @@ -128,34 +210,38 @@ void AnalogSensor::measure() { } } } - // poll digital io every time + // poll digital io every time with debounce // go through the list of digital sensors for (auto & sensor : sensors_) { - if (sensor.type() == AnalogType::DIGITAL_IN || sensor.type() == AnalogType::COUNTER) { + 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()); - if (sensor.poll_ != current_reading) { // check for pinchange - sensor.polltime_ = uuid::get_uptime(); + if (sensor.poll_ != current_reading) { // check for pinchange + sensor.polltime_ = uuid::get_uptime(); // remember time of pinchange sensor.poll_ = current_reading; } - if (uuid::get_uptime() - sensor.polltime_ >= 15) { // debounce + // debounce and check for real pinchange + if (uuid::get_uptime() - sensor.polltime_ >= 15 && sensor.poll_ != sensor.last_reading_) { + sensor.last_reading_ = sensor.poll_; if (sensor.type() == AnalogType::DIGITAL_IN) { sensor.set_value(sensor.poll_); - } else if (sensor.type() == AnalogType::COUNTER) { - // capture reading and compare with the last one to see if there is high/low change - if (sensor.poll_ != sensor.last_reading_) { - sensor.last_reading_ = sensor.poll_; - if (!sensor.poll_) { - sensor.set_value(old_value + 1); - } + } else if (!sensor.poll_) { // falling edge + if (sensor.type() == AnalogType::COUNTER) { + sensor.set_value(old_value + sensor.factor()); + } else if (sensor.type() == AnalogType::RATE) { // dafault uom: Hz (1/sec) with factor 1 + sensor.set_value(sensor.factor() * 1000 / (sensor.polltime_ - sensor.last_polltime_)); + } else if (sensor.type() == AnalogType::TIMER) { // default seconds with factor 1 + sensor.set_value(sensor.factor() * (sensor.polltime_ - sensor.last_polltime_) / 1000); } + sensor.last_polltime_ = sensor.polltime_; } - // see if there is a change and increment # reads - if (old_value != sensor.value()) { - sensorreads_++; - changed_ = true; - publish_sensor(sensor); - } + } + // see if there is a change and increment # reads + if (old_value != sensor.value()) { + sensorreads_++; + changed_ = true; + publish_sensor(sensor); } } } @@ -170,7 +256,7 @@ void AnalogSensor::loop() { } // update analog information name and offset -bool AnalogSensor::update(uint8_t id, const std::string & name, uint16_t offset, float factor, uint8_t uom, int8_t type) { +bool AnalogSensor::update(uint8_t id, 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( @@ -240,7 +326,11 @@ bool AnalogSensor::updated_values() { void AnalogSensor::publish_sensor(const Sensor & sensor) { if (Mqtt::publish_single()) { char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; - snprintf(topic, sizeof(topic), "%s/%s", read_flash_string(F_(analogsensor)).c_str(), sensor.name().c_str()); + if (Mqtt::publish_single2cmd()) { + snprintf(topic, sizeof(topic), "%s/%s", read_flash_string(F_(analogsensor)).c_str(), sensor.name().c_str()); + } else { + snprintf(topic, sizeof(topic), "%s%s/%s", read_flash_string(F_(analogsensor)).c_str(), "_data", sensor.name().c_str()); + } char payload[10]; Mqtt::publish(topic, Helpers::render_value(payload, sensor.value(), 2)); // always publish as floats } @@ -285,12 +375,16 @@ void AnalogSensor::publish_values(const bool force) { dataSensor["name"] = sensor.name(); switch (sensor.type()) { case AnalogType::COUNTER: - dataSensor["value"] = (uint16_t)sensor.value(); // convert to integer - break; + case AnalogType::TIMER: + case AnalogType::RATE: case AnalogType::ADC: + case AnalogType::PWM_0: + case AnalogType::PWM_1: + case AnalogType::PWM_2: dataSensor["value"] = (float)sensor.value(); // float break; case AnalogType::DIGITAL_IN: + case AnalogType::DIGITAL_OUT: default: dataSensor["value"] = (uint8_t)sensor.value(); // convert to char for 1 or 0 break; @@ -373,6 +467,15 @@ bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject dataSensor["uom"] = EMSdevice::uom_to_string(sensor.uom()); dataSensor["offset"] = sensor.offset(); dataSensor["factor"] = sensor.factor(); + } else if (sensor.type() == AnalogType::COUNTER) { + dataSensor["uom"] = EMSdevice::uom_to_string(sensor.uom()); + dataSensor["start_value"] = sensor.offset(); + dataSensor["factor"] = sensor.factor(); + } else if (sensor.type() == AnalogType::TIMER || sensor.type() == AnalogType::RATE) { + dataSensor["factor"] = sensor.factor(); + } else if (sensor.type() >= AnalogType::PWM_0) { + dataSensor["uom"] = EMSdevice::uom_to_string(sensor.uom()); + dataSensor["frequency"] = sensor.factor(); } dataSensor["value"] = sensor.value(); } else { @@ -384,7 +487,7 @@ 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 uint16_t offset, const float factor, const uint8_t uom, const int8_t type) +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) , name_(name) , offset_(offset) @@ -405,28 +508,70 @@ std::string AnalogSensor::Sensor::name() const { } // set the counter value, id is gpio-no -bool AnalogSensor::command_counter(const char * value, const int8_t id) { - int val; - if (!Helpers::value2number(value, val)) { +bool AnalogSensor::command_setvalue(const char * value, const int8_t id) { + float val; + if (!Helpers::value2float(value, val)) { return false; } for (auto & sensor : sensors_) { - if (sensor.type() == AnalogType::COUNTER && sensor.id() == id) { - if (val < 0) { // negative values corrects - sensor.set_value(sensor.value() + val); - } else { // positive values are set + if (sensor.id() == id) { + if (sensor.type() == AnalogType::COUNTER) { + if (val < 0 || value[0] == '+') { // sign corrects values + sensor.set_offset(sensor.value() + val); + sensor.set_value(sensor.value() + val); + } else { // positive values are set + sensor.set_offset(val); + sensor.set_value(val); + } + publish_sensor(sensor); + return true; + } else if (sensor.type() == AnalogType::ADC) { + sensor.set_offset(val); + return true; + } else if (sensor.type() == AnalogType::DIGITAL_OUT) { + uint8_t v = val; + if ((sensor.id() == 25 || sensor.id() == 26) && v <= 255) { + sensor.set_offset(v); + sensor.set_value(v); + pinMode(sensor.id(), OUTPUT); + dacWrite(sensor.id(), 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); + publish_sensor(sensor); + return true; + } + } else if (sensor.type() >= AnalogType::PWM_0) { + uint8_t channel = sensor.type() - AnalogType::PWM_0; + if (val > 100) { + val = 100; + } else if (val < 0) { + val = 0; + } + sensor.set_offset(val); sensor.set_value(val); + ledcWrite(channel, (uint32_t)(val * 8191 / 100)); + publish_sensor(sensor); + return true; } - return true; } } return false; } +// list commands +bool AnalogSensor::command_commands(const char * value, const int8_t id, JsonObject & output) { + return Command::list(EMSdevice::DeviceType::ANALOGSENSOR, output); +} + // hard coded tests #ifdef EMSESP_DEBUG void AnalogSensor::test() { - // Sensor(const uint8_t id, const std::string & name, const uint16_t offset, const float factor, const uint8_t uom, const int8_t type); + // Sensor(const uint8_t id, const std::string & name, const float offset, const float factor, const uint8_t uom, const int8_t type); sensors_.emplace_back(36, "test12", 0, 0.1, 17, AnalogType::ADC); sensors_.back().set_value(12.4); diff --git a/src/analogsensor.h b/src/analogsensor.h index 70e94fd95..e48acd7e9 100644 --- a/src/analogsensor.h +++ b/src/analogsensor.h @@ -36,10 +36,10 @@ class AnalogSensor { public: class Sensor { public: - Sensor(const uint8_t id, const std::string & name, const uint16_t offset, const float factor, const uint8_t uom, const int8_t type); + Sensor(const uint8_t id, const std::string & name, const float offset, const float factor, const uint8_t uom, const int8_t type); ~Sensor() = default; - void set_offset(const uint16_t offset) { + void set_offset(const float offset) { offset_ = offset; } @@ -68,7 +68,7 @@ class AnalogSensor { factor_ = factor; } - uint16_t offset() const { + float offset() const { return offset_; } @@ -90,16 +90,18 @@ class AnalogSensor { bool ha_registered = false; - uint16_t analog_ = 0; // ADC - average value - uint32_t sum_ = 0; // ADC - rolling sum - uint16_t last_reading_ = 0; // IO COUNTER & ADC - last reading - uint32_t polltime_ = 0; // digital IO & COUNTER debounce time - int poll_ = 0; + uint16_t analog_ = 0; // ADC - average value + uint32_t sum_ = 0; // ADC - rolling sum + uint16_t last_reading_ = 0; // IO COUNTER & ADC - last reading + uint16_t count_ = 0; // counter raw counts + uint32_t polltime_ = 0; // digital IO & COUNTER debounce time + int poll_ = 0; + uint32_t last_polltime_ = 0; // for timer private: uint8_t id_; std::string name_; - uint16_t offset_; + float offset_; float factor_; uint8_t uom_; float value_; // float because of the factor is a float @@ -112,9 +114,15 @@ class AnalogSensor { enum AnalogType : int8_t { MARK_DELETED = -1, // mark for deletion NOTUSED, // 0 - disabled - DIGITAL_IN, // 1 - COUNTER, // 2 - ADC // 3 + DIGITAL_IN, + COUNTER, + ADC, + TIMER, + RATE, + DIGITAL_OUT, + PWM_0, + PWM_1, + PWM_2 }; void start(); @@ -149,7 +157,7 @@ class AnalogSensor { return sensors_.size(); } - bool update(uint8_t id, const std::string & name, uint16_t offset, float factor, uint8_t uom, int8_t type); + bool update(uint8_t id, 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); #ifdef EMSESP_DEBUG @@ -163,9 +171,10 @@ class AnalogSensor { static uuid::log::Logger logger_; void remove_ha_topic(const uint8_t id); - bool command_counter(const char * value, const int8_t id); + bool command_setvalue(const char * value, const int8_t id); void measure(); bool command_info(const char * value, const int8_t id, JsonObject & output); + bool command_commands(const char * value, const int8_t id, JsonObject & output); std::vector sensors_; // our list of sensors diff --git a/src/emsdevicevalue.h b/src/emsdevicevalue.h index a9b4b029c..c6bf629b6 100644 --- a/src/emsdevicevalue.h +++ b/src/emsdevicevalue.h @@ -66,7 +66,9 @@ class DeviceValue { DBM, // 15 FAHRENHEIT, // 16 MV, // 17 - SQM // 18 + SQM, // 18 squaremeter + M3, // 19 cubic meter + L // 20 }; // TAG mapping - maps to DeviceValueTAG_s in emsdevice.cpp diff --git a/src/helpers.cpp b/src/helpers.cpp index 343b5a01a..0f9b339f3 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -526,6 +526,10 @@ bool Helpers::value2float(const char * v, float & value) { value = atof((char *)v); return true; } + if (v[0] == '+' && (v[1] == '.' || (v[1] >= '0' && v[1] <= '9'))) { + value = atof((char *)(v + 1)); + return true; + } return false; } diff --git a/src/locale_DE.h b/src/locale_DE.h index 82345d198..c57701bfd 100644 --- a/src/locale_DE.h +++ b/src/locale_DE.h @@ -70,7 +70,7 @@ MAKE_PSTR_WORD(pin) MAKE_PSTR_WORD(publish) MAKE_PSTR_WORD(timeout) MAKE_PSTR_WORD(board_profile) -MAKE_PSTR_WORD(counter) +MAKE_PSTR_WORD(setvalue) // for commands MAKE_PSTR_WORD(call) @@ -121,7 +121,7 @@ MAKE_STR(productid_fmt, "%s EMS ProductID") MAKE_PSTR_LIST(enum_syslog_level, F_(off), F("emerg"), F("alert"), F("crit"), F_(error), F("warn"), F("notice"), F_(info), F_(debug), F("trace"), F("all")) MAKE_PSTR_LIST(enum_watch, F_(off), F_(on), F_(raw), F_(unknown)) -MAKE_PSTR_LIST(enum_sensortype, F("none"), F("digital in"), F("counter"), F("adc")) +MAKE_PSTR_LIST(enum_sensortype, F("none"), F("digital in"), F("counter"), F("adc"), F("timer"), F("rate"), F("digital out"), F("pwm 0"), F("pwm 1"), F("pwm 2")) // strings MAKE_PSTR(EMSESP, "EMS-ESP") @@ -196,6 +196,8 @@ MAKE_PSTR(dbm, "dBm") MAKE_PSTR(fahrenheit, "°F") MAKE_PSTR(mv, "mV") MAKE_PSTR(sqm, "sqm") +MAKE_PSTR(m3, "m3") +MAKE_PSTR(l, "l") // MAKE_PSTR(times, "mal") // MAKE_PSTR(oclock, "Uhr") @@ -585,6 +587,9 @@ MAKE_PSTR_LIST(mode, F("mode"), F("modus")) MAKE_PSTR_LIST(modetype, F("modetype"), F("modus Typ")) MAKE_PSTR_LIST(fastheatup, F("fastheatup"), F("fast heatup")) MAKE_PSTR_LIST(daytemp, F("daytemp"), F("Tagestemperatur")) +MAKE_PSTR_LIST(daylowtemp, F("daytemp2"), F("Tagestemperatur T2")) +MAKE_PSTR_LIST(daymidtemp, F("daytemp3"), F("Tagestemperatur T3")) +MAKE_PSTR_LIST(dayhightemp, F("daytemp4"), F("Tagestemperatur T4")) MAKE_PSTR_LIST(heattemp, F("heattemp"), F("Heizen Temperatur")) MAKE_PSTR_LIST(nighttemp, F("nighttemp"), F("Nachttemperatur")) MAKE_PSTR_LIST(ecotemp, F("ecotemp"), F("eco Temperatur")) @@ -597,7 +602,8 @@ MAKE_PSTR_LIST(offsettemp, F("offsettemp"), F("Temperaturanhebung")) MAKE_PSTR_LIST(minflowtemp, F("minflowtemp"), F("min Flusstemperatur")) MAKE_PSTR_LIST(maxflowtemp, F("maxflowtemp"), F("max Flusstemperatur")) MAKE_PSTR_LIST(roominfluence, F("roominfluence"), F("Raumeinfluss")) -MAKE_PSTR_LIST(curroominfl, F("curroominfl"), F("current room influence")) +MAKE_PSTR_LIST(roominfl_factor, F("roominflfactor"), F("Raumeinfluss Factor")) +MAKE_PSTR_LIST(curroominfl, F("curroominfl"), F("aktueller Raumeinfluss")) MAKE_PSTR_LIST(nofrosttemp, F("nofrosttemp"), F("Frostschutztemperatur")) MAKE_PSTR_LIST(targetflowtemp, F("targetflowtemp"), F("berechnete Flusstemperatur")) MAKE_PSTR_LIST(heatingtype, F("heatingtype"), F("Heizungstyp")) diff --git a/src/locale_EN.h b/src/locale_EN.h index 0afdb0b1b..e6908a12c 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -70,7 +70,7 @@ MAKE_PSTR_WORD(pin) MAKE_PSTR_WORD(publish) MAKE_PSTR_WORD(timeout) MAKE_PSTR_WORD(board_profile) -MAKE_PSTR_WORD(counter) +MAKE_PSTR_WORD(setvalue) // for commands MAKE_PSTR_WORD(call) @@ -121,7 +121,7 @@ MAKE_STR(productid_fmt, "%s EMS ProductID") MAKE_PSTR_LIST(enum_syslog_level, F_(off), F("emerg"), F("alert"), F("crit"), F_(error), F("warn"), F("notice"), F_(info), F_(debug), F("trace"), F("all")) MAKE_PSTR_LIST(enum_watch, F_(off), F_(on), F_(raw), F_(unknown)) -MAKE_PSTR_LIST(enum_sensortype, F("none"), F("digital in"), F("counter"), F("adc")) +MAKE_PSTR_LIST(enum_sensortype, F("none"), F("digital in"), F("counter"), F("adc"), F("timer"), F("rate"), F("digital out"), F("pwm 0"), F("pwm 1"), F("pwm 2")) // strings MAKE_PSTR(EMSESP, "EMS-ESP") @@ -196,6 +196,8 @@ MAKE_PSTR(dbm, "dBm") MAKE_PSTR(fahrenheit, "°F") MAKE_PSTR(mv, "mV") MAKE_PSTR(sqm, "sqm") +MAKE_PSTR(m3, "m3") +MAKE_PSTR(l, "l") // MAKE_PSTR(times, "times") // MAKE_PSTR(oclock, "o'clock") diff --git a/src/system.cpp b/src/system.cpp index 6b56724a9..d05dffb29 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -73,18 +73,18 @@ bool System::command_pin(const char * value, const int8_t id) { } else if (Helpers::value2bool(value, v)) { pinMode(id, OUTPUT); digitalWrite(id, v); - LOG_INFO(F("GPIO %d set to %s"), id, v ? "HIGH" : "LOW"); + // LOG_INFO(F("GPIO %d set to %s"), id, v ? "HIGH" : "LOW"); return true; } else if (Helpers::value2string(value, v1)) { if (v1 == "input" || v1 == "in" || v1 == "-1") { pinMode(id, INPUT); v = digitalRead(id); - LOG_INFO(F("GPIO %d set input, state %s"), id, v ? "HIGH" : "LOW"); + // LOG_INFO(F("GPIO %d set input, state %s"), id, v ? "HIGH" : "LOW"); return true; } } - LOG_INFO(F("GPIO %d: invalid value"), id); + // LOG_INFO(F("GPIO %d: invalid value"), id); #endif return false; @@ -162,13 +162,19 @@ bool System::command_publish(const char * value, const int8_t id) { bool System::command_syslog_level(const char * value, const int8_t id) { uint8_t s = 0xff; if (Helpers::value2enum(value, s, FL_(enum_syslog_level))) { + bool changed = false; EMSESP::webSettingsService.update( [&](WebSettings & settings) { - settings.syslog_level = (int8_t)s - 1; + if (settings.syslog_level != (int8_t)s - 1) { + settings.syslog_level = (int8_t)s - 1; + changed = true; + } return StateUpdateResult::CHANGED; }, "local"); - EMSESP::system_.syslog_init(); + if (changed) { + EMSESP::system_.syslog_init(); + } return true; } return false; @@ -176,29 +182,35 @@ bool System::command_syslog_level(const char * value, const int8_t id) { // watch bool System::command_watch(const char * value, const int8_t id) { - uint8_t w = 0xff; + uint8_t w = 0xff; + uint16_t i = Helpers::hextoint(value); if (Helpers::value2enum(value, w, FL_(enum_watch))) { if (w == 0 || EMSESP::watch() == EMSESP::Watch::WATCH_OFF) { EMSESP::watch_id(0); } - EMSESP::watch(w); - if (Mqtt::publish_single()) { - Mqtt::publish(F("system/watch"), read_flash_string(FL_(enum_watch)[w]).c_str()); + if (Mqtt::publish_single() && w != EMSESP::watch()) { + if (Mqtt::publish_single2cmd()) { + Mqtt::publish(F("system/watch"), + EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(w) : read_flash_string(FL_(enum_watch)[w]).c_str()); + } else { + Mqtt::publish(F("system_data/watch"), + EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(w) : read_flash_string(FL_(enum_watch)[w]).c_str()); + } } + EMSESP::watch(w); return true; - } - uint16_t i = Helpers::hextoint(value); - if (i) { + } else if (i) { + if (Mqtt::publish_single() && i != EMSESP::watch_id()) { + if (Mqtt::publish_single2cmd()) { + Mqtt::publish(F("system/watch"), Helpers::hextoa(i)); + } else { + Mqtt::publish(F("system_data/watch"), Helpers::hextoa(i)); + } + } EMSESP::watch_id(i); if (EMSESP::watch() == EMSESP::Watch::WATCH_OFF) { EMSESP::watch(EMSESP::Watch::WATCH_ON); } - if (Mqtt::publish_single()) { - char s[10]; - snprintf(s, sizeof(s), "0x%04X", i); - Mqtt::publish(F("system/watch"), s); - // Mqtt::publish(F("system/watch"), read_flash_string(FL_(enum_watch)[EMSESP::watch()]).c_str()); - } return true; } return false; @@ -273,13 +285,25 @@ void System::syslog_init() { } if (Mqtt::publish_single()) { - Mqtt::publish(F("system/syslog"), syslog_enabled_ ? read_flash_string(FL_(enum_syslog_level)[syslog_level_ + 1]).c_str() : "off"); - if (EMSESP::watch_id() == 0 || EMSESP::watch() == 0) { - Mqtt::publish(F("system/watch"), read_flash_string(FL_(enum_watch)[EMSESP::watch()]).c_str()); + if (Mqtt::publish_single2cmd()) { + Mqtt::publish(F("system/syslog"), syslog_enabled_ ? read_flash_string(FL_(enum_syslog_level)[syslog_level_ + 1]).c_str() : "off"); + if (EMSESP::watch_id() == 0 || EMSESP::watch() == 0) { + Mqtt::publish(F("system/watch"), + EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(EMSESP::watch()) + : read_flash_string(FL_(enum_watch)[EMSESP::watch()]).c_str()); + } else { + Mqtt::publish(F("system/watch"), Helpers::hextoa(EMSESP::watch_id())); + } + } else { - char s[10]; - snprintf(s, sizeof(s), "0x%04X", EMSESP::watch_id()); - Mqtt::publish(F("system/watch"), s); + Mqtt::publish(F("system_data/syslog"), syslog_enabled_ ? read_flash_string(FL_(enum_syslog_level)[syslog_level_ + 1]).c_str() : "off"); + if (EMSESP::watch_id() == 0 || EMSESP::watch() == 0) { + Mqtt::publish(F("system_data/watch"), + EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX ? Helpers::itoa(EMSESP::watch()) + : read_flash_string(FL_(enum_watch)[EMSESP::watch()]).c_str()); + } else { + Mqtt::publish(F("system_data/watch"), Helpers::hextoa(EMSESP::watch_id())); + } } } #endif @@ -524,7 +548,7 @@ bool System::heartbeat_json(JsonObject & output) { output["txfails"] = EMSESP::txservice_.telegram_read_fail_count() + EMSESP::txservice_.telegram_write_fail_count(); if (Mqtt::enabled()) { - output["mqttfails"] = Mqtt::publish_fails(); + output["mqttcount"] = Mqtt::publish_count(); output["mqttfails"] = Mqtt::publish_fails(); } output["apicalls"] = WebAPIService::api_count(); // + WebAPIService::api_fails(); @@ -636,16 +660,12 @@ void System::system_check() { // commands - takes static function pointers void System::commands_init() { - Command::add(EMSdevice::DeviceType::SYSTEM, - F_(pin), - System::command_pin, - F("set a GPIO on/off"), - CommandFlag::MQTT_SUB_FLAG_NOSUB | CommandFlag::ADMIN_ONLY); // dont create a MQTT topic for this - + // Command::add(EMSdevice::DeviceType::SYSTEM, F_(pin), System::command_pin, F("set a GPIO on/off"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send, F("send a telegram"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch, F("refresh all EMS values"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, F("restart EMS-ESP"), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, F("watch incoming telegrams")); + // register syslog command in syslog init // Command::add(EMSdevice::DeviceType::SYSTEM, F_(syslog), System::command_syslog_level, F("set syslog level"), CommandFlag::ADMIN_ONLY); if (Mqtt::enabled()) { @@ -822,7 +842,7 @@ void System::show_system(uuid::console::Shell & shell) { // show Ethernet if connected if (ethernet_connected_) { shell.println(); - shell.printfln(F(" Wired Network: connected")); + shell.printfln(F(" Ethernet Network: connected")); shell.printfln(F(" MAC address: %s"), ETH.macAddress().c_str()); shell.printfln(F(" Hostname: %s"), ETH.getHostname()); shell.printfln(F(" IPv4 address: %s/%s"), uuid::printable_to_string(ETH.localIP()).c_str(), uuid::printable_to_string(ETH.subnetMask()).c_str()); @@ -1021,6 +1041,13 @@ bool System::command_customizations(const char * value, const int8_t id, JsonObj sensorJson["offset"] = sensor.offset; sensorJson["factor"] = sensor.factor; sensorJson["uom"] = EMSdevice::uom_to_string(sensor.uom); + } else if (sensor.type == AnalogSensor::AnalogType::COUNTER || sensor.type == AnalogSensor::AnalogType::TIMER + || sensor.type == AnalogSensor::AnalogType::RATE) { + sensorJson["factor"] = sensor.factor; + sensorJson["uom"] = EMSdevice::uom_to_string(sensor.uom); + } else if (sensor.type >= AnalogSensor::AnalogType::PWM_0) { + sensorJson["frequency"] = sensor.factor; + sensorJson["factor"] = sensor.factor; } } @@ -1154,10 +1181,14 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp for (const auto & device_class : EMSFactory::device_handlers()) { for (const auto & emsdevice : EMSESP::emsdevices) { if ((emsdevice) && (emsdevice->device_type() == device_class.first)) { - JsonObject obj = devices.createNestedObject(); - obj["type"] = emsdevice->device_type_name(); - obj["name"] = emsdevice->to_string(); - obj["entities"] = emsdevice->count_entities(); + JsonObject obj = devices.createNestedObject(); + obj["type"] = emsdevice->device_type_name(); + // obj["name"] = emsdevice->to_string(); + obj["name"] = emsdevice->name(); + obj["device id"] = Helpers::hextoa(emsdevice->device_id()); + obj["product id"] = emsdevice->product_id(); + obj["version"] = emsdevice->version(); + obj["entities"] = emsdevice->count_entities(); char result[200]; (void)emsdevice->show_telegram_handlers(result, EMSdevice::Handlers::RECEIVED); if (result[0] != '\0') { diff --git a/src/web/WebCustomizationService.h b/src/web/WebCustomizationService.h index 5371e74bb..b2bd869da 100644 --- a/src/web/WebCustomizationService.h +++ b/src/web/WebCustomizationService.h @@ -44,7 +44,7 @@ class AnalogCustomization { public: uint8_t id; std::string name; - uint16_t offset; + float offset; float factor; uint8_t uom; // 0 is none int8_t type; // -1 is for deletion diff --git a/src/web/WebDataService.cpp b/src/web/WebDataService.cpp index a012c2d35..85989b9c7 100644 --- a/src/web/WebDataService.cpp +++ b/src/web/WebDataService.cpp @@ -275,7 +275,7 @@ void WebDataService::write_analog(AsyncWebServerRequest * request, JsonVariant & uint8_t id = analog["id"]; // this is the unique key std::string name = analog["name"]; float factor = analog["factor"]; - int16_t offset = analog["offset"]; + float offset = analog["offset"]; uint8_t uom = analog["uom"]; int8_t type = analog["type"]; ok = EMSESP::analogsensor_.update(id, name, offset, factor, uom, type);