13 Commits

Author SHA1 Message Date
Emanuele Trabattoni
1457c6f1d2 minor fixes 2025-09-24 10:48:15 +02:00
Emanuele Trabattoni
d07ee18a22 updated getCronJobs response with next execution 2025-09-22 12:38:59 +02:00
Emanuele Trabattoni
9a0bc4c03f updated clock correction data 2025-09-22 12:05:42 +02:00
Emanuele Trabattoni
df66a9d076 fix timeDrift values and return for getCronJobs all 2025-08-31 10:16:10 +02:00
Emanuele Trabattoni
145698d3b9 fix pinlist naming 2025-08-30 11:34:57 +02:00
Emanuele Trabattoni
0952be3141 fix HPlimits pin ordering and introduce pin naming map 2025-08-30 10:55:40 +02:00
Emanuele Trabattoni
6a6931bde0 added getRainInfo command 2025-08-29 22:19:06 +02:00
Emanuele Trabattoni
4aeffc76b0 fixed log on TCP reconnection 2025-08-29 22:18:49 +02:00
Emanuele Trabattoni
cde86a7f99 reenabled ota and logs to TCP ocnnection port 9876 2025-08-29 21:30:38 +02:00
Emanuele Trabattoni
f9c5ab86ef refactor cronjobs 2025-08-29 19:30:41 +02:00
Emanuele Trabattoni
fc2687947a Fixed pinlist and temperature sensor map 2025-08-29 10:21:44 +02:00
Emanuele Trabattoni
637304781c Merge branch 'pro-develop' of https://git.etss.it/Obbart/ETcontroller_PRO into pro-develop 2025-08-17 18:41:28 +02:00
Emanuele Trabattoni
c973632fb8 PSram check 2025-08-17 18:41:24 +02:00
10 changed files with 370 additions and 98 deletions

72
.vscode/settings.json vendored
View File

@@ -1,5 +1,75 @@
{ {
"files.associations": { "files.associations": {
"esp32-hal.h": "c" "*.h": "cpp",
"esp32-hal.h": "c",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"netfwd": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"source_location": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"format": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"semaphore": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"text_encoding": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"variant": "cpp"
} }
} }

Binary file not shown.

View File

