2017-01-28 13:41:01 +00:00
|
|
|
/*
|
2017-05-13 12:02:10 +01:00
|
|
|
support.ino - support for Sonoff-Tasmota
|
|
|
|
|
2019-01-01 12:55:01 +00:00
|
|
|
Copyright (C) 2019 Theo Arends
|
2017-05-13 12:02:10 +01:00
|
|
|
|
|
|
|
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
|
|
|
*/
|
|
|
|
|
2018-02-20 15:19:48 +00:00
|
|
|
IPAddress syslog_host_addr; // Syslog host IP address
|
|
|
|
uint32_t syslog_host_hash = 0; // Syslog host name hash
|
2017-09-26 16:50:39 +01:00
|
|
|
|
2017-02-28 15:01:48 +00:00
|
|
|
/*********************************************************************************************\
|
|
|
|
* Watchdog extension (https://github.com/esp8266/Arduino/issues/1532)
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2018-11-20 14:00:24 +00:00
|
|
|
#include <Ticker.h>
|
|
|
|
|
2017-02-28 15:01:48 +00:00
|
|
|
Ticker tickerOSWatch;
|
|
|
|
|
2018-01-13 14:53:02 +00:00
|
|
|
#define OSWATCH_RESET_TIME 120
|
2017-02-28 15:01:48 +00:00
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
static unsigned long oswatch_last_loop_time;
|
2019-01-28 13:08:33 +00:00
|
|
|
uint8_t oswatch_blocked_loop = 0;
|
2017-02-28 15:01:48 +00:00
|
|
|
|
2017-04-03 15:38:15 +01:00
|
|
|
#ifndef USE_WS2812_DMA // Collides with Neopixelbus but solves exception
|
2017-11-19 17:02:03 +00:00
|
|
|
//void OsWatchTicker() ICACHE_RAM_ATTR;
|
2017-04-03 15:38:15 +01:00
|
|
|
#endif // USE_WS2812_DMA
|
|
|
|
|
2018-05-11 14:00:41 +01:00
|
|
|
#ifdef USE_KNX
|
|
|
|
bool knx_started = false;
|
|
|
|
#endif // USE_KNX
|
|
|
|
|
2018-11-14 13:32:09 +00:00
|
|
|
void OsWatchTicker(void)
|
2017-02-28 15:01:48 +00:00
|
|
|
{
|
|
|
|
unsigned long t = millis();
|
2017-10-18 17:22:34 +01:00
|
|
|
unsigned long last_run = abs(t - oswatch_last_loop_time);
|
2017-02-28 15:01:48 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG_THEO
|
2019-03-08 14:15:42 +00:00
|
|
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_OSWATCH " FreeRam %d, rssi %d, last_run %d"), ESP.getFreeHeap(), WifiGetRssiAsQuality(WiFi.RSSI()), last_run);
|
2017-02-28 15:01:48 +00:00
|
|
|
#endif // DEBUG_THEO
|
2017-04-25 17:24:42 +01:00
|
|
|
if (last_run >= (OSWATCH_RESET_TIME * 1000)) {
|
2017-11-17 16:52:31 +00:00
|
|
|
// AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_OSWATCH " " D_BLOCKED_LOOP ". " D_RESTARTING)); // Save iram space
|
2017-10-18 17:22:34 +01:00
|
|
|
RtcSettings.oswatch_blocked_loop = 1;
|
|
|
|
RtcSettingsSave();
|
2017-09-02 13:37:02 +01:00
|
|
|
// ESP.restart(); // normal reboot
|
2017-02-28 15:01:48 +00:00
|
|
|
ESP.reset(); // hard reset
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-14 13:32:09 +00:00
|
|
|
void OsWatchInit(void)
|
2017-02-28 15:01:48 +00:00
|
|
|
{
|
2017-10-18 17:22:34 +01:00
|
|
|
oswatch_blocked_loop = RtcSettings.oswatch_blocked_loop;
|
|
|
|
RtcSettings.oswatch_blocked_loop = 0;
|
|
|
|
oswatch_last_loop_time = millis();
|
|
|
|
tickerOSWatch.attach_ms(((OSWATCH_RESET_TIME / 3) * 1000), OsWatchTicker);
|
2017-02-28 15:01:48 +00:00
|
|
|
}
|
|
|
|
|
2018-11-14 13:32:09 +00:00
|
|
|
void OsWatchLoop(void)
|
2017-02-28 15:01:48 +00:00
|
|
|
{
|
2017-10-18 17:22:34 +01:00
|
|
|
oswatch_last_loop_time = millis();
|
2017-02-28 15:01:48 +00:00
|
|
|
// while(1) delay(1000); // this will trigger the os watch
|
|
|
|
}
|
|
|
|
|
2018-11-14 13:32:09 +00:00
|
|
|
String GetResetReason(void)
|
2017-02-28 15:01:48 +00:00
|
|
|
{
|
|
|
|
char buff[32];
|
2017-10-18 17:22:34 +01:00
|
|
|
if (oswatch_blocked_loop) {
|
2018-01-06 16:34:42 +00:00
|
|
|
strncpy_P(buff, PSTR(D_JSON_BLOCKED_LOOP), sizeof(buff));
|
2017-02-28 15:01:48 +00:00
|
|
|
return String(buff);
|
|
|
|
} else {
|
|
|
|
return ESP.getResetReason();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
bool OsWatchBlockedLoop(void)
|
2018-08-28 10:10:32 +01:00
|
|
|
{
|
|
|
|
return oswatch_blocked_loop;
|
|
|
|
}
|
2017-03-25 16:24:11 +00:00
|
|
|
/*********************************************************************************************\
|
2018-01-30 13:14:55 +00:00
|
|
|
* Miscellaneous
|
2017-03-25 16:24:11 +00:00
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2018-01-30 13:14:55 +00:00
|
|
|
#ifdef ARDUINO_ESP8266_RELEASE_2_3_0
|
|
|
|
// Functions not available in 2.3.0
|
|
|
|
|
|
|
|
// http://clc-wiki.net/wiki/C_standard_library:string.h:memchr
|
|
|
|
void* memchr(const void* ptr, int value, size_t num)
|
|
|
|
{
|
|
|
|
unsigned char *p = (unsigned char*)ptr;
|
|
|
|
while (num--) {
|
|
|
|
if (*p != (unsigned char)value) {
|
|
|
|
p++;
|
|
|
|
} else {
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// http://clc-wiki.net/wiki/C_standard_library:string.h:strspn
|
2018-02-01 15:18:00 +00:00
|
|
|
// Get span until any character in string
|
2018-01-30 13:14:55 +00:00
|
|
|
size_t strcspn(const char *str1, const char *str2)
|
|
|
|
{
|
|
|
|
size_t ret = 0;
|
|
|
|
while (*str1) {
|
2018-02-01 15:18:00 +00:00
|
|
|
if (strchr(str2, *str1)) { // Slow
|
2018-01-30 13:14:55 +00:00
|
|
|
return ret;
|
|
|
|
} else {
|
|
|
|
str1++;
|
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2018-02-01 15:18:00 +00:00
|
|
|
#endif // ARDUINO_ESP8266_RELEASE_2_3_0
|
2018-01-30 13:14:55 +00:00
|
|
|
|
2018-02-01 15:18:00 +00:00
|
|
|
// Get span until single character in string
|
|
|
|
size_t strchrspn(const char *str1, int character)
|
2018-01-30 13:14:55 +00:00
|
|
|
{
|
2018-02-01 15:18:00 +00:00
|
|
|
size_t ret = 0;
|
|
|
|
char *start = (char*)str1;
|
|
|
|
char *end = strchr(str1, character);
|
|
|
|
if (end) ret = end - start;
|
|
|
|
return ret;
|
2018-01-30 13:14:55 +00:00
|
|
|
}
|
|
|
|
|
2018-07-23 05:32:54 +01:00
|
|
|
// Function to return a substring defined by a delimiter at an index
|
|
|
|
char* subStr(char* dest, char* str, const char *delim, int index)
|
|
|
|
{
|
|
|
|
char *act;
|
2018-12-24 17:14:25 +00:00
|
|
|
char *sub = NULL;
|
2018-07-23 05:32:54 +01:00
|
|
|
char *ptr;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Since strtok consumes the first arg, make a copy
|
2018-09-06 18:21:52 +01:00
|
|
|
strncpy(dest, str, strlen(str)+1);
|
2018-07-23 05:32:54 +01:00
|
|
|
for (i = 1, act = dest; i <= index; i++, act = NULL) {
|
|
|
|
sub = strtok_r(act, delim, &ptr);
|
|
|
|
if (sub == NULL) break;
|
|
|
|
}
|
|
|
|
sub = Trim(sub);
|
|
|
|
return sub;
|
|
|
|
}
|
|
|
|
|
Introduce Expression in Rules
Support use an expression as paramter in some rule commands, include Var<x>, Mem<x> and Ruletimer<x>.
Expression is constructed by constants (float number), variables (var<x>, mem<x>, Time, Uptime, Sunrise, Sunset), operators and round brackets.
Currently support 6 operators, order by priority from high to low:
^ (power)
% (modulo)
*, /
+, -
Commands examples:
Var1 3.14 * (MEM1 * (10 + VAR2 ^2) - 100) % 10 + uptime / (2 + MEM2)
Ruletimer4 Time - Sunrise + MEM2/2
2019-02-13 02:46:42 +00:00
|
|
|
double CharToDouble(const char *str)
|
2018-04-05 11:49:43 +01:00
|
|
|
{
|
|
|
|
// simple ascii to double, because atof or strtod are too large
|
|
|
|
char strbuf[24];
|
|
|
|
|
2018-09-02 10:52:24 +01:00
|
|
|
strlcpy(strbuf, str, sizeof(strbuf));
|
2019-03-07 17:18:30 +00:00
|
|
|
char *pt = strbuf;
|
|
|
|
while ((*pt != '\0') && isblank(*pt)) { pt++; } // Trim leading spaces
|
|
|
|
|
|
|
|
signed char sign = 1;
|
|
|
|
if (*pt == '-') { sign = -1; }
|
|
|
|
if (*pt == '-' || *pt=='+') { pt++; } // Skip any sign
|
|
|
|
|
|
|
|
double left = 0;
|
|
|
|
if (*pt != '.') {
|
|
|
|
left = atoi(pt); // Get left part
|
|
|
|
while (isdigit(*pt)) { pt++; } // Skip number
|
|
|
|
}
|
|
|
|
|
2018-04-05 11:49:43 +01:00
|
|
|
double right = 0;
|
2019-03-07 17:18:30 +00:00
|
|
|
if (*pt == '.') {
|
|
|
|
pt++;
|
|
|
|
right = atoi(pt); // Decimal part
|
|
|
|
while (isdigit(*pt)) {
|
|
|
|
pt++;
|
|
|
|
right /= 10.0;
|
2018-04-05 11:49:43 +01:00
|
|
|
}
|
|
|
|
}
|
2019-03-07 17:18:30 +00:00
|
|
|
|
2018-04-17 14:34:18 +01:00
|
|
|
double result = left + right;
|
2019-03-07 17:18:30 +00:00
|
|
|
if (sign < 0) {
|
|
|
|
return -result; // Add negative sign
|
|
|
|
}
|
2018-04-17 14:34:18 +01:00
|
|
|
return result;
|
2018-04-05 11:49:43 +01:00
|
|
|
}
|
|
|
|
|
2018-08-23 15:05:51 +01:00
|
|
|
int TextToInt(char *str)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
uint8_t radix = 10;
|
|
|
|
if ('#' == str[0]) {
|
|
|
|
radix = 16;
|
|
|
|
str++;
|
|
|
|
}
|
|
|
|
return strtol(str, &p, radix);
|
|
|
|
}
|
|
|
|
|
2018-01-20 11:12:39 +00:00
|
|
|
char* dtostrfd(double number, unsigned char prec, char *s)
|
2017-09-02 13:37:02 +01:00
|
|
|
{
|
2018-10-25 13:03:34 +01:00
|
|
|
if ((isnan(number)) || (isinf(number))) { // Fix for JSON output (https://stackoverflow.com/questions/1423081/json-left-out-infinity-and-nan-json-status-in-ecmascript)
|
2018-10-25 09:44:59 +01:00
|
|
|
strcpy(s, "null");
|
|
|
|
return s;
|
|
|
|
} else {
|
|
|
|
return dtostrf(number, 1, prec, s);
|
|
|
|
}
|
2017-09-02 13:37:02 +01:00
|
|
|
}
|
|
|
|
|
2018-03-20 13:31:11 +00:00
|
|
|
char* Unescape(char* buffer, uint16_t* size)
|
|
|
|
{
|
|
|
|
uint8_t* read = (uint8_t*)buffer;
|
|
|
|
uint8_t* write = (uint8_t*)buffer;
|
2019-01-17 16:48:34 +00:00
|
|
|
int16_t start_size = *size;
|
|
|
|
int16_t end_size = *size;
|
2018-03-20 13:31:11 +00:00
|
|
|
uint8_t che = 0;
|
|
|
|
|
2019-01-17 16:48:34 +00:00
|
|
|
// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)buffer, *size);
|
|
|
|
|
2018-03-20 13:31:11 +00:00
|
|
|
while (start_size > 0) {
|
|
|
|
uint8_t ch = *read++;
|
|
|
|
start_size--;
|
|
|
|
if (ch != '\\') {
|
|
|
|
*write++ = ch;
|
|
|
|
} else {
|
|
|
|
if (start_size > 0) {
|
|
|
|
uint8_t chi = *read++;
|
|
|
|
start_size--;
|
|
|
|
end_size--;
|
|
|
|
switch (chi) {
|
|
|
|
case '\\': che = '\\'; break; // 5C Backslash
|
|
|
|
case 'a': che = '\a'; break; // 07 Bell (Alert)
|
|
|
|
case 'b': che = '\b'; break; // 08 Backspace
|
|
|
|
case 'e': che = '\e'; break; // 1B Escape
|
|
|
|
case 'f': che = '\f'; break; // 0C Formfeed
|
|
|
|
case 'n': che = '\n'; break; // 0A Linefeed (Newline)
|
|
|
|
case 'r': che = '\r'; break; // 0D Carriage return
|
2018-03-20 15:28:18 +00:00
|
|
|
case 's': che = ' '; break; // 20 Space
|
2018-03-20 13:31:11 +00:00
|
|
|
case 't': che = '\t'; break; // 09 Horizontal tab
|
|
|
|
case 'v': che = '\v'; break; // 0B Vertical tab
|
2019-01-17 16:48:34 +00:00
|
|
|
case 'x': {
|
|
|
|
uint8_t* start = read;
|
|
|
|
che = (uint8_t)strtol((const char*)read, (char**)&read, 16);
|
|
|
|
start_size -= (uint16_t)(read - start);
|
|
|
|
end_size -= (uint16_t)(read - start);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '"': che = '\"'; break; // 22 Quotation mark
|
2018-03-20 13:31:11 +00:00
|
|
|
// case '?': che = '\?'; break; // 3F Question mark
|
|
|
|
default : {
|
|
|
|
che = chi;
|
|
|
|
*write++ = ch;
|
|
|
|
end_size++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*write++ = che;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*size = end_size;
|
2019-01-17 16:48:34 +00:00
|
|
|
|
|
|
|
// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)buffer, *size);
|
|
|
|
|
2018-03-20 13:31:11 +00:00
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2018-10-14 11:53:11 +01:00
|
|
|
char* RemoveSpace(char* p)
|
|
|
|
{
|
|
|
|
char* write = p;
|
|
|
|
char* read = p;
|
|
|
|
char ch = '.';
|
|
|
|
|
|
|
|
while (ch != '\0') {
|
|
|
|
ch = *read++;
|
|
|
|
if (!isspace(ch)) {
|
|
|
|
*write++ = ch;
|
|
|
|
}
|
|
|
|
}
|
2019-02-23 11:48:39 +00:00
|
|
|
// *write = '\0'; // Removed 20190223 as it buffer overflows on no isspace found - no need either
|
2018-10-14 11:53:11 +01:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2018-03-23 16:20:20 +00:00
|
|
|
char* UpperCase(char* dest, const char* source)
|
|
|
|
{
|
|
|
|
char* write = dest;
|
|
|
|
const char* read = source;
|
|
|
|
char ch = '.';
|
|
|
|
|
|
|
|
while (ch != '\0') {
|
|
|
|
ch = *read++;
|
|
|
|
*write++ = toupper(ch);
|
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* UpperCase_P(char* dest, const char* source)
|
|
|
|
{
|
|
|
|
char* write = dest;
|
|
|
|
const char* read = source;
|
|
|
|
char ch = '.';
|
|
|
|
|
|
|
|
while (ch != '\0') {
|
|
|
|
ch = pgm_read_byte(read++);
|
|
|
|
*write++ = toupper(ch);
|
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2018-05-29 16:24:42 +01:00
|
|
|
char* Trim(char* p)
|
|
|
|
{
|
2018-11-12 11:33:49 +00:00
|
|
|
while ((*p != '\0') && isblank(*p)) { p++; } // Trim leading spaces
|
2018-05-29 16:24:42 +01:00
|
|
|
char* q = p + strlen(p) -1;
|
2018-11-12 11:33:49 +00:00
|
|
|
while ((q >= p) && isblank(*q)) { q--; } // Trim trailing spaces
|
2018-05-29 16:24:42 +01:00
|
|
|
q++;
|
|
|
|
*q = '\0';
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2018-04-20 16:43:20 +01:00
|
|
|
char* NoAlNumToUnderscore(char* dest, const char* source)
|
2018-04-19 20:41:59 +01:00
|
|
|
{
|
|
|
|
char* write = dest;
|
|
|
|
const char* read = source;
|
|
|
|
char ch = '.';
|
|
|
|
|
|
|
|
while (ch != '\0') {
|
|
|
|
ch = *read++;
|
2018-04-20 16:43:20 +01:00
|
|
|
*write++ = (isalnum(ch) || ('\0' == ch)) ? ch : '_';
|
2018-04-19 20:41:59 +01:00
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2018-08-27 13:53:09 +01:00
|
|
|
void SetShortcut(char* str, uint8_t action)
|
|
|
|
{
|
|
|
|
if ('\0' != str[0]) { // There must be at least one character in the buffer
|
|
|
|
str[0] = '0' + action; // SC_CLEAR, SC_DEFAULT, SC_USER
|
|
|
|
str[1] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-27 12:06:22 +01:00
|
|
|
uint8_t Shortcut(const char* str)
|
|
|
|
{
|
|
|
|
uint8_t result = 10;
|
|
|
|
|
|
|
|
if ('\0' == str[1]) { // Only allow single character input for shortcut
|
|
|
|
if (('"' == str[0]) || ('0' == str[0])) {
|
2018-08-27 13:53:09 +01:00
|
|
|
result = SC_CLEAR;
|
2018-08-27 12:06:22 +01:00
|
|
|
} else {
|
2018-08-27 13:53:09 +01:00
|
|
|
result = atoi(str); // 1 = SC_DEFAULT, 2 = SC_USER
|
2018-08-27 12:06:22 +01:00
|
|
|
if (0 == result) {
|
|
|
|
result = 10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
bool ParseIp(uint32_t* addr, const char* str)
|
2017-03-25 16:24:11 +00:00
|
|
|
{
|
|
|
|
uint8_t *part = (uint8_t*)addr;
|
2019-01-28 13:08:33 +00:00
|
|
|
uint8_t i;
|
2017-03-25 16:24:11 +00:00
|
|
|
|
|
|
|
*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
|
|
|
}
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
void MakeValidMqtt(uint8_t option, char* str)
|
2017-06-16 13:33:49 +01:00
|
|
|
{
|
|
|
|
// 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.
|
2017-10-18 17:22:34 +01:00
|
|
|
bool NewerVersion(char* version_str)
|
2017-06-30 16:54:19 +01:00
|
|
|
{
|
|
|
|
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-10-18 17:22:34 +01:00
|
|
|
char* GetPowerDevice(char* dest, uint8_t idx, size_t size, uint8_t option)
|
2017-09-02 13:37:02 +01:00
|
|
|
{
|
|
|
|
char sidx[8];
|
|
|
|
|
2018-06-28 11:25:50 +01:00
|
|
|
strncpy_P(dest, S_RSLT_POWER, size); // POWER
|
2017-10-18 17:22:34 +01:00
|
|
|
if ((devices_present + option) > 1) {
|
2018-06-28 11:25:50 +01:00
|
|
|
snprintf_P(sidx, sizeof(sidx), PSTR("%d"), idx); // x
|
2018-11-22 14:41:30 +00:00
|
|
|
strncat(dest, sidx, size - strlen(dest) -1); // POWERx
|
2017-09-02 13:37:02 +01:00
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
char* GetPowerDevice(char* dest, uint8_t idx, size_t size)
|
2017-09-02 13:37:02 +01:00
|
|
|
{
|
2017-10-18 17:22:34 +01:00
|
|
|
return GetPowerDevice(dest, idx, size, 0);
|
2017-09-02 13:37:02 +01:00
|
|
|
}
|
|
|
|
|
2018-01-30 13:14:55 +00:00
|
|
|
float ConvertTemp(float c)
|
|
|
|
{
|
|
|
|
float result = c;
|
|
|
|
|
|
|
|
if (!isnan(c) && Settings.flag.temperature_conversion) {
|
|
|
|
result = c * 1.8 + 32; // Fahrenheit
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-11-14 13:32:09 +00:00
|
|
|
char TempUnit(void)
|
2018-01-30 13:14:55 +00:00
|
|
|
{
|
|
|
|
return (Settings.flag.temperature_conversion) ? 'F' : 'C';
|
|
|
|
}
|
|
|
|
|
2018-11-04 15:55:12 +00:00
|
|
|
float ConvertPressure(float p)
|
2018-11-01 15:36:22 +00:00
|
|
|
{
|
|
|
|
float result = p;
|
|
|
|
|
2018-11-04 15:55:12 +00:00
|
|
|
if (!isnan(p) && Settings.flag.pressure_conversion) {
|
2018-11-01 15:36:22 +00:00
|
|
|
result = p * 0.75006375541921; // mmHg
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-11-14 13:32:09 +00:00
|
|
|
String PressureUnit(void)
|
2018-11-04 15:55:12 +00:00
|
|
|
{
|
|
|
|
return (Settings.flag.pressure_conversion) ? String(D_UNIT_MILLIMETER_MERCURY) : String(D_UNIT_PRESSURE);
|
|
|
|
}
|
|
|
|
|
2018-07-24 17:41:50 +01:00
|
|
|
void SetGlobalValues(float temperature, float humidity)
|
|
|
|
{
|
|
|
|
global_update = uptime;
|
|
|
|
global_temperature = temperature;
|
|
|
|
global_humidity = humidity;
|
|
|
|
}
|
|
|
|
|
2018-11-14 13:32:09 +00:00
|
|
|
void ResetGlobalValues(void)
|
2018-07-24 17:41:50 +01:00
|
|
|
{
|
|
|
|
if ((uptime - global_update) > GLOBAL_VALUES_VALID) { // Reset after 5 minutes
|
|
|
|
global_update = 0;
|
|
|
|
global_temperature = 0;
|
|
|
|
global_humidity = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-30 13:14:55 +00:00
|
|
|
double FastPrecisePow(double a, double b)
|
|
|
|
{
|
|
|
|
// https://martin.ankerl.com/2012/01/25/optimized-approximative-pow-in-c-and-cpp/
|
|
|
|
// calculate approximation with fraction of the exponent
|
|
|
|
int e = (int)b;
|
|
|
|
union {
|
|
|
|
double d;
|
|
|
|
int x[2];
|
|
|
|
} u = { a };
|
|
|
|
u.x[1] = (int)((b - e) * (u.x[1] - 1072632447) + 1072632447);
|
|
|
|
u.x[0] = 0;
|
|
|
|
// exponentiation by squaring with the exponent's integer part
|
|
|
|
// double r = u.d makes everything much slower, not sure why
|
|
|
|
double r = 1.0;
|
|
|
|
while (e) {
|
|
|
|
if (e & 1) {
|
|
|
|
r *= a;
|
|
|
|
}
|
|
|
|
a *= a;
|
|
|
|
e >>= 1;
|
|
|
|
}
|
|
|
|
return r * u.d;
|
|
|
|
}
|
|
|
|
|
2018-09-28 14:48:42 +01:00
|
|
|
uint32_t SqrtInt(uint32_t num)
|
|
|
|
{
|
|
|
|
if (num <= 1) {
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t x = num / 2;
|
|
|
|
uint32_t y;
|
|
|
|
do {
|
|
|
|
y = (x + num / x) / 2;
|
|
|
|
if (y >= x) {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
x = y;
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t RoundSqrtInt(uint32_t num)
|
|
|
|
{
|
|
|
|
uint32_t s = SqrtInt(4 * num);
|
|
|
|
if (s & 1) {
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
return s / 2;
|
|
|
|
}
|
|
|
|
|
2018-01-30 13:14:55 +00:00
|
|
|
char* GetTextIndexed(char* destination, size_t destination_size, uint16_t index, const char* haystack)
|
|
|
|
{
|
|
|
|
// Returns empty string if not found
|
|
|
|
// Returns text of found
|
|
|
|
char* write = destination;
|
|
|
|
const char* read = haystack;
|
|
|
|
|
|
|
|
index++;
|
|
|
|
while (index--) {
|
|
|
|
size_t size = destination_size -1;
|
|
|
|
write = destination;
|
|
|
|
char ch = '.';
|
|
|
|
while ((ch != '\0') && (ch != '|')) {
|
|
|
|
ch = pgm_read_byte(read++);
|
|
|
|
if (size && (ch != '|')) {
|
|
|
|
*write++ = ch;
|
|
|
|
size--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (0 == ch) {
|
|
|
|
if (index) {
|
|
|
|
write = destination;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*write = '\0';
|
|
|
|
return destination;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetCommandCode(char* destination, size_t destination_size, const char* needle, const char* haystack)
|
|
|
|
{
|
|
|
|
// Returns -1 of not found
|
|
|
|
// Returns index and command if found
|
|
|
|
int result = -1;
|
|
|
|
const char* read = haystack;
|
|
|
|
char* write = destination;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
result++;
|
|
|
|
size_t size = destination_size -1;
|
|
|
|
write = destination;
|
|
|
|
char ch = '.';
|
|
|
|
while ((ch != '\0') && (ch != '|')) {
|
|
|
|
ch = pgm_read_byte(read++);
|
|
|
|
if (size && (ch != '|')) {
|
|
|
|
*write++ = ch;
|
|
|
|
size--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*write = '\0';
|
|
|
|
if (!strcasecmp(needle, destination)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (0 == ch) {
|
|
|
|
result = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-05-06 15:07:42 +01:00
|
|
|
int GetStateNumber(char *state_text)
|
|
|
|
{
|
|
|
|
char command[CMDSZ];
|
|
|
|
int state_number = -1;
|
|
|
|
|
2018-09-02 10:11:49 +01:00
|
|
|
if (GetCommandCode(command, sizeof(command), state_text, kOptionOff) >= 0) {
|
2018-05-06 15:07:42 +01:00
|
|
|
state_number = 0;
|
|
|
|
}
|
2018-09-02 10:11:49 +01:00
|
|
|
else if (GetCommandCode(command, sizeof(command), state_text, kOptionOn) >= 0) {
|
2018-05-06 15:07:42 +01:00
|
|
|
state_number = 1;
|
|
|
|
}
|
2018-09-02 10:11:49 +01:00
|
|
|
else if (GetCommandCode(command, sizeof(command), state_text, kOptionToggle) >= 0) {
|
2018-05-06 15:07:42 +01:00
|
|
|
state_number = 2;
|
|
|
|
}
|
|
|
|
else if (GetCommandCode(command, sizeof(command), state_text, kOptionBlink) >= 0) {
|
|
|
|
state_number = 3;
|
|
|
|
}
|
|
|
|
else if (GetCommandCode(command, sizeof(command), state_text, kOptionBlinkOff) >= 0) {
|
|
|
|
state_number = 4;
|
|
|
|
}
|
|
|
|
return state_number;
|
|
|
|
}
|
|
|
|
|
2018-01-30 13:14:55 +00:00
|
|
|
void SetSerialBaudrate(int baudrate)
|
|
|
|
{
|
2018-03-18 12:47:30 +00:00
|
|
|
Settings.baudrate = baudrate / 1200;
|
2018-01-30 13:14:55 +00:00
|
|
|
if (Serial.baudRate() != baudrate) {
|
|
|
|
if (seriallog_level) {
|
2019-03-08 14:15:42 +00:00
|
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_SET_BAUDRATE_TO " %d"), baudrate);
|
2018-01-30 13:14:55 +00:00
|
|
|
}
|
|
|
|
delay(100);
|
|
|
|
Serial.flush();
|
2018-02-03 22:25:05 +00:00
|
|
|
Serial.begin(baudrate, serial_config);
|
2018-01-30 13:14:55 +00:00
|
|
|
delay(10);
|
|
|
|
Serial.println();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-14 13:32:09 +00:00
|
|
|
void ClaimSerial(void)
|
2018-05-09 12:43:22 +01:00
|
|
|
{
|
2019-01-28 13:08:33 +00:00
|
|
|
serial_local = true;
|
2018-05-10 16:21:26 +01:00
|
|
|
AddLog_P(LOG_LEVEL_INFO, PSTR("SNS: Hardware Serial"));
|
|
|
|
SetSeriallog(LOG_LEVEL_NONE);
|
|
|
|
baudrate = Serial.baudRate();
|
|
|
|
Settings.baudrate = baudrate / 1200;
|
2018-05-09 12:43:22 +01:00
|
|
|
}
|
|
|
|
|
2018-10-16 10:21:44 +01:00
|
|
|
void SerialSendRaw(char *codes)
|
2018-09-16 15:09:00 +01:00
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
char stemp[3];
|
|
|
|
uint8_t code;
|
2018-10-16 10:21:44 +01:00
|
|
|
|
|
|
|
int size = strlen(codes);
|
2018-09-16 15:09:00 +01:00
|
|
|
|
|
|
|
while (size > 0) {
|
2019-03-08 18:24:02 +00:00
|
|
|
strlcpy(stemp, codes, sizeof(stemp));
|
2018-09-16 15:09:00 +01:00
|
|
|
code = strtol(stemp, &p, 16);
|
|
|
|
Serial.write(code);
|
|
|
|
size -= 2;
|
|
|
|
codes += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-20 15:19:48 +00:00
|
|
|
uint32_t GetHash(const char *buffer, size_t size)
|
|
|
|
{
|
|
|
|
uint32_t hash = 0;
|
|
|
|
for (uint16_t i = 0; i <= size; i++) {
|
|
|
|
hash += (uint8_t)*buffer++ * (i +1);
|
|
|
|
}
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
2018-05-28 14:52:42 +01:00
|
|
|
void ShowSource(int source)
|
|
|
|
{
|
|
|
|
if ((source > 0) && (source < SRC_MAX)) {
|
|
|
|
char stemp1[20];
|
2019-03-08 14:15:42 +00:00
|
|
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SRC: %s"), GetTextIndexed(stemp1, sizeof(stemp1), source, kCommandSource));
|
2018-05-28 14:52:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-12 10:55:47 +00:00
|
|
|
/*********************************************************************************************\
|
|
|
|
* GPIO Module and Template management
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2019-02-22 11:11:15 +00:00
|
|
|
uint8_t ModuleNr()
|
|
|
|
{
|
|
|
|
// 0 = User module (255)
|
|
|
|
// 1 up = Template module 0 up
|
|
|
|
return (USER_MODULE == Settings.module) ? 0 : Settings.module +1;
|
|
|
|
}
|
|
|
|
|
2019-02-12 10:55:47 +00:00
|
|
|
String AnyModuleName(uint8_t index)
|
|
|
|
{
|
|
|
|
if (USER_MODULE == index) {
|
|
|
|
return String(Settings.user_template.name);
|
|
|
|
} else {
|
|
|
|
return FPSTR(kModules[index].name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
String ModuleName()
|
|
|
|
{
|
|
|
|
return AnyModuleName(Settings.module);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleGpios(myio *gp)
|
|
|
|
{
|
|
|
|
uint8_t *dest = (uint8_t *)gp;
|
|
|
|
memset(dest, GPIO_NONE, sizeof(myio));
|
|
|
|
|
|
|
|
uint8_t src[sizeof(mycfgio)];
|
|
|
|
if (USER_MODULE == Settings.module) {
|
|
|
|
memcpy(&src, &Settings.user_template.gp, sizeof(mycfgio));
|
|
|
|
} else {
|
|
|
|
memcpy_P(&src, &kModules[Settings.module].gp, sizeof(mycfgio));
|
|
|
|
}
|
|
|
|
// 11 85 00 85 85 00 00 00 15 38 85 00 00 81
|
|
|
|
|
|
|
|
// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)&src, sizeof(mycfgio));
|
|
|
|
|
|
|
|
uint8_t j = 0;
|
|
|
|
for (uint8_t i = 0; i < sizeof(mycfgio); i++) {
|
|
|
|
if (6 == i) { j = 9; }
|
|
|
|
if (8 == i) { j = 12; }
|
|
|
|
dest[j] = src[i];
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
// 11 85 00 85 85 00 00 00 00 00 00 00 15 38 85 00 00 81
|
|
|
|
|
|
|
|
// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)gp, sizeof(myio));
|
|
|
|
}
|
|
|
|
|
|
|
|
gpio_flag ModuleFlag()
|
|
|
|
{
|
|
|
|
gpio_flag flag;
|
|
|
|
|
|
|
|
if (USER_MODULE == Settings.module) {
|
|
|
|
flag = Settings.user_template.flag;
|
|
|
|
} else {
|
|
|
|
memcpy_P(&flag, &kModules[Settings.module].flag, sizeof(gpio_flag));
|
|
|
|
}
|
|
|
|
|
|
|
|
return flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleDefault(uint8_t module)
|
|
|
|
{
|
|
|
|
if (USER_MODULE == module) { module = WEMOS; } // Generic
|
|
|
|
Settings.user_template_base = module;
|
|
|
|
memcpy_P(&Settings.user_template, &kModules[module], sizeof(mytmplt));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetModuleType()
|
|
|
|
{
|
|
|
|
my_module_type = (USER_MODULE == Settings.module) ? Settings.user_template_base : Settings.module;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t ValidPin(uint8_t pin, uint8_t gpio)
|
|
|
|
{
|
|
|
|
uint8_t result = gpio;
|
2019-02-16 10:33:29 +00:00
|
|
|
|
|
|
|
if (((pin > 5) && (pin < 9)) || (11 == pin)) {
|
|
|
|
result = GPIO_NONE; // Disable flash pins GPIO6, GPIO7, GPIO8 and GPIO11
|
2019-02-12 10:55:47 +00:00
|
|
|
}
|
2019-02-16 10:33:29 +00:00
|
|
|
if ((WEMOS == Settings.module) && (!Settings.flag3.user_esp8285_enable)) {
|
|
|
|
if ((pin == 9) || (pin == 10)) { result = GPIO_NONE; } // Disable possible flash GPIO9 and GPIO10
|
2019-02-12 10:55:47 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ValidGPIO(uint8_t pin, uint8_t gpio)
|
|
|
|
{
|
2019-02-16 10:33:29 +00:00
|
|
|
return (GPIO_USER == ValidPin(pin, gpio)); // Only allow GPIO_USER pins
|
2019-02-12 10:55:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GetUsedInModule(uint8_t val, uint8_t *arr)
|
|
|
|
{
|
|
|
|
int offset = 0;
|
|
|
|
|
|
|
|
if (!val) { return false; } // None
|
|
|
|
|
|
|
|
if ((val >= GPIO_KEY1) && (val < GPIO_KEY1 + MAX_KEYS)) {
|
|
|
|
offset = (GPIO_KEY1_NP - GPIO_KEY1);
|
|
|
|
}
|
|
|
|
if ((val >= GPIO_KEY1_NP) && (val < GPIO_KEY1_NP + MAX_KEYS)) {
|
|
|
|
offset = -(GPIO_KEY1_NP - GPIO_KEY1);
|
|
|
|
}
|
|
|
|
if ((val >= GPIO_KEY1_INV) && (val < GPIO_KEY1_INV + MAX_KEYS)) {
|
|
|
|
offset = -(GPIO_KEY1_INV - GPIO_KEY1);
|
|
|
|
}
|
|
|
|
if ((val >= GPIO_KEY1_INV_NP) && (val < GPIO_KEY1_INV_NP + MAX_KEYS)) {
|
|
|
|
offset = -(GPIO_KEY1_INV_NP - GPIO_KEY1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((val >= GPIO_SWT1) && (val < GPIO_SWT1 + MAX_SWITCHES)) {
|
|
|
|
offset = (GPIO_SWT1_NP - GPIO_SWT1);
|
|
|
|
}
|
|
|
|
if ((val >= GPIO_SWT1_NP) && (val < GPIO_SWT1_NP + MAX_SWITCHES)) {
|
|
|
|
offset = -(GPIO_SWT1_NP - GPIO_SWT1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((val >= GPIO_REL1) && (val < GPIO_REL1 + MAX_RELAYS)) {
|
|
|
|
offset = (GPIO_REL1_INV - GPIO_REL1);
|
|
|
|
}
|
|
|
|
if ((val >= GPIO_REL1_INV) && (val < GPIO_REL1_INV + MAX_RELAYS)) {
|
|
|
|
offset = -(GPIO_REL1_INV - GPIO_REL1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((val >= GPIO_LED1) && (val < GPIO_LED1 + MAX_LEDS)) {
|
|
|
|
offset = (GPIO_LED1_INV - GPIO_LED1);
|
|
|
|
}
|
|
|
|
if ((val >= GPIO_LED1_INV) && (val < GPIO_LED1_INV + MAX_LEDS)) {
|
|
|
|
offset = -(GPIO_LED1_INV - GPIO_LED1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((val >= GPIO_PWM1) && (val < GPIO_PWM1 + MAX_PWMS)) {
|
|
|
|
offset = (GPIO_PWM1_INV - GPIO_PWM1);
|
|
|
|
}
|
|
|
|
if ((val >= GPIO_PWM1_INV) && (val < GPIO_PWM1_INV + MAX_PWMS)) {
|
|
|
|
offset = -(GPIO_PWM1_INV - GPIO_PWM1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((val >= GPIO_CNTR1) && (val < GPIO_CNTR1 + MAX_COUNTERS)) {
|
|
|
|
offset = (GPIO_CNTR1_NP - GPIO_CNTR1);
|
|
|
|
}
|
|
|
|
if ((val >= GPIO_CNTR1_NP) && (val < GPIO_CNTR1_NP + MAX_COUNTERS)) {
|
|
|
|
offset = -(GPIO_CNTR1_NP - GPIO_CNTR1);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint8_t i = 0; i < MAX_GPIO_PIN; i++) {
|
|
|
|
if (arr[i] == val) { return true; }
|
|
|
|
if (arr[i] == val + offset) { return true; }
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-21 13:31:31 +00:00
|
|
|
bool JsonTemplate(const char* dataBuf)
|
|
|
|
{
|
|
|
|
StaticJsonBuffer<350> jb; // 331 from https://arduinojson.org/v5/assistant/
|
|
|
|
JsonObject& obj = jb.parseObject(dataBuf);
|
|
|
|
if (!obj.success()) { return false; }
|
|
|
|
|
|
|
|
// All parameters are optional allowing for partial changes
|
|
|
|
const char* name = obj[D_JSON_NAME];
|
|
|
|
if (name != nullptr) {
|
|
|
|
strlcpy(Settings.user_template.name, name, sizeof(Settings.user_template.name));
|
|
|
|
}
|
|
|
|
if (obj[D_JSON_GPIO].success()) {
|
|
|
|
for (uint8_t i = 0; i < sizeof(mycfgio); i++) {
|
|
|
|
Settings.user_template.gp.io[i] = obj[D_JSON_GPIO][i] | 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (obj[D_JSON_FLAG].success()) {
|
|
|
|
uint8_t flag = obj[D_JSON_FLAG] | 0;
|
|
|
|
memcpy(&Settings.user_template.flag, &flag, sizeof(gpio_flag));
|
|
|
|
}
|
|
|
|
if (obj[D_JSON_BASE].success()) {
|
|
|
|
uint8_t base = obj[D_JSON_BASE];
|
|
|
|
if ((0 == base) || (base >= MAXMODULE)) { base = 17; } else { base--; }
|
|
|
|
Settings.user_template_base = base; // Default WEMOS
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-12 10:55:47 +00:00
|
|
|
void TemplateJson()
|
|
|
|
{
|
|
|
|
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), Settings.user_template.name);
|
|
|
|
for (uint8_t i = 0; i < sizeof(Settings.user_template.gp); i++) {
|
|
|
|
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s%d"), mqtt_data, (i>0)?",":"", Settings.user_template.gp.io[i]);
|
|
|
|
}
|
|
|
|
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"),
|
|
|
|
mqtt_data, Settings.user_template.flag, Settings.user_template_base +1);
|
|
|
|
}
|
|
|
|
|
2018-08-26 14:42:35 +01:00
|
|
|
/*********************************************************************************************\
|
|
|
|
* Sleep aware time scheduler functions borrowed from ESPEasy
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
long TimeDifference(unsigned long prev, unsigned long next)
|
|
|
|
{
|
|
|
|
// Return the time difference as a signed value, taking into account the timers may overflow.
|
|
|
|
// Returned timediff is between -24.9 days and +24.9 days.
|
|
|
|
// Returned value is positive when "next" is after "prev"
|
|
|
|
long signed_diff = 0;
|
|
|
|
// To cast a value to a signed long, the difference may not exceed half 0xffffffffUL (= 4294967294)
|
|
|
|
const unsigned long half_max_unsigned_long = 2147483647u; // = 2^31 -1
|
|
|
|
if (next >= prev) {
|
|
|
|
const unsigned long diff = next - prev;
|
|
|
|
if (diff <= half_max_unsigned_long) { // Normal situation, just return the difference.
|
|
|
|
signed_diff = static_cast<long>(diff); // Difference is a positive value.
|
|
|
|
} else {
|
|
|
|
// prev has overflow, return a negative difference value
|
|
|
|
signed_diff = static_cast<long>((0xffffffffUL - next) + prev + 1u);
|
|
|
|
signed_diff = -1 * signed_diff;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// next < prev
|
|
|
|
const unsigned long diff = prev - next;
|
|
|
|
if (diff <= half_max_unsigned_long) { // Normal situation, return a negative difference value
|
|
|
|
signed_diff = static_cast<long>(diff);
|
|
|
|
signed_diff = -1 * signed_diff;
|
|
|
|
} else {
|
|
|
|
// next has overflow, return a positive difference value
|
|
|
|
signed_diff = static_cast<long>((0xffffffffUL - prev) + next + 1u);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return signed_diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
long TimePassedSince(unsigned long timestamp)
|
|
|
|
{
|
|
|
|
// Compute the number of milliSeconds passed since timestamp given.
|
|
|
|
// Note: value can be negative if the timestamp has not yet been reached.
|
|
|
|
return TimeDifference(timestamp, millis());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TimeReached(unsigned long timer)
|
|
|
|
{
|
|
|
|
// Check if a certain timeout has been reached.
|
|
|
|
const long passed = TimePassedSince(timer);
|
|
|
|
return (passed >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetNextTimeInterval(unsigned long& timer, const unsigned long step)
|
|
|
|
{
|
|
|
|
timer += step;
|
|
|
|
const long passed = TimePassedSince(timer);
|
|
|
|
if (passed < 0) { return; } // Event has not yet happened, which is fine.
|
|
|
|
if (static_cast<unsigned long>(passed) > step) {
|
|
|
|
// No need to keep running behind, start again.
|
|
|
|
timer = millis() + step;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Try to get in sync again.
|
|
|
|
timer = millis() + (step - passed);
|
2018-05-17 14:36:45 +01:00
|
|
|
}
|
|
|
|
|
2017-01-28 13:41:01 +00:00
|
|
|
/*********************************************************************************************\
|
|
|
|
* Basic I2C routines
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
#ifdef USE_I2C
|
|
|
|
#define I2C_RETRY_COUNTER 3
|
|
|
|
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
uint32_t i2c_buffer = 0;
|
|
|
|
|
|
|
|
bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
2019-01-28 13:08:33 +00:00
|
|
|
uint8_t x = I2C_RETRY_COUNTER;
|
2017-01-28 13:41:01 +00:00
|
|
|
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
i2c_buffer = 0;
|
2017-01-28 13:41:01 +00:00
|
|
|
do {
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
Wire.beginTransmission(addr); // start transmission to device
|
|
|
|
Wire.write(reg); // sends register address to read from
|
|
|
|
if (0 == Wire.endTransmission(false)) { // Try to become I2C Master, send data and collect bytes, keep master status for next request...
|
|
|
|
Wire.requestFrom((int)addr, (int)size); // send data n-bytes read
|
2017-04-25 17:24:42 +01:00
|
|
|
if (Wire.available() == size) {
|
2019-01-28 13:08:33 +00:00
|
|
|
for (uint8_t i = 0; i < size; i++) {
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
i2c_buffer = i2c_buffer << 8 | Wire.read(); // receive DATA
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
x--;
|
|
|
|
} while (Wire.endTransmission(true) != 0 && x != 0); // end transmission
|
|
|
|
return (x);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool I2cValidRead8(uint8_t *data, uint8_t addr, uint8_t reg)
|
|
|
|
{
|
|
|
|
bool status = I2cValidRead(addr, reg, 1);
|
|
|
|
*data = (uint8_t)i2c_buffer;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool I2cValidRead16(uint16_t *data, uint8_t addr, uint8_t reg)
|
|
|
|
{
|
|
|
|
bool status = I2cValidRead(addr, reg, 2);
|
|
|
|
*data = (uint16_t)i2c_buffer;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool I2cValidReadS16(int16_t *data, uint8_t addr, uint8_t reg)
|
|
|
|
{
|
|
|
|
bool status = I2cValidRead(addr, reg, 2);
|
|
|
|
*data = (int16_t)i2c_buffer;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool I2cValidRead16LE(uint16_t *data, uint8_t addr, uint8_t reg)
|
|
|
|
{
|
|
|
|
uint16_t ldata;
|
|
|
|
bool status = I2cValidRead16(&ldata, addr, reg);
|
|
|
|
*data = (ldata >> 8) | (ldata << 8);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool I2cValidReadS16_LE(int16_t *data, uint8_t addr, uint8_t reg)
|
|
|
|
{
|
|
|
|
uint16_t ldata;
|
|
|
|
bool status = I2cValidRead16LE(&ldata, addr, reg);
|
|
|
|
*data = (int16_t)ldata;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool I2cValidRead24(int32_t *data, uint8_t addr, uint8_t reg)
|
|
|
|
{
|
|
|
|
bool status = I2cValidRead(addr, reg, 3);
|
|
|
|
*data = i2c_buffer;
|
|
|
|
return status;
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
uint8_t I2cRead8(uint8_t addr, uint8_t reg)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
I2cValidRead(addr, reg, 1);
|
|
|
|
return (uint8_t)i2c_buffer;
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
uint16_t I2cRead16(uint8_t addr, uint8_t reg)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
I2cValidRead(addr, reg, 2);
|
|
|
|
return (uint16_t)i2c_buffer;
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
int16_t I2cReadS16(uint8_t addr, uint8_t reg)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
I2cValidRead(addr, reg, 2);
|
|
|
|
return (int16_t)i2c_buffer;
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
uint16_t I2cRead16LE(uint8_t addr, uint8_t reg)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
I2cValidRead(addr, reg, 2);
|
|
|
|
uint16_t temp = (uint16_t)i2c_buffer;
|
2017-01-28 13:41:01 +00:00
|
|
|
return (temp >> 8) | (temp << 8);
|
|
|
|
}
|
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
int16_t I2cReadS16_LE(uint8_t addr, uint8_t reg)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
2017-10-18 17:22:34 +01:00
|
|
|
return (int16_t)I2cRead16LE(addr, reg);
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
int32_t I2cRead24(uint8_t addr, uint8_t reg)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
I2cValidRead(addr, reg, 3);
|
|
|
|
return i2c_buffer;
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
2017-11-11 11:33:30 +00:00
|
|
|
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size)
|
2017-11-07 14:57:24 +00:00
|
|
|
{
|
2019-01-28 13:08:33 +00:00
|
|
|
uint8_t x = I2C_RETRY_COUNTER;
|
2017-11-07 14:57:24 +00:00
|
|
|
|
|
|
|
do {
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
Wire.beginTransmission((uint8_t)addr); // start transmission to device
|
|
|
|
Wire.write(reg); // sends register address to write to
|
2017-11-28 20:57:35 +00:00
|
|
|
uint8_t bytes = size;
|
|
|
|
while (bytes--) {
|
|
|
|
Wire.write((val >> (8 * bytes)) & 0xFF); // write data
|
|
|
|
}
|
2017-11-07 14:57:24 +00:00
|
|
|
x--;
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
} while (Wire.endTransmission(true) != 0 && x != 0); // end transmission
|
|
|
|
return (x);
|
2017-11-07 14:57:24 +00:00
|
|
|
}
|
|
|
|
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
bool I2cWrite8(uint8_t addr, uint8_t reg, uint16_t val)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
return I2cWrite(addr, reg, val, 1);
|
2017-11-11 11:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool I2cWrite16(uint8_t addr, uint8_t reg, uint16_t val)
|
|
|
|
{
|
v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes
5.9.1j
* Revert changes to xsns_05_ds18x20.ino and rename to
xsns_05_ds18x20_legacy.ino still needing library OneWire and providing
legacy JSON message:
*
"DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}}
* Add new xdrv_05_ds18x20.ino free from library OneWire and add the
following features:
* Add support for DS1822
* Add forced setting of
12-bit resolution for selected device types (#1222)
* Add read
temperature retry counter (#1215)
* Fix lost sensors by performing
sensor probe at restart only thereby removing dynamic sensor probe
(#1215)
* Fix sensor address sorting using ascending sort on sensor
type followed by sensor address
* Rewrite JSON resulting in shorter
message allowing more sensors in default firmware image:
*
"DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6}
* Add additional define in user_config.h to select either single sensor
(defines disabled), new multi sensor (USE_DS18X20) or legacy multi
sensor (USE_DS18X20_LEGACY)
* Add support for Sonoff Dual R2 (#1249)
*
Fix ADS1115 detection (#1258)
2017-11-27 16:46:51 +00:00
|
|
|
return I2cWrite(addr, reg, val, 2);
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
2018-07-04 17:41:00 +01:00
|
|
|
int8_t I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len)
|
|
|
|
{
|
|
|
|
Wire.beginTransmission((uint8_t)addr);
|
|
|
|
Wire.write((uint8_t)reg);
|
|
|
|
Wire.endTransmission();
|
2019-01-28 13:08:33 +00:00
|
|
|
if (len != Wire.requestFrom((uint8_t)addr, (uint8_t)len)) {
|
2018-07-04 17:41:00 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
while (len--) {
|
|
|
|
*reg_data = (uint8_t)Wire.read();
|
|
|
|
reg_data++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len)
|
|
|
|
{
|
|
|
|
Wire.beginTransmission((uint8_t)addr);
|
|
|
|
Wire.write((uint8_t)reg);
|
|
|
|
while (len--) {
|
|
|
|
Wire.write(*reg_data);
|
|
|
|
reg_data++;
|
|
|
|
}
|
|
|
|
Wire.endTransmission();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
void I2cScan(char *devs, unsigned int devs_len)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
2018-09-29 11:34:24 +01:00
|
|
|
// Return error codes defined in twi.h and core_esp8266_si2c.c
|
|
|
|
// I2C_OK 0
|
|
|
|
// I2C_SCL_HELD_LOW 1 = SCL held low by another device, no procedure available to recover
|
|
|
|
// I2C_SCL_HELD_LOW_AFTER_READ 2 = I2C bus error. SCL held low beyond slave clock stretch time
|
|
|
|
// I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by slave/another_master after n bits
|
|
|
|
// I2C_SDA_HELD_LOW_AFTER_INIT 4 = line busy. SDA again held low by another device. 2nd master?
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
uint8_t error = 0;
|
|
|
|
uint8_t address = 0;
|
|
|
|
uint8_t any = 0;
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2018-01-06 16:34:42 +00:00
|
|
|
snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_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
|
|
|
any = 1;
|
2018-09-29 11:34:24 +01:00
|
|
|
snprintf_P(devs, devs_len, PSTR("%s 0x%02x"), devs, address);
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
2018-09-29 11:34:24 +01:00
|
|
|
else if (error != 2) { // Seems to happen anyway using this scan
|
|
|
|
any = 2;
|
|
|
|
snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"Error %d at 0x%02x"), error, address);
|
|
|
|
break;
|
2017-04-25 17:24:42 +01:00
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
if (any) {
|
2018-11-22 14:41:30 +00:00
|
|
|
strncat(devs, "\"}", devs_len - strlen(devs) -1);
|
2018-09-29 11:34:24 +01:00
|
|
|
}
|
|
|
|
else {
|
2018-01-06 16:34:42 +00:00
|
|
|
snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_NO_DEVICES_FOUND "\"}"));
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
}
|
2017-10-25 13:27:30 +01:00
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
bool I2cDevice(uint8_t addr)
|
2017-10-25 13:27:30 +01:00
|
|
|
{
|
2019-01-28 13:08:33 +00:00
|
|
|
for (uint8_t address = 1; address <= 127; address++) {
|
2017-10-25 13:27:30 +01:00
|
|
|
Wire.beginTransmission(address);
|
|
|
|
if (!Wire.endTransmission() && (address == addr)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
#endif // USE_I2C
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* Syslog
|
2017-11-04 15:36:51 +00:00
|
|
|
*
|
2017-11-03 17:07:25 +00:00
|
|
|
* Example:
|
2019-03-08 14:15:42 +00:00
|
|
|
* AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_LOG "Any value %d"), value);
|
2017-11-03 17:07:25 +00:00
|
|
|
*
|
2017-01-28 13:41:01 +00:00
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
void SetSeriallog(uint8_t loglevel)
|
2018-03-18 12:47:30 +00:00
|
|
|
{
|
|
|
|
Settings.seriallog_level = loglevel;
|
|
|
|
seriallog_level = loglevel;
|
|
|
|
seriallog_timer = 0;
|
|
|
|
}
|
|
|
|
|
2018-01-30 13:14:55 +00:00
|
|
|
#ifdef USE_WEBSERVER
|
2019-01-28 13:08:33 +00:00
|
|
|
void GetLog(uint8_t idx, char** entry_pp, size_t* len_p)
|
2018-01-30 13:14:55 +00:00
|
|
|
{
|
|
|
|
char* entry_p = NULL;
|
|
|
|
size_t len = 0;
|
|
|
|
|
|
|
|
if (idx) {
|
|
|
|
char* it = web_log;
|
|
|
|
do {
|
2019-01-28 13:08:33 +00:00
|
|
|
uint8_t cur_idx = *it;
|
2018-01-30 13:14:55 +00:00
|
|
|
it++;
|
2018-02-01 15:18:00 +00:00
|
|
|
size_t tmp = strchrspn(it, '\1');
|
2018-01-30 13:14:55 +00:00
|
|
|
tmp++; // Skip terminating '\1'
|
|
|
|
if (cur_idx == idx) { // Found the requested entry
|
|
|
|
len = tmp;
|
|
|
|
entry_p = it;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
it += tmp;
|
|
|
|
} while (it < web_log + WEB_LOG_SIZE && *it != '\0');
|
|
|
|
}
|
|
|
|
*entry_pp = entry_p;
|
|
|
|
*len_p = len;
|
|
|
|
}
|
|
|
|
#endif // USE_WEBSERVER
|
|
|
|
|
2018-11-14 13:32:09 +00:00
|
|
|
void Syslog(void)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
2017-09-14 13:20:27 +01:00
|
|
|
// Destroys log_data
|
|
|
|
char syslog_preamble[64]; // Hostname + Id
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2018-02-20 15:19:48 +00:00
|
|
|
if (syslog_host_hash != GetHash(Settings.syslog_host, strlen(Settings.syslog_host))) {
|
|
|
|
syslog_host_hash = GetHash(Settings.syslog_host, strlen(Settings.syslog_host));
|
|
|
|
WiFi.hostByName(Settings.syslog_host, syslog_host_addr); // If sleep enabled this might result in exception so try to do it once using hash
|
2017-09-26 16:50:39 +01:00
|
|
|
}
|
2017-10-18 17:22:34 +01:00
|
|
|
if (PortUdp.beginPacket(syslog_host_addr, Settings.syslog_port)) {
|
|
|
|
snprintf_P(syslog_preamble, sizeof(syslog_preamble), PSTR("%s ESP-"), my_hostname);
|
2017-09-14 13:20:27 +01:00
|
|
|
memmove(log_data + strlen(syslog_preamble), log_data, sizeof(log_data) - strlen(syslog_preamble));
|
|
|
|
log_data[sizeof(log_data) -1] = '\0';
|
|
|
|
memcpy(log_data, syslog_preamble, strlen(syslog_preamble));
|
2017-10-18 17:22:34 +01:00
|
|
|
PortUdp.write(log_data);
|
|
|
|
PortUdp.endPacket();
|
2019-03-23 11:41:35 +00:00
|
|
|
delay(1); // Add time for UDP handling (#5512)
|
2017-01-28 13:41:01 +00:00
|
|
|
} else {
|
|
|
|
syslog_level = 0;
|
|
|
|
syslog_timer = SYSLOG_TIMER;
|
2019-03-08 14:15:42 +00:00
|
|
|
AddLog_P2(LOG_LEVEL_INFO, 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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
void AddLog(uint8_t loglevel)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
2018-01-30 13:14:55 +00:00
|
|
|
char mxtime[10]; // "13:45:21 "
|
2017-01-28 13:41:01 +00:00
|
|
|
|
2018-01-30 13:14:55 +00: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
|
|
|
|
2017-09-14 13:20:27 +01:00
|
|
|
if (loglevel <= seriallog_level) {
|
2018-12-17 18:25:13 +00:00
|
|
|
Serial.printf("%s%s\r\n", mxtime, log_data);
|
2017-09-14 13:20:27 +01:00
|
|
|
}
|
2017-01-28 13:41:01 +00:00
|
|
|
#ifdef USE_WEBSERVER
|
2017-10-18 17:22:34 +01:00
|
|
|
if (Settings.webserver && (loglevel <= Settings.weblog_level)) {
|
2018-01-30 13:14:55 +00:00
|
|
|
// Delimited, zero-terminated buffer of log lines.
|
|
|
|
// Each entry has this format: [index][log data]['\1']
|
|
|
|
if (!web_log_index) web_log_index++; // Index 0 is not allowed as it is the end of char string
|
|
|
|
while (web_log_index == web_log[0] || // If log already holds the next index, remove it
|
|
|
|
strlen(web_log) + strlen(log_data) + 13 > WEB_LOG_SIZE) // 13 = web_log_index + mxtime + '\1' + '\0'
|
|
|
|
{
|
|
|
|
char* it = web_log;
|
|
|
|
it++; // Skip web_log_index
|
2018-02-01 15:18:00 +00:00
|
|
|
it += strchrspn(it, '\1'); // Skip log line
|
2018-01-30 13:14:55 +00:00
|
|
|
it++; // Skip delimiting "\1"
|
|
|
|
memmove(web_log, it, WEB_LOG_SIZE -(it-web_log)); // Move buffer forward to remove oldest log line
|
2017-04-25 17:24:42 +01:00
|
|
|
}
|
2018-01-30 13:14:55 +00:00
|
|
|
snprintf_P(web_log, sizeof(web_log), PSTR("%s%c%s%s\1"), web_log, web_log_index++, mxtime, log_data);
|
2018-02-06 12:50:05 +00:00
|
|
|
if (!web_log_index) web_log_index++; // Index 0 is not allowed as it is the end of char string
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
#endif // USE_WEBSERVER
|
2018-11-04 17:00:07 +00:00
|
|
|
if (!global_state.wifi_down && (loglevel <= syslog_level)) { Syslog(); }
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
void AddLog_P(uint8_t loglevel, const char *formatP)
|
2017-01-28 13:41:01 +00:00
|
|
|
{
|
2017-09-13 13:19:34 +01:00
|
|
|
snprintf_P(log_data, sizeof(log_data), formatP);
|
2017-10-18 17:22:34 +01:00
|
|
|
AddLog(loglevel);
|
2017-01-28 13:41:01 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
void AddLog_P(uint8_t loglevel, const char *formatP, const char *formatP2)
|
2017-09-02 13:37:02 +01:00
|
|
|
{
|
2017-09-14 13:20:27 +01:00
|
|
|
char message[100];
|
2017-09-02 13:37:02 +01:00
|
|
|
|
2017-09-13 13:19:34 +01:00
|
|
|
snprintf_P(log_data, sizeof(log_data), formatP);
|
2017-09-14 13:20:27 +01:00
|
|
|
snprintf_P(message, sizeof(message), formatP2);
|
2018-11-22 14:41:30 +00:00
|
|
|
strncat(log_data, message, sizeof(log_data) - strlen(log_data) -1);
|
2017-10-18 17:22:34 +01:00
|
|
|
AddLog(loglevel);
|
2017-09-02 13:37:02 +01:00
|
|
|
}
|
|
|
|
|
2019-03-07 17:18:30 +00:00
|
|
|
void AddLog_P2(uint8_t loglevel, PGM_P formatP, ...)
|
|
|
|
{
|
|
|
|
va_list arg;
|
|
|
|
va_start(arg, formatP);
|
2019-03-14 15:50:56 +00:00
|
|
|
vsnprintf_P(log_data, sizeof(log_data), formatP, arg);
|
2019-03-07 17:18:30 +00:00
|
|
|
va_end(arg);
|
|
|
|
|
|
|
|
AddLog(loglevel);
|
|
|
|
}
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
void AddLogBuffer(uint8_t loglevel, uint8_t *buffer, int count)
|
2018-02-04 17:09:09 +00:00
|
|
|
{
|
2019-01-17 16:48:34 +00:00
|
|
|
snprintf_P(log_data, sizeof(log_data), PSTR("DMP:"));
|
2018-04-14 13:39:16 +01:00
|
|
|
for (int i = 0; i < count; i++) {
|
2018-02-13 13:30:30 +00:00
|
|
|
snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, *(buffer++));
|
2018-02-04 17:09:09 +00:00
|
|
|
}
|
|
|
|
AddLog(loglevel);
|
|
|
|
}
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
void AddLogSerial(uint8_t loglevel)
|
2018-02-13 13:30:30 +00:00
|
|
|
{
|
2019-01-17 16:48:34 +00:00
|
|
|
AddLogBuffer(loglevel, (uint8_t*)serial_in_buffer, serial_in_byte_counter);
|
2018-02-13 13:30:30 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 21:12:16 +01:00
|
|
|
void AddLogMissed(char *sensor, uint8_t misses)
|
|
|
|
{
|
2019-03-08 14:15:42 +00:00
|
|
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SNS: %s missed %d"), sensor, SENSOR_MAX_MISS - misses);
|
2018-07-10 21:12:16 +01:00
|
|
|
}
|