/* Copyright 2023 Bogdan Pilyugin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * File name: CronTimers.c * Project: webguiapp_ref_implement * Created on: 2023-04-15 * Author: bogdan * Description: */ //{ // "data":{ // "msgid":123456789, // "time":"2023-06-03T12:25:24+00:00", // "msgtype":1,"payloadtype":1, "payload":{"applytype":1, // "variables":{ // "cronrecs":[{ "num": 1, "del": 0, "enab": 1, "prev": 0, "name": "Timer Name", "obj": 0, "act": 0, // "cron": "*/3 * * * * *", // "exec": "OUTPUTS,TEST,ARGUMENTS" // }] // }}},"signature":"6a11b872e8f766673eb82e127b6918a0dc96a42c5c9d184604f9787f3d27bcef"} #include #include "esp_log.h" #include "webguiapp.h" #define TAG "CRON_TIMER" const char *cron_actions[] = { "ON", "REBOOT", "TOGGLE", "OFF","VERYLONG_OPERATION" }; const char *cron_objects[] = { "RELAY1", "RELAY2", "RELAY3", "RELAY4", "RELAY5", "RELAY6", "RELAY7", "RELAY8", "SYSTEM" }; const char *cron_act_avail[] = { "[0,2,3]", "[0,2,3]", "[0,2,3]", "[0,2,3]", "[0,2,3]", "[0,2,3]", "[0,2,3]", "[0,2,3]", "[1,4]" }; char* GetCronObjectNameDef(int idx) { if(idx < 0 || idx >= sizeof(cron_objects)/sizeof(char*)) return ""; return (char*)cron_objects[idx]; } char* GetCronObjectName(int idx) { if(idx < 0 || idx >= sizeof(cron_objects)/sizeof(char*)) return ""; return GetSysConf()->CronObjects[idx].objname; } char* GetCronActionName(int idx) { if(idx < 0 || idx >= sizeof(cron_actions)/sizeof(char*)) return ""; return (char*)cron_actions[idx]; } char* GetCronActAvail(int idx) { if(idx < 0 || idx >= sizeof(cron_act_avail)/sizeof(char*)) return "[]"; return (char*)cron_act_avail[idx]; } static cron_job *JobsList[CRON_TIMERS_NUMBER]; static char cron_express_error[CRON_EXPRESS_MAX_LENGTH]; char* GetCronError() { return cron_express_error; } /** * \brief Handle all actions under all objects * \param obj Index of the object * \param act Index of the action */ void custom_cron_execute(int obj, int act) { } void custom_cron_job_callback(cron_job *job) { ExecCommand(((cron_timer_t*) job->data)->exec); /* int act = ((cron_timer_t*) job->data)->act; int obj = ((cron_timer_t*) job->data)->obj; char *name = ((cron_timer_t*) job->data)->name; //here call all timers jobs depends on object and action time_t now; time(&now); ESP_LOGI(TAG, "Execute scheduler '%s' action %d under object %d at time %d", name, act, obj, (unsigned int )now); LogFile("cron.log", "Executed sheduler with action %u under object %u", act, obj); custom_cron_execute(obj, act); return; */ } esp_err_t InitCronSheduler() { esp_err_t res = ESP_OK; return res; } const char* check_expr(const char *expr) { const char *err = NULL; cron_expr test; memset(&test, 0, sizeof(test)); cron_parse_expr(expr, &test, &err); return err; } static void ExecuteLastAction() { int obj; for (obj = 0; obj < sizeof(cron_objects); obj++) { int shdl; time_t now; time(&now); time_t delta = now; int act = -1; for (shdl = 0; shdl < CRON_TIMERS_NUMBER; shdl++) { if (GetSysConf()->Timers[shdl].enab && !GetSysConf()->Timers[shdl].del && GetSysConf()->Timers[shdl].prev && GetSysConf()->Timers[shdl].obj == obj) { cron_expr cron_exp = { 0 }; cron_parse_expr(GetSysConf()->Timers[shdl].cron, &cron_exp, NULL); time_t prev = cron_prev(&cron_exp, now); if ((now - prev) < delta) { delta = (now - prev); act = GetSysConf()->Timers[shdl].act; } } } if(act != -1) { ESP_LOGW(TAG, "Execute last action %d with object %d", act, obj); LogFile("cron.log", "Execute last action %d under object %d", act, obj); custom_cron_execute(obj, act); } } } void TimeObtainHandler(struct timeval *tm) { ESP_LOGW(TAG, "Current time received with value %d", (unsigned int )tm->tv_sec); ReloadCronSheduler(); ExecuteLastAction(); LogFile("cron.log", "Cron service started"); } void DebugTimer() { ExecuteLastAction(); } esp_err_t ReloadCronSheduler() { //remove all jobs ESP_LOGI(TAG, "Cron stop call result %d", cron_stop()); cron_job_clear_all(); //check if we have jobs to run bool isExpressError = false; for (int i = 0; i < CRON_TIMERS_NUMBER; i++) { const char *err = check_expr(GetSysConf()->Timers[i].cron); if (err) { snprintf(cron_express_error, CRON_EXPRESS_MAX_LENGTH - 1, "In timer %d expression error:%s", i + 1, err); ESP_LOGE(TAG, "%s", cron_express_error); isExpressError = true; continue; } else if (!GetSysConf()->Timers[i].del && GetSysConf()->Timers[i].enab) { JobsList[i] = cron_job_create(GetSysConf()->Timers[i].cron, custom_cron_job_callback, (void*) &GetSysConf()->Timers[i]); } } if (!isExpressError) cron_express_error[0] = 0x00; //clear last cron expression parse int jobs_num = cron_job_node_count(); ESP_LOGI(TAG, "In config presents %d jobs", jobs_num); if (jobs_num > 0) ESP_LOGI(TAG, "Cron start call result %d", cron_start()); return ESP_OK; }