diff --git a/README.md b/README.md index a5e309f9e..8f1b01512 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Sonoff-Tasmota Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE. -Current version is **3.9.7** - See ```sonoff/_releasenotes.ino``` for change information. +Current version is **3.9.11** - See ```sonoff/_releasenotes.ino``` for change information. - This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic. - Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```. @@ -11,7 +11,7 @@ Current version is **3.9.7** - See ```sonoff/_releasenotes.ino``` for change inf See [Wiki](https://github.com/arendst/Sonoff-Tasmota/wiki) for more information.
See [Community](https://groups.google.com/d/forum/sonoffusers) for forum and more user experience. -Starting with version 2.0.0 the following devices are supported: +The following devices are supported: - [iTead Sonoff Basic](http://sonoff.itead.cc/en/products/sonoff/sonoff-basic) - [iTead Sonoff RF](http://sonoff.itead.cc/en/products/sonoff/sonoff-rf) - [iTead Sonoff SV](https://www.itead.cc/sonoff-sv.html) diff --git a/api/arduino/sonoff.ino.bin b/api/arduino/sonoff.ino.bin index b4306d1dc..644b8b625 100644 Binary files a/api/arduino/sonoff.ino.bin and b/api/arduino/sonoff.ino.bin differ diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index d0ee99334..e3a59587e 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,24 @@ -/* 3.9.7 20170129 +/* 3.9.11 20170204 + * Fix command I2Cscan + * Fix not allowed spaces in Topic, ButtonTopic and SwitchTopic + * Make all TELEMETRY, STATUS and COMMAND message topics unique (#4) + * Advertise command topic to be used by iobroker (#299) + * Fix butten (non)detection if no GPIO_KEY1 is defined (#13) + * Change WeMo serialnumber from 7 decimal chars to 8 hexadecimal chars (#18) + * Update web page with Build Date/Time, Emulation and mDNS Discovery and Advertise information (#21) + * + * 3.9.10 20170130 + * Add WS2812 Color Type selection (RGB or GRB) to user_config.h (#7) + * Hue api changes to support HUE App(s) (#8) + * + * 3.9.9 20170130 + * Add command status 10 showing sensor data + * Fix hlw status messages if hlw is disabled + * + * 3.9.8 20170130 + * Remove GPIO07 and GPIO08 from user selectable (#5) + * + * 3.9.7 20170129 * Fix possible WS2812 exceptions when using emulation * Add command Emulation to dynamic configure Belkin WeMo and Hue Bridge for Alexa * diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 4dfa6853a..b6bc9eecf 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -10,7 +10,7 @@ * ==================================================== */ -#define VERSION 0x03090700 // 3.9.7 +#define VERSION 0x03090B00 // 3.9.11 enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; enum week_t {Last, First, Second, Third, Fourth}; @@ -93,7 +93,7 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX}; #endif #define APP_BAUDRATE 115200 // Default serial baudrate -#define MAX_STATUS 9 +#define MAX_STATUS 10 enum butt_t {PRESSED, NOT_PRESSED}; @@ -927,6 +927,15 @@ void mqtt_publish(const char* topic, const char* data) mqtt_publish(topic, data, false); } +void mqtt_publish_topic_P(uint8_t prefix, const char* subtopic, const char* data) +{ + char romram[16], stopic[TOPSZ]; + + snprintf_P(romram, sizeof(romram), subtopic); + snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s"), (prefix) ? PUB_PREFIX2 : PUB_PREFIX, sysCfg.mqtt_topic, romram); + mqtt_publish(stopic, data); +} + void mqtt_publishPowerState(byte device) { char stopic[TOPSZ], svalue[MESSZ], sdevice[10]; @@ -943,14 +952,13 @@ void mqtt_publishPowerState(byte device) void mqtt_publishPowerBlinkState(byte device) { - char stopic[TOPSZ], svalue[MESSZ], sdevice[10]; + char svalue[MESSZ], sdevice[10]; if ((device < 1) || (device > Maxdevice)) device = 1; snprintf_P(sdevice, sizeof(sdevice), PSTR("%d"), device); - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/RESULT"), PUB_PREFIX, sysCfg.mqtt_topic); snprintf_P(svalue, sizeof(svalue), PSTR("{\"%s%s\":\"BLINK %s\"}"), sysCfg.mqtt_subtopic, (Maxdevice > 1) ? sdevice : "", (blink_mask & (0x01 << (device -1))) ? MQTT_STATUS_ON : MQTT_STATUS_OFF); - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(0, PSTR("RESULT"), svalue); } void mqtt_connected() @@ -958,6 +966,12 @@ void mqtt_connected() char stopic[TOPSZ], svalue[MESSZ]; if (sysCfg.mqtt_enabled) { + + // Satisfy iobroker (#299) + snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/POWER"), SUB_PREFIX, sysCfg.mqtt_topic); + svalue[0] ='\0'; + mqtt_publish(stopic, svalue); + snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/#"), SUB_PREFIX, sysCfg.mqtt_topic); mqttClient.subscribe(stopic); mqttClient.loop(); // Solve LmacRxBlk:1 messages @@ -973,24 +987,23 @@ void mqtt_connected() } if (mqttflag) { - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/RESULT"), PUB_PREFIX2, sysCfg.mqtt_topic); - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Info1\":{\"Module\":\"%s\", \"Version\":\"%s\", \"FallbackTopic\":\"%s\", \"GroupTopic\":\"%s\"}}"), + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Module\":\"%s\", \"Version\":\"%s\", \"FallbackTopic\":\"%s\", \"GroupTopic\":\"%s\"}"), my_module.name, Version, MQTTClient, sysCfg.mqtt_grptopic); - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(1, PSTR("INFO1"), svalue); #ifdef USE_WEBSERVER if (sysCfg.webserver) { - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Info2\":{\"WebserverMode\":\"%s\", \"Hostname\":\"%s\", \"IPaddress\":\"%s\"}}"), + snprintf_P(svalue, sizeof(svalue), PSTR("{\"WebserverMode\":\"%s\", \"Hostname\":\"%s\", \"IPaddress\":\"%s\"}"), (sysCfg.webserver == 2) ? "Admin" : "User", Hostname, WiFi.localIP().toString().c_str()); - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(1, PSTR("INFO2"), svalue); } #endif // USE_WEBSERVER if (sysCfg.mqtt_enabled && (MQTT_MAX_PACKET_SIZE < (TOPSZ+MESSZ))) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"Warning1\":\"Change MQTT_MAX_PACKET_SIZE in libraries/PubSubClient.h to at least %d\"}"), TOPSZ+MESSZ); - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(1, PSTR("WARNING1"), svalue); } if (!spiffsPresent()) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"Warning2\":\"No persistent config. Please reflash with at least 16K SPIFFS\"}")); - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(1, PSTR("WARNING2"), svalue); } if (sysCfg.tele_period) tele_period = sysCfg.tele_period -9; status_update_timer = 2; @@ -1106,13 +1119,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) index = 1; if (type != NULL) { - for (i = 0; i < strlen(type); i++) { - type[i] = toupper(type[i]); - if (isdigit(type[i])) { - index = atoi(type +i); - break; - } - } + for (i = 0; i < strlen(type); i++) type[i] = toupper(type[i]); + while (isdigit(type[i-1])) i--; + if (i < strlen(type)) index = atoi(type +i); type[i] = '\0'; } @@ -1122,7 +1131,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) mtopic, grpflg, index, type, dataBuf, dataBufUc); addLog(LOG_LEVEL_DEBUG, svalue); - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/RESULT"), PUB_PREFIX, sysCfg.mqtt_topic); +// snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/RESULT"), PUB_PREFIX, sysCfg.mqtt_topic); if (type != NULL) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"Command\":\"Error\"}")); if (sysCfg.ledstate &0x02) blinks++; @@ -1241,7 +1250,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) snprintf_P(svalue, sizeof(svalue), PSTR("%s%s (%d)"), svalue, stemp1, i +1); } snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue); - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(0, PSTR("RESULT"), svalue); snprintf_P(svalue, sizeof(svalue), PSTR("{\"Modules2\":\""), svalue); jsflg = 0; for (byte i = 11; i < MAXMODULE; i++) { @@ -1588,7 +1597,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) else if (sysCfg.mqtt_enabled && !grpflg && !strcmp(type,"TOPIC")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_topic))) { for(i = 0; i <= data_len; i++) - if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#')) dataBuf[i] = '_'; + if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) dataBuf[i] = '_'; if (!strcmp(dataBuf, MQTTClient)) payload = 1; strlcpy(sysCfg.mqtt_topic, (payload == 1) ? MQTT_TOPIC : dataBuf, sizeof(sysCfg.mqtt_topic)); restartflag = 2; @@ -1598,7 +1607,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) else if (sysCfg.mqtt_enabled && !grpflg && !strcmp(type,"BUTTONTOPIC")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.button_topic))) { for(i = 0; i <= data_len; i++) - if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#')) dataBuf[i] = '_'; + if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) dataBuf[i] = '_'; if (!strcmp(dataBuf, MQTTClient)) payload = 1; strlcpy(sysCfg.button_topic, (payload == 1) ? sysCfg.mqtt_topic : dataBuf, sizeof(sysCfg.button_topic)); } @@ -1607,7 +1616,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) else if (sysCfg.mqtt_enabled && !grpflg && !strcmp(type,"SWITCHTOPIC")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.switch_topic))) { for(i = 0; i <= data_len; i++) - if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#')) dataBuf[i] = '_'; + if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) dataBuf[i] = '_'; if (!strcmp(dataBuf, MQTTClient)) payload = 1; strlcpy(sysCfg.switch_topic, (payload == 1) ? sysCfg.mqtt_topic : dataBuf, sizeof(sysCfg.switch_topic)); } @@ -1672,17 +1681,17 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } if (type == NULL) { blinks = 201; - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands\":\"Status, SaveData, SaveSate, Sleep, Upgrade, Otaurl, Restart, Reset, WifiConfig, Seriallog, Syslog, LogHost, LogPort, SSId1, SSId2, Password1, Password2, AP%s\"}"), (!grpflg) ? ", Hostname, Module, Modules, GPIO, GPIOs" : ""); - mqtt_publish(stopic, svalue); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands1\":\"Status, SaveData, SaveSate, Sleep, Upgrade, Otaurl, Restart, Reset, WifiConfig, Seriallog, Syslog, LogHost, LogPort, SSId1, SSId2, Password1, Password2, AP%s\"}"), (!grpflg) ? ", Hostname, Module, Modules, GPIO, GPIOs" : ""); + mqtt_publish_topic_P(0, PSTR("COMMANDS1"), svalue); if (sysCfg.mqtt_enabled) { - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands\":\"Mqtt, MqttHost, MqttPort, MqttUser, MqttPassword%s, GroupTopic, Units, Timezone, LedState, LedPower, TelePeriod\"}"), (!grpflg) ? ", MqttClient, Topic, ButtonTopic, ButtonRetain, SwitchTopic, SwitchRetain, PowerRetain" : ""); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands2\":\"Mqtt, MqttHost, MqttPort, MqttUser, MqttPassword%s, GroupTopic, Units, Timezone, LedState, LedPower, TelePeriod\"}"), (!grpflg) ? ", MqttClient, Topic, ButtonTopic, ButtonRetain, SwitchTopic, SwitchRetain, PowerRetain" : ""); } else { - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands\":\"Mqtt, Units, Timezone, LedState, LedPower, TelePeriod\"}"), (!grpflg) ? ", MqttClient" : ""); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands2\":\"Mqtt, Units, Timezone, LedState, LedPower, TelePeriod\"}"), (!grpflg) ? ", MqttClient" : ""); } - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(0, PSTR("COMMANDS2"), svalue); - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands\":\"%s%s, PulseTime, BlinkTime, BlinkCount"), (Maxdevice == 1) ? "Power, Light" : "Power1, Power2, Light1 Light2", (sysCfg.module != MOTOR) ? ", PowerOnState" : ""); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands3\":\"%s%s, PulseTime, BlinkTime, BlinkCount"), (Maxdevice == 1) ? "Power, Light" : "Power1, Power2, Light1 Light2", (sysCfg.module != MOTOR) ? ", PowerOnState" : ""); #ifdef USE_WEBSERVER snprintf_P(svalue, sizeof(svalue), PSTR("%s, Weblog, Webserver, Emulation"), svalue); #endif @@ -1694,18 +1703,20 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) if (pin[GPIO_WS2812] < 99) snprintf_P(svalue, sizeof(svalue), PSTR("%s, Pixels, Led, Color, Dimmer, Scheme, Fade, Speed, Width, Wakeup, LedTable"), svalue); #endif snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue); + mqtt_publish_topic_P(0, PSTR("COMMANDS3"), svalue); #ifdef USE_DOMOTICZ - mqtt_publish(stopic, svalue); domoticz_commands(svalue, sizeof(svalue)); + mqtt_publish_topic_P(0, PSTR("COMMANDS4"), svalue); #endif // USE_DOMOTICZ if (hlw_flg) { - mqtt_publish(stopic, svalue); hlw_commands(svalue, sizeof(svalue)); + mqtt_publish_topic_P(0, PSTR("COMMANDS5"), svalue); } + } else { + mqtt_publish_topic_P(0, PSTR("RESULT"), svalue); } - mqtt_publish(stopic, svalue); } /********************************************************************************************/ @@ -1827,84 +1838,121 @@ void do_cmnd(char *cmnd) void publish_status(uint8_t payload) { - char stopic[TOPSZ], svalue[MESSZ], stemp1[TOPSZ], stemp2[10], stemp3[10]; + char svalue[MESSZ], stemp1[TOPSZ], stemp2[10], stemp3[10]; float ped, pi, pc; uint16_t pe, pw, pu; + uint8_t option = 0; // Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/RESULT"), - (!strcmp(SUB_PREFIX,PUB_PREFIX) && (!payload)) ? PUB_PREFIX2 : PUB_PREFIX, sysCfg.mqtt_topic); + option = (!strcmp(SUB_PREFIX,PUB_PREFIX) && (!payload)); if ((!sysCfg.mqtt_enabled) && (payload == 6)) payload = 99; + if ((!hlw_flg) && ((payload == 8) || (payload == 9))) payload = 99; if ((payload == 0) || (payload == 99)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"Status\":{\"Module\":%d, \"FriendlyName\":\"%s\", \"Topic\":\"%s\", \"ButtonTopic\":\"%s\", \"Subtopic\":\"%s\", \"Power\":%d, \"PowerOnState\":%d, \"LedState\":%d, \"SaveData\":%d, \"SaveState\":%d, \"ButtonRetain\":%d, \"PowerRetain\":%d}}"), sysCfg.module +1, sysCfg.friendlyname[0], sysCfg.mqtt_topic, sysCfg.button_topic, sysCfg.mqtt_subtopic, power, sysCfg.poweronstate, sysCfg.ledstate, sysCfg.savedata, sysCfg.savestate, sysCfg.mqtt_button_retain, sysCfg.mqtt_power_retain); - if (payload == 0) mqtt_publish(stopic, svalue); - } - - if (hlw_flg) { - if ((payload == 0) || (payload == 8)) { - hlw_readEnergy(0, ped, pe, pw, pu, pi, pc); - dtostrf(pi, 1, 3, stemp1); - dtostrf(ped, 1, 3, stemp2); - dtostrf(pc, 1, 2, stemp3); - snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusPWR\":{\"Voltage\":%d, \"Current\":\"%s\", \"Power\":%d, \"Today\":\"%s\", \"Factor\":\"%s\"}}"), - pu, stemp1, pw, stemp2, stemp3); - if (payload == 0) mqtt_publish(stopic, svalue); - } - - if ((payload == 0) || (payload == 9)) { - snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusPWRThreshold\":{\"PowerLow\":%d, \"PowerHigh\":%d, \"VoltageLow\":%d, \"VoltageHigh\":%d, \"CurrentLow\":%d, \"CurrentHigh\":%d}}"), - sysCfg.hlw_pmin, sysCfg.hlw_pmax, sysCfg.hlw_umin, sysCfg.hlw_umax, sysCfg.hlw_imin, sysCfg.hlw_imax); - if (payload == 0) mqtt_publish(stopic, svalue); - } + mqtt_publish_topic_P(option, PSTR("STATUS"), svalue); } if ((payload == 0) || (payload == 1)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusPRM\":{\"Baudrate\":%d, \"GroupTopic\":\"%s\", \"OtaUrl\":\"%s\", \"Uptime\":%d, \"Sleep\":%d, \"BootCount\":%d, \"SaveCount\":%d}}"), Baudrate, sysCfg.mqtt_grptopic, sysCfg.otaUrl, uptime, sysCfg.sleep, sysCfg.bootcount, sysCfg.saveFlag); - if (payload == 0) mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(option, PSTR("STATUS1"), svalue); } if ((payload == 0) || (payload == 2)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusFWR\":{\"Program\":\"%s\", \"Boot\":%d, \"SDK\":\"%s\"}}"), Version, ESP.getBootVersion(), ESP.getSdkVersion()); - if (payload == 0) mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(option, PSTR("STATUS2"), svalue); } if ((payload == 0) || (payload == 3)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusLOG\":{\"Seriallog\":%d, \"Weblog\":%d, \"Syslog\":%d, \"LogHost\":\"%s\", \"SSId1\":\"%s\", \"SSId2\":\"%s\", \"TelePeriod\":%d}}"), sysCfg.seriallog_level, sysCfg.weblog_level, sysCfg.syslog_level, sysCfg.syslog_host, sysCfg.sta_ssid[0], sysCfg.sta_ssid[1], sysCfg.tele_period); - if (payload == 0) mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(option, PSTR("STATUS3"), svalue); } if ((payload == 0) || (payload == 4)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusMEM\":{\"ProgramSize\":%d, \"Free\":%d, \"Heap\":%d, \"SpiffsStart\":%d, \"SpiffsSize\":%d, \"FlashSize\":%d, \"ProgramFlashSize\":%d}}"), ESP.getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024, ((uint32_t)&_SPIFFS_start - 0x40200000)/1024, (((uint32_t)&_SPIFFS_end - 0x40200000) - ((uint32_t)&_SPIFFS_start - 0x40200000))/1024, ESP.getFlashChipRealSize()/1024, ESP.getFlashChipSize()/1024); - if (payload == 0) mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(option, PSTR("STATUS4"), svalue); } if ((payload == 0) || (payload == 5)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusNET\":{\"Host\":\"%s\", \"IP\":\"%s\", \"Gateway\":\"%s\", \"Subnetmask\":\"%s\", \"Mac\":\"%s\", \"Webserver\":%d, \"WifiConfig\":%d}}"), Hostname, WiFi.localIP().toString().c_str(), WiFi.gatewayIP().toString().c_str(), WiFi.subnetMask().toString().c_str(), WiFi.macAddress().c_str(), sysCfg.webserver, sysCfg.sta_config); - if (payload == 0) mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(option, PSTR("STATUS5"), svalue); } if (((payload == 0) || (payload == 6)) && sysCfg.mqtt_enabled) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusMQT\":{\"Host\":\"%s\", \"Port\":%d, \"ClientMask\":\"%s\", \"Client\":\"%s\", \"User\":\"%s\", \"MAX_PACKET_SIZE\":%d, \"KEEPALIVE\":%d}}"), sysCfg.mqtt_host, sysCfg.mqtt_port, sysCfg.mqtt_client, MQTTClient, sysCfg.mqtt_user, MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE); - if (payload == 0) mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(option, PSTR("STATUS6"), svalue); } if ((payload == 0) || (payload == 7)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusTIM\":{\"UTC\":\"%s\", \"Local\":\"%s\", \"StartDST\":\"%s\", \"EndDST\":\"%s\", \"Timezone\":%d}}"), rtc_time(0).c_str(), rtc_time(1).c_str(), rtc_time(2).c_str(), rtc_time(3).c_str(), sysCfg.timezone); + mqtt_publish_topic_P(option, PSTR("STATUS7"), svalue); } + + if (hlw_flg) { + if ((payload == 0) || (payload == 8)) { + hlw_mqttStatus(svalue, sizeof(svalue)); + mqtt_publish_topic_P(option, PSTR("STATUS8"), svalue); + } + + if ((payload == 0) || (payload == 9)) { + snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusPTH\":{\"PowerLow\":%d, \"PowerHigh\":%d, \"VoltageLow\":%d, \"VoltageHigh\":%d, \"CurrentLow\":%d, \"CurrentHigh\":%d}}"), + sysCfg.hlw_pmin, sysCfg.hlw_pmax, sysCfg.hlw_umin, sysCfg.hlw_umax, sysCfg.hlw_imin, sysCfg.hlw_imax); + mqtt_publish_topic_P(option, PSTR("STATUS9"), svalue); + } + } + + if ((payload == 0) || (payload == 10)) { + uint8_t djson = 0; + snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusSNS\":")); + sensors_mqttPresent(svalue, sizeof(svalue), &djson); + if (!djson) snprintf_P(svalue, sizeof(svalue), PSTR("%s}"), svalue); + mqtt_publish_topic_P(option, PSTR("STATUS10"), svalue); + } +} + +void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) +{ + char stime[21]; - mqtt_publish(stopic, svalue); + snprintf_P(stime, sizeof(stime), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"), + rtcTime.Year, rtcTime.Month, rtcTime.Day, rtcTime.Hour, rtcTime.Minute, rtcTime.Second); + snprintf_P(svalue, ssvalue, PSTR("%s{\"Time\":\"%s\""), svalue, stime); + if (pin[GPIO_DSB] < 99) { +#ifdef USE_DS18B20 + dsb_mqttPresent(svalue, ssvalue, djson); +#endif // USE_DS18B20 +#ifdef USE_DS18x20 + ds18x20_mqttPresent(svalue, ssvalue, djson); +#endif // USE_DS18x20 + } +#if defined(USE_DHT) || defined(USE_DHT2) + if (dht_type) dht_mqttPresent(svalue, ssvalue, djson); +#endif // USE_DHT/2 +#ifdef USE_I2C + if (i2c_flg) { +#ifdef USE_HTU + htu_mqttPresent(svalue, ssvalue, djson); +#endif // USE_HTU +#ifdef USE_BMP + bmp_mqttPresent(svalue, ssvalue, djson); +#endif // USE_BMP +#ifdef USE_BH1750 + bh1750_mqttPresent(svalue, ssvalue, djson); +#endif // USE_BH1750 + } +#endif // USE_I2C + snprintf_P(svalue, ssvalue, PSTR("%s}"), svalue); } /********************************************************************************************/ @@ -1988,7 +2036,6 @@ void every_second() if (tele_period >= sysCfg.tele_period) { tele_period = 0; - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/TELEMETRY"), PUB_PREFIX2, sysCfg.mqtt_topic); snprintf_P(svalue, sizeof(svalue), PSTR("{\"Time\":\"%s\", \"Uptime\":%d"), stime, uptime); for (byte i = 0; i < Maxdevice; i++) { if (Maxdevice == 1) { // Legacy @@ -2000,40 +2047,14 @@ void every_second() } snprintf_P(svalue, sizeof(svalue), PSTR("%s, \"Wifi\":{\"AP\":%d, \"SSID\":\"%s\", \"RSSI\":%d}}"), svalue, sysCfg.sta_active +1, sysCfg.sta_ssid[sysCfg.sta_active], WIFI_getRSSIasQuality(WiFi.RSSI())); - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(1, PSTR("STATE"), svalue); uint8_t djson = 0; - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Time\":\"%s\""), stime); - if (pin[GPIO_DSB] < 99) { -#ifdef USE_DS18B20 - dsb_mqttPresent(svalue, sizeof(svalue), &djson, 0); -#endif // USE_DS18B20 -#ifdef USE_DS18x20 - ds18x20_mqttPresent(svalue, sizeof(svalue), &djson, 0); -#endif // USE_DS18x20 - } -#if defined(USE_DHT) || defined(USE_DHT2) - if (dht_type) dht_mqttPresent(svalue, sizeof(svalue), &djson, 1); -#endif // USE_DHT/2 -#ifdef USE_I2C - if (i2c_flg) { -#ifdef USE_HTU - htu_mqttPresent(svalue, sizeof(svalue), &djson, 1); -#endif // USE_HTU -#ifdef USE_BMP - bmp_mqttPresent(svalue, sizeof(svalue), &djson, 2); -#endif // USE_BMP -#ifdef USE_BH1750 - bh1750_mqttPresent(svalue, sizeof(svalue), &djson, 3); -#endif // USE_BH1750 - } -#endif // USE_I2C - if (djson) { - snprintf_P(svalue, sizeof(svalue), PSTR("%s}"), svalue); - mqtt_publish(stopic, svalue); - } + svalue[0] = '\0'; + sensors_mqttPresent(svalue, sizeof(svalue), &djson); + if (djson) mqtt_publish_topic_P(1, PSTR("SENSOR"), svalue); - if (hlw_flg) hlw_mqttPresent(4); + if (hlw_flg) hlw_mqttPresent(); } } @@ -2041,16 +2062,15 @@ void every_second() if ((rtcTime.Minute == 2) && (rtcTime.Second == 30)) { uptime++; - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/TELEMETRY"), PUB_PREFIX2, sysCfg.mqtt_topic); snprintf_P(svalue, sizeof(svalue), PSTR("{\"Time\":\"%s\", \"Uptime\":%d}"), stime, uptime); - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(1, PSTR("UPTIME"), svalue); } } void stateloop() { - uint8_t button, flag, switchflag, power_now; - char scmnd[20], log[LOGSZ], stopic[TOPSZ], svalue[MESSZ]; + uint8_t button = NOT_PRESSED, flag, switchflag, power_now; + char scmnd[20], log[LOGSZ], svalue[MESSZ]; timerxs = millis() + (1000 / STATES); state++; @@ -2096,7 +2116,7 @@ void stateloop() button = NOT_PRESSED; } } else { - button = digitalRead(pin[GPIO_KEY1]); + if (pin[GPIO_KEY1] < 99) button = digitalRead(pin[GPIO_KEY1]); } if ((button == PRESSED) && (lastbutton[0] == NOT_PRESSED)) { multipress = (multiwindow) ? multipress +1 : 1; @@ -2225,14 +2245,13 @@ void stateloop() } if (otaflag == 10) { // Allow MQTT to reconnect otaflag = 0; - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/UPGRADE"), PUB_PREFIX, sysCfg.mqtt_topic); if (otaok) { snprintf_P(svalue, sizeof(svalue), PSTR("Successful. Restarting")); restartflag = 2; } else { snprintf_P(svalue, sizeof(svalue), PSTR("Failed %s"), ESPhttpUpdate.getLastErrorString().c_str()); } - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(0, PSTR("UPGRADE"), svalue); } } break; @@ -2348,7 +2367,7 @@ void GPIO_init() uint8_t mpin; mytmplt def_module; - if (!sysCfg.module) sysCfg.module = SONOFF_BASIC; // Sonoff Basic + if (!sysCfg.module || (sysCfg.module >= MAXMODULE)) sysCfg.module = SONOFF_BASIC; // Sonoff Basic memcpy_P(&def_module, &modules[sysCfg.module], sizeof(def_module)); strlcpy(my_module.name, def_module.name, sizeof(my_module.name)); diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 315f26b3f..b664637c5 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -149,12 +149,10 @@ const mytmplt modules[MAXMODULE] PROGMEM = { GPIO_KEY1, // GPIO00 Button 1 0, GPIO_USER, // GPIO02 Optional sensor - 0, + GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_REL3, // GPIO04 Sonoff 4CH Red Led and Relay 3 (0 = Off, 1 = On) GPIO_REL2, // GPIO05 Sonoff 4CH Red Led and Relay 2 (0 = Off, 1 = On) - 0, - GPIO_USER, // GPIO07 Optional sensor - GPIO_USER, // GPIO08 Optional sensor + 0, 0, 0, GPIO_KEY2, // GPIO09 Button 2 GPIO_KEY3, // GPIO10 Button 3 0, @@ -235,7 +233,8 @@ const mytmplt modules[MAXMODULE] PROGMEM = { }, { "User Test", // Sonoff Basic User Test GPIO_KEY1, // GPIO00 Button - 0, 0, + 0, + GPIO_USER, // GPIO02 Optional sensor GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_USER, // GPIO04 Optional sensor 0, 0, 0, 0, 0, 0, 0, diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 2edb63c08..fae221352 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -127,6 +127,7 @@ #define USE_HTU // Add I2C code for HTU21 sensor #define USE_WS2812 // WS2812 Led string support (+8k code, +1k mem) + #define USE_WS2812_CTYPE 1 // WS2812 Color type (0 - RGB, 1 - GRB) // #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial TXD) (+1k mem) // When USE_WS2812_DMA is enabled expect Exceptions on Pow diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index 7689ada06..204d0510d 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -164,8 +164,8 @@ const char HTTP_FORM_OTHER2[] PROGMEM = #ifdef USE_EMULATION const char HTTP_FORM_OTHER3[] PROGMEM = "
 Emulation " - "
None
" - "
Belkin WeMo
" + "
None" + "
Belkin WeMo" "
Hue Bridge
"; #endif // USE_EMULATION const char HTTP_FORM_END[] PROGMEM = @@ -288,6 +288,28 @@ const char HUE_LIGHT_STATUS_JSON[] PROGMEM = "}"; const char HUE_LIGHT_RESPONSE_JSON[] PROGMEM = "{\"success\":{\"{api}/{id}/{cmd}\":{res}}}"; +const char HUE_CONFIG_RESPONSE_JSON[] PROGMEM = + "{\"name\":\"Philips hue\"," + "\"mac\":\"{mac}\"," + "\"dhcp\":true," + "\"ipaddress\":\"{ip}\"," + "\"netmask\":\"{mask}\"," + "\"gateway\":\"{gw}\"," + "\"proxyaddress\":\"\"," + "\"proxyport\":0," + "\"UTC\":\"{dt}\"," + "\"whitelist\":{\"{id}\":{" + "\"last use date\":\"{dt}\"," + "\"create date\":\"{dt}\"," + "\"name\":\"Remote\"}}," + "\"swversion\":\"01036659\"," + "\"apiversion\":\"1.16.0\"," + "\"swupdate\":{\"updatestate\":0,\"url\":\"\",\"text\":\"\",\"notify\": false}," + "\"linkbutton\":false," + "\"portalservices\":false" + "}"; +const char HUE_NO_AUTH_JSON[] PROGMEM = + "[{\"error\":{\"type\":101,\"address\":\"/\",\"description\":\"link button not pressed\"}}]"; #endif // USE_EMULATION #define DNS_PORT 53 @@ -971,23 +993,23 @@ void handleUploadDone() page.replace("{v}", "Info"); page += F("
Upload "); if (_uploaderror) { - page += F("failed"); + page += F("failed

"); if (_uploaderror == 1) { - page += F("

No file selected"); + page += F("No file selected"); } else if (_uploaderror == 2) { - page += F("

File size is larger than available free space"); + page += F("File size is larger than available free space"); } else if (_uploaderror == 3) { - page += F("

File magic header does not start with 0xE9"); + page += F("File magic header does not start with 0xE9"); } else if (_uploaderror == 4) { - page += F("

File flash size is larger than device flash size"); + page += F("File flash size is larger than device flash size"); } else if (_uploaderror == 5) { - page += F("

File upload buffer miscompare"); + page += F("File upload buffer miscompare"); } else if (_uploaderror == 6) { - page += F("

Upload failed. Enable logging option 3 for more information"); + page += F("Upload failed. Enable logging option 3 for more information"); } else if (_uploaderror == 7) { - page += F("

Upload aborted"); + page += F("Upload aborted"); } else { - page += F("

Upload error code "); + page += F("Upload error code "); page += String(_uploaderror); } if (Update.hasError()) { @@ -1205,52 +1227,86 @@ void handleInfo() // page += F("
 Information "); page += F(""); page += F(""); - page += F(""); - page += F(""); -// page += F(""); - page += F(""); - page += F(""); - page += F(""); - page += F(""); + page += F(""); + page += F(""); + page += F(""); +// page += F(""); + page += F(""); + page += F(""); + page += F(""); + page += F(""); for (byte i = 0; i < Maxdevice; i++) { - page += F(""); + page += F(""); } page += F(""); -// page += F(""); - page += F(""); - page += F(""); +// page += F(""); + page += F(""); + page += F(""); if (static_cast(WiFi.localIP()) != 0) { - page += F(""); - page += F(""); - page += F(""); + page += F(""); + page += F(""); + page += F(""); } if (static_cast(WiFi.softAPIP()) != 0) { - page += F(""); - page += F(""); - page += F(""); + page += F(""); + page += F(""); + page += F(""); } page += F(""); if (sysCfg.mqtt_enabled) { - page += F(""); - page += F(""); - page += F(""); - page += F(""); -// page += F(""); - page += F(""); - page += F(""); + page += F(""); + page += F(""); + page += F(""); + page += F(""); +// page += F(""); + page += F(""); + page += F(""); } else { - page += F(""); + page += F(""); } + + page += F(""); + + page += F(""); + page += F(""); + page += F(""); - page += F(""); - page += F(""); - page += F(""); - page += F(""); - page += F(""); - page += F(""); - page += F(""); + page += F(""); + page += F(""); + page += F(""); + page += F(""); + page += F(""); + page += F(""); + page += F(""); page += F("
Program version"); page += Version; page += F("
Core/SDK version"); page += ESP.getCoreVersion(); page += F("/"); page += String(ESP.getSdkVersion()); page += F("
Boot version"); page += String(ESP.getBootVersion()); page += F("
Uptime"); page += String(uptime); page += F(" Hours
Flash write count"); page += String(sysCfg.saveFlag); page += F("
Boot count"); page += String(sysCfg.bootcount); page += F("
Reset reason"); page += ESP.getResetReason(); page += F("
Program version"); page += Version; page += F("
Build Date/Time"); page += __DATE__; + page += F("/"); page += __TIME__ ; page += F("
Core/SDK version"); page += ESP.getCoreVersion(); page += F("/"); page += String(ESP.getSdkVersion()); page += F("
Boot version"); page += String(ESP.getBootVersion()); page += F("
Uptime"); page += String(uptime); page += F(" Hours
Flash write count"); page += String(sysCfg.saveFlag); page += F("
Boot count"); page += String(sysCfg.bootcount); page += F("
Reset reason"); page += ESP.getResetReason(); page += F("
Friendly name "); + page += F("
Friendly name "); page += i +1; - page += F(""); page += String(sysCfg.friendlyname[i]); page += F("
"); page += String(sysCfg.friendlyname[i]); page += F("
 
SSId (RSSI)"); page += (sysCfg.sta_active)? sysCfg.sta_ssid2 : sysCfg.sta_ssid1; page += F(" ("); page += WIFI_getRSSIasQuality(WiFi.RSSI()); page += F("%)
AP"); page += String(sysCfg.sta_active +1); page += F(" SSId (RSSI)"); page += sysCfg.sta_ssid[sysCfg.sta_active]; page += F(" ("); page += WIFI_getRSSIasQuality(WiFi.RSSI()); page += F("%)
Hostname"); page += Hostname; page += F("
SSId (RSSI)"); page += (sysCfg.sta_active)? sysCfg.sta_ssid2 : sysCfg.sta_ssid1; page += F(" ("); page += WIFI_getRSSIasQuality(WiFi.RSSI()); page += F("%)
AP"); page += String(sysCfg.sta_active +1); page += F(" SSId (RSSI)"); page += sysCfg.sta_ssid[sysCfg.sta_active]; page += F(" ("); page += WIFI_getRSSIasQuality(WiFi.RSSI()); page += F("%)
Hostname"); page += Hostname; page += F("
IP address"); page += WiFi.localIP().toString(); page += F("
Gateway"); page += WiFi.gatewayIP().toString(); page += F("
MAC address"); page += WiFi.macAddress(); page += F("
IP address"); page += WiFi.localIP().toString(); page += F("
Gateway"); page += WiFi.gatewayIP().toString(); page += F("
MAC address"); page += WiFi.macAddress(); page += F("
AP IP address"); page += WiFi.softAPIP().toString(); page += F("
AP Gateway"); page += WiFi.softAPIP().toString(); page += F("
AP MAC address"); page += WiFi.softAPmacAddress(); page += F("
AP IP address"); page += WiFi.softAPIP().toString(); page += F("
AP Gateway"); page += WiFi.softAPIP().toString(); page += F("
AP MAC address"); page += WiFi.softAPmacAddress(); page += F("
 
MQTT Host"); page += sysCfg.mqtt_host; page += F("
MQTT Port"); page += String(sysCfg.mqtt_port); page += F("
MQTT Client and
 Fallback Topic
"); page += MQTTClient; page += F("
MQTT User"); page += sysCfg.mqtt_user; page += F("
MQTT Password"); page += sysCfg.mqtt_pwd; page += F("
MQTT Topic"); page += sysCfg.mqtt_topic; page += F("
MQTT Group Topic"); page += sysCfg.mqtt_grptopic; page += F("
MQTT Host"); page += sysCfg.mqtt_host; page += F("
MQTT Port"); page += String(sysCfg.mqtt_port); page += F("
MQTT Client and
 Fallback Topic
"); page += MQTTClient; page += F("
MQTT User"); page += sysCfg.mqtt_user; page += F("
MQTT Password"); page += sysCfg.mqtt_pwd; page += F("
MQTT Topic"); page += sysCfg.mqtt_topic; page += F("
MQTT Group Topic"); page += sysCfg.mqtt_grptopic; page += F("
MQTTDisabled
MQTTDisabled
Emulation"); +#ifdef USE_EMULATION + if (sysCfg.emulation == EMUL_WEMO) { + page += F("Belkin WeMo"); + } + else if (sysCfg.emulation == EMUL_HUE) { + page += F("Hue Bridge"); + } + else { + page += F("None"); + } +#else + page += F("Disabled"); +#endif // USE_EMULATION + page += F("
mDNS Discovery"); +#ifdef USE_DISCOVERY + page += F("Enabled"); + page += F("
mDNS Webserver Advertise"); +#ifdef WEBSERVER_ADVERTISE + page += F("Enabled"); +#else + page += F("Disabled"); +#endif // WEBSERVER_ADVERTISE +#else + page += F("Disabled"); +#endif // USE_DISCOVERY + page += F("
 
ESP Chip id"); page += String(ESP.getChipId()); page += F("
Flash Chip id"); page += String(ESP.getFlashChipId()); page += F("
Flash size"); page += String(ESP.getFlashChipRealSize() / 1024); page += F("kB
Program flash size"); page += String(ESP.getFlashChipSize() / 1024); page += F("kB
Program size"); page += String(ESP.getSketchSize() / 1024); page += F("kB
Free program space"); page += String(ESP.getFreeSketchSpace() / 1024); page += F("kB
Free memory"); page += String(freeMem / 1024); page += F("kB
ESP Chip id"); page += String(ESP.getChipId()); page += F("
Flash Chip id"); page += String(ESP.getFlashChipId()); page += F("
Flash size"); page += String(ESP.getFlashChipRealSize() / 1024); page += F("kB
Program flash size"); page += String(ESP.getFlashChipSize() / 1024); page += F("kB
Program size"); page += String(ESP.getSketchSize() / 1024); page += F("kB
Free program space"); page += String(ESP.getFreeSketchSpace() / 1024); page += F("kB
Free memory"); page += String(freeMem / 1024); page += F("kB
"); // page += F("
"); page += FPSTR(HTTP_BTN_MAIN); @@ -1286,8 +1342,8 @@ void handleUPnPevent() addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle WeMo basic event")); String request = webServer->arg(0); - if(request.indexOf("State>1 0) do_cmnd_power(1, 1); - if(request.indexOf("State>0 0) do_cmnd_power(1, 0); + if (request.indexOf("State>1 0) do_cmnd_power(1, 1); + if (request.indexOf("State>0 0) do_cmnd_power(1, 0); webServer->send(200, "text/plain", ""); } @@ -1304,7 +1360,6 @@ void handleUPnPsetupWemo() addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle WeMo setup")); String setup_xml = FPSTR(WEMO_SETUP_XML); -// setup_xml.replace("{x1}", String(MQTTClient)); setup_xml.replace("{x1}", String(sysCfg.friendlyname[0])); setup_xml.replace("{x2}", wemo_UUID()); setup_xml.replace("{x3}", wemo_serial()); @@ -1339,6 +1394,76 @@ void hue_todo(String *path) addLog(LOG_LEVEL_DEBUG_MORE, log); } +void hue_config_response(String *response) +{ + char buffer[21]; + + *response += FPSTR(HUE_CONFIG_RESPONSE_JSON); + response->replace("{mac}", WiFi.macAddress()); + response->replace("{ip}", WiFi.localIP().toString()); + response->replace("{mask}", WiFi.subnetMask().toString()); + response->replace("{gw}", WiFi.gatewayIP().toString()); + snprintf_P(buffer, sizeof(buffer), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"), + rtcTime.Year, rtcTime.Month, rtcTime.Day, rtcTime.Hour, rtcTime.Minute, rtcTime.Second); + response->replace("{dt}", String(buffer)); +} + +void hue_global_cfg(String *path) +{ + String response; + + path->remove(0,1); // cut leading / to get + response = "{\"lights\":{\""; + for (uint8_t i = 1; i <= Maxdevice; i++) + { + response += i; + response += "\":"; + response += FPSTR(HUE_LIGHT_STATUS_JSON); + if (i < Maxdevice) response += ",\""; + response.replace("{state}", (power & (0x01 << (i-1))) ? "true" : "false"); + response.replace("{j1}", sysCfg.friendlyname[i-1]); + response.replace("{j2}", hue_deviceId(i)); + if (pin[GPIO_WS2812] < 99) { +#ifdef USE_WS2812 + ws2812_replaceHSB(&response); +#endif // USE_WS2812 + } else + { + response.replace("{h}", "0"); + response.replace("{s}", "0"); + response.replace("{b}", "0"); + } + } + response += F("},\"groups\":{},\"schedules\":{},\"config\":"); + + hue_config_response(&response); + response.replace("{id}", *path); + response += "}"; + webServer->send(200, "application/json", response); +} + +void hue_auth(String *path) +{ + String response; + char uid[7]; + + snprintf_P(uid, sizeof(uid), PSTR("%03x"), ESP.getChipId()); + response="[{\"success\":{\"username\":\""; + response+=String(uid); + response+="\"}}]"; + webServer->send(200, "application/json", response); +} + +void hue_config(String *path) +{ + String response = ""; + + path->remove(0,1); // cut leading / to get + hue_config_response(&response); + response.replace("{id}", *path); + webServer->send(200, "application/json", response); +} + void hue_lights(String *path) { String response; @@ -1347,7 +1472,7 @@ void hue_lights(String *path) uint8_t bri = 0; char id[4]; - path->remove(0,path->indexOf("/lights")); // Remove until /lights + path->remove(0,path->indexOf("/lights")); // Remove until /lights if (path->endsWith("/lights")) // Got /lights { response = "{\""; @@ -1388,7 +1513,8 @@ void hue_lights(String *path) if (webServer->args() == 1) { String json = webServer->arg(0); -// Serial.print("HUE API: POST "); Serial.println(json.c_str()); + json.replace(" ",""); // remove blanks + if (json.indexOf("\"on\":") >= 0) // Got "on" command { if (json.indexOf("false") >= 0) // false -> turn device off @@ -1408,7 +1534,7 @@ void hue_lights(String *path) } #ifdef USE_WS2812 if ((pin[GPIO_WS2812] < 99) && ((pos=json.indexOf("\"bri\":")) >= 0)) { - bri=atoi(json.substring(pos+6).c_str()); + bri = atoi(json.substring(pos+6).c_str()); ws2812_changeBrightness(bri); response += ","; response += FPSTR(HUE_LIGHT_RESPONSE_JSON); @@ -1456,22 +1582,34 @@ void handle_hue_api(String *path) */ char log[LOGSZ]; + uint8_t args = 0; path->remove(0, 4); // remove /api + snprintf_P(log, sizeof(log), PSTR("HTTP: Handle Hue API (%s)"), path->c_str()); + addLog(LOG_LEVEL_DEBUG_MORE, log); + for (args = 0; args < webServer->args(); args++) { + String json = webServer->arg(args); + snprintf_P(log, sizeof(log), PSTR("HTTP: Hue POST args (%s)"), json.c_str()); + addLog(LOG_LEVEL_DEBUG_MORE, log); + } + if (path->endsWith("/invalid/")) {} // Just ignore - else if (path->endsWith("/config")) hue_todo(path); - else if(path->indexOf("/lights") >= 0) hue_lights(path); - else if(path->endsWith("/groups")) hue_todo(path); - else if(path->endsWith("/schedules")) hue_todo(path); - else if(path->endsWith("/sensors")) hue_todo(path); - else if(path->endsWith("/scenes")) hue_todo(path); - else if(path->endsWith("/rules")) hue_todo(path); - else + else if (path->endsWith("/")) hue_auth(path); // New HUE App setup + else if (path->endsWith("/config")) hue_config(path); + else if (path->indexOf("/lights") >= 0) hue_lights(path); + else if (path->endsWith("/groups")) hue_todo(path); + else if (path->endsWith("/schedules")) hue_todo(path); + else if (path->endsWith("/sensors")) hue_todo(path); + else if (path->endsWith("/scenes")) hue_todo(path); + else if (path->endsWith("/rules")) hue_todo(path); + else hue_global_cfg(path); +/* { snprintf_P(log, sizeof(log), PSTR("HTTP: Handle Hue API (%s)"),path->c_str()); addLog(LOG_LEVEL_DEBUG_MORE, log); webServer->send(406, "application/json", "{}"); } +*/ } #endif // USE_EMULATION diff --git a/sonoff/xdrv_domoticz.ino b/sonoff/xdrv_domoticz.ino index 259313798..ce1743da0 100644 --- a/sonoff/xdrv_domoticz.ino +++ b/sonoff/xdrv_domoticz.ino @@ -239,7 +239,7 @@ boolean domoticz_command(char *type, uint16_t index, char *dataBuf, uint16_t dat void domoticz_commands(char *svalue, uint16_t ssvalue) { - snprintf_P(svalue, ssvalue, PSTR("{\"Commands\":\"DomoticzInTopic, DomoticzOutTopic, DomoticzIdx, DomoticzKeyIdx, DomoticzSwitchIdx, DomoticzSensorIdx, DomoticzUpdateTimer\"}")); + snprintf_P(svalue, ssvalue, PSTR("{\"Commands4\":\"DomoticzInTopic, DomoticzOutTopic, DomoticzIdx, DomoticzKeyIdx, DomoticzSwitchIdx, DomoticzSensorIdx, DomoticzUpdateTimer\"}")); } boolean domoticz_button(byte key, byte device, byte state, byte svalflg) diff --git a/sonoff/xdrv_wemohue.ino b/sonoff/xdrv_wemohue.ino index 38d379c48..2a4472133 100644 --- a/sonoff/xdrv_wemohue.ino +++ b/sonoff/xdrv_wemohue.ino @@ -52,14 +52,14 @@ const char WEMO_MSEARCH[] PROGMEM = String wemo_serial() { - char serial[15]; - snprintf_P(serial, sizeof(serial), PSTR("201612K%07d"), ESP.getChipId()); + char serial[16]; + snprintf_P(serial, sizeof(serial), PSTR("201612K%08X"), ESP.getChipId()); return String(serial); } String wemo_UUID() { - char uuid[26]; + char uuid[27]; snprintf_P(uuid, sizeof(uuid), PSTR("Socket-1_0-%s"), wemo_serial().c_str()); return String(uuid); } @@ -138,7 +138,6 @@ void hue_respondToMSearch() response.replace("{r3}", hue_UUID()); portUDP.write(response.c_str()); portUDP.endPacket(); - snprintf_P(message, sizeof(message), PSTR("Response1 sent")); // addLog(LOG_LEVEL_DEBUG_MORE, response.c_str()); response = FPSTR(HUE_RESPONSE); @@ -150,7 +149,6 @@ void hue_respondToMSearch() response.replace("{r3}", hue_UUID()); portUDP.write(response.c_str()); portUDP.endPacket(); - snprintf_P(message, sizeof(message), PSTR("Response2 sent")); // addLog(LOG_LEVEL_DEBUG_MORE, response.c_str()); response = FPSTR(HUE_RESPONSE); @@ -161,7 +159,8 @@ void hue_respondToMSearch() response.replace("{r3}", hue_UUID()); portUDP.write(response.c_str()); portUDP.endPacket(); - snprintf_P(message, sizeof(message), PSTR("Response3 sent")); + + snprintf_P(message, sizeof(message), PSTR("3 response packets sent")); // addLog(LOG_LEVEL_DEBUG_MORE, response.c_str()); } else { diff --git a/sonoff/xdrv_ws2812.ino b/sonoff/xdrv_ws2812.ino index d56cfb7d2..da64bde0d 100644 --- a/sonoff/xdrv_ws2812.ino +++ b/sonoff/xdrv_ws2812.ino @@ -31,9 +31,17 @@ POSSIBILITY OF SUCH DAMAGE. #include #ifdef USE_WS2812_DMA +#if (USE_WS2812_CTYPE == 1) NeoPixelBus *strip = NULL; -#else +#else // USE_WS2812_CTYPE + NeoPixelBus *strip = NULL; +#endif // USE_WS2812_CTYPE +#else // USE_WS2812_DMA +#if (USE_WS2812_CTYPE == 1) NeoPixelBus *strip = NULL; +#else // USE_WS2812_CTYPE + NeoPixelBus *strip = NULL; +#endif // USE_WS2812_CTYPE #endif // USE_WS2812_DMA #define COLOR_SATURATION 254.0f @@ -457,9 +465,17 @@ void ws2812_pixels() void ws2812_init() { #ifdef USE_WS2812_DMA +#if (USE_WS2812_CTYPE == 1) strip = new NeoPixelBus(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. -#else +#else // USE_WS2812_CTYPE + strip = new NeoPixelBus(WS2812_MAX_LEDS); // For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. +#endif // USE_WS2812_CTYPE +#else // USE_WS2812_DMA +#if (USE_WS2812_CTYPE == 1) strip = new NeoPixelBus(WS2812_MAX_LEDS, pin[GPIO_WS2812]); +#else // USE_WS2812_CTYPE + strip = new NeoPixelBus(WS2812_MAX_LEDS, pin[GPIO_WS2812]); +#endif // USE_WS2812_CTYPE #endif // USE_WS2812_DMA strip->Begin(); ws2812_pixels(); diff --git a/sonoff/xsns_bh1750.ino b/sonoff/xsns_bh1750.ino index 405e4a1f1..603fd9805 100644 --- a/sonoff/xsns_bh1750.ino +++ b/sonoff/xsns_bh1750.ino @@ -82,7 +82,7 @@ boolean bh1750_detect() * Presentation \*********************************************************************************************/ -void bh1750_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx) +void bh1750_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { if (!bh1750type) return; diff --git a/sonoff/xsns_bmp.ino b/sonoff/xsns_bmp.ino index 91f00eb55..6475895b6 100644 --- a/sonoff/xsns_bmp.ino +++ b/sonoff/xsns_bmp.ino @@ -424,7 +424,7 @@ boolean bmp_detect() * Presentation \*********************************************************************************************/ -void bmp_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx) +void bmp_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { if (!bmptype) return; diff --git a/sonoff/xsns_dht.ino b/sonoff/xsns_dht.ino index 4809c83ac..816819567 100644 --- a/sonoff/xsns_dht.ino +++ b/sonoff/xsns_dht.ino @@ -178,7 +178,7 @@ void dht_init() * Presentation \*********************************************************************************************/ -void dht_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx) +void dht_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { char stemp1[10], stemp2[10]; float t, h; diff --git a/sonoff/xsns_dht2.ino b/sonoff/xsns_dht2.ino index 9239182a8..5b885625a 100644 --- a/sonoff/xsns_dht2.ino +++ b/sonoff/xsns_dht2.ino @@ -57,7 +57,7 @@ void dht_init() * Presentation \*********************************************************************************************/ -void dht_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx) +void dht_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { char stemp1[10], stemp2[10]; float t, h; diff --git a/sonoff/xsns_ds18b20.ino b/sonoff/xsns_ds18b20.ino index eec7d5cb2..b77d89f69 100644 --- a/sonoff/xsns_ds18b20.ino +++ b/sonoff/xsns_ds18b20.ino @@ -172,7 +172,7 @@ boolean dsb_readTemp(bool S, float &t) * Presentation \*********************************************************************************************/ -void dsb_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx) +void dsb_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { char stemp1[10]; float t; diff --git a/sonoff/xsns_ds18x20.ino b/sonoff/xsns_ds18x20.ino index 1205d76ea..334c3c944 100644 --- a/sonoff/xsns_ds18x20.ino +++ b/sonoff/xsns_ds18x20.ino @@ -155,7 +155,7 @@ boolean ds18x20_read(uint8_t sensor, bool S, float &t) * Presentation \*********************************************************************************************/ -void ds18x20_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx) +void ds18x20_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { char stemp1[10], stemp2[10]; float t; diff --git a/sonoff/xsns_hlw8012.ino b/sonoff/xsns_hlw8012.ino index a15b62ded..097969e7a 100644 --- a/sonoff/xsns_hlw8012.ino +++ b/sonoff/xsns_hlw8012.ino @@ -279,7 +279,7 @@ void hlw_setPowerSteadyCounter(byte value) void hlw_margin_chk() { - char log[LOGSZ], stopic[TOPSZ], svalue[MESSZ]; + char log[LOGSZ], svalue[MESSZ]; float ped, pi, pc; uint16_t uped, piv, pe, pw, pu; byte flag, jsonflg; @@ -296,7 +296,6 @@ void hlw_margin_chk() // snprintf_P(log, sizeof(log), PSTR("HLW: W %d, U %d, I %d"), pw, pu, piv); // addLog(LOG_LEVEL_DEBUG, log); - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/TELEMETRY"), PUB_PREFIX2, sysCfg.mqtt_topic); snprintf_P(svalue, sizeof(svalue), PSTR("{")); jsonflg = 0; if (hlw_margin(0, sysCfg.hlw_pmin, pw, flag, hlw_pminflg)) { @@ -325,12 +324,11 @@ void hlw_margin_chk() } if (jsonflg) { snprintf_P(svalue, sizeof(svalue), PSTR("%s}"), svalue); - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(1, PSTR("MARGINS"), svalue); } } #if FEATURE_POWER_LIMIT - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/RESULT"), PUB_PREFIX, sysCfg.mqtt_topic); // Max Power if (sysCfg.hlw_mpl) { if (pw > sysCfg.hlw_mpl) { @@ -340,7 +338,7 @@ void hlw_margin_chk() hlw_mplh_counter--; if (!hlw_mplh_counter) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"MaxPowerReached\":\"%d%s\"}"), pw, (sysCfg.value_units) ? " W" : ""); - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(0, PSTR("WARNING"), svalue); do_cmnd_power(1, 0); if (!hlw_mplr_counter) hlw_mplr_counter = MAX_POWER_RETRY +1; hlw_mplw_counter = sysCfg.hlw_mplw; @@ -359,12 +357,12 @@ void hlw_margin_chk() if (hlw_mplr_counter) { hlw_mplr_counter--; if (hlw_mplr_counter) { - snprintf_P(svalue, sizeof(stopic), PSTR("{\"PowerMonitor\":\"%s\"}"), MQTT_STATUS_ON); - mqtt_publish(stopic, svalue); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"PowerMonitor\":\"%s\"}"), MQTT_STATUS_ON); + mqtt_publish_topic_P(0, PSTR("RESULT"), svalue); do_cmnd_power(1, 1); } else { - snprintf_P(svalue, sizeof(stopic), PSTR("{\"MaxPowerReachedRetry\":\"%s\"}"), MQTT_STATUS_OFF); - mqtt_publish(stopic, svalue); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"MaxPowerReachedRetry\":\"%s\"}"), MQTT_STATUS_OFF); + mqtt_publish_topic_P(0, PSTR("WARNING"), svalue); } } } @@ -376,15 +374,15 @@ void hlw_margin_chk() uped = (uint16_t)(ped * 1000); if (!hlw_mkwh_state && (rtcTime.Hour == sysCfg.hlw_mkwhs)) { hlw_mkwh_state = 1; - snprintf_P(svalue, sizeof(stopic), PSTR("{\"EnergyMonitor\":\"%s\"}"), MQTT_STATUS_ON); - mqtt_publish(stopic, svalue); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"EnergyMonitor\":\"%s\"}"), MQTT_STATUS_ON); + mqtt_publish_topic_P(0, PSTR("RESULT"), svalue); do_cmnd_power(1, 1); } else if ((hlw_mkwh_state == 1) && (uped >= sysCfg.hlw_mkwh)) { hlw_mkwh_state = 2; dtostrf(ped, 1, 3, svalue); snprintf_P(svalue, sizeof(svalue), PSTR("{\"MaxEnergyReached\":\"%s%s\"}"), svalue, (sysCfg.value_units) ? " kWh" : ""); - mqtt_publish(stopic, svalue); + mqtt_publish_topic_P(0, PSTR("WARNING"), svalue); do_cmnd_power(1, 0); } } @@ -512,7 +510,7 @@ boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len void hlw_commands(char *svalue, uint16_t ssvalue) { - snprintf_P(svalue, ssvalue, PSTR("{\"Commands\":\"PowerLow, PowerHigh, VoltageLow, VoltageHigh, CurrentLow, CurrentHigh, HlwPcal, HlwUcal, HlwIcal%s\"}"), + snprintf_P(svalue, ssvalue, PSTR("{\"Commands5\":\"PowerLow, PowerHigh, VoltageLow, VoltageHigh, CurrentLow, CurrentHigh, HlwPcal, HlwUcal, HlwIcal%s\"}"), (FEATURE_POWER_LIMIT)?", SafePower, SafePowerHold, SafePowerWindow, MaxPower, MaxPowerHold, MaxPowerWindow, MaxEnergy, MaxEnergyStart":""); } @@ -520,29 +518,50 @@ void hlw_commands(char *svalue, uint16_t ssvalue) * Presentation \*********************************************************************************************/ -void hlw_mqttPresent(uint8_t domidx) +void hlw_mqttStat(byte option, char* svalue, uint16_t ssvalue) { - char stopic[TOPSZ], svalue[MESSZ], stime[21], stemp0[10], stemp1[10], stemp2[10], stemp3[10]; + char stemp0[10], stemp1[10], stemp2[10], stemp3[10], speriod[20]; float ped, pi, pc; uint16_t pe, pw, pu; - snprintf_P(stime, sizeof(stime), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"), - rtcTime.Year, rtcTime.Month, rtcTime.Day, rtcTime.Hour, rtcTime.Minute, rtcTime.Second); - hlw_readEnergy(1, ped, pe, pw, pu, pi, pc); + hlw_readEnergy(option, ped, pe, pw, pu, pi, pc); dtostrf((float)sysCfg.hlw_kWhyesterday / 100000000, 1, 3, stemp0); dtostrf(ped, 1, 3, stemp1); dtostrf(pc, 1, 2, stemp2); dtostrf(pi, 1, 3, stemp3); - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/TELEMETRY"), PUB_PREFIX2, sysCfg.mqtt_topic); - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Time\":\"%s\", \"Energy\":{\"Yesterday\":\"%s\", \"Today\":\"%s\", \"Period\":%d, \"Power\":%d, \"Factor\":\"%s\", \"Voltage\":%d, \"Current\":\"%s\"}}"), - stime, stemp0, stemp1, pe, pw, stemp2, pu, stemp3); - mqtt_publish(stopic, svalue); + snprintf_P(speriod, sizeof(speriod), PSTR(", \"Period\":%d"), pe); + snprintf_P(svalue, ssvalue, PSTR("%s\"Yesterday\":\"%s\", \"Today\":\"%s\"%s, \"Power\":%d, \"Factor\":\"%s\", \"Voltage\":%d, \"Current\":\"%s\"}"), + svalue, stemp0, stemp1, (option) ? speriod : "", pw, stemp2, pu, stemp3); #ifdef USE_DOMOTICZ dtostrf(ped * 1000, 1, 1, stemp1); domoticz_sensor4(pw, stemp1); #endif // USE_DOMOTICZ } +void hlw_mqttPresent() +{ +// char stopic[TOPSZ], svalue[MESSZ], stime[21]; + char svalue[MESSZ], stime[21]; + + snprintf_P(stime, sizeof(stime), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"), + rtcTime.Year, rtcTime.Month, rtcTime.Day, rtcTime.Hour, rtcTime.Minute, rtcTime.Second); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Time\":\"%s\", "), stime); + hlw_mqttStat(1, svalue, sizeof(svalue)); + +// snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/ENERGY"), PUB_PREFIX2, sysCfg.mqtt_topic); +// mqtt_publish(stopic, svalue); + + mqtt_publish_topic_P(1, PSTR("ENERGY"), svalue); + +} + +void hlw_mqttStatus(char* svalue, uint16_t ssvalue) +{ + snprintf_P(svalue, ssvalue, PSTR("{\"StatusPWR\":{")); + hlw_mqttStat(0, svalue, ssvalue); + snprintf_P(svalue, ssvalue, PSTR("%s}"), svalue); +} + #ifdef USE_WEBSERVER String hlw_webPresent() { diff --git a/sonoff/xsns_htu21.ino b/sonoff/xsns_htu21.ino index ddb9cc6bc..36e26f8be 100644 --- a/sonoff/xsns_htu21.ino +++ b/sonoff/xsns_htu21.ino @@ -229,7 +229,7 @@ uint8_t htu_detect() * Presentation \*********************************************************************************************/ -void htu_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson, uint8_t domidx) +void htu_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { if (!htutype) return;