@@ -2,25 +2,44 @@
enum RO // relay output channels enum RO // relay output channels
{ {
P1 = 0, P4 = 0,
P2 = 1, P3 = 1,
P3 = 2, P2 = 2,
P4 = 3, P1 = 3,
RO_4 = 4, RO_4 = 4,
FST_FLOOR = 5, FST_FLOOR = 5,
GND_FLOOR = 6, GND_FLOOR = 6,
PUMP_HT = 7, PUMP_HT = 7,
PUMP_IRR = 8, PUMP_IRR = 8,
ZONE1 = 9, RETURN = 9,
ZONE2 = 10, ZONE1 = 10,
ZONE3 = 11, ZONE2 = 11,
DRIP = 12, ZONE3 = 12,
RETURN = 13, DRIP = 13,
RO_14 = 14, RO_14 = 14,
RO_15 = 15, RO_15 = 15,
RO_MAX = 16 // unused to detect invalid values RO_MAX = 16 // unused to detect invalid values
}; };
static const std::map<const int, const char *> RO_2str = {
{RO::P1, "HPLimit1"},
{RO::P2, "HPLimit2"},
{RO::P3, "HPLimit3"},
{RO::P4, "HPLimit4"},
{RO::RO_4, "Out4"},
{RO::FST_FLOOR, "PianoPrimo"},
{RO::GND_FLOOR, "PianoTerra"},
{RO::PUMP_HT, "PompaRisc"},
{RO::PUMP_IRR, "PompaIrr"},
{RO::RETURN, "Ricircolo"},
{RO::ZONE1, "IrrZona1"},
{RO::ZONE2, "IrrZona2"},
{RO::ZONE3, "IrrZona3"},
{RO::DRIP, "IrrDrip"},
{RO::RO_14, "Out14"},
{RO::RO_15, "Out15"},
{RO::RO_MAX, "Invalid"}};
enum DI // digital input channels enum DI // digital input channels
{ {
CONFRESET = 0, CONFRESET = 0,
@@ -28,6 +47,7 @@ enum DI // digital input channels
DI_2 = 2, DI_2 = 2,
DI_3 = 3, DI_3 = 3,
DI_4 = 4, DI_4 = 4,
DI_5 = 5,
DI_6 = 6, DI_6 = 6,
OTAENABLE = 7, OTAENABLE = 7,
PUMP_PRESSURE = 8, PUMP_PRESSURE = 8,
@@ -38,5 +58,25 @@ enum DI // digital input channels
DI_13 = 13, DI_13 = 13,
DI_14 = 14, DI_14 = 14,
DI_15 = 15, DI_15 = 15,
DI_MAX = 16 DI_MAX = 16 // unused to detect invalid values
}; // unused to detect invalid values };
static const std::map<const int, const char *> DI_2str =
{
{DI::CONFRESET, "ConfigReset"},
{DI::RESTART, "Restart"},
{DI::DI_2, "In2"},
{DI::DI_3, "In3"},
{DI::DI_4, "In4"},
{DI::DI_5, "In5"},
{DI::DI_6, "In6"},
{DI::OTAENABLE, "OtaEnable"},
{DI::PUMP_PRESSURE, "IrrPumpPressure"},
{DI::RAIN, "IrrRainSensor"},
{DI::IRR_OVERRIDE, "IrrRainOverride"},
{DI::DI_11, "In11"},
{DI::DI_12, "In12"},
{DI::DI_13, "In13"},
{DI::DI_14, "In14"},
{DI::DI_15, "In15"},
{DI::DI_MAX, "Invalid"}};

View File

@@ -71,10 +71,10 @@ namespace commands
response["values"]["status"] = "valid"; response["values"]["status"] = "valid";
return response; return response;
} }
const ArduinoJson::JsonDocument Commands::setCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params) const ArduinoJson::JsonDocument Commands::addCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params)
{ {
ArduinoJson::JsonDocument response; ArduinoJson::JsonDocument response;
response["cmd"] = "setCronJob"; response["cmd"] = "addCronJob";
const auto &eventName = params["name"].as<std::string>(); const auto &eventName = params["name"].as<std::string>();
const auto &timeStr = params["cronExpr"].as<std::string>(); const auto &timeStr = params["cronExpr"].as<std::string>();
@@ -84,7 +84,7 @@ namespace commands
ArduinoJson::JsonDocument action; ArduinoJson::JsonDocument action;
if (ArduinoJson::deserializeJson(action, actionStr) != ArduinoJson::DeserializationError::Ok) if (ArduinoJson::deserializeJson(action, actionStr) != ArduinoJson::DeserializationError::Ok)
{ {
LOG_ERROR("setCronJob unable to deserialize cron job [", actionStr.c_str(), "]"); LOG_ERROR("addCronJob unable to deserialize cron job [", actionStr.c_str(), "]");
response["values"]["status"] = "invalid"; response["values"]["status"] = "invalid";
return response; return response;
} }
@@ -92,11 +92,31 @@ namespace commands
auto &cron = Cron::getInstance(dev); auto &cron = Cron::getInstance(dev);
if (!cron.addEvent(eventName, timeStr, action)) if (!cron.addEvent(eventName, timeStr, action))
{ {
LOG_ERROR("setCronJob unable to add job [", actionStr.c_str(), "]"); LOG_ERROR("addCronJob unable to add job [", actionStr.c_str(), "]");
response["values"]["status"] = "invalid"; response["values"]["status"] = "invalid";
return response; return response;
} }
LOG_INFO("setCronJob added job [", actionStr.c_str(), "]"); LOG_INFO("addCronJob added job [", actionStr.c_str(), "]");
response["values"]["status"] = "valid";
return response;
}
const ArduinoJson::JsonDocument Commands::setCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params)
{
ArduinoJson::JsonDocument response;
response["cmd"] = "setCronJob";
const auto &eventName = params["name"].as<std::string>();
const auto &statusStr = params["status"].as<std::string>();
response["values"]["name"] = eventName;
auto &cron = Cron::getInstance(dev);
if (Cron::str2Enum(statusStr) == Cron::str2Enum("INVALID"))
{
LOG_ERROR("setCronJob invalid status [", statusStr.c_str(), "]");
response["values"]["status"] = "invalid";
return response;
}
cron.setEvent(eventName, Cron::str2Enum(statusStr));
LOG_INFO("setCronJob set job [", eventName.c_str(), "] to [", statusStr.c_str(), "]");
response["values"]["status"] = "valid"; response["values"]["status"] = "valid";
return response; return response;
} }
@@ -120,8 +140,12 @@ namespace commands
uint8_t eventNum(0); uint8_t eventNum(0);
for (const auto &[name, event] : eventMap) for (const auto &[name, event] : eventMap)
{ {
const auto cmd = std::get<0>(event); ArduinoJson::JsonDocument action;
response["values"][name] = cmd; action["cmd"] = event.cmd;
action["params"] = event.cmdParams;
action["status"] = Cron::enum2Str(event.status);
action["next"] = drivers::PCF85063::tm2str(event.next);
response["values"][name] = action;
eventNum++; eventNum++;
} }
LOG_INFO("getCronJob got [", eventNum, "] events"); LOG_INFO("getCronJob got [", eventNum, "] events");
@@ -137,16 +161,13 @@ namespace commands
return response; return response;
} }
auto cmd = std::get<0>(event);
auto cronExpr = std::get<1>(event);
auto cmdParams = std::get<3>(event);
ArduinoJson::JsonDocument action; ArduinoJson::JsonDocument action;
action["cmd"] = cmd; action["cmd"] = event.cmd;
action["params"] = cmdParams; action["params"] = event.cmdParams;
response["values"]["cronExpr"] = cron::to_cronstr(cronExpr); action["status"] = Cron::enum2Str(event.status);
action["next"] = drivers::PCF85063::tm2str(event.next);
action["cronExpr"] = cron::to_cronstr(event.cronExpr);
response["values"]["action"] = action; response["values"]["action"] = action;
LOG_INFO("getCronJob get job [", eventName.c_str(), "]"); LOG_INFO("getCronJob get job [", eventName.c_str(), "]");
return response; return response;
} }
@@ -185,6 +206,15 @@ namespace commands
// SETTERS // // SETTERS //
// SETTERS // // SETTERS //
const ArduinoJson::JsonDocument Commands::resetHPcounters(const devices_t &dev, const ArduinoJson::JsonDocument &params)
{
ArduinoJson::JsonDocument response;
response["cmd"] = "resetHPcounters";
response["values"]["status"] = "valid";
dev.seneca.resetPartialCounters();
return response;
}
const ArduinoJson::JsonDocument Commands::setHPlimit(const devices_t &dev, const ArduinoJson::JsonDocument &params) const ArduinoJson::JsonDocument Commands::setHPlimit(const devices_t &dev, const ArduinoJson::JsonDocument &params)
{ {
ArduinoJson::JsonDocument response; ArduinoJson::JsonDocument response;
@@ -204,6 +234,8 @@ namespace commands
} }
for (const auto [lvl, ro] : c_hpLimitsMap) for (const auto [lvl, ro] : c_hpLimitsMap)
{ {
if (ro == RO::RO_MAX)
continue; // avoid overshooting relay range
if (level == lvl && level != "UNLIMITED") if (level == lvl && level != "UNLIMITED")
dev.io.digitalOutWrite(ro, true); dev.io.digitalOutWrite(ro, true);
else else
@@ -281,7 +313,6 @@ namespace commands
const std::string zone(params["zone"].as<std::string>()); const std::string zone(params["zone"].as<std::string>());
const uint16_t tOn(params["timeOn"].as<uint16_t>()); const uint16_t tOn(params["timeOn"].as<uint16_t>());
const uint16_t tPause(params["timePause"].as<uint16_t>()); const uint16_t tPause(params["timePause"].as<uint16_t>());
response["values"]["zone"] = zone; response["values"]["zone"] = zone;
if (zone == "stop") if (zone == "stop")
@@ -302,7 +333,7 @@ namespace commands
} }
} }
LOG_INFO("setIrrigation closing", zoneName.c_str()); LOG_INFO("setIrrigation closing", zoneName.c_str());
dev.io.digitalOutWrite(c_irrigationValveMap.at(zoneName), false); // shuto down the valve dev.io.digitalOutWrite(c_irrigationValveMap.at(zoneName), false); // shutdown the valve
} }
if (s_irrigationPumpTimer) if (s_irrigationPumpTimer)
{ {
@@ -313,6 +344,13 @@ namespace commands
return response; return response;
} }
if (!s_rainOverride && !dev.io.digitalInRead(DI::RAIN)) // verify rain sensor and override value (rain sensor input is inverted)
{
LOG_WARN("setIrrigation skipping zone [", zone.c_str(), "] because its raining");
response["values"]["status"] = "rain";
return response;
}
response["values"]["timeOn"] = tOn; response["values"]["timeOn"] = tOn;
response["values"]["timePause"] = tPause; response["values"]["timePause"] = tPause;
if (!c_irrigationValveMap.contains(zone) || tOn <= 0 || tPause <= 0) // verify if zone is a valid map key if (!c_irrigationValveMap.contains(zone) || tOn <= 0 || tPause <= 0) // verify if zone is a valid map key
@@ -358,6 +396,7 @@ namespace commands
if (shTimer) if (shTimer)
{ {
dev.io.digitalOutWrite(zoneIoNumber, true); dev.io.digitalOutWrite(zoneIoNumber, true);
// controllare riempimento serbatoio con controllo del pressostato, magari in un timer
xTimerStart(shTimer, 0); xTimerStart(shTimer, 0);
timerHandle = shTimer; timerHandle = shTimer;
response["values"]["status"] = "valid"; response["values"]["status"] = "valid";
@@ -365,6 +404,20 @@ namespace commands
} }
return response; return response;
} }
const ArduinoJson::JsonDocument Commands::setRainOverride(const devices_t &dev, const ArduinoJson::JsonDocument &params)
{
ArduinoJson::JsonDocument response;
response["cmd"] = "setRainOverride";
if (params.isNull())
{
LOG_ERROR("setRainOverride incorrect paramaters");
return response;
}
s_rainOverride = params["status"].as<std::string>() == "True" ? true : false;
response["values"]["status"] = "valid";
LOG_INFO("setRainOverride [", s_rainOverride ? "True]" : "False]");
return response;
}
const ArduinoJson::JsonDocument Commands::setTimeNTP(const devices_t &dev, const ArduinoJson::JsonDocument &params) const ArduinoJson::JsonDocument Commands::setTimeNTP(const devices_t &dev, const ArduinoJson::JsonDocument &params)
{ {
ArduinoJson::JsonDocument response; ArduinoJson::JsonDocument response;
@@ -386,7 +439,7 @@ namespace commands
response["values"]["status"] = "valid"; response["values"]["status"] = "valid";
response["values"]["time"] = rtc.getTimeStr(); response["values"]["time"] = rtc.getTimeStr();
LOG_INFO("setTimeNTP -> RTC is [", response["status"]["time"].as<std::string>().c_str(), "]"); LOG_INFO("setTimeNTP -> RTC is [", response["values"]["time"].as<std::string>().c_str(), "]");
return response; return response;
} }
// SETTERS // // SETTERS //
@@ -420,8 +473,7 @@ namespace commands
uint8_t i(0); uint8_t i(0);
for (auto s : inStatus) for (auto s : inStatus)
{ {
const std::string k("DI" + std::to_string(i)); response["values"][DI_2str.at(i++)] = s;
response["values"][k.c_str()] = s;
} }
LOG_INFO("getInputStatus ->", printBoolVec(inStatus).c_str()); LOG_INFO("getInputStatus ->", printBoolVec(inStatus).c_str());
return response; return response;
@@ -439,8 +491,7 @@ namespace commands
uint8_t i(0); uint8_t i(0);
for (auto s : inStatus) for (auto s : inStatus)
{ {
const std::string k("DO" + std::to_string(i)); response["values"][RO_2str.at(i++)] = s;
response["values"][k.c_str()] = s;
} }
LOG_INFO("getOutputStatus ->", printBoolVec(inStatus).c_str()); LOG_INFO("getOutputStatus ->", printBoolVec(inStatus).c_str());
return response; return response;
@@ -466,7 +517,10 @@ namespace commands
const ArduinoJson::JsonDocument Commands::getRainInfo(const devices_t &dev, const ArduinoJson::JsonDocument &params) const ArduinoJson::JsonDocument Commands::getRainInfo(const devices_t &dev, const ArduinoJson::JsonDocument &params)
{ {
ArduinoJson::JsonDocument response; ArduinoJson::JsonDocument response;
LOG_WARN("Comand not yet implemented"); const auto rain = !dev.io.digitalInRead(DI::RAIN) ? "True" : "False";
response["cmd"] = "getRainInfo";
response["values"]["status"] = rain;
LOG_INFO("getRainInfo -> ", rain);
return response; return response;
} }
const ArduinoJson::JsonDocument Commands::getIrrigation(const devices_t &dev, const ArduinoJson::JsonDocument &params) const ArduinoJson::JsonDocument Commands::getIrrigation(const devices_t &dev, const ArduinoJson::JsonDocument &params)
@@ -475,6 +529,15 @@ namespace commands
LOG_WARN("Comand not yet implemented"); LOG_WARN("Comand not yet implemented");
return response; return response;
} }
const ArduinoJson::JsonDocument Commands::getRainOverride(const devices_t &dev, const ArduinoJson::JsonDocument &params)
{
ArduinoJson::JsonDocument response;
const auto ovr = s_rainOverride ? "True" : "False";
response["cmd"] = "getRainOverride";
response["values"]["rainOverride"] = ovr;
LOG_INFO("getRainOverride -> ", ovr);
return response;
}
const ArduinoJson::JsonDocument Commands::getTimeDrift(const devices_t &dev, const ArduinoJson::JsonDocument &params) const ArduinoJson::JsonDocument Commands::getTimeDrift(const devices_t &dev, const ArduinoJson::JsonDocument &params)
{ {
ArduinoJson::JsonDocument response; ArduinoJson::JsonDocument response;
@@ -500,13 +563,12 @@ namespace commands
auto timeDiff = std::chrono::duration_cast<std::chrono::seconds>(ntpTimePoint - rtcTimePoint); auto timeDiff = std::chrono::duration_cast<std::chrono::seconds>(ntpTimePoint - rtcTimePoint);
auto direction = timeDiff.count() >= 0 ? "BEYOND" : "AHEAD"; auto direction = timeDiff.count() >= 0 ? "BEYOND" : "AHEAD";
const int32_t drift = timeDiff.count();
response["values"]["status"] = "valid"; response["values"]["status"] = "valid";
response["values"]["drift"] = (uint32_t)timeDiff.count(); response["values"]["drift"] = drift;
response["values"]["direction"] = "RTC is [" + std::string(direction) + "] NTP time"; response["values"]["direction"] = "RTC is [" + std::string(direction) + "] NTP time";
LOG_INFO("getTimeDrift -> RTC is [", drift, "] sec, [", direction, "] NTP time");
LOG_INFO("getTimeDrift -> RTC is [", (int32_t)timeDiff.count(), "] sec, [", std::string(direction).c_str(), "] NTP time");
return response; return response;
} }
// GETTERS // // GETTERS //

