diff --git a/platformio.ini b/platformio.ini
index 372919b99..ecb72a3fe 100755
--- a/platformio.ini
+++ b/platformio.ini
@@ -67,7 +67,7 @@ build_flags = ${esp82xx_defaults.build_flags}
[core_2_5_2]
; *** Esp8266 core for Arduino version 2.5.2
-platform = espressif8266@~2.2.1
+platform = espressif8266@~2.2.2
build_flags = ${esp82xx_defaults.build_flags}
-Wl,-Teagle.flash.1m.ld
; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473
diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino
index 0ebffba3b..a1871ad18 100644
--- a/sonoff/_changelog.ino
+++ b/sonoff/_changelog.ino
@@ -7,6 +7,7 @@
* Add define USE_DHT to my_user_config.h to save space in sonoff-basic.bin
* Change TLS+AWS IoT optimization for speed, code and memory footprint
* Add command SetOption40 0..250 to disable button functionality if activated for over 0.1 second. Needs SetOption1 1 and SetOption13 0 (#5449)
+ * Change converted double to float in rules, and replaced trigonometric functions from stdlib with smaller versions.
*
* 6.5.0.15 20190606
* Change pubsubclient MQTT_KEEPALIVE from 10 to 30 seconds in preparation of AWS IoT support
diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino
index 8f14f714b..02ea25524 100755
--- a/sonoff/sonoff.ino
+++ b/sonoff/sonoff.ino
@@ -1939,8 +1939,8 @@ void MqttShowState(void)
ResponseAppend_P(PSTR(",\"" D_JSON_VCC "\":%s"), stemp1);
#endif
- ResponseAppend_P(PSTR(",\"SleepMode\":\"%s\",\"Sleep\":%u,\"LoadAvg\":%u"),
- GetTextIndexed(stemp1, sizeof(stemp1), Settings.flag3.sleep_normal, kSleepMode), sleep, loop_load_avg);
+ ResponseAppend_P(PSTR(",\"" D_JSON_HEAPSIZE "\":%d,\"SleepMode\":\"%s\",\"Sleep\":%u,\"LoadAvg\":%u"),
+ ESP.getFreeHeap()/1024, GetTextIndexed(stemp1, sizeof(stemp1), Settings.flag3.sleep_normal, kSleepMode), sleep, loop_load_avg);
for (uint32_t i = 0; i < devices_present; i++) {
#ifdef USE_LIGHT
diff --git a/sonoff/support.ino b/sonoff/support.ino
index be441f167..41e5ffd3b 100644
--- a/sonoff/support.ino
+++ b/sonoff/support.ino
@@ -224,7 +224,7 @@ char* subStr(char* dest, char* str, const char *delim, int index)
return sub;
}
-double CharToDouble(const char *str)
+float CharToFloat(const char *str)
{
// simple ascii to double, because atof or strtod are too large
char strbuf[24];
@@ -237,23 +237,23 @@ double CharToDouble(const char *str)
if (*pt == '-') { sign = -1; }
if (*pt == '-' || *pt=='+') { pt++; } // Skip any sign
- double left = 0;
+ float left = 0;
if (*pt != '.') {
left = atoi(pt); // Get left part
while (isdigit(*pt)) { pt++; } // Skip number
}
- double right = 0;
+ float right = 0;
if (*pt == '.') {
pt++;
right = atoi(pt); // Decimal part
while (isdigit(*pt)) {
pt++;
- right /= 10.0;
+ right /= 10.0f;
}
}
- double result = left + right;
+ float result = left + right;
if (sign < 0) {
return -result; // Add negative sign
}
@@ -650,66 +650,6 @@ void ResetGlobalValues(void)
}
}
-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 = abs((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;
-}
-
-float FastPrecisePowf(const float x, const float y)
-{
-// return (float)(pow((double)x, (double)y));
- return (float)FastPrecisePow(x, y);
-}
-
-double TaylorLog(double x)
-{
- // https://stackoverflow.com/questions/46879166/finding-the-natural-logarithm-of-a-number-using-taylor-series-in-c
-
- if (x <= 0.0) { return NAN; }
- double z = (x + 1) / (x - 1); // We start from power -1, to make sure we get the right power in each iteration;
- double step = ((x - 1) * (x - 1)) / ((x + 1) * (x + 1)); // Store step to not have to calculate it each time
- double totalValue = 0;
- double powe = 1;
- double y;
- for (uint32_t count = 0; count < 10; count++) { // Experimental number of 10 iterations
- z *= step;
- y = (1 / powe) * z;
- totalValue = totalValue + y;
- powe = powe + 2;
- }
- totalValue *= 2;
-/*
- char logxs[33];
- dtostrfd(x, 8, logxs);
- double log1 = log(x);
- char log1s[33];
- dtostrfd(log1, 8, log1s);
- char log2s[33];
- dtostrfd(totalValue, 8, log2s);
- AddLog_P2(LOG_LEVEL_DEBUG, PSTR("input %s, log %s, taylor %s"), logxs, log1s, log2s);
-*/
- return totalValue;
-}
-
uint32_t SqrtInt(uint32_t num)
{
if (num <= 1) {
diff --git a/sonoff/support_float.ino b/sonoff/support_float.ino
new file mode 100644
index 000000000..fc2dccf04
--- /dev/null
+++ b/sonoff/support_float.ino
@@ -0,0 +1,318 @@
+/*
+ support_float.ino - support for Sonoff-Tasmota
+
+ Copyright (C) 2019 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 .
+*/
+
+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 = abs((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;
+}
+
+float FastPrecisePowf(const float x, const float y)
+{
+// return (float)(pow((double)x, (double)y));
+ return (float)FastPrecisePow(x, y);
+}
+
+double TaylorLog(double x)
+{
+ // https://stackoverflow.com/questions/46879166/finding-the-natural-logarithm-of-a-number-using-taylor-series-in-c
+
+ if (x <= 0.0) { return NAN; }
+ double z = (x + 1) / (x - 1); // We start from power -1, to make sure we get the right power in each iteration;
+ double step = ((x - 1) * (x - 1)) / ((x + 1) * (x + 1)); // Store step to not have to calculate it each time
+ double totalValue = 0;
+ double powe = 1;
+ double y;
+ for (uint32_t count = 0; count < 10; count++) { // Experimental number of 10 iterations
+ z *= step;
+ y = (1 / powe) * z;
+ totalValue = totalValue + y;
+ powe = powe + 2;
+ }
+ totalValue *= 2;
+/*
+ char logxs[33];
+ dtostrfd(x, 8, logxs);
+ double log1 = log(x);
+ char log1s[33];
+ dtostrfd(log1, 8, log1s);
+ char log2s[33];
+ dtostrfd(totalValue, 8, log2s);
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("input %s, log %s, taylor %s"), logxs, log1s, log2s);
+*/
+ return totalValue;
+}
+
+// All code adapted from: http://www.ganssle.com/approx.htm
+
+/// ========================================
+// The following code implements approximations to various trig functions.
+//
+// This is demo code to guide developers in implementing their own approximation
+// software. This code is merely meant to illustrate algorithms.
+
+inline float sinf(float x) { return sin_52(x); }
+inline float cosf(float x) { return cos_52(x); }
+inline float tanf(float x) { return tan_56(x); }
+inline float atanf(float x) { return atan_66(x); }
+inline float asinf(float x) { return asinf1(x); }
+inline float acosf(float x) { return acosf1(x); }
+inline float sqrtf(float x) { return sqrt1(x); }
+inline float powf(float x, float y) { return FastPrecisePow(x, y); }
+
+// Math constants we'll use
+double const f_pi=3.1415926535897932384626433; // f_pi
+double const f_twopi=2.0*f_pi; // f_pi times 2
+double const f_two_over_pi= 2.0/f_pi; // 2/f_pi
+double const f_halfpi=f_pi/2.0; // f_pi divided by 2
+double const f_threehalfpi=3.0*f_pi/2.0; // f_pi times 3/2, used in tan routines
+double const f_four_over_pi=4.0/f_pi; // 4/f_pi, used in tan routines
+double const f_qtrpi=f_pi/4.0; // f_pi/4.0, used in tan routines
+double const f_sixthpi=f_pi/6.0; // f_pi/6.0, used in atan routines
+double const f_tansixthpi=tan(f_sixthpi); // tan(f_pi/6), used in atan routines
+double const f_twelfthpi=f_pi/12.0; // f_pi/12.0, used in atan routines
+double const f_tantwelfthpi=tan(f_twelfthpi); // tan(f_pi/12), used in atan routines
+
+// *********************************************************
+// ***
+// *** Routines to compute sine and cosine to 5.2 digits
+// *** of accuracy.
+// ***
+// *********************************************************
+//
+// cos_52s computes cosine (x)
+//
+// Accurate to about 5.2 decimal digits over the range [0, f_pi/2].
+// The input argument is in radians.
+//
+// Algorithm:
+// cos(x)= c1 + c2*x**2 + c3*x**4 + c4*x**6
+// which is the same as:
+// cos(x)= c1 + x**2(c2 + c3*x**2 + c4*x**4)
+// cos(x)= c1 + x**2(c2 + x**2(c3 + c4*x**2))
+//
+float cos_52s(float x)
+{
+const float c1= 0.9999932946;
+const float c2=-0.4999124376;
+const float c3= 0.0414877472;
+const float c4=-0.0012712095;
+
+float x2; // The input argument squared
+
+x2=x * x;
+return (c1 + x2*(c2 + x2*(c3 + c4*x2)));
+}
+
+//
+// This is the main cosine approximation "driver"
+// It reduces the input argument's range to [0, f_pi/2],
+// and then calls the approximator.
+// See the notes for an explanation of the range reduction.
+//
+float cos_52(float x){
+ int quad; // what quadrant are we in?
+
+ x=fmodf(x, f_twopi); // Get rid of values > 2* f_pi
+ if(x<0)x=-x; // cos(-x) = cos(x)
+ quad=int(x * (float)f_two_over_pi); // Get quadrant # (0 to 3) we're in
+ switch (quad){
+ case 0: return cos_52s(x);
+ case 1: return -cos_52s((float)f_pi-x);
+ case 2: return -cos_52s(x-(float)f_pi);
+ case 3: return cos_52s((float)f_twopi-x);
+ }
+}
+//
+// The sine is just cosine shifted a half-f_pi, so
+// we'll adjust the argument and call the cosine approximation.
+//
+float sin_52(float x){
+ return cos_52((float)f_halfpi-x);
+}
+
+// *********************************************************
+// ***
+// *** Routines to compute tangent to 5.6 digits
+// *** of accuracy.
+// ***
+// *********************************************************
+//
+// tan_56s computes tan(f_pi*x/4)
+//
+// Accurate to about 5.6 decimal digits over the range [0, f_pi/4].
+// The input argument is in radians. Note that the function
+// computes tan(f_pi*x/4), NOT tan(x); it's up to the range
+// reduction algorithm that calls this to scale things properly.
+//
+// Algorithm:
+// tan(x)= x(c1 + c2*x**2)/(c3 + x**2)
+//
+float tan_56s(float x)
+{
+const float c1=-3.16783027;
+const float c2= 0.134516124;
+const float c3=-4.033321984;
+
+float x2; // The input argument squared
+
+x2=x * x;
+return (x*(c1 + c2 * x2)/(c3 + x2));
+}
+
+//
+// This is the main tangent approximation "driver"
+// It reduces the input argument's range to [0, f_pi/4],
+// and then calls the approximator.
+// See the notes for an explanation of the range reduction.
+// Enter with positive angles only.
+//
+// WARNING: We do not test for the tangent approaching infinity,
+// which it will at x=f_pi/2 and x=3*f_pi/2. If this is a problem
+// in your application, take appropriate action.
+//
+float tan_56(float x){
+ int octant; // what octant are we in?
+
+ x=fmodf(x, (float)f_twopi); // Get rid of values >2 *f_pi
+ octant=int(x * (float)f_four_over_pi); // Get octant # (0 to 7)
+ switch (octant){
+ case 0: return tan_56s(x *(float)f_four_over_pi);
+ case 1: return 1.0f/tan_56s(((float)f_halfpi-x) *(float)f_four_over_pi);
+ case 2: return -1.0f/tan_56s((x-(float)f_halfpi) *(float)f_four_over_pi);
+ case 3: return - tan_56s(((float)f_pi-x) *(float)f_four_over_pi);
+ case 4: return tan_56s((x-(float)f_pi) *(float)f_four_over_pi);
+ case 5: return 1.0f/tan_56s(((float)f_threehalfpi-x)*(float)f_four_over_pi);
+ case 6: return -1.0f/tan_56s((x-(float)f_threehalfpi)*(float)f_four_over_pi);
+ case 7: return - tan_56s(((float)f_twopi-x) *(float)f_four_over_pi);
+ }
+}
+
+// *********************************************************
+// ***
+// *** Routines to compute arctangent to 6.6 digits
+// *** of accuracy.
+// ***
+// *********************************************************
+//
+// atan_66s computes atan(x)
+//
+// Accurate to about 6.6 decimal digits over the range [0, f_pi/12].
+//
+// Algorithm:
+// atan(x)= x(c1 + c2*x**2)/(c3 + x**2)
+//
+float atan_66s(float x)
+{
+const float c1=1.6867629106;
+const float c2=0.4378497304;
+const float c3=1.6867633134;
+
+float x2; // The input argument squared
+
+x2=x * x;
+return (x*(c1 + x2*c2)/(c3 + x2));
+}
+
+//
+// This is the main arctangent approximation "driver"
+// It reduces the input argument's range to [0, f_pi/12],
+// and then calls the approximator.
+//
+//
+float atan_66(float x){
+ float y; // return from atan__s function
+ bool complement= false; // true if arg was >1
+ bool region= false; // true depending on region arg is in
+ bool sign= false; // true if arg was < 0
+
+ if (x <0 ){
+ x=-x;
+ sign=true; // arctan(-x)=-arctan(x)
+ }
+ if (x > 1.0){
+ x=1.0/x; // keep arg between 0 and 1
+ complement=true;
+ }
+ if (x > (float)f_tantwelfthpi){
+ x = (x-(float)f_tansixthpi)/(1+(float)f_tansixthpi*x); // reduce arg to under tan(f_pi/12)
+ region=true;
+ }
+
+ y=atan_66s(x); // run the approximation
+ if (region) y+=(float)f_sixthpi; // correct for region we're in
+ if (complement)y=(float)f_halfpi-y; // correct for 1/x if we did that
+ if (sign)y=-y; // correct for negative arg
+ return (y);
+}
+
+float asinf1(float x) {
+ float d = 1.0f - x*x;
+ if (d < 0.0f) { return nanf(""); }
+ return 2 * atan_66(x / (1 + sqrt1(d)));
+}
+
+float acosf1(float x) {
+ float d = 1.0f - x*x;
+ if (d < 0.0f) { return nanf(""); }
+ float y = asinf1(sqrt1(d));
+ if (x >= 0.0f) {
+ return y;
+ } else {
+ return (float)f_pi - y;
+ }
+}
+
+// https://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi
+float sqrt1(const float x)
+{
+ union
+ {
+ int i;
+ float x;
+ } u;
+ u.x = x;
+ u.i = (1<<29) + (u.i >> 1) - (1<<22);
+
+ // Two Babylonian Steps (simplified from:)
+ // u.x = 0.5f * (u.x + x/u.x);
+ // u.x = 0.5f * (u.x + x/u.x);
+ u.x = u.x + x/u.x;
+ u.x = 0.25f*u.x + x/u.x;
+
+ return u.x;
+}
diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino
index 5b7dce6fb..4de82c817 100644
--- a/sonoff/xdrv_09_timers.ino
+++ b/sonoff/xdrv_09_timers.ino
@@ -487,7 +487,7 @@ bool TimerCommand(void)
#ifdef USE_SUNRISE
else if (CMND_LONGITUDE == command_code) {
if (XdrvMailbox.data_len) {
- Settings.longitude = (int)(CharToDouble(XdrvMailbox.data) *1000000);
+ Settings.longitude = (int)(CharToFloat(XdrvMailbox.data) *1000000);
}
char lbuff[33];
dtostrfd(((float)Settings.longitude) /1000000, 6, lbuff);
@@ -495,7 +495,7 @@ bool TimerCommand(void)
}
else if (CMND_LATITUDE == command_code) {
if (XdrvMailbox.data_len) {
- Settings.latitude = (int)(CharToDouble(XdrvMailbox.data) *1000000);
+ Settings.latitude = (int)(CharToFloat(XdrvMailbox.data) *1000000);
}
char lbuff[33];
dtostrfd(((float)Settings.latitude) /1000000, 6, lbuff);
diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino
index 61bb27796..e4da6939b 100644
--- a/sonoff/xdrv_10_rules.ino
+++ b/sonoff/xdrv_10_rules.ino
@@ -179,7 +179,7 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
}
char rule_svalue[CMDSZ] = { 0 };
- double rule_value = 0;
+ float rule_value = 0;
if (compare != COMPARE_OPERATOR_NONE) {
String rule_param = rule_name.substring(pos + strlen(compare_operator));
for (uint32_t i = 0; i < MAX_RULE_VARS; i++) {
@@ -225,7 +225,7 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
if (temp_value > -1) {
rule_value = temp_value;
} else {
- rule_value = CharToDouble((char*)rule_svalue); // 0.1 - This saves 9k code over toFLoat()!
+ rule_value = CharToFloat((char*)rule_svalue); // 0.1 - This saves 9k code over toFLoat()!
}
rule_name = rule_name.substring(0, pos); // "CURRENT"
}
@@ -235,7 +235,7 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
JsonObject &root = jsonBuf.parseObject(event);
if (!root.success()) { return false; } // No valid JSON data
- double value = 0;
+ float value = 0;
const char* str_value = root[rule_task][rule_name];
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: Task %s, Name %s, Value |%s|, TrigCnt %d, TrigSt %d, Source %s, Json %s"),
@@ -248,7 +248,7 @@ bool RulesRuleMatch(uint8_t rule_set, String &event, String &rule)
// Step 3: Compare rule (value)
if (str_value) {
- value = CharToDouble((char*)str_value);
+ value = CharToFloat((char*)str_value);
int int_value = int(value);
int int_rule_value = int(rule_value);
switch (compare) {
@@ -797,15 +797,15 @@ String RulesUnsubscribe(const char * data, int data_len)
* Parse a number value
* Input:
* pNumber - A char pointer point to a digit started string (guaranteed)
- * value - Reference a double variable used to accept the result
+ * value - Reference a float variable used to accept the result
* Output:
* pNumber - Pointer forward to next character after the number
- * value - double type, the result value
+ * value - float type, the result value
* Return:
* true - succeed
* false - failed
*/
-bool findNextNumber(char * &pNumber, double &value)
+bool findNextNumber(char * &pNumber, float &value)
{
bool bSucceed = false;
String sNumber = "";
@@ -818,7 +818,7 @@ bool findNextNumber(char * &pNumber, double &value)
}
}
if (sNumber.length() > 0) {
- value = CharToDouble(sNumber.c_str());
+ value = CharToFloat(sNumber.c_str());
bSucceed = true;
}
return bSucceed;
@@ -826,18 +826,18 @@ bool findNextNumber(char * &pNumber, double &value)
/********************************************************************************************/
/*
- * Parse a variable (like VAR1, MEM3) and get its value (double type)
+ * Parse a variable (like VAR1, MEM3) and get its value (float type)
* Input:
* pVarname - A char pointer point to a variable name string
- * value - Reference a double variable used to accept the result
+ * value - Reference a float variable used to accept the result
* Output:
* pVarname - Pointer forward to next character after the variable
- * value - double type, the result value
+ * value - float type, the result value
* Return:
* true - succeed
* false - failed
*/
-bool findNextVariableValue(char * &pVarname, double &value)
+bool findNextVariableValue(char * &pVarname, float &value)
{
bool succeed = true;
value = 0;
@@ -854,12 +854,12 @@ bool findNextVariableValue(char * &pVarname, double &value)
if (sVarName.startsWith(F("VAR"))) {
int index = sVarName.substring(3).toInt();
if (index > 0 && index <= MAX_RULE_VARS) {
- value = CharToDouble(vars[index -1]);
+ value = CharToFloat(vars[index -1]);
}
} else if (sVarName.startsWith(F("MEM"))) {
int index = sVarName.substring(3).toInt();
if (index > 0 && index <= MAX_RULE_MEMS) {
- value = CharToDouble(Settings.mems[index -1]);
+ value = CharToFloat(Settings.mems[index -1]);
}
} else if (sVarName.equals(F("TIME"))) {
value = MinutesPastMidnight();
@@ -891,15 +891,15 @@ bool findNextVariableValue(char * &pVarname, double &value)
* - An expression enclosed with a pair of round brackets, (.....)
* Input:
* pointer - A char pointer point to a place of the expression string
- * value - Reference a double variable used to accept the result
+ * value - Reference a float variable used to accept the result
* Output:
* pointer - Pointer forward to next character after next object
- * value - double type, the result value
+ * value - float type, the result value
* Return:
* true - succeed
* false - failed
*/
-bool findNextObjectValue(char * &pointer, double &value)
+bool findNextObjectValue(char * &pointer, float &value)
{
bool bSucceed = false;
while (*pointer)
@@ -984,15 +984,15 @@ bool findNextOperator(char * &pointer, int8_t &op)
* Calculate a simple expression composed by 2 value and 1 operator, like 2 * 3
* Input:
* pointer - A char pointer point to a place of the expression string
- * value - Reference a double variable used to accept the result
+ * value - Reference a float variable used to accept the result
* Output:
* pointer - Pointer forward to next character after next object
- * value - double type, the result value
+ * value - float type, the result value
* Return:
* true - succeed
* false - failed
*/
-double calculateTwoValues(double v1, double v2, uint8_t op)
+float calculateTwoValues(float v1, float v2, uint8_t op)
{
switch (op)
{
@@ -1025,7 +1025,7 @@ double calculateTwoValues(double v1, double v2, uint8_t op)
* expression - The expression to be evaluated
* len - Length of the expression
* Return:
- * double - result.
+ * float - result.
* 0 - if the expression is invalid
* An example:
* MEM1 = 3, MEM2 = 6, VAR2 = 15, VAR10 = 80
@@ -1045,17 +1045,17 @@ double calculateTwoValues(double v1, double v2, uint8_t op)
* 2 + 1
* 3 / 2
*/
-double evaluateExpression(const char * expression, unsigned int len)
+float evaluateExpression(const char * expression, unsigned int len)
{
char expbuf[len + 1];
memcpy(expbuf, expression, len);
expbuf[len] = '\0';
char * scan_pointer = expbuf;
- LinkedList object_values;
+ LinkedList object_values;
LinkedList operators;
int8_t op;
- double va;
+ float va;
//Find and add the value of first object
if (findNextObjectValue(scan_pointer, va)) {
object_values.add(va);
@@ -1154,7 +1154,7 @@ bool RulesCommand(void)
else if ((CMND_RULETIMER == command_code) && (index > 0) && (index <= MAX_RULE_TIMERS)) {
if (XdrvMailbox.data_len > 0) {
#ifdef USE_EXPRESSION
- double timer_set = evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len);
+ float timer_set = evaluateExpression(XdrvMailbox.data, XdrvMailbox.data_len);
rules_timer[index -1] = (timer_set > 0) ? millis() + (1000 * timer_set) : 0;
#else
rules_timer[index -1] = (XdrvMailbox.payload > 0) ? millis() + (1000 * XdrvMailbox.payload) : 0;
@@ -1202,7 +1202,7 @@ bool RulesCommand(void)
}
else if ((CMND_ADD == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) {
if (XdrvMailbox.data_len > 0) {
- double tempvar = CharToDouble(vars[index -1]) + CharToDouble(XdrvMailbox.data);
+ float tempvar = CharToFloat(vars[index -1]) + CharToFloat(XdrvMailbox.data);
dtostrfd(tempvar, Settings.flag2.calc_resolution, vars[index -1]);
bitSet(vars_event, index -1);
}
@@ -1210,7 +1210,7 @@ bool RulesCommand(void)
}
else if ((CMND_SUB == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) {
if (XdrvMailbox.data_len > 0) {
- double tempvar = CharToDouble(vars[index -1]) - CharToDouble(XdrvMailbox.data);
+ float tempvar = CharToFloat(vars[index -1]) - CharToFloat(XdrvMailbox.data);
dtostrfd(tempvar, Settings.flag2.calc_resolution, vars[index -1]);
bitSet(vars_event, index -1);
}
@@ -1218,7 +1218,7 @@ bool RulesCommand(void)
}
else if ((CMND_MULT == command_code) && (index > 0) && (index <= MAX_RULE_VARS)) {
if (XdrvMailbox.data_len > 0) {
- double tempvar = CharToDouble(vars[index -1]) * CharToDouble(XdrvMailbox.data);
+ float tempvar = CharToFloat(vars[index -1]) * CharToFloat(XdrvMailbox.data);
dtostrfd(tempvar, Settings.flag2.calc_resolution, vars[index -1]);
bitSet(vars_event, index -1);
}
@@ -1229,12 +1229,12 @@ bool RulesCommand(void)
if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry
char sub_string[XdrvMailbox.data_len +1];
- double valueIN = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 1));
- double fromLow = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 2));
- double fromHigh = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 3));
- double toLow = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 4));
- double toHigh = CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 5));
- double value = map_double(valueIN, fromLow, fromHigh, toLow, toHigh);
+ float valueIN = CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 1));
+ float fromLow = CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 2));
+ float fromHigh = CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 3));
+ float toLow = CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 4));
+ float toHigh = CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 5));
+ float value = map_double(valueIN, fromLow, fromHigh, toLow, toHigh);
dtostrfd(value, Settings.flag2.calc_resolution, vars[index -1]);
bitSet(vars_event, index -1);
}
@@ -1254,7 +1254,7 @@ bool RulesCommand(void)
return serviced;
}
-double map_double(double x, double in_min, double in_max, double out_min, double out_max)
+float map_double(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
@@ -1302,4 +1302,4 @@ bool Xdrv10(uint8_t function)
}
#endif // Do not USE_SCRIPT
-#endif // USE_RULES
\ No newline at end of file
+#endif // USE_RULES
diff --git a/sonoff/xdrv_10_scripter.ino b/sonoff/xdrv_10_scripter.ino
index 93ff63878..284128033 100644
--- a/sonoff/xdrv_10_scripter.ino
+++ b/sonoff/xdrv_10_scripter.ino
@@ -298,7 +298,7 @@ char *script;
op++;
if (*op!='"') {
float fv;
- fv=CharToDouble(op);
+ fv=CharToFloat(op);
fvalues[nvars]=fv;
vtypes[vars].bits.is_string=0;
if (!vtypes[vars].bits.is_filter) vtypes[vars].index=nvars;
@@ -670,7 +670,7 @@ char *isvar(char *lp, uint8_t *vtype,struct T_INDEX *tind,float *fp,char *sp,Jso
if (isdigit(*lp) || (*lp=='-' && isdigit(*(lp+1))) || *lp=='.') {
// isnumber
- if (fp) *fp=CharToDouble(lp);
+ if (fp) *fp=CharToFloat(lp);
if (*lp=='-') lp++;
while (isdigit(*lp) || *lp=='.') {
if (*lp==0 || *lp==SCRIPT_EOL) break;
@@ -839,7 +839,7 @@ char *isvar(char *lp, uint8_t *vtype,struct T_INDEX *tind,float *fp,char *sp,Jso
return lp+len;
}
} else {
- if (fp) *fp=CharToDouble((char*)str_value);
+ if (fp) *fp=CharToFloat((char*)str_value);
*vtype=NUM_RES;
tind->bits.constant=1;
tind->bits.is_string=0;
@@ -2266,7 +2266,7 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) {
// mismatch was string, not number
// get the string and convert to number
lp=isvar(slp,&vtype,&ind,0,cmpstr,jo);
- fvar=CharToDouble(cmpstr);
+ fvar=CharToFloat(cmpstr);
}
switch (lastop) {
case OPER_EQU:
@@ -2398,7 +2398,7 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) {
*dfvar=fparam;
} else {
// mismatch
- *dfvar=CharToDouble(cmpstr);
+ *dfvar=CharToFloat(cmpstr);
}
} else {
// string result
diff --git a/sonoff/xdrv_11_knx.ino b/sonoff/xdrv_11_knx.ino
index d0a2c9212..7a477bff8 100644
--- a/sonoff/xdrv_11_knx.ino
+++ b/sonoff/xdrv_11_knx.ino
@@ -1030,7 +1030,7 @@ bool KnxCommand(void)
while ( i != KNX_Empty ) {
KNX_addr.value = Settings.knx_GA_addr[i];
- float tempvar = CharToDouble(XdrvMailbox.data);
+ float tempvar = CharToFloat(XdrvMailbox.data);
dtostrfd(tempvar,2,XdrvMailbox.data);
knx.write_2byte_float(KNX_addr, tempvar);
diff --git a/sonoff/xdrv_13_display.ino b/sonoff/xdrv_13_display.ino
index b00f2a3ce..c95fd980a 100644
--- a/sonoff/xdrv_13_display.ino
+++ b/sonoff/xdrv_13_display.ino
@@ -61,18 +61,8 @@ const char S_JSON_DISPLAY_COMMAND_VALUE[] PROGMEM = "{\"" D_CMND_DISPLAY
const char S_JSON_DISPLAY_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_DISPLAY "%s\":%d}";
const char S_JSON_DISPLAY_COMMAND_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_DISPLAY "%s%d\":%d}";
-uint8_t disp_power = 0;
-uint8_t disp_device = 0;
-uint8_t disp_refresh = 1;
+char *dsp_str;
-int16_t disp_xpos = 0;
-int16_t disp_ypos = 0;
-uint8_t disp_autodraw = 1;
-
-uint8_t dsp_init;
-uint8_t dsp_font;
-uint8_t dsp_flag;
-uint8_t dsp_on;
uint16_t dsp_x;
uint16_t dsp_y;
uint16_t dsp_x2;
@@ -80,21 +70,30 @@ uint16_t dsp_y2;
uint16_t dsp_rad;
uint16_t dsp_color;
int16_t dsp_len;
-char *dsp_str;
+int16_t disp_xpos = 0;
+int16_t disp_ypos = 0;
+
+uint8_t disp_power = 0;
+uint8_t disp_device = 0;
+uint8_t disp_refresh = 1;
+uint8_t disp_autodraw = 1;
+uint8_t dsp_init;
+uint8_t dsp_font;
+uint8_t dsp_flag;
+uint8_t dsp_on;
#ifdef USE_DISPLAY_MODES1TO5
-char disp_temp[2]; // C or F
-uint8_t disp_subscribed = 0;
-
char **disp_log_buffer;
+char **disp_screen_buffer;
+char disp_temp[2]; // C or F
+
uint8_t disp_log_buffer_cols = 0;
uint8_t disp_log_buffer_idx = 0;
uint8_t disp_log_buffer_ptr = 0;
-
-char **disp_screen_buffer;
uint8_t disp_screen_buffer_cols = 0;
uint8_t disp_screen_buffer_rows = 0;
+bool disp_subscribed = false;
#endif // USE_DISPLAY_MODES1TO5
@@ -820,8 +819,7 @@ void DisplayMqttSubscribe(void)
* - home/%prefix%/%topic%
* - home/level2/%prefix%/%topic% etc.
*/
-// if (Settings.display_mode &0x04) {
- if (Settings.display_model) {
+ if (Settings.display_model && (Settings.display_mode &0x04)) {
char stopic[TOPSZ];
char ntopic[TOPSZ];
@@ -839,9 +837,9 @@ void DisplayMqttSubscribe(void)
strncat(ntopic, Settings.mqtt_prefix[2], sizeof(ntopic) - strlen(ntopic) -1); // Subscribe to tele messages
strncat_P(ntopic, PSTR("/#"), sizeof(ntopic) - strlen(ntopic) -1); // Add multi-level wildcard
MqttSubscribe(ntopic);
- disp_subscribed = 1;
+ disp_subscribed = true;
} else {
- disp_subscribed = 0;
+ disp_subscribed = false;
}
}
@@ -948,16 +946,16 @@ bool DisplayCommand(void)
* 5 = Mqtt up and time Mqtt (incl local) sensors and time Mqtt (incl local) sensors and time
*/
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 5)) {
- uint8_t last_display_mode = Settings.display_mode;
+ uint32_t last_display_mode = Settings.display_mode;
Settings.display_mode = XdrvMailbox.payload;
- if (!disp_subscribed) {
+
+ if (disp_subscribed != (Settings.display_mode &0x04)) {
restart_flag = 2; // Restart to Add/Remove MQTT subscribe
} else {
if (last_display_mode && !Settings.display_mode) { // Switch to mode 0
DisplayInit(DISPLAY_INIT_MODE);
DisplayClear();
} else {
-// if (!last_display_mode && Settings.display_mode) { // Switch to non mode 0
DisplayLogBufferInit();
DisplayInit(DISPLAY_INIT_MODE);
}
diff --git a/sonoff/xdsp_04_ili9341.ino b/sonoff/xdsp_04_ili9341.ino
index 5bb777607..f98866d5e 100644
--- a/sonoff/xdsp_04_ili9341.ino
+++ b/sonoff/xdsp_04_ili9341.ino
@@ -173,6 +173,7 @@ void Ili9341PrintLog(void)
tft->print(disp_screen_buffer[i]);
tft_scroll += theight;
tft->setCursor(0, tft_scroll);
+ delay(1); // Fix background runs heap usage due to long runtime of this loop (up to 1 second)
}
strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols);
DisplayFillScreen(last_row);
diff --git a/sonoff/xnrg_01_hlw8012.ino b/sonoff/xnrg_01_hlw8012.ino
index 503d4e50f..73f31c91f 100644
--- a/sonoff/xnrg_01_hlw8012.ino
+++ b/sonoff/xnrg_01_hlw8012.ino
@@ -287,17 +287,17 @@ bool HlwCommand(void)
}
else if (CMND_POWERSET == energy_command_code) {
if (XdrvMailbox.data_len && hlw_cf_power_pulse_length) {
- Settings.energy_power_calibration = ((unsigned long)(CharToDouble(XdrvMailbox.data) * 10) * hlw_cf_power_pulse_length) / hlw_power_ratio;
+ Settings.energy_power_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data) * 10) * hlw_cf_power_pulse_length) / hlw_power_ratio;
}
}
else if (CMND_VOLTAGESET == energy_command_code) {
if (XdrvMailbox.data_len && hlw_cf1_voltage_pulse_length) {
- Settings.energy_voltage_calibration = ((unsigned long)(CharToDouble(XdrvMailbox.data) * 10) * hlw_cf1_voltage_pulse_length) / hlw_voltage_ratio;
+ Settings.energy_voltage_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data) * 10) * hlw_cf1_voltage_pulse_length) / hlw_voltage_ratio;
}
}
else if (CMND_CURRENTSET == energy_command_code) {
if (XdrvMailbox.data_len && hlw_cf1_current_pulse_length) {
- Settings.energy_current_calibration = ((unsigned long)(CharToDouble(XdrvMailbox.data)) * hlw_cf1_current_pulse_length) / hlw_current_ratio;
+ Settings.energy_current_calibration = ((unsigned long)(CharToFloat(XdrvMailbox.data)) * hlw_cf1_current_pulse_length) / hlw_current_ratio;
}
}
else serviced = false; // Unknown command
diff --git a/sonoff/xnrg_02_cse7766.ino b/sonoff/xnrg_02_cse7766.ino
index c546571bb..f9d6d81e2 100644
--- a/sonoff/xnrg_02_cse7766.ino
+++ b/sonoff/xnrg_02_cse7766.ino
@@ -225,17 +225,17 @@ bool CseCommand(void)
if (CMND_POWERSET == energy_command_code) {
if (XdrvMailbox.data_len && power_cycle) {
- Settings.energy_power_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * power_cycle) / CSE_PREF;
+ Settings.energy_power_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * power_cycle) / CSE_PREF;
}
}
else if (CMND_VOLTAGESET == energy_command_code) {
if (XdrvMailbox.data_len && voltage_cycle) {
- Settings.energy_voltage_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * voltage_cycle) / CSE_UREF;
+ Settings.energy_voltage_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * voltage_cycle) / CSE_UREF;
}
}
else if (CMND_CURRENTSET == energy_command_code) {
if (XdrvMailbox.data_len && current_cycle) {
- Settings.energy_current_calibration = (unsigned long)(CharToDouble(XdrvMailbox.data) * current_cycle) / 1000;
+ Settings.energy_current_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * current_cycle) / 1000;
}
}
else serviced = false; // Unknown command
diff --git a/sonoff/xnrg_04_mcp39f501.ino b/sonoff/xnrg_04_mcp39f501.ino
index 86bb81855..6171ef93a 100644
--- a/sonoff/xnrg_04_mcp39f501.ino
+++ b/sonoff/xnrg_04_mcp39f501.ino
@@ -604,7 +604,7 @@ bool McpCommand(void)
if (CMND_POWERSET == energy_command_code) {
if (XdrvMailbox.data_len && mcp_active_power) {
- value = (unsigned long)(CharToDouble(XdrvMailbox.data) * 100);
+ value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 100);
if ((value > 100) && (value < 200000)) { // Between 1W and 2000W
Settings.energy_power_calibration = value;
mcp_calibrate |= MCP_CALIBRATE_POWER;
@@ -614,7 +614,7 @@ bool McpCommand(void)
}
else if (CMND_VOLTAGESET == energy_command_code) {
if (XdrvMailbox.data_len && mcp_voltage_rms) {
- value = (unsigned long)(CharToDouble(XdrvMailbox.data) * 10);
+ value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10);
if ((value > 1000) && (value < 2600)) { // Between 100V and 260V
Settings.energy_voltage_calibration = value;
mcp_calibrate |= MCP_CALIBRATE_VOLTAGE;
@@ -624,7 +624,7 @@ bool McpCommand(void)
}
else if (CMND_CURRENTSET == energy_command_code) {
if (XdrvMailbox.data_len && mcp_current_rms) {
- value = (unsigned long)(CharToDouble(XdrvMailbox.data) * 10);
+ value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10);
if ((value > 100) && (value < 80000)) { // Between 10mA and 8A
Settings.energy_current_calibration = value;
mcp_calibrate |= MCP_CALIBRATE_CURRENT;
@@ -634,7 +634,7 @@ bool McpCommand(void)
}
else if (CMND_FREQUENCYSET == energy_command_code) {
if (XdrvMailbox.data_len && mcp_line_frequency) {
- value = (unsigned long)(CharToDouble(XdrvMailbox.data) * 1000);
+ value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 1000);
if ((value > 45000) && (value < 65000)) { // Between 45Hz and 65Hz
Settings.energy_frequency_calibration = value;
mcp_calibrate |= MCP_CALIBRATE_FREQUENCY;
diff --git a/sonoff/xnrg_07_ade7953.ino b/sonoff/xnrg_07_ade7953.ino
index 09566266b..c11a283ae 100644
--- a/sonoff/xnrg_07_ade7953.ino
+++ b/sonoff/xnrg_07_ade7953.ino
@@ -184,7 +184,7 @@ bool Ade7953Command(void)
{
bool serviced = true;
- uint32_t value = (uint32_t)(CharToDouble(XdrvMailbox.data) * 100); // 1.23 = 123
+ uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); // 1.23 = 123
if (CMND_POWERCAL == energy_command_code) {
if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_PREF; }
diff --git a/sonoff/xsns_02_analog.ino b/sonoff/xsns_02_analog.ino
index 9a0c94029..6dbfcc53e 100644
--- a/sonoff/xsns_02_analog.ino
+++ b/sonoff/xsns_02_analog.ino
@@ -151,7 +151,7 @@ bool AdcCommand(void)
// Settings.adc_param_type = my_adc0;
Settings.adc_param1 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10);
Settings.adc_param2 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 3), nullptr, 10);
- Settings.adc_param3 = (int)(CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 4)) * 10000);
+ Settings.adc_param3 = (int)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 4)) * 10000);
} else { // Set default values based on current adc type
// AdcParam 2
// AdcParam 3
diff --git a/sonoff/xsns_34_hx711.ino b/sonoff/xsns_34_hx711.ino
index 47a38f7d3..8a362ddfd 100644
--- a/sonoff/xsns_34_hx711.ino
+++ b/sonoff/xsns_34_hx711.ino
@@ -204,7 +204,7 @@ bool HxCommand(void)
break;
case 6: // WeightItem
if (strstr(XdrvMailbox.data, ",") != nullptr) {
- Settings.weight_item = (unsigned long)(CharToDouble(subStr(sub_string, XdrvMailbox.data, ",", 2)) * 10);
+ Settings.weight_item = (unsigned long)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 2)) * 10);
}
show_parms = true;
break;
@@ -444,7 +444,7 @@ void HandleHxAction(void)
if (WebServer->hasArg("calibrate")) {
WebGetArg("p1", stemp1, sizeof(stemp1));
- Settings.weight_reference = (!strlen(stemp1)) ? 0 : (unsigned long)(CharToDouble(stemp1) * 1000);
+ Settings.weight_reference = (!strlen(stemp1)) ? 0 : (unsigned long)(CharToFloat(stemp1) * 1000);
HxLogUpdates();
@@ -471,7 +471,7 @@ void HxSaveSettings(void)
char tmp[100];
WebGetArg("p2", tmp, sizeof(tmp));
- Settings.weight_item = (!strlen(tmp)) ? 0 : (unsigned long)(CharToDouble(tmp) * 10000);
+ Settings.weight_item = (!strlen(tmp)) ? 0 : (unsigned long)(CharToFloat(tmp) * 10000);
HxLogUpdates();
}
diff --git a/sonoff/xsns_38_az7798.ino b/sonoff/xsns_38_az7798.ino
index 9bf97a424..5339a392f 100644
--- a/sonoff/xsns_38_az7798.ino
+++ b/sonoff/xsns_38_az7798.ino
@@ -182,7 +182,7 @@ void AzEverySecond(void)
return;
}
response_substr[j] = 0; // add null terminator
- az_temperature = CharToDouble((char*)response_substr); // units (C or F) depends on meter setting
+ az_temperature = CharToFloat((char*)response_substr); // units (C or F) depends on meter setting
if(az_response[i] == 'C') { // meter transmits in degC
az_temperature = ConvertTemp((float)az_temperature); // convert to degF, depending on settings
} else { // meter transmits in degF
@@ -232,7 +232,7 @@ void AzEverySecond(void)
return;
}
response_substr[j] = 0; // add null terminator
- az_humidity = ConvertHumidity(CharToDouble((char*)response_substr));
+ az_humidity = ConvertHumidity(CharToFloat((char*)response_substr));
}
}