mirror of https://github.com/arendst/Tasmota.git
v5.0.7
5.0.7 20170511 * Fix possible exception 28 on empty command * Add command SetOption0 as replacement for SaveState * Add command SetOption1 as replacement for ButtonRestrict * Add command SetOption2 as replacement for Units * Add command SetOption4 as replacement for MqttResponse * Add command SetOption8 as replacement for TempUnit * Add command SetOption10 On|Off to select between Offline or Removing previous retained topic (#417, #436)
This commit is contained in:
parent
32c3a66ead
commit
103c5606ac
|
@ -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.0.6** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
|
||||
Current version is **5.0.7** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
|
||||
|
||||
### **** ATTENTION Version 5.0.x specific information ****
|
||||
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,14 @@
|
|||
/* 5.0.6 20170510
|
||||
* Remove hyphen in case of a single DHT sensor connecetd (#427)
|
||||
/* 5.0.7 20170511
|
||||
* Fix possible exception 28 on empty command
|
||||
* Add command SetOption0 as replacement for SaveState
|
||||
* Add command SetOption1 as replacement for ButtonRestrict
|
||||
* Add command SetOption2 as replacement for Units
|
||||
* Add command SetOption4 as replacement for MqttResponse
|
||||
* Add command SetOption8 as replacement for TempUnit
|
||||
* Add command SetOption10 On|Off to select between Offline or Removing previous retained topic (#417, #436)
|
||||
*
|
||||
* 5.0.6 20170510
|
||||
* Remove hyphen in case of a single DHT sensor connected (#427)
|
||||
* Add command MqttRetry <seconds> to change default MQTT reconnect retry timer from minimal 10 seconds (#429)
|
||||
*
|
||||
* 5.0.5 20170508
|
||||
|
|
|
@ -2,33 +2,36 @@
|
|||
* Config settings
|
||||
\*********************************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
uint32_t savestate : 1;
|
||||
uint32_t button_restrict : 1;
|
||||
uint32_t value_units : 1;
|
||||
uint32_t mqtt_enabled : 1;
|
||||
uint32_t mqtt_response : 1;
|
||||
uint32_t mqtt_power_retain : 1;
|
||||
uint32_t mqtt_button_retain : 1;
|
||||
uint32_t mqtt_switch_retain : 1;
|
||||
uint32_t temperature_conversion : 1;
|
||||
uint32_t mqtt_sensor_retain : 1;
|
||||
uint32_t spare22 : 1;
|
||||
uint32_t spare21 : 1;
|
||||
uint32_t spare20 : 1;
|
||||
uint32_t spare19 : 1;
|
||||
uint32_t spare18 : 1;
|
||||
uint32_t spare17 : 1;
|
||||
uint32_t spare16 : 1;
|
||||
uint32_t spare15 : 1;
|
||||
uint32_t spare14 : 1;
|
||||
uint32_t spare13 : 1;
|
||||
uint32_t spare12 : 1;
|
||||
uint32_t emulation : 2;
|
||||
uint32_t energy_resolution : 3;
|
||||
uint32_t pressure_resolution : 2;
|
||||
uint32_t humidity_resolution : 2;
|
||||
uint32_t temperature_resolution : 2;
|
||||
typedef union { // Restricted by MISRA-C Rule 18.4 but so usefull...
|
||||
uint32_t data; // Allow bit manipulation using SetOption
|
||||
struct {
|
||||
uint32_t savestate : 1; // bit 0
|
||||
uint32_t button_restrict : 1; // bit 1
|
||||
uint32_t value_units : 1; // bit 2
|
||||
uint32_t mqtt_enabled : 1;
|
||||
uint32_t mqtt_response : 1; // bit 4
|
||||
uint32_t mqtt_power_retain : 1;
|
||||
uint32_t mqtt_button_retain : 1;
|
||||
uint32_t mqtt_switch_retain : 1;
|
||||
uint32_t temperature_conversion : 1; // bit 8
|
||||
uint32_t mqtt_sensor_retain : 1;
|
||||
uint32_t mqtt_offline : 1; // bit 10
|
||||
uint32_t spare11 : 1;
|
||||
uint32_t spare12 : 1;
|
||||
uint32_t spare13 : 1;
|
||||
uint32_t spare14 : 1;
|
||||
uint32_t spare15 : 1;
|
||||
uint32_t spare16 : 1;
|
||||
uint32_t spare17 : 1;
|
||||
uint32_t spare18 : 1;
|
||||
uint32_t spare19 : 1;
|
||||
uint32_t spare20 : 1;
|
||||
uint32_t emulation : 2;
|
||||
uint32_t energy_resolution : 3;
|
||||
uint32_t pressure_resolution : 2;
|
||||
uint32_t humidity_resolution : 2;
|
||||
uint32_t temperature_resolution : 2;
|
||||
};
|
||||
} sysBitfield;
|
||||
|
||||
struct SYSCFG {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
* ====================================================
|
||||
*/
|
||||
|
||||
#define VERSION 0x05000600 // 5.0.6
|
||||
#define VERSION 0x05000700 // 5.0.7
|
||||
|
||||
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};
|
||||
|
@ -749,8 +749,12 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf,
|
|||
if (!strcmp(dataBuf, MQTTClient)) {
|
||||
payload = 1;
|
||||
}
|
||||
strlcpy(sysCfg.mqtt_topic, (1 == payload) ? MQTT_TOPIC : dataBuf, sizeof(sysCfg.mqtt_topic));
|
||||
restartflag = 2;
|
||||
strlcpy(stemp1, (1 == payload) ? MQTT_TOPIC : dataBuf, sizeof(stemp1));
|
||||
if (strcmp(stemp1, sysCfg.mqtt_topic)) {
|
||||
mqtt_publish_topic_P(2, PSTR("LWT"), (sysCfg.flag.mqtt_offline) ? "Offline" : "", true); // Offline or remove previous retained topic
|
||||
strlcpy(sysCfg.mqtt_topic, stemp1, sizeof(sysCfg.mqtt_topic));
|
||||
restartflag = 2;
|
||||
}
|
||||
}
|
||||
snprintf_P(svalue, ssvalue, PSTR("{\"Topic\":\"%s\"}"), sysCfg.mqtt_topic);
|
||||
}
|
||||
|
@ -1013,6 +1017,20 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
|
|||
}
|
||||
snprintf_P(svalue, sizeof(svalue), PSTR("{\"SaveData\":\"%s\"}"), (sysCfg.savedata > 1) ? stemp1 : getStateText(sysCfg.savedata));
|
||||
}
|
||||
else if (!strcmp_P(type,PSTR("SETOPTION")) && (index >= 0) && (index <= 10)) {
|
||||
if ((data_len > 0) && (payload >= 0) && (payload <= 1)) {
|
||||
switch (index) {
|
||||
case 0: // savestate
|
||||
case 1: // button_restrict
|
||||
case 2: // value_units
|
||||
case 4: // mqtt_response
|
||||
case 8: // temperature_conversion
|
||||
case 10: // mqtt_offline
|
||||
bitWrite(sysCfg.flag.data, index, payload);
|
||||
}
|
||||
}
|
||||
snprintf_P(svalue, sizeof(svalue), PSTR("{\"SetOption%d\":\"%s\"}"), index, getStateText(bitRead(sysCfg.flag.data, index)));
|
||||
}
|
||||
else if (!strcmp_P(type,PSTR("SAVESTATE"))) {
|
||||
if ((data_len > 0) && (payload >= 0) && (payload <= 1)) {
|
||||
sysCfg.flag.savestate = payload;
|
||||
|
@ -1619,7 +1637,7 @@ void do_cmnd(char *cmnd)
|
|||
token = start +1;
|
||||
}
|
||||
}
|
||||
snprintf_P(stopic, sizeof(stopic), PSTR("/%s"), token);
|
||||
snprintf_P(stopic, sizeof(stopic), PSTR("/%s"), (token == NULL) ? "" : token);
|
||||
token = strtok(NULL, "");
|
||||
snprintf_P(svalue, sizeof(svalue), PSTR("%s"), (token == NULL) ? "" : token);
|
||||
mqttDataCb(stopic, (byte*)svalue, strlen(svalue));
|
||||
|
|
|
@ -278,6 +278,9 @@ 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";
|
||||
|
||||
#define DNS_PORT 53
|
||||
enum http_t {HTTP_OFF, HTTP_USER, HTTP_ADMIN, HTTP_MANAGER};
|
||||
|
||||
|
@ -405,10 +408,10 @@ void showPage(String &page)
|
|||
}
|
||||
page += FPSTR(HTTP_END);
|
||||
|
||||
webServer->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
webServer->sendHeader("Pragma", "no-cache");
|
||||
webServer->sendHeader("Expires", "-1");
|
||||
webServer->send(200, "text/html", page);
|
||||
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);
|
||||
}
|
||||
|
||||
void handleRoot()
|
||||
|
@ -529,10 +532,7 @@ void handleAjax2()
|
|||
page += line;
|
||||
}
|
||||
*/
|
||||
webServer->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
webServer->sendHeader("Pragma", "no-cache");
|
||||
webServer->sendHeader("Expires", "-1");
|
||||
webServer->send(200, "text/plain", page);
|
||||
webServer->send(200, F("text/html"), page);
|
||||
}
|
||||
|
||||
boolean httpUser()
|
||||
|
@ -896,8 +896,8 @@ void handleDownload()
|
|||
char attachment[100];
|
||||
snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_%s.dmp"),
|
||||
sysCfg.friendlyname[0], Version);
|
||||
webServer->sendHeader("Content-Disposition", attachment);
|
||||
webServer->send(200, "application/octet-stream", "");
|
||||
webServer->sendHeader(F("Content-Disposition"), attachment);
|
||||
webServer->send(200, F("application/octet-stream"), "");
|
||||
memcpy(buffer, &sysCfg, sizeof(sysCfg));
|
||||
buffer[0] = CONFIG_FILE_SIGN;
|
||||
buffer[1] = (!CONFIG_FILE_XOR)?0:1;
|
||||
|
@ -916,7 +916,7 @@ void handleSave()
|
|||
}
|
||||
|
||||
char log[LOGSZ +20];
|
||||
char stemp[20];
|
||||
char stemp[TOPSZ];
|
||||
byte what = 0;
|
||||
byte restart;
|
||||
String result = "";
|
||||
|
@ -942,12 +942,16 @@ void handleSave()
|
|||
result += F("<br/>Trying to connect device to network<br/>If it fails reconnect to try again");
|
||||
break;
|
||||
case 2:
|
||||
strlcpy(stemp, (!strlen(webServer->arg("mt").c_str())) ? MQTT_TOPIC : webServer->arg("mt").c_str(), sizeof(stemp));
|
||||
if (strcmp(stemp, sysCfg.mqtt_topic)) {
|
||||
mqtt_publish_topic_P(2, PSTR("LWT"), (sysCfg.flag.mqtt_offline) ? "Offline" : "", true); // Offline or remove previous retained topic
|
||||
}
|
||||
strlcpy(sysCfg.mqtt_topic, stemp, sizeof(sysCfg.mqtt_topic));
|
||||
strlcpy(sysCfg.mqtt_host, (!strlen(webServer->arg("mh").c_str())) ? MQTT_HOST : webServer->arg("mh").c_str(), sizeof(sysCfg.mqtt_host));
|
||||
sysCfg.mqtt_port = (!strlen(webServer->arg("ml").c_str())) ? MQTT_PORT : atoi(webServer->arg("ml").c_str());
|
||||
strlcpy(sysCfg.mqtt_client, (!strlen(webServer->arg("mc").c_str())) ? MQTT_CLIENT_ID : webServer->arg("mc").c_str(), sizeof(sysCfg.mqtt_client));
|
||||
strlcpy(sysCfg.mqtt_user, (!strlen(webServer->arg("mu").c_str())) ? MQTT_USER : (!strcmp(webServer->arg("mu").c_str(),"0")) ? "" : webServer->arg("mu").c_str(), sizeof(sysCfg.mqtt_user));
|
||||
strlcpy(sysCfg.mqtt_pwd, (!strlen(webServer->arg("mp").c_str())) ? MQTT_PASS : (!strcmp(webServer->arg("mp").c_str(),"0")) ? "" : webServer->arg("mp").c_str(), sizeof(sysCfg.mqtt_pwd));
|
||||
strlcpy(sysCfg.mqtt_topic, (!strlen(webServer->arg("mt").c_str())) ? MQTT_TOPIC : webServer->arg("mt").c_str(), sizeof(sysCfg.mqtt_topic));
|
||||
snprintf_P(log, sizeof(log), PSTR("HTTP: MQTT Host %s, Port %d, Client %s, User %s, Password %s, Topic %s"),
|
||||
sysCfg.mqtt_host, sysCfg.mqtt_port, sysCfg.mqtt_client, sysCfg.mqtt_user, sysCfg.mqtt_pwd, sysCfg.mqtt_topic);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
@ -1340,11 +1344,7 @@ void handleCmnd()
|
|||
} else {
|
||||
message = F("Need user=<username>&password=<password>\n");
|
||||
}
|
||||
|
||||
webServer->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
webServer->sendHeader("Pragma", "no-cache");
|
||||
webServer->sendHeader("Expires", "-1");
|
||||
webServer->send(200, "text/plain", message);
|
||||
webServer->send(200, F("text/plain"), message);
|
||||
}
|
||||
|
||||
void handleConsole()
|
||||
|
@ -1418,11 +1418,7 @@ void handleAjax()
|
|||
} while (counter != logidx);
|
||||
}
|
||||
message += F("</l></r>");
|
||||
|
||||
webServer->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
webServer->sendHeader("Pragma", "no-cache");
|
||||
webServer->sendHeader("Expires", "-1");
|
||||
webServer->send(200, "text/xml", message);
|
||||
webServer->send(200, F("text/xml"), message);
|
||||
}
|
||||
|
||||
void handleInfo()
|
||||
|
@ -1572,10 +1568,10 @@ void handleNotFound()
|
|||
message += " " + webServer->argName ( i ) + ": " + webServer->arg ( i ) + "\n";
|
||||
}
|
||||
|
||||
webServer->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
webServer->sendHeader("Pragma", "no-cache");
|
||||
webServer->sendHeader("Expires", "-1");
|
||||
webServer->send(404, "text/plain", message);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1585,8 +1581,8 @@ boolean captivePortal()
|
|||
if ((HTTP_MANAGER == _httpflag) && !isIp(webServer->hostHeader())) {
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Request redirected to captive portal"));
|
||||
|
||||
webServer->sendHeader("Location", String("http://") + webServer->client().localIP().toString(), true);
|
||||
webServer->send(302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
|
||||
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->client().stop(); // Stop is needed because we sent no content length
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -212,7 +212,10 @@ void pollUDP()
|
|||
packetBuffer[len] = 0;
|
||||
}
|
||||
String request = packetBuffer;
|
||||
|
||||
// addLog_P(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet received"));
|
||||
// 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)) {
|
||||
wemo_respondToMSearch();
|
||||
|
@ -354,15 +357,13 @@ void handleUPnPevent()
|
|||
if (request.indexOf("State>0</Binary") > 0) {
|
||||
do_cmnd_power(1, 0);
|
||||
}
|
||||
webServer->send(200, "text/plain", "");
|
||||
webServer->send(200, F("text/plain"), "");
|
||||
}
|
||||
|
||||
void handleUPnPservice()
|
||||
{
|
||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle WeMo event service"));
|
||||
|
||||
String eventservice_xml = FPSTR(WEMO_EVENTSERVICE_XML);
|
||||
webServer->send(200, "text/plain", eventservice_xml);
|
||||
webServer->send_P(200, PSTR("text/plain"), WEMO_EVENTSERVICE_XML);
|
||||
}
|
||||
|
||||
void handleUPnPsetupWemo()
|
||||
|
@ -373,7 +374,7 @@ void handleUPnPsetupWemo()
|
|||
setup_xml.replace("{x1}", sysCfg.friendlyname[0]);
|
||||
setup_xml.replace("{x2}", wemo_UUID());
|
||||
setup_xml.replace("{x3}", wemo_serial());
|
||||
webServer->send(200, "text/xml", setup_xml);
|
||||
webServer->send(200, F("text/xml"), setup_xml);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
@ -393,7 +394,7 @@ void handleUPnPsetupHue()
|
|||
String description_xml = FPSTR(HUE_DESCRIPTION_XML);
|
||||
description_xml.replace("{x1}", WiFi.localIP().toString());
|
||||
description_xml.replace("{x2}", hue_UUID());
|
||||
webServer->send(200, "text/xml", description_xml);
|
||||
webServer->send(200, F("text/xml"), description_xml);
|
||||
}
|
||||
|
||||
void hue_todo(String *path)
|
||||
|
@ -445,7 +446,7 @@ void hue_global_cfg(String *path)
|
|||
hue_config_response(&response);
|
||||
response.replace("{id}", *path);
|
||||
response += "}";
|
||||
webServer->send(200, "application/json", response);
|
||||
webServer->send(200, F("application/json"), response);
|
||||
}
|
||||
|
||||
void hue_auth(String *path)
|
||||
|
@ -453,7 +454,7 @@ void hue_auth(String *path)
|
|||
char response[38];
|
||||
|
||||
snprintf_P(response, sizeof(response), PSTR("[{\"success\":{\"username\":\"%03x\"}}]"), ESP.getChipId());
|
||||
webServer->send(200, "application/json", response);
|
||||
webServer->send(200, F("application/json"), response);
|
||||
}
|
||||
|
||||
void hue_config(String *path)
|
||||
|
@ -463,7 +464,7 @@ void hue_config(String *path)
|
|||
path->remove(0,1); // cut leading / to get <id>
|
||||
hue_config_response(&response);
|
||||
response.replace("{id}", *path);
|
||||
webServer->send(200, "application/json", response);
|
||||
webServer->send(200, F("application/json"), response);
|
||||
}
|
||||
|
||||
void hue_lights(String *path)
|
||||
|
@ -506,7 +507,7 @@ void hue_lights(String *path)
|
|||
}
|
||||
}
|
||||
response += "}";
|
||||
webServer->send(200, "application/json", response);
|
||||
webServer->send(200, F("application/json"), response);
|
||||
}
|
||||
else if (path->endsWith("/state")) { // Got ID/state
|
||||
path->remove(0,8); // Remove /lights/
|
||||
|
@ -582,7 +583,7 @@ void hue_lights(String *path)
|
|||
else {
|
||||
response=FPSTR(HUE_ERROR_JSON);
|
||||
}
|
||||
webServer->send(200, "application/json", response);
|
||||
webServer->send(200, F("application/json"), response);
|
||||
}
|
||||
else if(path->indexOf("/lights/") >= 0) { // Got /lights/ID
|
||||
path->remove(0,8); // Remove /lights/
|
||||
|
@ -603,9 +604,9 @@ void hue_lights(String *path)
|
|||
response.replace("{s}", "0");
|
||||
response.replace("{b}", "0");
|
||||
}
|
||||
webServer->send(200, "application/json", response);
|
||||
webServer->send(200, F("application/json"), response);
|
||||
}
|
||||
else webServer->send(406, "application/json", "{}");
|
||||
else webServer->send(406, F("application/json"), "{}");
|
||||
}
|
||||
|
||||
void handle_hue_api(String *path)
|
||||
|
|
Loading…
Reference in New Issue