View File

@@ -35,6 +35,7 @@ namespace commands
{"rubinetti", {"rubinetti", NULL}}}; {"rubinetti", {"rubinetti", NULL}}};
static TimerHandle_t s_irrigationPumpTimer = NULL; static TimerHandle_t s_irrigationPumpTimer = NULL;
static bool s_rainOverride = false;
// define command callback type // define command callback type
using Command = std::function<const ArduinoJson::JsonDocument(const devices_t &, const ArduinoJson::JsonDocument &)>; using Command = std::function<const ArduinoJson::JsonDocument(const devices_t &, const ArduinoJson::JsonDocument &)>;
@@ -53,15 +54,18 @@ namespace commands
// CRONJOBS // // CRONJOBS //
static const ArduinoJson::JsonDocument loadCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument loadCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument addCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument setCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument setCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument getCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument getCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument delCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument delCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument storeCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument storeCronJob(const devices_t &dev, const ArduinoJson::JsonDocument &params);
// SETTERS // // SETTERS //
static const ArduinoJson::JsonDocument resetHPcounters(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument setHPlimit(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument setHPlimit(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument setHeating(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument setHeating(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument setIrrigation(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument setIrrigation(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument setRainOverride(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument setTimeNTP(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument setTimeNTP(const devices_t &dev, const ArduinoJson::JsonDocument &params);
// GETTERS // // GETTERS //
@@ -73,6 +77,7 @@ namespace commands
static const ArduinoJson::JsonDocument getTankInfo(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument getTankInfo(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument getRainInfo(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument getRainInfo(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument getIrrigation(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument getIrrigation(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument getRainOverride(const devices_t &dev, const ArduinoJson::JsonDocument &params);
static const ArduinoJson::JsonDocument getTimeDrift(const devices_t &dev, const ArduinoJson::JsonDocument &params); static const ArduinoJson::JsonDocument getTimeDrift(const devices_t &dev, const ArduinoJson::JsonDocument &params);
}; };
@@ -84,18 +89,23 @@ namespace commands
{"getConfig", Commands::getConfig}, {"getConfig", Commands::getConfig},
// CRONJOBS // CRONJOBS
{"loadCronJob", Commands::loadCronJob}, {"loadCronJob", Commands::loadCronJob},
{"addCronJob", Commands::addCronJob},
{"setCronJob", Commands::setCronJob}, {"setCronJob", Commands::setCronJob},
{"getCronJob", Commands::getCronJob}, {"getCronJob", Commands::getCronJob},
{"delCronJob", Commands::delCronJob}, {"delCronJob", Commands::delCronJob},
{"storeCronJob", Commands::storeCronJob}, {"storeCronJob", Commands::storeCronJob},
// SETTERS // SETTERS
{"resetHPcounters", Commands::resetHPcounters},
{"setHPlimit", Commands::setHPlimit}, {"setHPlimit", Commands::setHPlimit},
{"setHeating", Commands::setHeating}, {"setHeating", Commands::setHeating},
{"setIrrigation", Commands::setIrrigation}, {"setIrrigation", Commands::setIrrigation},
{"setRainOverride", Commands::setRainOverride},
// GETTERS // GETTERS
{"getHPpower", Commands::getHPpower}, {"getHPpower", Commands::getHPpower},
{"getRainInfo", Commands::getRainInfo},
{"getInputStatus", Commands::getInputStatus}, {"getInputStatus", Commands::getInputStatus},
{"getOutputStatus", Commands::getOutputStatus}, {"getOutputStatus", Commands::getOutputStatus},
{"getRainOverride", Commands::getRainOverride},
// NTP and Time // NTP and Time
{"getTimeDrift", Commands::getTimeDrift}, {"getTimeDrift", Commands::getTimeDrift},
{"setTimeNTP", Commands::setTimeNTP}, {"setTimeNTP", Commands::setTimeNTP},

View File

@@ -4,6 +4,8 @@
#define STACK_DEPTH 4096 #define STACK_DEPTH 4096
#define PRIORITY 3 #define PRIORITY 3
#define PROCESS_INTERVAL 1000
#define PROCESS_CORE 0
const bool Cron::loadEvents() const bool Cron::loadEvents()
{ {
@@ -22,8 +24,9 @@ const bool Cron::loadEvents()
} }
std::string buf; std::string buf;
ArduinoJson::serializeJsonPretty(cronFileContent, buf); ArduinoJson::serializeJson(cronFileContent, buf);
LOG_INFO("Cron loadEvents loaded cronjobs.json\n", buf.c_str()); LOG_INFO("Cron loadEvents loaded cronjobs.json");
LOG_INFO(buf.c_str());
ArduinoJson::JsonArray cronjobList = cronFileContent.as<JsonArray>(); ArduinoJson::JsonArray cronjobList = cronFileContent.as<JsonArray>();
LOG_INFO("Cron loadEvents loaded [", cronjobList.size(), "] events"); LOG_INFO("Cron loadEvents loaded [", cronjobList.size(), "] events");
@@ -31,12 +34,12 @@ const bool Cron::loadEvents()
{ {
const auto &eventName = job["name"].as<std::string>(); const auto &eventName = job["name"].as<std::string>();
const auto &cronExpr = job["cronExpr"].as<std::string>(); const auto &cronExpr = job["cronExpr"].as<std::string>();
const auto status = str2Enum(job["status"].as<std::string>());
ArduinoJson::JsonDocument action(job["action"]); ArduinoJson::JsonDocument action(job["action"]);
if (!addEvent(eventName, cronExpr, action)) if (!addEvent(eventName, cronExpr, action, status))
LOG_ERROR("Cron failed to load event [", eventName.c_str(), "]"); LOG_ERROR("Cron failed to load event [", eventName.c_str(), "]");
else else
LOG_INFO("Cron loaded event [", eventName.c_str(), "]"); LOG_INFO("Cron loaded event [", eventName.c_str(), "]");
delay(10);
} }
cronFile.close(); cronFile.close();
return true; return true;
@@ -56,34 +59,28 @@ const bool Cron::storeEvents()
ArduinoJson::JsonDocument cronFileContent; ArduinoJson::JsonDocument cronFileContent;
ArduinoJson::JsonArray cronFileArray = cronFileContent.to<JsonArray>(); ArduinoJson::JsonArray cronFileArray = cronFileContent.to<JsonArray>();
for (const auto &job : m_cronMap) // convert cron events map to json file for (const auto &[eventName, eventParams] : m_cronMap) // convert cron events map to json file
{ {
const auto &eventName = job.first;
const auto &params = job.second;
const auto &cmd = std::get<0>(params);
const auto &cronExpr = std::get<1>(params);
const auto &cmdParams = std::get<3>(params);
ArduinoJson::JsonDocument thisJob; ArduinoJson::JsonDocument thisJob;
thisJob["name"] = eventName; thisJob["name"] = eventName;
thisJob["cronExpr"] = cron::to_cronstr(cronExpr); thisJob["cronExpr"] = cron::to_cronstr(eventParams.cronExpr);
thisJob["action"]["cmd"] = cmd; thisJob["status"] = enum2Str(eventParams.status);
thisJob["action"]["params"] = cmdParams; thisJob["action"]["cmd"] = eventParams.cmd;
thisJob["action"]["params"] = eventParams.cmdParams;
cronFileArray.add(thisJob); cronFileArray.add(thisJob);
} }
std::string buf; std::string buf;
ArduinoJson::serializeJsonPretty(cronFileContent, buf); ArduinoJson::serializeJson(cronFileContent, buf);
LOG_INFO("Cron storeEvents generated cronjobs.json\n", buf.c_str()); LOG_INFO("Cron storeEvents generated cronjobs.json");
LOG_INFO(buf.c_str());
ArduinoJson::serializeJson(cronFileContent, cronFile); ArduinoJson::serializeJson(cronFileContent, cronFile);
cronFile.close(); cronFile.close();
return true; return true;
} }
const bool Cron::addEvent(const std::string &name, const std::string &expr, const ArduinoJson::JsonDocument action) const bool Cron::addEvent(const std::string &name, const std::string &expr, const ArduinoJson::JsonDocument action, const CronStatus status)
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
if (m_cronMap.contains(name)) if (m_cronMap.contains(name))
@@ -99,9 +96,9 @@ const bool Cron::addEvent(const std::string &name, const std::string &expr, cons
try try
{ {
const auto eventExpr(cron::make_cron(expr));
const auto cmd = action["cmd"].as<std::string>(); const auto cmd = action["cmd"].as<std::string>();
const auto params = action["params"]; const auto params = action["params"];
const auto cronExpr(cron::make_cron(expr));
if (!commands::s_commandMap.contains(cmd)) if (!commands::s_commandMap.contains(cmd))
{ {
LOG_ERROR("Cron unknown command [", cmd.c_str(), "]"); LOG_ERROR("Cron unknown command [", cmd.c_str(), "]");
@@ -113,11 +110,11 @@ const bool Cron::addEvent(const std::string &name, const std::string &expr, cons
LOG_ERROR("Cron unable to update current time"); LOG_ERROR("Cron unable to update current time");
return false; return false;
} }
std::tm nowTm = drivers::PCF85063::datetime2tm(now); const std::tm nowTm = drivers::PCF85063::datetime2tm(now);
auto next = cron::cron_next(eventExpr, nowTm); const std::tm next = cron::cron_next(cronExpr, nowTm);
JsonDocument act(params); JsonDocument cmdParams(params); // create a copy of command parameters
LOG_INFO("Cron adding event [", name.c_str(), "] next execution [", drivers::PCF85063::tm2str(next).c_str(), "]"); LOG_INFO("Cron adding event [", name.c_str(), "] next execution [", drivers::PCF85063::tm2str(next).c_str(), "]");
m_cronMap[name] = std::make_tuple(cmd, eventExpr, next, act); m_cronMap[name] = CronEvent(cmd, cmdParams, cronExpr, next, status);
} }
catch (cron::bad_cronexpr const &ex) catch (cron::bad_cronexpr const &ex)
{ {
@@ -127,6 +124,19 @@ const bool Cron::addEvent(const std::string &name, const std::string &expr, cons
return true; return true;
} }
const bool Cron::setEvent(const std::string &name, const CronStatus status)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (!m_cronMap.contains(name))
{
LOG_ERROR("Cron event [", name.c_str(), "] does not exist");
return false;
}
LOG_INFO("Cron set event [", name.c_str(), "] status [", enum2Str(status).c_str(), "]");
m_cronMap.at(name).status = status;
return true;
}
const bool Cron::getEvent(const std::string &name, CronEvent &event) const bool Cron::getEvent(const std::string &name, CronEvent &event)
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
@@ -164,7 +174,7 @@ void cronLoop(void *cronPtr)
while (true) while (true)
{ {
cron.processEvents(); cron.processEvents();
delay(1000); delay(PROCESS_INTERVAL);
} }
} }
@@ -173,7 +183,11 @@ void Cron::startCron()
if (!m_cronTaskHandle) if (!m_cronTaskHandle)
{ {
LOG_INFO("Cron starting loop"); LOG_INFO("Cron starting loop");
xTaskCreate(cronLoop, "cronLoop", STACK_DEPTH, this, PRIORITY, &m_cronTaskHandle); if (xTaskCreatePinnedToCore(cronLoop, "cronLoop", STACK_DEPTH, this, PRIORITY, &m_cronTaskHandle, PROCESS_CORE) != pdPASS)
{
LOG_ERROR("Cron failed to start loop");
m_cronTaskHandle = NULL;
}
} }
} }
@@ -201,38 +215,43 @@ const bool Cron::processEvents()
std::tm nowTm = drivers::PCF85063::datetime2tm(now); std::tm nowTm = drivers::PCF85063::datetime2tm(now);
for (auto &event : m_cronMap) for (auto &[eventName, eventParams] : m_cronMap)
{ {
auto &eventName = event.first;
auto &eventAction = event.second;
auto &cmd = std::get<0>(eventAction);
auto &cronexrp = std::get<1>(eventAction);
auto &next = std::get<2>(eventAction);
auto &cmdParams = std::get<3>(eventAction);
const auto nowPoint = std::chrono::system_clock::from_time_t(std::mktime(&nowTm)); const auto nowPoint = std::chrono::system_clock::from_time_t(std::mktime(&nowTm));
const auto nextEventPoint = std::chrono::system_clock::from_time_t(std::mktime(&next)); const auto nextEventPoint = std::chrono::system_clock::from_time_t(std::mktime(&eventParams.next));
LOG_DEBUG("Cron current time [", std::asctime(&nowTm), "]"); LOG_DEBUG("Cron current time [", std::asctime(&nowTm), "]");
LOG_DEBUG("Cron checking event [", eventName.c_str(), "] executionTime [", drivers::PCF85063::tm2str(next).c_str(), "]"); LOG_DEBUG("Cron checking event [", eventName.c_str(), "] executionTime [", drivers::PCF85063::tm2str(eventParams.next).c_str(), "]");
if (nextEventPoint <= nowPoint) // execution time hs passed, run event if (nextEventPoint <= nowPoint) // execution time hs passed, run event
{ {
next = cron::cron_next(cronexrp, nowTm); // update next execution time only if event was executed
// otherwise time tracking is lost
LOG_INFO("Cron running event [", eventName.c_str(), "] next execution time [", drivers::PCF85063::tm2str(next).c_str(), "]");
auto action = commands::s_commandMap.at(cmd)(m_dev, cmdParams); // here the magic happens
ArduinoJson::JsonDocument resp; ArduinoJson::JsonDocument resp;
ArduinoJson::JsonDocument action;
eventParams.next = cron::cron_next(eventParams.cronExpr, nowTm); // update next execution time only if event was executed, otherwise time tracking is lost
resp["cmd"] = "logCronJob"; resp["cmd"] = "logCronJob";
resp["values"]["name"] = eventName; resp["values"]["name"] = eventName;
resp["values"]["now"] = drivers::PCF85063::tm2str(nowTm).c_str(); resp["values"]["now"] = drivers::PCF85063::tm2str(nowTm).c_str();
resp["values"]["next"] = drivers::PCF85063::tm2str(next).c_str(); resp["values"]["next"] = drivers::PCF85063::tm2str(eventParams.next).c_str();
resp["values"]["action"] = action; resp["values"]["status"] = enum2Str(eventParams.status).c_str();
if (m_callback) switch (eventParams.status)
{ {
m_callback(resp); case CronStatus::ACTIVE:
LOG_INFO("Cron running ACTIVE event [", eventName.c_str(), "] next execution time [", drivers::PCF85063::tm2str(eventParams.next).c_str(), "]");
action = commands::s_commandMap.at(eventParams.cmd)(m_dev, eventParams.cmdParams); // here the magic happens
resp["values"]["action"] = action;
break;
case CronStatus::INACTIVE:
LOG_INFO("Cron skipping INACTIVE event [", eventName.c_str(), "] next execution time [", drivers::PCF85063::tm2str(eventParams.next).c_str(), "]");
break;
case CronStatus::SKIP:
LOG_INFO("Cron skipping one time ACTIVE event [", eventName.c_str(), "] next execution time [", drivers::PCF85063::tm2str(eventParams.next).c_str(), "]");
eventParams.status = CronStatus::ACTIVE;
break;
default:
break;
} }
if (m_callback)
m_callback(resp); // execute cronLog callback action
} }
} }
return true; return true;

View File

@@ -13,10 +13,39 @@
#include <filesystem> #include <filesystem>
#include <croncpp.h> #include <croncpp.h>
enum class CronStatus
{
ACTIVE,
INACTIVE,
SKIP,
INVALID
};
static const std::map<const CronStatus, std::string> c_statusEnum2Str = {
{CronStatus::ACTIVE, "ACTIVE"},
{CronStatus::INACTIVE, "INACTIVE"},
{CronStatus::SKIP, "SKIP"},
{CronStatus::INVALID, "INVALID"}};
static const std::map<const std::string, CronStatus> c_statusStr2Enum = {
{"ACTIVE", CronStatus::ACTIVE},
{"INACTIVE", CronStatus::INACTIVE},
{"SKIP", CronStatus::SKIP},
{"INVALID", CronStatus::INVALID}};
class Cron class Cron
{ {
public: // eventName cronExpression nextExec command parameters public:
using CronEvent = std::tuple<std::string, cron::cronexpr, std::tm, ArduinoJson::JsonDocument>;
struct CronEvent
{
std::string cmd;
ArduinoJson::JsonDocument cmdParams;
cron::cronexpr cronExpr;
std::tm next;
CronStatus status;
};
using CronEventMap = std::map<std::string, CronEvent>; using CronEventMap = std::map<std::string, CronEvent>;
using CronCallback = std::function<void(const ArduinoJson::JsonDocument &)>; using CronCallback = std::function<void(const ArduinoJson::JsonDocument &)>;
@@ -40,7 +69,8 @@ public:
const bool loadEvents(); const bool loadEvents();
const bool storeEvents(); const bool storeEvents();
const bool addEvent(const std::string &name, const std::string &expr, const ArduinoJson::JsonDocument action); const bool addEvent(const std::string &name, const std::string &expr, const ArduinoJson::JsonDocument action, const CronStatus status = CronStatus::ACTIVE);
const bool setEvent(const std::string &name, const CronStatus status);
const bool getEvent(const std::string &name, CronEvent &event); const bool getEvent(const std::string &name, CronEvent &event);
const bool delEvent(const std::string &name); const bool delEvent(const std::string &name);
const CronEventMap &getAllEvents(); const CronEventMap &getAllEvents();
@@ -49,6 +79,20 @@ public:
void stopCron(); void stopCron();
const bool processEvents(); const bool processEvents();
static const std::string enum2Str(const CronStatus status)
{
if (!c_statusEnum2Str.contains(status))
return "INVALID";
return c_statusEnum2Str.at(status);
}
static const CronStatus str2Enum(const std::string &status)
{
if (!c_statusStr2Enum.contains(status))
return CronStatus::INVALID;
return c_statusStr2Enum.at(status);
}
private: private:
const devices_t &m_dev; const devices_t &m_dev;
CronCallback m_callback; CronCallback m_callback;

View File

@@ -24,6 +24,11 @@ void setup()
LOG_ATTACH_SERIAL(Serial); LOG_ATTACH_SERIAL(Serial);
LOG_SET_LEVEL(DebugLogLevel::LVL_INFO); LOG_SET_LEVEL(DebugLogLevel::LVL_INFO);
conf.init(); // read the configuration from internal flash conf.init(); // read the configuration from internal flash
LOG_INFO("ESP32 Chip:", ESP.getChipModel());
LOG_INFO("ESP32 PSram:", ESP.getPsramSize());
LOG_INFO("ESP32 Flash:", ESP.getFlashChipSize());
LOG_INFO("ESP32 Heap:", ESP.getHeapSize());
LOG_INFO("ESP32 Sketch:", ESP.getFreeSketchSpace());
} }
void loop() void loop()
@@ -31,6 +36,8 @@ void loop()
uint16_t k(0); uint16_t k(0);
uint8_t sensors(0); uint8_t sensors(0);
bool buzzing(false); bool buzzing(false);
NetworkClient logStream;
LOG_ATTACH_STREAM(logStream);
//////////////// DEVICES //////////////// //////////////// DEVICES ////////////////
// Declared here to keep devices local to the main loop otherwise the kernel crashes // // Declared here to keep devices local to the main loop otherwise the kernel crashes //
@@ -89,13 +96,13 @@ void loop()
MQTTwrapper::MessageCallback onMessage = [&devices](const MQTTwrapper::Topic &topic, const MQTTwrapper::Message &message) MQTTwrapper::MessageCallback onMessage = [&devices](const MQTTwrapper::Topic &topic, const MQTTwrapper::Message &message)
{ {
LOG_DEBUG("onMessage callback [", topic.c_str(), "]"); LOG_DEBUG("onMessage callback [", topic.c_str(), "]\n", message.c_str());
devices.led.setColor(devices.led.COLOR_MAGENTA); devices.led.setColor(devices.led.COLOR_MAGENTA);
}; };
MQTTwrapper::MessageCallback onPublish = [&devices](const MQTTwrapper::Topic &topic, const MQTTwrapper::Message &message) MQTTwrapper::MessageCallback onPublish = [&devices](const MQTTwrapper::Topic &topic, const MQTTwrapper::Message &message)
{ {
LOG_DEBUG("onPublish callback [", topic.c_str(), "]"); LOG_DEBUG("onPublish callback [", topic.c_str(), "]\n", message.c_str());
devices.led.setColor(devices.led.COLOR_SKYBLUE); devices.led.setColor(devices.led.COLOR_SKYBLUE);
}; };
@@ -124,6 +131,7 @@ void loop()
if (!eth.isConnected()) if (!eth.isConnected())
{ {
led.setColor(led.COLOR_RED); led.setColor(led.COLOR_RED);
logStream.stop();
return; return;
} }
if (io.digitalInRead(DI::OTAENABLE)) // Initialize OTA, BLUE if (io.digitalInRead(DI::OTAENABLE)) // Initialize OTA, BLUE
@@ -149,7 +157,6 @@ void loop()
{ // skip NTP update for drift testing { // skip NTP update for drift testing
buzzer.beep(250, NOTE_A); buzzer.beep(250, NOTE_A);
led.setColor(led.COLOR_ORANGE); led.setColor(led.COLOR_ORANGE);
// rtc.setDatetime(drivers::PCF85063::fromEpoch(ntpTime));
const drivers::PCF85063::datetime_t dt(drivers::PCF85063::fromEpoch(ntpTime)); const drivers::PCF85063::datetime_t dt(drivers::PCF85063::fromEpoch(ntpTime));
LOG_INFO("NTP Time: ", drivers::PCF85063::datetime2str(dt).c_str()); LOG_INFO("NTP Time: ", drivers::PCF85063::datetime2str(dt).c_str());
break; break;
@@ -179,6 +186,16 @@ void loop()
{ {
const uint32_t start(millis()); const uint32_t start(millis());
drivers::PCF85063::datetime_t datetime; drivers::PCF85063::datetime_t datetime;
if (!logStream.connected())
{
logStream.stop();
logStream.clearWriteError();
logStream.setConnectionTimeout(100);
logStream.connect(conf.m_mqttHost.c_str(), 9876);
LOG_WARN("TCP LogStream Connected");
}
rtc.readDatetime(datetime); rtc.readDatetime(datetime);
const std::string timeStr(drivers::PCF85063::datetime2str(datetime)); const std::string timeStr(drivers::PCF85063::datetime2str(datetime));
LOG_INFO("[", k++, "] Loop - Current Datetime UTC", timeStr.c_str()); LOG_INFO("[", k++, "] Loop - Current Datetime UTC", timeStr.c_str());
@@ -196,8 +213,8 @@ void loop()
ArduinoJson::JsonDocument ti; ArduinoJson::JsonDocument ti;
auto tempinfo = tmp.getTempAll(); auto tempinfo = tmp.getTempAll();
ti["solar"] = tempinfo.at(0); ti["solar"] = tempinfo.at(0);
ti["acs"] = tempinfo.at(0); ti["acs"] = tempinfo.at(1);
ti["heating"] = tempinfo.at(0); ti["heating"] = tempinfo.at(2);
mqtt.publish(conf.m_mqttPublish["temperatures"], ti); mqtt.publish(conf.m_mqttPublish["temperatures"], ti);
}; };

View File

@@ -3,6 +3,7 @@
#define STACK_DEPTH 8192 #define STACK_DEPTH 8192
#define BUFFER_SIZE 2048 #define BUFFER_SIZE 2048
#define PRIORITY 2 #define PRIORITY 2
#define PROCESS_CORE 1
MQTTwrapper::MQTTwrapper() : m_config(Config::getInstance()), m_tcp(NetworkClient()), m_client(PubSubClient(m_tcp)), m_loopHandle(NULL) MQTTwrapper::MQTTwrapper() : m_config(Config::getInstance()), m_tcp(NetworkClient()), m_client(PubSubClient(m_tcp)), m_loopHandle(NULL)
{ {
@@ -27,7 +28,11 @@ const bool MQTTwrapper::connect()
LOG_INFO("MQTT client connected to", m_config.m_mqttHost.c_str()); LOG_INFO("MQTT client connected to", m_config.m_mqttHost.c_str());
if (m_loopHandle == NULL) if (m_loopHandle == NULL)
{ {
xTaskCreate(clientLoop, "mqttLoop", STACK_DEPTH, this, PRIORITY, &m_loopHandle); if (xTaskCreatePinnedToCore(clientLoop, "mqttLoop", STACK_DEPTH, this, PRIORITY, &m_loopHandle, PROCESS_CORE) != pdPASS)
{
m_loopHandle = NULL;
return false;
}
m_client.setCallback(MQTTwrapper::callback); m_client.setCallback(MQTTwrapper::callback);
} }
return true; return true;

View File

@@ -2,6 +2,7 @@
#define STACK_DEPTH 4096 #define STACK_DEPTH 4096
#define TASK_PRIORITY 2 #define TASK_PRIORITY 2
#define PROCESS_CORE 1
OTA::OTA(const devices_t &dev) : m_dev(dev), m_taskHandle(NULL), m_updating(false), m_prevPercent(0) OTA::OTA(const devices_t &dev) : m_dev(dev), m_taskHandle(NULL), m_updating(false), m_prevPercent(0)
{ {
@@ -26,10 +27,11 @@ void OTA::begin()
ArduinoOTA.onEnd(s_onEnd); ArduinoOTA.onEnd(s_onEnd);
ArduinoOTA.onProgress(s_onProgress); ArduinoOTA.onProgress(s_onProgress);
ArduinoOTA.onError(s_onError); ArduinoOTA.onError(s_onError);
if (xTaskCreate(handle, "otaUpdate", STACK_DEPTH, this, TASK_PRIORITY, &m_taskHandle) != pdPASS) if (xTaskCreatePinnedToCore(handle, "otaUpdate", STACK_DEPTH, this, TASK_PRIORITY, &m_taskHandle, PROCESS_CORE) != pdPASS)
{ {
m_taskHandle = NULL; m_taskHandle = NULL;
LOG_ERROR("OTA failed to create handle task"); LOG_ERROR("OTA failed to create handle task");
return;
} }
ArduinoOTA.begin(); // start the OTA server ArduinoOTA.begin(); // start the OTA server
m_dev.led.blinkAlternate(100, 100, m_dev.led.COLOR_ORANGE, m_dev.led.COLOR_SKYBLUE); m_dev.led.blinkAlternate(100, 100, m_dev.led.COLOR_ORANGE, m_dev.led.COLOR_SKYBLUE);
@@ -72,6 +74,7 @@ void OTA::onProgress(const uint32_t progress, const uint32_t total)
m_prevPercent = percent; m_prevPercent = percent;
} }
} }
void OTA::onStart() void OTA::onStart()
{ {
LOG_WARN("OTA update started"); LOG_WARN("OTA update started");
@@ -81,6 +84,7 @@ void OTA::onStart()
m_dev.led.setEnforce(true); m_dev.led.setEnforce(true);
m_prevPercent = 0; m_prevPercent = 0;
} }
void OTA::onEnd() void OTA::onEnd()
{ {
LOG_WARN("OTA update end"); LOG_WARN("OTA update end");
@@ -89,6 +93,7 @@ void OTA::onEnd()
m_dev.led.blinkAlternate(50, 50, m_dev.led.COLOR_GREEN, m_dev.led.COLOR_YELLOW); m_dev.led.blinkAlternate(50, 50, m_dev.led.COLOR_GREEN, m_dev.led.COLOR_YELLOW);
m_dev.led.setEnforce(true); m_dev.led.setEnforce(true);
} }
void OTA::onError(const ota_error_t err) void OTA::onError(const ota_error_t err)
{ {
LOG_ERROR("OTA Error [", err, "]"); LOG_ERROR("OTA Error [", err, "]");