Merge branch 'mega' of https://github.com/letscontrolit/ESPEasy into feature/P073_improve_7dtext_add_7ddt

This commit is contained in:
Ton Huisman
2021-02-13 16:41:46 +01:00
43 changed files with 395 additions and 203 deletions
+2
View File
@@ -51,3 +51,5 @@ tools/vagrant/pio_envlist.txt
build_output/
**/__tmpfile.cpp
src/_Custom.h
+1 -1
View File
@@ -486,7 +486,7 @@ void TinyGPSDate::commit()
}
{
const uint16_t newyear = year();
if (newyear < 2020) {
if (newyear < 2021) {
// Looks like it is an old GPS unit not working well with the 1024 week rollover.
struct tm tm;
tm.tm_year = newyear - 1900;
+4 -3
View File
@@ -100,7 +100,7 @@ lib_ignore = ${esp82xx_defaults.lib_ignore}
[core_2_7_4]
extends = esp82xx_2_6_x
platform = espressif8266@2.6.2
platform = espressif8266@2.6.3
platform_packages =
framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#2.7.4
build_flags = ${esp82xx_2_6_x.build_flags}
@@ -111,7 +111,7 @@ build_flags = ${esp82xx_2_6_x.build_flags}
; e.g. Sonoff Basic R2.
[core_2_7_4_alt_wifi]
extends = esp82xx_2_6_x
platform = espressif8266@2.6.2
platform = espressif8266@2.6.3
platform_packages =
framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#2.7.4
build_flags = ${esp82xx_2_6_x.build_flags}
@@ -120,7 +120,7 @@ build_flags = ${esp82xx_2_6_x.build_flags}
[core_2_7_4_sdk3]
extends = esp82xx_2_6_x
platform = espressif8266@2.6.2
platform = espressif8266@2.6.3
platform_packages =
framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git#2.7.4
build_flags = ${esp82xx_2_6_x.build_flags}
@@ -131,6 +131,7 @@ extends = esp82xx_2_6_x
platform = https://github.com/platformio/platform-espressif8266.git
build_flags = ${esp82xx_2_6_x.build_flags}
-DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191122
-DPHASE_LOCKED_WAVEFORM
-Wno-deprecated-declarations
platform_packages =
platformio/framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git
+1 -1
View File
@@ -21,7 +21,7 @@ pathtools==0.1.2
platformio>=5.0.1
port-for==0.3.1
pycparser==2.20
pyelftools==0.26
pyelftools==0.27
pygit2==1.2.1
Pygments==2.6.1
pyparsing==2.4.7
+7
View File
@@ -160,6 +160,10 @@
#include "src/WebServer/WebServer.h"
#ifdef PHASE_LOCKED_WAVEFORM
#include <core_esp8266_waveform.h>
#endif
#if FEATURE_ADC_VCC
ADC_MODE(ADC_VCC);
#endif
@@ -203,6 +207,9 @@ void setup()
{
#ifdef ESP8266_DISABLE_EXTRA4K
disable_extra4k_at_link_time();
#endif
#ifdef PHASE_LOCKED_WAVEFORM
enablePhaseLockedWaveform();
#endif
initWiFi();
+1 -1
View File
@@ -372,4 +372,4 @@ bool Plugin_003_pulseinit(byte Par1, byte Index, byte Mode)
return true;
}
#endif // USES_P003
#endif // USES_P003
+3 -5
View File
@@ -108,8 +108,7 @@ boolean Plugin_008(byte function, struct EventStruct *event, String& string)
{
if (Plugin_008_init && PCONFIG(2) == 0) { // PCONFIG(2) check uses inversed logic!
// Reset card id on timeout
UserVar[event->BaseVarIndex] = PCONFIG_LONG(0) & 0xFFFF;
UserVar[event->BaseVarIndex + 1] = (PCONFIG_LONG(0) >> 16) & 0xFFFF;
UserVar.setSensorTypeLong(event->TaskIndex, PCONFIG_LONG(0));
addLog(LOG_LEVEL_INFO, F("RFID : Removed Tag"));
if (PCONFIG(3) == 1) {
sendData(event);
@@ -156,15 +155,14 @@ boolean Plugin_008(byte function, struct EventStruct *event, String& string)
break;
}
unsigned long old_key = ((uint32_t) UserVar[event->BaseVarIndex]) | ((uint32_t) UserVar[event->BaseVarIndex + 1])<<16;
unsigned long old_key = UserVar.getSensorTypeLong(event->TaskIndex);
bool new_key = false;
if (PCONFIG(1) == 1) {
Plugin_008_keyBuffer = castHexAsDec(Plugin_008_keyBuffer);
}
if (old_key != Plugin_008_keyBuffer) {
UserVar[event->BaseVarIndex] = (Plugin_008_keyBuffer & 0xFFFF);
UserVar[event->BaseVarIndex + 1] = ((Plugin_008_keyBuffer >> 16) & 0xFFFF);
UserVar.setSensorTypeLong(event->TaskIndex, Plugin_008_keyBuffer);
new_key = true;
}
+1 -2
View File
@@ -520,8 +520,7 @@ boolean Plugin_016(byte function, struct EventStruct *event, String &string)
if (P016_SEND_IR_TO_CONTROLLER) sendData(event);
else {
unsigned long IRcode = results.value;
UserVar[event->BaseVarIndex] = (IRcode & 0xFFFF);
UserVar[event->BaseVarIndex + 1] = ((IRcode >> 16) & 0xFFFF);
UserVar.setSensorTypeLong(event->TaskIndex, IRcode);
sendData(event);
}
}
+3 -5
View File
@@ -121,8 +121,7 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string)
{
// Reset card id on timeout
if (PCONFIG(0) == 0) {
UserVar[event->BaseVarIndex + 0] = PCONFIG_LONG(0) && 0xFFFF;
UserVar[event->BaseVarIndex + 1] = (PCONFIG_LONG(0) >> 16) & 0xFFFF;
UserVar.setSensorTypeLong(event->TaskIndex, PCONFIG_LONG(0));
addLog(LOG_LEVEL_INFO, F("RFID : Removed Tag"));
if (PCONFIG(1) == 1) {
sendData(event);
@@ -180,12 +179,11 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string)
key <<= 8;
key += uid[i];
}
unsigned long old_key = ((uint32_t)UserVar[event->BaseVarIndex]) | ((uint32_t)UserVar[event->BaseVarIndex + 1]) << 16;
unsigned long old_key = UserVar.getSensorTypeLong(event->TaskIndex);
bool new_key = false;
if (old_key != key) {
UserVar[event->BaseVarIndex] = (key & 0xFFFF);
UserVar[event->BaseVarIndex + 1] = ((key >> 16) & 0xFFFF);
UserVar.setSensorTypeLong(event->TaskIndex, key);
new_key = true;
}
+3 -5
View File
@@ -59,8 +59,7 @@ boolean Plugin_040(byte function, struct EventStruct *event, String& string)
{
if (Plugin_040_init) {
// Reset card id on timeout
UserVar[event->BaseVarIndex] = 0;
UserVar[event->BaseVarIndex + 1] = 0;
UserVar.setSensorTypeLong(event->TaskIndex, 0);
addLog(LOG_LEVEL_INFO, F("RFID : Removed Tag"));
sendData(event);
success = true;
@@ -136,12 +135,11 @@ boolean Plugin_040(byte function, struct EventStruct *event, String& string)
// endof workaround
unsigned long key = 0, old_key = 0;
old_key = ((uint32_t) UserVar[event->BaseVarIndex]) | ((uint32_t) UserVar[event->BaseVarIndex + 1])<<16;
old_key = UserVar.getSensorTypeLong(event->TaskIndex);
for (byte i = 1; i < 5; i++) key = key | (((unsigned long) code[i] << ((4 - i) * 8)));
bool new_key = false;
if (old_key != key) {
UserVar[event->BaseVarIndex] = (key & 0xFFFF);
UserVar[event->BaseVarIndex + 1] = ((key >> 16) & 0xFFFF);
UserVar.setSensorTypeLong(event->TaskIndex, key);
new_key = true;
}
+24 -31
View File
@@ -26,8 +26,8 @@ extern "C"
# define PLUGIN_081_DEBUG false // set to true for extra log info in the debug
#endif // ifndef PLUGIN_081_DEBUG
#define PLUGIN_081_EXPRESSION_SIZE 41
#define LASTEXECUTION UserVar[event->BaseVarIndex]
#define NEXTEXECUTION UserVar[event->BaseVarIndex + 1]
#define LASTEXECUTION 0
#define NEXTEXECUTION 1
struct P081_data_struct : public PluginTaskData_base {
@@ -74,12 +74,6 @@ private:
bool _initialized = false;
};
union timeToFloat
{
time_t time;
float value;
};
String P081_getCronExpr(taskIndex_t taskIndex)
{
@@ -120,22 +114,14 @@ time_t P081_computeNextCronTime(taskIndex_t taskIndex, time_t last)
return CRON_INVALID_INSTANT;
}
time_t P081_getCronExecTime(float execTime)
time_t P081_getCronExecTime(taskIndex_t taskIndex, byte varNr)
{
timeToFloat converter;
converter.value = execTime;
return converter.time;
return static_cast<time_t>(UserVar.getUint32(taskIndex, varNr));
}
void P081_setCronExecTimes(struct EventStruct *event, time_t lastExecTime, time_t nextExecTime) {
timeToFloat converter;
converter.time = lastExecTime;
LASTEXECUTION = converter.value;
converter.time = nextExecTime;
NEXTEXECUTION = converter.value;
UserVar.setUint32(event->TaskIndex, LASTEXECUTION, static_cast<uint32_t>(lastExecTime));
UserVar.setUint32(event->TaskIndex, NEXTEXECUTION, static_cast<uint32_t>(nextExecTime));
}
time_t P081_getCurrentTime()
@@ -151,8 +137,8 @@ void P081_check_or_init(struct EventStruct *event)
{
if (node_time.systemTimePresent()) {
const time_t current_time = P081_getCurrentTime();
time_t last_exec_time = P081_getCronExecTime(LASTEXECUTION);
time_t next_exec_time = P081_getCronExecTime(NEXTEXECUTION);
time_t last_exec_time = P081_getCronExecTime(event->TaskIndex, LASTEXECUTION);
time_t next_exec_time = P081_getCronExecTime(event->TaskIndex, NEXTEXECUTION);
// Must check if the values of LASTEXECUTION and NEXTEXECUTION make sense.
// These can be invalid values from a reboot, or simply contain uninitialized values.
@@ -250,11 +236,18 @@ boolean Plugin_081(byte function, struct EventStruct *event, String& string)
success = true;
break;
}
case PLUGIN_WEBFORM_SHOW_VALUES:
case PLUGIN_FORMAT_USERVAR:
{
pluginWebformShowValue(ExtraTaskSettings.TaskDeviceValueNames[0], P081_formatExecTime(LASTEXECUTION));
pluginWebformShowValue(ExtraTaskSettings.TaskDeviceValueNames[1], P081_formatExecTime(NEXTEXECUTION), false);
success = true;
switch (event->idx) {
case 0:
string = P081_formatExecTime(event->TaskIndex, LASTEXECUTION);
break;
case 1:
string = P081_formatExecTime(event->TaskIndex, NEXTEXECUTION);
break;
}
success = string.length() > 0;
break;
}
@@ -291,7 +284,7 @@ boolean Plugin_081(byte function, struct EventStruct *event, String& string)
// code to be executed once a second. Tasks which do not require fast response can be added here
if (node_time.systemTimePresent()) {
P081_check_or_init(event);
time_t next_exec_time = P081_getCronExecTime(NEXTEXECUTION);
time_t next_exec_time = P081_getCronExecTime(event->TaskIndex, NEXTEXECUTION);
if (next_exec_time != CRON_INVALID_INSTANT) {
const time_t current_time = P081_getCurrentTime();
@@ -386,8 +379,8 @@ void PrintCronExp(struct cron_expr_t e) {
#endif // if PLUGIN_081_DEBUG
String P081_formatExecTime(float execTime_f) {
time_t exec_time = P081_getCronExecTime(execTime_f);
String P081_formatExecTime(taskIndex_t taskIndex, byte varNr) {
time_t exec_time = P081_getCronExecTime(taskIndex, varNr);
if (exec_time != CRON_INVALID_INSTANT) {
return ESPEasy_time::getDateTimeString(*gmtime(&exec_time));
@@ -407,9 +400,9 @@ void P081_html_show_cron_expr(struct EventStruct *event) {
addHtml(error);
} else {
addRowLabel(F("Last Exec Time"));
addHtml(P081_formatExecTime(LASTEXECUTION));
addHtml(P081_formatExecTime(event->TaskIndex, LASTEXECUTION));
addRowLabel(F("Next Exec Time"));
addHtml(P081_formatExecTime(NEXTEXECUTION));
addHtml(P081_formatExecTime(event->TaskIndex, NEXTEXECUTION));
}
}
}
+2 -2
View File
@@ -71,8 +71,8 @@ String Command_DateTime(struct EventStruct *event, const char *Line)
struct tm tm;
int yr, mnth, d;
sscanf(TmpStr1.c_str(), "%4d-%2d-%2d", &yr, &mnth, &d);
tm.tm_year = yr - 1970;
tm.tm_mon = mnth;
tm.tm_year = yr - 1900;
tm.tm_mon = mnth - 1; // tm_mon starts at 0
tm.tm_mday = d;
if (GetArgv(Line, TmpStr1, 3)) {
+2
View File
@@ -21,12 +21,14 @@
#define BUILD 20112 // git version e.g. "20103" can be read as "2.1.03" (stored in int16_t)
#ifndef BUILD_NOTES
#if defined(ESP8266)
# define BUILD_NOTES " - Mega"
#endif // if defined(ESP8266)
#if defined(ESP32)
# define BUILD_NOTES " - Mega32"
#endif // if defined(ESP32)
#endif
#ifndef BUILD_GIT
# define BUILD_GIT "(custom)"
+2
View File
@@ -78,6 +78,7 @@ String getPluginFunctionName(int function) {
case PLUGIN_WEBFORM_SAVE: return F("WEBFORM_SAVE");
case PLUGIN_WEBFORM_LOAD: return F("WEBFORM_LOAD");
case PLUGIN_WEBFORM_SHOW_VALUES: return F("WEBFORM_SHOW_VALUES");
case PLUGIN_FORMAT_USERVAR: return F("FORMAT_USERVAR");
case PLUGIN_GET_DEVICENAME: return F("GET_DEVICENAME");
case PLUGIN_GET_DEVICEVALUENAMES: return F("GET_DEVICEVALUENAMES");
case PLUGIN_WRITE: return F("WRITE");
@@ -110,6 +111,7 @@ bool mustLogFunction(int function) {
case PLUGIN_WEBFORM_SAVE: return false;
case PLUGIN_WEBFORM_LOAD: return false;
case PLUGIN_WEBFORM_SHOW_VALUES: return false;
case PLUGIN_FORMAT_USERVAR: return false;
case PLUGIN_GET_DEVICENAME: return false;
case PLUGIN_GET_DEVICEVALUENAMES: return false;
case PLUGIN_WRITE: return true;
+90
View File
@@ -0,0 +1,90 @@
#include "../DataStructs/UserVarStruct.h"
#include "../ESPEasyCore/ESPEasy_Log.h"
#include "../Globals/Plugins.h"
UserVarStruct::UserVarStruct()
{
_data.resize(VARS_PER_TASK * TASKS_MAX, 0.0f);
}
// Implementation of [] operator. This function must return a
// reference as array element can be put on left side
float& UserVarStruct::operator[](unsigned int index)
{
if (index >= _data.size()) {
static float errorvalue = NAN;
addLog(LOG_LEVEL_ERROR, F("UserVar index out of range"));
return errorvalue;
}
return _data.at(index);
}
const float& UserVarStruct::operator[](unsigned int index) const
{
if (index >= _data.size()) {
static float errorvalue = NAN;
addLog(LOG_LEVEL_ERROR, F("UserVar index out of range"));
return errorvalue;
}
return _data.at(index);
}
unsigned long UserVarStruct::getSensorTypeLong(taskIndex_t taskIndex) const
{
unsigned long value = 0;
if (validTaskIndex(taskIndex)) {
const unsigned int baseVarIndex = taskIndex * VARS_PER_TASK;
value = static_cast<unsigned long>(_data[baseVarIndex]) + (static_cast<unsigned long>(_data[baseVarIndex + 1]) << 16);
}
return value;
}
void UserVarStruct::setSensorTypeLong(taskIndex_t taskIndex, unsigned long value)
{
if (!validTaskIndex(taskIndex)) {
return;
}
const unsigned int baseVarIndex = taskIndex * VARS_PER_TASK;
_data[baseVarIndex] = value & 0xFFFF;
_data[baseVarIndex + 1] = (value >> 16) & 0xFFFF;
}
uint32_t UserVarStruct::getUint32(taskIndex_t taskIndex, byte varNr) const
{
if (!validTaskIndex(taskIndex) || (varNr >= VARS_PER_TASK)) {
addLog(LOG_LEVEL_ERROR, F("UserVar index out of range"));
return 0;
}
const unsigned int baseVarIndex = taskIndex * VARS_PER_TASK;
uint32_t res;
memcpy(&res, &_data[baseVarIndex + varNr], sizeof(float));
return res;
}
void UserVarStruct::setUint32(taskIndex_t taskIndex, byte varNr, uint32_t value)
{
if (!validTaskIndex(taskIndex) || (varNr >= VARS_PER_TASK)) {
addLog(LOG_LEVEL_ERROR, F("UserVar index out of range"));
return;
}
const unsigned int baseVarIndex = taskIndex * VARS_PER_TASK;
// Store in a new variable to prevent
// warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
float tmp;
memcpy(&tmp, &value, sizeof(float));
_data[baseVarIndex + varNr] = tmp;
}
size_t UserVarStruct::getNrElements() const
{
return _data.size();
}
byte * UserVarStruct::get()
{
return (byte *)(&_data[0]);
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef DATASTRUCTS_USERVARSTRUCT_H
#define DATASTRUCTS_USERVARSTRUCT_H
#include "../../ESPEasy_common.h"
#include "../DataTypes/TaskIndex.h"
struct UserVarStruct {
UserVarStruct();
// Overloading [] operator to access elements in array style
float & operator[](unsigned int index);
const float & operator[](unsigned int index) const;
unsigned long getSensorTypeLong(taskIndex_t taskIndex) const;
void setSensorTypeLong(taskIndex_t taskIndex,
unsigned long value);
// 32 bit unsigned int stored at the memory location of the float
uint32_t getUint32(taskIndex_t taskIndex,
byte varNr) const;
void setUint32(taskIndex_t taskIndex,
byte varNr,
uint32_t value);
size_t getNrElements() const;
byte * get();
private:
std::vector<float>_data;
};
#endif // ifndef DATASTRUCTS_USERVARSTRUCT_H
@@ -43,6 +43,7 @@
#define PLUGIN_WEBFORM_SHOW_SERIAL_PARAMS 35 // When needed, show additional parameters like baudrate or specific serial config
#define PLUGIN_MQTT_CONNECTION_STATE 36 // Signal when connection to MQTT broker is re-established
#define PLUGIN_MQTT_IMPORT 37 // For P037 MQTT import
#define PLUGIN_FORMAT_USERVAR 38 // Allow plugin specific formatting of a task variable (event->idx = variable)
+1 -1
View File
@@ -386,7 +386,7 @@ String getLWT_topic(const ControllerSettingsStruct& ControllerSettings) {
LWTTopic = ControllerSettings.Subscribe;
LWTTopic += F("/LWT");
}
LWTTopic.replace(F("/#"), F("/status"));
LWTTopic.replace(String(F("/#")), String(F("/status")));
parseSystemVariables(LWTTopic, false);
}
return LWTTopic;
+6 -1
View File
@@ -94,6 +94,7 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) {
processEthernetConnected();
break;
case SYSTEM_EVENT_ETH_GOT_IP:
eth_connected = true;
if (loglevelActiveFor(LOG_LEVEL_INFO))
{
String log = F("ETH MAC: ");
@@ -114,7 +115,6 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) {
log += F("Mbps");
addLog(LOG_LEVEL_INFO, log);
}
eth_connected = true;
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
addLog(LOG_LEVEL_ERROR, F("ETH Disconnected"));
@@ -130,6 +130,11 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) {
break;
#endif //HAS_ETHERNET
default:
{
String log = F("UNKNOWN EVENT: ");
log += event;
addLog(LOG_LEVEL_ERROR, log);
}
break;
}
}
+1 -1
View File
@@ -119,7 +119,7 @@ void process_serialWriteBuffer() {
if (snip < bytes_to_write) { bytes_to_write = snip; }
while (bytes_to_write > 0) {
while (bytes_to_write > 0 && !serialWriteBuffer.empty()) {
const char c = serialWriteBuffer.front();
Serial.write(c);
serialWriteBuffer.pop_front();
+1
View File
@@ -580,6 +580,7 @@ bool PluginCall(byte Function, struct EventStruct *event, String& str)
case PLUGIN_WEBFORM_SHOW_CONFIG:
case PLUGIN_WEBFORM_SHOW_I2C_PARAMS:
case PLUGIN_WEBFORM_SHOW_SERIAL_PARAMS:
case PLUGIN_FORMAT_USERVAR:
case PLUGIN_SET_CONFIG:
case PLUGIN_SET_DEFAULTS:
+3 -1
View File
@@ -3,7 +3,9 @@
std::map<uint32_t, double> customFloatVar;
float UserVar[VARS_PER_TASK * TASKS_MAX];
//float UserVar[VARS_PER_TASK * TASKS_MAX];
UserVarStruct UserVar;
double getCustomFloatVar(uint32_t index) {
+5 -1
View File
@@ -3,6 +3,8 @@
#include "../CustomBuild/ESPEasyLimits.h"
#include "../DataStructs/UserVarStruct.h"
#include <map>
/*********************************************************************************************\
@@ -28,7 +30,9 @@ bool getNextCustomFloatVar(uint32_t& index, double& value);
* let,1,10
* if %v1%=10 do ...
\*********************************************************************************************/
extern float UserVar[VARS_PER_TASK * TASKS_MAX];
//extern float UserVar[VARS_PER_TASK * TASKS_MAX];
extern UserVarStruct UserVar;
+6 -6
View File
@@ -47,7 +47,7 @@
// these offsets are in blocks, bytes = blocks * 4
// 64 RTCStruct max 40 bytes: ( 74 - 64 ) * 4
// 74 UserVar
// 122 UserVar checksum: RTC_BASE_USERVAR + (sizeof(UserVar) / 4)
// 122 UserVar checksum: RTC_BASE_USERVAR + UserVar.getNrElements()
// 128 Cache (C016) metadata 4 blocks
// 132 Cache (C016) data 6 blocks per sample => max 10 samples
@@ -87,7 +87,7 @@ void initRTC()
RTC.init();
saveToRTC();
for (size_t i = 0; i < sizeof(UserVar) / sizeof(float); ++i) {
for (size_t i = 0; i < UserVar.getNrElements(); ++i) {
UserVar[i] = 0.0f;
}
saveUserVarToRTC();
@@ -119,8 +119,8 @@ bool saveUserVarToRTC()
#else // if defined(ESP32)
// addLog(LOG_LEVEL_DEBUG, F("RTCMEM: saveUserVarToRTC"));
byte *buffer = (byte *)&UserVar;
size_t size = sizeof(UserVar);
byte *buffer = UserVar.get();
size_t size = UserVar.getNrElements() * sizeof(float);
uint32_t sum = calc_CRC32(buffer, size);
bool ret = system_rtc_mem_write(RTC_BASE_USERVAR, buffer, size);
ret &= system_rtc_mem_write(RTC_BASE_USERVAR + (size >> 2), (byte *)&sum, 4);
@@ -138,8 +138,8 @@ bool readUserVarFromRTC()
#else // if defined(ESP32)
// addLog(LOG_LEVEL_DEBUG, F("RTCMEM: readUserVarFromRTC"));
byte *buffer = (byte *)&UserVar;
size_t size = sizeof(UserVar);
byte *buffer = UserVar.get();
size_t size = UserVar.getNrElements() * sizeof(float);
bool ret = system_rtc_mem_read(RTC_BASE_USERVAR, buffer, size);
uint32_t sumRAM = calc_CRC32(buffer, size);
uint32_t sumRTC = 0;
+12 -31
View File
@@ -40,13 +40,7 @@ struct tm ESPEasy_time::addSeconds(const struct tm& ts, int seconds, bool toLoca
void ESPEasy_time::breakTime(unsigned long timeInput, struct tm& tm) {
uint8_t year;
uint8_t month, monthLength;
uint32_t time;
unsigned long days;
const uint8_t monthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
time = (uint32_t)timeInput;
uint32_t time = (uint32_t)timeInput;
tm.tm_sec = time % 60;
time /= 60; // now it is minutes
tm.tm_min = time % 60;
@@ -55,40 +49,27 @@ void ESPEasy_time::breakTime(unsigned long timeInput, struct tm& tm) {
time /= 24; // now it is days
tm.tm_wday = ((time + 4) % 7) + 1; // Sunday is day 1
year = 0;
days = 0;
int year = 1970;
unsigned long days = 0;
while ((unsigned)(days += (isLeapYear(year) ? 366 : 365)) <= time) {
year++;
}
tm.tm_year = year; // year is offset from 1970
tm.tm_year = year - 1900; // tm_year starts at 1900
days -= isLeapYear(year) ? 366 : 365;
time -= days; // now it is days in this year, starting at 0
days = 0;
month = 0;
monthLength = 0;
uint8_t month = 0;
for (month = 0; month < 12; month++) {
if (month == 1) { // february
if (isLeapYear(year)) {
monthLength = 29;
} else {
monthLength = 28;
}
} else {
monthLength = monthDays[month];
}
const uint8_t monthLength = getMonthDays(year, month);
if (time >= monthLength) {
time -= monthLength;
} else {
break;
}
}
tm.tm_mon = month + 1; // jan is month 1
tm.tm_mday = time + 1; // day of month
tm.tm_mon = month; // Jan is month 0
tm.tm_mday = time + 1; // day of month start at 1
}
@@ -415,9 +396,9 @@ String ESPEasy_time::getDateString(char delimiter) const
String ESPEasy_time::getDateString(const struct tm& ts, char delimiter) {
// time format example with ':' delimiter: 23:59:59 (HH:MM:SS)
char DateString[20]; // 19 digits plus the null char
const int year = 1970 + ts.tm_year;
const int year = 1900 + ts.tm_year;
sprintf_P(DateString, PSTR("%4d%c%02d%c%02d"), year, delimiter, ts.tm_mon, delimiter, ts.tm_mday);
sprintf_P(DateString, PSTR("%4d%c%02d%c%02d"), year, delimiter, ts.tm_mon + 1, delimiter, ts.tm_mday);
return DateString;
}
@@ -494,7 +475,7 @@ int ESPEasy_time::year(unsigned long t)
struct tm tmp;
breakTime(t, tmp);
return 1970 + tmp.tm_year;
return 1900 + tmp.tm_year;
}
int ESPEasy_time::weekday(unsigned long t)
@@ -615,7 +596,7 @@ int ESPEasy_time::dayOfYear(int year, int month, int day) {
}
void ESPEasy_time::calcSunRiseAndSet() {
int doy = dayOfYear(tm.tm_year, tm.tm_mon, tm.tm_mday);
int doy = dayOfYear(tm.tm_year, tm.tm_mon + 1, tm.tm_mday);
float eqt = equationOfTime(doy);
float dec = sunDeclination(doy);
float da = diurnalArc(dec, Settings.Latitude);
+2 -2
View File
@@ -94,13 +94,13 @@ static String weekday_str(int wday);
// Get current year.
int year() const
{
return 1970 + tm.tm_year;
return 1900 + tm.tm_year;
}
// Get current month
byte month() const
{
return tm.tm_mon;
return tm.tm_mon + 1; // tm_mon starts at 0
}
// Get current day of the month
+29 -16
View File
@@ -13,7 +13,18 @@
bool isLeapYear(int year) {
return (((1970 + year) > 0) && !((1970 + year) % 4) && (((1970 + year) % 100) || !((1970 + year) % 400)));
return ((year > 0) && !(year % 4) && ((year % 100) || !(year % 400)));
}
uint8_t getMonthDays(int year, uint8_t month) {
const uint8_t monthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (month == 1 && isLeapYear(year)) {
return 29;
}
if (month > 11) {
return 0;
}
return monthDays[month];
}
/********************************************************************************************\
@@ -24,32 +35,34 @@ uint32_t makeTime(const struct tm& tm) {
// assemble time elements into uint32_t
// note year argument is offset from 1970 (see macros in time.h to convert to other formats)
// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9
const uint8_t monthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int i;
uint32_t seconds;
const int tm_year = tm.tm_year + 1900;
// seconds from 1970 till 1 jan 00:00:00 of the given year
seconds = tm.tm_year * (SECS_PER_DAY * 365);
// tm_year starts at 1900
uint32_t seconds = 1577836800; // 01/01/2020 @ 12:00am (UTC)
int year = 2020;
if (tm_year < year) {
// Just in case this function is called on old dates
year = 1970;
seconds = 0;
}
for (i = 0; i < tm.tm_year; i++) {
if (isLeapYear(i)) {
seconds += SECS_PER_DAY; // add extra days for leap years
for (; year < tm_year; ++year) {
seconds += SECS_PER_DAY * 365;
if (isLeapYear(year)) {
seconds += SECS_PER_DAY; // add extra days for leap years
}
}
// add days for this year, months start from 1
for (i = 1; i < tm.tm_mon; i++) {
if ((i == 2) && isLeapYear(tm.tm_year)) {
seconds += SECS_PER_DAY * 29;
} else {
seconds += SECS_PER_DAY * monthDays[i - 1]; // monthDay array starts from 0
}
// add days for this year, months start from 0
for (int i = 0; i < tm.tm_mon; i++) {
seconds += SECS_PER_DAY * getMonthDays(tm_year, i);
}
seconds += (tm.tm_mday - 1) * SECS_PER_DAY;
seconds += tm.tm_hour * SECS_PER_HOUR;
seconds += tm.tm_min * SECS_PER_MIN;
seconds += tm.tm_sec;
return (uint32_t)seconds;
return seconds;
}
+4
View File
@@ -59,6 +59,10 @@ bool usecTimeOutReached(unsigned long timer);
\*********************************************************************************************/
bool isLeapYear(int year);
// Get number of days in a month.
// Month starts at 0 for January.
uint8_t getMonthDays(int year, uint8_t month);
uint32_t makeTime(const struct tm& tm);
/********************************************************************************************\
+3 -3
View File
@@ -90,7 +90,7 @@ void ESPEasy_time_zone::logTimeZoneInfo() {
// *----------------------------------------------------------------------*/
uint32_t ESPEasy_time_zone::calcTimeChangeForRule(const TimeChangeRule& r, int yr)
{
uint8_t m = r.month; // temp copies of r.month and r.week
uint8_t m = r.month;
uint8_t w = r.week;
if (w == 0) // is this a "Last week" rule?
@@ -109,8 +109,8 @@ uint32_t ESPEasy_time_zone::calcTimeChangeForRule(const TimeChangeRule& r, int y
tm.tm_min = 0;
tm.tm_sec = 0;
tm.tm_mday = 1;
tm.tm_mon = m;
tm.tm_year = yr - 1970;
tm.tm_mon = m - 1; // TimeChangeRule month starts at 1
tm.tm_year = yr - 1900;
uint32_t t = makeTime(tm);
// add offset from the first of the month to r.dow, and offset for the given week
+44 -28
View File
@@ -151,14 +151,40 @@ bool mustConsiderAsString(NumericalType detectedType) {
case NumericalType::HexadecimalUInt:
case NumericalType::BinaryUint:
return true; // Has '0x' or '0b' as prefix
case NumericalType::Unknown:
return true; // Apparently it is not a numerical, when printed consider it a string
}
return false;
}
bool mustConsiderAsString(const String& value) {
const unsigned int length = value.length();
if (length == 0) return true;
unsigned int i = 0;
char c = value[i];
if (c == '+' || c == '-') {
++i;
if (length == i) return true;
c = value[i];
}
bool dotFound = false;
for (; i < length; ++i) {
if (c == '.') {
if (dotFound) {
return true;
} else {
dotFound = true;
}
} else {
if (!isdigit(c)) {
return true;
}
}
c = value[i];
}
return i < length;
}
String getNumerical(const String& tBuf, NumericalType requestedType, NumericalType& detectedType) {
detectedType = NumericalType::Unknown;
const unsigned int bufLength = tBuf.length();
unsigned int firstDec = 0;
String result;
@@ -170,12 +196,13 @@ String getNumerical(const String& tBuf, NumericalType requestedType, NumericalTy
if (firstDec >= bufLength) { return result; }
bool decPt = false;
detectedType = NumericalType::Integer;
char c = tBuf.charAt(firstDec);
if ((c == '+') || (c == '-')) {
if ((requestedType != NumericalType::HexadecimalUInt) &&
(requestedType != NumericalType::BinaryUint)) {
detectedType = NumericalType::Integer;
if (c == '-') {
result += c;
}
@@ -187,54 +214,37 @@ String getNumerical(const String& tBuf, NumericalType requestedType, NumericalTy
}
if (c == '0') {
++firstDec;
result += c;
if (firstDec < bufLength) {
c = tBuf.charAt(firstDec);
if ((c == 'x') || (c == 'X')) {
++firstDec;
result += '0';
result += c;
detectedType = NumericalType::HexadecimalUInt;
} else if ((c == 'b') || (c == 'B')) {
++firstDec;
result += '0';
result += c;
detectedType = NumericalType::BinaryUint;
} else if (NumericalType::Integer == requestedType) {
// Allow leading zeroes in Integer types (e.g. in time notation)
detectedType = NumericalType::Integer;
while (c == '0' && firstDec < bufLength) {
// N.B. intentional "reverse order" of reading char and ++firstDec
c = tBuf.charAt(firstDec);
++firstDec;
}
if (firstDec >= bufLength) {
result += '0';
}
}
} else if (NumericalType::FloatingPoint == requestedType && c == '.') {
// Only floating point numbers should start with '0.'
// All other combinations are not valid.
++firstDec;
result += '0';
result += c;
decPt = true;
detectedType = NumericalType::FloatingPoint;
} else {
detectedType = NumericalType::Integer;
result += '0';
return result;
}
}
} else if (NumericalType::Unknown == detectedType) {
if (NumericalType::HexadecimalUInt == requestedType && isxdigit(c)) {
// Should be careful here, as we're patching a string,
// which may yield different result when the requested type is not specifically hex.
detectedType = NumericalType::HexadecimalUInt;
result = F("0x");
} else if (isdigit(c)) {
detectedType = NumericalType::Integer;
}
}
for (unsigned int x = firstDec; x < bufLength; ++x) {
@@ -270,9 +280,6 @@ String getNumerical(const String& tBuf, NumericalType requestedType, NumericalTy
return result;
}
break;
case NumericalType::Unknown:
// If we still have no clue what it is by now, return it.
return result;
}
}
result += c;
@@ -283,8 +290,17 @@ String getNumerical(const String& tBuf, NumericalType requestedType, NumericalTy
bool isNumerical(const String& tBuf, NumericalType& detectedType) {
NumericalType requestedType = NumericalType::FloatingPoint;
const String result = getNumerical(tBuf, requestedType, detectedType);
if (NumericalType::Unknown == detectedType) {
return false;
if (result.length() > 0)
{
String tmp(tBuf);
tmp.trim(); // remove leading and trailing spaces
// Resulting size should be the same size as the given string.
// Not sure if it is possible to have a longer result, but better be sure to also allow for larger resulting strings.
// For example ".123" -> "0.123"
return result.length() >= tmp.length();
}
return result.length() > 0;
}
+1 -1
View File
@@ -23,7 +23,6 @@ bool validDoubleFromString(const String& tBuf, double& result);
// Numerical types sorted from least specific to most specific.
enum class NumericalType {
Unknown,
FloatingPoint,
Integer,
HexadecimalUInt,
@@ -31,6 +30,7 @@ enum class NumericalType {
};
bool mustConsiderAsString(NumericalType detectedType);
bool mustConsiderAsString(const String& value);
String getNumerical(const String& tBuf, NumericalType requestedType, NumericalType& detectedType);
+10 -1
View File
@@ -165,7 +165,16 @@ String getPinStateJSON(bool search, uint32_t key, const String& log, int16_t noS
String reply;
reply.reserve(128);
reply += F("{\n\"log\": \"");
reply += log.substring(7, 32); // truncate to 25 chars, max MQTT message size = 128 including header...
{
// truncate to 25 chars, max MQTT message size = 128 including header...
int colonPos = log.indexOf(':');
if (colonPos == -1) {
colonPos = 0;
}
String tmp = log.substring(colonPos, colonPos + 25);
tmp.trim();
reply += tmp;
}
reply += F("\",\n\"plugin\": ");
reply += getPluginFromKey(key);
reply += F(",\n\"pin\": ");
+17 -8
View File
@@ -241,6 +241,18 @@ String doFormatUserVar(struct EventStruct *event, byte rel_index, bool mustCheck
return "0";
}
{
// First try to format using the plugin specific formatting.
String result;
EventStruct tempEvent(*event);
tempEvent.idx = rel_index;
PluginCall(PLUGIN_FORMAT_USERVAR, &tempEvent, result);
if (result.length() > 0) {
return result;
}
}
const byte valueCount = getValueCountForTask(event->TaskIndex);
Sensor_VType sensorType = event->getSensorType();
@@ -264,7 +276,7 @@ String doFormatUserVar(struct EventStruct *event, byte rel_index, bool mustCheck
switch (sensorType) {
case Sensor_VType::SENSOR_TYPE_LONG:
return String((unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16));
return String(UserVar.getSensorTypeLong(event->TaskIndex));
case Sensor_VType::SENSOR_TYPE_STRING:
return event->String2;
@@ -386,10 +398,7 @@ String to_json_object_value(const String& object, const String& value) {
result += F("\"\"");
return result;
}
NumericalType detectedType;
bool isNum = isNumerical(value, detectedType);
if (!isNum || mustConsiderAsString(detectedType)) {
if (mustConsiderAsString(value)) {
// Is not a numerical value, or BIN/HEX notation, thus wrap with quotes
if ((value.indexOf('\n') != -1) || (value.indexOf('\r') != -1) || (value.indexOf('"') != -1)) {
// Must replace characters, so make a deepcopy
@@ -461,13 +470,13 @@ bool safe_strncpy(char *dest, const char *source, size_t max_size) {
bool result = true;
memset(dest, 0, max_size);
size_t str_length = strlen(source);
size_t str_length = strlen_P(source);
if (str_length >= max_size) {
str_length = max_size;
result = false;
}
strncpy(dest, source, str_length);
strncpy_P(dest, source, str_length);
dest[max_size - 1] = 0;
return result;
}
@@ -768,7 +777,7 @@ void parseEventVariables(String& s, struct EventStruct *event, boolean useURLenc
if (validTaskIndex(event->TaskIndex)) {
if (s.indexOf(F("%val")) != -1) {
if (event->getSensorType() == Sensor_VType::SENSOR_TYPE_LONG) {
SMART_REPL(F("%val1%"), String((unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)))
SMART_REPL(F("%val1%"), String(UserVar.getSensorTypeLong(event->TaskIndex)))
} else {
for (byte i = 0; i < getValueCountForTask(event->TaskIndex); ++i) {
String valstr = F("%val");
+17 -19
View File
@@ -105,7 +105,9 @@ bool WiFi_AP_CandidatesList::getNext() {
if (mustPop) {
known_it = known.begin();
candidates.pop_front();
if (!candidates.empty()) {
candidates.pop_front();
}
}
return true;
}
@@ -176,30 +178,26 @@ void WiFi_AP_CandidatesList::addFromRTC() {
return;
}
WiFi_AP_Candidate tmp(RTC.lastWiFiSettingsIndex, ssid, key);
candidates.emplace_front(RTC.lastWiFiSettingsIndex, ssid, key);
candidates.front().setBSSID(RTC.lastBSSID);
candidates.front().rssi = -1; // Set to best possible RSSI so it is tried first.
candidates.front().channel = RTC.lastWiFiChannel;
tmp.setBSSID(RTC.lastBSSID);
if (!tmp.bssid_set()) return;
if (!candidates.front().usable() || !candidates.front().allowQuickConnect()) {
candidates.pop_front();
return;
}
// This is not taken from a scan, so no idea of the used encryption.
// Try to find a matching BSSID to get the encryption.
bool matchfound = false;
for (auto it = candidates.begin(); !matchfound && it != candidates.end(); ++it) {
if (tmp == *it) {
matchfound = true;
tmp = *it;
for (auto it = candidates.begin(); it != candidates.end(); ++it) {
if ((it->rssi != -1) && candidates.front() == *it) {
candidates.front().enc_type = it->enc_type;
return;
}
}
if (!matchfound) {
if (currentCandidate == tmp) {
tmp = currentCandidate;
}
}
tmp.channel = RTC.lastWiFiChannel;
tmp.rssi = -1; // Set to best possible RSSI so it is tried first.
if (tmp.usable() && tmp.allowQuickConnect()) {
candidates.push_front(tmp);
if (currentCandidate == candidates.front()) {
candidates.front().enc_type = currentCandidate.enc_type;
}
}
+1 -1
View File
@@ -83,7 +83,7 @@ String formatDomoticzSensorType(struct EventStruct *event) {
values = formatUserVarDomoticz(event, 0);
break;
case Sensor_VType::SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
values = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
values = UserVar.getSensorTypeLong(event->TaskIndex);
break;
case Sensor_VType::SENSOR_TYPE_DUAL: // any sensor that uses two simple values
values = formatUserVarDomoticz(event, 0);
+1 -1
View File
@@ -44,7 +44,7 @@ String getPackedFromPlugin(struct EventStruct *event, uint8_t sampleSetCount)
{
case Sensor_VType::SENSOR_TYPE_LONG:
{
unsigned long longval = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
unsigned long longval = UserVar.getSensorTypeLong(event->TaskIndex);
packed += LoRa_addInt(longval, PackedData_uint32);
break;
}
+2 -2
View File
@@ -161,8 +161,8 @@ bool P082_data_struct::getDateTime(struct tm& dateTime, uint32_t& age, bool& pps
if (!gps->date.isValid() || !gps->time.isValid()) {
return false;
}
dateTime.tm_year = gps->date.year() - 1970;
dateTime.tm_mon = gps->date.month();
dateTime.tm_year = gps->date.year() - 1900;
dateTime.tm_mon = gps->date.month() - 1; // GPS month starts at 1, tm_mon at 0
dateTime.tm_mday = gps->date.day();
dateTime.tm_hour = gps->time.hour();
File diff suppressed because one or more lines are too long
+8 -2
View File
@@ -310,10 +310,16 @@ void handle_json()
for (byte x = 0; x < valueCount; x++)
{
addHtml('{');
const String value = formatUserVarNoCheck(TaskIndex, x);
byte nrDecimals = ExtraTaskSettings.TaskDeviceValueDecimals[x];
if (mustConsiderAsString(value)) {
// Flag as not to treat as a float
nrDecimals = 255;
}
stream_next_json_object_value(F("ValueNumber"), String(x + 1));
stream_next_json_object_value(F("Name"), String(ExtraTaskSettings.TaskDeviceValueNames[x]));
stream_next_json_object_value(F("NrDecimals"), String(ExtraTaskSettings.TaskDeviceValueDecimals[x]));
stream_last_json_object_value(F("Value"), formatUserVarNoCheck(TaskIndex, x));
stream_next_json_object_value(F("NrDecimals"), String(nrDecimals));
stream_last_json_object_value(F("Value"), value);
if (x < (valueCount - 1)) {
addHtml(F(",\n"));
+12 -8
View File
File diff suppressed because one or more lines are too long
+4 -2
View File
@@ -41,7 +41,9 @@ function loopDeLoop(timeForNext, activeRequests) {
if (valueEntry !== 'TypeError') {
tempValue = data.Sensors[c].TaskValues[k].Value;
decimalsValue = data.Sensors[c].TaskValues[k].NrDecimals;
tempValue = parseFloat(tempValue).toFixed(decimalsValue);
if (decimalsValue < 255) {
tempValue = parseFloat(tempValue).toFixed(decimalsValue);
}
var valueID = 'value_' + (data.Sensors[c].TaskNumber - 1) + '_' + (data.Sensors[c].TaskValues[k].ValueNumber - 1);
var valueNameID = 'valuename_' + (data.Sensors[c].TaskNumber - 1) + '_' + (data.Sensors[c].TaskValues[k].ValueNumber - 1);
var valueElement = document.getElementById(valueID);
@@ -72,4 +74,4 @@ function loopDeLoop(timeForNext, activeRequests) {
check = 1;
}
}, timeForNext);
}
}
+20 -9
View File
@@ -1,6 +1,14 @@
Import("env")
import os
import glob
import filecmp
def do_concat_cpp_files(cpp_files, output_file):
with open(output_file, 'wb') as newf:
for filename in cpp_files:
with open(filename, 'rb') as hf:
newf.write(hf.read())
newf.write(os.linesep.encode()) # append newline to separate files.
def concat_cpp_files(path_to_concat):
@@ -15,13 +23,11 @@ def concat_cpp_files(path_to_concat):
os.makedirs(cpp_path_out)
tmp_cpp_file = os.path.join(cpp_path_out, '__tmpfile.cpp')
tmp2_cpp_file = os.path.join(cpp_path_out, '__tmpfile.cpp.test')
print("\u001b[32m Concat {}/*.cpp to {} \u001b[0m".format(cpp_path, tmp_cpp_file))
if os.path.exists(tmp_cpp_file):
os.remove(tmp_cpp_file)
for root, dirs, files in os.walk(cpp_path):
for file in files:
if file.endswith('.cpp'):
@@ -29,13 +35,18 @@ def concat_cpp_files(path_to_concat):
cpp_files.append(fullname)
print("\u001b[33m Add: \u001b[0m {}".format(fullname))
if os.path.exists(tmp_cpp_file):
do_concat_cpp_files(cpp_files, tmp2_cpp_file)
if filecmp.cmp(tmp_cpp_file, tmp2_cpp_file):
print("\u001b[32m Files not changed, will not touch __tmpfile.cpp \u001b[0m")
os.remove(tmp2_cpp_file)
else:
os.remove(tmp_cpp_file)
os.rename(tmp2_cpp_file, tmp_cpp_file)
else:
do_concat_cpp_files(cpp_files, tmp_cpp_file)
with open(tmp_cpp_file,'wb') as newf:
for filename in cpp_files:
with open(filename,'rb') as hf:
newf.write(hf.read())
newf.write(os.linesep.encode()) #append newline to separate files.
print("\u001b[32m ------------------------------- \u001b[0m")
+1 -1
View File
@@ -24,4 +24,4 @@ def clear_all_concat_cpp_files(source, target, env):
print("\u001b[32m ------------------------------ \u001b[0m")
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [clear_all_concat_cpp_files])
#env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [clear_all_concat_cpp_files])