1 #include "stdafx.h"
2 #include "mainworker.h"
3 #include "SQLHelper.h"
4 #include "localtime_r.h"
5 #include "../hardware/hardwaretypes.h"
6 #include "../main/Logger.h"
7 #include "../main/WebServerHelper.h"
8 #include "../main/LuaTable.h"
9 #include "../main/json_helper.h"
10 #include "dzVents.h"
11 #define __STDC_FORMAT_MACROS
12 #include <inttypes.h>
13 #include "../webserver/Base64.h"
14
15 extern "C" {
16 #include <lua.h>
17 #include <lualib.h>
18 #include <lauxlib.h>
19 }
20
21 extern std::string szUserDataFolder, szWebRoot, szStartupFolder, szAppVersion;
22 extern http::server::CWebServerHelper m_webservers;
23
24 CdzVents CdzVents::m_dzvents;
25
CdzVents(void)26 CdzVents::CdzVents(void) :
27 m_version("3.0.2")
28 {
29 m_bdzVentsExist = false;
30 }
31
~CdzVents(void)32 CdzVents::~CdzVents(void)
33 {
34 }
35
GetVersion()36 const std::string CdzVents::GetVersion()
37 {
38 return m_version;
39 }
40
EvaluateDzVents(lua_State * lua_state,const std::vector<CEventSystem::_tEventQueue> & items,const int secStatus)41 void CdzVents::EvaluateDzVents(lua_State *lua_state, const std::vector<CEventSystem::_tEventQueue> &items, const int secStatus)
42 {
43 // reroute print library to Domoticz logger
44 luaL_openlibs(lua_state);
45 lua_pushcfunction(lua_state, l_domoticz_print);
46 lua_setglobal(lua_state, "print");
47
48 bool reasonTime = false;
49 bool reasonURL = false;
50 bool reasonSecurity = false;
51 bool reasonNotification = false;
52 std::vector<CEventSystem::_tEventQueue>::const_iterator itt;
53 for (itt = items.begin(); itt != items.end(); ++itt)
54 {
55 if (itt->reason == m_mainworker.m_eventsystem.REASON_URL)
56 reasonURL = true;
57
58 if (itt->reason == m_mainworker.m_eventsystem.REASON_SECURITY)
59 reasonSecurity = true;
60
61 if (itt->reason == m_mainworker.m_eventsystem.REASON_TIME)
62 reasonTime = true;
63
64 if (itt->reason == m_mainworker.m_eventsystem.REASON_NOTIFICATION)
65 {
66 // _log.Log(LOG_STATUS, "Notification raised: %d(%s)", itt->nValue, m_mainworker.m_notificationsystem.GetTypeString(itt->nValue).c_str());
67 reasonNotification = true;
68 }
69 }
70 ExportDomoticzDataToLua(lua_state, items);
71 SetGlobalVariables(lua_state, reasonTime, secStatus);
72
73 if (reasonURL)
74 ProcessHttpResponse(lua_state, items);
75
76 if (reasonSecurity)
77 ProcessSecurity(lua_state, items);
78
79 if (reasonNotification)
80 ProcessNotification(lua_state, items);
81 }
82
ProcessNotificationItem(CLuaTable & luaTable,int & index,const CEventSystem::_tEventQueue & item)83 void CdzVents::ProcessNotificationItem(CLuaTable &luaTable, int &index, const CEventSystem::_tEventQueue& item)
84 {
85 std::string type, status;
86
87 luaTable.OpenSubTableEntry(index, 1, 4);
88 type = m_mainworker.m_notificationsystem.GetTypeString(item.nValue);
89 status = m_mainworker.m_notificationsystem.GetStatusString(item.lastLevel);
90
91 if (item.sValue.empty())
92 {
93 luaTable.AddString("message", "");
94 }
95 else
96 {
97 luaTable.AddString("message", "");
98 luaTable.OpenSubTableEntry("data", 0, 0);
99 if (item.nValue >= Notification::HW_TIMEOUT && item.nValue <= Notification::HW_THREAD_ENDED)
100 {
101 Json::Value eventdata;
102 if (ParseJSon(item.sValue, eventdata))
103 {
104 luaTable.AddInteger("id", eventdata["m_HwdID"].asInt());
105 luaTable.AddString("name", eventdata["m_Name"].asString());
106 }
107 }
108 else if (item.nValue == Notification::DZ_BACKUP_DONE)
109 {
110 Json::Value eventdata;
111 if(ParseJSon(item.sValue, eventdata))
112 {
113 type = type + eventdata["type"].asString();
114 luaTable.AddNumber("duration", eventdata["duration"].asFloat());
115 luaTable.AddString("location", eventdata["location"].asString());
116 }
117 }
118 else if (item.nValue == Notification::DZ_CUSTOM)
119 {
120 Json::Value eventdata;
121 if (ParseJSon(item.sValue, eventdata))
122 {
123 luaTable.AddString("name", eventdata["name"].asString());
124 luaTable.AddString("data", eventdata["data"].asString());
125 }
126 }
127 luaTable.CloseSubTableEntry();
128 }
129 luaTable.AddString("type", type);
130 luaTable.AddString("status", status);
131 luaTable.CloseSubTableEntry();
132 index++;
133 //_log.Log(LOG_STATUS, "dzVents notification: type: %s, status: %s, message: %s", type.c_str(), status.c_str(), item.sValue.c_str());
134 }
135
ProcessNotification(lua_State * lua_state,const std::vector<CEventSystem::_tEventQueue> & items)136 void CdzVents::ProcessNotification(lua_State* lua_state, const std::vector<CEventSystem::_tEventQueue>& items)
137 {
138 int index = 1;
139 bool bHardware = false;
140 bool bCustomEvent = false;
141 CLuaTable luaTable(lua_state, "notification");
142
143 luaTable.OpenSubTableEntry("domoticz", 0, 0);
144 std::vector<CEventSystem::_tEventQueue>::const_iterator itt;
145 for (itt = items.begin(); itt != items.end(); itt++)
146 {
147 if (itt->reason == m_mainworker.m_eventsystem.REASON_NOTIFICATION)
148 {
149 switch (itt->nValue)
150 {
151 case Notification::DZ_START:
152 case Notification::DZ_STOP:
153 case Notification::DZ_BACKUP_DONE:
154 case Notification::DZ_NOTIFICATION:
155 ProcessNotificationItem(luaTable, index, *itt);
156 break;
157 case Notification::DZ_CUSTOM:
158 bCustomEvent = true;
159 break;
160 default:
161 bHardware = true;
162 break;
163 }
164 }
165 }
166 luaTable.CloseSubTableEntry();
167
168 luaTable.OpenSubTableEntry("hardware", 0, 0);
169 if (bHardware)
170 {
171 for (itt = items.begin(); itt != items.end(); itt++)
172 {
173 switch (itt->nValue)
174 {
175 case Notification::HW_START:
176 case Notification::HW_STOP:
177 case Notification::HW_THREAD_ENDED:
178 case Notification::HW_TIMEOUT:
179 _log.Log(LOG_ERROR, "dzVents notification type: %s not yet supported", m_mainworker.m_notificationsystem.GetTypeString(itt->nValue).c_str());
180 //ProcessNotificationItem(luaTable, index, *itt);
181 break;
182 default:
183 break;
184 }
185 }
186 }
187 luaTable.CloseSubTableEntry();
188
189 luaTable.OpenSubTableEntry("customevent", 0, 0);
190 if (bCustomEvent)
191 {
192 for (itt = items.begin(); itt != items.end(); itt++)
193 {
194 switch (itt->nValue)
195 {
196 case Notification::DZ_CUSTOM:
197 ProcessNotificationItem(luaTable, index, *itt);
198 break;
199 default:
200 break;
201 }
202 }
203 }
204 luaTable.CloseSubTableEntry();
205
206 luaTable.Publish();
207 }
208
ProcessSecurity(lua_State * lua_state,const std::vector<CEventSystem::_tEventQueue> & items)209 void CdzVents::ProcessSecurity(lua_State *lua_state, const std::vector<CEventSystem::_tEventQueue> &items)
210 {
211 int index = 1;
212 int secstatus = 0;
213 std::string secstatusw = "";
214
215 CLuaTable luaTable(lua_state, "securityupdates");
216
217 std::vector<CEventSystem::_tEventQueue>::const_iterator itt;
218 for (itt = items.begin(); itt != items.end(); ++itt)
219 {
220 if (itt->reason == m_mainworker.m_eventsystem.REASON_SECURITY)
221 {
222 m_sql.GetPreferencesVar("SecStatus", secstatus);
223 if (itt->nValue == 1)
224 secstatusw = "Armed Home";
225 else if (itt->nValue == 2)
226 secstatusw = "Armed Away";
227 else
228 secstatusw = "Disarmed";
229 luaTable.AddString(index, secstatusw);
230 index++;
231 }
232 }
233 luaTable.Publish();
234 }
235
ProcessHttpResponse(lua_State * lua_state,const std::vector<CEventSystem::_tEventQueue> & items)236 void CdzVents::ProcessHttpResponse(lua_State* lua_state, const std::vector<CEventSystem::_tEventQueue>& items)
237 {
238 int index = 1;
239 int statusCode = 0;
240
241 std::string protocol;
242 std::string statusText;
243
244 CLuaTable luaTable(lua_state, "httpresponse");
245
246 std::vector<CEventSystem::_tEventQueue>::const_iterator itt;
247 for (itt = items.begin(); itt != items.end(); ++itt)
248 {
249 if (itt->reason == m_mainworker.m_eventsystem.REASON_URL)
250 {
251 luaTable.OpenSubTableEntry(index, 0, 0);
252 luaTable.OpenSubTableEntry("headers", (int)itt->vData.size() + 2, 0); // status is split into 3 parts
253 if (!itt->vData.empty())
254 {
255 std::vector<std::string>::const_iterator itt2;
256 for (itt2 = itt->vData.begin(); itt2 != itt->vData.end(); ++itt2)
257 {
258 std::string header = (*itt2);
259
260 size_t pos = header.find(": ");
261 if (pos != std::string::npos)
262 {
263 luaTable.AddString(header.substr(0, pos), header.substr(pos + 2));
264 }
265 else
266 {
267 if (header.find("HTTP/") == 0)
268 {
269 std::vector<std::string> results;
270 StringSplit(header, " ", results);
271 if (results.size() >= 2)
272 {
273 pos = header.find(results[0]);
274 protocol = header.substr(0, pos + results[0].size());
275 statusCode = atoi(results[1].c_str());
276 if (results.size() >= 3)
277 {
278 statusText = header.substr(header.find(results[2]));
279 }
280 else
281 {
282 statusText = ((statusCode >= 200) && (statusCode <= 299)) ? "OK" : "No reason returned!";
283 }
284 }
285 }
286 }
287 }
288 }
289 luaTable.CloseSubTableEntry(); // headers, why rawset was done here???
290
291 luaTable.AddString("protocol", protocol);
292 luaTable.AddString("statusText", statusText);
293 luaTable.AddInteger("statusCode", statusCode);
294 luaTable.AddString("data", itt->sValue);
295 luaTable.AddString("callback", itt->nValueWording);
296 luaTable.CloseSubTableEntry(); // index entry
297 index++;
298 }
299 }
300 luaTable.Publish();
301 }
302
OpenURL(lua_State * lua_state,const std::vector<_tLuaTableValues> & vLuaTable)303 bool CdzVents::OpenURL(lua_State *lua_state, const std::vector<_tLuaTableValues> &vLuaTable)
304 {
305 float delayTime = 0;
306 std::string URL, extraHeaders, method, postData, trigger;
307
308 std::vector<_tLuaTableValues>::const_iterator itt;
309 for (itt = vLuaTable.begin(); itt != vLuaTable.end(); ++itt)
310 {
311 if (itt->isTable && itt->sValue == "headers" && itt != vLuaTable.end() - 1)
312 {
313 int tIndex = itt->tIndex;
314 itt++;
315 std::vector<_tLuaTableValues>::const_iterator itt2;
316 for (itt2 = itt; itt2 != vLuaTable.end(); ++itt2)
317 {
318 if (itt2->tIndex != tIndex)
319 {
320 itt--;
321 break;
322 }
323 extraHeaders += "!#" + itt2->name + ": " + itt2->sValue;
324 if (itt != vLuaTable.end() - 1)
325 itt++;
326 }
327 }
328 else if (itt->type == TYPE_STRING)
329 {
330 if (itt->name == "URL")
331 URL = itt->sValue;
332 else if (itt->name == "method")
333 method = itt->sValue;
334 else if (itt->name == "postdata")
335 postData = itt->sValue;
336 else if (itt->name == "_trigger")
337 trigger = itt->sValue;
338 }
339 else if (itt->type == TYPE_INTEGER)
340 {
341 if (itt->name == "_random")
342 delayTime = static_cast<float>(GenerateRandomNumber(itt->iValue));
343 else if (itt->name == "_after")
344 delayTime = static_cast<float>(itt->iValue);
345 }
346 }
347
348 if (URL.empty())
349 {
350 _log.Log(LOG_ERROR, "dzVents: No URL supplied!");
351 return false;
352 }
353
354 // Handle situation where WebLocalNetworks is not open without password for dzVents
355 if (URL.find("127.0.0.1") != std::string::npos)
356 {
357 std::string allowedNetworks;
358 int rnvalue = 0;
359 m_sql.GetPreferencesVar("WebLocalNetworks",rnvalue, allowedNetworks);
360 if (allowedNetworks.find("127.0.0.") == std::string::npos)
361 {
362 _log.Log(LOG_ERROR, "dzVents: local netWork not open for dzVents openURL call !");
363 _log.Log(LOG_ERROR, "dzVents: check dzVents wiki (look for 'Using dzVents with Domoticz')");
364 return false;
365 }
366 }
367
368 HTTPClient::_eHTTPmethod eMethod = HTTPClient::HTTP_METHOD_GET; // defaults to GET
369 if (!method.empty())
370 {
371 if (method == "GET")
372 eMethod = HTTPClient::HTTP_METHOD_GET;
373 else if (method == "POST")
374 eMethod = HTTPClient::HTTP_METHOD_POST;
375 else if (method == "PUT")
376 eMethod = HTTPClient::HTTP_METHOD_PUT;
377 else if (method == "DELETE")
378 eMethod = HTTPClient::HTTP_METHOD_DELETE;
379 else
380 {
381 _log.Log(LOG_ERROR, "dzVents: Invalid HTTP method '%s'", method.c_str());
382 return false;
383 }
384 }
385
386 if (!postData.empty() && eMethod == HTTPClient::HTTP_METHOD_GET)
387 {
388 _log.Log(LOG_ERROR, "dzVents: You cannot use postdata with method GET.");
389 return false;
390 }
391
392 m_sql.AddTaskItem(_tTaskItem::GetHTTPPage(delayTime, URL, extraHeaders, eMethod, postData, trigger));
393 return true;
394 }
395
TriggerCustomEvent(lua_State * lua_state,const std::vector<_tLuaTableValues> & vLuaTable)396 bool CdzVents::TriggerCustomEvent(lua_State* lua_state, const std::vector<_tLuaTableValues>& vLuaTable)
397 {
398 float delayTime = 0;
399 std::string name;
400 std::string sValue;
401
402 std::vector<_tLuaTableValues>::const_iterator itt;
403 for (itt = vLuaTable.begin(); itt != vLuaTable.end(); ++itt)
404 {
405 if ((itt->type == TYPE_STRING) && (itt->name == "name"))
406 {
407 name = itt->sValue;
408 }
409 else if ((itt->type == TYPE_STRING) && (itt->name == "data"))
410 {
411 sValue = itt->sValue;
412 }
413 else if (itt->type == TYPE_INTEGER)
414 {
415 if (itt->name == "_random")
416 delayTime = static_cast<float>(GenerateRandomNumber(itt->iValue));
417 else if (itt->name == "_after")
418 {
419 delayTime = static_cast<float>(itt->iValue);
420 // _log.Log(LOG_STATUS, "dzVents: delayed custom event for %d seconds", itt->iValue);
421 }
422 }
423 }
424 if (name.empty())
425 return false;
426
427 m_sql.AddTaskItem(_tTaskItem::CustomEvent(delayTime, name, sValue));
428
429 return true;
430 }
UpdateDevice(lua_State * lua_state,const std::vector<_tLuaTableValues> & vLuaTable)431 bool CdzVents::UpdateDevice(lua_State *lua_state, const std::vector<_tLuaTableValues> &vLuaTable)
432 {
433 bool bEventTrigger = false;
434 int nValue = -1, Protected = -1;
435 int idx = -1;
436 float delayTime = 0;
437 std::string sValue;
438
439 std::vector<_tLuaTableValues>::const_iterator itt;
440 for (itt = vLuaTable.begin(); itt != vLuaTable.end(); ++itt)
441 {
442 if (itt->type == TYPE_INTEGER)
443 {
444 if (itt->name == "idx")
445 idx = itt->iValue;
446 else if (itt->name == "nValue")
447 nValue = itt->iValue;
448 else if (itt->name == "protected")
449 Protected = itt->iValue;
450 else if (itt->name == "_random")
451 delayTime = static_cast<float>(GenerateRandomNumber(itt->iValue));
452 else if (itt->name == "_after")
453 delayTime = static_cast<float>(itt->iValue);
454 }
455 else if (itt->type == TYPE_STRING && itt->name == "sValue")
456 sValue = itt->sValue;
457 else if (itt->type == TYPE_BOOLEAN && itt->name == "_trigger")
458 bEventTrigger = true;
459 }
460 if (idx == -1)
461 return false;
462
463 m_sql.AddTaskItem(_tTaskItem::UpdateDevice(delayTime, idx, nValue, sValue, Protected, bEventTrigger), false);
464 return true;
465 }
466
TriggerIFTTT(lua_State * lua_state,const std::vector<_tLuaTableValues> & vLuaTable)467 bool CdzVents::TriggerIFTTT(lua_State *lua_state, const std::vector<_tLuaTableValues> &vLuaTable)
468 {
469 std::string sID, sValue1, sValue2, sValue3 ;
470 float delayTime = 1;
471 int rnvalue = 0;
472
473 m_sql.GetPreferencesVar("IFTTTEnabled", rnvalue);
474 if (rnvalue == 0)
475 {
476 _log.Log(LOG_ERROR, "dzVents: IFTTT not enabled" );
477 return false;
478 }
479
480 std::vector<_tLuaTableValues>::const_iterator itt;
481 for (itt = vLuaTable.begin(); itt != vLuaTable.end(); ++itt)
482 {
483 if (itt->type == TYPE_INTEGER )
484 {
485 if (itt->name == "_random")
486 delayTime = static_cast<float>(GenerateRandomNumber(itt->iValue));
487
488 else if (itt->name == "_after")
489 delayTime = static_cast<float>(itt->iValue);
490
491 else if (itt->name == "sID")
492 sID = std::to_string(itt->iValue);
493
494 else if (itt->name == "sValue1")
495 sValue1 = std::to_string(itt->iValue);
496
497 else if (itt->name == "sValue2")
498 sValue2 = std::to_string(itt->iValue);
499
500 else if (itt->name == "sValue3")
501 sValue2 = std::to_string(itt->iValue);
502 }
503 else if (itt->type == TYPE_STRING)
504 {
505 if (itt->name == "sID")
506 sID = itt->sValue;
507
508 else if (itt->name == "sValue1")
509 sValue1 = itt->sValue;
510
511 else if (itt->name == "sValue2")
512 sValue2 = itt->sValue;
513
514 else if (itt->name == "sValue3")
515 sValue3 = itt->sValue;
516 }
517 }
518
519 m_sql.AddTaskItem(_tTaskItem::SendIFTTTTrigger(delayTime, sID, sValue1, sValue2, sValue3));
520 return true;
521 }
522
UpdateVariable(lua_State * lua_state,const std::vector<_tLuaTableValues> & vLuaTable)523 bool CdzVents::UpdateVariable(lua_State *lua_state, const std::vector<_tLuaTableValues> &vLuaTable)
524 {
525 std::string variableValue;
526 float delayTime = 0;
527 bool bEventTrigger = false;
528 int idx = 0;
529
530 std::vector<_tLuaTableValues>::const_iterator itt;
531 for (itt = vLuaTable.begin(); itt != vLuaTable.end(); ++itt)
532 {
533 if (itt->type == TYPE_INTEGER)
534 {
535 if (itt->name == "idx")
536 idx = itt->iValue;
537 else if (itt->name == "_random")
538 delayTime = static_cast<float>(GenerateRandomNumber(itt->iValue));
539 else if (itt->name == "_after")
540 delayTime = static_cast<float>(itt->iValue);
541 }
542 else if (itt->type == TYPE_STRING && itt->name == "value")
543 variableValue = itt->sValue;
544
545 else if (itt->type == TYPE_BOOLEAN && itt->name == "_trigger")
546 bEventTrigger = true;
547 }
548 if (idx == 0)
549 return false;
550
551 if (bEventTrigger)
552 m_mainworker.m_eventsystem.SetEventTrigger(idx, m_mainworker.m_eventsystem.REASON_USERVARIABLE, delayTime);
553
554 m_sql.AddTaskItem(_tTaskItem::SetVariable(delayTime, idx, variableValue, false));
555 return true;
556 }
557
CancelItem(lua_State * lua_state,const std::vector<_tLuaTableValues> & vLuaTable)558 bool CdzVents::CancelItem(lua_State *lua_state, const std::vector<_tLuaTableValues> &vLuaTable)
559 {
560 int idx = 0;
561 std::string type;
562
563 std::vector<_tLuaTableValues>::const_iterator itt;
564 for (itt = vLuaTable.begin(); itt != vLuaTable.end(); ++itt)
565 {
566 if (itt->type == TYPE_INTEGER && itt->name == "idx")
567 idx = itt->iValue;
568
569 else if (itt->type == TYPE_STRING && itt->name == "type")
570 type = itt->sValue;
571 }
572
573 if (idx == 0)
574 return false;
575
576 _tTaskItem tItem;
577 tItem._idx = idx;
578 tItem._DelayTime = 0;
579 if (type == "device")
580 {
581 tItem._ItemType = TITEM_SWITCHCMD_EVENT;
582 m_sql.AddTaskItem(tItem, true);
583 tItem._ItemType = TITEM_UPDATEDEVICE;
584 }
585 else if (type == "scene")
586 tItem._ItemType = TITEM_SWITCHCMD_SCENE;
587 else if (type == "variable")
588 tItem._ItemType = TITEM_SET_VARIABLE;
589
590 m_sql.AddTaskItem(tItem, true);
591 return true;
592 }
593
processLuaCommand(lua_State * lua_state,const std::string & filename,const int tIndex)594 bool CdzVents::processLuaCommand(lua_State *lua_state, const std::string &filename, const int tIndex)
595 {
596 bool scriptTrue = false;
597 std::string lCommand = std::string(lua_tostring(lua_state, -2));
598 std::vector<_tLuaTableValues> vLuaTable;
599 IterateTable(lua_state, tIndex, vLuaTable);
600 if (vLuaTable.size() > 0)
601 {
602 if (lCommand == "OpenURL")
603 scriptTrue = OpenURL(lua_state, vLuaTable);
604
605 else if (lCommand == "UpdateDevice")
606 scriptTrue = UpdateDevice(lua_state, vLuaTable);
607
608 else if (lCommand == "Variable")
609 scriptTrue = UpdateVariable(lua_state, vLuaTable);
610
611 else if (lCommand == "Cancel")
612 scriptTrue = CancelItem(lua_state, vLuaTable);
613
614 else if (lCommand == "TriggerIFTTT")
615 scriptTrue = TriggerIFTTT(lua_state, vLuaTable);
616
617 else if (lCommand == "CustomEvent")
618 scriptTrue = TriggerCustomEvent(lua_state, vLuaTable);
619 }
620 return scriptTrue;
621 }
622
IterateTable(lua_State * lua_state,const int tIndex,std::vector<_tLuaTableValues> & vLuaTable)623 void CdzVents::IterateTable(lua_State *lua_state, const int tIndex, std::vector<_tLuaTableValues> &vLuaTable)
624 {
625 _tLuaTableValues item;
626 item.isTable = false;
627
628 lua_pushnil(lua_state);
629 while (lua_next(lua_state, tIndex) != 0)
630 {
631 item.type = TYPE_UNKNOWN;
632 item.isTable = false;
633 item.tIndex = tIndex;
634 if (lua_istable(lua_state, -1))
635 {
636 if (std::string(luaL_typename(lua_state, -2)) == "string")
637 {
638 item.type = TYPE_STRING;
639 item.sValue = std::string(lua_tostring(lua_state, -2));
640 }
641 else if (std::string(luaL_typename(lua_state, -2)) == "number")
642 {
643 item.type = TYPE_INTEGER;
644 item.iValue = static_cast<int>(lua_tonumber(lua_state, -2));
645 }
646 else
647 {
648 lua_pop(lua_state, 1);
649 continue;
650 }
651 item.isTable = true;
652 item.tIndex += 2;
653 vLuaTable.push_back(item);
654 IterateTable(lua_state, item.tIndex, vLuaTable);
655 }
656 else if (std::string(luaL_typename(lua_state, -1)) == "string")
657 {
658 item.type = TYPE_STRING;
659 item.name = std::string(lua_tostring(lua_state, -2));
660 item.sValue = std::string(lua_tostring(lua_state, -1));
661 }
662 else if (std::string(luaL_typename(lua_state, -1)) == "number")
663 {
664 item.type = TYPE_INTEGER;
665 item.iValue = (int)lua_tointeger(lua_state, -1);
666 item.name = std::string(lua_tostring(lua_state, -2));
667 }
668 else if (std::string(luaL_typename(lua_state, -1)) == "boolean")
669 {
670 item.type = TYPE_BOOLEAN;
671 item.iValue = lua_toboolean(lua_state, -1);
672 item.name = std::string(lua_tostring(lua_state, -2));
673 }
674 if (!item.isTable && item.type != TYPE_UNKNOWN)
675 vLuaTable.push_back(item);
676
677 lua_pop(lua_state, 1);
678 }
679 }
680
l_domoticz_print(lua_State * lua_state)681 int CdzVents::l_domoticz_print(lua_State* lua_state)
682 {
683 int nargs = lua_gettop(lua_state);
684
685 for (int i = 1; i <= nargs; i++)
686 {
687 if (lua_isstring(lua_state, i))
688 {
689 std::string lstring = lua_tostring(lua_state, i);
690 if (lstring.find("Error: ") != std::string::npos)
691 {
692 _log.Log(LOG_ERROR, "dzVents: %s", lstring.c_str());
693 }
694 else
695 {
696 _log.Log(LOG_STATUS, "dzVents: %s", lstring.c_str());
697 }
698 }
699 else
700 {
701 /* non strings? */
702 }
703 }
704 return 0;
705 }
706
SetGlobalVariables(lua_State * lua_state,const bool reasonTime,const int secStatus)707 void CdzVents::SetGlobalVariables(lua_State *lua_state, const bool reasonTime, const int secStatus)
708 {
709 std::stringstream lua_DirT, runtime_DirT;
710
711 lua_DirT << szUserDataFolder <<
712 #ifdef WIN32
713 "scripts\\dzVents\\";
714 #else
715 "scripts/dzVents/";
716 #endif
717
718 runtime_DirT << szStartupFolder <<
719 #ifdef WIN32
720 "dzVents\\runtime\\";
721 #else
722 "dzVents/runtime/";
723 #endif
724
725 CLuaTable luaTable(lua_state, "globalvariables");
726 luaTable.AddString("Security", m_mainworker.m_eventsystem.m_szSecStatus[secStatus]);
727 luaTable.AddString("script_path", lua_DirT.str());
728 luaTable.AddString("runtime_path", runtime_DirT.str());
729 luaTable.AddBool("isTimeEvent", reasonTime);
730
731 char szTmp[10];
732 sprintf(szTmp, "%.02f", 1.23f);
733 luaTable.AddString("radix_separator", std::string(1,szTmp[1]));
734
735 sprintf(szTmp, "%.02f", 1234.56f);
736 if (szTmp[1] == '2')
737 {
738 luaTable.AddString("group_separator", "");
739 }
740 else
741 {
742 luaTable.AddString("group_separator", std::string(1,szTmp[1]));
743 }
744
745 int rnvalue = 0;
746 m_sql.GetPreferencesVar("DzVentsLogLevel", rnvalue);
747 luaTable.AddInteger("dzVents_log_level", rnvalue);
748
749 std::string sTitle;
750 m_sql.GetPreferencesVar("Title", sTitle);
751 luaTable.AddString("domoticz_title", sTitle);
752
753 // Only when webLocalNetworks has local network defined
754 // Add latitude / longitude to table
755 std::string allowedNetworks;
756 rnvalue = 0;
757 m_sql.GetPreferencesVar("WebLocalNetworks",rnvalue, allowedNetworks);
758 if (allowedNetworks.find("127.0.0.") != std::string::npos)
759 {
760 std::string location;
761 std::vector<std::string> strarray;
762 if (m_sql.GetPreferencesVar("Location", rnvalue, location))
763 StringSplit(location, ";", strarray);
764 if (strarray.size() == 2)
765 {
766 // Only when location entered in the settings
767 // Add to table
768 luaTable.AddString("latitude", strarray[0]);
769 luaTable.AddString("longitude", strarray[1]);
770 }
771 }
772
773 luaTable.AddString("domoticz_listening_port", m_webservers.our_listener_port);
774 luaTable.AddString("domoticz_webroot", szWebRoot);
775 luaTable.AddString("domoticz_start_time", m_mainworker.m_eventsystem.m_szStartTime);
776 luaTable.AddString("currentTime", TimeToString(NULL, TF_DateTimeMs));
777 luaTable.AddInteger("systemUptime", SystemUptime());
778 luaTable.AddString("domoticz_version", szAppVersion);
779 luaTable.AddString("dzVents_version", GetVersion());
780
781 luaTable.Publish();
782 }
783
ExportHardwareData(CLuaTable & luaTable,int & index,const std::vector<CEventSystem::_tEventQueue> & items)784 void CdzVents::ExportHardwareData(CLuaTable &luaTable, int& index, const std::vector<CEventSystem::_tEventQueue>& items)
785 {
786 ;// to be implemented when hardware notification support is added
787 }
788
ExportDomoticzDataToLua(lua_State * lua_state,const std::vector<CEventSystem::_tEventQueue> & items)789 void CdzVents::ExportDomoticzDataToLua(lua_State *lua_state, const std::vector<CEventSystem::_tEventQueue> &items)
790 {
791 boost::shared_lock<boost::shared_mutex> devicestatesMutexLock(m_mainworker.m_eventsystem.m_devicestatesMutex);
792 int index = 1;
793 time_t now = mytime(NULL);
794 struct tm tm1;
795 localtime_r(&now, &tm1);
796 struct tm tLastUpdate;
797 localtime_r(&now, &tLastUpdate);
798 int SensorTimeOut = 60;
799 m_sql.GetPreferencesVar("SensorTimeout", SensorTimeOut);
800
801 struct tm ntime;
802 time_t checktime;
803
804 CLuaTable luaTable(lua_state, "domoticzData");
805
806 // First export all the devices.
807 std::map<uint64_t, CEventSystem::_tDeviceStatus>::iterator iterator;
808 for (iterator = m_mainworker.m_eventsystem.m_devicestates.begin(); iterator != m_mainworker.m_eventsystem.m_devicestates.end(); ++iterator)
809 {
810 CEventSystem::_tDeviceStatus sitem = iterator->second;
811 const char *dev_type = RFX_Type_Desc(sitem.devType, 1);
812 const char *sub_type = RFX_Type_SubType_Desc(sitem.devType, sitem.subType);
813
814 bool triggerDevice = false;
815 std::vector<CEventSystem::_tEventQueue>::const_iterator itt;
816 for (itt = items.begin(); itt != items.end(); ++itt)
817 {
818 if (sitem.ID == itt->id && itt->reason == m_mainworker.m_eventsystem.REASON_DEVICE)
819 {
820 triggerDevice = true;
821 sitem.lastUpdate = itt->lastUpdate;
822 sitem.lastLevel = itt->lastLevel;
823 sitem.sValue = itt->sValue;
824 sitem.nValueWording = itt->nValueWording;
825 sitem.nValue = itt->nValue;
826 if (itt->JsonMapString.size() > 0)
827 sitem.JsonMapString = itt->JsonMapString;
828 if (itt->JsonMapFloat.size() > 0)
829 sitem.JsonMapFloat = itt->JsonMapFloat;
830 if (itt->JsonMapInt.size() > 0)
831 sitem.JsonMapInt = itt->JsonMapInt;
832 if (itt->JsonMapBool.size() > 0)
833 sitem.JsonMapBool = itt->JsonMapBool;
834 }
835 }
836
837 //_log.Log(LOG_STATUS, "Getting device with id: %s", rowid.c_str());
838
839 ParseSQLdatetime(checktime, ntime, sitem.lastUpdate, tm1.tm_isdst);
840 bool timed_out = (now - checktime >= SensorTimeOut * 60);
841
842 luaTable.OpenSubTableEntry(index, 1, 12);
843
844 luaTable.AddString("name", sitem.deviceName);
845 luaTable.AddBool("protected", (sitem.protection == 1) );
846 luaTable.AddInteger("id", sitem.ID);
847 luaTable.AddString("baseType","device");
848 luaTable.AddString("deviceType", dev_type);
849 luaTable.AddString("subType", sub_type);
850 luaTable.AddString("switchType", Switch_Type_Desc((_eSwitchType)sitem.switchtype));
851 luaTable.AddInteger("switchTypeValue", sitem.switchtype);
852 luaTable.AddString("lastUpdate", sitem.lastUpdate);
853 luaTable.AddInteger("lastLevel", sitem.lastLevel);
854 luaTable.AddBool("changed", triggerDevice);
855 luaTable.AddBool("timedOut", timed_out);
856
857 //get all svalues separate
858 std::vector<std::string> strarray;
859 StringSplit(sitem.sValue, ";", strarray);
860
861 luaTable.OpenSubTableEntry("rawData", 0, 0);
862 for (uint8_t i = 0; i < strarray.size(); i++)
863 {
864 luaTable.AddString(i + 1, strarray[i]);
865 }
866 luaTable.CloseSubTableEntry(); // rawData table
867
868 luaTable.AddString("deviceID", sitem.deviceID);
869 luaTable.AddString("description", sitem.description);
870 luaTable.AddInteger("batteryLevel", sitem.batteryLevel);
871 luaTable.AddInteger("signalLevel", sitem.signalLevel);
872
873 luaTable.OpenSubTableEntry("data", 0, 0);
874 luaTable.AddString("_state", sitem.nValueWording);
875 luaTable.AddInteger("_nValue", sitem.nValue);
876 luaTable.AddInteger("hardwareID", sitem.hardwareID);
877
878 // Lux does not have it's own field yet.
879 if (sitem.devType == pTypeLux && sitem.subType == sTypeLux)
880 {
881 int lux = 0;
882 if (strarray.size() > 0)
883 lux = atoi(strarray[0].c_str());
884 luaTable.AddNumber("lux", lux);
885 }
886
887 if (sitem.devType == pTypeGeneral && sitem.subType == sTypeKwh)
888 {
889 long double value = 0.0f;
890 if (strarray.size() > 1)
891 value = atof(strarray[1].c_str());
892 luaTable.AddNumber("whTotal", value);
893 value = 0.0f;
894 if (strarray.size() > 0)
895 value = atof(strarray[0].c_str());
896 luaTable.AddNumber("whActual", value);
897 }
898
899 // Now see if we have additional fields from the JSON data
900 if (sitem.JsonMapString.size() > 0)
901 {
902 std::map<uint8_t, std::string>::const_iterator itt;
903 for (itt = sitem.JsonMapString.begin(); itt != sitem.JsonMapString.end(); ++itt)
904 {
905 if (strcmp(m_mainworker.m_eventsystem.JsonMap[itt->first].szOriginal, "LevelNames") == 0 ||
906 strcmp(m_mainworker.m_eventsystem.JsonMap[itt->first].szOriginal, "LevelActions") == 0)
907 luaTable.AddString(
908 m_mainworker.m_eventsystem.JsonMap[itt->first].szNew,
909 base64_decode(itt->second));
910 else
911 luaTable.AddString(
912 m_mainworker.m_eventsystem.JsonMap[itt->first].szNew,
913 itt->second);
914 }
915 }
916
917 if (sitem.JsonMapFloat.size() > 0)
918 {
919 std::map<uint8_t, float>::const_iterator itt;
920 for (itt = sitem.JsonMapFloat.begin(); itt != sitem.JsonMapFloat.end(); ++itt)
921 {
922 luaTable.AddNumber(m_mainworker.m_eventsystem.JsonMap[itt->first].szNew, itt->second);
923 }
924 }
925
926 if (sitem.JsonMapInt.size() > 0)
927 {
928 std::map<uint8_t, int>::const_iterator itt;
929 for (itt = sitem.JsonMapInt.begin(); itt != sitem.JsonMapInt.end(); ++itt)
930 {
931 luaTable.AddInteger(m_mainworker.m_eventsystem.JsonMap[itt->first].szNew, itt->second);
932 }
933 }
934
935 if (sitem.JsonMapBool.size() > 0)
936 {
937 std::map<uint8_t, bool>::const_iterator itt;
938 for (itt = sitem.JsonMapBool.begin(); itt != sitem.JsonMapBool.end(); ++itt)
939 {
940 luaTable.AddBool(m_mainworker.m_eventsystem.JsonMap[itt->first].szNew, itt->second);
941 }
942 }
943
944 luaTable.CloseSubTableEntry(); // data table
945 luaTable.CloseSubTableEntry(); // device entry
946 index++;
947 }
948 devicestatesMutexLock.unlock();
949
950 // Now do the scenes and groups.
951 const char *description = "";
952 boost::shared_lock<boost::shared_mutex> scenesgroupsMutexLock(m_mainworker.m_eventsystem.m_scenesgroupsMutex);
953
954 std::map<uint64_t, CEventSystem::_tScenesGroups>::const_iterator ittScenes;
955 for (ittScenes = m_mainworker.m_eventsystem.m_scenesgroups.begin(); ittScenes != m_mainworker.m_eventsystem.m_scenesgroups.end(); ++ittScenes)
956 {
957 CEventSystem::_tScenesGroups sgitem = ittScenes->second;
958 bool triggerScene = false;
959 std::vector<CEventSystem::_tEventQueue>::const_iterator itt;
960 for (itt = items.begin(); itt != items.end(); ++itt)
961 {
962 if (sgitem.ID == itt->id && itt->reason == m_mainworker.m_eventsystem.REASON_SCENEGROUP)
963 {
964 triggerScene = true;
965 sgitem.lastUpdate = itt->lastUpdate;
966 sgitem.scenesgroupValue = itt->sValue;
967 }
968 }
969
970 std::vector<std::vector<std::string> > result;
971 result = m_sql.safe_query("SELECT Description FROM Scenes WHERE (ID=='%d')", sgitem.ID);
972 if (result.empty())
973 description = "";
974 else
975 description = result[0][0].c_str();
976
977 luaTable.OpenSubTableEntry(index, 1, 7);
978
979 luaTable.AddString("name", sgitem.scenesgroupName);
980 luaTable.AddInteger("id", sgitem.ID);
981 luaTable.AddString("description", description);
982 luaTable.AddString("baseType", (sgitem.scenesgroupType == 0) ? "scene" : "group");
983 luaTable.AddBool("protected", (lua_Number)sgitem.protection == 1);
984 luaTable.AddString("lastUpdate", sgitem.lastUpdate);
985 luaTable.AddBool("changed", triggerScene);
986
987 luaTable.OpenSubTableEntry("data", 0, 0);
988
989 luaTable.AddString("_state", sgitem.scenesgroupValue);
990
991 luaTable.CloseSubTableEntry(); // data, why rawset was done here???
992
993 luaTable.OpenSubTableEntry("deviceIDs", 0, 0);
994 std::vector<uint64_t>::const_iterator itt2;
995 if (sgitem.memberID.size() > 0)
996 {
997 int index = 1;
998 for (itt2 = sgitem.memberID.begin(); itt2 != sgitem.memberID.end(); ++itt2)
999 {
1000 luaTable.AddInteger(index, *itt2);
1001 index++;
1002 }
1003 }
1004
1005 luaTable.CloseSubTableEntry(); // device table
1006 luaTable.CloseSubTableEntry(); // end entry
1007 index++;
1008 }
1009 scenesgroupsMutexLock.unlock();
1010
1011 std::string vtype;
1012
1013 // Now do the user variables.
1014 boost::shared_lock<boost::shared_mutex> uservariablesMutexLock(m_mainworker.m_eventsystem.m_uservariablesMutex);
1015 std::map<uint64_t, CEventSystem::_tUserVariable>::const_iterator it_var;
1016 for (it_var = m_mainworker.m_eventsystem.m_uservariables.begin(); it_var != m_mainworker.m_eventsystem.m_uservariables.end(); ++it_var)
1017 {
1018 CEventSystem::_tUserVariable uvitem = it_var->second;
1019 bool triggerVar = false;
1020 std::vector<CEventSystem::_tEventQueue>::const_iterator itt;
1021 for (itt = items.begin(); itt != items.end(); ++itt)
1022 {
1023 if (uvitem.ID == itt->id && itt->reason == m_mainworker.m_eventsystem.REASON_USERVARIABLE)
1024 {
1025 triggerVar = true;
1026 uvitem.lastUpdate = itt->lastUpdate;
1027 uvitem.variableValue = itt->sValue;
1028 }
1029 }
1030
1031 luaTable.OpenSubTableEntry(index, 1, 5);
1032
1033 luaTable.AddString("name", uvitem.variableName);
1034 luaTable.AddInteger("id", uvitem.ID);
1035 luaTable.AddString("baseType", "uservariable");
1036 luaTable.AddString("lastUpdate", uvitem.lastUpdate);
1037 luaTable.AddBool("changed", triggerVar);
1038
1039 luaTable.OpenSubTableEntry("data", 0, 0);
1040
1041 if (uvitem.variableType == 0)
1042 {
1043 luaTable.AddInteger("value", atoi(uvitem.variableValue.c_str()));
1044 vtype = "integer";
1045 }
1046 else if (uvitem.variableType == 1)
1047 {
1048 //Float
1049 luaTable.AddNumber("value", atof(uvitem.variableValue.c_str()));
1050 vtype = "float";
1051 }
1052 else
1053 {
1054 //String,Date,Time
1055 luaTable.AddString("value", uvitem.variableValue);
1056 if (uvitem.variableType == 2)
1057 vtype = "string";
1058 else if (uvitem.variableType == 3)
1059 vtype = "date";
1060 else if (uvitem.variableType == 4)
1061 vtype = "time";
1062 else
1063 vtype = "unknown";
1064 }
1065
1066 luaTable.CloseSubTableEntry(); // data table
1067
1068 luaTable.AddString("variableType", vtype);
1069
1070 luaTable.CloseSubTableEntry(); // end entry
1071
1072 index++;
1073 }
1074
1075 // Now do the cameras.
1076 std::vector<std::vector<std::string> > result;
1077 result = m_sql.safe_query("SELECT ID, Name FROM Cameras where enabled = '1' ORDER BY ID ASC");
1078 if (!result.empty())
1079 {
1080 for (const auto & itt : result)
1081 {
1082 std::vector<std::string> sd = itt;
1083
1084 luaTable.OpenSubTableEntry(index, 1, 3);
1085 luaTable.AddString("name", sd[1]);
1086 luaTable.AddInteger("id", atoi(sd[0].c_str()));
1087 luaTable.AddString("baseType", "camera");
1088 luaTable.CloseSubTableEntry(); // end entry
1089
1090 index++;
1091 }
1092 }
1093 ExportHardwareData(luaTable, index, items);
1094
1095 luaTable.Publish();
1096 }
1097