mirror of https://github.com/arendst/Tasmota.git
v5.3.0
5.3.0 20170715 * Major Hue rewrite which might introduce Alexa problems. If so, initiate an issue * Add support for Sonoff Led and BN-SZ01 Ceiling Led brightness control to Hue * Fix Sonoff Led Power, Dimmer and Color MQTT response (#176) * Add commands Delay and Backlog to allow multiple commands at once separated by ";" (#593) * Use default flashmode DOUT to solve restart hangs on esp8285 chips (#453, #598) * Change Web console column width from 99 to 300 (#599)
This commit is contained in:
parent
88ec2c6a94
commit
7e6b3a2bb1
|
@ -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 **5.2.4** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
|
||||
Current version is **5.3.0** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
|
||||
|
||||
### **** ATTENTION Version 5.x.x specific information ****
|
||||
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
/* 5.2.4 20170703
|
||||
/* 5.3.0 20170715
|
||||
* Major Hue rewrite which might introduce Alexa problems. If so, initiate an issue
|
||||
* Add support for Sonoff Led and BN-SZ01 Ceiling Led brightness control to Hue
|
||||
* Fix Sonoff Led Power, Dimmer and Color MQTT response (#176)
|
||||
* Add commands Delay and Backlog to allow multiple commands at once separated by ";" (#593)
|
||||
* Use default flashmode DOUT to solve restart hangs on esp8285 chips (#453, #598)
|
||||
* Change Web console column width from 99 to 300 (#599)
|
||||
*
|
||||
* 5.2.4 20170703
|
||||
* Removed flash mode update after selecting different module solving esp8285 related problems
|
||||
* Add device type flag to sonoff_template.ino
|
||||
* Change Sonoff Led Wakeup and add support for Sonoff BN-SZ01 Led (#567)
|
||||
|
|
|
@ -130,7 +130,7 @@ extern "C" uint32_t _SPIFFS_end;
|
|||
// Version 4.2 config = eeprom area
|
||||
#define CFG_LOCATION SPIFFS_END // No need for SPIFFS as it uses EEPROM area
|
||||
// Version 5.2 allow for more flash space
|
||||
#define CFG_ROTATES 8 // Number of additional flash sectors used (handles uploads)
|
||||
#define CFG_ROTATES 8 // Number of flash sectors used (handles uploads)
|
||||
|
||||
uint32_t _cfgHash = 0;
|
||||
uint32_t _cfgLocation = CFG_LOCATION;
|
||||
|
@ -171,16 +171,6 @@ void setFlashMode(byte option, byte mode)
|
|||
delete[] _buffer;
|
||||
}
|
||||
|
||||
void setModuleFlashMode(byte option)
|
||||
{
|
||||
uint8_t mode = 0; // QIO - ESP8266
|
||||
// if ((SONOFF_TOUCH == sysCfg.module) || (SONOFF_4CH == sysCfg.module)) {
|
||||
if (sysCfg.my_module.flag &1) {
|
||||
mode = 3; // DOUT - ESP8285
|
||||
}
|
||||
setFlashMode(option, mode);
|
||||
}
|
||||
|
||||
uint32_t getHash()
|
||||
{
|
||||
uint32_t hash = 0;
|
||||
|
|
|
@ -20,11 +20,12 @@
|
|||
Prerequisites:
|
||||
- Change libraries/PubSubClient/src/PubSubClient.h
|
||||
#define MQTT_MAX_PACKET_SIZE 512
|
||||
|
||||
- Select IDE Tools - Flash size: "1M (no SPIFFS)"
|
||||
|
||||
- Select IDE Tools - Flash Mode: "DOUT"
|
||||
- Select IDE Tools - Flash Size: "1M (no SPIFFS)"
|
||||
====================================================*/
|
||||
|
||||
#define VERSION 0x05020400 // 5.2.4
|
||||
#define VERSION 0x05030000 // 5.3.0
|
||||
|
||||
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};
|
||||
|
@ -136,7 +137,7 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
|
|||
#define SERIALLOG_TIMER 600 // Seconds to disable SerialLog
|
||||
#define OTA_ATTEMPTS 10 // Number of times to try fetching the new firmware
|
||||
|
||||
#define INPUT_BUFFER_SIZE 100 // Max number of characters in serial buffer
|
||||
#define INPUT_BUFFER_SIZE 250 // Max number of characters in (serial) command buffer
|
||||
#define CMDSZ 20 // Max number of characters in command
|
||||
#define TOPSZ 100 // Max number of characters in topic string
|
||||
#define LOGSZ 128 // Max number of characters in log string
|
||||
|
@ -145,6 +146,8 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
|
|||
#else
|
||||
#define MAX_LOG_LINES 20 // Max number of lines in weblog
|
||||
#endif
|
||||
#define MAX_BACKLOG 16 // Max number of commands in backlog (chk blogidx and blogptr code)
|
||||
#define MIN_BACKLOG_DELAY 2 // Minimal backlog delay in 0.1 seconds
|
||||
|
||||
#define APP_BAUDRATE 115200 // Default serial baudrate
|
||||
#define MAX_STATUS 11 // Max number of status lines
|
||||
|
@ -179,7 +182,7 @@ enum opt_t {P_HOLD_TIME, P_MAX_POWER_RETRY, P_MAX_PARAM8}; // Index in sysCf
|
|||
#ifdef USE_I2C
|
||||
#include <Wire.h> // I2C support library
|
||||
#endif // USE_I2C
|
||||
#ifdef USI_SPI
|
||||
#ifdef USE_SPI
|
||||
#include <SPI.h> // SPI support, TFT
|
||||
#endif // USE_SPI
|
||||
#include "settings.h"
|
||||
|
@ -257,6 +260,11 @@ uint8_t blink_powersave; // Blink start power save state
|
|||
uint16_t mqtt_cmnd_publish = 0; // ignore flag for publish command
|
||||
uint8_t latching_power = 0; // Power state at latching start
|
||||
uint8_t latching_relay_pulse = 0; // Latching relay pulse timer
|
||||
String Backlog[MAX_BACKLOG]; // Command backlog
|
||||
uint8_t blogidx = 0; // Command backlog index
|
||||
uint8_t blogptr = 0; // Command backlog pointer
|
||||
uint8_t blogmutex = 0; // Command backlog pending
|
||||
uint16_t blogdelay = 0; // Command backlog delay
|
||||
|
||||
#ifdef USE_MQTT_TLS
|
||||
WiFiClientSecure espClient; // Wifi Secure Client
|
||||
|
@ -936,6 +944,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
|
|||
payload = (int16_t) lnum; // -32766 - 32767
|
||||
payload16 = (uint16_t) lnum; // 0 - 65535
|
||||
}
|
||||
blogdelay = MIN_BACKLOG_DELAY; // Reset backlog delay
|
||||
|
||||
if (!strcmp_P(dataBufUc,PSTR("OFF")) || !strcmp_P(dataBufUc,PSTR("FALSE")) || !strcmp_P(dataBufUc,PSTR("STOP")) || !strcmp_P(dataBufUc,PSTR("CELSIUS"))) {
|
||||
payload = 0;
|
||||
|
@ -956,7 +965,34 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
|
|||
// snprintf_P(svalue, sizeof(svalue), PSTR("RSLT: Payload %d, Payload16 %d"), payload, payload16);
|
||||
// addLog(LOG_LEVEL_DEBUG, svalue);
|
||||
|
||||
if (!strcmp_P(type,PSTR("POWER")) && (index > 0) && (index <= Maxdevice)) {
|
||||
if (!strcmp_P(type,PSTR("BACKLOG"))) {
|
||||
if (data_len) {
|
||||
char *blcommand = strtok(dataBuf, ";");
|
||||
while (blcommand != NULL) {
|
||||
Backlog[blogidx] = String(blcommand);
|
||||
blogidx++;
|
||||
/*
|
||||
if (blogidx >= MAX_BACKLOG) {
|
||||
blogidx = 0;
|
||||
}
|
||||
*/
|
||||
blogidx &= 0xF;
|
||||
blcommand = strtok(NULL, ";");
|
||||
}
|
||||
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Backlog\":\"Appended\"}"));
|
||||
} else {
|
||||
uint8_t blflag = (blogptr == blogidx);
|
||||
blogptr = blogidx;
|
||||
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Backlog\":\"%s\"}"), blflag ? "Empty" : "Aborted");
|
||||
}
|
||||
}
|
||||
else if (!strcmp_P(type,PSTR("DELAY"))) {
|
||||
if ((payload >= MIN_BACKLOG_DELAY) && (payload <= 3600)) {
|
||||
blogdelay = payload;
|
||||
}
|
||||
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Delay\":%d}"), blogdelay);
|
||||
}
|
||||
else if (!strcmp_P(type,PSTR("POWER")) && (index > 0) && (index <= Maxdevice)) {
|
||||
if ((payload < 0) || (payload > 4)) {
|
||||
payload = 9;
|
||||
}
|
||||
|
@ -1148,7 +1184,6 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
|
|||
for (byte i = 0; i < MAX_GPIO_PIN; i++) {
|
||||
sysCfg.my_module.gp.io[i] = 0;
|
||||
}
|
||||
// setModuleFlashMode(0); // Fails on esp8285 based devices
|
||||
}
|
||||
restartflag = 2;
|
||||
}
|
||||
|
@ -1646,12 +1681,19 @@ void do_cmnd_power(byte device, byte state)
|
|||
{
|
||||
// device = Relay number 1 and up
|
||||
// state 0 = Relay Off
|
||||
// state 1 = Relay on (turn off after sysCfg.pulsetime * 100 mSec if enabled)
|
||||
// state 1 = Relay On (turn off after sysCfg.pulsetime * 100 mSec if enabled)
|
||||
// state 2 = Toggle relay
|
||||
// state 3 = Blink relay
|
||||
// state 4 = Stop blinking relay
|
||||
// state 6 = Relay Off and no publishPowerState
|
||||
// state 7 = Relay On and no publishPowerState
|
||||
// state 9 = Show power state
|
||||
|
||||
uint8_t publishPower = 1;
|
||||
if ((6 == state) || (7 == state)) {
|
||||
state &= 1;
|
||||
publishPower = 0;
|
||||
}
|
||||
if ((device < 1) || (device > Maxdevice)) {
|
||||
device = 1;
|
||||
}
|
||||
|
@ -1698,7 +1740,9 @@ void do_cmnd_power(byte device, byte state)
|
|||
}
|
||||
return;
|
||||
}
|
||||
mqtt_publishPowerState(device);
|
||||
if (publishPower) {
|
||||
mqtt_publishPowerState(device);
|
||||
}
|
||||
}
|
||||
|
||||
void stop_all_power_blink()
|
||||
|
@ -1718,7 +1762,7 @@ void stop_all_power_blink()
|
|||
void do_cmnd(char *cmnd)
|
||||
{
|
||||
char stopic[CMDSZ];
|
||||
char svalue[128];
|
||||
char svalue[INPUT_BUFFER_SIZE];
|
||||
char *start;
|
||||
char *token;
|
||||
|
||||
|
@ -2045,7 +2089,7 @@ void stateloop()
|
|||
if (mqtt_cmnd_publish) {
|
||||
mqtt_cmnd_publish--; // Clean up
|
||||
}
|
||||
|
||||
|
||||
if (latching_relay_pulse) {
|
||||
latching_relay_pulse--;
|
||||
if (!latching_relay_pulse) {
|
||||
|
@ -2274,9 +2318,25 @@ void stateloop()
|
|||
}
|
||||
}
|
||||
|
||||
if (blogdelay) {
|
||||
blogdelay--;
|
||||
}
|
||||
if ((blogptr != blogidx) && !blogdelay && !blogmutex) {
|
||||
blogmutex = 1;
|
||||
do_cmnd((char*)Backlog[blogptr].c_str());
|
||||
blogmutex = 0;
|
||||
blogptr++;
|
||||
/*
|
||||
if (blogptr >= MAX_BACKLOG) {
|
||||
blogptr = 0;
|
||||
}
|
||||
*/
|
||||
blogptr &= 0xF;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case (STATES/10)*2:
|
||||
if (otaflag) {
|
||||
if (otaflag && (blogptr == blogidx)) {
|
||||
otaflag--;
|
||||
if (2 == otaflag) {
|
||||
otaretry = OTA_ATTEMPTS;
|
||||
|
@ -2304,7 +2364,7 @@ void stateloop()
|
|||
if (90 == otaflag) { // Allow MQTT to reconnect
|
||||
otaflag = 0;
|
||||
if (otaok) {
|
||||
setModuleFlashMode(1); // QIO - ESP8266, DOUT - ESP8285 (Sonoff 4CH, Touch and BN-SZ01)
|
||||
setFlashMode(1, 3); // DOUT for both ESP8266 and ESP8285
|
||||
snprintf_P(svalue, sizeof(svalue), PSTR("Successful. Restarting"));
|
||||
} else {
|
||||
snprintf_P(svalue, sizeof(svalue), PSTR("Failed %s"), ESPhttpUpdate.getLastErrorString().c_str());
|
||||
|
@ -2318,7 +2378,7 @@ void stateloop()
|
|||
if (rtc_midnight_now()) {
|
||||
counter_savestate();
|
||||
}
|
||||
if (savedatacounter) {
|
||||
if (savedatacounter && (blogptr == blogidx)) {
|
||||
savedatacounter--;
|
||||
if (savedatacounter <= 0) {
|
||||
if (sysCfg.flag.savestate) {
|
||||
|
@ -2336,7 +2396,7 @@ void stateloop()
|
|||
savedatacounter = sysCfg.savedata;
|
||||
}
|
||||
}
|
||||
if (restartflag) {
|
||||
if (restartflag && (blogptr == blogidx)) {
|
||||
if (211 == restartflag) {
|
||||
CFG_Default();
|
||||
restartflag = 2;
|
||||
|
@ -2459,7 +2519,7 @@ void GPIO_init()
|
|||
}
|
||||
|
||||
memcpy_P(&def_module, &modules[sysCfg.module], sizeof(def_module));
|
||||
sysCfg.my_module.flag = def_module.flag;
|
||||
// sysCfg.my_module.flag = def_module.flag;
|
||||
strlcpy(my_module.name, def_module.name, sizeof(my_module.name));
|
||||
for (byte i = 0; i < MAX_GPIO_PIN; i++) {
|
||||
if (sysCfg.my_module.gp.io[i] > GPIO_NONE) {
|
||||
|
|
|
@ -158,14 +158,14 @@ typedef struct MYIO {
|
|||
|
||||
typedef struct MYTMPLT {
|
||||
char name[14];
|
||||
uint8_t flag; // bit 0 = flashmode (0 = esp8266, 1 = esp8285)
|
||||
uint8_t flag; // not used
|
||||
myio gp;
|
||||
} mytmplt;
|
||||
|
||||
// Default module settings
|
||||
const mytmplt modules[MAXMODULE] PROGMEM = {
|
||||
{ "Sonoff Basic", // Sonoff Basic (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
0, // GPIO02
|
||||
|
@ -174,7 +174,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, // GPIO05
|
||||
0, // GPIO06 (SD_CLK Flash)
|
||||
0, // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT)
|
||||
0, // GPIO08 (SD_DATA1 Flash QIO/DIO)
|
||||
0, // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT)
|
||||
0, // GPIO09 (SD_DATA2 Flash QIO)
|
||||
0, // GPIO10 (SD_DATA3 Flash QIO)
|
||||
0, // GPIO11 (SD_CMD Flash)
|
||||
|
@ -186,7 +186,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0 // ADC0 Analog input
|
||||
},
|
||||
{ "Sonoff RF", // Sonoff RF (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
0,
|
||||
|
@ -200,7 +200,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0, 0
|
||||
},
|
||||
{ "Sonoff SV", // Sonoff SV (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
0,
|
||||
|
@ -215,7 +215,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
GPIO_ADC0 // ADC0 Analog input
|
||||
},
|
||||
{ "Sonoff TH", // Sonoff TH10/16 (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
0,
|
||||
|
@ -229,7 +229,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0, 0
|
||||
},
|
||||
{ "Sonoff Dual", // Sonoff Dual (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
0,
|
||||
GPIO_TXD, // GPIO01 Relay control
|
||||
0,
|
||||
|
@ -242,7 +242,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0, 0, 0
|
||||
},
|
||||
{ "Sonoff Pow", // Sonoff Pow (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button
|
||||
0, 0, 0, 0,
|
||||
GPIO_HLW_SEL, // GPIO05 HLW8012 Sel output
|
||||
|
@ -254,7 +254,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0
|
||||
},
|
||||
{ "Sonoff 4CH", // Sonoff 4CH (ESP8285)
|
||||
1, // esp8285
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button 1
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
GPIO_USER, // GPIO02 Optional sensor
|
||||
|
@ -264,7 +264,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0, 0, // Flash connection
|
||||
GPIO_KEY2, // GPIO09 Button 2
|
||||
GPIO_KEY3, // GPIO10 Button 3
|
||||
0,
|
||||
0, // Flash connection
|
||||
GPIO_REL1, // GPIO12 Red Led and Relay 1 (0 = Off, 1 = On)
|
||||
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off)
|
||||
GPIO_KEY4, // GPIO14 Button 4
|
||||
|
@ -272,7 +272,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0
|
||||
},
|
||||
{ "S20 Socket", // S20 Smart Socket (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
0,
|
||||
|
@ -284,7 +284,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0, 0, 0
|
||||
},
|
||||
{ "Slampher", // Slampher (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
0,
|
||||
|
@ -296,20 +296,21 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0, 0, 0
|
||||
},
|
||||
{ "Sonoff Touch", // Sonoff Touch (ESP8285)
|
||||
1, // esp8285
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
0,
|
||||
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
||||
0, 0,
|
||||
0, 0, 0, // Flash connection
|
||||
0, 0, 0,
|
||||
0, 0,
|
||||
0, // Flash connection
|
||||
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off)
|
||||
0, 0, 0, 0
|
||||
},
|
||||
{ "Sonoff LED", // Sonoff LED (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button
|
||||
0, 0, 0,
|
||||
GPIO_USER, // GPIO04 Optional sensor (PWM3 Green)
|
||||
|
@ -321,8 +322,8 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
GPIO_USER, // GPIO15 Optional sensor (PWM4 Blue)
|
||||
0, 0
|
||||
},
|
||||
{ "1 Channel", // 1 Channel Inching/Latching Relay using (PSA-B01 - ESP8266)
|
||||
0, // esp8266
|
||||
{ "1 Channel", // 1 Channel Inching/Latching Relay using (PSA-B01 - ESP8266 and PSF-B01 - ESP8285)
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button
|
||||
0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, // Flash connection
|
||||
|
@ -331,7 +332,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0, 0, 0
|
||||
},
|
||||
{ "4 Channel", // 4 Channel Inching/Latching Relays (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
0,
|
||||
GPIO_TXD, // GPIO01 Relay control
|
||||
0,
|
||||
|
@ -343,7 +344,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0, 0, 0
|
||||
},
|
||||
{ "Motor C/AC", // Motor Clockwise / Anti clockwise (PSA-B01 - ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button
|
||||
0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, // Flash connection
|
||||
|
@ -352,7 +353,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0, 0, 0
|
||||
},
|
||||
{ "ElectroDragon", // ElectroDragon IoT Relay Board (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY2, // GPIO00 Button 2
|
||||
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
|
||||
GPIO_KEY1, // GPIO02 Button 1
|
||||
|
@ -369,7 +370,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
},
|
||||
{ "EXS Relay", // Latching relay https://ex-store.de/ESP8266-WiFi-Relay-V31 (ESP8266)
|
||||
// Module Pin 1 VCC 3V3, Module Pin 6 GND
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Module Pin 8 - Button (firmware flash)
|
||||
GPIO_USER, // GPIO01 Module Pin 2 = UART0_TXD
|
||||
GPIO_USER, // GPIO02 Module Pin 7
|
||||
|
@ -385,7 +386,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0
|
||||
},
|
||||
{ "WiOn", // Indoor Tap https://www.amazon.com/gp/product/B00ZYLUBJU/ref=s9_acsd_al_bw_c_x_3_w (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_USER, // GPIO00 Optional sensor (pm clock)
|
||||
0,
|
||||
GPIO_LED1, // GPIO02 Green Led (1 = On, 0 = Off)
|
||||
|
@ -398,7 +399,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0
|
||||
},
|
||||
{ "WeMos D1 mini", // WeMos and NodeMCU hardware (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_USER, // GPIO00 D3 Wemos Button Shield
|
||||
GPIO_USER, // GPIO01 TX Serial RXD
|
||||
GPIO_USER, // GPIO02 D4 Wemos DHT Shield
|
||||
|
@ -414,7 +415,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
GPIO_ADC0 // ADC0 A0 Analog input
|
||||
},
|
||||
{ "Sonoff Dev", // Sonoff Dev (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 E-FW Button
|
||||
GPIO_USER, // GPIO01 TX Serial RXD and Optional sensor
|
||||
0, // GPIO02
|
||||
|
@ -430,7 +431,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
GPIO_ADC0 // ADC0 A0 Analog input
|
||||
},
|
||||
{ "H801", // Lixada H801 Wifi (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 E-FW Button
|
||||
GPIO_LED1, // GPIO01 Green LED
|
||||
GPIO_TXD, // GPIO02 RX - Pin next to TX on the PCB
|
||||
|
@ -445,7 +446,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
0, 0
|
||||
},
|
||||
{ "Sonoff SC", // Sonoff SC (ESP8266)
|
||||
0, // esp8266
|
||||
0, // not used
|
||||
GPIO_KEY1, // GPIO00 Button
|
||||
GPIO_TXD, // GPIO01 RXD to ATMEGA328P
|
||||
GPIO_USER, // GPIO02 Optional sensor
|
||||
|
@ -456,11 +457,12 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
||||
0, 0, 0, 0
|
||||
},
|
||||
{ "Sonoff BN-SZ", // Sonoff BN-SZ01 LED (ESP8285)
|
||||
1, // esp8285
|
||||
{ "Sonoff BN-SZ", // Sonoff BN-SZ01 Ceiling led (ESP8285)
|
||||
0, // not used
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, // Flash connection
|
||||
0, 0, 0,
|
||||
0, 0,
|
||||
0, // Flash connection
|
||||
GPIO_PWM1, // GPIO12 Light
|
||||
GPIO_LED1_INV, // GPIO13 Red Led (0 = On, 1 = Off)
|
||||
0, 0,
|
||||
|
|
|
@ -753,7 +753,7 @@ uint8_t midnightnow = 0;
|
|||
|
||||
String getBuildDateTime()
|
||||
{
|
||||
// "2017-03-07T11:08:02"
|
||||
// "2017-03-07T11:08:02" - ISO8601:2004
|
||||
char bdt[21];
|
||||
char *str;
|
||||
char *p;
|
||||
|
@ -784,7 +784,7 @@ String getBuildDateTime()
|
|||
|
||||
String getDateTime()
|
||||
{
|
||||
// "2017-03-07T11:08:02"
|
||||
// "2017-03-07T11:08:02" - ISO8601:2004
|
||||
char dt[21];
|
||||
|
||||
snprintf_P(dt, sizeof(dt), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"),
|
||||
|
@ -792,6 +792,20 @@ String getDateTime()
|
|||
return String(dt);
|
||||
}
|
||||
|
||||
String getUTCDateTime()
|
||||
{
|
||||
// "2017-03-07T11:08:02" - ISO8601:2004
|
||||
char dt[21];
|
||||
|
||||
TIME_T tmpTime;
|
||||
breakTime(utctime, tmpTime);
|
||||
tmpTime.Year += 1970;
|
||||
|
||||
snprintf_P(dt, sizeof(dt), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"),
|
||||
tmpTime.Year, tmpTime.Month, tmpTime.Day, tmpTime.Hour, tmpTime.Minute, tmpTime.Second);
|
||||
return String(dt);
|
||||
}
|
||||
|
||||
void breakTime(uint32_t timeInput, TIME_T &tm)
|
||||
{
|
||||
// break the given timeInput into time components
|
||||
|
|
|
@ -165,7 +165,7 @@
|
|||
#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+3k code, 0.3k mem)
|
||||
// #define USE_IR_HVAC // Support for HVAC system using IR (+2k code)
|
||||
|
||||
#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+8k code, +1k mem) - Disable by //
|
||||
#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+11k code, +1k mem) - Disable by //
|
||||
#define USE_WS2812_CTYPE 1 // WS2812 Color type (0 - RGB, 1 - GRB)
|
||||
// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem)
|
||||
// When USE_WS2812_DMA is enabled expect Exceptions on Pow
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
* Web server and WiFi Manager
|
||||
*
|
||||
* Enables configuration and reconfiguration of WiFi credentials using a Captive Portal
|
||||
* Source by AlexT (https://github.com/tzapu)
|
||||
* Based on source by AlexT (https://github.com/tzapu)
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define STR_HELPER(x) #x
|
||||
|
@ -235,7 +235,7 @@ const char HTTP_FORM_RST_UPG[] PROGMEM =
|
|||
"</div>"
|
||||
"<div id='f2' name='f2' style='display:none;text-align:center;'><b>Upload started ...</b></div>";
|
||||
const char HTTP_FORM_CMND[] PROGMEM =
|
||||
"<br/><textarea readonly id='t1' name='t1' cols='99' wrap='off'></textarea><br/><br/>"
|
||||
"<br/><textarea readonly id='t1' name='t1' cols='" STR(MESSZ) "' wrap='off'></textarea><br/><br/>"
|
||||
"<form method='get' onsubmit='return l(1);'>"
|
||||
"<input style='width:98%' id='c1' name='c1' length='99' placeholder='Enter command' autofocus><br/>"
|
||||
// "<br/><button type='submit'>Send command</button>"
|
||||
|
@ -261,8 +261,11 @@ const char HTTP_END[] PROGMEM =
|
|||
"</body>"
|
||||
"</html>";
|
||||
|
||||
const char HDR_CCNTL[] PROGMEM = "Cache-Control";
|
||||
const char HDR_REVAL[] PROGMEM = "no-cache, no-store, must-revalidate";
|
||||
const char HDR_CTYPE_PLAIN[] PROGMEM = "text/plain";
|
||||
const char HDR_CTYPE_HTML[] PROGMEM = "text/html";
|
||||
const char HDR_CTYPE_XML[] PROGMEM = "text/xml";
|
||||
const char HDR_CTYPE_JSON[] PROGMEM = "application/json";
|
||||
const char HDR_CTYPE_STREAM[] PROGMEM = "application/octet-stream";
|
||||
|
||||
#define DNS_PORT 53
|
||||
enum http_t {HTTP_OFF, HTTP_USER, HTTP_ADMIN, HTTP_MANAGER};
|
||||
|
@ -376,6 +379,13 @@ void pollDnsWeb()
|
|||
}
|
||||
}
|
||||
|
||||
void setHeader()
|
||||
{
|
||||
webServer->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate"));
|
||||
webServer->sendHeader(F("Pragma"), F("no-cache"));
|
||||
webServer->sendHeader(F("Expires"), F("-1"));
|
||||
}
|
||||
|
||||
void showPage(String &page)
|
||||
{
|
||||
if((HTTP_ADMIN == _httpflag) && (sysCfg.web_password[0] != 0) && !webServer->authenticate(WEB_USERNAME, sysCfg.web_password)) {
|
||||
|
@ -390,16 +400,13 @@ void showPage(String &page)
|
|||
}
|
||||
}
|
||||
page += FPSTR(HTTP_END);
|
||||
|
||||
webServer->sendHeader(FPSTR(HDR_CCNTL), FPSTR(HDR_REVAL));
|
||||
webServer->sendHeader(F("Pragma"), F("no-cache"));
|
||||
webServer->sendHeader(F("Expires"), F("-1"));
|
||||
webServer->send(200, F("text/html"), page);
|
||||
setHeader();
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_HTML), page);
|
||||
}
|
||||
|
||||
void handleRoot()
|
||||
{
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle root"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Root"));
|
||||
|
||||
if (captivePortal()) { // If captive portal redirect instead of displaying the page.
|
||||
return;
|
||||
|
@ -515,7 +522,7 @@ void handleAjax2()
|
|||
page += line;
|
||||
}
|
||||
*/
|
||||
webServer->send(200, F("text/html"), page);
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_HTML), page);
|
||||
}
|
||||
|
||||
boolean httpUser()
|
||||
|
@ -532,7 +539,7 @@ void handleConfig()
|
|||
if (httpUser()) {
|
||||
return;
|
||||
}
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle config"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Config"));
|
||||
|
||||
String page = FPSTR(HTTP_HEAD);
|
||||
page.replace(F("{v}"), F("Configuration"));
|
||||
|
@ -594,7 +601,7 @@ void handleModule()
|
|||
}
|
||||
char stemp[20], line[128];
|
||||
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle Module config"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Module config"));
|
||||
|
||||
String page = FPSTR(HTTP_HEAD);
|
||||
page.replace(F("{v}"), F("Config module"));
|
||||
|
@ -658,7 +665,7 @@ void handleWifi(boolean scan)
|
|||
}
|
||||
char log[LOGSZ];
|
||||
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle Wifi config"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Wifi config"));
|
||||
|
||||
String page = FPSTR(HTTP_HEAD);
|
||||
page.replace(F("{v}"), F("Configure Wifi"));
|
||||
|
@ -757,7 +764,7 @@ void handleMqtt()
|
|||
if (httpUser()) {
|
||||
return;
|
||||
}
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle MQTT config"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: MQTT config"));
|
||||
|
||||
String page = FPSTR(HTTP_HEAD);
|
||||
page.replace(F("{v}"), F("Configure MQTT"));
|
||||
|
@ -782,7 +789,7 @@ void handleLog()
|
|||
if (httpUser()) {
|
||||
return;
|
||||
}
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle Log config"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Log config"));
|
||||
|
||||
String page = FPSTR(HTTP_HEAD);
|
||||
page.replace(F("{v}"), F("Config logging"));
|
||||
|
@ -830,7 +837,7 @@ void handleOther()
|
|||
if (httpUser()) {
|
||||
return;
|
||||
}
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle other config"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Other config"));
|
||||
char stemp[40];
|
||||
|
||||
String page = FPSTR(HTTP_HEAD);
|
||||
|
@ -871,7 +878,7 @@ void handleDownload()
|
|||
if (httpUser()) {
|
||||
return;
|
||||
}
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle download config"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Download config"));
|
||||
|
||||
uint8_t buffer[sizeof(sysCfg)];
|
||||
|
||||
|
@ -882,7 +889,7 @@ void handleDownload()
|
|||
snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_%s.dmp"),
|
||||
sysCfg.friendlyname[0], Version);
|
||||
webServer->sendHeader(F("Content-Disposition"), attachment);
|
||||
webServer->send(200, F("application/octet-stream"), "");
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_STREAM), "");
|
||||
memcpy(buffer, &sysCfg, sizeof(sysCfg));
|
||||
buffer[0] = CONFIG_FILE_SIGN;
|
||||
buffer[1] = (!CONFIG_FILE_XOR)?0:1;
|
||||
|
@ -995,7 +1002,6 @@ void handleSave()
|
|||
gpios += F(", GPIO"); gpios += String(i); gpios += F(" "); gpios += String(sysCfg.my_module.gp.io[i]);
|
||||
}
|
||||
}
|
||||
// setModuleFlashMode(0); // Fails on esp8285 based devices
|
||||
snprintf_P(stemp, sizeof(stemp), modules[sysCfg.module].name);
|
||||
snprintf_P(log, sizeof(log), PSTR("HTTP: %s Module%s"), stemp, gpios.c_str());
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
@ -1049,7 +1055,7 @@ void handleRestore()
|
|||
if (httpUser()) {
|
||||
return;
|
||||
}
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle restore"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Restore"));
|
||||
|
||||
String page = FPSTR(HTTP_HEAD);
|
||||
page.replace(F("{v}"), F("Restore Configuration"));
|
||||
|
@ -1068,7 +1074,7 @@ void handleUpgrade()
|
|||
if (httpUser()) {
|
||||
return;
|
||||
}
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle upgrade"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Upgrade"));
|
||||
|
||||
String page = FPSTR(HTTP_HEAD);
|
||||
page.replace(F("{v}"), F("Firmware upgrade"));
|
||||
|
@ -1218,11 +1224,7 @@ void handleUploadLoop()
|
|||
_uploaderror = 4;
|
||||
return;
|
||||
}
|
||||
// if ((SONOFF_TOUCH == sysCfg.module) || (SONOFF_4CH == sysCfg.module)) {
|
||||
if (sysCfg.my_module.flag &1) {
|
||||
upload.buf[2] = 3; // DOUT - ESP8285
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("FLSH: Set Flash Mode to 3"));
|
||||
}
|
||||
upload.buf[2] = 3; // Force DOUT - ESP8285
|
||||
}
|
||||
}
|
||||
if (_uploadfiletype) { // config
|
||||
|
@ -1282,9 +1284,9 @@ void handleCmnd()
|
|||
if (httpUser()) {
|
||||
return;
|
||||
}
|
||||
char svalue[128]; // was MESSZ
|
||||
char svalue[INPUT_BUFFER_SIZE]; // big to serve Backlog
|
||||
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle cmnd"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Command"));
|
||||
|
||||
uint8_t valid = 1;
|
||||
if (sysCfg.web_password[0] != 0) {
|
||||
|
@ -1332,7 +1334,7 @@ void handleCmnd()
|
|||
} else {
|
||||
message = F("Need user=<username>&password=<password>\n");
|
||||
}
|
||||
webServer->send(200, F("text/plain"), message);
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_PLAIN), message);
|
||||
}
|
||||
|
||||
void handleConsole()
|
||||
|
@ -1341,7 +1343,7 @@ void handleConsole()
|
|||
return;
|
||||
}
|
||||
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle console"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Console"));
|
||||
|
||||
String page = FPSTR(HTTP_HEAD);
|
||||
page.replace(F("{v}"), F("Console"));
|
||||
|
@ -1358,7 +1360,7 @@ void handleAjax()
|
|||
return;
|
||||
}
|
||||
char log[LOGSZ];
|
||||
char svalue[128]; // was MESSZ
|
||||
char svalue[INPUT_BUFFER_SIZE]; // big to serve Backlog
|
||||
byte cflg = 1;
|
||||
byte counter = 99;
|
||||
|
||||
|
@ -1406,7 +1408,7 @@ void handleAjax()
|
|||
} while (counter != logidx);
|
||||
}
|
||||
message += F("</l></r>");
|
||||
webServer->send(200, F("text/xml"), message);
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_XML), message);
|
||||
}
|
||||
|
||||
void handleInfo()
|
||||
|
@ -1414,7 +1416,7 @@ void handleInfo()
|
|||
if (httpUser()) {
|
||||
return;
|
||||
}
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle info"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Info"));
|
||||
|
||||
char stopic[TOPSZ];
|
||||
|
||||
|
@ -1440,8 +1442,8 @@ void handleInfo()
|
|||
page += F("</th><td>"); page += sysCfg.friendlyname[i]; page += F("</td></tr>");
|
||||
}
|
||||
page += F("<tr><td> </td></tr>");
|
||||
// page += F("<tr><th>SSId (RSSI)</th><td>"); page += (sysCfg.sta_active)? sysCfg.sta_ssid2 : sysCfg.sta_ssid1; page += F(" ("); page += WIFI_getRSSIasQuality(WiFi.RSSI()); page += F("%)</td></tr>");
|
||||
page += F("<tr><th>AP"); page += String(sysCfg.sta_active +1); page += F(" SSId (RSSI)</th><td>"); page += sysCfg.sta_ssid[sysCfg.sta_active]; page += F(" ("); page += WIFI_getRSSIasQuality(WiFi.RSSI()); page += F("%)</td></tr>");
|
||||
page += F("<tr><th>AP"); page += String(sysCfg.sta_active +1);
|
||||
page += F(" SSId (RSSI)</th><td>"); page += sysCfg.sta_ssid[sysCfg.sta_active]; page += F(" ("); page += WIFI_getRSSIasQuality(WiFi.RSSI()); page += F("%)</td></tr>");
|
||||
page += F("<tr><th>Hostname</th><td>"); page += Hostname; page += F("</td></tr>");
|
||||
if (static_cast<uint32_t>(WiFi.localIP()) != 0) {
|
||||
page += F("<tr><th>IP address</th><td>"); page += WiFi.localIP().toString(); page += F("</td></tr>");
|
||||
|
@ -1555,18 +1557,15 @@ void handleNotFound()
|
|||
String message = F("File Not Found\n\nURI: ");
|
||||
message += webServer->uri();
|
||||
message += F("\nMethod: ");
|
||||
message += ( webServer->method() == HTTP_GET ) ? F("GET") : F("POST");
|
||||
message += (webServer->method() == HTTP_GET) ? F("GET") : F("POST");
|
||||
message += F("\nArguments: ");
|
||||
message += webServer->args();
|
||||
message += F("\n");
|
||||
for ( uint8_t i = 0; i < webServer->args(); i++ ) {
|
||||
message += " " + webServer->argName ( i ) + ": " + webServer->arg ( i ) + "\n";
|
||||
message += " " + webServer->argName(i) + ": " + webServer->arg(i) + "\n";
|
||||
}
|
||||
|
||||
webServer->sendHeader(FPSTR(HDR_CCNTL), FPSTR(HDR_REVAL));
|
||||
webServer->sendHeader(F("Pragma"), F("no-cache"));
|
||||
webServer->sendHeader(F("Expires"), F("-1"));
|
||||
webServer->send(404, F("text/plain"), message);
|
||||
setHeader();
|
||||
webServer->send(404, FPSTR(HDR_CTYPE_PLAIN), message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1577,7 +1576,7 @@ boolean captivePortal()
|
|||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Request redirected to captive portal"));
|
||||
|
||||
webServer->sendHeader(F("Location"), String("http://") + webServer->client().localIP().toString(), true);
|
||||
webServer->send(302, F("text/plain"), ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
|
||||
webServer->send(302, FPSTR(HDR_CTYPE_PLAIN), ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
|
||||
webServer->client().stop(); // Stop is needed because we sent no content length
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -51,11 +51,10 @@ void mqtt_publishDomoticzPowerState(byte device)
|
|||
{
|
||||
char svalue[64]; // was MESSZ
|
||||
|
||||
if (sysCfg.domoticz_relay_idx[device -1]) {
|
||||
if (sysCfg.flag.mqtt_enabled && sysCfg.domoticz_relay_idx[device -1]) {
|
||||
if ((device < 1) || (device > Maxdevice)) {
|
||||
device = 1;
|
||||
}
|
||||
|
||||
if (sfl_flg) {
|
||||
snprintf_P(svalue, sizeof(svalue), PSTR("{\"idx\":%d,\"nvalue\":2,\"svalue\":\"%d\"}"),
|
||||
sysCfg.domoticz_relay_idx[device -1], sysCfg.led_dimmer[device -1]);
|
||||
|
@ -74,10 +73,10 @@ void mqtt_publishDomoticzPowerState(byte device)
|
|||
|
||||
void domoticz_updatePowerState(byte device)
|
||||
{
|
||||
if (domoticz_update_flag) {
|
||||
if (domoticz_update_flag) {
|
||||
mqtt_publishDomoticzPowerState(device);
|
||||
}
|
||||
domoticz_update_flag = 1;
|
||||
}
|
||||
domoticz_update_flag = 1;
|
||||
}
|
||||
|
||||
void domoticz_mqttUpdate()
|
||||
|
|
|
@ -49,6 +49,8 @@ uint8_t sl_wakeupActive = 0;
|
|||
uint8_t sl_wakeupDimmer = 0;
|
||||
uint16_t sl_wakeupCntr = 0;
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void sl_setDim(uint8_t myDimmer)
|
||||
{
|
||||
if ((1 == sfl_flg) && (100 == myDimmer)) {
|
||||
|
@ -61,11 +63,9 @@ void sl_setDim(uint8_t myDimmer)
|
|||
sl_dcolor[1] = (uint8_t)fmyWrm;
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void sl_init(void)
|
||||
{
|
||||
sysCfg.pwmvalue[0] = 0; // We use dimmer / led_color
|
||||
sysCfg.pwmvalue[0] = 0; // We use dimmer / led_color
|
||||
if (2 == sfl_flg) {
|
||||
sysCfg.pwmvalue[1] = 0; // We use led_color
|
||||
}
|
||||
|
@ -74,6 +74,51 @@ void sl_init(void)
|
|||
sl_wakeupActive = 0;
|
||||
}
|
||||
|
||||
void sl_setColor(char* colstr)
|
||||
{
|
||||
uint8_t my_color[2];
|
||||
char *p;
|
||||
|
||||
uint16_t temp = strtol(colstr, &p, 16);
|
||||
my_color[1] = temp & 0xFF; // Warm
|
||||
temp >>= 8;
|
||||
my_color[0] = temp & 0xFF; // Cold
|
||||
if (temp < my_color[1]) {
|
||||
temp = my_color[1];
|
||||
}
|
||||
float mDim = (float)temp / 2.55;
|
||||
sysCfg.led_dimmer[0] = (uint8_t)mDim;
|
||||
float newDim = 100 / mDim;
|
||||
float fmyCold = (float)my_color[0] * newDim;
|
||||
float fmyWarm = (float)my_color[1] * newDim;
|
||||
sysCfg.led_color[0] = (uint8_t)fmyCold;
|
||||
sysCfg.led_color[1] = (uint8_t)fmyWarm;
|
||||
}
|
||||
|
||||
void sl_prepPower(char *svalue, uint16_t ssvalue)
|
||||
{
|
||||
// do_cmnd_power(index, (sysCfg.led_dimmer[0]>0));
|
||||
if (sysCfg.led_dimmer[0] && !(power&1)) {
|
||||
do_cmnd_power(1, 7); // No publishPowerState
|
||||
}
|
||||
else if (!sysCfg.led_dimmer[0] && (power&1)) {
|
||||
do_cmnd_power(1, 6); // No publishPowerState
|
||||
}
|
||||
#ifdef USE_DOMOTICZ
|
||||
mqtt_publishDomoticzPowerState(1);
|
||||
#endif // USE_DOMOTICZ
|
||||
sl_setDim(sysCfg.led_dimmer[0]);
|
||||
if (2 == sfl_flg) {
|
||||
uint16_t color = (uint16_t)sl_dcolor[0] << 8;
|
||||
color += (uint16_t)sl_dcolor[1];
|
||||
snprintf_P(svalue, ssvalue, PSTR("{\"POWER\":\"%s\", \"Dimmer\":%d, \"Color\":\"%04X\"}"),
|
||||
getStateText(power &1), sysCfg.led_dimmer[0], color);
|
||||
} else {
|
||||
snprintf_P(svalue, ssvalue, PSTR("{\"POWER\":\"%s\", \"Dimmer\":%d}"),
|
||||
getStateText(power &1), sysCfg.led_dimmer[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void sl_setPower(uint8_t power)
|
||||
{
|
||||
sl_power = power &1;
|
||||
|
@ -153,6 +198,34 @@ void sl_animate()
|
|||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Hue support
|
||||
\*********************************************************************************************/
|
||||
|
||||
void sl_replaceHSB(String *response)
|
||||
{
|
||||
response->replace("{h}", "0");
|
||||
response->replace("{s}", "0");
|
||||
response->replace("{b}", String((uint8_t)(2.54f * (float)sysCfg.led_dimmer[0])));
|
||||
}
|
||||
|
||||
void sl_getHSB(float *hue, float *sat, float *bri)
|
||||
{
|
||||
*hue = 0;
|
||||
*sat = 0;
|
||||
*bri = (2.54f * (float)sysCfg.led_dimmer[0]);
|
||||
}
|
||||
|
||||
void sl_setHSB(float hue, float sat, float bri)
|
||||
{
|
||||
char svalue[MESSZ];
|
||||
|
||||
uint8_t tmp = (uint8_t)(bri * 100);
|
||||
sysCfg.led_dimmer[0] = tmp;
|
||||
sl_prepPower(svalue, sizeof(svalue));
|
||||
mqtt_publish_topic_P(5, "DIMMER", svalue);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Commands
|
||||
\*********************************************************************************************/
|
||||
|
@ -166,20 +239,7 @@ boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_le
|
|||
uint8_t my_color[2];
|
||||
char *p;
|
||||
if (4 == data_len) {
|
||||
uint16_t temp = strtol(dataBufUc, &p, 16);
|
||||
my_color[1] = temp & 0xFF; // Warm
|
||||
temp >>= 8;
|
||||
my_color[0] = temp & 0xFF; // Cold
|
||||
if (temp < my_color[1]) {
|
||||
temp = my_color[1];
|
||||
}
|
||||
float mDim = (float)temp / 2.55;
|
||||
sysCfg.led_dimmer[0] = (uint8_t)mDim;
|
||||
float newDim = 100 / mDim;
|
||||
float fmyCold = (float)my_color[0] * newDim;
|
||||
float fmyWarm = (float)my_color[1] * newDim;
|
||||
sysCfg.led_color[0] = (uint8_t)fmyCold;
|
||||
sysCfg.led_color[1] = (uint8_t)fmyWarm;
|
||||
sl_setColor(dataBufUc);
|
||||
coldim = true;
|
||||
} else {
|
||||
sl_setDim(sysCfg.led_dimmer[0]);
|
||||
|
@ -245,26 +305,7 @@ boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_le
|
|||
serviced = false; // Unknown command
|
||||
}
|
||||
if (coldim) {
|
||||
// do_cmnd_power(index, (sysCfg.led_dimmer[0]>0));
|
||||
if (sysCfg.led_dimmer[0] && !(power&1)) {
|
||||
do_cmnd_power(1, 1);
|
||||
}
|
||||
else if (!sysCfg.led_dimmer[0] && (power&1)) {
|
||||
do_cmnd_power(1, 0);
|
||||
}
|
||||
#ifdef USE_DOMOTICZ
|
||||
mqtt_publishDomoticzPowerState(1);
|
||||
#endif // USE_DOMOTICZ
|
||||
sl_setDim(sysCfg.led_dimmer[0]);
|
||||
if (2 == sfl_flg) {
|
||||
uint16_t color = (uint16_t)sl_dcolor[0] << 8;
|
||||
color += (uint16_t)sl_dcolor[1];
|
||||
snprintf_P(svalue, ssvalue, PSTR("{\"POWER\":\"%s\", \"Dimmer\":%d, \"Color\":\"%04X\"}"),
|
||||
getStateText(power &1), sysCfg.led_dimmer[0], color);
|
||||
} else {
|
||||
snprintf_P(svalue, ssvalue, PSTR("{\"POWER\":\"%s\", \"Dimmer\":%d}"),
|
||||
getStateText(power &1), sysCfg.led_dimmer[0]);
|
||||
}
|
||||
sl_prepPower(svalue, ssvalue);
|
||||
}
|
||||
return serviced;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Belkin WeMo and Philips Hue bridge emulation
|
||||
\*********************************************************************************************/
|
||||
|
||||
#ifdef USE_EMULATION
|
||||
|
||||
#define UDP_BUFFER_SIZE 200 // Max UDP buffer size needed for M-SEARCH message
|
||||
|
@ -30,6 +34,7 @@ uint32_t portMulticast = 1900; // Multicast address and port
|
|||
/*********************************************************************************************\
|
||||
* WeMo UPNP support routines
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char WEMO_MSEARCH[] PROGMEM =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=86400\r\n"
|
||||
|
@ -83,44 +88,53 @@ void wemo_respondToMSearch()
|
|||
/*********************************************************************************************\
|
||||
* Hue Bridge UPNP support routines
|
||||
* Need to send 3 response packets with varying ST and USN
|
||||
*
|
||||
* Using Espressif Inc Mac Address of 5C:CF:7F:00:00:00
|
||||
* Philips Lighting is 00:17:88:00:00:00
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char HUE_RESPONSE[] PROGMEM =
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"HOST: 239.255.255.250:1900\r\n"
|
||||
"CACHE-CONTROL: max-age=100\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://{r1}:80/description.xml\r\n"
|
||||
"SERVER: FreeRTOS/7.4.2 UPnP/1.0 IpBridge/1.15.0\r\n"
|
||||
"SERVER: FreeRTOS/7.4.2 UPnP/1.0 IpBridge/1.16.0\r\n"
|
||||
"hue-bridgeid: {r2}\r\n";
|
||||
const char HUE_ST1[] PROGMEM =
|
||||
"ST: upnp:rootdevice\r\n";
|
||||
const char HUE_USN1[] PROGMEM =
|
||||
"ST: upnp:rootdevice\r\n"
|
||||
"USN: uuid:{r3}::upnp:rootdevice\r\n"
|
||||
"\r\n";
|
||||
|
||||
const char HUE_ST2[] PROGMEM =
|
||||
"ST: uuid:{r3}\r\n";
|
||||
const char HUE_USN2[] PROGMEM =
|
||||
"ST: uuid:{r3}\r\n"
|
||||
"USN: uuid:{r3}\r\n"
|
||||
"\r\n";
|
||||
|
||||
const char HUE_ST3[] PROGMEM =
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n";
|
||||
"ST: urn:schemas-upnp-org:device:Basic:1\r\n"
|
||||
"USN: uuid:{r3}\r\n"
|
||||
"\r\n";
|
||||
|
||||
String hue_bridgeid()
|
||||
{
|
||||
char bridgeid[16];
|
||||
|
||||
snprintf_P(bridgeid, sizeof(bridgeid), PSTR("5CCF7FFFFE%03X"), ESP.getChipId());
|
||||
return String(bridgeid);
|
||||
String temp = WiFi.macAddress();
|
||||
temp.replace(":", "");
|
||||
String bridgeid = temp.substring(0, 6) + "FFFE" + temp.substring(6);
|
||||
return bridgeid; // 5CCF7FFFFE139F3D
|
||||
}
|
||||
|
||||
String hue_serial()
|
||||
{
|
||||
String serial = WiFi.macAddress();
|
||||
serial.replace(":", "");
|
||||
serial.toLowerCase();
|
||||
return serial; // 5ccf7f139f3d
|
||||
}
|
||||
|
||||
String hue_UUID()
|
||||
{
|
||||
char serial[36];
|
||||
|
||||
snprintf_P(serial, sizeof(serial), PSTR("f6543a06-da50-11ba-8d8f-5ccf7f%03x"), ESP.getChipId());
|
||||
return String(serial);
|
||||
String uuid = F("f6543a06-da50-11ba-8d8f-");
|
||||
uuid += hue_serial();
|
||||
return uuid; // f6543a06-da50-11ba-8d8f-5ccf7f139f3d
|
||||
}
|
||||
|
||||
void hue_respondToMSearch()
|
||||
|
@ -129,40 +143,35 @@ void hue_respondToMSearch()
|
|||
char log[LOGSZ];
|
||||
|
||||
if (portUDP.beginPacket(portUDP.remoteIP(), portUDP.remotePort())) {
|
||||
String response = FPSTR(HUE_RESPONSE);
|
||||
String response_st = FPSTR(HUE_ST1);
|
||||
String response_usn = FPSTR(HUE_USN1);
|
||||
response += response_st + response_usn;
|
||||
response.replace("{r1}", WiFi.localIP().toString());
|
||||
response.replace("{r2}", hue_bridgeid());
|
||||
response.replace("{r3}", hue_UUID());
|
||||
portUDP.write(response.c_str());
|
||||
portUDP.endPacket();
|
||||
// addLog(LOG_LEVEL_DEBUG_MORE, response.c_str());
|
||||
|
||||
response = FPSTR(HUE_RESPONSE);
|
||||
response_st = FPSTR(HUE_ST2);
|
||||
response_usn = FPSTR(HUE_USN2);
|
||||
response += response_st + response_usn;
|
||||
response.replace("{r1}", WiFi.localIP().toString());
|
||||
response.replace("{r2}", hue_bridgeid());
|
||||
response.replace("{r3}", hue_UUID());
|
||||
portUDP.write(response.c_str());
|
||||
portUDP.endPacket();
|
||||
// addLog(LOG_LEVEL_DEBUG_MORE, response.c_str());
|
||||
|
||||
response = FPSTR(HUE_RESPONSE);
|
||||
response_st = FPSTR(HUE_ST3);
|
||||
response += response_st + response_usn;
|
||||
response.replace("{r1}", WiFi.localIP().toString());
|
||||
response.replace("{r2}", hue_bridgeid());
|
||||
response.replace("{r3}", hue_UUID());
|
||||
portUDP.write(response.c_str());
|
||||
portUDP.endPacket();
|
||||
|
||||
snprintf_P(message, sizeof(message), PSTR("3 response packets sent"));
|
||||
// addLog(LOG_LEVEL_DEBUG_MORE, response.c_str());
|
||||
String response1 = FPSTR(HUE_RESPONSE);
|
||||
response1.replace("{r1}", WiFi.localIP().toString());
|
||||
response1.replace("{r2}", hue_bridgeid());
|
||||
|
||||
String response = response1;
|
||||
response += FPSTR(HUE_ST1);
|
||||
response.replace("{r3}", hue_UUID());
|
||||
portUDP.write(response.c_str());
|
||||
portUDP.endPacket();
|
||||
|
||||
//addLog(LOG_LEVEL_DEBUG_MORE, response.c_str());
|
||||
|
||||
response = response1;
|
||||
response += FPSTR(HUE_ST2);
|
||||
response.replace("{r3}", hue_UUID());
|
||||
portUDP.write(response.c_str());
|
||||
portUDP.endPacket();
|
||||
|
||||
//addLog(LOG_LEVEL_DEBUG_MORE, response.c_str());
|
||||
|
||||
response = response1;
|
||||
response += FPSTR(HUE_ST3);
|
||||
response.replace("{r3}", hue_UUID());
|
||||
portUDP.write(response.c_str());
|
||||
portUDP.endPacket();
|
||||
|
||||
//addLog(LOG_LEVEL_DEBUG_MORE, response.c_str());
|
||||
|
||||
snprintf_P(message, sizeof(message), PSTR("3 response packets sent"));
|
||||
} else {
|
||||
snprintf_P(message, sizeof(message), PSTR("Failed to send response"));
|
||||
}
|
||||
|
@ -171,7 +180,9 @@ void hue_respondToMSearch()
|
|||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
/*********************************************************************************************\
|
||||
* Belkin WeMo and Philips Hue bridge UDP multicast support
|
||||
\*********************************************************************************************/
|
||||
|
||||
boolean UDP_Disconnect()
|
||||
{
|
||||
|
@ -211,10 +222,20 @@ void pollUDP()
|
|||
// addLog_P(LOG_LEVEL_DEBUG_MORE, packetBuffer);
|
||||
|
||||
if (request.indexOf("M-SEARCH") >= 0) {
|
||||
if ((EMUL_WEMO == sysCfg.flag.emulation) &&(request.indexOf("urn:Belkin:device:**") > 0)) {
|
||||
request.toLowerCase();
|
||||
request.replace(" ", "");
|
||||
|
||||
// addLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: M-SEARCH Packet received"));
|
||||
// addLog_P(LOG_LEVEL_DEBUG_MORE, request.c_str());
|
||||
|
||||
if ((EMUL_WEMO == sysCfg.flag.emulation) && (request.indexOf(F("urn:belkin:device:**")) > 0)) {
|
||||
wemo_respondToMSearch();
|
||||
}
|
||||
else if ((EMUL_HUE == sysCfg.flag.emulation) && ((request.indexOf("ST: urn:schemas-upnp-org:device:basic:1") > 0) || (request.indexOf("ST: upnp:rootdevice") > 0) || (request.indexOf("ST: ssdp:all") > 0))) {
|
||||
else if ((EMUL_HUE == sysCfg.flag.emulation) &&
|
||||
((request.indexOf(F("st:urn:schemas-upnp-org:device:basic:1")) > 0) ||
|
||||
(request.indexOf(F("st:upnp:rootdevice")) > 0) ||
|
||||
(request.indexOf(F("st:ssdpsearch:all")) > 0) ||
|
||||
(request.indexOf(F("st:ssdp:all")) > 0))) {
|
||||
hue_respondToMSearch();
|
||||
}
|
||||
}
|
||||
|
@ -224,8 +245,9 @@ void pollUDP()
|
|||
|
||||
#ifdef USE_WEBSERVER
|
||||
/*********************************************************************************************\
|
||||
* Web server additions
|
||||
* Wemo web server additions
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char WEMO_EVENTSERVICE_XML[] PROGMEM =
|
||||
"<?scpd xmlns=\"urn:Belkin:service-1-0\"?>"
|
||||
"<actionList>"
|
||||
|
@ -278,45 +300,93 @@ const char WEMO_SETUP_XML[] PROGMEM =
|
|||
"</device>"
|
||||
"</root>\r\n"
|
||||
"\r\n";
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void handleUPnPevent()
|
||||
{
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: WeMo basic event"));
|
||||
|
||||
String request = webServer->arg(0);
|
||||
if (request.indexOf(F("State>1</Binary")) > 0) {
|
||||
// do_cmnd_power(1, 1);
|
||||
do_cmnd_power(Maxdevice, 1);
|
||||
}
|
||||
if (request.indexOf(F("State>0</Binary")) > 0) {
|
||||
// do_cmnd_power(1, 0);
|
||||
do_cmnd_power(Maxdevice, 0);
|
||||
}
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_PLAIN), "");
|
||||
}
|
||||
|
||||
void handleUPnPservice()
|
||||
{
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: WeMo event service"));
|
||||
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_PLAIN), FPSTR(WEMO_EVENTSERVICE_XML));
|
||||
}
|
||||
|
||||
void handleUPnPsetupWemo()
|
||||
{
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: WeMo setup"));
|
||||
|
||||
String setup_xml = FPSTR(WEMO_SETUP_XML);
|
||||
setup_xml.replace("{x1}", sysCfg.friendlyname[0]);
|
||||
setup_xml.replace("{x2}", wemo_UUID());
|
||||
setup_xml.replace("{x3}", wemo_serial());
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_XML), setup_xml);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Hue web server additions
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char HUE_DESCRIPTION_XML[] PROGMEM =
|
||||
"<?xml version=\"1.0\"?>"
|
||||
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
|
||||
"<specVersion>"
|
||||
"<major>1</major>"
|
||||
"<minor>0</minor>"
|
||||
"<major>1</major>"
|
||||
"<minor>0</minor>"
|
||||
"</specVersion>"
|
||||
"<URLBase>http://{x1}/</URLBase>"
|
||||
// "<URLBase>http://{x1}/</URLBase>"
|
||||
"<URLBase>http://{x1}:80/</URLBase>"
|
||||
"<device>"
|
||||
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>"
|
||||
"<friendlyName>Amazon-Echo-HA-Bridge ({x1})</friendlyName>"
|
||||
"<manufacturer>Royal Philips Electronics</manufacturer>"
|
||||
"<modelName>Philips hue bridge 2012</modelName>"
|
||||
"<modelNumber>929000226503</modelNumber>"
|
||||
"<UDN>uuid:{x2}</UDN>"
|
||||
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>"
|
||||
"<friendlyName>Amazon-Echo-HA-Bridge ({x1})</friendlyName>"
|
||||
// "<friendlyName>Philips hue ({x1})</friendlyName>"
|
||||
"<manufacturer>Royal Philips Electronics</manufacturer>"
|
||||
"<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>"
|
||||
"<modelName>Philips hue bridge 2012</modelName>"
|
||||
"<modelNumber>929000226503</modelNumber>"
|
||||
"<serialNumber>{x3}</serialNumber>"
|
||||
"<UDN>uuid:{x2}</UDN>"
|
||||
"</device>"
|
||||
"</root>\r\n"
|
||||
"\r\n";
|
||||
const char HUE_LIGHT_STATUS_JSON[] PROGMEM =
|
||||
"{\"state\":"
|
||||
"{\"on\":{state},"
|
||||
"\"bri\":{b},"
|
||||
"\"hue\":{h},"
|
||||
"\"sat\":{s},"
|
||||
"\"ct\":500,"
|
||||
"\"xy\":[0.5, 0.5],"
|
||||
"\"alert\":\"none\","
|
||||
"\"effect\":\"none\","
|
||||
"\"colormode\":\"hs\","
|
||||
"\"reachable\":true"
|
||||
"},"
|
||||
"\"on\":{state},"
|
||||
"\"bri\":{b},"
|
||||
"\"hue\":{h},"
|
||||
"\"sat\":{s},"
|
||||
"\"xy\":[0.5, 0.5],"
|
||||
"\"ct\":500,"
|
||||
"\"alert\":\"none\","
|
||||
"\"effect\":\"none\","
|
||||
"\"colormode\":\"hs\","
|
||||
"\"reachable\":true";
|
||||
const char HUE_LIGHTS_STATUS_JSON[] PROGMEM =
|
||||
"\"type\":\"Extended color light\","
|
||||
"\"name\":\"{j1}\","
|
||||
"\"modelid\":\"LCT007\","
|
||||
"\"uniqueid\":\"{j2}\","
|
||||
"\"swversion\":\"5.50.1.19085\""
|
||||
"}";
|
||||
const char HUE_LIGHT_RESPONSE_JSON[] PROGMEM =
|
||||
"{\"success\":{\"{api}/{id}/{cmd}\":{res}}}";
|
||||
const char HUE_GROUP0_STATUS_JSON[] PROGMEM =
|
||||
"{\"name\":\"Group 0\","
|
||||
"\"lights\":[{l1}],"
|
||||
"\"type\":\"LightGroup\","
|
||||
"\"action\":{";
|
||||
// "\"scene\":\"none\",";
|
||||
const char HUE_CONFIG_RESPONSE_JSON[] PROGMEM =
|
||||
"{\"name\":\"Philips hue\","
|
||||
"\"mac\":\"{mac}\","
|
||||
|
@ -324,8 +394,9 @@ const char HUE_CONFIG_RESPONSE_JSON[] PROGMEM =
|
|||
"\"ipaddress\":\"{ip}\","
|
||||
"\"netmask\":\"{mask}\","
|
||||
"\"gateway\":\"{gw}\","
|
||||
"\"proxyaddress\":\"\","
|
||||
"\"proxyaddress\":\"none\","
|
||||
"\"proxyport\":0,"
|
||||
"\"bridgeid\":\"{bid}\","
|
||||
"\"UTC\":\"{dt}\","
|
||||
"\"whitelist\":{\"{id}\":{"
|
||||
"\"last use date\":\"{dt}\","
|
||||
|
@ -337,60 +408,37 @@ const char HUE_CONFIG_RESPONSE_JSON[] PROGMEM =
|
|||
"\"linkbutton\":false,"
|
||||
"\"portalservices\":false"
|
||||
"}";
|
||||
const char HUE_LIGHT_RESPONSE_JSON[] PROGMEM =
|
||||
"{\"success\":{\"/lights/{id}/state/{cmd}\":{res}}}";
|
||||
const char HUE_ERROR_JSON[] PROGMEM =
|
||||
"[{\"error\":{\"type\":901,\"address\":\"/\",\"description\":\"Internal Error\"}}]";
|
||||
|
||||
void handleUPnPevent()
|
||||
{
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle WeMo basic event"));
|
||||
|
||||
String request = webServer->arg(0);
|
||||
if (request.indexOf("State>1</Binary") > 0) {
|
||||
// do_cmnd_power(1, 1);
|
||||
do_cmnd_power(Maxdevice, 1);
|
||||
}
|
||||
if (request.indexOf("State>0</Binary") > 0) {
|
||||
// do_cmnd_power(1, 0);
|
||||
do_cmnd_power(Maxdevice, 0);
|
||||
}
|
||||
webServer->send(200, F("text/plain"), "");
|
||||
}
|
||||
|
||||
void handleUPnPservice()
|
||||
{
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle WeMo event service"));
|
||||
webServer->send_P(200, PSTR("text/plain"), WEMO_EVENTSERVICE_XML);
|
||||
}
|
||||
|
||||
void handleUPnPsetupWemo()
|
||||
{
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle WeMo setup"));
|
||||
|
||||
String setup_xml = FPSTR(WEMO_SETUP_XML);
|
||||
setup_xml.replace("{x1}", sysCfg.friendlyname[0]);
|
||||
setup_xml.replace("{x2}", wemo_UUID());
|
||||
setup_xml.replace("{x3}", wemo_serial());
|
||||
webServer->send(200, F("text/xml"), setup_xml);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
String hue_deviceId(uint8_t id)
|
||||
{
|
||||
char deviceid[16];
|
||||
|
||||
snprintf_P(deviceid, sizeof(deviceid), PSTR("5CCF7F%03X-%0d"), ESP.getChipId(), id);
|
||||
return String(deviceid);
|
||||
String deviceid = WiFi.macAddress() + F(":00:11-") + String(id);
|
||||
deviceid.toLowerCase();
|
||||
return deviceid; // 5c:cf:7f:13:9f:3d:00:11-1
|
||||
}
|
||||
|
||||
String hue_userId()
|
||||
{
|
||||
char userid[7];
|
||||
|
||||
snprintf_P(userid, sizeof(userid), PSTR("%03x"), ESP.getChipId());
|
||||
return String(userid);
|
||||
}
|
||||
|
||||
void handleUPnPsetupHue()
|
||||
{
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle Hue Bridge setup"));
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Hue Bridge setup"));
|
||||
|
||||
String description_xml = FPSTR(HUE_DESCRIPTION_XML);
|
||||
description_xml.replace("{x1}", WiFi.localIP().toString());
|
||||
description_xml.replace("{x2}", hue_UUID());
|
||||
webServer->send(200, F("text/xml"), description_xml);
|
||||
description_xml.replace("{x3}", hue_serial());
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_XML), description_xml);
|
||||
}
|
||||
|
||||
void hue_todo(String *path)
|
||||
|
@ -399,6 +447,8 @@ void hue_todo(String *path)
|
|||
|
||||
snprintf_P(log, sizeof(log), PSTR("HTTP: HUE API not implemented (%s)"),path->c_str());
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_JSON), "{}");
|
||||
}
|
||||
|
||||
void hue_config_response(String *response)
|
||||
|
@ -408,7 +458,35 @@ void hue_config_response(String *response)
|
|||
response->replace("{ip}", WiFi.localIP().toString());
|
||||
response->replace("{mask}", WiFi.subnetMask().toString());
|
||||
response->replace("{gw}", WiFi.gatewayIP().toString());
|
||||
response->replace("{dt}", getDateTime());
|
||||
response->replace("{bid}", hue_bridgeid());
|
||||
response->replace("{dt}", getUTCDateTime());
|
||||
response->replace("{id}", hue_userId());
|
||||
}
|
||||
|
||||
void hue_config(String *path)
|
||||
{
|
||||
String response = "";
|
||||
hue_config_response(&response);
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_JSON), response);
|
||||
}
|
||||
|
||||
void hue_light_status(byte device, String *response)
|
||||
{
|
||||
*response += FPSTR(HUE_LIGHT_STATUS_JSON);
|
||||
response->replace("{state}", (power & (0x01 << (device-1))) ? "true" : "false");
|
||||
|
||||
if (sfl_flg) {
|
||||
sl_replaceHSB(response);
|
||||
#ifdef USE_WS2812
|
||||
}
|
||||
else if (pin[GPIO_WS2812] < 99) {
|
||||
ws2812_replaceHSB(response);
|
||||
#endif // USE_WS2812
|
||||
} else {
|
||||
response->replace("{h}", "0");
|
||||
response->replace("{s}", "0");
|
||||
response->replace("{b}", "0");
|
||||
}
|
||||
}
|
||||
|
||||
void hue_global_cfg(String *path)
|
||||
|
@ -416,51 +494,31 @@ void hue_global_cfg(String *path)
|
|||
String response;
|
||||
|
||||
path->remove(0,1); // cut leading / to get <id>
|
||||
response = "{\"lights\":{\"";
|
||||
response = F("{\"lights\":{\"");
|
||||
for (uint8_t i = 1; i <= Maxdevice; i++) {
|
||||
response += i;
|
||||
response += "\":";
|
||||
response += FPSTR(HUE_LIGHT_STATUS_JSON);
|
||||
response += F("\":{\"state\":{");
|
||||
hue_light_status(i, &response);
|
||||
response += "},";
|
||||
response += FPSTR(HUE_LIGHTS_STATUS_JSON);
|
||||
response.replace("{j1}", sysCfg.friendlyname[i-1]);
|
||||
response.replace("{j2}", hue_deviceId(i));
|
||||
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, F("application/json"), response);
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_JSON), response);
|
||||
}
|
||||
|
||||
void hue_auth(String *path)
|
||||
{
|
||||
char response[38];
|
||||
|
||||
snprintf_P(response, sizeof(response), PSTR("[{\"success\":{\"username\":\"%03x\"}}]"), ESP.getChipId());
|
||||
webServer->send(200, F("application/json"), response);
|
||||
}
|
||||
|
||||
void hue_config(String *path)
|
||||
{
|
||||
String response = "";
|
||||
|
||||
path->remove(0,1); // cut leading / to get <id>
|
||||
hue_config_response(&response);
|
||||
response.replace("{id}", *path);
|
||||
webServer->send(200, F("application/json"), response);
|
||||
snprintf_P(response, sizeof(response), PSTR("[{\"success\":{\"username\":\"%s\"}}]"), hue_userId().c_str());
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_JSON), response);
|
||||
}
|
||||
|
||||
void hue_lights(String *path)
|
||||
|
@ -468,13 +526,14 @@ void hue_lights(String *path)
|
|||
/*
|
||||
* http://sonoff/api/username/lights/1/state?1={"on":true,"hue":56100,"sat":254,"bri":254,"alert":"none","transitiontime":40}
|
||||
*/
|
||||
String response;
|
||||
String response;
|
||||
uint8_t device = 1;
|
||||
uint16_t tmp=0;
|
||||
uint16_t tmp = 0;
|
||||
int16_t pos = 0;
|
||||
float bri = 0;
|
||||
float hue = 0;
|
||||
float sat = 0;
|
||||
float bri = 0;
|
||||
float hue = 0;
|
||||
float sat = 0;
|
||||
bool resp = false;
|
||||
bool on = false;
|
||||
bool change = false;
|
||||
char id[4];
|
||||
|
@ -484,26 +543,18 @@ void hue_lights(String *path)
|
|||
response = "{\"";
|
||||
for (uint8_t i = 1; i <= Maxdevice; i++) {
|
||||
response += i;
|
||||
response += "\":";
|
||||
response += FPSTR(HUE_LIGHT_STATUS_JSON);
|
||||
response += F("\":{\"state\":{");
|
||||
hue_light_status(i, &response);
|
||||
response += "},";
|
||||
response += FPSTR(HUE_LIGHTS_STATUS_JSON);
|
||||
response.replace("{j1}", sysCfg.friendlyname[i-1]);
|
||||
response.replace("{j2}", hue_deviceId(i));
|
||||
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 += "}";
|
||||
webServer->send(200, F("application/json"), response);
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_JSON), response);
|
||||
}
|
||||
else if (path->endsWith("/state")) { // Got ID/state
|
||||
path->remove(0,8); // Remove /lights/
|
||||
|
@ -512,15 +563,17 @@ void hue_lights(String *path)
|
|||
if ((device < 1) || (device > Maxdevice)) {
|
||||
device = 1;
|
||||
}
|
||||
response = "[";
|
||||
response += FPSTR(HUE_LIGHT_RESPONSE_JSON);
|
||||
response.replace("{api}", "/lights");
|
||||
response.replace("{id}", String(device));
|
||||
response.replace("{cmd}", "state/on");
|
||||
if (1 == webServer->args()) {
|
||||
response = "[";
|
||||
|
||||
StaticJsonBuffer<400> jsonBuffer;
|
||||
JsonObject &hue_json = jsonBuffer.parseObject(webServer->arg(0));
|
||||
if (hue_json.containsKey("on")) {
|
||||
|
||||
response += FPSTR(HUE_LIGHT_RESPONSE_JSON);
|
||||
response.replace("{id}", String(device));
|
||||
response.replace("{cmd}", "on");
|
||||
|
||||
on = hue_json["on"];
|
||||
switch(on)
|
||||
{
|
||||
|
@ -533,53 +586,76 @@ void hue_lights(String *path)
|
|||
default : response.replace("{res}", (power & (0x01 << (device-1))) ? "true" : "false");
|
||||
break;
|
||||
}
|
||||
resp = true;
|
||||
}
|
||||
|
||||
if (sfl_flg) {
|
||||
sl_getHSB(&hue,&sat,&bri);
|
||||
#ifdef USE_WS2812
|
||||
ws2812_getHSB(&hue,&sat,&bri);
|
||||
}
|
||||
else if (pin[GPIO_WS2812] < 99) {
|
||||
ws2812_getHSB(&hue,&sat,&bri);
|
||||
#endif // USE_WS2812
|
||||
}
|
||||
|
||||
if (hue_json.containsKey("bri")) {
|
||||
tmp = hue_json["bri"];
|
||||
bri = (float)tmp/254.0f;
|
||||
response += ",";
|
||||
bri = (float)tmp / 254.0f;
|
||||
if (resp) {
|
||||
response += ",";
|
||||
}
|
||||
response += FPSTR(HUE_LIGHT_RESPONSE_JSON);
|
||||
response.replace("{api}", "/lights");
|
||||
response.replace("{id}", String(device));
|
||||
response.replace("{cmd}", "state/bri");
|
||||
response.replace("{cmd}", "bri");
|
||||
response.replace("{res}", String(tmp));
|
||||
resp = true;
|
||||
change = true;
|
||||
}
|
||||
if (hue_json.containsKey("hue")) {
|
||||
tmp = hue_json["hue"];
|
||||
hue = (float)tmp/65535.0f;
|
||||
response += ",";
|
||||
hue = (float)tmp / 65535.0f;
|
||||
if (resp) {
|
||||
response += ",";
|
||||
}
|
||||
response += FPSTR(HUE_LIGHT_RESPONSE_JSON);
|
||||
response.replace("{api}", "/lights");
|
||||
response.replace("{id}", String(device));
|
||||
response.replace("{cmd}", "state/hue");
|
||||
response.replace("{cmd}", "hue");
|
||||
response.replace("{res}", String(tmp));
|
||||
resp = true;
|
||||
change = true;
|
||||
}
|
||||
if (hue_json.containsKey("sat")) {
|
||||
tmp = hue_json["sat"];
|
||||
sat = (float)tmp/254.0f;
|
||||
response += ",";
|
||||
sat = (float)tmp / 254.0f;
|
||||
if (resp) {
|
||||
response += ",";
|
||||
}
|
||||
response += FPSTR(HUE_LIGHT_RESPONSE_JSON);
|
||||
response.replace("{api}", "/lights");
|
||||
response.replace("{id}", String(device));
|
||||
response.replace("{cmd}", "state/sat");
|
||||
response.replace("{cmd}", "sat");
|
||||
response.replace("{res}", String(tmp));
|
||||
change = true;
|
||||
}
|
||||
if (change && (pin[GPIO_WS2812] < 99)) {
|
||||
ws2812_setHSB(hue, sat, bri);
|
||||
if (change) {
|
||||
if (sfl_flg) {
|
||||
sl_setHSB(hue, sat, bri);
|
||||
#ifdef USE_WS2812
|
||||
}
|
||||
else if (pin[GPIO_WS2812] < 99) {
|
||||
ws2812_setHSB(hue, sat, bri);
|
||||
#endif // USE_WS2812
|
||||
}
|
||||
change = false;
|
||||
}
|
||||
#endif // USE_WS2812
|
||||
response += "]";
|
||||
if (2 == response.length()) {
|
||||
response = FPSTR(HUE_ERROR_JSON);
|
||||
}
|
||||
}
|
||||
else {
|
||||
response=FPSTR(HUE_ERROR_JSON);
|
||||
response = FPSTR(HUE_ERROR_JSON);
|
||||
}
|
||||
webServer->send(200, F("application/json"), response);
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_JSON), response);
|
||||
}
|
||||
else if(path->indexOf("/lights/") >= 0) { // Got /lights/ID
|
||||
path->remove(0,8); // Remove /lights/
|
||||
|
@ -587,22 +663,35 @@ void hue_lights(String *path)
|
|||
if ((device < 1) || (device > Maxdevice)) {
|
||||
device = 1;
|
||||
}
|
||||
response = FPSTR(HUE_LIGHT_STATUS_JSON);
|
||||
response.replace("{state}", (power & (0x01 << (device -1))) ? "true" : "false");
|
||||
response.replace("{j1}", sysCfg.friendlyname[device -1]);
|
||||
response += F("{\"state\":{");
|
||||
hue_light_status(device, &response);
|
||||
response += "},";
|
||||
response += FPSTR(HUE_LIGHTS_STATUS_JSON);
|
||||
response.replace("{j1}", sysCfg.friendlyname[device-1]);
|
||||
response.replace("{j2}", hue_deviceId(device));
|
||||
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");
|
||||
}
|
||||
webServer->send(200, F("application/json"), response);
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_JSON), response);
|
||||
}
|
||||
else webServer->send(406, F("application/json"), "{}");
|
||||
else {
|
||||
webServer->send(406, FPSTR(HDR_CTYPE_JSON), "{}");
|
||||
}
|
||||
}
|
||||
|
||||
void hue_groups(String *path)
|
||||
{
|
||||
String response = "{}";
|
||||
|
||||
if (path->endsWith("/0")) {
|
||||
response = FPSTR(HUE_GROUP0_STATUS_JSON);
|
||||
String lights = F("\"1\"");
|
||||
for (uint8_t i = 2; i <= Maxdevice; i++) {
|
||||
lights += ",\"" + String(i) + "\"";
|
||||
}
|
||||
response.replace("{l1}", lights);
|
||||
hue_light_status(1, &response);
|
||||
response += F("}}");
|
||||
}
|
||||
|
||||
webServer->send(200, FPSTR(HDR_CTYPE_JSON), response);
|
||||
}
|
||||
|
||||
void handle_hue_api(String *path)
|
||||
|
@ -617,8 +706,9 @@ 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());
|
||||
path->remove(0, 4); // remove /api
|
||||
uint16_t apilen = path->length();
|
||||
snprintf_P(log, sizeof(log), PSTR("HTTP: Hue API (%s)"), path->c_str());
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
for (args = 0; args < webServer->args(); args++) {
|
||||
String json = webServer->arg(args);
|
||||
|
@ -627,10 +717,11 @@ void handle_hue_api(String *path)
|
|||
}
|
||||
|
||||
if (path->endsWith("/invalid/")) {} // Just ignore
|
||||
else if (!apilen) hue_auth(path); // New HUE App setup
|
||||
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->indexOf("/groups") >= 0) hue_groups(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);
|
||||
|
|
Loading…
Reference in New Issue