diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index be07e8788..98b13e80e 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -7,6 +7,10 @@ * Add initial support for shutters by Stefan Bode (#288) * Add command to MCP230xx: sensor29 pin,0/1/2 for OFF/ON/TOGGLE * Add initial support for PCF8574 I2C I/O Expander (currently output only) by Stefan Bode + * Add command SetOption71 0/1 to switch between different Modbus Active Energy registers on DDS238-2 energy meters (#6531) + * Change command SetOption43 to make it more general. Now supports PS_16_DZ driver too (#6547) + * Change command handling by moving buffers up in chain solving MQTTlog support (#6524) + * Change detection of non-MQTT commands by allowing non-space characters as delimiter (#6540) * Fix TasmotaSerial: move serial send to IRAM for high speed baud rates * * 6.6.0.13 20190922 diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index f53267421..71c4a1de1 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v6.6.0.4 + * Updated until v6.6.0.14 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -443,17 +443,17 @@ #define D_ENERGY_TOTAL "Energie insgesamt" // xdrv_27_shutter.ino -#define D_OPEN "Open" -#define D_CLOSE "Close" -#define D_DOMOTICZ_SHUTTER "Shutter" +#define D_OPEN "Öffnen" +#define D_CLOSE "Schliessen" +#define D_DOMOTICZ_SHUTTER "Rollo" // xdrv_28_pcf8574.ino -#define D_CONFIGURE_PCF8574 "Configure PCF8574" -#define D_PCF8574_PARAMETERS "PCF8574 parameters" -#define D_INVERT_PORTS "Invert Ports" -#define D_DEVICE "Device" -#define D_DEVICE_INPUT "Input" -#define D_DEVICE_OUTPUT "Output" +#define D_CONFIGURE_PCF8574 "Konfiguriere PCF8574" +#define D_PCF8574_PARAMETERS "PCF8574 Parameter" +#define D_INVERT_PORTS "Invertiere Ports" +#define D_DEVICE "Gerät" +#define D_DEVICE_INPUT "Eingang" +#define D_DEVICE_OUTPUT "Ausgang" // xsns_05_ds18b20.ino #define D_SENSOR_BUSY "Sensor beschäftigt" diff --git a/sonoff/settings.h b/sonoff/settings.h index 4f808586d..c2be9d6e3 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -84,7 +84,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t pwm_multi_channels : 1; // bit 18 (v6.6.0.3) - SetOption68 - Enable multi-channels PWM instead of Color PWM uint32_t tuya_dimmer_min_limit : 1; // bit 19 (v6.6.0.5) - SetOption69 - Limits Tuya dimmers to minimum of 10% (25) when enabled. uint32_t energy_weekend : 1; // bit 20 (v6.6.0.8) - CMND_TARIFF - uint32_t spare21 : 1; + uint32_t dds2382_model : 1; // bit 21 (v6.6.0.14) - SetOption71 - Select different Modbus registers for Active Energy (#6531) uint32_t spare22 : 1; uint32_t spare23 : 1; uint32_t spare24 : 1; diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 289c8392b..f16273f7c 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -125,8 +125,8 @@ #ifndef ENERGY_OVERTEMP #define ENERGY_OVERTEMP 90 // Overtemp in Celsius #endif -#ifndef TUYA_DIMMER_MAX -#define TUYA_DIMMER_MAX 100 +#ifndef DEFAULT_DIMMER_MAX +#define DEFAULT_DIMMER_MAX 100 #endif enum WebColors { @@ -774,7 +774,7 @@ void SettingsDefaultSet2(void) // Settings.light_rotation = 0; SettingsDefaultSet_5_8_1(); // Clock color - Settings.param[P_TUYA_DIMMER_MAX] = TUYA_DIMMER_MAX; + Settings.param[P_DIMMER_MAX] = DEFAULT_DIMMER_MAX; // Display SettingsDefaultSet_5_10_1(); // Display settings @@ -1084,9 +1084,9 @@ void SettingsDelta(void) if (Settings.version < 0x06060008) { // Move current tuya dimmer range to the new param. if (Settings.flag3.tuya_dimmer_range_255) { - Settings.param[P_TUYA_DIMMER_MAX] = 100; + Settings.param[P_DIMMER_MAX] = 100; } else { - Settings.param[P_TUYA_DIMMER_MAX] = 255; + Settings.param[P_DIMMER_MAX] = 255; } } if (Settings.version < 0x06060009) { diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 46c0868e2..c1c19f3fe 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -249,7 +249,7 @@ enum Shortcuts { SC_CLEAR, SC_DEFAULT, SC_USER }; enum SettingsParamIndex { P_HOLD_TIME, P_MAX_POWER_RETRY, P_ex_TUYA_DIMMER_ID, P_MDNS_DELAYED_START, P_BOOT_LOOP_OFFSET, P_RGB_REMAP, P_IR_UNKNOW_THRESHOLD, // SetOption32 .. SetOption38 P_CSE7766_INVALID_POWER, P_HOLD_IGNORE, P_ex_TUYA_RELAYS, P_OVER_TEMP, // SetOption39 .. SetOption42 - P_TUYA_DIMMER_MAX, + P_DIMMER_MAX, P_ex_TUYA_VOLTAGE_ID, P_ex_TUYA_CURRENT_ID, P_ex_TUYA_POWER_ID, // SetOption43 .. SetOption46 P_ex_ENERGY_TARIFF1, P_ex_ENERGY_TARIFF2, // SetOption47 .. SetOption48 P_MAX_PARAM8 }; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49 diff --git a/sonoff/support_command.ino b/sonoff/support_command.ino index 0e2f6d4e6..182796519 100644 --- a/sonoff/support_command.ino +++ b/sonoff/support_command.ino @@ -81,55 +81,61 @@ void ResponseCmndIdxChar(const char* value) /********************************************************************************************/ -void ExecuteCommand(char *cmnd, uint32_t source) +void ExecuteCommand(const char *cmnd, uint32_t source) { - char *start; - char *token; - + // cmnd: "status 0" = stopic "status" and svalue " 0" + // cmnd: "var1 =1" = stopic "var1" and svalue " =1" + // cmnd: "var1=1" = stopic "var1" and svalue "=1" #ifdef USE_DEBUG_DRIVER ShowFreeMem(PSTR("ExecuteCommand")); #endif ShowSource(source); - token = strtok(cmnd, " "); - if (token != nullptr) { - start = strrchr(token, '/'); // Skip possible cmnd/sonoff/ preamble - if (start) { token = start +1; } + const char *pos = cmnd; + while (*pos && isspace(*pos)) { + pos++; // Skip all spaces } - uint32_t size = (token != nullptr) ? strlen(token) : 0; - char stopic[size +2]; // / + \0 - snprintf_P(stopic, sizeof(stopic), PSTR("/%s"), (token == nullptr) ? "" : token); - token = strtok(nullptr, ""); - size = (token != nullptr) ? strlen(token) : 0; - char svalue[size +1]; - strlcpy(svalue, (token == nullptr) ? "" : token, sizeof(svalue)); // Fixed 5.8.0b - CommandHandler(stopic, (uint8_t*)svalue, strlen(svalue)); + const char *start = pos; + // Get a command. Commands can only use letters, digits and underscores + while (*pos && (isalpha(*pos) || isdigit(*pos) || '_' == *pos || '/' == *pos)) { + if ('/' == *pos) { // Skip possible cmnd/sonoff/ preamble + start = pos + 1; + } + pos++; + } + if ('\0' == *start || pos <= start) { + return; // Did not find any command to execute + } + + uint32_t size = pos - start; + char stopic[size + 2]; // with leader '/' and end '\0' + stopic[0] = '/'; + memcpy(stopic+1, start, size); + stopic[size+1] = '\0'; + + char svalue[strlen(pos) +1]; // pos point to the start of parameters + strlcpy(svalue, pos, sizeof(svalue)); + CommandHandler(stopic, svalue, strlen(svalue)); } /********************************************************************************************/ -// topic: /power1 data: toggle = Console command -// topic: cmnd/sonoff/power1 data: toggle = Mqtt command using topic -// topic: cmnd/sonoffs/power1 data: toggle = Mqtt command using a group topic -// topic: cmnd/DVES_83BB10_fb/power1 data: toggle = Mqtt command using fallback topic +// topicBuf: /power1 dataBuf: toggle = Console command +// topicBuf: cmnd/sonoff/power1 dataBuf: toggle = Mqtt command using topic +// topicBuf: cmnd/sonoffs/power1 dataBuf: toggle = Mqtt command using a group topic +// topicBuf: cmnd/DVES_83BB10_fb/power1 dataBuf: toggle = Mqtt command using fallback topic -void CommandHandler(char* topic, uint8_t* data, uint32_t data_len) +void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len) { #ifdef USE_DEBUG_DRIVER ShowFreeMem(PSTR("CommandHandler")); #endif - char topicBuf[TOPSZ]; - strlcpy(topicBuf, topic, sizeof(topicBuf)); - - uint32_t i = 0; - for (i = 0; i < data_len; i++) { - if (!isspace(data[i])) { break; } // Skip leading spaces in data + while (*dataBuf && isspace(*dataBuf)) { + dataBuf++; // Skip leading spaces in data + data_len--; } - data_len -= i; - char dataBuf[data_len+1]; - memcpy(dataBuf, data +i, sizeof(dataBuf)); bool grpflg = (strstr(topicBuf, Settings.mqtt_grptopic) != nullptr); @@ -137,8 +143,9 @@ void CommandHandler(char* topic, uint8_t* data, uint32_t data_len) GetFallbackTopic_P(stemp1, CMND, ""); // Full Fallback topic = cmnd/DVES_xxxxxxxx_fb/ fallback_topic_flag = (!strncmp(topicBuf, stemp1, strlen(stemp1))); - char *type = strrchr(topicBuf, '/'); // Last part of received topic is always the command (type) + char *type = strrchr(topicBuf, '/'); // Last part of received topic is always the command (type) + uint32_t i = 0; uint32_t index = 1; bool user_index = false; if (type != nullptr) { @@ -156,7 +163,7 @@ void CommandHandler(char* topic, uint8_t* data, uint32_t data_len) type[i] = '\0'; } - DEBUG_CORE_LOG(PSTR("CMD: " D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " \"%s\", " D_DATA " \"%s\""), grpflg, index, type, dataBuf); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CMD: " D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " \"%s\", " D_DATA " \"%s\""), grpflg, index, type, dataBuf); if (type != nullptr) { Response_P(PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_ERROR "\"}")); @@ -686,11 +693,9 @@ void CmndSetoption(void) IrReceiveUpdateThreshold(); break; #endif -#ifdef USE_TUYA_MCU - case P_TUYA_DIMMER_MAX: + case P_DIMMER_MAX: restart_flag = 2; // Need a restart to update GUI break; -#endif } } } diff --git a/sonoff/support_udp.ino b/sonoff/support_udp.ino index 550e97b97..a33ca6973 100644 --- a/sonoff/support_udp.ino +++ b/sonoff/support_udp.ino @@ -85,7 +85,11 @@ void PollUdp(void) // AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), packet_buffer); // Simple Service Discovery Protocol (SSDP) +#ifdef USE_SCRIPT_HUE + if (!udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) { +#else if (devices_present && !udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) { +#endif udp_response_mutex = true; udp_remote_ip = PortUdp.remoteIP(); diff --git a/sonoff/xdrv_02_mqtt.ino b/sonoff/xdrv_02_mqtt.ino index d1bf375a6..edc844448 100644 --- a/sonoff/xdrv_02_mqtt.ino +++ b/sonoff/xdrv_02_mqtt.ino @@ -251,7 +251,7 @@ bool MqttPublishLib(const char* topic, bool retained) return result; } -void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) +void MqttDataHandler(char* mqtt_topic, uint8_t* mqtt_data, unsigned int data_len) { #ifdef USE_DEBUG_DRIVER ShowFreeMem(PSTR("MqttDataHandler")); @@ -262,8 +262,8 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) // Do not execute multiple times if Prefix1 equals Prefix2 if (!strcmp(Settings.mqtt_prefix[0], Settings.mqtt_prefix[1])) { - char *str = strstr(topic, Settings.mqtt_prefix[0]); - if ((str == topic) && mqtt_cmnd_publish) { + char *str = strstr(mqtt_topic, Settings.mqtt_prefix[0]); + if ((str == mqtt_topic) && mqtt_cmnd_publish) { if (mqtt_cmnd_publish > 3) { mqtt_cmnd_publish -= 3; } else { @@ -273,13 +273,22 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) } } - data[data_len] = 0; + // Save MQTT data ASAP as it's data is discarded by PubSubClient with next publish as used in MQTTlog + char topic[TOPSZ]; + strlcpy(topic, mqtt_topic, sizeof(topic)); + mqtt_data[data_len] = 0; + char data[data_len +1]; + memcpy(data, mqtt_data, sizeof(data)); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_MQTT D_RECEIVED_TOPIC " %s, " D_DATA_SIZE " %d, " D_DATA " %s"), topic, data_len, data); -// if (LOG_LEVEL_DEBUG_MORE <= seriallog_level) { Serial.println(dataBuf); } + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_MQTT D_RECEIVED_TOPIC " \"%s\", " D_DATA_SIZE " %d, " D_DATA " \"%s\""), topic, data_len, data); +// if (LOG_LEVEL_DEBUG_MORE <= seriallog_level) { Serial.println(data); } // MQTT pre-processing - if (XdrvMqttData(topic, strlen(topic), (char*)data, data_len)) { return; } + XdrvMailbox.index = strlen(topic); + XdrvMailbox.data_len = data_len; + XdrvMailbox.topic = topic; + XdrvMailbox.data = (char*)data; + if (XdrvCall(FUNC_MQTT_DATA)) { return; } ShowSource(SRC_MQTT); diff --git a/sonoff/xdrv_07_domoticz.ino b/sonoff/xdrv_07_domoticz.ino index 44959045b..0bdc22b83 100644 --- a/sonoff/xdrv_07_domoticz.ino +++ b/sonoff/xdrv_07_domoticz.ino @@ -199,102 +199,104 @@ void DomoticzMqttSubscribe(void) bool DomoticzMqttData(void) { - char stemp1[10]; - unsigned long idx = 0; - int16_t nvalue = -1; - bool found = false; - domoticz_update_flag = true; - if (!strncmp(XdrvMailbox.topic, domoticz_out_topic, strlen(domoticz_out_topic))) { - if (XdrvMailbox.data_len < 20) { - return true; // No valid data - } - StaticJsonBuffer<400> jsonBuf; - JsonObject& domoticz = jsonBuf.parseObject(XdrvMailbox.data); - if (!domoticz.success()) { - return true; // To much or invalid data - } + + if (strncasecmp(XdrvMailbox.topic, domoticz_out_topic, strlen(domoticz_out_topic)) != 0) { + return false; // Process unchanged data + } + + // topic is domoticz/out so try to analyse + if (XdrvMailbox.data_len < 20) { + return true; // No valid data + } + StaticJsonBuffer<400> jsonBuf; + JsonObject& domoticz = jsonBuf.parseObject(XdrvMailbox.data); + if (!domoticz.success()) { + return true; // To much or invalid data + } // if (strcmp_P(domoticz["dtype"],PSTR("Light/Switch"))) { // return true; // } - idx = domoticz["idx"]; - if (domoticz.containsKey("nvalue")) { - nvalue = domoticz["nvalue"]; - } + uint32_t idx = domoticz["idx"]; + int16_t nvalue = -1; + if (domoticz.containsKey("nvalue")) { + nvalue = domoticz["nvalue"]; + } - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ "idx %d, nvalue %d"), idx, nvalue); + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ "idx %d, nvalue %d"), idx, nvalue); - if ((idx > 0) && (nvalue >= 0) && (nvalue <= 15)) { - uint8_t maxdev = (devices_present > MAX_DOMOTICZ_IDX) ? MAX_DOMOTICZ_IDX : devices_present; - for (uint32_t i = 0; i < maxdev; i++) { - if (idx == Settings.domoticz_relay_idx[i]) { - bool iscolordimmer = strcmp_P(domoticz["dtype"],PSTR("Color Switch")) == 0; - snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), i +1); + bool found = false; + if ((idx > 0) && (nvalue >= 0) && (nvalue <= 15)) { + uint8_t maxdev = (devices_present > MAX_DOMOTICZ_IDX) ? MAX_DOMOTICZ_IDX : devices_present; + for (uint32_t i = 0; i < maxdev; i++) { + if (idx == Settings.domoticz_relay_idx[i]) { + bool iscolordimmer = strcmp_P(domoticz["dtype"],PSTR("Color Switch")) == 0; + char stemp1[10]; + snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), i +1); #ifdef USE_SONOFF_IFAN - if (IsModuleIfan() && (1 == i)) { // Idx 2 is fanspeed - uint8_t svalue = 0; - if (domoticz.containsKey("svalue1")) { - svalue = domoticz["svalue1"]; - } else { - return true; // Invalid data - } - svalue = (nvalue == 2) ? svalue / 10 : 0; - if (GetFanspeed() == svalue) { - return true; // Stop loop as already set - } - if (TimePassedSince(domoticz_fan_debounce) < 1000) { - return true; // Stop loop if device in limbo - } - snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_FANSPEED)); - snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), svalue); - found = true; - } else + if (IsModuleIfan() && (1 == i)) { // Idx 2 is fanspeed + uint8_t svalue = 0; + if (domoticz.containsKey("svalue1")) { + svalue = domoticz["svalue1"]; + } else { + return true; // Invalid data + } + svalue = (nvalue == 2) ? svalue / 10 : 0; + if (GetFanspeed() == svalue) { + return true; // Stop loop as already set + } + if (TimePassedSince(domoticz_fan_debounce) < 1000) { + return true; // Stop loop if device in limbo + } + snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_FANSPEED)); + snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), svalue); + found = true; + } else #endif // USE_SONOFF_IFAN - if (iscolordimmer && 10 == nvalue) { // Color_SetColor - JsonObject& color = domoticz["Color"]; - uint16_t level = nvalue = domoticz["svalue1"]; - uint16_t r = color["r"]; r = r * level / 100; - uint16_t g = color["g"]; g = g * level / 100; - uint16_t b = color["b"]; b = b * level / 100; - uint16_t cw = color["cw"]; cw = cw * level / 100; - uint16_t ww = color["ww"]; ww = ww * level / 100; - 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); - found = true; - } - else if ((!iscolordimmer && 2 == nvalue) || // gswitch_sSetLevel - (iscolordimmer && 15 == nvalue)) { // Color_SetBrightnessLevel - if (domoticz.containsKey("svalue1")) { - nvalue = domoticz["svalue1"]; - } else { - return true; // Invalid data - } - if (light_type && (Settings.light_dimmer == nvalue) && ((power >> i) &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); - found = true; - } - else if (1 == nvalue || 0 == nvalue) { - if (((power >> i) &1) == (power_t)nvalue) { - return true; // Stop loop - } - snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_POWER "%s"), (devices_present > 1) ? stemp1 : ""); - snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue); - found = true; - } - break; + if (iscolordimmer && 10 == nvalue) { // Color_SetColor + JsonObject& color = domoticz["Color"]; + uint16_t level = nvalue = domoticz["svalue1"]; + uint16_t r = color["r"]; r = r * level / 100; + uint16_t g = color["g"]; g = g * level / 100; + uint16_t b = color["b"]; b = b * level / 100; + uint16_t cw = color["cw"]; cw = cw * level / 100; + uint16_t ww = color["ww"]; ww = ww * level / 100; + 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); + found = true; } + else if ((!iscolordimmer && 2 == nvalue) || // gswitch_sSetLevel + (iscolordimmer && 15 == nvalue)) { // Color_SetBrightnessLevel + if (domoticz.containsKey("svalue1")) { + nvalue = domoticz["svalue1"]; + } else { + return true; // Invalid data + } + if (light_type && (Settings.light_dimmer == nvalue) && ((power >> i) &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); + found = true; + } + else if (1 == nvalue || 0 == nvalue) { + if (((power >> i) &1) == (power_t)nvalue) { + return true; // Stop loop + } + snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_POWER "%s"), (devices_present > 1) ? stemp1 : ""); + snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue); + found = true; + } + break; } } - if (!found) { return true; } // No command received - - AddLog_P2(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 unchanged or new data + if (!found) { return true; } // No command received + + AddLog_P2(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 } /*********************************************************************************************/ diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index b26e5402d..04a6d3413 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -698,10 +698,10 @@ void RulesTeleperiod(void) */ bool RulesMqttData(void) { - bool serviced = false; if (XdrvMailbox.data_len < 1 || XdrvMailbox.data_len > 256) { return false; } + bool serviced = false; String sTopic = XdrvMailbox.topic; String sData = XdrvMailbox.data; //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: MQTT Topic %s, Event %s"), XdrvMailbox.topic, XdrvMailbox.data); diff --git a/sonoff/xdrv_10_scripter.ino b/sonoff/xdrv_10_scripter.ino index ce0430f8f..4c12c6253 100644 --- a/sonoff/xdrv_10_scripter.ino +++ b/sonoff/xdrv_10_scripter.ino @@ -3366,30 +3366,8 @@ void ScriptSaveSettings(void) { #endif -#if defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE) && defined(USE_LIGHT) +#if defined(USE_SCRIPT_HUE) && defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE) && defined(USE_LIGHT) -/* -"state": { -"temperature": 2674, -"lastupdated": "2017-08-04T12:13:04" -}, -"config": { -"on": true, -"battery": 100, -"reachable": true, -"alert": "none", -"ledindication": false, -"usertest": false, -"pending": [] -}, -"name": "Hue temperature sensor 1", -"type": "ZLLTemperature", -"modelid": "SML001", -"manufacturername": "Philips", -"swversion": "6.1.0.18912", -"uniqueid": "xxx" -} -*/ #define HUE_DEV_MVNUM 5 #define HUE_DEV_NSIZE 16 @@ -3414,8 +3392,76 @@ const char SCRIPT_HUE_LIGHTS_STATUS_JSON1[] PROGMEM = "\"uniqueid\":\"{j2\"," "\"swversion\":\"5.50.1.19085\"}"; +/* +const char SCRIPT_HUE_LIGHTS_STATUS_JSON2[] PROGMEM = + "{\"state\":" + "{\"temperature\": 2674," + "\"lastupdated\": \"2019-08-04T12:13:04\"}," + "\"config\": {" + "\"on\": true," + "\"battery\": 100," + "\"reachable\": true," + "\"alert\": \"none\"," + "\"ledindication\": false," + "\"usertest\": false," + "\"pending\": []" + "}," + "\"name\": \"{j1\"," + "\"type\": \"ZLLTemperature\"," + "\"modelid\": \"SML001\"," + "\"manufacturername\": \"Philips\"," + "\"swversion\": \"6.1.0.18912\"," + "\"uniqueid\": \"{j2\"}"; +*/ + + +const char SCRIPT_HUE_LIGHTS_STATUS_JSON2[] PROGMEM = +"{\"state\":{" +"\"presence\":{state}," +"\"lastupdated\":\"2017-10-01T12:37:30\"" +"}," +"\"swupdate\":{" +"\"state\":\"noupdates\"," +"\"lastinstall\": null" +"}," +"\"config\":{" +"\"on\":true," +"\"battery\":100," +"\"reachable\":true," +"\"alert\":\"none\"," +"\"ledindication\":false," +"\"usertest\":false," +"\"sensitivity\":2," +"\"sensitivitymax\":2," +"\"pending\":[]" +"}," +"\"name\":\"{j1\"," +"\"type\":\"ZLLPresence\"," +"\"modelid\":\"SML001\"," +"\"manufacturername\":\"Philips\"," +"\"swversion\":\"6.1.0.18912\"," +"\"uniqueid\":\"{j2\"" +"}"; + +/* + temperature ZLLTemperature + lightlevel ZLLLightLevel + presence ZLLPresence + */ + + void Script_HueStatus(String *response, uint16_t hue_devs) { + + if (hue_script[hue_devs].type=='P') { + *response+=FPSTR(SCRIPT_HUE_LIGHTS_STATUS_JSON2); + response->replace("{j1",hue_script[hue_devs].name); + response->replace("{j2", GetHueDeviceId(hue_devs)); + uint8_t pwr=glob_script_mem.fvars[hue_script[hue_devs].index[0]-1]; + response->replace("{state}", (pwr ? "true" : "false")); + return; + } + *response+=FPSTR(SCRIPT_HUE_LIGHTS_STATUS_JSON1); uint8_t pwr=glob_script_mem.fvars[hue_script[hue_devs].index[0]-1]; response->replace("{state}", (pwr ? "true" : "false")); @@ -3454,16 +3500,44 @@ void Script_HueStatus(String *response, uint16_t hue_devs) { light_status += ","; } - response->replace("{light_status}", light_status); - response->replace("{j1",hue_script[hue_devs].name); - response->replace("{j2", GetHueDeviceId(hue_devs<<8)); - - if (hue_script[hue_devs].type=='E') { - response->replace("{type}","Extended color light"); - } else { - response->replace("{type}","color light"); + float temp; + switch (hue_script[hue_devs].type) { + case 'E': + response->replace("{type}","Extended color light"); + break; + case 'S': + response->replace("{type}","color light"); + break; + case 'T': + response->replace("{type}","ZLLTemperature"); + temp=glob_script_mem.fvars[hue_script[hue_devs].index[2]-1]; + light_status += "\"temperature\":"; + light_status += String(temp*100); + light_status += ","; + break; + case 'L': + response->replace("{type}","ZLLLightLevel"); + temp=glob_script_mem.fvars[hue_script[hue_devs].index[2]-1]; + light_status += "\"lightlevel\":"; + light_status += String(temp); + light_status += ","; + break; + case 'P': + response->replace("{type}","ZLLPresence"); + temp=glob_script_mem.fvars[hue_script[hue_devs].index[0]-1]; + light_status += "\"presence\":"; + if (temp==0)light_status += "false"; + else light_status += "true"; + light_status += ","; + break; + default: + response->replace("{type}","color light"); + break; } + response->replace("{light_status}", light_status); + response->replace("{j1",hue_script[hue_devs].name); + response->replace("{j2", GetHueDeviceId(hue_devs)); } @@ -3570,7 +3644,13 @@ void Script_Check_Hue(String *response) { } // append response if (response) { - *response+=",\""+String(EncodeLightId(hue_devs+devices_present+1))+"\":"; + if (devices_present) { + *response+=",\""; + } + else { + if (hue_devs>0) *response+=",\""; + } + *response+=String(EncodeLightId(hue_devs+devices_present+1))+"\":"; Script_HueStatus(response,hue_devs); } @@ -3584,16 +3664,22 @@ void Script_Check_Hue(String *response) { lp++; } } -#if 0 - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Hue: %d"), hue_devs); - toLog(">>>>"); - toLog(response->c_str()); - toLog(response->c_str()+LOGSZ); +#if 1 + if (response) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Hue: %d"), hue_devs); + toLog(">>>>"); + toLog(response->c_str()); + toLog(response->c_str()+LOGSZ); + } #endif } const char sHUE_LIGHT_RESPONSE_JSON[] PROGMEM = "{\"success\":{\"/lights/{id/state/{cm\":{re}}"; + +const char sHUE_SENSOR_RESPONSE_JSON[] PROGMEM = + "{\"success\":{\"/lights/{id/state/{cm\":{re}}"; + const char sHUE_ERROR_JSON[] PROGMEM = "[{\"error\":{\"type\":901,\"address\":\"/\",\"description\":\"Internal Error\"}}]"; @@ -3649,6 +3735,27 @@ void Script_Handle_Hue(String *path) { glob_script_mem.type[hue_script[index].vindex[1]].bits.changed=1; resp = true; } + if (hue_json.containsKey("xy")) { // Saturation of the light. 254 is the most saturated (colored) and 0 is the least saturated (white). + float x, y; + x = hue_json["xy"][0]; + y = hue_json["xy"][1]; + const String &x_str = hue_json["xy"][0]; + const String &y_str = hue_json["xy"][1]; + uint8_t rr,gg,bb; + LightStateClass::XyToRgb(x, y, &rr, &gg, &bb); + LightStateClass::RgbToHsb(rr, gg, bb, &hue, &sat, nullptr); + if (resp) { response += ","; } + response += FPSTR(sHUE_LIGHT_RESPONSE_JSON); + response.replace("{id", String(device)); + response.replace("{cm", "xy"); + response.replace("{re", "[" + x_str + "," + y_str + "]"); + glob_script_mem.fvars[hue_script[index].index[2]-1]=hue; + glob_script_mem.type[hue_script[index].vindex[2]].bits.changed=1; + glob_script_mem.fvars[hue_script[index].index[3]-1]=sat; + glob_script_mem.type[hue_script[index].vindex[3]].bits.changed=1; + resp = true; + } + if (hue_json.containsKey("hue")) { // The hue value is a wrapping value between 0 and 65535. Both 0 and 65535 are red, 25500 is green and 46920 is blue. tmp = hue_json["hue"]; //hue = changeUIntScale(tmp, 0, 65535, 0, 359); @@ -4067,7 +4174,7 @@ const char SCRIPT_MSG_BUTTONa_TBL[] PROGMEM = "