mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-19 16:56:34 +00:00
Change ESP32 Domoticz supports persistent settings for all relays, keys and switches using filesystem
This commit is contained in:
parent
6751bd397c
commit
fca68c6b30
@ -11,6 +11,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
|
||||
|
||||
### Fixed
|
||||
|
||||
|
@ -131,6 +131,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
|
||||
- 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)
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ESP8266
|
||||
#ifdef USE_DOMOTICZ
|
||||
/*********************************************************************************************\
|
||||
* Domoticz support
|
||||
@ -770,3 +771,4 @@ bool Xdrv07(uint32_t function) {
|
||||
}
|
||||
|
||||
#endif // USE_DOMOTICZ
|
||||
#endif // ESP8266
|
||||
|
869
tasmota/tasmota_xdrv_driver/xdrv_07_esp32_domoticz.ino
Normal file
869
tasmota/tasmota_xdrv_driver/xdrv_07_esp32_domoticz.ino
Normal file
@ -0,0 +1,869 @@
|
||||
/*
|
||||
xdrv_07_esp32_domoticz.ino - domoticz support for Tasmota
|
||||
|
||||
Copyright (C) 2025 Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ESP32
|
||||
#ifdef USE_DOMOTICZ
|
||||
/*********************************************************************************************\
|
||||
* Domoticz support with all relays/buttons/switches using more RAM and Settings from filesystem
|
||||
*
|
||||
* Adds commands:
|
||||
* DzIdx<number> <idx> - Set power number to Domoticz Idx allowing Domoticz to control Tasmota power
|
||||
* DzKeyIdx<number> <idx> - Set button number to Domoticz Idx allowing Tasmota button as input to Domoticz
|
||||
* DzSwitchId<number> <idx> - Set switch number to Domoticz Idx allowing Tasmota switch as input to Domoticz
|
||||
* DzSensorIdx<type> <idx> - Set sensor type to Domoticz Idx
|
||||
* DzUpdateTimer 0 - Send power state at teleperiod to Domoticz (default)
|
||||
* DzUpdateTimer <seconds> - Send power state at <seconds> interval to Domoticz
|
||||
* DzSend1 <idx>,<values> - {\"idx\":<idx>,\"nvalue\":0,\"svalue\":\"<values>\",\"Battery\":xx,\"RSSI\":yy}
|
||||
* Example: rule1 on power1#state do dzsend1 9001,%value% endon
|
||||
* DzSend1 418,%var1%;%var2% or DzSend1 418,%var1%:%var2% - Notice colon as substitute to semi-colon
|
||||
* DzSend2 <idx>,<values> - USE_SHUTTER only - {\"idx\":<idx>,\"nvalue\":<position>,\"svalue\":\"<values>\",\"Battery\":xx,\"RSSI\":yy}
|
||||
* DzSend3 <idx>,<values> - {\"idx\":<idx>,\"nvalue\":<values>,\"Battery\":xx,\"RSSI\":yy}
|
||||
* DzSend4 <idx>,<state> - {\"command\":\"switchlight\",\"idx\":<idx>,\"switchcmd\":\"<state>\"}
|
||||
* DzSend5 <idx>,<state> - {\"command\":\"switchscene\",\"idx\":<idx>,\"switchcmd\":\"<state>\"}
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XDRV_07 7
|
||||
|
||||
//#define USE_DOMOTICZ_DEBUG // Enable additional debug logging
|
||||
|
||||
#define D_PRFX_DOMOTICZ "Dz"
|
||||
#define D_CMND_IDX "Idx"
|
||||
#define D_CMND_KEYIDX "KeyIdx"
|
||||
#define D_CMND_SWITCHIDX "SwitchIdx"
|
||||
#define D_CMND_SENSORIDX "SensorIdx"
|
||||
#define D_CMND_UPDATETIMER "UpdateTimer"
|
||||
#define D_CMND_DZSEND "Send"
|
||||
|
||||
const char kDomoticzCommands[] PROGMEM = D_PRFX_DOMOTICZ "|" // Prefix
|
||||
D_CMND_IDX "|" D_CMND_KEYIDX "|" D_CMND_SWITCHIDX "|" D_CMND_SENSORIDX "|" D_CMND_UPDATETIMER "|" D_CMND_DZSEND ;
|
||||
|
||||
void (* const DomoticzCommand[])(void) PROGMEM = {
|
||||
&CmndDomoticzIdx, &CmndDomoticzKeyIdx, &CmndDomoticzSwitchIdx, &CmndDomoticzSensorIdx, &CmndDomoticzUpdateTimer, &CmndDomoticzSend };
|
||||
|
||||
const char DOMOTICZ_MESSAGE[] PROGMEM = "{\"idx\":%d,\"nvalue\":%d,\"svalue\":\"%s\",\"Battery\":%d,\"RSSI\":%d}";
|
||||
|
||||
const char kDomoticzSensors[] PROGMEM = // Relates to enum DomoticzSensors
|
||||
D_DOMOTICZ_TEMP "|" D_DOMOTICZ_TEMP_HUM "|" D_DOMOTICZ_TEMP_HUM_BARO "|" D_DOMOTICZ_POWER_ENERGY "|" D_DOMOTICZ_ILLUMINANCE "|"
|
||||
D_DOMOTICZ_COUNT "|" D_DOMOTICZ_VOLTAGE "|" D_DOMOTICZ_CURRENT "|" D_DOMOTICZ_AIRQUALITY "|" D_DOMOTICZ_P1_SMART_METER "|" D_DOMOTICZ_SHUTTER ;
|
||||
|
||||
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[MAX_RELAYS_SET];
|
||||
uint32_t key_idx[MAX_RELAYS_SET]; // = MAX_KEYS_SET
|
||||
uint32_t switch_idx[MAX_RELAYS_SET]; // = MAX_SWITCHES_SET
|
||||
uint32_t sensor_idx[DZ_MAX_SENSORS];
|
||||
} DzSettings_t;
|
||||
|
||||
typedef struct Domoticz_t {
|
||||
DzSettings_t Settings; // Persistent settings
|
||||
int update_timer;
|
||||
bool subscribe;
|
||||
bool update_flag;
|
||||
#ifdef USE_SHUTTER
|
||||
bool is_shutter;
|
||||
#endif // USE_SHUTTER
|
||||
} Domoticz_t;
|
||||
Domoticz_t* Domoticz;
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Driver Settings load and save
|
||||
\*********************************************************************************************/
|
||||
|
||||
#ifdef USE_UFILESYS
|
||||
#define XDRV_07_KEY "drvset03"
|
||||
|
||||
bool DomoticzLoadData(void) {
|
||||
char key[] = XDRV_07_KEY;
|
||||
String json = UfsJsonSettingsRead(key);
|
||||
if (json.length() == 0) { return false; }
|
||||
|
||||
// {"Crc":1882268982,"Update":0,"Relay":[1,2,3,4],"Key":[5,6,7,8],"Switch":[9,10,11,12],"Sensor":[13,14]}
|
||||
JsonParser parser((char*)json.c_str());
|
||||
JsonParserObject root = parser.getRootObject();
|
||||
if (!root) { return false; }
|
||||
|
||||
Domoticz->Settings.crc32 = root.getUInt(PSTR("Crc"), Domoticz->Settings.crc32);
|
||||
Domoticz->Settings.update_timer = root.getUInt(PSTR("Update"), Domoticz->Settings.update_timer);
|
||||
JsonParserArray arr = root[PSTR("Relay")];
|
||||
if (arr) {
|
||||
for (uint32_t i = 0; i < MAX_RELAYS_SET; i++) {
|
||||
if (arr[i]) { Domoticz->Settings.relay_idx[i] = arr[i].getUInt(); }
|
||||
}
|
||||
}
|
||||
arr = root[PSTR("Key")];
|
||||
if (arr) {
|
||||
for (uint32_t i = 0; i < MAX_RELAYS_SET; i++) {
|
||||
if (arr[i]) { Domoticz->Settings.key_idx[i] = arr[i].getUInt(); }
|
||||
}
|
||||
}
|
||||
arr = root[PSTR("Switch")];
|
||||
if (arr) {
|
||||
for (uint32_t i = 0; i < MAX_RELAYS_SET; i++) {
|
||||
if (arr[i]) { Domoticz->Settings.switch_idx[i] = arr[i].getUInt(); }
|
||||
}
|
||||
}
|
||||
arr = root[PSTR("Sensor")];
|
||||
if (arr) {
|
||||
for (uint32_t i = 0; i < DZ_MAX_SENSORS; i++) {
|
||||
if (arr[i]) { Domoticz->Settings.sensor_idx[i] = arr[i].getUInt(); }
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DomoticzSaveData(void) {
|
||||
Response_P(PSTR("{\"" XDRV_07_KEY "\":{"
|
||||
"\"Crc\":%u,"
|
||||
"\"Update\":%u"),
|
||||
Domoticz->Settings.crc32,
|
||||
Domoticz->Settings.update_timer);
|
||||
ResponseAppend_P(PSTR(",\"Relay\":"));
|
||||
for (uint32_t i = 0; i < MAX_RELAYS_SET; i++) {
|
||||
ResponseAppend_P(PSTR("%c%d"), (0==i)?'[':',', Domoticz->Settings.relay_idx[i]);
|
||||
}
|
||||
ResponseAppend_P(PSTR("],\"Key\":"));
|
||||
for (uint32_t i = 0; i < MAX_RELAYS_SET; i++) {
|
||||
ResponseAppend_P(PSTR("%c%d"), (0==i)?'[':',', Domoticz->Settings.key_idx[i]);
|
||||
}
|
||||
ResponseAppend_P(PSTR("],\"Switch\":"));
|
||||
for (uint32_t i = 0; i < MAX_RELAYS_SET; i++) {
|
||||
ResponseAppend_P(PSTR("%c%d"), (0==i)?'[':',', Domoticz->Settings.switch_idx[i]);
|
||||
}
|
||||
ResponseAppend_P(PSTR("],\"Sensor\":"));
|
||||
for (uint32_t i = 0; i < DZ_MAX_SENSORS; i++) {
|
||||
ResponseAppend_P(PSTR("%c%d"), (0==i)?'[':',', Domoticz->Settings.sensor_idx[i]);
|
||||
}
|
||||
ResponseAppend_P(PSTR("]}}"));
|
||||
|
||||
if (!UfsJsonSettingsWrite(ResponseData())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DomoticzDeleteData(void) {
|
||||
char key[] = XDRV_07_KEY;
|
||||
UfsJsonSettingsDelete(key); // Use defaults
|
||||
}
|
||||
#endif // USE_UFILESYS
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void DomoticzSettingsLoad(bool erase) {
|
||||
// Called from FUNC_PRE_INIT (erase = 0) once at restart
|
||||
// Called from FUNC_RESET_SETTINGS (erase = 1) after command reset 4, 5, or 6
|
||||
memset(&Domoticz->Settings, 0x00, sizeof(DzSettings_t));
|
||||
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32P4
|
||||
// Init any other parameter in struct DzSettings
|
||||
Domoticz->Settings.update_timer = Settings->domoticz_update_timer;
|
||||
for (uint32_t i = 0; i < MAX_DOMOTICZ_IDX; i++) {
|
||||
Domoticz->Settings.relay_idx[i] = Settings->domoticz_relay_idx[i];
|
||||
Domoticz->Settings.key_idx[i] = Settings->domoticz_key_idx[i];
|
||||
Domoticz->Settings.switch_idx[i] = Settings->domoticz_switch_idx[i];
|
||||
}
|
||||
uint32_t max_sns_idx = MAX_DOMOTICZ_SNS_IDX;
|
||||
if (max_sns_idx > DZ_MAX_SENSORS) {
|
||||
max_sns_idx = DZ_MAX_SENSORS;
|
||||
}
|
||||
for (uint32_t i = 0; i < max_sns_idx; i++) {
|
||||
Domoticz->Settings.sensor_idx[i] = Settings->domoticz_sensor_idx[i];
|
||||
}
|
||||
// *** 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();
|
||||
}
|
||||
else if (DomoticzLoadData()) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Domoticz loaded from file"));
|
||||
}
|
||||
else {
|
||||
// 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
|
||||
if (crc32 != Domoticz->Settings.crc32) {
|
||||
Domoticz->Settings.crc32 = crc32;
|
||||
if (DomoticzSaveData()) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Domoticz saved to file"));
|
||||
} else {
|
||||
// File system not ready: No flash space reserved for file system
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("CFG: Domoticz ERROR File system not ready or unable to save file"));
|
||||
}
|
||||
}
|
||||
#endif // USE_UFILESYS
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
int DomoticzBatteryQuality(void) {
|
||||
// Battery 0%: ESP 2.6V (minimum operating voltage is 2.5)
|
||||
// Battery 100%: ESP 3.6V (maximum operating voltage is 3.6)
|
||||
// Battery 101% to 200%: ESP over 3.6V (means over maximum operating voltage)
|
||||
|
||||
int quality = 100; // Voltage range from 2,6V > 0% to 3,6V > 100%
|
||||
|
||||
#ifdef ESP8266
|
||||
#ifdef USE_ADC_VCC
|
||||
uint16_t voltage = ESP.getVcc();
|
||||
if (voltage <= 2600) {
|
||||
quality = 0;
|
||||
} else if (voltage >= 4600) {
|
||||
quality = 200;
|
||||
} else {
|
||||
quality = (voltage - 2600) / 10;
|
||||
}
|
||||
#endif // USE_ADC_VCC
|
||||
#endif // ESP8266
|
||||
return quality;
|
||||
}
|
||||
|
||||
int DomoticzRssiQuality(void) {
|
||||
// RSSI range: 0% to 10% (12 means disable RSSI in Domoticz)
|
||||
|
||||
return WifiGetRssiAsQuality(WiFi.RSSI()) / 10;
|
||||
}
|
||||
|
||||
uint32_t DomoticzRelayIdx(uint32_t relay) {
|
||||
if (relay >= MAX_RELAYS_SET) { return 0; }
|
||||
return Domoticz->Settings.relay_idx[relay];
|
||||
}
|
||||
|
||||
void DomoticzSetRelayIdx(uint32_t relay, uint32_t idx) {
|
||||
if (relay >= MAX_RELAYS_SET) { return; }
|
||||
Domoticz->Settings.relay_idx[relay] = idx;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void MqttPublishDomoticzPowerState(uint8_t device) {
|
||||
if (Settings->flag.mqtt_enabled) { // SetOption3 - Enable MQTT
|
||||
if (device < 1) { device = 1; }
|
||||
if ((device > TasmotaGlobal.devices_present) || (device > MAX_RELAYS_SET)) { return; }
|
||||
if (DomoticzRelayIdx(device -1)) {
|
||||
#ifdef USE_SHUTTER
|
||||
if (Domoticz->is_shutter) {
|
||||
// Shutter is updated by sensor update - power state should not be sent
|
||||
} else {
|
||||
#endif // USE_SHUTTER
|
||||
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_SHUTTER
|
||||
}
|
||||
#endif //USE_SHUTTER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DomoticzUpdatePowerState(uint8_t device) {
|
||||
if (Domoticz) {
|
||||
if (Domoticz->update_flag) {
|
||||
MqttPublishDomoticzPowerState(device);
|
||||
}
|
||||
Domoticz->update_flag = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void DomoticzMqttUpdate(void) {
|
||||
if (Domoticz->subscribe && (Domoticz->Settings.update_timer || Domoticz->update_timer)) {
|
||||
Domoticz->update_timer--;
|
||||
if (Domoticz->update_timer <= 0) {
|
||||
Domoticz->update_timer = Domoticz->Settings.update_timer;
|
||||
for (uint32_t i = 1; i <= TasmotaGlobal.devices_present; i++) {
|
||||
#ifdef USE_SHUTTER
|
||||
if (Domoticz->is_shutter) {
|
||||
// no power state updates for shutters
|
||||
break;
|
||||
}
|
||||
#endif // USE_SHUTTER
|
||||
MqttPublishDomoticzPowerState(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DomoticzMqttSubscribe(void) {
|
||||
uint8_t maxdev = (TasmotaGlobal.devices_present > MAX_RELAYS_SET) ? MAX_RELAYS_SET : TasmotaGlobal.devices_present;
|
||||
bool any_relay = false;
|
||||
for (uint32_t i = 0; i < maxdev; i++) {
|
||||
if (DomoticzRelayIdx(i)) {
|
||||
any_relay = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
char stopic[TOPSZ];
|
||||
snprintf_P(stopic, sizeof(stopic), PSTR(DOMOTICZ_OUT_TOPIC "/#")); // domoticz topic
|
||||
if (Domoticz->subscribe && !any_relay) {
|
||||
Domoticz->subscribe = false;
|
||||
MqttUnsubscribe(stopic);
|
||||
}
|
||||
// if (!Domoticz->subscribe && any_relay) { // Fails on MQTT server reconnect
|
||||
if (any_relay) {
|
||||
Domoticz->subscribe = true;
|
||||
MqttSubscribe(stopic);
|
||||
}
|
||||
}
|
||||
|
||||
int DomoticzIdx2Relay(uint32_t idx) {
|
||||
if (idx > 0) {
|
||||
uint32_t maxdev = (TasmotaGlobal.devices_present > MAX_RELAYS_SET) ? MAX_RELAYS_SET : TasmotaGlobal.devices_present;
|
||||
for (uint32_t i = 0; i < maxdev; i++) {
|
||||
if (idx == DomoticzRelayIdx(i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1; // Idx not mine
|
||||
}
|
||||
|
||||
bool DomoticzMqttData(void) {
|
||||
/*
|
||||
XdrvMailbox.topic = topic;
|
||||
XdrvMailbox.index = strlen(topic);
|
||||
XdrvMailbox.data = (char*)data;
|
||||
XdrvMailbox.data_len = data_len;
|
||||
*/
|
||||
Domoticz->update_flag = true;
|
||||
|
||||
if (!Domoticz->subscribe) {
|
||||
return false; // No Domoticz driver subscription so try user subscribes
|
||||
}
|
||||
|
||||
// Default subscibed to domoticz/out/#
|
||||
if (strncasecmp_P(XdrvMailbox.topic, PSTR(DOMOTICZ_OUT_TOPIC), strlen(DOMOTICZ_OUT_TOPIC)) != 0) {
|
||||
return false; // Process unchanged data
|
||||
}
|
||||
|
||||
// topic is domoticz/out so check if valid data could be available
|
||||
if (XdrvMailbox.data_len < 20) {
|
||||
return true; // No valid data
|
||||
}
|
||||
|
||||
#ifdef USE_DOMOTICZ_DEBUG
|
||||
char dom_data[XdrvMailbox.data_len +1];
|
||||
strcpy(dom_data, XdrvMailbox.data);
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ "%s = %s"), XdrvMailbox.topic, RemoveControlCharacter(dom_data));
|
||||
#endif // USE_DOMOTICZ_DEBUG
|
||||
|
||||
// Quick check if this is mine using topic domoticz/out/{$idx}
|
||||
if (strlen(XdrvMailbox.topic) > strlen(DOMOTICZ_OUT_TOPIC)) {
|
||||
char* topic_index = &XdrvMailbox.topic[strlen(DOMOTICZ_OUT_TOPIC) +1];
|
||||
if (strchr(topic_index, '/') == nullptr) { // Skip if topic ...floor/room
|
||||
if (DomoticzIdx2Relay(atoi(topic_index)) < 0) {
|
||||
return true; // Idx not mine
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String domoticz_data = XdrvMailbox.data; // Copy the string into a new buffer that will be modified
|
||||
JsonParser parser((char*)domoticz_data.c_str());
|
||||
JsonParserObject domoticz = parser.getRootObject();
|
||||
if (!domoticz) {
|
||||
return true; // To much or invalid data
|
||||
}
|
||||
int32_t relay_index = DomoticzIdx2Relay(domoticz.getUInt(PSTR("idx"), 0));
|
||||
if (relay_index < 0) {
|
||||
return true; // Idx not mine
|
||||
}
|
||||
int32_t nvalue = domoticz.getInt(PSTR("nvalue"), -1);
|
||||
if ((nvalue < 0) || (nvalue > 16)) {
|
||||
return true; // Nvalue out of boundaries
|
||||
}
|
||||
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ "%s, idx %d, nvalue %d"), XdrvMailbox.topic, DomoticzRelayIdx(relay_index), nvalue);
|
||||
|
||||
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_SHUTTER
|
||||
if (isShutter) {
|
||||
uint32_t position = domoticz.getUInt(PSTR("svalue1"), 0);
|
||||
if (nvalue != 2) {
|
||||
position = (0 == nvalue) ? 0 : 100;
|
||||
}
|
||||
snprintf_P(XdrvMailbox.topic, TOPSZ, PSTR("/" D_PRFX_SHUTTER D_CMND_SHUTTER_POSITION));
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), position);
|
||||
XdrvMailbox.data_len = position > 99 ? 3 : (position > 9 ? 2 : 1);
|
||||
} else
|
||||
#endif // USE_SHUTTER
|
||||
#ifdef USE_LIGHT
|
||||
if (iscolordimmer && 10 == nvalue) { // Color_SetColor
|
||||
// https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Set_a_light_to_a_certain_color_or_color_temperature
|
||||
JsonParserObject color = domoticz[PSTR("Color")].getObject();
|
||||
// JsonObject& color = domoticz["Color"];
|
||||
uint32_t level = nvalue = domoticz.getUInt(PSTR("svalue1"), 0);
|
||||
uint32_t r = color.getUInt(PSTR("r"), 0) * level / 100;
|
||||
uint32_t g = color.getUInt(PSTR("g"), 0) * level / 100;
|
||||
uint32_t b = color.getUInt(PSTR("b"), 0) * level / 100;
|
||||
uint32_t cw = color.getUInt(PSTR("cw"), 0) * level / 100;
|
||||
uint32_t ww = color.getUInt(PSTR("ww"), 0) * level / 100;
|
||||
uint32_t m = color.getUInt(PSTR("m"), 0);
|
||||
uint32_t t = color.getUInt(PSTR("t"), 0);
|
||||
if (2 == m) { // White with color temperature. Valid fields: t
|
||||
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_BACKLOG));
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR(D_CMND_COLORTEMPERATURE " %d;" D_CMND_DIMMER " %d"), changeUIntScale(t, 0, 255, CT_MIN, CT_MAX), level);
|
||||
} else {
|
||||
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_COLOR));
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%02x%02x%02x%02x%02x"), r, g, b, cw, ww);
|
||||
}
|
||||
}
|
||||
else if ((!iscolordimmer && 2 == nvalue) || // gswitch_sSetLevel
|
||||
(iscolordimmer && 15 == nvalue)) { // Color_SetBrightnessLevel
|
||||
if (domoticz[PSTR("svalue1")]) {
|
||||
nvalue = domoticz.getUInt(PSTR("svalue1"), 0);
|
||||
} else {
|
||||
return true; // Invalid data
|
||||
}
|
||||
if (TasmotaGlobal.light_type && (Settings->light_dimmer == nvalue) && ((TasmotaGlobal.power >> relay_index) &1)) {
|
||||
return true; // State already set
|
||||
}
|
||||
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_DIMMER));
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue);
|
||||
} else
|
||||
#endif // USE_LIGHT
|
||||
if (1 == nvalue || 0 == nvalue) {
|
||||
if (((TasmotaGlobal.power >> relay_index) &1) == (power_t)nvalue) {
|
||||
return true; // Stop loop
|
||||
}
|
||||
char stemp1[10];
|
||||
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_POWER "%s"), (TasmotaGlobal.devices_present > 1) ? itoa(relay_index +1, stemp1, 10) : "");
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue);
|
||||
} else {
|
||||
return true; // No command received
|
||||
}
|
||||
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ D_RECEIVED_TOPIC " %s, " D_DATA " %s"), XdrvMailbox.topic, XdrvMailbox.data);
|
||||
|
||||
Domoticz->update_flag = false;
|
||||
return false; // Process new data
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void DomoticzSendSwitch(uint32_t type, uint32_t index, uint32_t state) {
|
||||
char stemp[16]; // "switchlight" or "switchscene"
|
||||
Response_P(PSTR("{\"command\":\"%s\",\"idx\":%d,\"switchcmd\":\"%s\"}"),
|
||||
GetTextIndexed(stemp, sizeof(stemp), type, kDomoticzCommand), index, (state) ? (POWER_TOGGLE == state) ? "Toggle" : "On" : "Off"); // Domoticz case sensitive
|
||||
MqttPublish(domoticz_in_topic);
|
||||
}
|
||||
|
||||
bool DomoticzSendKey(uint8_t key, uint8_t device, uint8_t state, uint8_t svalflg) {
|
||||
bool result = false;
|
||||
|
||||
if (device <= MAX_RELAYS_SET) {
|
||||
if ((Domoticz->Settings.key_idx[device -1] || Domoticz->Settings.switch_idx[device -1]) && (svalflg)) {
|
||||
DomoticzSendSwitch(0, (key) ? Domoticz->Settings.switch_idx[device -1] : Domoticz->Settings.key_idx[device -1], state);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Sensors
|
||||
*
|
||||
* Source : https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s
|
||||
* https://www.domoticz.com/wiki/MQTT
|
||||
*
|
||||
* Percentage, Barometric, Air Quality:
|
||||
* {\"idx\":%d,\"nvalue\":%s}, Idx, Value
|
||||
*
|
||||
* Humidity:
|
||||
* {\"idx\":%d,\"nvalue\":%s,\"svalue\":\"%s\"}, Idx, Humidity, HumidityStatus
|
||||
*
|
||||
* All other:
|
||||
* {\"idx\":%d,\"nvalue\":0,\"svalue\":\"%s\"}, Idx, Value(s)
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
|
||||
void DomoticzSendData(uint32_t sensor_idx, uint32_t idx, char *data) {
|
||||
char payload[128]; // {"idx":26700,"nvalue":0,"svalue":"22330.1;10234.4;22000.5;10243.4;1006;3000","Battery":100,"RSSI":10}
|
||||
if (DZ_AIRQUALITY == sensor_idx) {
|
||||
snprintf_P(payload, sizeof(payload), PSTR("{\"idx\":%d,\"nvalue\":%s,\"Battery\":%d,\"RSSI\":%d}"),
|
||||
idx, data, DomoticzBatteryQuality(), DomoticzRssiQuality());
|
||||
} else {
|
||||
uint8_t nvalue = 0;
|
||||
#ifdef USE_SHUTTER
|
||||
if (DZ_SHUTTER == sensor_idx) {
|
||||
uint8_t position = atoi(data);
|
||||
nvalue = position < 2 ? 0 : (position == 100 ? 1 : 2);
|
||||
}
|
||||
#endif // USE_SHUTTER
|
||||
snprintf_P(payload, sizeof(payload), DOMOTICZ_MESSAGE, // "{\"idx\":%d,\"nvalue\":%d,\"svalue\":\"%s\",\"Battery\":%d,\"RSSI\":%d}"
|
||||
idx, nvalue, data, DomoticzBatteryQuality(), DomoticzRssiQuality());
|
||||
}
|
||||
MqttPublishPayload(domoticz_in_topic, payload);
|
||||
}
|
||||
|
||||
void DomoticzSensor(uint8_t idx, char *data) {
|
||||
if (Domoticz->Settings.sensor_idx[idx]) {
|
||||
DomoticzSendData(idx, Domoticz->Settings.sensor_idx[idx], data);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t DomoticzHumidityState(float h) {
|
||||
return (!h) ? 0 : (h < 40) ? 2 : (h > 70) ? 3 : 1;
|
||||
}
|
||||
|
||||
void DomoticzSensor(uint8_t idx, int value) {
|
||||
char data[16];
|
||||
snprintf_P(data, sizeof(data), PSTR("%d"), value);
|
||||
DomoticzSensor(idx, data);
|
||||
}
|
||||
|
||||
void DomoticzFloatSensor(uint8_t idx, float value) {
|
||||
uint32_t resolution = 1;
|
||||
/*
|
||||
switch (idx) {
|
||||
case DZ_TEMP: resolution = Settings->flag2.temperature_resolution; break;
|
||||
case DZ_POWER_ENERGY: resolution = Settings->flag2.wattage_resolution; break;
|
||||
case DZ_VOLTAGE: resolution = Settings->flag2.voltage_resolution; break;
|
||||
case DZ_CURRENT: resolution = Settings->flag2.current_resolution; break;
|
||||
}
|
||||
*/
|
||||
if (DZ_TEMP == idx) { resolution = Settings->flag2.temperature_resolution; }
|
||||
else if (DZ_POWER_ENERGY == idx) { resolution = Settings->flag2.wattage_resolution; }
|
||||
else if (DZ_VOLTAGE == idx) { resolution = Settings->flag2.voltage_resolution; }
|
||||
else if (DZ_CURRENT == idx) { resolution = Settings->flag2.current_resolution; }
|
||||
char data[FLOATSZ];
|
||||
dtostrfd(value, resolution, data);
|
||||
DomoticzSensor(idx, data);
|
||||
}
|
||||
|
||||
//void DomoticzTempHumPressureSensor(float temp, float hum, float baro = -1);
|
||||
void DomoticzTempHumPressureSensor(float temp, float hum, float baro) {
|
||||
char temperature[FLOATSZ];
|
||||
dtostrfd(temp, Settings->flag2.temperature_resolution, temperature);
|
||||
char humidity[FLOATSZ];
|
||||
dtostrfd(hum, Settings->flag2.humidity_resolution, humidity);
|
||||
|
||||
char data[32];
|
||||
if (baro > -1) {
|
||||
char pressure[FLOATSZ];
|
||||
dtostrfd(baro, Settings->flag2.pressure_resolution, pressure);
|
||||
|
||||
snprintf_P(data, sizeof(data), PSTR("%s;%s;%d;%s;5"), temperature, humidity, DomoticzHumidityState(hum), pressure);
|
||||
DomoticzSensor(DZ_TEMP_HUM_BARO, data);
|
||||
} else {
|
||||
snprintf_P(data, sizeof(data), PSTR("%s;%s;%d"), temperature, humidity, DomoticzHumidityState(hum));
|
||||
DomoticzSensor(DZ_TEMP_HUM, data);
|
||||
}
|
||||
}
|
||||
|
||||
void DomoticzSensorPowerEnergy(int power, char *energy) {
|
||||
char data[16];
|
||||
snprintf_P(data, sizeof(data), PSTR("%d;%s"), power, energy);
|
||||
DomoticzSensor(DZ_POWER_ENERGY, data);
|
||||
}
|
||||
|
||||
void DomoticzSensorP1SmartMeter(char *usage1, char *usage2, char *return1, char *return2, int power) {
|
||||
//usage1 = energy usage meter tariff 1, This is an incrementing counter
|
||||
//usage2 = energy usage meter tariff 2, This is an incrementing counter
|
||||
//return1 = energy return meter tariff 1, This is an incrementing counter
|
||||
//return2 = energy return meter tariff 2, This is an incrementing counter
|
||||
//power = if >= 0 actual usage power. if < 0 actual return power (Watt)
|
||||
int consumed = power;
|
||||
int produced = 0;
|
||||
if (power < 0) {
|
||||
consumed = 0;
|
||||
produced = -power;
|
||||
}
|
||||
char data[64];
|
||||
snprintf_P(data, sizeof(data), PSTR("%s;%s;%s;%s;%d;%d"), usage1, usage2, return1, return2, consumed, produced);
|
||||
DomoticzSensor(DZ_P1_SMART_METER, data);
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void DomoticzInit(void) {
|
||||
if (Settings->flag.mqtt_enabled) { // SetOption3 - Enable MQTT
|
||||
Domoticz = (Domoticz_t*)calloc(1, sizeof(Domoticz_t)); // Need calloc to reset registers to 0/false
|
||||
if (nullptr == Domoticz) { return; }
|
||||
|
||||
DomoticzSettingsLoad(0);
|
||||
Domoticz->update_flag = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Commands
|
||||
\*********************************************************************************************/
|
||||
|
||||
void CmndDomoticzIdx(void) {
|
||||
// DzIdx0 0 - Reset all disabling subscription too
|
||||
// DzIdx1 403 - Relate relay1 (=Power1) to Domoticz Idx 403 persistent
|
||||
// DzIdx5 403 - Relate relay5 (=Power5) to Domoticz Idx 403 non-persistent (need a rule at boot to become persistent)
|
||||
if ((XdrvMailbox.index >= 0) && (XdrvMailbox.index <= MAX_RELAYS_SET)) {
|
||||
if (XdrvMailbox.payload >= 0) {
|
||||
if (0 == XdrvMailbox.index) {
|
||||
for (uint32_t i = 0; i < MAX_RELAYS_SET; i++) {
|
||||
DomoticzSetRelayIdx(i, 0);
|
||||
}
|
||||
} else {
|
||||
DomoticzSetRelayIdx(XdrvMailbox.index -1, XdrvMailbox.payload);
|
||||
}
|
||||
DomoticzMqttSubscribe();
|
||||
}
|
||||
ResponseCmndIdxNumber(DomoticzRelayIdx(XdrvMailbox.index -1));
|
||||
}
|
||||
}
|
||||
|
||||
void CmndDomoticzKeyIdx(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_RELAYS_SET)) {
|
||||
if (XdrvMailbox.payload >= 0) {
|
||||
Domoticz->Settings.key_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Domoticz->Settings.key_idx[XdrvMailbox.index -1]);
|
||||
}
|
||||
}
|
||||
|
||||
void CmndDomoticzSwitchIdx(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_RELAYS_SET)) {
|
||||
if (XdrvMailbox.payload >= 0) {
|
||||
Domoticz->Settings.switch_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Domoticz->Settings.switch_idx[XdrvMailbox.index -1]);
|
||||
}
|
||||
}
|
||||
|
||||
void CmndDomoticzSensorIdx(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= DZ_MAX_SENSORS)) {
|
||||
if (XdrvMailbox.payload >= 0) {
|
||||
Domoticz->Settings.sensor_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Domoticz->Settings.sensor_idx[XdrvMailbox.index -1]);
|
||||
}
|
||||
}
|
||||
|
||||
void CmndDomoticzUpdateTimer(void) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
|
||||
Domoticz->Settings.update_timer = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndNumber(Domoticz->Settings.update_timer);
|
||||
}
|
||||
|
||||
void CmndDomoticzSend(void) {
|
||||
/*
|
||||
DzSend1 <idx>,<values> - {\"idx\":<idx>,\"nvalue\":0,\"svalue\":\"<values>\",\"Battery\":xx,\"RSSI\":yy}
|
||||
rule1 on power1#state do dzsend1 9001,%value% endon
|
||||
DzSend1 418,%var1%;%var2% or DzSend1 418,%var1%:%var2% - Notice colon as substitute to semi-colon
|
||||
DzSend2 <idx>,<values> - USE_SHUTTER only - {\"idx\":<idx>,\"nvalue\":<position>,\"svalue\":\"<values>\",\"Battery\":xx,\"RSSI\":yy}
|
||||
DzSend3 <idx>,<values> - {\"idx\":<idx>,\"nvalue\":<values>,\"Battery\":xx,\"RSSI\":yy}
|
||||
DzSend4 <idx>,<state> - {\"command\":\"switchlight\",\"idx\":<idx>,\"switchcmd\":\"<state>\"}
|
||||
DzSend5 <idx>,<state> - {\"command\":\"switchscene\",\"idx\":<idx>,\"switchcmd\":\"<state>\"}
|
||||
*/
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 5)) {
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
if (strchr(XdrvMailbox.data, ',') != nullptr) { // Process parameter entry
|
||||
char *data;
|
||||
uint32_t index = strtoul(strtok_r(XdrvMailbox.data, ",", &data), nullptr, 10);
|
||||
if ((index > 0) && (data != nullptr)) {
|
||||
ReplaceChar(data,':',';'); // As a workaround for command backlog inter-command separator
|
||||
if (XdrvMailbox.index > 3) {
|
||||
uint32_t state = strtoul(data, nullptr, 10); // 0, 1 or 2
|
||||
DomoticzSendSwitch(XdrvMailbox.index -4, index, state);
|
||||
} else {
|
||||
uint32_t type = DZ_TEMP;
|
||||
if (2 == XdrvMailbox.index) { type = DZ_SHUTTER; }
|
||||
else if (3 == XdrvMailbox.index) { type = DZ_AIRQUALITY; }
|
||||
DomoticzSendData(type, index, data);
|
||||
}
|
||||
ResponseCmndDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Presentation
|
||||
\*********************************************************************************************/
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
|
||||
#define WEB_HANDLE_DOMOTICZ "dm"
|
||||
|
||||
const char HTTP_BTN_MENU_DOMOTICZ[] PROGMEM =
|
||||
"<p><form action='" WEB_HANDLE_DOMOTICZ "' method='get'><button>" D_CONFIGURE_DOMOTICZ "</button></form></p>";
|
||||
|
||||
const char HTTP_FORM_DOMOTICZ[] PROGMEM =
|
||||
"<fieldset><legend><b> " D_DOMOTICZ_PARAMETERS " </b></legend>"
|
||||
"<form method='post' action='" WEB_HANDLE_DOMOTICZ "'>"
|
||||
"<table>";
|
||||
const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM =
|
||||
"<tr><td style='width:260px'><b>" D_DOMOTICZ_IDX " %d</b></td><td style='width:70px'><input id='r%d' placeholder='0' value='%d'></td></tr>"
|
||||
"<tr><td style='width:260px'><b>" D_DOMOTICZ_KEY_IDX " %d</b></td><td style='width:70px'><input id='k%d' placeholder='0' value='%d'></td></tr>";
|
||||
const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM =
|
||||
"<tr><td style='width:260px'><b>" D_DOMOTICZ_SWITCH_IDX " %d</b></td><td style='width:70px'><input id='s%d' placeholder='0' value='%d'></td></tr>";
|
||||
const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM =
|
||||
"<tr><td style='width:260px'><b>" D_DOMOTICZ_SENSOR_IDX " %d</b> %s</td><td style='width:70px'><input id='l%d' placeholder='0' value='%d'></td></tr>";
|
||||
const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM =
|
||||
"<tr><td style='width:260px'><b>" D_DOMOTICZ_UPDATE_TIMER "</b> (" STR(DOMOTICZ_UPDATE_TIMER) ")</td><td style='width:70px'><input id='ut' placeholder='" STR(DOMOTICZ_UPDATE_TIMER) "' value='%d'></td></tr>";
|
||||
|
||||
void HandleDomoticzConfiguration(void) {
|
||||
if (!HttpCheckPriviledgedAccess()) { return; }
|
||||
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_DOMOTICZ));
|
||||
|
||||
if (Webserver->hasArg(F("save"))) {
|
||||
DomoticzSaveSettings();
|
||||
HandleConfiguration();
|
||||
return;
|
||||
}
|
||||
|
||||
char stemp[40];
|
||||
|
||||
WSContentStart_P(PSTR(D_CONFIGURE_DOMOTICZ));
|
||||
WSContentSendStyle();
|
||||
WSContentSend_P(HTTP_FORM_DOMOTICZ);
|
||||
for (uint32_t i = 0; i < MAX_RELAYS_SET; i++) {
|
||||
if (i < TasmotaGlobal.devices_present) {
|
||||
WSContentSend_P(HTTP_FORM_DOMOTICZ_RELAY,
|
||||
i +1, i, Domoticz->Settings.relay_idx[i],
|
||||
i +1, i, Domoticz->Settings.key_idx[i]);
|
||||
}
|
||||
if (PinUsed(GPIO_SWT1, i)) {
|
||||
WSContentSend_P(HTTP_FORM_DOMOTICZ_SWITCH,
|
||||
i +1, i, Domoticz->Settings.switch_idx[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), i, Domoticz->Settings.sensor_idx[i]);
|
||||
}
|
||||
WSContentSend_P(HTTP_FORM_DOMOTICZ_TIMER, Domoticz->Settings.update_timer);
|
||||
WSContentSend_P(PSTR("</table>"));
|
||||
WSContentSend_P(HTTP_FORM_END);
|
||||
WSContentSpaceButton(BUTTON_CONFIGURATION);
|
||||
WSContentStop();
|
||||
}
|
||||
|
||||
String DomoticzAddWebCommand(const char* command, const char* arg, uint32_t value) {
|
||||
char tmp[8]; // WebGetArg numbers only
|
||||
WebGetArg(arg, tmp, sizeof(tmp));
|
||||
if (!strlen(tmp)) { return ""; }
|
||||
if (atoi(tmp) == value) { return ""; }
|
||||
return AddWebCommand(command, arg, PSTR("0"));
|
||||
}
|
||||
|
||||
void DomoticzSaveSettings(void) {
|
||||
String cmnd = F(D_CMND_BACKLOG "0 ");
|
||||
cmnd += AddWebCommand(PSTR(D_PRFX_DOMOTICZ D_CMND_UPDATETIMER), PSTR("ut"), STR(DOMOTICZ_UPDATE_TIMER));
|
||||
char arg_idx[5];
|
||||
char cmnd2[24];
|
||||
for (uint32_t i = 0; i < MAX_RELAYS_SET; i++) {
|
||||
snprintf_P(cmnd2, sizeof(cmnd2), PSTR(D_PRFX_DOMOTICZ D_CMND_IDX "%d"), i +1);
|
||||
snprintf_P(arg_idx, sizeof(arg_idx), PSTR("r%d"), i);
|
||||
cmnd += DomoticzAddWebCommand(cmnd2, arg_idx, Domoticz->Settings.relay_idx[i]);
|
||||
snprintf_P(cmnd2, sizeof(cmnd2), PSTR(D_PRFX_DOMOTICZ D_CMND_KEYIDX "%d"), i +1);
|
||||
arg_idx[0] = 'k';
|
||||
cmnd += DomoticzAddWebCommand(cmnd2, arg_idx, Domoticz->Settings.key_idx[i]);
|
||||
snprintf_P(cmnd2, sizeof(cmnd2), PSTR(D_PRFX_DOMOTICZ D_CMND_SWITCHIDX "%d"), i +1);
|
||||
arg_idx[0] = 's';
|
||||
cmnd += DomoticzAddWebCommand(cmnd2, arg_idx, Domoticz->Settings.switch_idx[i]);
|
||||
}
|
||||
for (uint32_t i = 0; i < DZ_MAX_SENSORS; i++) {
|
||||
snprintf_P(cmnd2, sizeof(cmnd2), PSTR(D_PRFX_DOMOTICZ D_CMND_SENSORIDX "%d"), i +1);
|
||||
snprintf_P(arg_idx, sizeof(arg_idx), PSTR("l%d"), i);
|
||||
cmnd += DomoticzAddWebCommand(cmnd2, arg_idx, Domoticz->Settings.sensor_idx[i]);
|
||||
}
|
||||
ExecuteWebCommand((char*)cmnd.c_str());
|
||||
}
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xdrv07(uint32_t function) {
|
||||
bool result = false;
|
||||
|
||||
if (FUNC_PRE_INIT == function) {
|
||||
DomoticzInit();
|
||||
}
|
||||
else if (Domoticz) {
|
||||
switch (function) {
|
||||
case FUNC_EVERY_SECOND:
|
||||
DomoticzMqttUpdate();
|
||||
break;
|
||||
case FUNC_MQTT_DATA:
|
||||
result = DomoticzMqttData();
|
||||
break;
|
||||
case FUNC_RESET_SETTINGS:
|
||||
DomoticzSettingsLoad(1);
|
||||
break;
|
||||
case FUNC_SAVE_SETTINGS:
|
||||
DomoticzSettingsSave();
|
||||
break;
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_ADD_BUTTON:
|
||||
WSContentSend_P(HTTP_BTN_MENU_DOMOTICZ);
|
||||
break;
|
||||
case FUNC_WEB_ADD_HANDLER:
|
||||
WebServer_on(PSTR("/" WEB_HANDLE_DOMOTICZ), HandleDomoticzConfiguration);
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
case FUNC_MQTT_SUBSCRIBE:
|
||||
DomoticzMqttSubscribe();
|
||||
#ifdef USE_SHUTTER
|
||||
if (Domoticz->Settings.sensor_idx[DZ_SHUTTER]) {
|
||||
Domoticz->is_shutter = true;
|
||||
}
|
||||
#endif // USE_SHUTTER
|
||||
break;
|
||||
case FUNC_MQTT_INIT:
|
||||
Domoticz->update_timer = 2;
|
||||
break;
|
||||
case FUNC_SHOW_SENSOR:
|
||||
// DomoticzSendSensor();
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = DecodeCommand(kDomoticzCommands, DomoticzCommand);
|
||||
break;
|
||||
case FUNC_ACTIVE:
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_DOMOTICZ
|
||||
#endif // ESP32
|
Loading…
x
Reference in New Issue
Block a user