mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-01-26 08:39:09 +03:00
Compare commits
11 Commits
79089a93bc
...
f8cc688241
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8cc688241 | ||
|
|
f51b3528d5 | ||
|
|
42c94a1017 | ||
|
|
acccb56f07 | ||
|
|
3a2d3ac985 | ||
|
|
0ab18e6e08 | ||
|
|
44db5991e7 | ||
|
|
15a6c50326 | ||
|
|
911aa40ca1 | ||
|
|
2b679daabc | ||
|
|
71b956e613 |
@@ -62,10 +62,10 @@
|
|||||||
"prettier": "^3.7.4",
|
"prettier": "^3.7.4",
|
||||||
"rollup-plugin-visualizer": "^6.0.5",
|
"rollup-plugin-visualizer": "^6.0.5",
|
||||||
"terser": "^5.44.1",
|
"terser": "^5.44.1",
|
||||||
"typescript-eslint": "^8.49.0",
|
"typescript-eslint": "^8.50.0",
|
||||||
"vite": "^7.2.7",
|
"vite": "^7.3.0",
|
||||||
"vite-plugin-imagemin": "^0.6.1",
|
"vite-plugin-imagemin": "^0.6.1",
|
||||||
"vite-tsconfig-paths": "^5.1.4"
|
"vite-tsconfig-paths": "^6.0.1"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.25.0+sha512.5e82639027af37cf832061bcc6d639c219634488e0f2baebe785028a793de7b525ffcd3f7ff574f5e9860654e098fe852ba8ac5dd5cefe1767d23a020a92f501"
|
"packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402"
|
||||||
}
|
}
|
||||||
|
|||||||
580
interface/pnpm-lock.yaml
generated
580
interface/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -15,5 +15,5 @@
|
|||||||
"itty-router": "^5.0.22",
|
"itty-router": "^5.0.22",
|
||||||
"prettier": "^3.7.4"
|
"prettier": "^3.7.4"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.25.0+sha512.5e82639027af37cf832061bcc6d639c219634488e0f2baebe785028a793de7b525ffcd3f7ff574f5e9860654e098fe852ba8ac5dd5cefe1767d23a020a92f501"
|
"packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ board_build.filesystem = littlefs
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson @ 7.4.2
|
bblanchon/ArduinoJson @ 7.4.2
|
||||||
ESP32Async/AsyncTCP @ 3.4.9
|
ESP32Async/AsyncTCP @ 3.4.9
|
||||||
ESP32Async/ESPAsyncWebServer @ 3.9.2
|
ESP32Async/ESPAsyncWebServer @ 3.9.3
|
||||||
https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
|
https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
|
||||||
|
|
||||||
|
|
||||||
@@ -181,7 +181,8 @@ build_flags =
|
|||||||
${common.build_flags}
|
${common.build_flags}
|
||||||
-DBOARD_C6
|
-DBOARD_C6
|
||||||
|
|
||||||
; foundation for building and testing natively, standalone without an ESP32.
|
; foundation for building and testing natively, standalone without an ESP32
|
||||||
|
; use the `standalone` environment instead of `native` for testing
|
||||||
[env:native]
|
[env:native]
|
||||||
platform = native
|
platform = native
|
||||||
build_type = debug
|
build_type = debug
|
||||||
|
|||||||
@@ -112,6 +112,12 @@ void AnalogSensor::reload(bool get_nvs) {
|
|||||||
for (auto sensor : sensors_) {
|
for (auto sensor : sensors_) {
|
||||||
remove_ha_topic(sensor.type(), sensor.gpio());
|
remove_ha_topic(sensor.type(), sensor.gpio());
|
||||||
sensor.ha_registered = false;
|
sensor.ha_registered = false;
|
||||||
|
#ifndef EMSESP_STANDALONE
|
||||||
|
if ((sensor.type() >= AnalogType::CNT_0 && sensor.type() <= AnalogType::CNT_2)
|
||||||
|
|| (sensor.type() >= AnalogType::FREQ_0 && sensor.type() <= AnalogType::FREQ_2)) {
|
||||||
|
detachInterrupt(sensor.gpio());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!analog_enabled_) {
|
if (!analog_enabled_) {
|
||||||
@@ -669,26 +675,27 @@ void AnalogSensor::publish_values(const bool force) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
|
JsonObject obj = doc.to<JsonObject>();
|
||||||
|
|
||||||
for (auto & sensor : sensors_) {
|
for (auto & sensor : sensors_) {
|
||||||
if (Mqtt::is_nested()) {
|
if (Mqtt::is_nested()) {
|
||||||
char s[10];
|
char s[10];
|
||||||
JsonObject dataSensor = doc[Helpers::smallitoa(s, sensor.gpio())].to<JsonObject>();
|
JsonObject dataSensor = obj[Helpers::smallitoa(s, sensor.gpio())].to<JsonObject>();
|
||||||
dataSensor["name"] = sensor.name();
|
dataSensor["name"] = sensor.name();
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
if (sensor.type() == AnalogType::PULSE || (sensor.type() == AnalogType::DIGITAL_OUT && sensor.gpio() != 25 && sensor.gpio() != 26)) {
|
if (sensor.type() == AnalogType::PULSE || (sensor.type() == AnalogType::DIGITAL_OUT && sensor.gpio() != 25 && sensor.gpio() != 26)) {
|
||||||
#else
|
#else
|
||||||
if (sensor.type() == AnalogType::PULSE || sensor.type() == AnalogType::DIGITAL_OUT) {
|
if (sensor.type() == AnalogType::PULSE || sensor.type() == AnalogType::DIGITAL_OUT) {
|
||||||
#endif
|
#endif
|
||||||
Mqtt::add_value_bool(doc.as<JsonObject>(), sensor.name(), sensor.value() != 0);
|
Mqtt::add_value_bool(dataSensor, "value", sensor.value() != 0);
|
||||||
} else {
|
} else {
|
||||||
dataSensor["value"] = serialized(Helpers::render_value(s, sensor.value(), 2)); // double
|
dataSensor["value"] = serialized(Helpers::render_value(s, sensor.value(), 2)); // double
|
||||||
}
|
}
|
||||||
} else if (sensor.type() == AnalogType::DIGITAL_IN || sensor.type() == AnalogType::DIGITAL_OUT || sensor.type() == AnalogType::PULSE) {
|
} else if (sensor.type() == AnalogType::DIGITAL_IN || sensor.type() == AnalogType::DIGITAL_OUT || sensor.type() == AnalogType::PULSE) {
|
||||||
Mqtt::add_value_bool(doc.as<JsonObject>(), sensor.name(), sensor.value() != 0);
|
Mqtt::add_value_bool(obj, (const char *)sensor.name(), sensor.value() != 0);
|
||||||
} else {
|
} else {
|
||||||
char s[10];
|
char s[10];
|
||||||
doc[sensor.name()] = serialized(Helpers::render_value(s, sensor.value(), 2));
|
obj[sensor.name()] = serialized(Helpers::render_value(s, sensor.value(), 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// create HA config if hasn't already been done
|
// create HA config if hasn't already been done
|
||||||
@@ -798,7 +805,7 @@ void AnalogSensor::publish_values(const bool force) {
|
|||||||
|
|
||||||
// add default_entity_id
|
// add default_entity_id
|
||||||
std::string topic_str(topic);
|
std::string topic_str(topic);
|
||||||
doc["def_ent_id"] = topic_str.substr(0, topic_str.find("/")) + "." + uniq_s;
|
config["def_ent_id"] = topic_str.substr(0, topic_str.find("/")) + "." + uniq_s;
|
||||||
|
|
||||||
Mqtt::add_ha_avty_section(config.as<JsonObject>(), stat_t, val_cond);
|
Mqtt::add_ha_avty_section(config.as<JsonObject>(), stat_t, val_cond);
|
||||||
|
|
||||||
@@ -808,7 +815,7 @@ void AnalogSensor::publish_values(const bool force) {
|
|||||||
|
|
||||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf(topic, sizeof(topic), "%s_data", F_(analogsensor));
|
snprintf(topic, sizeof(topic), "%s_data", F_(analogsensor));
|
||||||
Mqtt::queue_publish(topic, doc.as<JsonObject>());
|
Mqtt::queue_publish(topic, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from emsesp.cpp for commands
|
// called from emsesp.cpp for commands
|
||||||
|
|||||||
@@ -2086,7 +2086,6 @@ void EMSdevice::mqtt_ha_entity_config_create() {
|
|||||||
uint16_t count = 0;
|
uint16_t count = 0;
|
||||||
const char * const ** mode_options = nullptr;
|
const char * const ** mode_options = nullptr;
|
||||||
|
|
||||||
|
|
||||||
// check the state of each of the device values
|
// check the state of each of the device values
|
||||||
// create the discovery topic if if hasn't already been created, not a command (like reset) and is active and visible
|
// create the discovery topic if if hasn't already been created, not a command (like reset) and is active and visible
|
||||||
for (auto & dv : devicevalues_) {
|
for (auto & dv : devicevalues_) {
|
||||||
@@ -2134,9 +2133,16 @@ void EMSdevice::mqtt_ha_entity_config_create() {
|
|||||||
|
|
||||||
// SRC thermostats mapped to connect/src1/...
|
// SRC thermostats mapped to connect/src1/...
|
||||||
if (dv.tag >= DeviceValueTAG::TAG_SRC1 && dv.tag <= DeviceValueTAG::TAG_SRC16 && !strcmp(dv.short_name, FL_(selRoomTemp)[0])) {
|
if (dv.tag >= DeviceValueTAG::TAG_SRC1 && dv.tag <= DeviceValueTAG::TAG_SRC16 && !strcmp(dv.short_name, FL_(selRoomTemp)[0])) {
|
||||||
|
const char * icon = nullptr;
|
||||||
|
for (auto & d : devicevalues_) {
|
||||||
|
if (d.tag == dv.tag && !strcmp(d.short_name, FL_(icon)[0]) && *(uint8_t *)(d.value_p != 0)) {
|
||||||
|
icon = d.options[*(uint8_t *)(d.value_p)][0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
// add all modes - auto, heat, off, cool
|
// add all modes - auto, heat, off, cool
|
||||||
// https://github.com/emsesp/EMS-ESP32/issues/2636
|
// https://github.com/emsesp/EMS-ESP32/issues/2636
|
||||||
Mqtt::publish_ha_climate_config(dv, true, nullptr, false);
|
Mqtt::publish_ha_climate_config(dv, true, nullptr, false, icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
|
|||||||
@@ -1244,7 +1244,7 @@ void Mqtt::add_ha_classes(JsonObject doc, const uint8_t device_type, const uint8
|
|||||||
|
|
||||||
// publish the HA climate config
|
// publish the HA climate config
|
||||||
// https://www.home-assistant.io/integrations/climate.mqtt/
|
// https://www.home-assistant.io/integrations/climate.mqtt/
|
||||||
bool Mqtt::publish_ha_climate_config(const DeviceValue & dv, const bool has_roomtemp, const char * const ** mode_options, const bool remove) {
|
bool Mqtt::publish_ha_climate_config(const DeviceValue & dv, const bool has_roomtemp, const char * const ** mode_options, const bool remove, const char * icon) {
|
||||||
int8_t tag = dv.tag;
|
int8_t tag = dv.tag;
|
||||||
int16_t min = dv.min;
|
int16_t min = dv.min;
|
||||||
uint32_t max = dv.max;
|
uint32_t max = dv.max;
|
||||||
@@ -1367,10 +1367,10 @@ bool Mqtt::publish_ha_climate_config(const DeviceValue & dv, const bool has_room
|
|||||||
// map EMS modes to HA climate modes
|
// map EMS modes to HA climate modes
|
||||||
// EMS modes: auto, manual, heat, off, night, day, nofrost, eco, comfort, cool)
|
// EMS modes: auto, manual, heat, off, night, day, nofrost, eco, comfort, cool)
|
||||||
// HA supports: auto, off, cool, heat, dry, fan_only
|
// HA supports: auto, off, cool, heat, dry, fan_only
|
||||||
bool found_auto = true;
|
bool found_auto = false;
|
||||||
bool found_heat = true;
|
bool found_heat = false;
|
||||||
bool found_off = true;
|
bool found_off = false;
|
||||||
bool found_cool = true;
|
bool found_cool = false;
|
||||||
if (mode_options != nullptr) {
|
if (mode_options != nullptr) {
|
||||||
// scan through mode_options and add to modes
|
// scan through mode_options and add to modes
|
||||||
for (uint8_t i = 0; i < Helpers::count_items(mode_options); i++) {
|
for (uint8_t i = 0; i < Helpers::count_items(mode_options); i++) {
|
||||||
@@ -1385,21 +1385,33 @@ bool Mqtt::publish_ha_climate_config(const DeviceValue & dv, const bool has_room
|
|||||||
found_cool = true;
|
found_cool = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// add all modes if no mode_options are available, e.g. for SRC thermostats
|
||||||
|
found_auto = true; // auto
|
||||||
|
found_heat = true; // heat
|
||||||
|
found_off = true; // off
|
||||||
|
found_cool = true; // cool
|
||||||
}
|
}
|
||||||
|
|
||||||
// only add modes if we found at least one
|
// only add modes if we found at least one, i.e. if mode_options are available
|
||||||
JsonArray modes = doc["modes"].to<JsonArray>();
|
if (found_auto || found_heat || found_off || found_cool) {
|
||||||
if (found_auto) {
|
JsonArray modes = doc["modes"].to<JsonArray>();
|
||||||
modes.add("auto");
|
if (found_auto) {
|
||||||
|
modes.add("auto");
|
||||||
|
}
|
||||||
|
if (found_heat) {
|
||||||
|
modes.add("heat");
|
||||||
|
}
|
||||||
|
if (found_off) {
|
||||||
|
modes.add("off");
|
||||||
|
}
|
||||||
|
if (found_cool) {
|
||||||
|
modes.add("cool");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (found_heat) {
|
|
||||||
modes.add("heat");
|
if (icon != nullptr) {
|
||||||
}
|
doc["ic"] = icon;
|
||||||
if (found_off) {
|
|
||||||
modes.add("off");
|
|
||||||
}
|
|
||||||
if (found_cool) {
|
|
||||||
modes.add("cool");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_ha_dev_section(doc.as<JsonObject>(), devicename, nullptr, nullptr, nullptr, false); // add dev section
|
add_ha_dev_section(doc.as<JsonObject>(), devicename, nullptr, nullptr, nullptr, false); // add dev section
|
||||||
|
|||||||
@@ -113,7 +113,11 @@ class Mqtt {
|
|||||||
const bool create_device_config = false);
|
const bool create_device_config = false);
|
||||||
|
|
||||||
static bool publish_system_ha_sensor_config(uint8_t type, const char * name, const char * entity, const uint8_t uom);
|
static bool publish_system_ha_sensor_config(uint8_t type, const char * name, const char * entity, const uint8_t uom);
|
||||||
static bool publish_ha_climate_config(const DeviceValue & dv, const bool has_roomtemp, const char * const ** mode_options, const bool remove = false);
|
static bool publish_ha_climate_config(const DeviceValue & dv,
|
||||||
|
const bool has_roomtemp,
|
||||||
|
const char * const ** mode_options,
|
||||||
|
const bool remove = false,
|
||||||
|
const char * icon = nullptr);
|
||||||
|
|
||||||
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type);
|
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type);
|
||||||
static void show_mqtt(uuid::console::Shell & shell);
|
static void show_mqtt(uuid::console::Shell & shell);
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "3.7.3-dev.36"
|
#define EMSESP_APP_VERSION "3.7.3-dev.37"
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ bool WebCustomEntityService::command_setvalue(const char * value, const int8_t i
|
|||||||
// if add_uom is true it will add the UOM string to the value
|
// if add_uom is true it will add the UOM string to the value
|
||||||
void WebCustomEntityService::render_value(JsonObject output, CustomEntityItem const & entity, const bool useVal, const bool web, const bool add_uom) {
|
void WebCustomEntityService::render_value(JsonObject output, CustomEntityItem const & entity, const bool useVal, const bool web, const bool add_uom) {
|
||||||
char payload[20];
|
char payload[20];
|
||||||
const char * name = useVal ? "value" : entity.name;
|
const char * name = useVal ? "value" : (const char *)entity.name;
|
||||||
|
|
||||||
switch (entity.value_type) {
|
switch (entity.value_type) {
|
||||||
case DeviceValueType::BOOL:
|
case DeviceValueType::BOOL:
|
||||||
|
|||||||
@@ -235,10 +235,11 @@ void WebSchedulerService::publish(const bool force) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
|
JsonObject output = doc.to<JsonObject>();
|
||||||
bool ha_created = ha_registered_;
|
bool ha_created = ha_registered_;
|
||||||
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
|
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
|
||||||
if (scheduleItem.name[0] != '\0' && !doc[scheduleItem.name].is<JsonVariantConst>()) {
|
if (scheduleItem.name[0] != '\0' && !output[scheduleItem.name].is<JsonVariantConst>()) {
|
||||||
Mqtt::add_value_bool(doc.as<JsonObject>(), scheduleItem.name, scheduleItem.active);
|
Mqtt::add_value_bool(output, (const char *)scheduleItem.name, scheduleItem.active);
|
||||||
|
|
||||||
// create HA config
|
// create HA config
|
||||||
if (Mqtt::ha_enabled() && !ha_registered_) {
|
if (Mqtt::ha_enabled() && !ha_registered_) {
|
||||||
@@ -290,7 +291,7 @@ void WebSchedulerService::publish(const bool force) {
|
|||||||
if (!doc.isNull()) {
|
if (!doc.isNull()) {
|
||||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf(topic, sizeof(topic), "%s_data", F_(scheduler));
|
snprintf(topic, sizeof(topic), "%s_data", F_(scheduler));
|
||||||
Mqtt::queue_publish(topic, doc.as<JsonObject>());
|
Mqtt::queue_publish(topic, output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user