diff --git a/README.md b/README.md index 9c28ed7cd..7e4765b90 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 **4.0.8** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. +Current version is **4.1.0** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/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```. diff --git a/api/arduino/sonoff-minimal.ino.bin b/api/arduino/sonoff-minimal.ino.bin index 84e7a4ba7..18dcf1b0a 100644 Binary files a/api/arduino/sonoff-minimal.ino.bin and b/api/arduino/sonoff-minimal.ino.bin differ diff --git a/api/arduino/sonoff.ino.bin b/api/arduino/sonoff.ino.bin index 03dc74681..e51b7fb5e 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 1420097ed..0a64af3f5 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,13 @@ -/* 4.0.8 20170321 +/* 4.1.0 20170325 + * Change static IP addresses in user_config.h from list (using commas) to string (using dots) + * Unify display result of commands Modules, Module and Gpios + * Rewrite Module selection web page to bring size down from 18651 to 4319 bytes (!) (#234, #240) + * Add basic support for (Lixada) H801 RGBWW controller (#252) + * Add command Prefix1 to Prefix3 to assign SUB_PREFIX, PUB_PREFIX and PUB_PREFIX2 respectively (#255) + * Add static ip addresses to flash (#262) + * Add commands IpAddress, Gateway, Subnetmask and DnsServer to select static ip addresses (#273) + * + * 4.0.8 20170321 * Fix entering non-numeric webpassword * Force selection between TLS or Webserver due to memory restraint (#240) * Allow entering empty string using "0" for selected commands (#242) diff --git a/sonoff/settings.h b/sonoff/settings.h index 4575f98e5..0921305b9 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -83,7 +83,8 @@ struct SYSCFG { byte model; // Not used since 3.9.1 int8_t timezone; char otaUrl[101]; - char ex_friendlyname[33]; // Not used since 3.2.5 - see below + + char mqtt_prefix[3][11]; // was ex_friendlyname[33] until 3.2.5 byte serial_enable; byte seriallog_level; @@ -210,6 +211,10 @@ struct SYSCFG { // 4.0.7 uint16_t pwmvalue[5]; + // 4.0.9 +// uint8_t ip_address[4][4]; + uint32_t ip_address[4]; + } sysCfg; struct RTCMEM { diff --git a/sonoff/settings.ino b/sonoff/settings.ino index ff2e148bd..b249d0e6e 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -418,10 +418,9 @@ void CFG_DefaultSet2() { sysCfg.savedata = SAVE_DATA; sysCfg.savestate = SAVE_STATE; - sysCfg.model = 0; +// sysCfg.model = 0; sysCfg.timezone = APP_TIMEZONE; strlcpy(sysCfg.otaUrl, OTA_URL, sizeof(sysCfg.otaUrl)); - strlcpy(sysCfg.ex_friendlyname, FRIENDLY_NAME, sizeof(sysCfg.ex_friendlyname)); sysCfg.seriallog_level = SERIAL_LOG_LEVEL; sysCfg.sta_active = 0; @@ -451,14 +450,11 @@ void CFG_DefaultSet2() sysCfg.mqtt_power_retain = MQTT_POWER_RETAIN; sysCfg.value_units = 0; sysCfg.button_restrict = 0; -// sysCfg.message_format = 0; sysCfg.tele_period = TELE_PERIOD; sysCfg.power = APP_POWER; sysCfg.poweronstate = APP_POWERON_STATE; -// sysCfg.pulsetime = APP_PULSETIME; sysCfg.ledstate = APP_LEDSTATE; -// sysCfg.switchmode = SWITCH_MODE; sysCfg.blinktime = APP_BLINKTIME; sysCfg.blinkcount = APP_BLINKCOUNT; sysCfg.sleep = APP_SLEEP; @@ -495,7 +491,7 @@ void CFG_DefaultSet2() sysCfg.hlw_mkwhs = 0; // MaxEnergyStart CFG_DefaultSet_3_2_4(); - + strlcpy(sysCfg.friendlyname[0], FRIENDLY_NAME, sizeof(sysCfg.friendlyname[0])); strlcpy(sysCfg.friendlyname[1], FRIENDLY_NAME"2", sizeof(sysCfg.friendlyname[1])); strlcpy(sysCfg.friendlyname[2], FRIENDLY_NAME"3", sizeof(sysCfg.friendlyname[2])); @@ -514,8 +510,11 @@ void CFG_DefaultSet2() CFG_DefaultSet_4_0_4(); sysCfg.pulsetime[0] = APP_PULSETIME; - // v4.0.7 + // 4.0.7 for (byte i = 0; i < 5; i++) sysCfg.pwmvalue[i] = 0; + + // 4.0.9 + CFG_DefaultSet_4_0_9(); } void CFG_DefaultSet_3_2_4() @@ -564,6 +563,17 @@ void CFG_DefaultSet_4_0_4() for (byte i = 1; i < MAX_PULSETIMERS; i++) sysCfg.pulsetime[i] = 0; } +void CFG_DefaultSet_4_0_9() +{ + strlcpy(sysCfg.mqtt_prefix[0], SUB_PREFIX, sizeof(sysCfg.mqtt_prefix[0])); + strlcpy(sysCfg.mqtt_prefix[1], PUB_PREFIX, sizeof(sysCfg.mqtt_prefix[1])); + strlcpy(sysCfg.mqtt_prefix[2], PUB_PREFIX2, sizeof(sysCfg.mqtt_prefix[2])); + parseIP(&sysCfg.ip_address[0], WIFI_IP_ADDRESS); + parseIP(&sysCfg.ip_address[1], WIFI_GATEWAY); + parseIP(&sysCfg.ip_address[2], WIFI_SUBNETMASK); + parseIP(&sysCfg.ip_address[3], WIFI_DNS); +} + void CFG_Default() { addLog_P(LOG_LEVEL_NONE, PSTR("Config: Use default configuration")); @@ -600,7 +610,7 @@ void CFG_Migrate_Part2() strlcpy(sysCfg.mqtt_client, sysCfg2.mqtt_client, sizeof(sysCfg.mqtt_client)); strlcpy(sysCfg.mqtt_user, sysCfg2.mqtt_user, sizeof(sysCfg.mqtt_user)); strlcpy(sysCfg.mqtt_pwd, sysCfg2.mqtt_pwd, sizeof(sysCfg.mqtt_pwd)); - strlcpy(sysCfg.ex_friendlyname, sysCfg2.mqtt_client, sizeof(sysCfg.ex_friendlyname)); + strlcpy(sysCfg.friendlyname[0], sysCfg2.mqtt_client, sizeof(sysCfg.friendlyname[0])); } if (sysCfg2.version >= 0x01001700) { // 1.0.23 sysCfg.webserver = sysCfg2.webserver; @@ -691,19 +701,13 @@ void CFG_Delta() if (sysCfg.version < 0x03000600) { // 3.0.6 - Add parameter sysCfg.ex_pulsetime = APP_PULSETIME; } - if (sysCfg.version < 0x03010100) { // 3.1.1 - Add parameter - sysCfg.poweronstate = APP_POWERON_STATE; - } if (sysCfg.version < 0x03010200) { // 3.1.2 - Add parameter - if (sysCfg.poweronstate == 2) sysCfg.poweronstate = 3; + sysCfg.poweronstate = APP_POWERON_STATE; } if (sysCfg.version < 0x03010600) { // 3.1.6 - Add parameter sysCfg.blinktime = APP_BLINKTIME; sysCfg.blinkcount = APP_BLINKCOUNT; } - if (sysCfg.version < 0x03011000) { // 3.1.16 - Add parameter - getClient(sysCfg.friendlyname[0], sysCfg.mqtt_client, sizeof(sysCfg.friendlyname[0])); - } if (sysCfg.version < 0x03020400) { // 3.2.4 - Add parameter CFG_DefaultSet_3_2_4(); } @@ -746,6 +750,9 @@ void CFG_Delta() if (sysCfg.version < 0x04000700) { for (byte i = 0; i < 5; i++) sysCfg.pwmvalue[i] = 0; } + if (sysCfg.version < 0x04000804) { + CFG_DefaultSet_4_0_9(); + } sysCfg.version = VERSION; } } diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index d85cf8344..ed8db6723 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -12,9 +12,9 @@ //#define ALLOW_MIGRATE_TO_V3 #ifdef ALLOW_MIGRATE_TO_V3 - #define VERSION 0x03091F00 // 3.9.31 + #define VERSION 0x03092000 // 3.9.32 #else - #define VERSION 0x04000800 // 4.0.8 + #define VERSION 0x04010000 // 4.1.0 #endif // ALLOW_MIGRATE_TO_V3 enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; @@ -132,7 +132,11 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX}; #define INPUT_BUFFER_SIZE 100 // Max number of characters in serial buffer #define TOPSZ 60 // Max number of characters in topic string #define LOGSZ 128 // Max number of characters in log string -#define MAX_LOG_LINES 20 // Max number of lines in weblog +#ifdef USE_MQTT_TLS + #define MAX_LOG_LINES 10 // Max number of lines in weblog +#else + #define MAX_LOG_LINES 20 // Max number of lines in weblog +#endif #define APP_BAUDRATE 115200 // Default serial baudrate #define MAX_STATUS 11 // Max number of status lines @@ -208,13 +212,6 @@ struct TimeChangeRule TimeChangeRule myDST = { TIME_DST }; // Daylight Saving Time TimeChangeRule mySTD = { TIME_STD }; // Standard Time -#ifdef USE_STATIC_IP_ADDRESS -const uint8_t ipadd[4] = { WIFI_IP_ADDRESS }; // Static ip -const uint8_t ipgat[4] = { WIFI_GATEWAY }; // Local router gateway ip -const uint8_t ipdns[4] = { WIFI_DNS }; // DNS ip -const uint8_t ipsub[4] = { WIFI_SUBNETMASK }; // Subnetmask -#endif // USE_STATIC_IP_ADDRESS - int Baudrate = APP_BAUDRATE; // Serial interface baud rate byte SerialInByte; // Received byte int SerialInByteCounter = 0; // Index in receive buffer @@ -435,8 +432,8 @@ void mqtt_publish(const char* topic, const char* data, boolean retained) { char *me; - if (!strcmp(SUB_PREFIX,PUB_PREFIX)) { - me = strstr(topic,SUB_PREFIX); + if (!strcmp(sysCfg.mqtt_prefix[0],sysCfg.mqtt_prefix[1])) { + me = strstr(topic,sysCfg.mqtt_prefix[0]); if (me == topic) mqtt_cmnd_publish += 8; } mqtt_publish_sec(topic, data, retained); @@ -452,7 +449,7 @@ 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); + snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s"), sysCfg.mqtt_prefix[prefix +1], sysCfg.mqtt_topic, romram); mqtt_publish(stopic, data); } @@ -462,7 +459,7 @@ void mqtt_publishPowerState(byte device) 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(stopic, sizeof(stopic), PSTR("%s/%s/RESULT"), sysCfg.mqtt_prefix[1], sysCfg.mqtt_topic); snprintf_P(svalue, sizeof(svalue), PSTR("{\"%s%s\":\"%s\"}"), sysCfg.mqtt_subtopic, (Maxdevice > 1) ? sdevice : "", (power & (0x01 << (device -1))) ? MQTT_STATUS_ON : MQTT_STATUS_OFF); mqtt_publish(stopic, svalue); @@ -488,17 +485,17 @@ void mqtt_connected() if (sysCfg.mqtt_enabled) { // Satisfy iobroker (#299) - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/POWER"), SUB_PREFIX, sysCfg.mqtt_topic); + snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/POWER"), sysCfg.mqtt_prefix[0], sysCfg.mqtt_topic); svalue[0] ='\0'; mqtt_publish(stopic, svalue); - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/#"), SUB_PREFIX, sysCfg.mqtt_topic); + snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/#"), sysCfg.mqtt_prefix[0], sysCfg.mqtt_topic); mqttClient.subscribe(stopic); mqttClient.loop(); // Solve LmacRxBlk:1 messages - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/#"), SUB_PREFIX, sysCfg.mqtt_grptopic); + snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/#"), sysCfg.mqtt_prefix[0], sysCfg.mqtt_grptopic); mqttClient.subscribe(stopic); mqttClient.loop(); // Solve LmacRxBlk:1 messages - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/#"), SUB_PREFIX, MQTTClient); // Fall back topic + snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/#"), sysCfg.mqtt_prefix[0], MQTTClient); // Fall back topic mqttClient.subscribe(stopic); mqttClient.loop(); // Solve LmacRxBlk:1 messages #ifdef USE_DOMOTICZ @@ -576,7 +573,7 @@ void mqtt_reconnect() #endif // USE_DISCOVERY #endif // USE_MQTT_TLS mqttClient.setServer(sysCfg.mqtt_host, sysCfg.mqtt_port); - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/LWT"), PUB_PREFIX2, sysCfg.mqtt_topic); + snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/LWT"), sysCfg.mqtt_prefix[2], sysCfg.mqtt_topic); snprintf_P(svalue, sizeof(svalue), PSTR("Offline")); if (mqttClient.connect(MQTTClient, sysCfg.mqtt_user, sysCfg.mqtt_pwd, stopic, 1, true, svalue)) { addLog_P(LOG_LEVEL_INFO, PSTR("MQTT: Connected")); @@ -643,6 +640,17 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, } snprintf_P(svalue, ssvalue, PSTR("{\"MqttPassword\":\"%s\"}"), sysCfg.mqtt_pwd); } + else if (!strcmp(type,"PREFIX") && (index > 0) && (index <= 3)) { + if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_prefix[0]))) { + for(i = 0; i <= data_len; i++) +// if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) dataBuf[i] = '_'; + if ((dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) dataBuf[i] = '_'; + strlcpy(sysCfg.mqtt_prefix[index -1], (payload == 1) ? (index==1)?SUB_PREFIX:(index==2)?PUB_PREFIX:PUB_PREFIX : dataBuf, sizeof(sysCfg.mqtt_prefix[0])); +// if (sysCfg.mqtt_prefix[index -1][strlen(sysCfg.mqtt_prefix[index -1])] == '/') sysCfg.mqtt_prefix[index -1][strlen(sysCfg.mqtt_prefix[index -1])] = 0; + restartflag = 2; + } + snprintf_P(svalue, ssvalue, PSTR("{\"Prefix%d\":\"%s\"}"), index, sysCfg.mqtt_prefix[index -1]); + } else if (!strcmp(type,"GROUPTOPIC")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_grptopic))) { for(i = 0; i <= data_len; i++) @@ -710,9 +718,9 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, if (!payload) { for(i = 1; i <= Maxdevice; i++) { // Clear MQTT retain in broker snprintf_P(stemp2, sizeof(stemp2), PSTR("%d"), i); - snprintf_P(stemp1, sizeof(stemp1), PSTR("%s/%s/POWER%s"), PUB_PREFIX, sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp2 : ""); + snprintf_P(stemp1, sizeof(stemp1), PSTR("%s/%s/POWER%s"), sysCfg.mqtt_prefix[1], sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp2 : ""); mqtt_publish(stemp1, "", sysCfg.mqtt_power_retain); - snprintf_P(stemp1, sizeof(stemp1), PSTR("%s/%s/LIGHT%s"), PUB_PREFIX, sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp2 : ""); + snprintf_P(stemp1, sizeof(stemp1), PSTR("%s/%s/LIGHT%s"), sysCfg.mqtt_prefix[1], sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp2 : ""); mqtt_publish(stemp1, "", sysCfg.mqtt_power_retain); } } @@ -738,8 +746,8 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) { char *str; - if (!strcmp(SUB_PREFIX,PUB_PREFIX)) { - str = strstr(topic,SUB_PREFIX); + if (!strcmp(sysCfg.mqtt_prefix[0],sysCfg.mqtt_prefix[1])) { + str = strstr(topic,sysCfg.mqtt_prefix[0]); if ((str == topic) && mqtt_cmnd_publish) { if (mqtt_cmnd_publish > 8) mqtt_cmnd_publish -= 8; else mqtt_cmnd_publish = 0; return; @@ -749,6 +757,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) char topicBuf[TOPSZ], dataBuf[data_len+1], dataBufUc[128], svalue[MESSZ], stemp1[TOPSZ]; char *p, *mtopic = NULL, *type = NULL; uint16_t i = 0, grpflg = 0, index; + uint32_t address; strncpy(topicBuf, topic, sizeof(topicBuf)); memcpy(dataBuf, data, sizeof(dataBuf)); @@ -764,7 +773,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } #endif // USE_DOMOTICZ - memmove(topicBuf, topicBuf+sizeof(SUB_PREFIX), sizeof(topicBuf)-sizeof(SUB_PREFIX)); // Remove SUB_PREFIX + memmove(topicBuf, topicBuf+strlen(sysCfg.mqtt_prefix[0]), sizeof(topicBuf)-strlen(sysCfg.mqtt_prefix[0])); // Remove SUB_PREFIX i = 0; for (str = strtok_r(topicBuf, "/", &p); str && i < 2; str = strtok_r(NULL, "/", &p)) { @@ -891,7 +900,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) restartflag = 2; } snprintf_P(stemp1, sizeof(stemp1), modules[sysCfg.module].name); - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Module\":\"%s (%d)\"}"), stemp1, sysCfg.module +1); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Module\":\"%d (%s)\"}"), sysCfg.module +1, stemp1); } else if (!strcmp(type,"MODULES")) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"Modules1\":\""), svalue); @@ -900,7 +909,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) if (jsflg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); jsflg = 1; snprintf_P(stemp1, sizeof(stemp1), modules[i].name); - snprintf_P(svalue, sizeof(svalue), PSTR("%s%s (%d)"), svalue, stemp1, i +1); + snprintf_P(svalue, sizeof(svalue), PSTR("%s%d (%s)"), svalue, i +1, stemp1); } snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue); mqtt_publish_topic_P(0, PSTR("RESULT"), svalue); @@ -910,7 +919,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) if (jsflg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); jsflg = 1; snprintf_P(stemp1, sizeof(stemp1), modules[i].name); - snprintf_P(svalue, sizeof(svalue), PSTR("%s%s (%d)"), svalue, stemp1, i +1); + snprintf_P(svalue, sizeof(svalue), PSTR("%s%d (%s)"), svalue, i +1, stemp1); } snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue); } @@ -947,7 +956,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) if (jsflg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); jsflg = 1; snprintf_P(stemp1, sizeof(stemp1), sensors[i]); - snprintf_P(svalue, sizeof(svalue), PSTR("%s%s (%d)"), svalue, stemp1, i); + snprintf_P(svalue, sizeof(svalue), PSTR("%s%d (%s)"), svalue, i, stemp1); } snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue); mqtt_publish_topic_P(0, PSTR("RESULT"), svalue); @@ -957,7 +966,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) if (jsflg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); jsflg = 1; snprintf_P(stemp1, sizeof(stemp1), sensors[i]); - snprintf_P(svalue, sizeof(svalue), PSTR("%s%s (%d)"), svalue, stemp1, i); + snprintf_P(svalue, sizeof(svalue), PSTR("%s%d (%s)"), svalue, i, stemp1); } snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue); } @@ -1032,13 +1041,41 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } snprintf_P(svalue, sizeof(svalue), PSTR("{\"LogPort\":%d}"), sysCfg.syslog_port); } + else if (!strcmp(type,"IPADDRESS")) { + if (parseIP(&address, dataBuf)) { + sysCfg.ip_address[0] = address; + restartflag = 2; + } + snprintf_P(svalue, sizeof(svalue), PSTR("{\"IPAddress\":\"%s (%s)\"}"), IPAddress(sysCfg.ip_address[0]).toString().c_str(), WiFi.localIP().toString().c_str()); + } + else if (!strcmp(type,"GATEWAY")) { + if (parseIP(&address, dataBuf)) { + sysCfg.ip_address[1] = address; + restartflag = 2; + } + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Gateway\":\"%s\"}"), IPAddress(sysCfg.ip_address[1]).toString().c_str()); + } + else if (!strcmp(type,"SUBNETMASK")) { + if (parseIP(&address, dataBuf)) { + sysCfg.ip_address[2] = address; + restartflag = 2; + } + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Subnetmask\":\"%s\"}"), IPAddress(sysCfg.ip_address[2]).toString().c_str()); + } + else if (!strcmp(type,"DNSSERVER")) { + if (parseIP(&address, dataBuf)) { + sysCfg.ip_address[3] = address; + restartflag = 2; + } + snprintf_P(svalue, sizeof(svalue), PSTR("{\"DnsServer\":\"%s\"}"), IPAddress(sysCfg.ip_address[3]).toString().c_str()); + } else if (!strcmp(type,"NTPSERVER") && (index > 0) && (index <= 3)) { if ((data_len > 0) && (data_len < sizeof(sysCfg.ntp_server[0]))) { strlcpy(sysCfg.ntp_server[index -1], (!strcmp(dataBuf,"0")) ? "" : (payload == 1) ? (index==1)?NTP_SERVER1:(index==2)?NTP_SERVER2:NTP_SERVER3 : dataBuf, sizeof(sysCfg.ntp_server[0])); for (i = 0; i < strlen(sysCfg.ntp_server[index -1]); i++) if (sysCfg.ntp_server[index -1][i] == ',') sysCfg.ntp_server[index -1][i] = '.'; restartflag = 2; } - snprintf_P(svalue, sizeof(svalue), PSTR("{\"NTPServer%d\":\"%s\"}"), index, sysCfg.ntp_server[index -1]); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"NtpServer%d\":\"%s\"}"), index, sysCfg.ntp_server[index -1]); } else if (!strcmp(type,"AP")) { if ((data_len > 0) && (payload >= 0) && (payload <= 2)) { @@ -1302,7 +1339,7 @@ void send_button_power(byte key, byte device, byte state) if (!key && (device > Maxdevice)) device = 1; snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), device); snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s%s"), - SUB_PREFIX, (key) ? sysCfg.switch_topic : sysCfg.button_topic, sysCfg.mqtt_subtopic, (key || (Maxdevice > 1)) ? stemp1 : ""); + sysCfg.mqtt_prefix[0], (key) ? sysCfg.switch_topic : sysCfg.button_topic, sysCfg.mqtt_subtopic, (key || (Maxdevice > 1)) ? stemp1 : ""); if (state == 3) { svalue[0] = '\0'; @@ -1401,7 +1438,7 @@ void do_cmnd(char *cmnd) start = strrchr(token, '/'); // Skip possible cmnd/sonoff/ preamble if (start) token = start; } - snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s"), SUB_PREFIX, sysCfg.mqtt_topic, token); + snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s"), sysCfg.mqtt_prefix[0], sysCfg.mqtt_topic, token); token = strtok(NULL, ""); snprintf_P(svalue, sizeof(svalue), PSTR("%s"), (token == NULL) ? "" : token); mqttDataCb(stopic, (byte*)svalue, strlen(svalue)); @@ -1413,7 +1450,7 @@ void publish_status(uint8_t payload) uint8_t option = 0; // Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX - option = (!strcmp(SUB_PREFIX,PUB_PREFIX) && (!payload)); + option = (!strcmp(sysCfg.mqtt_prefix[0],sysCfg.mqtt_prefix[1]) && (!payload)); if ((!sysCfg.mqtt_enabled) && (payload == 6)) payload = 99; if ((!hlw_flg) && ((payload == 8) || (payload == 9))) payload = 99; @@ -1452,8 +1489,8 @@ void publish_status(uint8_t payload) } 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(), + snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusNET\":{\"Host\":\"%s\", \"IP\":\"%s\", \"Gateway\":\"%s\", \"Subnetmask\":\"%s\", \"DNSServer\":\"%s\", \"Mac\":\"%s\", \"Webserver\":%d, \"WifiConfig\":%d}}"), + Hostname, WiFi.localIP().toString().c_str(), IPAddress(sysCfg.ip_address[1]).toString().c_str(), IPAddress(sysCfg.ip_address[2]).toString().c_str(), IPAddress(sysCfg.ip_address[3]).toString().c_str(), WiFi.macAddress().c_str(), sysCfg.webserver, sysCfg.sta_config); mqtt_publish_topic_P(option, PSTR("STATUS5"), svalue); } @@ -2020,6 +2057,8 @@ void GPIO_init() } } + if (pin[GPIO_TXD] == 2) Serial.set_tx(2); + analogWriteRange(PWM_RANGE); // Default is 1023 (Arduino.h) analogWriteFreq(PWM_FREQ); // Default is 1000 (core_esp8266_wiring_pwm.c) diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 2c85c8d24..3b6a3b634 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -120,6 +120,7 @@ enum module_t { WION, WEMOS, SONOFF_DEV, + H801, MAXMODULE }; /********************************************************************************************/ @@ -376,6 +377,20 @@ const mytmplt modules[MAXMODULE] PROGMEM = { 0, // GPIO15 0, // GPIO16 GPIO_ADC0 // ADC0 A0 Analog input + }, + { "H801", // Lixada H801 Wifi (ESP8266) + GPIO_KEY1, // GPIO00 E-FW Button + GPIO_LED1, // GPIO01 Green LED + GPIO_TXD, // GPIO02 RX - Pin next to TX on the PCB + GPIO_RXD, // GPIO03 TX - Pin next to GND on the PCB + GPIO_PWM2, // GPIO04 W2 + GPIO_LED2_INV, // GPIO05 Red LED + 0, 0, 0, 0, 0, 0, // Flash connection + GPIO_PWM3, // GPIO12 Blue + GPIO_PWM4, // GPIO13 Green + GPIO_PWM1, // GPIO14 W1 + GPIO_PWM5, // GPIO15 Red + 0, 0 } }; diff --git a/sonoff/support.ino b/sonoff/support.ino index 985e9d0eb..89fa5835f 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -144,6 +144,42 @@ Decoding 14 results } #endif // DEBUG_THEO +/*********************************************************************************************\ + * General +\*********************************************************************************************/ + +boolean parseIPx(char* str, uint16_t len, uint32_t* addr) +{ + uint8_t *part = (uint8_t *)addr; + byte i; + + if (!len) return false; + *addr = 0; + for (i = 0; i <= len; i++) if (*(str +i) == ',') *(str +i) = '.'; + for (i = 0; i < 4; i++) { + part[i] = strtoul(str, NULL, 10); // Convert byte + str = strchr(str, '.'); + if (str == NULL || *str == '\0') break; // No more separators, exit + str++; // Point to next character after separator + } + return (i == 3); +} + +boolean parseIP(uint32_t* addr, const char* str) +{ + uint8_t *part = (uint8_t*)addr; + byte i; + + *addr = 0; + for (i = 0; i < 4; i++) { + part[i] = strtoul(str, NULL, 10); // Convert byte + str = strchr(str, '.'); + if (str == NULL || *str == '\0') break; // No more separators, exit + str++; // Point to next character after separator + } + return (i == 3); +} + /*********************************************************************************************\ * Wifi \*********************************************************************************************/ @@ -285,9 +321,8 @@ void WIFI_begin(uint8_t flag) sysCfg.sta_active ^= 1; } // 3: Current AP if (strlen(sysCfg.sta_ssid[1]) == 0) sysCfg.sta_active = 0; -#ifdef USE_STATIC_IP_ADDRESS - WiFi.config(ipadd, ipgat, ipsub, ipdns); // Set static IP -#endif // USE_STATIC_IP_ADDRESS + if (sysCfg.ip_address[0]) + WiFi.config(sysCfg.ip_address[0], sysCfg.ip_address[1], sysCfg.ip_address[2], sysCfg.ip_address[3]); // Set static IP WiFi.hostname(Hostname); WiFi.begin(sysCfg.sta_ssid[sysCfg.sta_active], sysCfg.sta_pwd[sysCfg.sta_active]); snprintf_P(log, sizeof(log), PSTR("Wifi: Connecting to AP%d %s in mode 11%c as %s..."), @@ -301,6 +336,12 @@ void WIFI_check_ip() _wificounter = WIFI_CHECK_SEC; _wifiretry = WIFI_RETRY_SEC; addLog_P((_wifistatus != WL_CONNECTED) ? LOG_LEVEL_INFO : LOG_LEVEL_DEBUG_MORE, PSTR("Wifi: Connected")); + if (_wifistatus != WL_CONNECTED) { +// addLog_P(LOG_LEVEL_INFO, PSTR("Wifi: Set IP addresses")); + sysCfg.ip_address[1] = (uint32_t)WiFi.gatewayIP(); + sysCfg.ip_address[2] = (uint32_t)WiFi.subnetMask(); + sysCfg.ip_address[3] = (uint32_t)WiFi.dnsIP(); + } _wifistatus = WL_CONNECTED; } else { _wifistatus = WiFi.status(); diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 0e32b81cb..66b898c9f 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -17,11 +17,11 @@ #define SAVE_STATE 1 // [SaveState] Save changed power state to Flash (0 = disable, 1 = enable) // -- Wifi ---------------------------------------- -//#define USE_STATIC_IP_ADDRESS // Enable optional static IP address (Use DHCP by disabling using //) - #define WIFI_IP_ADDRESS 192,168,2,72 // IP address using commas - #define WIFI_GATEWAY 192,168,2,254 // Gateway IP address using commas - #define WIFI_DNS 192,168,2,27 // DNS IP address (might be the same as WIFI_GATEWAY) using commas - #define WIFI_SUBNETMASK 255,255,255,0 // Network mask using commas +#define WIFI_IP_ADDRESS "0.0.0.0" // [IpAddress] Set to 0.0.0.0 for using DHCP or IP address +#define WIFI_GATEWAY "192.168.2.254" // {Gateway] If not using DHCP set Gateway IP address +#define WIFI_SUBNETMASK "255.255.255.0" // [Subnetmask] If not using DHCP set Network mask +#define WIFI_DNS "192.168.2.27" // [DnsServer] If not using DHCP set DNS IP address (might be equal to WIFI_GATEWAY) + #define STA_SSID1 "indebuurt1" // [Ssid1] Wifi SSID #define STA_PASS1 "VnsqrtnrsddbrN" // [Password1] Wifi password #define STA_SSID2 "indebuurt2" // [Ssid2] Optional alternate AP Wifi SSID @@ -59,9 +59,9 @@ #define MQTT_CLIENT_ID "DVES_%06X" // [MqttClient] Also fall back topic using Chip Id = last 6 characters of MAC address -#define SUB_PREFIX "cmnd" // Sonoff devices subscribe to:- SUB_PREFIX/MQTT_TOPIC and SUB_PREFIX/MQTT_GRPTOPIC -#define PUB_PREFIX "stat" // Sonoff devices publish to:- PUB_PREFIX/MQTT_TOPIC -#define PUB_PREFIX2 "tele" // Sonoff devices publish telemetry data to:- PUB_PREFIX2/MQTT_TOPIC/UPTIME, POWER/LIGHT and TIME +#define SUB_PREFIX "cmnd" // [Prefix1] Sonoff devices subscribe to:- SUB_PREFIX/MQTT_TOPIC and SUB_PREFIX/MQTT_GRPTOPIC +#define PUB_PREFIX "stat" // [Prefix2] Sonoff devices publish to:- PUB_PREFIX/MQTT_TOPIC +#define PUB_PREFIX2 "tele" // [Prefix3] Sonoff devices publish telemetry data to:- PUB_PREFIX2/MQTT_TOPIC/UPTIME, POWER/LIGHT and TIME // May be named the same as PUB_PREFIX #define MQTT_TOPIC PROJECT // [Topic] (unique) MQTT device topic #define MQTT_GRPTOPIC "sonoffs" // [GroupTopic] MQTT Group topic @@ -83,14 +83,14 @@ #define DOMOTICZ_UPDATE_TIMER 0 // [DomoticzUpdateTimer] Send relay status (0 = disable, 1 - 3600 seconds) (Optional) // -- HTTP ---------------------------------------- -#define USE_WEBSERVER // Enable web server and wifi manager (+62k code, +4k mem) - Disable by // - #define WEB_SERVER 2 // [WebServer] Web server (0 = Off, 1 = Start as User, 2 = Start as Admin) - #define WEB_PORT 80 // Web server Port for User and Admin mode - #define WEB_USERNAME "admin" // Web server Admin mode user name - #define WEB_PASSWORD "" // [WebPassword] Web server Admin mode Password for WEB_USERNAME (empty string = Disable) - #define FRIENDLY_NAME "Sonoff" // [FriendlyName] Friendlyname up to 32 characters used by webpages and Alexa +#define USE_WEBSERVER // Enable web server and wifi manager (+62k code, +8k mem) - Disable by // + #define WEB_SERVER 2 // [WebServer] Web server (0 = Off, 1 = Start as User, 2 = Start as Admin) + #define WEB_PORT 80 // Web server Port for User and Admin mode + #define WEB_USERNAME "admin" // Web server Admin mode user name + #define WEB_PASSWORD "" // [WebPassword] Web server Admin mode Password for WEB_USERNAME (empty string = Disable) + #define FRIENDLY_NAME "Sonoff" // [FriendlyName] Friendlyname up to 32 characters used by webpages and Alexa #define USE_EMULATION // Enable Belkin WeMo and Hue Bridge emulation for Alexa (+11k code, +2k mem) - #define EMULATION EMUL_NONE // [Emulation] Select Belkin WeMo or Hue Bridge emulation (EMUL_NONE, EMUL_WEMO or EMUL_HUE) + #define EMULATION EMUL_NONE // [Emulation] Select Belkin WeMo or Hue Bridge emulation (EMUL_NONE, EMUL_WEMO or EMUL_HUE) // -- mDNS ---------------------------------------- #define USE_DISCOVERY // Enable mDNS for the following services (+8k code, +0.3k mem) - Disable by // diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index 07ca6db85..60f7afbc0 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -548,22 +548,30 @@ void handleModule() page += line; } page += F("
"); + mytmplt cmodule; memcpy_P(&cmodule, &modules[sysCfg.module], sizeof(cmodule)); + String func = F("var os;function sk(s,g){var o=os.replace(\"value='\"+s+\"'\",\"selected value='\"+s+\"'\");document.getElementById('g'+g).innerHTML=o;}function sl(){var o0=\""); + for (byte j = 0; j < GPIO_SENSOR_END; j++) { + snprintf_P(stemp, sizeof(stemp), sensors[j]); + snprintf_P(line, sizeof(line), PSTR("%s'%d'>%02d %s-2"), + (inModule(j, cmodule.gp.io))?"\");"); for (byte i = 0; i < MAX_GPIO_PIN; i++) { if (cmodule.gp.io[i] == GPIO_USER) { - snprintf_P(line, sizeof(line), PSTR("
GPIO%d %s
"), i, (i==0)?"Button1":(i==1)?"Serial Out":(i==3)?"Serial In":(i==12)?"Relay1":(i==13)?"Led1I":(i==14)?"Sensor":"", i, i); page += line; - for (byte j = 0; j < GPIO_SENSOR_END; j++) { - snprintf_P(stemp, sizeof(stemp), sensors[j]); - snprintf_P(line, sizeof(line), PSTR("%02d %s"), - (j == my_module.gp.io[i])?" selected":(inModule(j, cmodule.gp.io))?" disabled":"", j, j, stemp); - page += line; - } - page += F("
"); + snprintf_P(line, sizeof(line), PSTR("sk(%d,%d);"), my_module.gp.io[i], i); + func += line; } } + func += F("}"); + page.replace("", func); + page.replace("", ""); + page += FPSTR(HTTP_FORM_END); page += FPSTR(HTTP_BTN_CONF); showPage(page); @@ -1285,7 +1293,9 @@ void handleInfo() page += F("Hostname"); page += Hostname; page += F(""); if (static_cast(WiFi.localIP()) != 0) { page += F("IP address"); page += WiFi.localIP().toString(); page += F(""); - page += F("Gateway"); page += WiFi.gatewayIP().toString(); page += F(""); + page += F("Gateway"); page += IPAddress(sysCfg.ip_address[1]).toString(); page += F(""); + page += F("Subnet mask"); page += IPAddress(sysCfg.ip_address[2]).toString(); page += F(""); + page += F("DNS server"); page += IPAddress(sysCfg.ip_address[3]).toString(); page += F(""); page += F("MAC address"); page += WiFi.macAddress(); page += F(""); } if (static_cast(WiFi.softAPIP()) != 0) { diff --git a/sonoff/xdrv_domoticz.ino b/sonoff/xdrv_domoticz.ino index ac2afb508..2a0672b67 100644 --- a/sonoff/xdrv_domoticz.ino +++ b/sonoff/xdrv_domoticz.ino @@ -145,13 +145,13 @@ boolean domoticz_mqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uin if ((pin[GPIO_WS2812] < 99) && (sysCfg.ws_dimmer == nvalue)) return 1; if ((sysCfg.module == SONOFF_LED) && (sysCfg.led_dimmer[i] == nvalue)) return 1; snprintf_P(topicBuf, stopicBuf, PSTR("%s/%s/DIMMER%s"), - SUB_PREFIX, sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp1 : ""); + sysCfg.mqtt_prefix[0], sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp1 : ""); snprintf_P(dataBuf, sdataBuf, PSTR("%d"), nvalue); found = 1; } else { if (((power >> i) &1) == nvalue) return 1; snprintf_P(topicBuf, stopicBuf, PSTR("%s/%s/%s%s"), - SUB_PREFIX, sysCfg.mqtt_topic, sysCfg.mqtt_subtopic, (Maxdevice > 1) ? stemp1 : ""); + sysCfg.mqtt_prefix[0], sysCfg.mqtt_topic, sysCfg.mqtt_subtopic, (Maxdevice > 1) ? stemp1 : ""); snprintf_P(dataBuf, sdataBuf, PSTR("%d"), nvalue); found = 1; } diff --git a/sonoff/xsns_hlw8012.ino b/sonoff/xsns_hlw8012.ino index 980aa0ada..a3aacd994 100644 --- a/sonoff/xsns_hlw8012.ino +++ b/sonoff/xsns_hlw8012.ino @@ -549,7 +549,7 @@ void hlw_mqttPresent() snprintf_P(svalue, sizeof(svalue), PSTR("{\"Time\":\"%s\", "), getDateTime().c_str()); hlw_mqttStat(1, svalue, sizeof(svalue)); -// snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/ENERGY"), PUB_PREFIX2, sysCfg.mqtt_topic); +// snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/ENERGY"), sysCfg.mqtt_prefix[2], sysCfg.mqtt_topic); // mqtt_publish(stopic, svalue); mqtt_publish_topic_P(1, PSTR("ENERGY"), svalue);