3 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
7 changed files with 82 additions and 34 deletions

Binary file not shown.

View File

@@ -109,13 +109,13 @@ namespace commands
response["values"]["name"] = eventName; response["values"]["name"] = eventName;
auto &cron = Cron::getInstance(dev); auto &cron = Cron::getInstance(dev);
if (!cron.c_statusStr2Enum.contains(statusStr)) if (Cron::str2Enum(statusStr) == Cron::str2Enum("INVALID"))
{ {
LOG_ERROR("setCronJob invalid status [", statusStr.c_str(), "]"); LOG_ERROR("setCronJob invalid status [", statusStr.c_str(), "]");
response["values"]["status"] = "invalid"; response["values"]["status"] = "invalid";
return response; return response;
} }
cron.setEvent(eventName, cron.c_statusStr2Enum.at(statusStr)); cron.setEvent(eventName, Cron::str2Enum(statusStr));
LOG_INFO("setCronJob set job [", eventName.c_str(), "] to [", statusStr.c_str(), "]"); LOG_INFO("setCronJob set job [", eventName.c_str(), "] to [", statusStr.c_str(), "]");
response["values"]["status"] = "valid"; response["values"]["status"] = "valid";
return response; return response;
@@ -143,7 +143,8 @@ namespace commands
ArduinoJson::JsonDocument action; ArduinoJson::JsonDocument action;
action["cmd"] = event.cmd; action["cmd"] = event.cmd;
action["params"] = event.cmdParams; action["params"] = event.cmdParams;
action["status"] = cron.c_statusEnum2Str.at(event.status); action["status"] = Cron::enum2Str(event.status);
action["next"] = drivers::PCF85063::tm2str(event.next);
response["values"][name] = action; response["values"][name] = action;
eventNum++; eventNum++;
} }
@@ -163,8 +164,9 @@ namespace commands
ArduinoJson::JsonDocument action; ArduinoJson::JsonDocument action;
action["cmd"] = event.cmd; action["cmd"] = event.cmd;
action["params"] = event.cmdParams; action["params"] = event.cmdParams;
action["status"] = cron.c_statusEnum2Str.at(event.status); action["status"] = Cron::enum2Str(event.status);
response["values"]["cronExpr"] = cron::to_cronstr(event.cronExpr); 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;
@@ -204,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;
@@ -428,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 //

View File

@@ -61,6 +61,7 @@ namespace commands
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);
@@ -94,6 +95,7 @@ namespace commands
{"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},

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,13 +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 = c_statusStr2Enum.at(job["status"].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, status)) 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;
@@ -62,15 +64,16 @@ const bool Cron::storeEvents()
ArduinoJson::JsonDocument thisJob; ArduinoJson::JsonDocument thisJob;
thisJob["name"] = eventName; thisJob["name"] = eventName;
thisJob["cronExpr"] = cron::to_cronstr(eventParams.cronExpr); thisJob["cronExpr"] = cron::to_cronstr(eventParams.cronExpr);
thisJob["status"] = c_statusEnum2Str.at(eventParams.status); thisJob["status"] = enum2Str(eventParams.status);
thisJob["action"]["cmd"] = eventParams.cmd; thisJob["action"]["cmd"] = eventParams.cmd;
thisJob["action"]["params"] = eventParams.cmdParams; 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();
@@ -129,7 +132,7 @@ const bool Cron::setEvent(const std::string &name, const CronStatus status)
LOG_ERROR("Cron event [", name.c_str(), "] does not exist"); LOG_ERROR("Cron event [", name.c_str(), "] does not exist");
return false; return false;
} }
LOG_INFO("Cron set event [", name.c_str(), "] status [", c_statusEnum2Str.at(status).c_str(), "]"); LOG_INFO("Cron set event [", name.c_str(), "] status [", enum2Str(status).c_str(), "]");
m_cronMap.at(name).status = status; m_cronMap.at(name).status = status;
return true; return true;
} }
@@ -171,7 +174,7 @@ void cronLoop(void *cronPtr)
while (true) while (true)
{ {
cron.processEvents(); cron.processEvents();
delay(1000); delay(PROCESS_INTERVAL);
} }
} }
@@ -180,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;
}
} }
} }
@@ -225,7 +232,7 @@ const bool Cron::processEvents()
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(eventParams.next).c_str(); resp["values"]["next"] = drivers::PCF85063::tm2str(eventParams.next).c_str();
resp["values"]["status"] = c_statusEnum2Str.at(eventParams.status).c_str(); resp["values"]["status"] = enum2Str(eventParams.status).c_str();
switch (eventParams.status) switch (eventParams.status)
{ {
case CronStatus::ACTIVE: case CronStatus::ACTIVE:

View File

@@ -13,25 +13,29 @@
#include <filesystem> #include <filesystem>
#include <croncpp.h> #include <croncpp.h>
class Cron
{
public:
enum class CronStatus enum class CronStatus
{ {
ACTIVE, ACTIVE,
INACTIVE, INACTIVE,
SKIP SKIP,
INVALID
}; };
const std::map<CronStatus, std::string> c_statusEnum2Str = { static const std::map<const CronStatus, std::string> c_statusEnum2Str = {
{CronStatus::ACTIVE, "ACTIVE"}, {CronStatus::ACTIVE, "ACTIVE"},
{CronStatus::INACTIVE, "INACTIVE"}, {CronStatus::INACTIVE, "INACTIVE"},
{CronStatus::SKIP, "SKIP"}}; {CronStatus::SKIP, "SKIP"},
{CronStatus::INVALID, "INVALID"}};
const std::map<std::string, CronStatus> c_statusStr2Enum = { static const std::map<const std::string, CronStatus> c_statusStr2Enum = {
{"ACTIVE", CronStatus::ACTIVE}, {"ACTIVE", CronStatus::ACTIVE},
{"INACTIVE", CronStatus::INACTIVE}, {"INACTIVE", CronStatus::INACTIVE},
{"SKIP", CronStatus::SKIP}}; {"SKIP", CronStatus::SKIP},
{"INVALID", CronStatus::INVALID}};
class Cron
{
public:
struct CronEvent struct CronEvent
{ {
@@ -75,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

@@ -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, "]");