Changed Domoticz supports persistent settings for all relays, keys and switches when filesystem #define USE_UFILESYS is enabled

This commit is contained in:
Theo Arends 2025-07-15 17:06:03 +02:00
parent a6124128a7
commit c0f11f0373
4 changed files with 100 additions and 30 deletions

View File

@ -14,7 +14,7 @@ All notable changes to this project will be documented in this file.
### Changed ### 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 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 ### Fixed

View File

@ -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) - Library names [#23560](https://github.com/arendst/Tasmota/issues/23560)
- CSS uses named colors variables [#23597](https://github.com/arendst/Tasmota/issues/23597) - 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) - 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` - 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) - BLE updates for esp-nimble-cpp v2.x [#23553](https://github.com/arendst/Tasmota/issues/23553)

View File

@ -17,8 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef ESP8266
#ifdef USE_DOMOTICZ #ifdef USE_DOMOTICZ
#ifndef USE_UFILESYS
/*********************************************************************************************\ /*********************************************************************************************\
* Domoticz support * Domoticz support
* *
@ -770,5 +770,5 @@ bool Xdrv07(uint32_t function) {
return result; return result;
} }
#endif // No USE_UFILESYS
#endif // USE_DOMOTICZ #endif // USE_DOMOTICZ
#endif // ESP8266

View File

@ -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 Copyright (C) 2025 Theo Arends
@ -17,8 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef ESP32
#ifdef USE_DOMOTICZ #ifdef USE_DOMOTICZ
#ifdef USE_UFILESYS
/*********************************************************************************************\ /*********************************************************************************************\
* Domoticz support with all relays/buttons/switches using more RAM and Settings from filesystem * Domoticz support with all relays/buttons/switches using more RAM and Settings from filesystem
* *
@ -40,8 +40,19 @@
#define XDRV_07 7 #define XDRV_07 7
//#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 //#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_PRFX_DOMOTICZ "Dz"
#define D_CMND_IDX "Idx" #define D_CMND_IDX "Idx"
#define D_CMND_KEYIDX "KeyIdx" #define D_CMND_KEYIDX "KeyIdx"
@ -68,15 +79,18 @@ char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC;
typedef struct DzSettings_t { typedef struct DzSettings_t {
uint32_t crc32; // To detect file changes uint32_t crc32; // To detect file changes
uint32_t update_timer; uintdz_t* relay_idx;
uint32_t* relay_idx; uintdz_t* key_idx;
uint32_t* key_idx; uintdz_t* switch_idx;
uint32_t* switch_idx; uintdz_t sensor_idx[DZ_MAX_SENSORS];
uint32_t sensor_idx[DZ_MAX_SENSORS]; uintdz_t update_timer;
} DzSettings_t; } DzSettings_t;
typedef struct Domoticz_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; int update_timer;
uint8_t keys; uint8_t keys;
uint8_t switches; uint8_t switches;
@ -92,7 +106,6 @@ Domoticz_t* Domoticz;
* Driver Settings load and save * Driver Settings load and save
\*********************************************************************************************/ \*********************************************************************************************/
#ifdef USE_UFILESYS
#define XDRV_07_KEY "drvset03" #define XDRV_07_KEY "drvset03"
bool DomoticzLoadData(void) { bool DomoticzLoadData(void) {
@ -175,7 +188,6 @@ void DomoticzDeleteData(void) {
char key[] = XDRV_07_KEY; char key[] = XDRV_07_KEY;
UfsJsonSettingsDelete(key); // Use defaults UfsJsonSettingsDelete(key); // Use defaults
} }
#endif // USE_UFILESYS
/*********************************************************************************************/ /*********************************************************************************************/
@ -206,9 +218,6 @@ void DomoticzSettingsLoad(bool erase) {
// *** End Init default values *** // *** End Init default values ***
#endif // CONFIG_IDF_TARGET_ESP32P4 #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 // Try to load key
if (erase) { if (erase) {
DomoticzDeleteData(); DomoticzDeleteData();
@ -220,19 +229,17 @@ void DomoticzSettingsLoad(bool erase) {
// File system not ready: No flash space reserved for file system // 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")); 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) { void DomoticzSettingsSave(void) {
// Called from FUNC_SAVE_SETTINGS every SaveData second and at restart // 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 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) { 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) { 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) { if (crc32 != Domoticz->Settings.crc32) {
Domoticz->Settings.crc32 = 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")); 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; 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) { 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 // Shutter is updated by sensor update - power state should not be sent
} else { } else {
#endif // USE_SHUTTER #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 char svalue[8]; // Dimmer value
snprintf_P(svalue, sizeof(svalue), PSTR("%d"), Settings->light_dimmer); 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()); 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); MqttPublish(domoticz_in_topic);
#ifdef USE_SONOFF_IFAN
}
#endif // USE_SONOFF_IFAN
#ifdef USE_SHUTTER #ifdef USE_SHUTTER
} }
#endif //USE_SHUTTER #endif //USE_SHUTTER
@ -333,7 +371,16 @@ void DomoticzMqttUpdate(void) {
break; break;
} }
#endif // USE_SHUTTER #endif // USE_SHUTTER
#ifdef USE_SONOFF_IFAN
if (IsModuleIfan() && (i > 1)) {
MqttPublishDomoticzFanState();
break;
} else {
#endif // USE_SONOFF_IFAN
MqttPublishDomoticzPowerState(i); 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 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); 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 #ifdef USE_SHUTTER
if (isShutter) { if (isShutter) {
uint32_t position = domoticz.getUInt(PSTR("svalue1"), 0); 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 Domoticz = (Domoticz_t*)calloc(1, sizeof(Domoticz_t)); // Need calloc to reset registers to 0/false
if (nullptr == Domoticz) { return; } 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++) { for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) {
if (ButtonUsed(i)) { Domoticz->keys++; } if (ButtonUsed(i)) { Domoticz->keys++; }
if (SwitchUsed(i)) { Domoticz->switches++; } if (SwitchUsed(i)) { Domoticz->switches++; }
} }
if (Domoticz->keys) { 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 (nullptr == Domoticz->Settings.key_idx) { return; }
} }
if (Domoticz->switches) { 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; } if (nullptr == Domoticz->Settings.switch_idx) { return; }
} }
@ -806,6 +871,11 @@ void HandleDomoticzConfiguration(void) {
WSContentSend_P(PSTR("</td><td>")); WSContentSend_P(PSTR("</td><td>"));
WSContentSend_P(HTTP_FORM_DOMOTICZ_INPUT, 'r', i, Domoticz->Settings.relay_idx[i]); WSContentSend_P(HTTP_FORM_DOMOTICZ_INPUT, 'r', i, Domoticz->Settings.relay_idx[i]);
WSContentSend_P(PSTR("</td></tr>")); WSContentSend_P(PSTR("</td></tr>"));
#ifdef USE_SONOFF_IFAN
if (IsModuleIfan() && (1 == i)) { break; }
#endif // USE_SONOFF_IFAN
} }
for (uint32_t i = 0; i < DZ_MAX_SENSORS; i++) { for (uint32_t i = 0; i < DZ_MAX_SENSORS; i++) {
WSContentSend_P(HTTP_FORM_DOMOTICZ_SENSOR, i +1, GetTextIndexed(stemp, sizeof(stemp), i, kDomoticzSensors)); 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; return result;
} }
#endif // USE_UFILESYS
#endif // USE_DOMOTICZ #endif // USE_DOMOTICZ
#endif // ESP32