implementing cron in system component

This commit is contained in:
Bogdan Pilyugin 2023-10-10 08:58:00 +02:00
parent 97fb6e44c3
commit 25bc6d831e
9 changed files with 133 additions and 296 deletions

@ -1 +1 @@
Subproject commit 1e3eb967ab70d350fd9dba82832c69c9d85a7b5a
Subproject commit fcffb19740889a4df6ceb731bd18e9398c6e1067

View File

@ -26,8 +26,8 @@
#include <stdint.h>
#include <stdbool.h>
#include "../../components/webguiapp/include/CronTimers.h"
#include "esp_netif.h"
#include "CronTimers.h"
/// Application-dependent structure used to contain address information

View File

@ -1,76 +0,0 @@
/* 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.h
* Project: webguiapp_ref_implement
* Created on: 2023-04-15
* Author: bogdan
* Description:
*/
#ifndef MAIN_INCLUDE_CRONTIMERS_H_
#define MAIN_INCLUDE_CRONTIMERS_H_
#include "esp_err.h"
#include "cron.h"
#include "jobs.h"
#include "ccronexpr.h"
#define CRON_TIMERS_NUMBER (16)
#define TIMER_NAME_LENGTH (16)
#define TIMER_CRONSTRING_LENGTH (32)
#define CRON_EXPRESS_MAX_LENGTH (128)
#define CRON_OBJECTS_NUMBER (16)
#define CRON_OBJECT_NAME_LENGTH (16)
typedef struct
{
int idx;
char objname[CRON_OBJECT_NAME_LENGTH];
} cron_obj_t;
/**
* Cron scheduler configuration structure
*/
typedef struct
{
int num; /*!< Index of sheduler */
bool del; /*!< Flag of non valid record, free for future overwrite */
bool enab; /*!< Enable scheduler */
bool prev; /*!< Enable to execute nearest in the past sheduled action */
char name[TIMER_NAME_LENGTH]; /*!< Human readable name of scheduler */
int obj; /*!< Index of object scheduler affected on */
int act; /*!< Index of action with the object*/
char cron[TIMER_CRONSTRING_LENGTH]; /*!< Cron expression */
} cron_timer_t;
esp_err_t InitCronSheduler();
esp_err_t ReloadCronSheduler();
char* GetCronError();
void DebugTimer();
char* GetCronObjectNameDef(int idx);
char* GetCronObjectName(int idx);
char* GetCronActionName(int idx);
char* GetCronActAvail(int idx);
/**
* \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);
#endif /* MAIN_INCLUDE_CRONTIMERS_H_ */

View File

