Added support for time scheduled lua scripts
This commit is contained in:
@@ -11,8 +11,9 @@ include(FindLua)
|
|||||||
find_package(lua REQUIRED)
|
find_package(lua REQUIRED)
|
||||||
find_package(InfluxDB REQUIRED)
|
find_package(InfluxDB REQUIRED)
|
||||||
find_package(eclipse-paho-mqtt-c CONFIG REQUIRED)
|
find_package(eclipse-paho-mqtt-c CONFIG REQUIRED)
|
||||||
|
find_package(croncpp CONFIG REQUIRED)
|
||||||
|
|
||||||
add_executable(thrawn src/main.cpp src src/thrawn_api.cpp src/thrawn_api_db_logger.cpp src/Service.cpp src/Cache.cpp src/LuaEngine.cpp lib/mqtt++/src/mqtt++.cpp src/DBLogger.cpp)
|
add_executable(thrawn src/main.cpp src src/thrawn_api.cpp src/thrawn_api_db_logger.cpp src/Service.cpp src/Cache.cpp src/LuaEngine.cpp lib/mqtt++/src/mqtt++.cpp src/DBLogger.cpp)
|
||||||
target_link_libraries(thrawn ${LIBS} spdlog::spdlog InfluxData::InfluxDB ${LUA_LIBRARIES} OpenSSL::SSL eclipse-paho-mqtt-c::paho-mqtt3cs-static)
|
target_link_libraries(thrawn ${LIBS} croncpp::croncpp spdlog::spdlog InfluxData::InfluxDB ${LUA_LIBRARIES} OpenSSL::SSL eclipse-paho-mqtt-c::paho-mqtt3cs-static)
|
||||||
target_include_directories(thrawn PRIVATE ${LUA_INCLUDE_DIR})
|
target_include_directories(thrawn PRIVATE ${LUA_INCLUDE_DIR})
|
||||||
install(TARGETS thrawn DESTINATION bin)
|
install(TARGETS thrawn DESTINATION bin)
|
||||||
@@ -1,4 +1,13 @@
|
|||||||
#include "LuaEngine.h"
|
#include "LuaEngine.h"
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
bool ScheduledService::operator<(const ScheduledService& rhs) const {
|
||||||
|
return next_run > rhs.next_run;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduledService::next() {
|
||||||
|
next_run = cron::cron_next(cron, std::time(0));
|
||||||
|
}
|
||||||
|
|
||||||
LuaEngine::LuaEngine() : db_logger("http://localhost:8086", "test") {}
|
LuaEngine::LuaEngine() : db_logger("http://localhost:8086", "test") {}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,20 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "DBLogger.h"
|
#include "DBLogger.h"
|
||||||
|
#include "croncpp/croncpp.h"
|
||||||
|
#include <ctime>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
struct ScheduledService {
|
||||||
|
cron::cronexpr cron;
|
||||||
|
std::time_t next_run;
|
||||||
|
LuaService* service;
|
||||||
|
std::string callback;
|
||||||
|
|
||||||
|
void next();
|
||||||
|
bool operator<(const ScheduledService& rhs) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class LuaEngine {
|
class LuaEngine {
|
||||||
private:
|
private:
|
||||||
@@ -13,6 +27,7 @@ class LuaEngine {
|
|||||||
public:
|
public:
|
||||||
std::function<void(const TopicState& state)> publish;
|
std::function<void(const TopicState& state)> publish;
|
||||||
DBLogger db_logger;
|
DBLogger db_logger;
|
||||||
|
std::priority_queue<ScheduledService> time_schedule;
|
||||||
|
|
||||||
static LuaEngine& get_instance() {
|
static LuaEngine& get_instance() {
|
||||||
static LuaEngine instance;
|
static LuaEngine instance;
|
||||||
@@ -23,6 +38,7 @@ class LuaEngine {
|
|||||||
|
|
||||||
Cache cache;
|
Cache cache;
|
||||||
|
|
||||||
|
|
||||||
void load_services();
|
void load_services();
|
||||||
void start_services();
|
void start_services();
|
||||||
LuaService* create_service(std::string filename);
|
LuaService* create_service(std::string filename);
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ LuaService::LuaService(std::string filename) {
|
|||||||
lua_pushcfunction(lua, thrawn_subscribe);
|
lua_pushcfunction(lua, thrawn_subscribe);
|
||||||
lua_setglobal(lua, "thrawn_subscribe");
|
lua_setglobal(lua, "thrawn_subscribe");
|
||||||
|
|
||||||
|
lua_pushcfunction(lua, thrawn_schedule);
|
||||||
|
lua_setglobal(lua, "thrawn_schedule");
|
||||||
|
|
||||||
lua_pushcfunction(lua, thrawn_publish);
|
lua_pushcfunction(lua, thrawn_publish);
|
||||||
lua_setglobal(lua, "thrawn_publish");
|
lua_setglobal(lua, "thrawn_publish");
|
||||||
|
|
||||||
|
|||||||
21
src/main.cpp
21
src/main.cpp
@@ -11,6 +11,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "mqtt++.h"
|
#include "mqtt++.h"
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
std::vector<std::string> lua_scripts_in_folder(const std::string& path_str) {
|
std::vector<std::string> lua_scripts_in_folder(const std::string& path_str) {
|
||||||
std::vector<std::string> scripts;
|
std::vector<std::string> scripts;
|
||||||
@@ -110,6 +111,26 @@ int main(int argc, char* argv[]) {
|
|||||||
spdlog::info("All services loaded.");
|
spdlog::info("All services loaded.");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
time_t now = std::time(0);
|
||||||
|
|
||||||
|
bool check_next = true;
|
||||||
|
|
||||||
|
while (check_next) {
|
||||||
|
ScheduledService scheduled_service = LuaEngine::get_instance().time_schedule.top();
|
||||||
|
if (now > scheduled_service.next_run) {
|
||||||
|
LuaEngine::get_instance().time_schedule.pop();
|
||||||
|
call_thrawn_on_schedule(*scheduled_service.service, now, scheduled_service.callback);
|
||||||
|
scheduled_service.next();
|
||||||
|
spdlog::info("Now: {} Next: {}, Time: {}", now, scheduled_service.next_run, std::time(0));
|
||||||
|
LuaEngine::get_instance().time_schedule.push(scheduled_service);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
check_next = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
std::this_thread::sleep_for(100ms);
|
std::this_thread::sleep_for(100ms);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include "LuaEngine.h"
|
#include "LuaEngine.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include "croncpp/croncpp.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
HELPER
|
HELPER
|
||||||
*/
|
*/
|
||||||
@@ -135,6 +137,51 @@ int thrawn_subscribe(lua_State* lua) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int thrawn_schedule(lua_State* lua) {
|
||||||
|
int paramCount = lua_gettop(lua);
|
||||||
|
|
||||||
|
if(paramCount < 1 || paramCount > 2){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaService* service = LuaEngine::get_instance().service_by_lua_state(lua);
|
||||||
|
|
||||||
|
if (service->name == "") {
|
||||||
|
spdlog::error("Not registered service tried to subscribe to schedule '{}'", lua_tostring(lua, -1));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ScheduledService scheduled_service;
|
||||||
|
|
||||||
|
std::string cron_str = lua_tostring(lua, -1);
|
||||||
|
scheduled_service.callback = "thrawn_on_schedule";
|
||||||
|
|
||||||
|
if (paramCount == 2) {
|
||||||
|
cron_str = lua_tostring(lua, -2);
|
||||||
|
scheduled_service.callback = lua_tostring(lua, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduled_service.cron = cron::make_cron(cron_str);
|
||||||
|
|
||||||
|
scheduled_service.service = service;
|
||||||
|
scheduled_service.next();
|
||||||
|
|
||||||
|
LuaEngine::get_instance().time_schedule.push(scheduled_service);
|
||||||
|
|
||||||
|
spdlog::info("Service '{}' scheduled to '{}'", service->name, cron_str);
|
||||||
|
}
|
||||||
|
catch (cron::bad_cronexpr const & ex)
|
||||||
|
{
|
||||||
|
spdlog::error("Could not register scheduled job for cron string '{}' and service '{}'", lua_tostring(lua, -1), service->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int thrawn_cached_topic(lua_State* lua) {
|
int thrawn_cached_topic(lua_State* lua) {
|
||||||
int paramCount = lua_gettop(lua);
|
int paramCount = lua_gettop(lua);
|
||||||
|
|
||||||
@@ -170,10 +217,10 @@ int thrawn_topic_components(lua_State* lua) {
|
|||||||
|
|
||||||
std::vector<std::string> string_components;
|
std::vector<std::string> string_components;
|
||||||
std::stringstream topic(lua_tostring(lua, -1));
|
std::stringstream topic(lua_tostring(lua, -1));
|
||||||
std::string token;
|
std::string token;
|
||||||
while (std::getline(topic, token, '/')) {
|
while (std::getline(topic, token, '/')) {
|
||||||
string_components.push_back(token);
|
string_components.push_back(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_newtable(lua);
|
lua_newtable(lua);
|
||||||
int i = 1;
|
int i = 1;
|
||||||
@@ -224,6 +271,18 @@ void call_thrawn_on_update(LuaService& service, TopicState state) {
|
|||||||
if (lua_pcall(service.lua, 1, 0, 0) != 0) {
|
if (lua_pcall(service.lua, 1, 0, 0) != 0) {
|
||||||
spdlog::error("[{}] Unable to call 'thrawn_on_update'. [Lua: '{}']", service.name, lua_tostring(service.lua,-1));
|
spdlog::error("[{}] Unable to call 'thrawn_on_update'. [Lua: '{}']", service.name, lua_tostring(service.lua,-1));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void call_thrawn_on_schedule(LuaService& service, std::time_t now, const std::string& callback) {
|
||||||
|
lua_getglobal(service.lua, callback.c_str());
|
||||||
|
|
||||||
|
lua_pushinteger(service.lua, now);
|
||||||
|
|
||||||
|
if (lua_pcall(service.lua, 1, 0, 0) != 0) {
|
||||||
|
spdlog::error("[{}] Unable to call 'thrawn_on_schedule'. [Lua: '{}']", service.name);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,7 @@ extern "C"
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "Service.h"
|
#include "Service.h"
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
//Functions for LUA
|
//Functions for LUA
|
||||||
int thrawn_log(lua_State* lua);
|
int thrawn_log(lua_State* lua);
|
||||||
@@ -19,6 +20,8 @@ int thrawn_register_service(lua_State* lua);
|
|||||||
|
|
||||||
int thrawn_subscribe(lua_State* lua);
|
int thrawn_subscribe(lua_State* lua);
|
||||||
|
|
||||||
|
int thrawn_schedule(lua_State* lua);
|
||||||
|
|
||||||
int thrawn_publish(lua_State* lua);
|
int thrawn_publish(lua_State* lua);
|
||||||
|
|
||||||
int thrawn_create_topic_state(lua_State* lua);
|
int thrawn_create_topic_state(lua_State* lua);
|
||||||
@@ -34,6 +37,8 @@ void call_thrawn_on_start(LuaService& service);
|
|||||||
|
|
||||||
void call_thrawn_on_update(LuaService& service, TopicState state);
|
void call_thrawn_on_update(LuaService& service, TopicState state);
|
||||||
|
|
||||||
|
void call_thrawn_on_schedule(LuaService& service, std::time_t now, const std::string& callback);
|
||||||
|
|
||||||
//Database logging
|
//Database logging
|
||||||
|
|
||||||
int thrawn_log_light(lua_State* lua);
|
int thrawn_log_light(lua_State* lua);
|
||||||
|
|||||||
@@ -12,9 +12,12 @@ int thrawn_log_light(lua_State* lua) {
|
|||||||
//Param 1: room
|
//Param 1: room
|
||||||
//Param 2: name
|
//Param 2: name
|
||||||
//Param 3: is_on
|
//Param 3: is_on
|
||||||
if (!lua_isstring(lua, -3) || !lua_isstring (lua, -2) || !lua_isboolean (lua, -1)) {
|
if (!check_arguments<std::string, std::string, bool>(lua)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
// if (!lua_isstring(lua, -3) || !lua_isstring (lua, -2) || !lua_isboolean (lua, -1)) {
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
|
||||||
LuaEngine::get_instance().db_logger.write_light(lua_tostring(lua, -3), lua_tostring(lua, -2), lua_toboolean(lua, -1));
|
LuaEngine::get_instance().db_logger.write_light(lua_tostring(lua, -3), lua_tostring(lua, -2), lua_toboolean(lua, -1));
|
||||||
|
|
||||||
@@ -32,9 +35,12 @@ int thrawn_log_light_dimmable(lua_State* lua) {
|
|||||||
//Param 2: name
|
//Param 2: name
|
||||||
//Param 3: is_on
|
//Param 3: is_on
|
||||||
//Param 4: brightness
|
//Param 4: brightness
|
||||||
if (!lua_isstring(lua, -4) | !lua_isstring(lua, -3) || !lua_isboolean(lua, -2) || !lua_isinteger(lua, -1)) {
|
if (!check_arguments<std::string, std::string, bool, int>(lua)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
// if (!lua_isstring(lua, -4) | !lua_isstring(lua, -3) || !lua_isboolean(lua, -2) || !lua_isinteger(lua, -1)) {
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
|
||||||
LuaEngine::get_instance().db_logger.write_light_dimmable(lua_tostring(lua, -4), lua_tostring(lua, -3), lua_toboolean(lua, -2), lua_tointeger(lua, -1));
|
LuaEngine::get_instance().db_logger.write_light_dimmable(lua_tostring(lua, -4), lua_tostring(lua, -3), lua_toboolean(lua, -2), lua_tointeger(lua, -1));
|
||||||
|
|
||||||
@@ -53,9 +59,12 @@ int thrawn_log_light_tw(lua_State* lua) {
|
|||||||
//Param 3: is_on
|
//Param 3: is_on
|
||||||
//Param 4: brightness
|
//Param 4: brightness
|
||||||
//Param 5: color_temperature
|
//Param 5: color_temperature
|
||||||
if (!lua_isstring(lua, -5) || !lua_isstring(lua, -4) || !lua_isboolean(lua, -3) || !lua_isinteger(lua, -2) || !lua_isinteger(lua, -1)) {
|
if (!check_arguments<std::string, std::string, bool, int, int>(lua)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
// if (!lua_isstring(lua, -5) || !lua_isstring(lua, -4) || !lua_isboolean(lua, -3) || !lua_isinteger(lua, -2) || !lua_isinteger(lua, -1)) {
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
|
||||||
LuaEngine::get_instance().db_logger.write_light_tuneable_white(lua_tostring(lua, -5), lua_tostring(lua, -4), lua_toboolean(lua, -3), lua_tointeger(lua, -2), lua_tointeger(lua, -1));
|
LuaEngine::get_instance().db_logger.write_light_tuneable_white(lua_tostring(lua, -5), lua_tostring(lua, -4), lua_toboolean(lua, -3), lua_tointeger(lua, -2), lua_tointeger(lua, -1));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user