diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9220b2149..21958d49d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,7 +14,7 @@ All notable changes to this project will be documented in this file.
### Changed
- ESP32 Platform from 2025.05.30 to 2025.07.30, Framework (Arduino Core) from v3.1.3.250504 to v3.1.3.250707 and IDF from v5.3.3.250501 to v5.3.3.250707 (#23642)
-- ESP32 Domoticz supports persistent settings for all relays, keys and switches using filesystem
+- Domoticz supports persistent settings for all relays, keys and switches when filesystem `#define USE_UFILESYS` is enabled
### Fixed
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index be9804f81..b73344ce3 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -134,7 +134,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
- Library names [#23560](https://github.com/arendst/Tasmota/issues/23560)
- CSS uses named colors variables [#23597](https://github.com/arendst/Tasmota/issues/23597)
- VEML6070 and AHT2x device detection [#23581](https://github.com/arendst/Tasmota/issues/23581)
-- ESP32 Domoticz supports persistent settings for all relays, keys and switches using filesystem
+- Domoticz supports persistent settings for all relays, keys and switches when filesystem `#define USE_UFILESYS` is enabled
- ESP32 LoRaWan decoding won't duplicate non-decoded message if `SO147 0`
- BLE updates for esp-nimble-cpp v2.x [#23553](https://github.com/arendst/Tasmota/issues/23553)
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_07_domoticz.ino b/tasmota/tasmota_xdrv_driver/xdrv_07_domoticz.ino
index 8f6fd8b15..fd844152a 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_07_domoticz.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_07_domoticz.ino
@@ -17,8 +17,8 @@
along with this program. If not, see .
*/
-#ifdef ESP8266
#ifdef USE_DOMOTICZ
+#ifndef USE_UFILESYS
/*********************************************************************************************\
* Domoticz support
*
@@ -770,5 +770,5 @@ bool Xdrv07(uint32_t function) {
return result;
}
+#endif // No USE_UFILESYS
#endif // USE_DOMOTICZ
-#endif // ESP8266
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_07_esp32_domoticz.ino b/tasmota/tasmota_xdrv_driver/xdrv_07_ufs_domoticz.ino
similarity index 91%
rename from tasmota/tasmota_xdrv_driver/xdrv_07_esp32_domoticz.ino
rename to tasmota/tasmota_xdrv_driver/xdrv_07_ufs_domoticz.ino
index 00a9c6ec4..4593f4060 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_07_esp32_domoticz.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_07_ufs_domoticz.ino
@@ -1,5 +1,5 @@
/*
- xdrv_07_esp32_domoticz.ino - domoticz support for Tasmota
+ xdrv_07_ufs_domoticz.ino - domoticz support for Tasmota
Copyright (C) 2025 Theo Arends
@@ -17,8 +17,8 @@
along with this program. If not, see .
*/
-#ifdef ESP32
#ifdef USE_DOMOTICZ
+#ifdef USE_UFILESYS
/*********************************************************************************************\
* Domoticz support with all relays/buttons/switches using more RAM and Settings from filesystem
*
@@ -40,7 +40,18 @@
#define XDRV_07 7
-//#define USE_DOMOTICZ_DEBUG // Enable additional debug logging
+//#define DOMOTICZ_IDX_MAX // Support for highest Domoticz Idx number over 65535 (uses uint32_t which uses more RAM)
+
+//#define USE_DOMOTICZ_DEBUG // Enable additional debug logging
+
+#ifdef ESP32
+#define DOMOTICZ_IDX_MAX // Support for highest Domoticz Idx number (uses uint32_t)
+#endif
+#ifdef DOMOTICZ_IDX_MAX
+typedef uint32_t uintdz_t; // Max Domoticz Idx = 0xFFFFFFFF = 4294967295
+#else
+typedef uint16_t uintdz_t; // Max Domoticz Idx = 0xFFFF = 65535
+#endif
#define D_PRFX_DOMOTICZ "Dz"
#define D_CMND_IDX "Idx"
@@ -67,16 +78,19 @@ const char kDomoticzCommand[] PROGMEM = "switchlight|switchscene";
char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC;
typedef struct DzSettings_t {
- uint32_t crc32; // To detect file changes
- uint32_t update_timer;
- uint32_t* relay_idx;
- uint32_t* key_idx;
- uint32_t* switch_idx;
- uint32_t sensor_idx[DZ_MAX_SENSORS];
+ uint32_t crc32; // To detect file changes
+ uintdz_t* relay_idx;
+ uintdz_t* key_idx;
+ uintdz_t* switch_idx;
+ uintdz_t sensor_idx[DZ_MAX_SENSORS];
+ uintdz_t update_timer;
} DzSettings_t;
typedef struct Domoticz_t {
- DzSettings_t Settings; // Persistent settings
+ DzSettings_t Settings; // Persistent settings
+#ifdef USE_SONOFF_IFAN
+ uint32_t fan_debounce; // iFan02 state debounce timer
+#endif // USE_SONOFF_IFAN
int update_timer;
uint8_t keys;
uint8_t switches;
@@ -92,7 +106,6 @@ Domoticz_t* Domoticz;
* Driver Settings load and save
\*********************************************************************************************/
-#ifdef USE_UFILESYS
#define XDRV_07_KEY "drvset03"
bool DomoticzLoadData(void) {
@@ -175,7 +188,6 @@ void DomoticzDeleteData(void) {
char key[] = XDRV_07_KEY;
UfsJsonSettingsDelete(key); // Use defaults
}
-#endif // USE_UFILESYS
/*********************************************************************************************/
@@ -206,9 +218,6 @@ void DomoticzSettingsLoad(bool erase) {
// *** End Init default values ***
#endif // CONFIG_IDF_TARGET_ESP32P4
-#ifndef USE_UFILESYS
- AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Domoticz use defaults as file system not enabled"));
-#else
// Try to load key
if (erase) {
DomoticzDeleteData();
@@ -220,19 +229,17 @@ void DomoticzSettingsLoad(bool erase) {
// File system not ready: No flash space reserved for file system
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("CFG: Domoticz use defaults as file system not ready or key not found"));
}
-#endif // USE_UFILESYS
}
void DomoticzSettingsSave(void) {
// Called from FUNC_SAVE_SETTINGS every SaveData second and at restart
-#ifdef USE_UFILESYS
uint32_t crc32 = GetCfgCrc32((uint8_t*)&Domoticz->Settings +4, sizeof(DzSettings_t) -4); // Skip crc32
- crc32 += GetCfgCrc32((uint8_t*)Domoticz->Settings.relay_idx, TasmotaGlobal.devices_present * sizeof(uint32_t));
+ crc32 += GetCfgCrc32((uint8_t*)Domoticz->Settings.relay_idx, TasmotaGlobal.devices_present * sizeof(uintdz_t));
if (Domoticz->keys) {
- crc32 += GetCfgCrc32((uint8_t*)Domoticz->Settings.key_idx, Domoticz->keys * sizeof(uint32_t));
+ crc32 += GetCfgCrc32((uint8_t*)Domoticz->Settings.key_idx, Domoticz->keys * sizeof(uintdz_t));
}
if (Domoticz->switches) {
- crc32 += GetCfgCrc32((uint8_t*)Domoticz->Settings.switch_idx, Domoticz->switches * sizeof(uint32_t));
+ crc32 += GetCfgCrc32((uint8_t*)Domoticz->Settings.switch_idx, Domoticz->switches * sizeof(uintdz_t));
}
if (crc32 != Domoticz->Settings.crc32) {
Domoticz->Settings.crc32 = crc32;
@@ -243,7 +250,6 @@ void DomoticzSettingsSave(void) {
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("CFG: Domoticz ERROR File system not ready or unable to save file"));
}
}
-#endif // USE_UFILESYS
}
/*********************************************************************************************/
@@ -286,6 +292,30 @@ void DomoticzSetRelayIdx(uint32_t relay, uint32_t idx) {
Domoticz->Settings.relay_idx[relay] = idx;
}
+#ifdef USE_SONOFF_IFAN
+void MqttPublishDomoticzFanState(void) {
+ if (Settings->flag.mqtt_enabled && DomoticzRelayIdx(1)) { // SetOption3 - Enable MQTT
+ char svalue[8]; // Fanspeed value
+
+ int fan_speed = GetFanspeed();
+ snprintf_P(svalue, sizeof(svalue), PSTR("%d"), fan_speed * 10);
+ Response_P(DOMOTICZ_MESSAGE, (int)DomoticzRelayIdx(1), (0 == fan_speed) ? 0 : 2, svalue, DomoticzBatteryQuality(), DomoticzRssiQuality());
+ MqttPublish(domoticz_in_topic);
+
+ Domoticz->fan_debounce = millis() + 1000; // 1 second
+ }
+}
+
+void DomoticzUpdateFanState(void) {
+ if (Domoticz) {
+ if (Domoticz->update_flag) {
+ MqttPublishDomoticzFanState();
+ }
+ Domoticz->update_flag = true;
+ }
+}
+#endif // USE_SONOFF_IFAN
+
/*********************************************************************************************/
void MqttPublishDomoticzPowerState(uint8_t device) {
@@ -298,11 +328,19 @@ void MqttPublishDomoticzPowerState(uint8_t device) {
// Shutter is updated by sensor update - power state should not be sent
} else {
#endif // USE_SHUTTER
+#ifdef USE_SONOFF_IFAN
+ if (IsModuleIfan() && (device > 1)) {
+ // Fan handled by MqttPublishDomoticzFanState
+ } else {
+#endif // USE_SONOFF_IFAN
char svalue[8]; // Dimmer value
snprintf_P(svalue, sizeof(svalue), PSTR("%d"), Settings->light_dimmer);
Response_P(DOMOTICZ_MESSAGE, (int)DomoticzRelayIdx(device -1), (TasmotaGlobal.power & (1 << (device -1))) ? 1 : 0, (TasmotaGlobal.light_type) ? svalue : "", DomoticzBatteryQuality(), DomoticzRssiQuality());
MqttPublish(domoticz_in_topic);
+#ifdef USE_SONOFF_IFAN
+ }
+#endif // USE_SONOFF_IFAN
#ifdef USE_SHUTTER
}
#endif //USE_SHUTTER
@@ -333,7 +371,16 @@ void DomoticzMqttUpdate(void) {
break;
}
#endif // USE_SHUTTER
- MqttPublishDomoticzPowerState(i);
+#ifdef USE_SONOFF_IFAN
+ if (IsModuleIfan() && (i > 1)) {
+ MqttPublishDomoticzFanState();
+ break;
+ } else {
+#endif // USE_SONOFF_IFAN
+ MqttPublishDomoticzPowerState(i);
+#ifdef USE_SONOFF_IFAN
+ }
+#endif // USE_SONOFF_IFAN
}
}
}
@@ -430,6 +477,24 @@ bool DomoticzMqttData(void) {
bool iscolordimmer = (strcmp_P(domoticz.getStr(PSTR("dtype")), PSTR("Color Switch")) == 0);
bool isShutter = (strcmp_P(domoticz.getStr(PSTR("dtype")), PSTR("Light/Switch")) == 0) && (strncmp_P(domoticz.getStr(PSTR("switchType")),PSTR("Blinds"), 6) == 0);
+#ifdef USE_SONOFF_IFAN
+ if (IsModuleIfan() && (1 == relay_index)) { // Idx 2 is fanspeed
+ JsonParserToken svalue_tok = domoticz[PSTR("svalue1")];
+ if (!svalue_tok) {
+ return true;
+ }
+ uint32_t svalue = svalue_tok.getUInt();
+ svalue = (2 == nvalue) ? svalue / 10 : 0;
+ if (GetFanspeed() == svalue) {
+ return true; // Stop as already set
+ }
+ if (!TimeReached(Domoticz->fan_debounce)) {
+ return true; // Stop if device in limbo
+ }
+ snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_FANSPEED));
+ snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), svalue);
+ } else
+#endif // USE_SONOFF_IFAN
#ifdef USE_SHUTTER
if (isShutter) {
uint32_t position = domoticz.getUInt(PSTR("svalue1"), 0);
@@ -641,17 +706,17 @@ void DomoticzInit(void) {
Domoticz = (Domoticz_t*)calloc(1, sizeof(Domoticz_t)); // Need calloc to reset registers to 0/false
if (nullptr == Domoticz) { return; }
- Domoticz->Settings.relay_idx = (uint32_t*)calloc(TasmotaGlobal.devices_present, sizeof(uint32_t)); // Need calloc to reset registers to 0/false
+ Domoticz->Settings.relay_idx = (uintdz_t*)calloc(TasmotaGlobal.devices_present, sizeof(uintdz_t)); // Need calloc to reset registers to 0/false
for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) {
if (ButtonUsed(i)) { Domoticz->keys++; }
if (SwitchUsed(i)) { Domoticz->switches++; }
}
if (Domoticz->keys) {
- Domoticz->Settings.key_idx = (uint32_t*)calloc(Domoticz->keys, sizeof(uint32_t)); // Need calloc to reset registers to 0/false
+ Domoticz->Settings.key_idx = (uintdz_t*)calloc(Domoticz->keys, sizeof(uintdz_t)); // Need calloc to reset registers to 0/false
if (nullptr == Domoticz->Settings.key_idx) { return; }
}
if (Domoticz->switches) {
- Domoticz->Settings.switch_idx = (uint32_t*)calloc(Domoticz->switches, sizeof(uint32_t)); // Need calloc to reset registers to 0/false
+ Domoticz->Settings.switch_idx = (uintdz_t*)calloc(Domoticz->switches, sizeof(uintdz_t)); // Need calloc to reset registers to 0/false
if (nullptr == Domoticz->Settings.switch_idx) { return; }
}
@@ -806,6 +871,11 @@ void HandleDomoticzConfiguration(void) {
WSContentSend_P(PSTR("
"));
WSContentSend_P(HTTP_FORM_DOMOTICZ_INPUT, 'r', i, Domoticz->Settings.relay_idx[i]);
WSContentSend_P(PSTR(" | "));
+
+#ifdef USE_SONOFF_IFAN
+ if (IsModuleIfan() && (1 == i)) { break; }
+#endif // USE_SONOFF_IFAN
+
}
for (uint32_t i = 0; i < DZ_MAX_SENSORS; i++) {
WSContentSend_P(HTTP_FORM_DOMOTICZ_SENSOR, i +1, GetTextIndexed(stemp, sizeof(stemp), i, kDomoticzSensors));
@@ -913,5 +983,5 @@ bool Xdrv07(uint32_t function) {
return result;
}
+#endif // USE_UFILESYS
#endif // USE_DOMOTICZ
-#endif // ESP32