Merge remote-tracking branch 'upstream/development' into development

This commit is contained in:
Laurent 2019-02-19 20:15:43 -05:00
commit 4e66dce049
6 changed files with 92 additions and 78 deletions

View File

@ -8,6 +8,7 @@
* Add property LinkCount to state and status 11 message representing number of Wifi Link re-connections * Add property LinkCount to state and status 11 message representing number of Wifi Link re-connections
* Add property MqttCount to status 6 message representing number of Mqtt re-connections * Add property MqttCount to status 6 message representing number of Mqtt re-connections
* Add property Downtime to state and status 11 message representing the duration of wifi connection loss * Add property Downtime to state and status 11 message representing the duration of wifi connection loss
* Fix command WebSend intermittent results (#5273)
* *
* 6.4.1.16 20190211 * 6.4.1.16 20190211
* Initial support for online template change using command Template or GUI Configure Other (#5177) * Initial support for online template change using command Template or GUI Configure Other (#5177)

View File

@ -1306,10 +1306,7 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
restart_flag = 211; restart_flag = 211;
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command , D_JSON_RESET_AND_RESTARTING); snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command , D_JSON_RESET_AND_RESTARTING);
break; break;
case 2: case 2 ... 6:
case 3:
case 4:
case 5:
restart_flag = 210 + payload; restart_flag = 210 + payload;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_RESET "\":\"" D_JSON_ERASE ", " D_JSON_RESET_AND_RESTARTING "\"}")); snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_RESET "\":\"" D_JSON_ERASE ", " D_JSON_RESET_AND_RESTARTING "\"}"));
break; break;
@ -2084,14 +2081,33 @@ void Every250mSeconds(void)
} }
} }
if (restart_flag && (backlog_pointer == backlog_index)) { if (restart_flag && (backlog_pointer == backlog_index)) {
if ((214 == restart_flag) || (215 == restart_flag)) { if ((214 == restart_flag) || (215 == restart_flag) || (216 == restart_flag)) {
char storage[sizeof(Settings.sta_ssid) + sizeof(Settings.sta_pwd)]; char storage[sizeof(Settings.sta_ssid) + sizeof(Settings.sta_pwd)];
char storage_mqtt_host[sizeof(Settings.mqtt_host)];
uint16_t storage_mqtt_port;
char storage_mqtt_user[sizeof(Settings.mqtt_user)];
char storage_mqtt_pwd[sizeof(Settings.mqtt_pwd)];
char storage_mqtt_topic[sizeof(Settings.mqtt_topic)];
memcpy(storage, Settings.sta_ssid, sizeof(storage)); // Backup current SSIDs and Passwords memcpy(storage, Settings.sta_ssid, sizeof(storage)); // Backup current SSIDs and Passwords
if (215 == restart_flag) { if (216 == restart_flag) {
memcpy(storage_mqtt_host, Settings.mqtt_host, sizeof(Settings.mqtt_host));
storage_mqtt_port = Settings.mqtt_port;
memcpy(storage_mqtt_user, Settings.mqtt_user, sizeof(Settings.mqtt_user));
memcpy(storage_mqtt_pwd, Settings.mqtt_pwd, sizeof(Settings.mqtt_pwd));
memcpy(storage_mqtt_topic, Settings.mqtt_topic, sizeof(Settings.mqtt_topic));
}
if ((215 == restart_flag) || (216 == restart_flag)) {
SettingsErase(0); // Erase all flash from program end to end of physical flash SettingsErase(0); // Erase all flash from program end to end of physical flash
} }
SettingsDefault(); SettingsDefault();
memcpy(Settings.sta_ssid, storage, sizeof(storage)); // Restore current SSIDs and Passwords memcpy(Settings.sta_ssid, storage, sizeof(storage)); // Restore current SSIDs and Passwords
if (216 == restart_flag) { // Restore the mqtt host, port, username and password
memcpy(Settings.mqtt_host, storage_mqtt_host, sizeof(Settings.mqtt_host));
Settings.mqtt_port = storage_mqtt_port;
memcpy(Settings.mqtt_user, storage_mqtt_user, sizeof(Settings.mqtt_user));
memcpy(Settings.mqtt_pwd, storage_mqtt_pwd, sizeof(Settings.mqtt_pwd));
memcpy(Settings.mqtt_topic, storage_mqtt_topic, sizeof(Settings.mqtt_topic));
}
restart_flag = 2; restart_flag = 2;
} }
else if (213 == restart_flag) { else if (213 == restart_flag) {

View File

@ -181,20 +181,17 @@ uint32_t UpTime(void)
} }
} }
uint32_t MinutesUptime(void)
{
return (UpTime() / 60);
}
String GetUptime(void) String GetUptime(void)
{ {
return GetDuration(UpTime()); return GetDuration(UpTime());
} }
uint32_t GetMinutesUptime(void) uint32_t MinutesPastMidnight(void)
{
TIME_T ut;
BreakTime(UpTime(), ut);
return (ut.days *1440) + (ut.hour *60) + ut.minute;
}
uint32_t GetMinutesPastMidnight(void)
{ {
uint32_t minutes = 0; uint32_t minutes = 0;
@ -326,6 +323,11 @@ uint32_t RuleToTime(TimeRule r, int yr)
return t; return t;
} }
uint32_t UtcTime(void)
{
return utc_time;
}
uint32_t LocalTime(void) uint32_t LocalTime(void)
{ {
return local_time; return local_time;

View File

@ -2146,23 +2146,22 @@ String UrlEncode(const String& text)
int WebSend(char *buffer) int WebSend(char *buffer)
{ {
/* [sonoff] POWER1 ON --> Sends http://sonoff/cm?cmnd=POWER1 ON // [sonoff] POWER1 ON --> Sends http://sonoff/cm?cmnd=POWER1 ON
* [192.168.178.86:80,admin:joker] POWER1 ON --> Sends http://hostname:80/cm?user=admin&password=joker&cmnd=POWER1 ON // [192.168.178.86:80,admin:joker] POWER1 ON --> Sends http://hostname:80/cm?user=admin&password=joker&cmnd=POWER1 ON
* [sonoff] /any/link/starting/with/a/slash.php?log=123 --> Sends http://sonoff/any/link/starting/with/a/slash.php?log=123 // [sonoff] /any/link/starting/with/a/slash.php?log=123 --> Sends http://sonoff/any/link/starting/with/a/slash.php?log=123
* [sonoff,admin:joker] /any/link/starting/with/a/slash.php?log=123 --> Sends http://sonoff/any/link/starting/with/a/slash.php?log=123 // [sonoff,admin:joker] /any/link/starting/with/a/slash.php?log=123 --> Sends http://sonoff/any/link/starting/with/a/slash.php?log=123
*/
char *host; char *host;
char *port; char *port;
char *user; char *user;
char *password; char *password;
char *command; char *command;
uint16_t nport = 80;
int status = 1; // Wrong parameters int status = 1; // Wrong parameters
// buffer = | [ 192.168.178.86 : 80 , admin : joker ] POWER1 ON | // buffer = | [ 192.168.178.86 : 80 , admin : joker ] POWER1 ON |
host = strtok_r(buffer, "]", &command); // host = | [ 192.168.178.86 : 80 , admin : joker |, command = | POWER1 ON | host = strtok_r(buffer, "]", &command); // host = | [ 192.168.178.86 : 80 , admin : joker |, command = | POWER1 ON |
if (host && command) { if (host && command) {
String url = F("http:"); // url = |http:|
host = Trim(host); // host = |[ 192.168.178.86 : 80 , admin : joker| host = Trim(host); // host = |[ 192.168.178.86 : 80 , admin : joker|
host++; // host = | 192.168.178.86 : 80 , admin : joker| - Skip [ host++; // host = | 192.168.178.86 : 80 , admin : joker| - Skip [
host = strtok_r(host, ",", &user); // host = | 192.168.178.86 : 80 |, user = | admin : joker| host = strtok_r(host, ",", &user); // host = | 192.168.178.86 : 80 |, user = | admin : joker|
@ -2170,66 +2169,62 @@ int WebSend(char *buffer)
host = Trim(host); // host = |192.168.178.86| host = Trim(host); // host = |192.168.178.86|
if (port) { if (port) {
port = Trim(port); // port = |80| port = Trim(port); // port = |80|
nport = atoi(port); url += port; // url = |http:80|
} }
url += F("//"); // url = |http://| or |http:80//|
url += host; // url = |http://192.168.178.86|
if (user) { if (user) {
user = strtok_r(user, ":", &password); // user = | admin |, password = | joker| user = strtok_r(user, ":", &password); // user = | admin |, password = | joker|
user = Trim(user); // user = |admin| user = Trim(user); // user = |admin|
if (password) { password = Trim(password); } // password = |joker| if (password) { password = Trim(password); } // password = |joker|
} }
command = Trim(command); // command = |POWER1 ON| or |/any/link/starting/with/a/slash.php?log=123| command = Trim(command); // command = |POWER1 ON| or |/any/link/starting/with/a/slash.php?log=123|
String nuri = "";
if (command[0] != '/') { if (command[0] != '/') {
nuri = "/cm?"; url += F("/cm?"); // url = |http://192.168.178.86/cm?|
if (user && password) { if (user && password) {
nuri += F("user="); url += F("user="); // url = |http://192.168.178.86/cm?user=|
nuri += user; url += user; // url = |http://192.168.178.86/cm?user=admin|
nuri += F("&password="); url += F("&password="); // url = |http://192.168.178.86/cm?user=admin&password=|
nuri += password; url += password; // url = |http://192.168.178.86/cm?user=admin&password=joker|
nuri += F("&"); url += F("&"); // url = |http://192.168.178.86/cm?user=admin&password=joker&|
} }
nuri += F("cmnd="); url += F("cmnd="); // url = |http://192.168.178.86/cm?cmnd=| or |http://192.168.178.86/cm?user=admin&password=joker&cmnd=|
} }
nuri += command; url += command; // url = |http://192.168.178.86/cm?cmnd=POWER1 ON|
String uri = UrlEncode(nuri);
IPAddress host_ip; //snprintf_P(log_data, sizeof(log_data), PSTR("DBG: Uri |%s|"), url.c_str());
if (WiFi.hostByName(host, host_ip)) {
WiFiClient client;
bool connected = false;
uint8_t retry = 2;
while ((retry > 0) && !connected) {
--retry;
connected = client.connect(host_ip, nport);
if (connected) break;
}
if (connected) {
String url = F("GET ");
url += uri;
url += F(" HTTP/1.1\r\nHost: ");
// url += IPAddress(host_ip).toString();
url += host; // https://tools.ietf.org/html/rfc7230#section-5.4 (#4331)
if (port) {
url += F(":");
url += port;
}
url += F("\r\nConnection: close\r\n\r\n");
//snprintf_P(log_data, sizeof(log_data), PSTR("DBG: Url |%s|"), url.c_str());
//AddLog(LOG_LEVEL_DEBUG); //AddLog(LOG_LEVEL_DEBUG);
client.print(url.c_str()); HTTPClient http;
client.flush(); if (http.begin(UrlEncode(url))) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON|
client.stop(); int http_code = http.GET(); // Start connection and send HTTP header
if (http_code > 0) { // http_code will be negative on error
if (http_code == HTTP_CODE_OK || http_code == HTTP_CODE_MOVED_PERMANENTLY) {
/*
// Return received data to the user - Adds 900+ bytes to the code
String result = http.getString(); // File found at server - may need lot of ram or trigger out of memory!
uint16_t j = 0;
for (uint16_t i = 0; i < result.length(); i++) {
char text = result.charAt(i);
if (text > 31) { // Remove control characters like linefeed
mqtt_data[j] = result.charAt(i);
j++;
if (j == sizeof(mqtt_data) -2) { break; }
}
}
mqtt_data[j] = '\0';
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_WEBSEND));
*/
}
status = 0; // No error - Done status = 0; // No error - Done
} else { } else {
status = 2; // Connection failed status = 2; // Connection failed
} }
http.end();
} else { } else {
status = 3; // Host not found status = 3; // Host not found or connection error
} }
} }
return status; return status;

View File

@ -232,7 +232,7 @@ String GetSun(uint8_t dawn)
return String(stime); return String(stime);
} }
uint16_t GetSunMinutes(uint8_t dawn) uint16_t SunMinutes(uint8_t dawn)
{ {
uint8_t hour[2]; uint8_t hour[2];
uint8_t minute[2]; uint8_t minute[2];

View File

@ -185,11 +185,11 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
} }
snprintf_P(stemp, sizeof(stemp), PSTR("%%TIME%%")); snprintf_P(stemp, sizeof(stemp), PSTR("%%TIME%%"));
if (rule_param.startsWith(stemp)) { if (rule_param.startsWith(stemp)) {
rule_param = String(GetMinutesPastMidnight()); rule_param = String(MinutesPastMidnight());
} }
snprintf_P(stemp, sizeof(stemp), PSTR("%%UPTIME%%")); snprintf_P(stemp, sizeof(stemp), PSTR("%%UPTIME%%"));
if (rule_param.startsWith(stemp)) { if (rule_param.startsWith(stemp)) {
rule_param = String(GetMinutesUptime()); rule_param = String(MinutesUptime());
} }
snprintf_P(stemp, sizeof(stemp), PSTR("%%TIMESTAMP%%")); snprintf_P(stemp, sizeof(stemp), PSTR("%%TIMESTAMP%%"));
if (rule_param.startsWith(stemp)) { if (rule_param.startsWith(stemp)) {
@ -198,11 +198,11 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
#if defined(USE_TIMERS) && defined(USE_SUNRISE) #if defined(USE_TIMERS) && defined(USE_SUNRISE)
snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNRISE%%")); snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNRISE%%"));
if (rule_param.startsWith(stemp)) { if (rule_param.startsWith(stemp)) {
rule_param = String(GetSunMinutes(0)); rule_param = String(SunMinutes(0));
} }
snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNSET%%")); snprintf_P(stemp, sizeof(stemp), PSTR("%%SUNSET%%"));
if (rule_param.startsWith(stemp)) { if (rule_param.startsWith(stemp)) {
rule_param = String(GetSunMinutes(1)); rule_param = String(SunMinutes(1));
} }
#endif // USE_TIMERS and USE_SUNRISE #endif // USE_TIMERS and USE_SUNRISE
rule_param.toUpperCase(); rule_param.toUpperCase();
@ -347,12 +347,12 @@ bool RuleSetProcess(uint8_t rule_set, String &event_saved)
snprintf_P(stemp, sizeof(stemp), PSTR("%%mem%d%%"), i +1); snprintf_P(stemp, sizeof(stemp), PSTR("%%mem%d%%"), i +1);
commands.replace(stemp, Settings.mems[i]); commands.replace(stemp, Settings.mems[i]);
} }
commands.replace(F("%time%"), String(GetMinutesPastMidnight())); commands.replace(F("%time%"), String(MinutesPastMidnight()));
commands.replace(F("%uptime%"), String(GetMinutesUptime())); commands.replace(F("%uptime%"), String(MinutesUptime()));
commands.replace(F("%timestamp%"), GetDateAndTime(DT_LOCAL).c_str()); commands.replace(F("%timestamp%"), GetDateAndTime(DT_LOCAL).c_str());
#if defined(USE_TIMERS) && defined(USE_SUNRISE) #if defined(USE_TIMERS) && defined(USE_SUNRISE)
commands.replace(F("%sunrise%"), String(GetSunMinutes(0))); commands.replace(F("%sunrise%"), String(SunMinutes(0)));
commands.replace(F("%sunset%"), String(GetSunMinutes(1))); commands.replace(F("%sunset%"), String(SunMinutes(1)));
#endif // USE_TIMERS and USE_SUNRISE #endif // USE_TIMERS and USE_SUNRISE
char command[commands.length() +1]; char command[commands.length() +1];
@ -505,8 +505,8 @@ void RulesEvery50ms(void)
json_event[0] = '\0'; json_event[0] = '\0';
switch (i) { switch (i) {
case 0: strncpy_P(json_event, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(json_event)); break; case 0: strncpy_P(json_event, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(json_event)); break;
case 1: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Initialized\":%d}}"), GetMinutesPastMidnight()); break; case 1: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Initialized\":%d}}"), MinutesPastMidnight()); break;
case 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%d}}"), GetMinutesPastMidnight()); break; case 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%d}}"), MinutesPastMidnight()); break;
case 3: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(json_event)); break; case 3: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(json_event)); break;
case 4: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(json_event)); break; case 4: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(json_event)); break;
case 5: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Connected\":1}}"), sizeof(json_event)); break; case 5: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Connected\":1}}"), sizeof(json_event)); break;
@ -549,7 +549,7 @@ void RulesEverySecond(void)
if (RtcTime.valid) { if (RtcTime.valid) {
if ((uptime > 60) && (RtcTime.minute != rules_last_minute)) { // Execute from one minute after restart every minute only once if ((uptime > 60) && (RtcTime.minute != rules_last_minute)) { // Execute from one minute after restart every minute only once
rules_last_minute = RtcTime.minute; rules_last_minute = RtcTime.minute;
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Minute\":%d}}"), GetMinutesPastMidnight()); snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Minute\":%d}}"), MinutesPastMidnight());
RulesProcessEvent(json_event); RulesProcessEvent(json_event);
} }
} }
@ -648,18 +648,18 @@ bool findNextVariableValue(char * &pVarname, double &value)
value = CharToDouble(Settings.mems[index -1]); value = CharToDouble(Settings.mems[index -1]);
} }
} else if (sVarName.equals(F("TIME"))) { } else if (sVarName.equals(F("TIME"))) {
value = GetMinutesPastMidnight(); value = MinutesPastMidnight();
} else if (sVarName.equals(F("UPTIME"))) { } else if (sVarName.equals(F("UPTIME"))) {
value = GetMinutesUptime(); value = MinutesUptime();
} else if (sVarName.equals(F("UTCTIME"))) { } else if (sVarName.equals(F("UTCTIME"))) {
value = UtcTime(); value = UtcTime();
} else if (sVarName.equals(F("LOCALTIME"))) { } else if (sVarName.equals(F("LOCALTIME"))) {
value = LocalTime(); value = LocalTime();
#if defined(USE_TIMERS) && defined(USE_SUNRISE) #if defined(USE_TIMERS) && defined(USE_SUNRISE)
} else if (sVarName.equals(F("SUNRISE"))) { } else if (sVarName.equals(F("SUNRISE"))) {
value = GetSunMinutes(0); value = SunMinutes(0);
} else if (sVarName.equals(F("SUNSET"))) { } else if (sVarName.equals(F("SUNSET"))) {
value = GetSunMinutes(1); value = SunMinutes(1);
#endif #endif
} else { } else {
succeed = false; succeed = false;