first version of cron, does not read configuation from file

This commit is contained in:
Emanuele Trabattoni
2025-07-26 16:05:03 +02:00
parent 91f4c5c750
commit 448e1bad15
8 changed files with 1129 additions and 9 deletions

View File

@@ -56,6 +56,9 @@ namespace commands
static TimerHandle_t s_irrigationPumpTimer = NULL;
// define command callback type
using Command = std::function<const ArduinoJson::JsonDocument(const devices_t &, const ArduinoJson::JsonDocument &)>;
class Commands
{
Commands() = delete;
@@ -86,7 +89,7 @@ namespace commands
static const ArduinoJson::JsonDocument getIrrigation(const devices_t &dev, const ArduinoJson::JsonDocument &params);
};
static const std::map<const std::string, std::function<const ArduinoJson::JsonDocument(const devices_t &, const ArduinoJson::JsonDocument &)>> commandMap = {
static const std::map<const std::string, Command> commandMap = {
{"setConfig", Commands::setConfig},
{"getConfig", Commands::getConfig},

139
src/cronjobs.cpp Normal file
View File

@@ -0,0 +1,139 @@
#include <cronjobs.h>
#include <chrono>
#define STACK_DEPTH 4096
#define PRIORITY 3
Cron::Cron(devices_t &dev) : m_dev(dev)
{
}
Cron::~Cron()
{
}
const bool Cron::loadEvents(fs::File &file)
{
return true;
}
const bool Cron::addEvent(const std::string &name, const std::string &command, const std::string &expr)
{
if (m_cronMap.contains(name))
{
LOG_ERROR("Cron event [", name.c_str(), "] already scheduled");
return false;
}
if (name.empty() || command.empty() || expr.empty())
{
LOG_ERROR("Cron event invalid parameters");
return false;
}
try
{
const auto eventExpr(cron::make_cron(expr));
ArduinoJson::JsonDocument action;
if (ArduinoJson::deserializeJson(action, command) != ArduinoJson::DeserializationError::Ok)
{
LOG_ERROR("Cron unable to deserialize command [", command.c_str(), "]");
return false;
}
const auto cmd = action["cmd"].as<std::string>();
const auto params = action["params"].as<JsonObject>();
if (!commands::commandMap.contains(cmd))
{
LOG_ERROR("Cron unknown command [", command.c_str(), "]");
return false;
}
LOG_INFO("Cron added event [", name.c_str(), "]");
drivers::PCF85063::datetime_t now;
if (!m_dev.rtc.readDatetime(now))
{
LOG_ERROR("Cron unable to update current time");
return false;
}
std::tm nowTm = drivers::PCF85063::datetime2tm(now);
m_cronMap[name] = std::make_tuple(cmd, eventExpr, cron::cron_next(eventExpr, nowTm), params);
}
catch (cron::bad_cronexpr const &ex)
{
LOG_ERROR("Cron failed to parse expression [", expr.c_str(), "] ->", ex.what());
return false;
}
return true;
}
const bool Cron::delEvent(const std::string &name)
{
if (!m_cronMap.contains(name))
{
LOG_WARN("Cron event [", name.c_str(), "] does not exist");
return false;
}
m_cronMap.erase(name);
LOG_INFO("Cron removed event [", name.c_str(), "]");
return true;
}
void cronLoop(void* params) {
auto cron = (Cron*)(params);
while (true) {
cron->processEvents();
delay(1000);
}
}
void Cron::startCron() {
if (!m_cronTaskHandle) {
LOG_INFO("Cron starting loop");
xTaskCreate(cronLoop, "cronLoop", STACK_DEPTH, this, PRIORITY, &m_cronTaskHandle);
}
}
void Cron::stopCron() {
if (m_cronTaskHandle) {
LOG_WARN("Cron stopping loop");
vTaskDelete(m_cronTaskHandle);
m_cronTaskHandle = NULL;
}
}
const bool Cron::processEvents()
{
LOG_DEBUG("Cron processEvents [", m_cronMap.size(), "]");
drivers::PCF85063::datetime_t now;
if (!m_dev.rtc.readDatetime(now))
{
LOG_ERROR("Cron unable to update current time");
return false;
}
std::tm nowTm = drivers::PCF85063::datetime2tm(now);
for (auto &event : 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 &params = std::get<3>(eventAction);
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));
LOG_DEBUG("Cron current time [", std::asctime(&nowTm), "]");
LOG_DEBUG("Cron checking event [", eventName.c_str(), "] executionTime [", std::asctime(&next), "]");
if (nextEventPoint <= nowPoint) // execution time hs passed, run event
{
LOG_INFO("Cron executing event [", eventName.c_str(), "]");
commands::commandMap.at(cmd)(m_dev, params); // here the magic happens
next = cron::cron_next(cronexrp, nowTm); // update next execution time only if event was executed
} // otherwise time tracking is lost
}
return true;
}

34
src/cronjobs.h Normal file
View File

@@ -0,0 +1,34 @@
#pragma once
#define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG
#include <DebugLog.h>
#include <Arduino.h>
#include <PCF85063_Driver.h>
#include <commands.h>
#include <filesystem>
#include <croncpp.h>
class Cron
{
public:
Cron(devices_t &dev);
~Cron();
const bool loadEvents(fs::File &file);
const bool addEvent(const std::string &name, const std::string &command, const std::string &expr);
const bool delEvent(const std::string &name);
void startCron();
void stopCron();
const bool processEvents();
private:
devices_t &m_dev;
TaskHandle_t m_cronTaskHandle;
std::map<std::string, std::tuple<std::string, cron::cronexpr, std::tm, ArduinoJson::JsonDocument>> m_cronMap;
};

View File

@@ -6,6 +6,7 @@
#include <config.h>
#include <commands.h>
#include <cronjobs.h>
#include <mqtt.h>
#include <devices.h>
@@ -53,6 +54,24 @@ void loop()
//////////////// NETWORK ////////////////
auto mqtt = MQTTwrapper();
//////////////// NETWORK ////////////////
//////////////// CRONJOB ////////////////
auto cron = Cron(devices);
ArduinoJson::JsonDocument job;
job["cmd"] = "setIrrigation";
job["params"]["zone"] = "zone1";
job["params"]["timeOn"] = 30;
job["params"]["timePause"] = 2;
{
std::string buf;
serializeJson(job,buf);
LOG_INFO("Example Cronjob -> ", buf.c_str());
cron.addEvent("exampleCronEvent", buf, "0 */10 * * * *");
cron.startCron();
};
//////////////// CRONJOB ////////////////
//////////////// MQTT ////////////////
/////////////// CALLBACK //////////////

View File

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