2017-01-28 13:41:01 +00:00
|
|
|
/*
|
2017-05-13 12:02:10 +01:00
|
|
|
support.ino - support for Sonoff-Tasmota
|
|
|
|
|
|
|
|
Copyright (C) 2017 Theo Arends
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2017-01-28 13:41:01 +00:00
|
|
|
*/
|
|
|
|
|
2017-02-28 15:01:48 +00:00
|
|
|
/*********************************************************************************************\
|
|
|
|
* Watchdog extension (https://github.com/esp8266/Arduino/issues/1532)
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
Ticker tickerOSWatch;
|
|
|
|
|
|
|
|
#define OSWATCH_RESET_TIME 30
|
|
|
|
|
|
|
|
static unsigned long osw_last_loop;
|
|
|
|
byte osw_flag = 0;
|
|
|
|
|
2017-04-03 15:38:15 +01:00
|
|
|
#ifndef USE_WS2812_DMA // Collides with Neopixelbus but solves exception
|
|
|
|
void osw_osWatch() ICACHE_RAM_ATTR;
|
|
|
|
#endif // USE_WS2812_DMA
|
|
|
|
|
|
|
|
void osw_osWatch()
|
2017-02-28 15:01:48 +00:00
|
|
|
{
|
|
|
|
unsigned long t = millis();
|
|
|
|
unsigned long last_run = abs(t - osw_last_loop);
|
|
|
|
|
|
|
|
#ifdef DEBUG_THEO
|
|
|
|
char log[LOGSZ];
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(log, sizeof(log), PSTR(D_LOG_APPLICATION D_OSWATCH " FreeRam %d, rssi %d, last_run %d"), ESP.getFreeHeap(), WIFI_getRSSIasQuality(WiFi.RSSI()), last_run);
|
2017-02-28 15:01:48 +00:00
|
|
|
addLog(LOG_LEVEL_DEBUG, log);
|
|
|
|
#endif // DEBUG_THEO
|
2017-04-25 17:24:42 +01:00
|
|
|
if (last_run >= (OSWATCH_RESET_TIME * 1000)) {
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_OSWATCH " " D_BLOCKED_LOOP ". " D_RESTARTING));
|
2017-02-28 15:01:48 +00:00
|
|
|
rtcMem.osw_flag = 1;
|
|
|
|
RTC_Save();
|
2017-09-02 13:37:02 +01:00
|
|
|
// ESP.restart(); // normal reboot
|
2017-02-28 15:01:48 +00:00
|
|
|
ESP.reset(); // hard reset
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void osw_init()
|
|
|
|
{
|
|
|
|
osw_flag = rtcMem.osw_flag;
|
|
|
|
rtcMem.osw_flag = 0;
|
|
|
|
osw_last_loop = millis();
|
|
|
|
tickerOSWatch.attach_ms(((OSWATCH_RESET_TIME / 3) * 1000), osw_osWatch);
|
|
|
|
}
|
|
|
|
|
|
|
|
void osw_loop()
|
|
|
|
{
|
|
|
|
osw_last_loop = millis();
|
|
|
|
// while(1) delay(1000); // this will trigger the os watch
|
|
|
|
}
|
|
|
|
|
|
|
|
String getResetReason()
|
|
|
|
{
|
|
|
|
char buff[32];
|
|
|
|
if (osw_flag) {
|
2017-09-02 13:37:02 +01:00
|
|
|
strcpy_P(buff, PSTR(D_BLOCKED_LOOP));
|
2017-02-28 15:01:48 +00:00
|
|
|
return String(buff);
|
|
|
|
} else {
|
|
|
|
return ESP.getResetReason();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_THEO
|
|
|
|
void exception_tst(byte type)
|
|
|
|
{
|
2017-09-02 13:37:02 +01:00
|
|
|
/*
|
2017-02-28 15:01:48 +00:00
|
|
|
Exception (28):
|
|
|
|
epc1=0x4000bf64 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000007 depc=0x00000000
|
|
|
|
|
2017-09-02 13:37:02 +01:00
|
|
|
ctx: cont
|
2017-02-28 15:01:48 +00:00
|
|
|
sp: 3fff1f30 end: 3fff2840 offset: 01a0
|
|
|
|
|
|
|
|
>>>stack>>>
|
2017-03-19 17:19:08 +00:00
|
|
|
3fff20d0: 202c3573 756f7247 2c302070 646e4920
|
|
|
|
3fff20e0: 40236a6e 7954202c 45206570 00454358
|
|
|
|
3fff20f0: 00000010 00000007 00000000 3fff2180
|
|
|
|
3fff2100: 3fff2190 40107bfc 3fff3e4c 3fff22c0
|
|
|
|
3fff2110: 40261934 000000f0 3fff22c0 401004d8
|
|
|
|
3fff2120: 40238fcf 00000050 3fff2100 4021fc10
|
|
|
|
3fff2130: 3fff32bc 4021680c 3ffeade1 4021ff7d
|
|
|
|
3fff2140: 3fff2190 3fff2180 0000000c 7fffffff
|
|
|
|
3fff2150: 00000019 00000000 00000000 3fff21c0
|
|
|
|
3fff2160: 3fff23f3 3ffe8e08 00000000 4021ffb4
|
|
|
|
3fff2170: 3fff2190 3fff2180 0000000c 40201118
|
|
|
|
3fff2180: 3fff21c0 0000003c 3ffef840 00000007
|
|
|
|
3fff2190: 00000000 00000000 00000000 40201128
|
|
|
|
3fff21a0: 3fff23f3 000000f1 3fff23ec 4020fafb
|
|
|
|
3fff21b0: 3fff23f3 3fff21c0 3fff21d0 3fff23f6
|
|
|
|
3fff21c0: 00000000 3fff23fb 4022321b 00000000
|
2017-02-28 15:01:48 +00:00
|
|
|
|
|
|
|
Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
|
|
|
|
Decoding 14 results
|
|
|
|
0x40236a6e: ets_vsnprintf at ?? line ?
|
|
|
|
0x40107bfc: vsnprintf at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/libc_replacements.c line 387
|
|
|
|
0x40261934: bignum_exptmod at ?? line ?
|
|
|
|
0x401004d8: malloc at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266\umm_malloc/umm_malloc.c line 1664
|
|
|
|
0x40238fcf: wifi_station_get_connect_status at ?? line ?
|
|
|
|
0x4021fc10: operator new[](unsigned int) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/abi.cpp line 57
|
|
|
|
0x4021680c: ESP8266WiFiSTAClass::status() at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266WiFi\src/ESP8266WiFiSTA.cpp line 569
|
|
|
|
0x4021ff7d: vsnprintf_P(char*, unsigned int, char const*, __va_list_tag) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/pgmspace.cpp line 146
|
|
|
|
0x4021ffb4: snprintf_P(char*, unsigned int, char const*, ...) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/pgmspace.cpp line 146
|
|
|
|
0x40201118: atol at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_noniso.c line 45
|
|
|
|
0x40201128: atoi at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_noniso.c line 45
|
|
|
|
0x4020fafb: mqttDataCb(char*, unsigned char*, unsigned int) at R:\Arduino\Work-ESP8266\Theo\sonoff\sonoff-4\sonoff/sonoff.ino line 679 (discriminator 1)
|
|
|
|
0x4022321b: pp_attach at ?? line ?
|
|
|
|
|
|
|
|
00:00:08 MQTT: tele/sonoff/INFO3 = {"Started":"Fatal exception:28 flag:2 (EXCEPTION) epc1:0x4000bf64 epc2:0x00000000 epc3:0x00000000 excvaddr:0x00000007 depc:0x00000000"}
|
|
|
|
*/
|
2017-04-25 17:24:42 +01:00
|
|
|
if (1 == type) {
|
2017-02-28 15:01:48 +00:00
|
|
|
char svalue[10];
|
|
|
|
snprintf_P(svalue, sizeof(svalue), PSTR("%s"), 7); // Exception 28 as number in string (7 in excvaddr)
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
14:50:52 osWatch: FreeRam 25896, rssi 68, last_run 0
|
|
|
|
14:51:02 osWatch: FreeRam 25896, rssi 58, last_run 0
|
|
|
|
14:51:03 CMND: exception 2
|
|
|
|
14:51:12 osWatch: FreeRam 25360, rssi 60, last_run 8771
|
|
|
|
14:51:22 osWatch: FreeRam 25360, rssi 62, last_run 18771
|
|
|
|
14:51:32 osWatch: FreeRam 25360, rssi 62, last_run 28771
|
|
|
|
14:51:42 osWatch: FreeRam 25360, rssi 62, last_run 38771
|
|
|
|
14:51:42 osWatch: Warning, loop blocked. Restart now
|
|
|
|
*/
|
2017-04-25 17:24:42 +01:00
|
|
|
if (2 == type) {
|
2017-02-28 15:01:48 +00:00
|
|
|
while(1) delay(1000); // this will trigger the os watch
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // DEBUG_THEO
|
|
|
|
|
2017-03-25 16:24:11 +00:00
|
|
|
/*********************************************************************************************\
|
|
|
|
* General
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2017-09-02 13:37:02 +01:00
|
|
|
char* _dtostrf(double number, unsigned char prec, char *s, bool i18n)
|
|
|
|
{
|
|
|
|
bool negative = false;
|
|
|
|
|
|
|
|
if (isnan(number)) {
|
|
|
|
strcpy(s, "nan");
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
if (isinf(number)) {
|
|
|
|
strcpy(s, "inf");
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
char decimal = '.';
|
|
|
|
if (i18n) {
|
|
|
|
decimal = D_DECIMAL_SEPARATOR[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
char* out = s;
|
|
|
|
|
|
|
|
// Handle negative numbers
|
|
|
|
if (number < 0.0) {
|
|
|
|
negative = true;
|
|
|
|
number = -number;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Round correctly so that print(1.999, 2) prints as "2.00"
|
|
|
|
// I optimized out most of the divisions
|
|
|
|
double rounding = 2.0;
|
|
|
|
for (uint8_t i = 0; i < prec; ++i) {
|
|
|
|
rounding *= 10.0;
|
|
|
|
}
|
|
|
|
rounding = 1.0 / rounding;
|
|
|
|
number += rounding;
|
|
|
|
|
|
|
|
// Figure out how big our number really is
|
|
|
|
double tenpow = 1.0;
|
|
|
|
int digitcount = 1;
|
|
|
|
while (number >= 10.0 * tenpow) {
|
|
|
|
tenpow *= 10.0;
|
|
|
|
digitcount++;
|
|
|
|
}
|
|
|
|
number /= tenpow;
|
|
|
|
|
|
|
|
// Handle negative sign
|
|
|
|
if (negative) {
|
|
|
|
*out++ = '-';
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print the digits, and if necessary, the decimal point
|
|
|
|
digitcount += prec;
|
|
|
|
int8_t digit = 0;
|
|
|
|
while (digitcount-- > 0) {
|
|
|
|
digit = (int8_t)number;
|
|
|
|
if (digit > 9) {
|
|
|
|
digit = 9; // insurance
|
|
|
|
}
|
|
|
|
*out++ = (char)('0' | digit);
|
|
|
|
if ((digitcount == prec) && (prec > 0)) {
|
|
|
|
*out++ = decimal;
|
|
|
|
}
|
|
|
|
number -= digit;
|
|
|
|
number *= 10.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure the string is terminated
|
|
|
|
*out = 0;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* dtostrfd(double number, unsigned char prec, char *s) // Always decimal dot
|
|
|
|
{
|
|
|
|
return _dtostrf(number, prec, s, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* dtostrfi(double number, unsigned char prec, char *s) // Use localized decimal dot
|
|
|
|
{
|
|
|
|
return _dtostrf(number, prec, s, 1);
|
|
|
|
}
|
|
|
|
|
2017-03-25 16:24:11 +00:00
|
|
|
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, '.');
|
2017-04-25 17:24:42 +01:00
|
|
|
if (str == NULL || *str == '\0') {
|
|
|
|
break; // No more separators, exit
|
|
|
|
}
|
2017-03-25 16:24:11 +00:00
|
|
|
str++; // Point to next character after separator
|
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
return (3 == i);
|
2017-03-25 16:24:11 +00:00
|
|
|
}
|
|
|
|
|
2017-06-16 13:33:49 +01:00
|
|
|
void mqttfy(byte option, char* str)
|
|
|
|
{
|
|
|
|
// option 0 = replace by underscore
|
2017-09-02 13:37:02 +01:00
|
|
|
// option 1 = delete character
|
2017-06-16 13:33:49 +01:00
|
|
|
uint16_t i = 0;
|
|
|
|
while (str[i] > 0) {
|
|
|
|
// if ((str[i] == '/') || (str[i] == '+') || (str[i] == '#') || (str[i] == ' ')) {
|
|
|
|
if ((str[i] == '+') || (str[i] == '#') || (str[i] == ' ')) {
|
|
|
|
if (option) {
|
|
|
|
uint16_t j = i;
|
|
|
|
while (str[j] > 0) {
|
|
|
|
str[j] = str[j +1];
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
i--;
|
|
|
|
} else {
|
|
|
|
str[i] = '_';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-30 16:54:19 +01:00
|
|
|
// Function to parse & check if version_str is newer than our currently installed version.
|
|
|
|
bool newerVersion(char* version_str)
|
|
|
|
{
|
|
|
|
uint32_t version = 0;
|
|
|
|
uint8_t i = 0;
|
|
|
|
char *str_ptr;
|
|
|
|
char* version_dup = strdup(version_str); // Duplicate the version_str as strtok_r will modify it.
|
|
|
|
|
|
|
|
if (!version_dup) {
|
|
|
|
return false; // Bail if we can't duplicate. Assume bad.
|
|
|
|
}
|
|
|
|
// Loop through the version string, splitting on '.' seperators.
|
|
|
|
for (char *str = strtok_r(version_dup, ".", &str_ptr); str && i < sizeof(VERSION); str = strtok_r(NULL, ".", &str_ptr), i++) {
|
|
|
|
int field = atoi(str);
|
|
|
|
// The fields in a version string can only range from 0-255.
|
|
|
|
if ((field < 0) || (field > 255)) {
|
|
|
|
free(version_dup);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Shuffle the accumulated bytes across, and add the new byte.
|
|
|
|
version = (version << 8) + field;
|
|
|
|
// Check alpha delimiter after 1.2.3 only
|
|
|
|
if ((2 == i) && isalpha(str[strlen(str)-1])) {
|
|
|
|
field = str[strlen(str)-1] & 0x1f;
|
|
|
|
version = (version << 8) + field;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(version_dup); // We no longer need this.
|
|
|
|
// A version string should have 2-4 fields. e.g. 1.2, 1.2.3, or 1.2.3a (= 1.2.3.1).
|
|
|
|
// If not, then don't consider it a valid version string.
|
|
|
|
if ((i < 2) || (i > sizeof(VERSION))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Keep shifting the parsed version until we hit the maximum number of tokens.
|
|
|
|
// VERSION stores the major number of the version in the most significant byte of the uint32_t.
|
|
|
|
while (i < sizeof(VERSION)) {
|
|
|
|
version <<= 8;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
// Now we should have a fully constructed version number in uint32_t form.
|
|
|
|
return (version > VERSION);
|
|
|
|
}
|
|
|
|
|
2017-09-02 13:37:02 +01:00
|
|
|
char* getPowerDevice(char* dest, uint8_t idx, size_t size, uint8_t option)
|
|
|
|
{
|
|
|
|
char sidx[8];
|
|
|
|
|
|
|
|
strncpy_P(dest, S_RSLT_POWER, size);
|
|
|
|
if ((Maxdevice + option) > 1) {
|
|
|
|
snprintf_P(sidx, sizeof(sidx), PSTR("%d"), idx);
|
|
|
|
strncat(dest, sidx, size);
|
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* getPowerDevice(char* dest, uint8_t idx, size_t size)
|
|
|
|
{
|
|
|
|
return getPowerDevice(dest, idx, size, 0);
|
|
|
|
}
|
|
|
|
|
2017-01-28 13:41:01 +00:00
|
|
|
/*********************************************************************************************\
|
|
|
|
* Wifi
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2017-05-04 12:58:26 +01:00
|
|
|
#define WIFI_CONFIG_SEC 180 // seconds before restart
|
|
|
|
#define WIFI_MANAGER_SEC 180 // seconds before restart
|
2017-01-28 13:41:01 +00:00
|
|
|
#define WIFI_CHECK_SEC 20 // seconds
|
|
|
|
#define WIFI_RETRY_SEC 30 // seconds
|
|
|
|
|
2017-04-25 17:24:42 +01:00
|
|
|
uint8_t _wificounter;
|
|
|
|
uint8_t _wifiretry;
|
|
|
|
uint8_t _wifistatus;
|
|
|
|
uint8_t _wpsresult;
|
|
|
|
uint8_t _wificonfigflag = 0;
|
|
|
|
uint8_t _wifiConfigCounter = 0;
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
int WIFI_getRSSIasQuality(int RSSI)
|
|
|
|
{
|
|
|
|
int quality = 0;
|
|
|
|
|
|
|
|
if (RSSI <= -100) {
|
|
|
|
quality = 0;
|
|
|
|
} else if (RSSI >= -50) {
|
|
|
|
quality = 100;
|
|
|
|
} else {
|
|
|
|
quality = 2 * (RSSI + 100);
|
|
|
|
}
|
|
|
|
return quality;
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean WIFI_configCounter()
|
|
|
|
{
|
2017-04-25 17:24:42 +01:00
|
|
|
if (_wifiConfigCounter) {
|
|
|
|
_wifiConfigCounter = WIFI_MANAGER_SEC;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
return (_wifiConfigCounter);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include "user_interface.h"
|
|
|
|
}
|
|
|
|
|
|
|
|
void WIFI_wps_status_cb(wps_cb_status status);
|
|
|
|
|
|
|
|
void WIFI_wps_status_cb(wps_cb_status status)
|
|
|
|
{
|
|
|
|
char log[LOGSZ];
|
|
|
|
|
|
|
|
/* from user_interface.h:
|
|
|
|
enum wps_cb_status {
|
|
|
|
WPS_CB_ST_SUCCESS = 0,
|
|
|
|
WPS_CB_ST_FAILED,
|
|
|
|
WPS_CB_ST_TIMEOUT,
|
|
|
|
WPS_CB_ST_WEP, // WPS failed because that WEP is not supported
|
|
|
|
WPS_CB_ST_SCAN_ERR, // can not find the target WPS AP
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
|
|
|
|
_wpsresult = status;
|
2017-04-25 17:24:42 +01:00
|
|
|
if (WPS_CB_ST_SUCCESS == _wpsresult) {
|
2017-01-28 13:41:01 +00:00
|
|
|
wifi_wps_disable();
|
|
|
|
} else {
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(log, sizeof(log), PSTR(D_LOG_WIFI D_WPS_FAILED_WITH_STATUS " %d"), _wpsresult);
|
2017-01-28 13:41:01 +00:00
|
|
|
addLog(LOG_LEVEL_DEBUG, log);
|
|
|
|
_wifiConfigCounter = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean WIFI_WPSConfigDone(void)
|
|
|
|
{
|
|
|
|
return (!_wpsresult);
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean WIFI_beginWPSConfig(void)
|
|
|
|
{
|
|
|
|
_wpsresult = 99;
|
2017-04-25 17:24:42 +01:00
|
|
|
if (!wifi_wps_disable()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!wifi_wps_enable(WPS_TYPE_PBC)) {
|
|
|
|
return false; // so far only WPS_TYPE_PBC is supported (SDK 2.0.0)
|
|
|
|
}
|
|
|
|
if (!wifi_set_wps_cb((wps_st_cb_t) &WIFI_wps_status_cb)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!wifi_wps_start()) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WIFI_config(uint8_t type)
|
|
|
|
{
|
|
|
|
if (!_wificonfigflag) {
|
2017-04-25 17:24:42 +01:00
|
|
|
if (WIFI_RETRY == type) {
|
|
|
|
return;
|
|
|
|
}
|
2017-01-29 20:36:12 +00:00
|
|
|
#ifdef USE_EMULATION
|
2017-01-28 13:41:01 +00:00
|
|
|
UDP_Disconnect();
|
2017-01-29 20:36:12 +00:00
|
|
|
#endif // USE_EMULATION
|
2017-01-28 13:41:01 +00:00
|
|
|
WiFi.disconnect(); // Solve possible Wifi hangs
|
|
|
|
_wificonfigflag = type;
|
|
|
|
_wifiConfigCounter = WIFI_CONFIG_SEC; // Allow up to WIFI_CONFIG_SECS seconds for phone to provide ssid/pswd
|
|
|
|
_wificounter = _wifiConfigCounter +5;
|
|
|
|
blinks = 1999;
|
2017-04-25 17:24:42 +01:00
|
|
|
if (WIFI_RESTART == _wificonfigflag) {
|
2017-01-28 13:41:01 +00:00
|
|
|
restartflag = 2;
|
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
else if (WIFI_SMARTCONFIG == _wificonfigflag) {
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_1_SMARTCONFIG D_ACTIVE_FOR_1_MINUTE));
|
2017-01-28 13:41:01 +00:00
|
|
|
WiFi.beginSmartConfig();
|
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
else if (WIFI_WPSCONFIG == _wificonfigflag) {
|
2017-01-28 13:41:01 +00:00
|
|
|
if (WIFI_beginWPSConfig()) {
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_3_WPSCONFIG D_ACTIVE_FOR_1_MINUTE));
|
2017-01-28 13:41:01 +00:00
|
|
|
} else {
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_3_WPSCONFIG D_FAILED_TO_START));
|
2017-01-28 13:41:01 +00:00
|
|
|
_wifiConfigCounter = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef USE_WEBSERVER
|
2017-04-25 17:24:42 +01:00
|
|
|
else if (WIFI_MANAGER == _wificonfigflag) {
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_2_WIFIMANAGER D_ACTIVE_FOR_1_MINUTE));
|
2017-01-28 13:41:01 +00:00
|
|
|
beginWifiManager();
|
|
|
|
}
|
|
|
|
#endif // USE_WEBSERVER
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void WIFI_begin(uint8_t flag)
|
|
|
|
{
|
|
|
|
const char PhyMode[] = " BGN";
|
|
|
|
char log[LOGSZ];
|
|
|
|
|
2017-01-29 20:36:12 +00:00
|
|
|
#ifdef USE_EMULATION
|
2017-01-28 13:41:01 +00:00
|
|
|
UDP_Disconnect();
|
2017-01-29 20:36:12 +00:00
|
|
|
#endif // USE_EMULATION
|
2017-05-10 13:19:36 +01:00
|
|
|
if (!strncmp_P(ESP.getSdkVersion(),PSTR("1.5.3"),5)) {
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, PSTR(D_PATCH_ISSUE_2186));
|
2017-01-28 13:41:01 +00:00
|
|
|
WiFi.mode(WIFI_OFF); // See https://github.com/esp8266/Arduino/issues/2186
|
|
|
|
}
|
|
|
|
WiFi.disconnect();
|
|
|
|
WiFi.mode(WIFI_STA); // Disable AP mode
|
2017-04-25 17:24:42 +01:00
|
|
|
if (sysCfg.sleep) {
|
|
|
|
WiFi.setSleepMode(WIFI_LIGHT_SLEEP); // Allow light sleep during idle times
|
|
|
|
}
|
|
|
|
// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11N) {
|
|
|
|
// WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
|
|
|
// }
|
|
|
|
if (!WiFi.getAutoConnect()) {
|
|
|
|
WiFi.setAutoConnect(true);
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
// WiFi.setAutoReconnect(true);
|
|
|
|
switch (flag) {
|
|
|
|
case 0: // AP1
|
|
|
|
case 1: // AP2
|
|
|
|
sysCfg.sta_active = flag;
|
|
|
|
break;
|
|
|
|
case 2: // Toggle
|
|
|
|
sysCfg.sta_active ^= 1;
|
|
|
|
} // 3: Current AP
|
2017-04-25 17:24:42 +01:00
|
|
|
if (0 == strlen(sysCfg.sta_ssid[1])) {
|
|
|
|
sysCfg.sta_active = 0;
|
|
|
|
}
|
|
|
|
if (sysCfg.ip_address[0]) {
|
2017-03-25 16:24:11 +00:00
|
|
|
WiFi.config(sysCfg.ip_address[0], sysCfg.ip_address[1], sysCfg.ip_address[2], sysCfg.ip_address[3]); // Set static IP
|
2017-04-25 17:24:42 +01:00
|
|
|
}
|
2017-03-16 15:23:11 +00:00
|
|
|
WiFi.hostname(Hostname);
|
2017-01-28 13:41:01 +00:00
|
|
|
WiFi.begin(sysCfg.sta_ssid[sysCfg.sta_active], sysCfg.sta_pwd[sysCfg.sta_active]);
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(log, sizeof(log), PSTR(D_LOG_WIFI D_CONNECTING_TO_AP "%d %s " D_IN_MODE " 11%c " D_AS " %s..."),
|
2017-01-28 13:41:01 +00:00
|
|
|
sysCfg.sta_active +1, sysCfg.sta_ssid[sysCfg.sta_active], PhyMode[WiFi.getPhyMode() & 0x3], Hostname);
|
|
|
|
addLog(LOG_LEVEL_INFO, log);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WIFI_check_ip()
|
|
|
|
{
|
2017-04-25 17:24:42 +01:00
|
|
|
if ((WL_CONNECTED == WiFi.status()) && (static_cast<uint32_t>(WiFi.localIP()) != 0)) {
|
2017-01-28 13:41:01 +00:00
|
|
|
_wificounter = WIFI_CHECK_SEC;
|
|
|
|
_wifiretry = WIFI_RETRY_SEC;
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P((_wifistatus != WL_CONNECTED) ? LOG_LEVEL_INFO : LOG_LEVEL_DEBUG_MORE, S_LOG_WIFI, PSTR(D_CONNECTED));
|
2017-03-25 16:24:11 +00:00
|
|
|
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();
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
_wifistatus = WL_CONNECTED;
|
|
|
|
} else {
|
|
|
|
_wifistatus = WiFi.status();
|
|
|
|
switch (_wifistatus) {
|
|
|
|
case WL_CONNECTED:
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_NO_IP_ADDRESS));
|
2017-01-28 13:41:01 +00:00
|
|
|
_wifistatus = 0;
|
|
|
|
_wifiretry = WIFI_RETRY_SEC;
|
|
|
|
break;
|
|
|
|
case WL_NO_SSID_AVAIL:
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_AP_NOT_REACHED));
|
2017-04-25 17:24:42 +01:00
|
|
|
if (_wifiretry > (WIFI_RETRY_SEC / 2)) {
|
|
|
|
_wifiretry = WIFI_RETRY_SEC / 2;
|
|
|
|
}
|
|
|
|
else if (_wifiretry) {
|
|
|
|
_wifiretry = 0;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
break;
|
|
|
|
case WL_CONNECT_FAILED:
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_WRONG_PASSWORD));
|
2017-04-25 17:24:42 +01:00
|
|
|
if (_wifiretry > (WIFI_RETRY_SEC / 2)) {
|
|
|
|
_wifiretry = WIFI_RETRY_SEC / 2;
|
|
|
|
}
|
|
|
|
else if (_wifiretry) {
|
|
|
|
_wifiretry = 0;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
break;
|
|
|
|
default: // WL_IDLE_STATUS and WL_DISCONNECTED
|
2017-04-25 17:24:42 +01:00
|
|
|
if (!_wifiretry || ((WIFI_RETRY_SEC / 2) == _wifiretry)) {
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_AP_TIMEOUT));
|
2017-01-28 13:41:01 +00:00
|
|
|
} else {
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P(LOG_LEVEL_DEBUG, S_LOG_WIFI, PSTR(D_ATTEMPTING_CONNECTION));
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (_wifiretry) {
|
2017-04-25 17:24:42 +01:00
|
|
|
if (WIFI_RETRY_SEC == _wifiretry) {
|
|
|
|
WIFI_begin(3); // Select default SSID
|
|
|
|
}
|
|
|
|
if ((WIFI_RETRY_SEC / 2) == _wifiretry) {
|
|
|
|
WIFI_begin(2); // Select alternate SSID
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
_wificounter = 1;
|
|
|
|
_wifiretry--;
|
|
|
|
} else {
|
|
|
|
WIFI_config(sysCfg.sta_config);
|
|
|
|
_wificounter = 1;
|
|
|
|
_wifiretry = WIFI_RETRY_SEC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void WIFI_Check(uint8_t param)
|
|
|
|
{
|
|
|
|
char log[LOGSZ];
|
|
|
|
|
|
|
|
_wificounter--;
|
|
|
|
switch (param) {
|
|
|
|
case WIFI_SMARTCONFIG:
|
|
|
|
case WIFI_MANAGER:
|
|
|
|
case WIFI_WPSCONFIG:
|
|
|
|
WIFI_config(param);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (_wifiConfigCounter) {
|
|
|
|
_wifiConfigCounter--;
|
|
|
|
_wificounter = _wifiConfigCounter +5;
|
|
|
|
if (_wifiConfigCounter) {
|
2017-04-25 17:24:42 +01:00
|
|
|
if ((WIFI_SMARTCONFIG == _wificonfigflag) && WiFi.smartConfigDone()) {
|
|
|
|
_wifiConfigCounter = 0;
|
|
|
|
}
|
|
|
|
if ((WIFI_WPSCONFIG == _wificonfigflag) && WIFI_WPSConfigDone()) {
|
|
|
|
_wifiConfigCounter = 0;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
if (!_wifiConfigCounter) {
|
2017-04-25 17:24:42 +01:00
|
|
|
if (strlen(WiFi.SSID().c_str())) {
|
|
|
|
strlcpy(sysCfg.sta_ssid[0], WiFi.SSID().c_str(), sizeof(sysCfg.sta_ssid[0]));
|
|
|
|
}
|
|
|
|
if (strlen(WiFi.psk().c_str())) {
|
|
|
|
strlcpy(sysCfg.sta_pwd[0], WiFi.psk().c_str(), sizeof(sysCfg.sta_pwd[0]));
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
sysCfg.sta_active = 0;
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(log, sizeof(log), PSTR(D_LOG_WIFI D_WCFG_1_SMARTCONFIG D_CMND_SSID "1 %s, " D_CMND_PASSWORD "1 %s"), sysCfg.sta_ssid[0], sysCfg.sta_pwd[0]);
|
2017-01-28 13:41:01 +00:00
|
|
|
addLog(LOG_LEVEL_INFO, log);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!_wifiConfigCounter) {
|
2017-04-25 17:24:42 +01:00
|
|
|
if (WIFI_SMARTCONFIG == _wificonfigflag) {
|
|
|
|
WiFi.stopSmartConfig();
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
restartflag = 2;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (_wificounter <= 0) {
|
2017-09-02 13:37:02 +01:00
|
|
|
addLog_P(LOG_LEVEL_DEBUG_MORE, S_LOG_WIFI, PSTR(D_CHECKING_CONNECTION));
|
2017-01-28 13:41:01 +00:00
|
|
|
_wificounter = WIFI_CHECK_SEC;
|
|
|
|
WIFI_check_ip();
|
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
if ((WL_CONNECTED == WiFi.status()) && (static_cast<uint32_t>(WiFi.localIP()) != 0) && !_wificonfigflag) {
|
2017-01-28 13:41:01 +00:00
|
|
|
#ifdef USE_DISCOVERY
|
|
|
|
if (!mDNSbegun) {
|
|
|
|
mDNSbegun = MDNS.begin(Hostname);
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(log, sizeof(log), PSTR(D_LOG_MDNS "%s"), (mDNSbegun) ? D_INITIALIZED : D_FAILED);
|
2017-01-28 13:41:01 +00:00
|
|
|
addLog(LOG_LEVEL_INFO, log);
|
|
|
|
}
|
|
|
|
#endif // USE_DISCOVERY
|
|
|
|
#ifdef USE_WEBSERVER
|
|
|
|
if (sysCfg.webserver) {
|
|
|
|
startWebserver(sysCfg.webserver, WiFi.localIP());
|
|
|
|
#ifdef USE_DISCOVERY
|
|
|
|
#ifdef WEBSERVER_ADVERTISE
|
|
|
|
MDNS.addService("http", "tcp", 80);
|
2017-09-02 13:37:02 +01:00
|
|
|
#endif // WEBSERVER_ADVERTISE
|
2017-01-28 13:41:01 +00:00
|
|
|
#endif // USE_DISCOVERY
|
|
|
|
} else {
|
|
|
|
stopWebserver();
|
|
|
|
}
|
2017-01-29 20:36:12 +00:00
|
|
|
#ifdef USE_EMULATION
|
2017-05-03 17:19:13 +01:00
|
|
|
if (sysCfg.flag.emulation) {
|
2017-04-25 17:24:42 +01:00
|
|
|
UDP_Connect();
|
|
|
|
}
|
2017-01-29 20:36:12 +00:00
|
|
|
#endif // USE_EMULATION
|
2017-01-28 13:41:01 +00:00
|
|
|
#endif // USE_WEBSERVER
|
|
|
|
} else {
|
2017-01-29 20:36:12 +00:00
|
|
|
#ifdef USE_EMULATION
|
2017-01-28 13:41:01 +00:00
|
|
|
UDP_Disconnect();
|
2017-01-29 20:36:12 +00:00
|
|
|
#endif // USE_EMULATION
|
2017-01-28 13:41:01 +00:00
|
|
|
mDNSbegun = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int WIFI_State()
|
|
|
|
{
|
|
|
|
int state;
|
|
|
|
|
2017-04-25 17:24:42 +01:00
|
|
|
if ((WL_CONNECTED == WiFi.status()) && (static_cast<uint32_t>(WiFi.localIP()) != 0)) {
|
|
|
|
state = WIFI_RESTART;
|
|
|
|
}
|
|
|
|
if (_wificonfigflag) {
|
|
|
|
state = _wificonfigflag;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2017-03-16 15:23:11 +00:00
|
|
|
void WIFI_Connect()
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
|
|
|
WiFi.persistent(false); // Solve possible wifi init errors
|
|
|
|
_wifistatus = 0;
|
|
|
|
_wifiretry = WIFI_RETRY_SEC;
|
|
|
|
_wificounter = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_DISCOVERY
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* mDNS
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
#ifdef MQTT_HOST_DISCOVERY
|
|
|
|
boolean mdns_discoverMQTTServer()
|
|
|
|
{
|
2017-04-25 17:24:42 +01:00
|
|
|
char log[LOGSZ];
|
|
|
|
char ip_str[20];
|
2017-01-28 13:41:01 +00:00
|
|
|
int n;
|
|
|
|
|
2017-04-25 17:24:42 +01:00
|
|
|
if (!mDNSbegun) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
n = MDNS.queryService("mqtt", "tcp"); // Search for mqtt service
|
|
|
|
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(log, sizeof(log), PSTR(D_LOG_MDNS D_QUERY_DONE " %d"), n);
|
2017-01-28 13:41:01 +00:00
|
|
|
addLog(LOG_LEVEL_INFO, log);
|
|
|
|
|
|
|
|
if (n > 0) {
|
|
|
|
// Note: current strategy is to get the first MQTT service (even when many are found)
|
|
|
|
IPtoCharArray(MDNS.IP(0), ip_str, 20);
|
2017-09-02 13:37:02 +01:00
|
|
|
|
|
|
|
snprintf_P(log, sizeof(log), PSTR(D_LOG_MDNS D_MQTT_SERVICE_FOUND " %s, " D_IP_ADDRESS " %s, " D_PORT " %d"),
|
2017-01-28 13:41:01 +00:00
|
|
|
MDNS.hostname(0).c_str(), ip_str, MDNS.port(0));
|
|
|
|
addLog(LOG_LEVEL_INFO, log);
|
|
|
|
|
|
|
|
strlcpy(sysCfg.mqtt_host, ip_str, sizeof(sysCfg.mqtt_host));
|
|
|
|
sysCfg.mqtt_port = MDNS.port(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return n > 0;
|
|
|
|
}
|
|
|
|
#endif // MQTT_HOST_DISCOVERY
|
|
|
|
|
|
|
|
void IPtoCharArray(IPAddress address, char *ip_str, size_t size)
|
|
|
|
{
|
|
|
|
String str = String(address[0]);
|
|
|
|
str += ".";
|
|
|
|
str += String(address[1]);
|
|
|
|
str += ".";
|
|
|
|
str += String(address[2]);
|
|
|
|
str += ".";
|
|
|
|
str += String(address[3]);
|
|
|
|
str.toCharArray(ip_str, size);
|
|
|
|
}
|
|
|
|
#endif // USE_DISCOVERY
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* Basic I2C routines
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
#ifdef USE_I2C
|
|
|
|
#define I2C_RETRY_COUNTER 3
|
|
|
|
|
|
|
|
int32_t i2c_read(uint8_t addr, uint8_t reg, uint8_t size)
|
|
|
|
{
|
|
|
|
byte x = 0;
|
|
|
|
int32_t data = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
Wire.beginTransmission(addr); // start transmission to device
|
|
|
|
Wire.write(reg); // sends register address to read from
|
2017-04-25 17:24:42 +01:00
|
|
|
if (0 == Wire.endTransmission(false)) { // Try to become I2C Master, send data and collect bytes, keep master status for next request...
|
2017-01-28 13:41:01 +00:00
|
|
|
Wire.requestFrom((int)addr, (int)size); // send data n-bytes read
|
2017-04-25 17:24:42 +01:00
|
|
|
if (Wire.available() == size) {
|
2017-01-28 13:41:01 +00:00
|
|
|
for(byte i = 0; i < size; i++) {
|
|
|
|
data <<= 8;
|
|
|
|
data |= Wire.read(); // receive DATA
|
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
x++;
|
|
|
|
} while (Wire.endTransmission(true) != 0 && x <= I2C_RETRY_COUNTER); // end transmission
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t i2c_read8(uint8_t addr, uint8_t reg)
|
|
|
|
{
|
|
|
|
return i2c_read(addr, reg, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t i2c_read16(uint8_t addr, uint8_t reg)
|
|
|
|
{
|
|
|
|
return i2c_read(addr, reg, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
int16_t i2c_readS16(uint8_t addr, uint8_t reg)
|
|
|
|
{
|
|
|
|
return (int16_t)i2c_read(addr, reg, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t i2c_read16_LE(uint8_t addr, uint8_t reg)
|
|
|
|
{
|
|
|
|
uint16_t temp = i2c_read(addr, reg, 2);
|
|
|
|
return (temp >> 8) | (temp << 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
int16_t i2c_readS16_LE(uint8_t addr, uint8_t reg)
|
|
|
|
{
|
|
|
|
return (int16_t)i2c_read16_LE(addr, reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t i2c_read24(uint8_t addr, uint8_t reg)
|
|
|
|
{
|
|
|
|
return i2c_read(addr, reg, 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
void i2c_write8(uint8_t addr, uint8_t reg, uint8_t val)
|
|
|
|
{
|
|
|
|
byte x = I2C_RETRY_COUNTER;
|
|
|
|
|
|
|
|
do {
|
|
|
|
Wire.beginTransmission((uint8_t)addr); // start transmission to device
|
|
|
|
Wire.write(reg); // sends register address to read from
|
|
|
|
Wire.write(val); // write data
|
|
|
|
x--;
|
|
|
|
} while (Wire.endTransmission(true) != 0 && x != 0); // end transmission
|
|
|
|
}
|
|
|
|
|
|
|
|
void i2c_scan(char *devs, unsigned int devs_len)
|
|
|
|
{
|
2017-04-25 17:24:42 +01:00
|
|
|
byte error;
|
|
|
|
byte address;
|
|
|
|
byte any = 0;
|
2017-01-28 13:41:01 +00:00
|
|
|
char tstr[10];
|
|
|
|
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_I2CSCAN_DEVICES_FOUND_AT));
|
2017-01-28 13:41:01 +00:00
|
|
|
for (address = 1; address <= 127; address++) {
|
|
|
|
Wire.beginTransmission(address);
|
|
|
|
error = Wire.endTransmission();
|
2017-04-25 17:24:42 +01:00
|
|
|
if (0 == error) {
|
2017-01-28 13:41:01 +00:00
|
|
|
snprintf_P(tstr, sizeof(tstr), PSTR(" 0x%2x"), address);
|
|
|
|
strncat(devs, tstr, devs_len);
|
|
|
|
any = 1;
|
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
else if (4 == error) {
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_I2CSCAN_UNKNOWN_ERROR_AT " 0x%2x\"}"), address);
|
2017-04-25 17:24:42 +01:00
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
if (any) {
|
|
|
|
strncat(devs, "\"}", devs_len);
|
|
|
|
} else {
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_I2CSCAN_NO_DEVICES_FOUND "\"}"));
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // USE_I2C
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* Real Time Clock
|
|
|
|
*
|
|
|
|
* Sources: Time by Michael Margolis and Paul Stoffregen (https://github.com/PaulStoffregen/Time)
|
|
|
|
* Timezone by Jack Christensen (https://github.com/JChristensen/Timezone)
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include "sntp.h"
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SECS_PER_MIN ((uint32_t)(60UL))
|
|
|
|
#define SECS_PER_HOUR ((uint32_t)(3600UL))
|
|
|
|
#define SECS_PER_DAY ((uint32_t)(SECS_PER_HOUR * 24UL))
|
|
|
|
#define LEAP_YEAR(Y) (((1970+Y)>0) && !((1970+Y)%4) && (((1970+Y)%100) || !((1970+Y)%400)))
|
|
|
|
|
|
|
|
Ticker tickerRTC;
|
|
|
|
|
|
|
|
static const uint8_t monthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // API starts months from 1, this array starts from 0
|
|
|
|
|
2017-04-25 17:24:42 +01:00
|
|
|
uint32_t utctime = 0;
|
|
|
|
uint32_t loctime = 0;
|
|
|
|
uint32_t dsttime = 0;
|
|
|
|
uint32_t stdtime = 0;
|
|
|
|
uint32_t ntptime = 0;
|
|
|
|
uint32_t midnight = 1451602800;
|
2017-05-17 21:49:22 +01:00
|
|
|
uint8_t midnightnow = 0;
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2017-03-08 15:20:45 +00:00
|
|
|
String getBuildDateTime()
|
|
|
|
{
|
2017-07-15 14:07:30 +01:00
|
|
|
// "2017-03-07T11:08:02" - ISO8601:2004
|
2017-03-08 15:20:45 +00:00
|
|
|
char bdt[21];
|
2017-04-25 17:24:42 +01:00
|
|
|
char *str;
|
|
|
|
char *p;
|
|
|
|
char *smonth;
|
2017-03-08 15:20:45 +00:00
|
|
|
char mdate[] = __DATE__; // "Mar 7 2017"
|
2017-04-25 17:24:42 +01:00
|
|
|
int month;
|
|
|
|
int day;
|
|
|
|
int year;
|
2017-09-02 13:37:02 +01:00
|
|
|
|
2017-03-08 15:20:45 +00:00
|
|
|
// sscanf(mdate, "%s %d %d", bdt, &day, &year); // Not implemented in 2.3.0 and probably too many code
|
|
|
|
byte i = 0;
|
|
|
|
for (str = strtok_r(mdate, " ", &p); str && i < 3; str = strtok_r(NULL, " ", &p)) {
|
|
|
|
switch (i++) {
|
|
|
|
case 0: // Month
|
|
|
|
smonth = str;
|
|
|
|
break;
|
|
|
|
case 1: // Day
|
|
|
|
day = atoi(str);
|
|
|
|
break;
|
|
|
|
case 2: // Year
|
|
|
|
year = atoi(str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
month = (strstr(monthNames, smonth) -monthNames) /3 +1;
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(bdt, sizeof(bdt), PSTR("%d" D_YEAR_MONTH_SEPARATOR "%02d" D_MONTH_DAY_SEPARATOR "%02d" D_DATE_TIME_SEPARATOR "%s"), year, month, day, __TIME__);
|
2017-03-08 15:20:45 +00:00
|
|
|
return String(bdt);
|
|
|
|
}
|
|
|
|
|
|
|
|
String getDateTime()
|
|
|
|
{
|
2017-07-15 14:07:30 +01:00
|
|
|
// "2017-03-07T11:08:02" - ISO8601:2004
|
2017-03-08 15:20:45 +00:00
|
|
|
char dt[21];
|
2017-09-02 13:37:02 +01:00
|
|
|
|
|
|
|
snprintf_P(dt, sizeof(dt), PSTR("%04d" D_YEAR_MONTH_SEPARATOR "%02d" D_MONTH_DAY_SEPARATOR "%02d" D_DATE_TIME_SEPARATOR "%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"),
|
2017-03-08 15:20:45 +00:00
|
|
|
rtcTime.Year, rtcTime.Month, rtcTime.Day, rtcTime.Hour, rtcTime.Minute, rtcTime.Second);
|
|
|
|
return String(dt);
|
|
|
|
}
|
|
|
|
|
2017-07-15 14:07:30 +01:00
|
|
|
String getUTCDateTime()
|
|
|
|
{
|
|
|
|
// "2017-03-07T11:08:02" - ISO8601:2004
|
|
|
|
char dt[21];
|
|
|
|
|
|
|
|
TIME_T tmpTime;
|
|
|
|
breakTime(utctime, tmpTime);
|
|
|
|
tmpTime.Year += 1970;
|
|
|
|
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(dt, sizeof(dt), PSTR("%04d" D_YEAR_MONTH_SEPARATOR "%02d" D_MONTH_DAY_SEPARATOR "%02d" D_DATE_TIME_SEPARATOR "%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"),
|
2017-07-15 14:07:30 +01:00
|
|
|
tmpTime.Year, tmpTime.Month, tmpTime.Day, tmpTime.Hour, tmpTime.Minute, tmpTime.Second);
|
|
|
|
return String(dt);
|
|
|
|
}
|
|
|
|
|
2017-01-28 13:41:01 +00:00
|
|
|
void breakTime(uint32_t timeInput, TIME_T &tm)
|
|
|
|
{
|
|
|
|
// break the given timeInput into time components
|
|
|
|
// this is a more compact version of the C library localtime function
|
|
|
|
// note that year is offset from 1970 !!!
|
|
|
|
|
2017-04-25 17:24:42 +01:00
|
|
|
uint8_t year;
|
|
|
|
uint8_t month;
|
|
|
|
uint8_t monthLength;
|
2017-01-28 13:41:01 +00:00
|
|
|
uint32_t time;
|
|
|
|
unsigned long days;
|
|
|
|
|
|
|
|
time = timeInput;
|
|
|
|
tm.Second = time % 60;
|
|
|
|
time /= 60; // now it is minutes
|
|
|
|
tm.Minute = time % 60;
|
|
|
|
time /= 60; // now it is hours
|
|
|
|
tm.Hour = time % 24;
|
|
|
|
time /= 24; // now it is days
|
|
|
|
tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1
|
|
|
|
|
|
|
|
year = 0;
|
|
|
|
days = 0;
|
|
|
|
while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) {
|
|
|
|
year++;
|
|
|
|
}
|
|
|
|
tm.Year = year; // year is offset from 1970
|
|
|
|
|
|
|
|
days -= LEAP_YEAR(year) ? 366 : 365;
|
|
|
|
time -= days; // now it is days in this year, starting at 0
|
|
|
|
tm.DayOfYear = time;
|
|
|
|
|
|
|
|
days = 0;
|
|
|
|
month = 0;
|
|
|
|
monthLength = 0;
|
|
|
|
for (month = 0; month < 12; month++) {
|
2017-04-25 17:24:42 +01:00
|
|
|
if (1 == month) { // february
|
2017-01-28 13:41:01 +00:00
|
|
|
if (LEAP_YEAR(year)) {
|
|
|
|
monthLength = 29;
|
|
|
|
} else {
|
|
|
|
monthLength = 28;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
monthLength = monthDays[month];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (time >= monthLength) {
|
|
|
|
time -= monthLength;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strlcpy(tm.MonthName, monthNames + (month *3), 4);
|
|
|
|
tm.Month = month + 1; // jan is month 1
|
|
|
|
tm.Day = time + 1; // day of month
|
|
|
|
tm.Valid = (timeInput > 1451602800); // 2016-01-01
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t makeTime(TIME_T &tm)
|
|
|
|
{
|
|
|
|
// assemble time elements into time_t
|
|
|
|
// note year argument is offset from 1970
|
|
|
|
|
|
|
|
int i;
|
|
|
|
uint32_t seconds;
|
|
|
|
|
|
|
|
// seconds from 1970 till 1 jan 00:00:00 of the given year
|
|
|
|
seconds = tm.Year * (SECS_PER_DAY * 365);
|
|
|
|
for (i = 0; i < tm.Year; i++) {
|
|
|
|
if (LEAP_YEAR(i)) {
|
|
|
|
seconds += SECS_PER_DAY; // add extra days for leap years
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add days for this year, months start from 1
|
|
|
|
for (i = 1; i < tm.Month; i++) {
|
2017-04-25 17:24:42 +01:00
|
|
|
if ((2 == i) && LEAP_YEAR(tm.Year)) {
|
2017-01-28 13:41:01 +00:00
|
|
|
seconds += SECS_PER_DAY * 29;
|
|
|
|
} else {
|
|
|
|
seconds += SECS_PER_DAY * monthDays[i-1]; // monthDay array starts from 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
seconds+= (tm.Day - 1) * SECS_PER_DAY;
|
|
|
|
seconds+= tm.Hour * SECS_PER_HOUR;
|
|
|
|
seconds+= tm.Minute * SECS_PER_MIN;
|
|
|
|
seconds+= tm.Second;
|
|
|
|
return seconds;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t toTime_t(TimeChangeRule r, int yr)
|
|
|
|
{
|
|
|
|
TIME_T tm;
|
|
|
|
uint32_t t;
|
2017-04-25 17:24:42 +01:00
|
|
|
uint8_t m;
|
|
|
|
uint8_t w; // temp copies of r.month and r.week
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
m = r.month;
|
|
|
|
w = r.week;
|
2017-04-25 17:24:42 +01:00
|
|
|
if (0 == w) { // Last week = 0
|
|
|
|
if (++m > 12) { // for "Last", go to the next month
|
|
|
|
m = 1;
|
|
|
|
yr++;
|
|
|
|
}
|
|
|
|
w = 1; // and treat as first week of next month, subtract 7 days later
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tm.Hour = r.hour;
|
|
|
|
tm.Minute = 0;
|
|
|
|
tm.Second = 0;
|
|
|
|
tm.Day = 1;
|
|
|
|
tm.Month = m;
|
|
|
|
tm.Year = yr - 1970;
|
|
|
|
t = makeTime(tm); // First day of the month, or first day of next month for "Last" rules
|
|
|
|
breakTime(t, tm);
|
|
|
|
t += (7 * (w - 1) + (r.dow - tm.Wday + 7) % 7) * SECS_PER_DAY;
|
2017-04-25 17:24:42 +01:00
|
|
|
if (0 == r.week) {
|
|
|
|
t -= 7 * SECS_PER_DAY; //back up a week if this is a "Last" rule
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
String rtc_time(int type)
|
|
|
|
{
|
|
|
|
char stime[25]; // Skip newline
|
|
|
|
|
|
|
|
uint32_t time = utctime;
|
2017-04-25 17:24:42 +01:00
|
|
|
if (1 == type) time = loctime;
|
|
|
|
if (2 == type) time = dsttime;
|
|
|
|
if (3 == type) time = stdtime;
|
2017-01-28 13:41:01 +00:00
|
|
|
snprintf_P(stime, sizeof(stime), PSTR("%s"), sntp_get_real_time(time));
|
|
|
|
return String(stime);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t rtc_loctime()
|
|
|
|
{
|
|
|
|
return loctime;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t rtc_midnight()
|
|
|
|
{
|
|
|
|
return midnight;
|
|
|
|
}
|
|
|
|
|
2017-05-17 21:49:22 +01:00
|
|
|
boolean rtc_midnight_now()
|
|
|
|
{
|
|
|
|
boolean mnflg = midnightnow;
|
|
|
|
if (mnflg) {
|
|
|
|
midnightnow = 0;
|
|
|
|
}
|
|
|
|
return mnflg;
|
|
|
|
}
|
|
|
|
|
2017-01-28 13:41:01 +00:00
|
|
|
void rtc_second()
|
|
|
|
{
|
|
|
|
char log[LOGSZ];
|
|
|
|
byte ntpsync;
|
2017-04-25 17:24:42 +01:00
|
|
|
uint32_t stdoffset;
|
|
|
|
uint32_t dstoffset;
|
2017-01-28 13:41:01 +00:00
|
|
|
TIME_T tmpTime;
|
|
|
|
|
|
|
|
ntpsync = 0;
|
|
|
|
if (rtcTime.Year < 2016) {
|
2017-04-25 17:24:42 +01:00
|
|
|
if (WL_CONNECTED == WiFi.status()) {
|
2017-01-28 13:41:01 +00:00
|
|
|
ntpsync = 1; // Initial NTP sync
|
|
|
|
}
|
|
|
|
} else {
|
2017-04-25 17:24:42 +01:00
|
|
|
if ((1 == rtcTime.Minute) && (1 == rtcTime.Second)) {
|
2017-01-28 13:41:01 +00:00
|
|
|
ntpsync = 1; // Hourly NTP sync at xx:01:01
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ntpsync) {
|
|
|
|
ntptime = sntp_get_current_timestamp();
|
|
|
|
if (ntptime) {
|
|
|
|
utctime = ntptime;
|
|
|
|
breakTime(utctime, tmpTime);
|
|
|
|
rtcTime.Year = tmpTime.Year + 1970;
|
|
|
|
dsttime = toTime_t(myDST, rtcTime.Year);
|
|
|
|
stdtime = toTime_t(mySTD, rtcTime.Year);
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(log, sizeof(log), PSTR(D_LOG_APPLICATION "(" D_UTC_TIME ") %s"), rtc_time(0).c_str());
|
2017-01-28 13:41:01 +00:00
|
|
|
addLog(LOG_LEVEL_DEBUG, log);
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(log, sizeof(log), PSTR(D_LOG_APPLICATION "(" D_DST_TIME ") %s"), rtc_time(2).c_str());
|
2017-01-28 13:41:01 +00:00
|
|
|
addLog(LOG_LEVEL_DEBUG, log);
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(log, sizeof(log), PSTR(D_LOG_APPLICATION "(" D_STD_TIME ") %s"), rtc_time(3).c_str());
|
2017-01-28 13:41:01 +00:00
|
|
|
addLog(LOG_LEVEL_DEBUG, log);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
utctime++;
|
|
|
|
loctime = utctime;
|
|
|
|
if (loctime > 1451602800) { // 2016-01-01
|
2017-04-25 17:24:42 +01:00
|
|
|
if (99 == sysCfg.timezone) {
|
2017-01-28 13:41:01 +00:00
|
|
|
dstoffset = myDST.offset * SECS_PER_MIN;
|
|
|
|
stdoffset = mySTD.offset * SECS_PER_MIN;
|
|
|
|
if ((utctime >= (dsttime - stdoffset)) && (utctime < (stdtime - dstoffset))) {
|
|
|
|
loctime += dstoffset; // Daylight Saving Time
|
|
|
|
} else {
|
|
|
|
loctime += stdoffset; // Standard Time
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
loctime += sysCfg.timezone * SECS_PER_HOUR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
breakTime(loctime, rtcTime);
|
|
|
|
if (!rtcTime.Hour && !rtcTime.Minute && !rtcTime.Second && rtcTime.Valid) {
|
|
|
|
midnight = loctime;
|
2017-05-17 21:49:22 +01:00
|
|
|
midnightnow = 1;
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
rtcTime.Year += 1970;
|
|
|
|
}
|
|
|
|
|
2017-03-16 15:23:11 +00:00
|
|
|
void rtc_init()
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
2017-03-12 17:36:33 +00:00
|
|
|
sntp_setservername(0, sysCfg.ntp_server[0]);
|
|
|
|
sntp_setservername(1, sysCfg.ntp_server[1]);
|
|
|
|
sntp_setservername(2, sysCfg.ntp_server[2]);
|
2017-01-28 13:41:01 +00:00
|
|
|
sntp_stop();
|
|
|
|
sntp_set_timezone(0); // UTC time
|
|
|
|
sntp_init();
|
|
|
|
utctime = 0;
|
|
|
|
breakTime(utctime, rtcTime);
|
|
|
|
tickerRTC.attach(1, rtc_second);
|
|
|
|
}
|
|
|
|
|
2017-05-03 17:19:13 +01:00
|
|
|
/*********************************************************************************************\
|
|
|
|
* Miscellaneous
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
float convertTemp(float c)
|
|
|
|
{
|
|
|
|
float result = c;
|
2017-09-02 13:37:02 +01:00
|
|
|
|
2017-05-03 17:19:13 +01:00
|
|
|
if (!isnan(c) && sysCfg.flag.temperature_conversion) {
|
|
|
|
result = c * 1.8 + 32; // Fahrenheit
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
char tempUnit()
|
|
|
|
{
|
|
|
|
return (sysCfg.flag.temperature_conversion) ? 'F' : 'C';
|
|
|
|
}
|
|
|
|
|
2017-08-18 13:52:57 +01:00
|
|
|
uint16_t getAdc0()
|
|
|
|
{
|
|
|
|
uint16_t alr = 0;
|
|
|
|
for (byte i = 0; i < 32; i++) {
|
|
|
|
alr += analogRead(A0);
|
|
|
|
delay(1);
|
|
|
|
}
|
|
|
|
return alr >> 5;
|
|
|
|
}
|
|
|
|
|
2017-01-28 13:41:01 +00:00
|
|
|
/*********************************************************************************************\
|
|
|
|
* Syslog
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
void syslog(const char *message)
|
|
|
|
{
|
2017-03-05 14:07:30 +00:00
|
|
|
char str[TOPSZ + MESSZ];
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
if (portUDP.beginPacket(sysCfg.syslog_host, sysCfg.syslog_port)) {
|
|
|
|
snprintf_P(str, sizeof(str), PSTR("%s ESP-%s"), Hostname, message);
|
|
|
|
portUDP.write(str);
|
|
|
|
portUDP.endPacket();
|
|
|
|
} else {
|
|
|
|
syslog_level = 0;
|
|
|
|
syslog_timer = SYSLOG_TIMER;
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(str, sizeof(str), PSTR(D_LOG_APPLICATION D_SYSLOG_HOST_NOT_FOUND ". " D_RETRY_IN " %d " D_UNIT_SECOND), SYSLOG_TIMER);
|
2017-01-28 13:41:01 +00:00
|
|
|
addLog(LOG_LEVEL_INFO, str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void addLog(byte loglevel, const char *line)
|
|
|
|
{
|
|
|
|
char mxtime[9];
|
|
|
|
|
2017-09-02 13:37:02 +01:00
|
|
|
snprintf_P(mxtime, sizeof(mxtime), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), rtcTime.Hour, rtcTime.Minute, rtcTime.Second);
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
if (loglevel <= seriallog_level) Serial.printf("%s %s\n", mxtime, line);
|
|
|
|
#ifdef USE_WEBSERVER
|
2017-02-14 13:27:08 +00:00
|
|
|
if (sysCfg.webserver && (loglevel <= sysCfg.weblog_level)) {
|
2017-01-28 13:41:01 +00:00
|
|
|
Log[logidx] = String(mxtime) + " " + String(line);
|
|
|
|
logidx++;
|
2017-04-25 17:24:42 +01:00
|
|
|
if (logidx > MAX_LOG_LINES -1) {
|
|
|
|
logidx = 0;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
#endif // USE_WEBSERVER
|
2017-04-25 17:24:42 +01:00
|
|
|
if ((WL_CONNECTED == WiFi.status()) && (loglevel <= syslog_level)) {
|
|
|
|
syslog(line);
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void addLog_P(byte loglevel, const char *formatP)
|
|
|
|
{
|
2017-03-05 14:07:30 +00:00
|
|
|
char mess[LOGSZ]; // was MESSZ
|
2017-01-28 13:41:01 +00:00
|
|
|
|
|
|
|
snprintf_P(mess, sizeof(mess), formatP);
|
|
|
|
addLog(loglevel, mess);
|
|
|
|
}
|
|
|
|
|
2017-09-02 13:37:02 +01:00
|
|
|
void addLog_P(byte loglevel, const char *formatP, const char *formatP2)
|
|
|
|
{
|
|
|
|
char mess[LOGSZ]; // was MESSZ
|
|
|
|
char mes2[LOGSZ];
|
|
|
|
|
|
|
|
snprintf_P(mess, sizeof(mess), formatP);
|
|
|
|
snprintf_P(mes2, sizeof(mes2), formatP2);
|
|
|
|
strncat(mess, mes2, sizeof(mess));
|
|
|
|
addLog(loglevel, mess);
|
|
|
|
}
|
|
|
|
|
2017-01-28 13:41:01 +00:00
|
|
|
/*********************************************************************************************\
|
|
|
|
*
|
|
|
|
\*********************************************************************************************/
|