@ -1,3 +1,4 @@
#include <CronTimers.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
@ -5,13 +6,13 @@
#include "cron.h"
#include "jobs.h"
#include "AppConfiguration.h"
#include "CronTimers.h"
int HTTPPrintCustom(httpd_req_t *req, char *buf, char *var, int arg);
HTTP_IO_RESULT AfterPostHandlerCustom(httpd_req_t *req, const char *filename, char *PostData);
void UserMQTTEventHndlr(int idx, void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data);
void TimeObtainHandler(struct timeval *tm);
void SaveUserConf();
int ExecAppCommand(char *cmd);
const char my_context_data[] = "MyContextDataPassedIntoMQTTHandler";
@ -22,9 +23,11 @@ void app_main(void)
regUserEventHandler(&UserMQTTEventHndlr, (void*) my_context_data);
regTimeSyncCallback(&TimeObtainHandler);
regCustomSaveConf(&SaveUserConf);
regCustomExecCommand(&ExecAppCommand);
RegAppVariables();
WebGuiAppInit();
if (GetUserAppNeedReset())
{

124
main/src/CommandProcApp.c Normal file
View File

@ -0,0 +1,124 @@
/* 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: CommandProcApp.c
* Project: WebguiappTemplate
* Created on: 2023-10-09
* Author: bogdan
* Description:
*/
#include "webguiapp.h"
#define TAG "COMMAND_PROC_APP"
#define OBJECTS_NUMBER_APP (1)
#define EXEC_ACTIONS_MAX_NUMBER_APP (2)
static int ExecCommandParseApp(char *cmd);
static void APPLICATION_TEST1_handle(char *obj, char *com, char *arg)
{
ESP_LOGI(TAG, "INPUTS handler command %s with argument %s", com, arg);
}
static void APPLICATION_TEST2_handle(char *obj, char *com, char *arg)
{
ESP_LOGI(TAG, "SYSTEM handler command %s with argument %s", com, arg);
}
typedef struct
{
int index;
char object_name[EXEC_OBJECT_NAME_MAX_LENGTH];
char allowed_actions[EXEC_ACTIONS_MAX_NUMBER_APP][EXEC_ACTION_NAME_MAX_LENGTH];
void (*command_handlers[EXEC_ACTIONS_MAX_NUMBER_APP])(char *obj, char *com, char *arg);
} app_obj_struct_t;
const app_obj_struct_t app_com_obj_arr[] = {
{
.index = 0,
.object_name = "APPLICATION",
.allowed_actions = { "TEST1", "TEST2" },
.command_handlers = { &APPLICATION_TEST1_handle, &APPLICATION_TEST2_handle }
}
};
void GetAppObjectsInfo(char *data)
{
struct jWriteControl jwc;
jwOpen(&jwc, data, VAR_MAX_VALUE_LENGTH, JW_ARRAY, JW_COMPACT);
for (int idx = 0; idx < OBJECTS_NUMBER_APP; idx++)
{
jwArr_object(&jwc);
jwObj_string(&jwc, "object", app_com_obj_arr[idx].object_name);
jwObj_array(&jwc, "actions");
for (int i = 0; i < EXEC_ACTIONS_MAX_NUMBER_APP; i++)
{
if ((app_com_obj_arr[idx].allowed_actions[i])[0] != NULL)
jwArr_string(&jwc, app_com_obj_arr[idx].allowed_actions[i]);
}
jwEnd(&jwc);
jwEnd(&jwc);
}
jwClose(&jwc);
}
int ExecAppCommand(char *cmd)
{
return ExecCommandParseApp(cmd);
}
static int ExecCommandParseApp(char *cmd)
{
char *obj = NULL, *com = NULL, *arg = NULL;
int err = 0;
int commlen = strlen(cmd);
if (commlen > EXEC_COMMAND_MAX_LENGTH)
return 1;
char comm[EXEC_COMMAND_MAX_LENGTH + 1];
const char del1 = ',';
const char del2 = 0x00;
strcpy(comm, cmd);
obj = strtok(comm, &del1);
com = strtok(NULL, &del1);
arg = strtok(NULL, &del2);
if (!obj)
return 2;
if (!com)
return 2;
err = 4;
for (int idx = 0; idx < OBJECTS_NUMBER_APP; idx++)
{
if (!strcmp(obj, app_com_obj_arr[idx].object_name))
{
err = 5;
for (int i = 0; i < EXEC_ACTIONS_MAX_NUMBER_APP; i++)
{
if (!strcmp(com, app_com_obj_arr[idx].allowed_actions[i]))
{
if (app_com_obj_arr[idx].command_handlers[i] != NULL)
{
app_com_obj_arr[idx].command_handlers[i](obj, com, arg);
err = 0;
}
else
err = 6;
}
}
}
}
return err;
}

View File

@ -1,214 +0,0 @@
/* 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:
*/
#include "CronTimers.h"
#include "AppConfiguration.h"
#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 GetAppConf()->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)
{
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 (GetAppConf()->Timers[shdl].enab &&
!GetAppConf()->Timers[shdl].del &&
GetAppConf()->Timers[shdl].prev &&
GetAppConf()->Timers[shdl].obj == obj)
{
cron_expr cron_exp = { 0 };
cron_parse_expr(GetAppConf()->Timers[shdl].cron, &cron_exp, NULL);
time_t prev = cron_prev(&cron_exp, now);
if ((now - prev) < delta)
{
delta = (now - prev);
act = GetAppConf()->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(GetAppConf()->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 (!GetAppConf()->Timers[i].del && GetAppConf()->Timers[i].enab)
{
JobsList[i] = cron_job_create(GetAppConf()->Timers[i].cron, custom_cron_job_callback,
(void*) &GetAppConf()->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;
}

View File

@ -20,9 +20,9 @@
* \details
* \copyright Apache License, Version 2.0
*/
#include <CronTimers.h>
#include "webguiapp.h"
#include "AppConfiguration.h"
#include "CronTimers.h"
const char pg_40[] = "index40.html";
const char pg_42[] = "index42.html";

View File

@ -20,9 +20,9 @@
* \details
* \copyright Apache License, Version 2.0
*/
#include <CronTimers.h>
#include "webguiapp.h"
#include "AppConfiguration.h"
#include "CronTimers.h"
static void HTTPPrint_crontmr(char *VarData, void *arg)
{

View File

@ -21,9 +21,9 @@
* \copyright Apache License, Version 2.0
*/
#include <CronTimers.h>
#include "webguiapp.h"
#include "AppConfiguration.h"
#include "CronTimers.h"
extern APP_CONFIG AppConfig;