1 #include "stdafx.h"
2 #include "Helper.h"
3 #include "Logger.h"
4 #include "RFXtrx.h"
5 #include "LuaHandler.h"
6
7 extern "C" {
8 #include <lua.h>
9 #include <lualib.h>
10 #include <lauxlib.h>
11 }
12
13 #include "../tinyxpath/xpath_processor.h"
14
15 #include <json/json.h>
16 #include "SQLHelper.h"
17 #include "mainworker.h"
18 #include "../hardware/hardwaretypes.h"
19 #include <boost/thread.hpp>
20
21 extern std::string szUserDataFolder;
22
l_domoticz_updateDevice(lua_State * lua_state)23 int CLuaHandler::l_domoticz_updateDevice(lua_State* lua_state)
24 {
25 int nargs = lua_gettop(lua_state);
26 if (nargs >= 3 && nargs <= 5)
27 {
28 // Supported format ares :
29 // - deviceId (integer), svalue (string), nvalue (string), [rssi(integer)], [battery(integer)]
30 // - deviceId (integer), svalue (string), nvalue (integer), [rssi(integer)], [battery(integer)]
31 if (lua_isnumber(lua_state, 1) && (lua_isstring(lua_state, 2) || lua_isnumber(lua_state, 2)) && lua_isstring(lua_state, 3))
32 {
33 // Extract the parameters from the lua 'updateDevice' function
34 int ideviceId = (int)lua_tointeger(lua_state, 1);
35 std::string nvalue = lua_tostring(lua_state, 2);
36 std::string svalue = lua_tostring(lua_state, 3);
37 if (((lua_isstring(lua_state, 3) && nvalue.empty()) && svalue.empty()))
38 {
39 _log.Log(LOG_ERROR, "CLuaHandler (updateDevice from LUA) : nvalue and svalue are empty ");
40 return 0;
41 }
42
43 // Parse
44 int invalue = (!nvalue.empty()) ? atoi(nvalue.c_str()) : 0;
45 int signallevel = 12;
46 if (nargs >= 4 && lua_isnumber(lua_state, 4))
47 {
48 signallevel = (int)lua_tointeger(lua_state, 4);
49 }
50 int batterylevel = 255;
51 if (nargs == 5 && lua_isnumber(lua_state, 5))
52 {
53 batterylevel = (int)lua_tointeger(lua_state, 5);
54 }
55 _log.Log(LOG_NORM, "CLuaHandler (updateDevice from LUA) : idx=%d nvalue=%s svalue=%s invalue=%d signallevel=%d batterylevel=%d", ideviceId, nvalue.c_str(), svalue.c_str(), invalue, signallevel, batterylevel);
56
57 m_mainworker.UpdateDevice(ideviceId, invalue, svalue, signallevel, batterylevel);
58 }
59 else
60 {
61 _log.Log(LOG_ERROR, "CLuaHandler (updateDevice from LUA) : Incorrect parameters type");
62 }
63 }
64 else
65 {
66 _log.Log(LOG_ERROR, "CLuaHandler (updateDevice from LUA) : Not enough parameters");
67 }
68 return 0;
69 }
70
l_domoticz_print(lua_State * lua_state)71 int CLuaHandler::l_domoticz_print(lua_State* lua_state)
72 {
73 int nargs = lua_gettop(lua_state);
74
75 for (int i = 1; i <= nargs; i++)
76 {
77 if (lua_isstring(lua_state, i))
78 {
79 //std::string lstring=lua_tostring(lua_state, i);
80 _log.Log(LOG_NORM, "CLuaHandler: udevices: %s", lua_tostring(lua_state, i));
81 }
82 else
83 {
84 /* non strings? */
85 }
86 }
87 return 0;
88 }
89
CLuaHandler(int hwdID)90 CLuaHandler::CLuaHandler(int hwdID)
91 {
92 m_HwdID = hwdID;
93 }
94
luaThread(lua_State * lua_state,const std::string & filename)95 void CLuaHandler::luaThread(lua_State *lua_state, const std::string &filename)
96 {
97 int status;
98
99 status = lua_pcall(lua_state, 0, LUA_MULTRET, 0);
100 report_errors(lua_state, status);
101 lua_close(lua_state);
102 }
103
luaStop(lua_State * L,lua_Debug * ar)104 void CLuaHandler::luaStop(lua_State *L, lua_Debug *ar)
105 {
106 if (ar->event == LUA_HOOKCOUNT)
107 {
108 (void)ar; /* unused arg. */
109 lua_sethook(L, NULL, 0, 0);
110 luaL_error(L, "LuaHandler: Lua script execution exceeds maximum number of lines");
111 lua_close(L);
112 }
113 }
114
report_errors(lua_State * L,int status)115 void CLuaHandler::report_errors(lua_State *L, int status)
116 {
117 if (status != 0) {
118 _log.Log(LOG_ERROR, "CLuaHandler: %s", lua_tostring(L, -1));
119 lua_pop(L, 1); // remove error message
120 }
121 }
122
executeLuaScript(const std::string & script,const std::string & content)123 bool CLuaHandler::executeLuaScript(const std::string &script, const std::string &content)
124 {
125 std::vector<std::string> allParameters;
126 return executeLuaScript(script, content, allParameters);
127 }
128
executeLuaScript(const std::string & script,const std::string & content,std::vector<std::string> & allParameters)129 bool CLuaHandler::executeLuaScript(const std::string &script, const std::string &content, std::vector<std::string>& allParameters)
130 {
131 std::stringstream lua_DirT;
132 #ifdef WIN32
133 lua_DirT << szUserDataFolder << "scripts\\lua_parsers\\";
134 #else
135 lua_DirT << szUserDataFolder << "scripts/lua_parsers/";
136 #endif
137 std::string lua_Dir = lua_DirT.str();
138
139 lua_State *lua_state;
140 lua_state = luaL_newstate();
141
142 luaL_openlibs(lua_state);
143 lua_pushcfunction(lua_state, l_domoticz_print);
144 lua_setglobal(lua_state, "print");
145
146 lua_pushcfunction(lua_state, l_domoticz_updateDevice);
147 lua_setglobal(lua_state, "domoticz_updateDevice");
148
149 lua_pushcfunction(lua_state, l_domoticz_applyJsonPath);
150 lua_setglobal(lua_state, "domoticz_applyJsonPath");
151
152 lua_pushcfunction(lua_state, l_domoticz_applyXPath);
153 lua_setglobal(lua_state, "domoticz_applyXPath");
154
155 lua_pushinteger(lua_state, m_HwdID);
156 lua_setglobal(lua_state, "hwdId");
157
158 lua_createtable(lua_state, 1, 0);
159 lua_pushstring(lua_state, "content");
160 lua_pushstring(lua_state, content.c_str());
161 lua_rawset(lua_state, -3);
162 lua_setglobal(lua_state, "request");
163
164 CEventSystem::_tEventQueue item;
165 item.id = 0;
166 m_mainworker.m_eventsystem.ExportDeviceStatesToLua(lua_state, item);
167
168 // Push all url parameters as a map indexed by the parameter name
169 // Each entry will be uri[<param name>] = <param value>
170 int totParameters = (int)allParameters.size();
171 lua_createtable(lua_state, totParameters, 0);
172 for (int i = 0; i < totParameters; i++)
173 {
174 std::vector<std::string> parameterCouple;
175 StringSplit(allParameters[i], "=", parameterCouple);
176 if (parameterCouple.size() == 2) {
177 // Add an url parameter after 'url' decoding it
178 lua_pushstring(lua_state, CURLEncode::URLDecode(parameterCouple[0]).c_str());
179 lua_pushstring(lua_state, CURLEncode::URLDecode(parameterCouple[1]).c_str());
180 lua_rawset(lua_state, -3);
181 }
182 }
183 lua_setglobal(lua_state, "uri");
184
185 std::string fullfilename = lua_Dir + script;
186 int status = luaL_loadfile(lua_state, fullfilename.c_str());
187 if (status == 0)
188 {
189 lua_sethook(lua_state, luaStop, LUA_MASKCOUNT, 10000000);
190 boost::thread aluaThread(boost::bind(&CLuaHandler::luaThread, this, lua_state, fullfilename));
191 SetThreadName(aluaThread.native_handle(), "aluaThread");
192 aluaThread.timed_join(boost::posix_time::seconds(10));
193 return true;
194 }
195 else
196 {
197 report_errors(lua_state, status);
198 lua_close(lua_state);
199 }
200 return false;
201 }
202