1 #include "stdafx.h"
2 #include "mainworker.h"
3 #include "Helper.h"
4 #include "SunRiseSet.h"
5 #include "localtime_r.h"
6 #include "Logger.h"
7 #include "WebServerHelper.h"
8 #include "SQLHelper.h"
9 #include "../push/FibaroPush.h"
10 #include "../push/HttpPush.h"
11 #include "../push/InfluxPush.h"
12 #include "../push/GooglePubSubPush.h"
13
14 #include "../httpclient/HTTPClient.h"
15 #include "../webserver/Base64.h"
16 #include <boost/algorithm/string/join.hpp>
17 #include "../main/json_helper.h"
18
19 #include <boost/crc.hpp>
20 #include <algorithm>
21 #include <set>
22
23 //Hardware Devices
24 #include "../hardware/hardwaretypes.h"
25 #include "../hardware/RFXBase.h"
26 #include "../hardware/RFXComSerial.h"
27 #include "../hardware/RFXComTCP.h"
28 #include "../hardware/DomoticzTCP.h"
29 #include "../hardware/P1MeterBase.h"
30 #include "../hardware/P1MeterSerial.h"
31 #include "../hardware/P1MeterTCP.h"
32 #include "../hardware/YouLess.h"
33 #ifdef WITH_LIBUSB
34 #include "../hardware/TE923.h"
35 #include "../hardware/VolcraftCO20.h"
36 #endif
37 #include "../hardware/Rego6XXSerial.h"
38 #ifdef WITH_OPENZWAVE
39 #include "../hardware/OpenZWave.h"
40 #endif
41 #include "../hardware/DavisLoggerSerial.h"
42 #include "../hardware/1Wire.h"
43 #include "../hardware/I2C.h"
44 #include "../hardware/Wunderground.h"
45 #include "../hardware/DarkSky.h"
46 #include "../hardware/HardwareMonitor.h"
47 #include "../hardware/Dummy.h"
48 #include "../hardware/Tellstick.h"
49 #include "../hardware/PiFace.h"
50 #include "../hardware/S0MeterSerial.h"
51 #include "../hardware/S0MeterTCP.h"
52 #include "../hardware/OTGWSerial.h"
53 #include "../hardware/OTGWTCP.h"
54 #include "../hardware/TeleinfoBase.h"
55 #include "../hardware/TeleinfoSerial.h"
56 #include "../hardware/Limitless.h"
57 #include "../hardware/MochadTCP.h"
58 #include "../hardware/EnOceanESP2.h"
59 #include "../hardware/EnOceanESP3.h"
60 #include "../hardware/SBFSpot.h"
61 #include "../hardware/PhilipsHue/PhilipsHue.h"
62 #include "../hardware/ICYThermostat.h"
63 #include "../hardware/WOL.h"
64 #include "../hardware/Meteostick.h"
65 #include "../hardware/PVOutput_Input.h"
66 #include "../hardware/ToonThermostat.h"
67 #include "../hardware/HarmonyHub.h"
68 #include "../hardware/EcoDevices.h"
69 #include "../hardware/EvohomeBase.h"
70 #include "../hardware/EvohomeScript.h"
71 #include "../hardware/EvohomeSerial.h"
72 #include "../hardware/EvohomeTCP.h"
73 #include "../hardware/EvohomeWeb.h"
74 #include "../hardware/MySensorsSerial.h"
75 #include "../hardware/MySensorsTCP.h"
76 #include "../hardware/MySensorsMQTT.h"
77 #include "../hardware/MQTT.h"
78 #include "../hardware/FritzboxTCP.h"
79 #include "../hardware/ETH8020.h"
80 #include "../hardware/RFLinkSerial.h"
81 #include "../hardware/RFLinkTCP.h"
82 #include "../hardware/KMTronicSerial.h"
83 #include "../hardware/KMTronicTCP.h"
84 #include "../hardware/KMTronicUDP.h"
85 #include "../hardware/KMTronic433.h"
86 #include "../hardware/SolarMaxTCP.h"
87 #include "../hardware/Pinger.h"
88 #include "../hardware/Nest.h"
89 #include "../hardware/NestOAuthAPI.h"
90 #include "../hardware/Thermosmart.h"
91 #include "../hardware/Tado.h"
92 #include "../hardware/eVehicles/eVehicle.h"
93 #include "../hardware/Kodi.h"
94 #include "../hardware/Netatmo.h"
95 #include "../hardware/HttpPoller.h"
96 #include "../hardware/AnnaThermostat.h"
97 #include "../hardware/Winddelen.h"
98 #include "../hardware/SatelIntegra.h"
99 #include "../hardware/LogitechMediaServer.h"
100 #include "../hardware/Comm5TCP.h"
101 #include "../hardware/Comm5SMTCP.h"
102 #include "../hardware/Comm5Serial.h"
103 #include "../hardware/CurrentCostMeterSerial.h"
104 #include "../hardware/CurrentCostMeterTCP.h"
105 #include "../hardware/SolarEdgeAPI.h"
106 #include "../hardware/DomoticzInternal.h"
107 #include "../hardware/NefitEasy.h"
108 #include "../hardware/PanasonicTV.h"
109 #include "../hardware/OpenWebNetTCP.h"
110 #include "../hardware/AtagOne.h"
111 #include "../hardware/Sterbox.h"
112 #include "../hardware/RAVEn.h"
113 #include "../hardware/DenkoviDevices.h"
114 #include "../hardware/DenkoviUSBDevices.h"
115 #include "../hardware/DenkoviTCPDevices.h"
116 #include "../hardware/AccuWeather.h"
117 #include "../hardware/BleBox.h"
118 #include "../hardware/Ec3kMeterTCP.h"
119 #include "../hardware/OpenWeatherMap.h"
120 #include "../hardware/GoodweAPI.h"
121 #include "../hardware/Daikin.h"
122 #include "../hardware/HEOS.h"
123 #include "../hardware/MultiFun.h"
124 #include "../hardware/ZiBlueSerial.h"
125 #include "../hardware/ZiBlueTCP.h"
126 #include "../hardware/Yeelight.h"
127 #include "../hardware/XiaomiGateway.h"
128 #ifdef ENABLE_PYTHON
129 #include "../hardware/plugins/Plugins.h"
130 #endif
131 #include "../hardware/Arilux.h"
132 #include "../hardware/OpenWebNetUSB.h"
133 #include "../hardware/InComfort.h"
134 #include "../hardware/RelayNet.h"
135 #include "../hardware/SysfsGpio.h"
136 #include "../hardware/Rtl433.h"
137 #include "../hardware/OnkyoAVTCP.h"
138 #include "../hardware/USBtin.h"
139 #include "../hardware/USBtin_MultiblocV8.h"
140 #include "../hardware/EnphaseAPI.h"
141 #include "../hardware/eHouseTCP.h"
142 #include "../hardware/EcoCompteur.h"
143 #include "../hardware/Honeywell.h"
144 #include "../hardware/TTNMQTT.h"
145 #include "../hardware/Buienradar.h"
146 #include "../hardware/OctoPrintMQTT.h"
147
148 // load notifications configuration
149 #include "../notifications/NotificationHelper.h"
150
151 #ifdef WITH_GPIO
152 #include "../hardware/Gpio.h"
153 #include "../hardware/GpioPin.h"
154 #endif
155
156 #ifdef WIN32
157 #include "../msbuild/WindowsHelper.h"
158 #include "dirent_windows.h"
159 #else
160 #include <sys/utsname.h>
161 #include <dirent.h>
162 #endif
163
164 #include "mainstructs.h"
165 #define __STDC_FORMAT_MACROS
166 #include <inttypes.h>
167
168 #ifdef _DEBUG
169 //#define PARSE_RFXCOM_DEVICE_LOG
170 //#define DEBUG_DOWNLOAD
171 //#define DEBUG_RXQUEUE
172 #endif
173
174 #ifdef PARSE_RFXCOM_DEVICE_LOG
175 #include <iostream>
176 #include <fstream>
177 #endif
178
179 #define round(a) ( int ) ( a + .5 )
180
181 extern std::string szStartupFolder;
182 extern std::string szUserDataFolder;
183 extern std::string szWWWFolder;
184 extern int iAppRevision;
185 extern std::string szWebRoot;
186 extern bool g_bUseUpdater;
187 extern http::server::_eWebCompressionMode g_wwwCompressMode;
188 extern http::server::CWebServerHelper m_webservers;
189 extern bool g_bUseEventTrigger;
190 extern std::string szRandomUUID;
191
192 CFibaroPush m_fibaropush;
193 CGooglePubSubPush m_googlepubsubpush;
194 CHttpPush m_httppush;
195 CInfluxPush m_influxpush;
196
197
198 namespace tcp {
199 namespace server {
200 class CTCPClient;
201 } //namespace server
202 } //namespace tcp
203
MainWorker()204 MainWorker::MainWorker()
205 {
206 m_SecCountdown = -1;
207
208 m_bStartHardware = false;
209 m_hardwareStartCounter = 0;
210
211 // Set default settings for web servers
212 m_webserver_settings.listening_address = "::"; // listen to all network interfaces
213 m_webserver_settings.listening_port = "8080";
214 #ifdef WWW_ENABLE_SSL
215 m_secure_webserver_settings.listening_address = "::"; // listen to all network interfaces
216 m_secure_webserver_settings.listening_port = "443";
217 m_secure_webserver_settings.ssl_method = "sslv23";
218 m_secure_webserver_settings.certificate_chain_file_path = "./server_cert.pem";
219 m_secure_webserver_settings.ca_cert_file_path = m_secure_webserver_settings.certificate_chain_file_path; // not used
220 m_secure_webserver_settings.cert_file_path = m_secure_webserver_settings.certificate_chain_file_path;
221 m_secure_webserver_settings.private_key_file_path = m_secure_webserver_settings.certificate_chain_file_path;
222 m_secure_webserver_settings.private_key_pass_phrase = "";
223 m_secure_webserver_settings.ssl_options = "default_workarounds,no_sslv2,no_sslv3,no_tlsv1,no_tlsv1_1,single_dh_use";
224 m_secure_webserver_settings.tmp_dh_file_path = m_secure_webserver_settings.certificate_chain_file_path;
225 m_secure_webserver_settings.verify_peer = false;
226 m_secure_webserver_settings.verify_fail_if_no_peer_cert = false;
227 m_secure_webserver_settings.verify_file_path = "";
228 #endif
229 m_bIgnoreUsernamePassword = false;
230
231 time_t atime = mytime(NULL);
232 m_LastHeartbeat = atime;
233 struct tm ltime;
234 localtime_r(&atime, <ime);
235 m_ScheduleLastMinute = ltime.tm_min;
236 m_ScheduleLastHour = ltime.tm_hour;
237 m_ScheduleLastMinuteTime = 0;
238 m_ScheduleLastHourTime = 0;
239 m_ScheduleLastDayTime = 0;
240 m_LastSunriseSet = "";
241 m_DayLength = "";
242
243 m_bHaveDownloadedDomoticzUpdate = false;
244 m_bHaveDownloadedDomoticzUpdateSuccessFull = false;
245 m_bDoDownloadDomoticzUpdate = false;
246 m_LastUpdateCheck = 0;
247 m_bHaveUpdate = false;
248 m_iRevision = 0;
249
250 m_SecStatus = SECSTATUS_DISARMED;
251
252 m_rxMessageIdx = 1;
253 m_bForceLogNotificationCheck = false;
254 }
255
~MainWorker()256 MainWorker::~MainWorker()
257 {
258 Stop();
259 }
260
AddAllDomoticzHardware()261 void MainWorker::AddAllDomoticzHardware()
262 {
263 //Add Hardware devices
264 std::vector<std::vector<std::string> > result;
265 result = m_sql.safe_query(
266 "SELECT ID, Name, Enabled, Type, Address, Port, SerialPort, Username, Password, Extra, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6, DataTimeout FROM Hardware ORDER BY ID ASC");
267 if (!result.empty())
268 {
269 for (const auto& itt : result)
270 {
271 std::vector<std::string> sd = itt;
272
273 int ID = atoi(sd[0].c_str());
274 std::string Name = sd[1];
275 std::string sEnabled = sd[2];
276 bool Enabled = (sEnabled == "1") ? true : false;
277 _eHardwareTypes Type = (_eHardwareTypes)atoi(sd[3].c_str());
278 std::string Address = sd[4];
279 uint16_t Port = (uint16_t)atoi(sd[5].c_str());
280 std::string SerialPort = sd[6];
281 std::string Username = sd[7];
282 std::string Password = sd[8];
283 std::string Extra = sd[9];
284 int mode1 = atoi(sd[10].c_str());
285 int mode2 = atoi(sd[11].c_str());
286 int mode3 = atoi(sd[12].c_str());
287 int mode4 = atoi(sd[13].c_str());
288 int mode5 = atoi(sd[14].c_str());
289 int mode6 = atoi(sd[15].c_str());
290 int DataTimeout = atoi(sd[16].c_str());
291 AddHardwareFromParams(ID, Name, Enabled, Type, Address, Port, SerialPort, Username, Password, Extra, mode1, mode2, mode3, mode4, mode5, mode6, DataTimeout, false);
292 }
293 m_hardwareStartCounter = 0;
294 m_bStartHardware = true;
295 }
296 }
297
StartDomoticzHardware()298 void MainWorker::StartDomoticzHardware()
299 {
300 std::vector<CDomoticzHardwareBase*>::iterator itt;
301 for (auto& itt : m_hardwaredevices)
302 {
303 if (!itt->IsStarted())
304 {
305 itt->Start();
306 }
307 }
308 }
309
StopDomoticzHardware()310 void MainWorker::StopDomoticzHardware()
311 {
312 // Separate the Stop() from the device removal from the vector.
313 // Some actions the hardware might take during stop (e.g updating a device) can cause deadlocks on the m_devicemutex
314 std::vector<CDomoticzHardwareBase*> OrgHardwaredevices;
315 {
316 std::lock_guard<std::mutex> l(m_devicemutex);
317 for (auto& itt : m_hardwaredevices)
318 {
319 OrgHardwaredevices.push_back(itt);
320 }
321 m_hardwaredevices.clear();
322 }
323
324 for (auto& itt : OrgHardwaredevices)
325 {
326 #ifdef ENABLE_PYTHON
327 m_pluginsystem.DeregisterPlugin(itt->m_HwdID);
328 #endif
329 itt->Stop();
330 delete itt;
331 }
332 }
333
GetAvailableWebThemes()334 void MainWorker::GetAvailableWebThemes()
335 {
336 std::string ThemeFolder = szWWWFolder + "/styles/";
337 m_webthemes.clear();
338 DirectoryListing(m_webthemes, ThemeFolder, true, false);
339
340 //check if current theme is found, if not, select default
341 bool bFound = false;
342 std::string sValue;
343 if (m_sql.GetPreferencesVar("WebTheme", sValue))
344 {
345 for (const auto& itt : m_webthemes)
346 {
347 if (itt == sValue)
348 {
349 bFound = true;
350 break;
351 }
352 }
353 }
354 if (!bFound)
355 {
356 m_sql.UpdatePreferencesVar("WebTheme", "default");
357 }
358 }
359
AddDomoticzHardware(CDomoticzHardwareBase * pHardware)360 void MainWorker::AddDomoticzHardware(CDomoticzHardwareBase* pHardware)
361 {
362 int devidx = FindDomoticzHardware(pHardware->m_HwdID);
363 if (devidx != -1) //it is already there!, remove it
364 {
365 RemoveDomoticzHardware(m_hardwaredevices[devidx]);
366 }
367 std::lock_guard<std::mutex> l(m_devicemutex);
368 pHardware->sDecodeRXMessage.connect(boost::bind(&MainWorker::DecodeRXMessage, this, _1, _2, _3, _4));
369 pHardware->sOnConnected.connect(boost::bind(&MainWorker::OnHardwareConnected, this, _1));
370 m_hardwaredevices.push_back(pHardware);
371 }
372
RemoveDomoticzHardware(CDomoticzHardwareBase * pHardware)373 void MainWorker::RemoveDomoticzHardware(CDomoticzHardwareBase* pHardware)
374 {
375 // Separate the Stop() from the device removal from the vector.
376 // Some actions the hardware might take during stop (e.g updating a device) can cause deadlocks on the m_devicemutex
377 CDomoticzHardwareBase* pOrgHardware = NULL;
378 {
379 std::lock_guard<std::mutex> l(m_devicemutex);
380 std::vector<CDomoticzHardwareBase*>::iterator itt;
381 for (itt = m_hardwaredevices.begin(); itt != m_hardwaredevices.end(); ++itt)
382 {
383 pOrgHardware = *itt;
384 if (pOrgHardware == pHardware) {
385 m_hardwaredevices.erase(itt);
386 break;
387 }
388 }
389 }
390
391 if (pOrgHardware == pHardware)
392 {
393 try
394 {
395 pOrgHardware->Stop();
396 delete pOrgHardware;
397 }
398 catch (std::exception& e)
399 {
400 _log.Log(LOG_ERROR, "Mainworker: Exception: %s (%s:%d)", e.what(), std::string(__func__).substr(std::string(__func__).find_last_of("/\\") + 1).c_str(), __LINE__);
401 }
402 catch (...)
403 {
404 _log.Log(LOG_ERROR, "Mainworker: Exception catched! %s:%d", std::string(__func__).substr(std::string(__func__).find_last_of("/\\") + 1).c_str(), __LINE__);
405 }
406 }
407 }
408
RemoveDomoticzHardware(int HwdId)409 void MainWorker::RemoveDomoticzHardware(int HwdId)
410 {
411 int dpos = FindDomoticzHardware(HwdId);
412 if (dpos == -1)
413 return;
414 #ifdef ENABLE_PYTHON
415 m_pluginsystem.DeregisterPlugin(HwdId);
416 #endif
417 RemoveDomoticzHardware(m_hardwaredevices[dpos]);
418 }
419
FindDomoticzHardware(int HwdId)420 int MainWorker::FindDomoticzHardware(int HwdId)
421 {
422 std::lock_guard<std::mutex> l(m_devicemutex);
423 int ii = 0;
424 for (const auto& itt : m_hardwaredevices)
425 {
426 if (itt->m_HwdID == HwdId)
427 return ii;
428 ii++;
429 }
430 return -1;
431 }
432
FindDomoticzHardwareByType(const _eHardwareTypes HWType)433 int MainWorker::FindDomoticzHardwareByType(const _eHardwareTypes HWType)
434 {
435 std::lock_guard<std::mutex> l(m_devicemutex);
436 int ii = 0;
437 for (const auto& itt : m_hardwaredevices)
438 {
439 if (itt->HwdType == HWType)
440 return ii;
441 ii++;
442 }
443 return -1;
444 }
445
GetHardware(int HwdId)446 CDomoticzHardwareBase* MainWorker::GetHardware(int HwdId)
447 {
448 std::lock_guard<std::mutex> l(m_devicemutex);
449 for (auto& itt : m_hardwaredevices)
450 {
451 if (itt->m_HwdID == HwdId)
452 return itt;
453 }
454 return NULL;
455 }
456
GetHardwareByIDType(const std::string & HwdId,const _eHardwareTypes HWType)457 CDomoticzHardwareBase* MainWorker::GetHardwareByIDType(const std::string& HwdId, const _eHardwareTypes HWType)
458 {
459 if (HwdId == "")
460 return NULL;
461 int iHardwareID = atoi(HwdId.c_str());
462 CDomoticzHardwareBase* pHardware = m_mainworker.GetHardware(iHardwareID);
463 if (pHardware == NULL)
464 return NULL;
465 if (pHardware->HwdType != HWType)
466 return NULL;
467 return pHardware;
468 }
469
GetHardwareByType(const _eHardwareTypes HWType)470 CDomoticzHardwareBase* MainWorker::GetHardwareByType(const _eHardwareTypes HWType)
471 {
472 std::lock_guard<std::mutex> l(m_devicemutex);
473 for (auto& itt : m_hardwaredevices)
474 {
475 if (itt->HwdType == HWType)
476 return itt;
477 }
478 return NULL;
479 }
480
481 // sunset/sunrise
482 // http://www.earthtools.org/sun/<latitude>/<longitude>/<day>/<month>/<timezone>/<dst>
483 // example:
484 // http://www.earthtools.org/sun/52.214268/5.171002/11/11/99/1
485
GetSunSettings()486 bool MainWorker::GetSunSettings()
487 {
488 int nValue;
489 std::string sValue;
490 std::vector<std::string> strarray;
491 if (m_sql.GetPreferencesVar("Location", nValue, sValue))
492 StringSplit(sValue, ";", strarray);
493
494 if (strarray.size() != 2)
495 {
496 // No location entered in the settings, lets just reload our schedules and return
497 // Load non sun settings timers
498 m_scheduler.ReloadSchedules();
499 return false;
500 }
501
502 std::string Latitude = strarray[0];
503 std::string Longitude = strarray[1];
504
505 time_t atime = mytime(NULL);
506 struct tm ltime;
507 localtime_r(&atime, <ime);
508
509 int year = ltime.tm_year + 1900;
510 int month = ltime.tm_mon + 1;
511 int day = ltime.tm_mday;
512
513 double dLatitude = atof(Latitude.c_str());
514 double dLongitude = atof(Longitude.c_str());
515
516 SunRiseSet::_tSubRiseSetResults sresult;
517 SunRiseSet::GetSunRiseSet(dLatitude, dLongitude, year, month, day, sresult);
518
519 std::string sunrise;
520 std::string sunset;
521 std::string daylength;
522 std::string sunatsouth;
523 std::string civtwstart;
524 std::string civtwend;
525 std::string nauttwstart;
526 std::string nauttwend;
527 std::string asttwstart;
528 std::string asttwend;
529
530 char szRiseSet[30];
531 sprintf(szRiseSet, "%02d:%02d:00", sresult.SunRiseHour, sresult.SunRiseMin);
532 sunrise = szRiseSet;
533 sprintf(szRiseSet, "%02d:%02d:00", sresult.SunSetHour, sresult.SunSetMin);
534 sunset = szRiseSet;
535 sprintf(szRiseSet, "%02d:%02d:00", sresult.DaylengthHours, sresult.DaylengthMins);
536 daylength = szRiseSet;
537 sprintf(szRiseSet, "%02d:%02d:00", sresult.SunAtSouthHour, sresult.SunAtSouthMin);
538 sunatsouth = szRiseSet;
539 sprintf(szRiseSet, "%02d:%02d:00", sresult.CivilTwilightStartHour, sresult.CivilTwilightStartMin);
540 civtwstart = szRiseSet;
541 sprintf(szRiseSet, "%02d:%02d:00", sresult.CivilTwilightEndHour, sresult.CivilTwilightEndMin);
542 civtwend = szRiseSet;
543 sprintf(szRiseSet, "%02d:%02d:00", sresult.NauticalTwilightStartHour, sresult.NauticalTwilightStartMin);
544 nauttwstart = szRiseSet;
545 sprintf(szRiseSet, "%02d:%02d:00", sresult.NauticalTwilightEndHour, sresult.NauticalTwilightEndMin);
546 nauttwend = szRiseSet;
547 sprintf(szRiseSet, "%02d:%02d:00", sresult.AstronomicalTwilightStartHour, sresult.AstronomicalTwilightStartMin);
548 asttwstart = szRiseSet;
549 sprintf(szRiseSet, "%02d:%02d:00", sresult.AstronomicalTwilightEndHour, sresult.AstronomicalTwilightEndMin);
550 asttwend = szRiseSet;
551
552 m_scheduler.SetSunRiseSetTimers(sunrise, sunset, sunatsouth, civtwstart, civtwend, nauttwstart, nauttwend, asttwstart, asttwend); // Do not change the order
553
554 bool bFirstTime = m_LastSunriseSet.empty();
555
556 std::string riseset = sunrise.substr(0, sunrise.size() - 3) + ";" + sunset.substr(0, sunset.size() - 3) + ";" + sunatsouth.substr(0, sunatsouth.size() - 3) + ";" + civtwstart.substr(0, civtwstart.size() - 3) + ";" + civtwend.substr(0, civtwend.size() - 3) + ";" + nauttwstart.substr(0, nauttwstart.size() - 3) + ";" + nauttwend.substr(0, nauttwend.size() - 3) + ";" + asttwstart.substr(0, asttwstart.size() - 3) + ";" + asttwend.substr(0, asttwend.size() - 3) + ";" + daylength.substr(0, daylength.size() - 3); //make a short version
557 if (m_LastSunriseSet != riseset)
558 {
559 m_DayLength = daylength;
560 m_LastSunriseSet = riseset;
561
562 // Now store all the time stamps e.g. "08:42;09:12" etc, found in m_LastSunriseSet into
563 // a new vector after that we've first converted them to minutes after midnight.
564 std::vector<std::string> strarray;
565 std::vector<std::string> hourMinItem;
566 StringSplit(m_LastSunriseSet, ";", strarray);
567 m_SunRiseSetMins.clear();
568
569 for (const auto& it : strarray)
570 {
571 StringSplit(it, ":", hourMinItem);
572 int intMins = (atoi(hourMinItem[0].c_str()) * 60) + atoi(hourMinItem[1].c_str());
573 m_SunRiseSetMins.push_back(intMins);
574 }
575
576 if (sunrise == sunset)
577 if (m_DayLength == "00:00:00")
578 _log.Log(LOG_NORM, "Sun below horizon in the space of 24 hours");
579 else
580 _log.Log(LOG_NORM, "Sun above horizon in the space of 24 hours");
581 else
582 _log.Log(LOG_NORM, "Sunrise: %s SunSet: %s", sunrise.c_str(), sunset.c_str());
583 _log.Log(LOG_NORM, "Day length: %s Sun at south: %s", daylength.c_str(), sunatsouth.c_str());
584 if (civtwstart == civtwend)
585 _log.Log(LOG_NORM, "There is no civil twilight in the space of 24 hours");
586 else
587 _log.Log(LOG_NORM, "Civil twilight start: %s Civil twilight end: %s", civtwstart.c_str(), civtwend.c_str());
588 if (nauttwstart == nauttwend)
589 _log.Log(LOG_NORM, "There is no nautical twilight in the space of 24 hours");
590 else
591 _log.Log(LOG_NORM, "Nautical twilight start: %s Nautical twilight end: %s", nauttwstart.c_str(), nauttwend.c_str());
592 if (asttwstart == asttwend)
593 _log.Log(LOG_NORM, "There is no astronomical twilight in the space of 24 hours");
594 else
595 _log.Log(LOG_NORM, "Astronomical twilight start: %s Astronomical twilight end: %s", asttwstart.c_str(), asttwend.c_str());
596
597 if (!bFirstTime)
598 m_eventsystem.LoadEvents();
599
600 // FixMe: only reload schedules relative to sunset/sunrise to prevent race conditions
601 // m_scheduler.ReloadSchedules(); // force reload of all schedules to adjust for changed sunrise/sunset values
602 }
603 return true;
604 }
605
SetWebserverSettings(const http::server::server_settings & settings)606 void MainWorker::SetWebserverSettings(const http::server::server_settings& settings)
607 {
608 m_webserver_settings.set(settings);
609 }
610
GetWebserverAddress()611 std::string MainWorker::GetWebserverAddress()
612 {
613 return m_webserver_settings.listening_address;
614 }
615
GetWebserverPort()616 std::string MainWorker::GetWebserverPort()
617 {
618 return m_webserver_settings.listening_port;
619 }
620
621 #ifdef WWW_ENABLE_SSL
GetSecureWebserverPort()622 std::string MainWorker::GetSecureWebserverPort()
623 {
624 return m_secure_webserver_settings.listening_port;
625 }
626
SetSecureWebserverSettings(const http::server::ssl_server_settings & ssl_settings)627 void MainWorker::SetSecureWebserverSettings(const http::server::ssl_server_settings& ssl_settings)
628 {
629 m_secure_webserver_settings.set(ssl_settings);
630 }
631 #endif
632
RestartHardware(const std::string & idx)633 bool MainWorker::RestartHardware(const std::string& idx)
634 {
635 std::vector<std::vector<std::string> > result;
636 result = m_sql.safe_query(
637 "SELECT Name, Enabled, Type, Address, Port, SerialPort, Username, Password, Extra, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6, DataTimeout FROM Hardware WHERE (ID=='%q')",
638 idx.c_str());
639 if (result.empty())
640 return false;
641 std::vector<std::string> sd = result[0];
642 std::string Name = sd[0];
643 std::string senabled = (sd[1] == "1") ? "true" : "false";
644 _eHardwareTypes htype = (_eHardwareTypes)atoi(sd[2].c_str());
645 std::string address = sd[3];
646 uint16_t port = (uint16_t)atoi(sd[4].c_str());
647 std::string serialport = sd[5];
648 std::string username = sd[6];
649 std::string password = sd[7];
650 std::string extra = sd[8];
651 int Mode1 = atoi(sd[9].c_str());
652 int Mode2 = atoi(sd[10].c_str());
653 int Mode3 = atoi(sd[11].c_str());
654 int Mode4 = atoi(sd[12].c_str());
655 int Mode5 = atoi(sd[13].c_str());
656 int Mode6 = atoi(sd[14].c_str());
657 int DataTimeout = atoi(sd[15].c_str());
658 return AddHardwareFromParams(atoi(idx.c_str()), Name, (senabled == "true") ? true : false, htype, address, port, serialport, username, password, extra, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6, DataTimeout, true);
659 }
660
AddHardwareFromParams(const int ID,const std::string & Name,const bool Enabled,const _eHardwareTypes Type,const std::string & Address,const uint16_t Port,const std::string & SerialPort,const std::string & Username,const std::string & Password,const std::string & Extra,const int Mode1,const int Mode2,const int Mode3,const int Mode4,const int Mode5,const int Mode6,const int DataTimeout,const bool bDoStart)661 bool MainWorker::AddHardwareFromParams(
662 const int ID,
663 const std::string& Name,
664 const bool Enabled,
665 const _eHardwareTypes Type,
666 const std::string& Address, const uint16_t Port, const std::string& SerialPort,
667 const std::string& Username, const std::string& Password,
668 const std::string& Extra,
669 const int Mode1,
670 const int Mode2,
671 const int Mode3,
672 const int Mode4,
673 const int Mode5,
674 const int Mode6,
675 const int DataTimeout,
676 const bool bDoStart
677 )
678 {
679 RemoveDomoticzHardware(ID);
680
681 if (!Enabled)
682 return true;
683
684 CDomoticzHardwareBase* pHardware = NULL;
685
686 switch (Type)
687 {
688 case HTYPE_RFXtrx315:
689 case HTYPE_RFXtrx433:
690 case HTYPE_RFXtrx868:
691 pHardware = new RFXComSerial(ID, SerialPort, 38400, (CRFXBase::_eRFXAsyncType)atoi(Extra.c_str()));
692 break;
693 case HTYPE_RFXLAN:
694 pHardware = new RFXComTCP(ID, Address, Port, (CRFXBase::_eRFXAsyncType)atoi(Extra.c_str()));
695 break;
696 case HTYPE_P1SmartMeter:
697 pHardware = new P1MeterSerial(ID, SerialPort, (Mode1 == 1) ? 115200 : 9600, (Mode2 != 0), Mode3);
698 break;
699 case HTYPE_Rego6XX:
700 pHardware = new CRego6XXSerial(ID, SerialPort, Mode1);
701 break;
702 case HTYPE_DavisVantage:
703 pHardware = new CDavisLoggerSerial(ID, SerialPort, 19200);
704 break;
705 case HTYPE_S0SmartMeterUSB:
706 pHardware = new S0MeterSerial(ID, SerialPort, 9600);
707 break;
708 case HTYPE_S0SmartMeterTCP:
709 //LAN
710 pHardware = new S0MeterTCP(ID, Address, Port);
711 break;
712 case HTYPE_OpenThermGateway:
713 pHardware = new OTGWSerial(ID, SerialPort, 9600, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6);
714 break;
715 case HTYPE_TeleinfoMeter:
716 pHardware = new CTeleinfoSerial(ID, SerialPort, DataTimeout, Mode1, (Mode2 != 0), Mode3);
717 break;
718 case HTYPE_MySensorsUSB:
719 pHardware = new MySensorsSerial(ID, SerialPort, Mode1);
720 break;
721 case HTYPE_KMTronicUSB:
722 pHardware = new KMTronicSerial(ID, SerialPort);
723 break;
724 case HTYPE_KMTronic433:
725 pHardware = new KMTronic433(ID, SerialPort);
726 break;
727 case HTYPE_OpenZWave:
728 #ifdef WITH_OPENZWAVE
729 pHardware = new COpenZWave(ID, SerialPort);
730 #endif
731 break;
732 case HTYPE_EnOceanESP2:
733 pHardware = new CEnOceanESP2(ID, SerialPort, Mode1);
734 break;
735 case HTYPE_EnOceanESP3:
736 pHardware = new CEnOceanESP3(ID, SerialPort, Mode1);
737 break;
738 case HTYPE_Meteostick:
739 pHardware = new Meteostick(ID, SerialPort, 115200);
740 break;
741 case HTYPE_EVOHOME_SERIAL:
742 pHardware = new CEvohomeSerial(ID, SerialPort, Mode1, Extra);
743 break;
744 case HTYPE_EVOHOME_TCP:
745 pHardware = new CEvohomeTCP(ID, Address, Port, Extra);
746 break;
747 case HTYPE_RFLINKUSB:
748 pHardware = new CRFLinkSerial(ID, SerialPort);
749 break;
750 case HTYPE_ZIBLUEUSB:
751 pHardware = new CZiBlueSerial(ID, SerialPort);
752 break;
753 case HTYPE_CurrentCostMeter:
754 pHardware = new CurrentCostMeterSerial(ID, SerialPort, (Mode1 == 1) ? 57600 : 9600);
755 break;
756 case HTYPE_RAVEn:
757 pHardware = new RAVEn(ID, SerialPort);
758 break;
759 case HTYPE_Comm5Serial:
760 pHardware = new Comm5Serial(ID, SerialPort);
761 break;
762 case HTYPE_Domoticz:
763 //LAN
764 pHardware = new DomoticzTCP(ID, Address, Port, Username, Password);
765 break;
766 case HTYPE_P1SmartMeterLAN:
767 //LAN
768 pHardware = new P1MeterTCP(ID, Address, Port, (Mode2 != 0), Mode3);
769 break;
770 case HTYPE_WOL:
771 //LAN
772 pHardware = new CWOL(ID, Address, Port);
773 break;
774 case HTYPE_OpenThermGatewayTCP:
775 //LAN
776 pHardware = new OTGWTCP(ID, Address, Port, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6);
777 break;
778 case HTYPE_MySensorsTCP:
779 //LAN
780 pHardware = new MySensorsTCP(ID, Address, Port);
781 break;
782 case HTYPE_MySensorsMQTT:
783 //LAN
784 pHardware = new MySensorsMQTT(ID, Name, Address, Port, Username, Password, Extra, Mode2, Mode1, Mode3 != 0);
785 break;
786 case HTYPE_RFLINKTCP:
787 //LAN
788 pHardware = new CRFLinkTCP(ID, Address, Port);
789 break;
790 case HTYPE_ZIBLUETCP:
791 //LAN
792 pHardware = new CZiBlueTCP(ID, Address, Port);
793 break;
794 case HTYPE_MQTT:
795 //LAN
796 pHardware = new MQTT(ID, Address, Port, Username, Password, Extra, Mode2, Mode1, (std::string("Domoticz") + szRandomUUID).c_str(), Mode3 != 0);
797 break;
798 case HTYPE_eHouseTCP:
799 //eHouse LAN, WiFi,Pro and other via eHousePRO gateway
800 pHardware = new eHouseTCP(ID, Address, Port, Password, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6);
801 break;
802 case HTYPE_FRITZBOX:
803 //LAN
804 pHardware = new FritzboxTCP(ID, Address, Port);
805 break;
806 case HTYPE_SOLARMAXTCP:
807 //LAN
808 pHardware = new SolarMaxTCP(ID, Address, Port);
809 break;
810 case HTYPE_LimitlessLights:
811 //LAN
812 {
813 int rmode1 = Mode1;
814 if (rmode1 == 0)
815 rmode1 = 1;
816 pHardware = new CLimitLess(ID, rmode1, Mode2, Address, Port);
817 }
818 break;
819 case HTYPE_YouLess:
820 //LAN
821 pHardware = new CYouLess(ID, Address, Port, Password);
822 break;
823 case HTYPE_WINDDELEN:
824 pHardware = new CWinddelen(ID, Address, Port, Mode1);
825 break;
826 case HTYPE_ETH8020:
827 //LAN
828 pHardware = new CETH8020(ID, Address, Port, Username, Password);
829 break;
830 case HTYPE_RelayNet:
831 //LAN
832 pHardware = new RelayNet(ID, Address, Port, Username, Password, Mode1 != 0, Mode2 != 0, Mode3, Mode4, Mode5);
833 break;
834 case HTYPE_KMTronicTCP:
835 //LAN
836 pHardware = new KMTronicTCP(ID, Address, Port, Username, Password);
837 break;
838 case HTYPE_KMTronicUDP:
839 //UDP
840 pHardware = new KMTronicUDP(ID, Address, Port);
841 break;
842 case HTYPE_NefitEastLAN:
843 pHardware = new CNefitEasy(ID, Address, Port);
844 break;
845 case HTYPE_ECODEVICES:
846 //LAN
847 pHardware = new CEcoDevices(ID, Address, Port, Username, Password, DataTimeout, Mode1, Mode2);
848 break;
849 case HTYPE_1WIRE:
850 //1-Wire file system
851 pHardware = new C1Wire(ID, Mode1, Mode2, Extra);
852 break;
853 case HTYPE_Pinger:
854 //System Alive Checker (Ping)
855 pHardware = new CPinger(ID, Mode1, Mode2);
856 break;
857 case HTYPE_Kodi:
858 //Kodi Media Player
859 pHardware = new CKodi(ID, Mode1, Mode2);
860 break;
861 case HTYPE_PanasonicTV:
862 //Panasonic Viera TV's
863 pHardware = new CPanasonic(ID, Mode1, Mode2);
864 break;
865 case HTYPE_Mochad:
866 //LAN
867 pHardware = new MochadTCP(ID, Address, Port);
868 break;
869 case HTYPE_SatelIntegra:
870 pHardware = new SatelIntegra(ID, Address, Port, Password, Mode1);
871 break;
872 case HTYPE_LogitechMediaServer:
873 //Logitech Media Server
874 pHardware = new CLogitechMediaServer(ID, Address, Port, Username, Password, Mode1);
875 break;
876 case HTYPE_Sterbox:
877 //LAN
878 pHardware = new CSterbox(ID, Address, Port, Username, Password);
879 break;
880 case HTYPE_DenkoviHTTPDevices:
881 //LAN
882 pHardware = new CDenkoviDevices(ID, Address, Port, Password, Mode1, Mode2);
883 break;
884 case HTYPE_DenkoviUSBDevices:
885 //USB
886 pHardware = new CDenkoviUSBDevices(ID, SerialPort, Mode1);
887 break;
888 case HTYPE_DenkoviTCPDevices:
889 //LAN
890 pHardware = new CDenkoviTCPDevices(ID, Address, Port, Mode1, Mode2, Mode3);
891 break;
892 case HTYPE_HEOS:
893 //HEOS by DENON
894 pHardware = new CHEOS(ID, Address, Port, Username, Password, Mode1, Mode2);
895 break;
896 case HTYPE_MultiFun:
897 //MultiFun LAN
898 pHardware = new MultiFun(ID, Address, Port);
899 break;
900 #ifndef WIN32
901 case HTYPE_TE923:
902 //TE923 compatible weather station
903 #ifdef WITH_LIBUSB
904 pHardware = new CTE923(ID);
905 #endif
906 break;
907 case HTYPE_VOLCRAFTCO20:
908 //Voltcraft CO-20 Air Quality
909 #ifdef WITH_LIBUSB
910 pHardware = new CVolcraftCO20(ID);
911 #endif
912 break;
913 #endif
914 case HTYPE_RaspberryBMP085:
915 pHardware = new I2C(ID, I2C::I2CTYPE_BMP085, Address, SerialPort, Mode1);
916 break;
917 case HTYPE_RaspberryHTU21D:
918 pHardware = new I2C(ID, I2C::I2CTYPE_HTU21D, Address, SerialPort, Mode1);
919 break;
920 case HTYPE_RaspberryTSL2561:
921 pHardware = new I2C(ID, I2C::I2CTYPE_TSL2561, Address, SerialPort, Mode1);
922 break;
923 case HTYPE_RaspberryPCF8574:
924 pHardware = new I2C(ID, I2C::I2CTYPE_PCF8574, Address, SerialPort, Mode1);
925 break;
926 case HTYPE_RaspberryBME280:
927 pHardware = new I2C(ID, I2C::I2CTYPE_BME280, Address, SerialPort, Mode1);
928 break;
929 case HTYPE_RaspberryMCP23017:
930 pHardware = new I2C(ID, I2C::I2CTYPE_MCP23017, Address, SerialPort, Mode1);
931 break;
932 case HTYPE_Wunderground:
933 pHardware = new CWunderground(ID, Username, Password);
934 break;
935 case HTYPE_HTTPPOLLER:
936 pHardware = new CHttpPoller(ID, Username, Password, Address, Extra, Port);
937 break;
938 case HTYPE_DarkSky:
939 pHardware = new CDarkSky(ID, Username, Password);
940 break;
941 case HTYPE_AccuWeather:
942 pHardware = new CAccuWeather(ID, Username, Password);
943 break;
944 case HTYPE_SolarEdgeAPI:
945 pHardware = new SolarEdgeAPI(ID, Username);
946 break;
947 case HTYPE_Netatmo:
948 pHardware = new CNetatmo(ID, Username, Password);
949 break;
950 case HTYPE_Daikin:
951 pHardware = new CDaikin(ID, Address, Port, Username, Password);
952 break;
953 case HTYPE_SBFSpot:
954 pHardware = new CSBFSpot(ID, Username);
955 break;
956 case HTYPE_ICYTHERMOSTAT:
957 pHardware = new CICYThermostat(ID, Username, Password);
958 break;
959 case HTYPE_TOONTHERMOSTAT:
960 pHardware = new CToonThermostat(ID, Username, Password, Mode1);
961 break;
962 case HTYPE_AtagOne:
963 pHardware = new CAtagOne(ID, Username, Password, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6);
964 break;
965 case HTYPE_NEST:
966 pHardware = new CNest(ID, Username, Password);
967 break;
968 case HTYPE_Nest_OAuthAPI:
969 pHardware = new CNestOAuthAPI(ID, Username, Extra);
970 break;
971 case HTYPE_ANNATHERMOSTAT:
972 pHardware = new CAnnaThermostat(ID, Address, Port, Username, Password);
973 break;
974 case HTYPE_THERMOSMART:
975 pHardware = new CThermosmart(ID, Username, Password, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6);
976 break;
977 case HTYPE_Tado:
978 pHardware = new CTado(ID, Username, Password);
979 break;
980 case HTYPE_Tesla:
981 pHardware = new CeVehicle(ID, CeVehicle::Tesla, Username, Password, Mode1, Mode2, Mode3, Extra);
982 break;
983 case HTYPE_Honeywell:
984 pHardware = new CHoneywell(ID, Username, Password, Extra);
985 break;
986 case HTYPE_Philips_Hue:
987 pHardware = new CPhilipsHue(ID, Address, Port, Username, Mode1, Mode2);
988 break;
989 case HTYPE_HARMONY_HUB:
990 pHardware = new CHarmonyHub(ID, Address, Port);
991 break;
992 case HTYPE_PVOUTPUT_INPUT:
993 pHardware = new CPVOutputInput(ID, Username, Password);
994 break;
995 case HTYPE_Dummy:
996 pHardware = new CDummy(ID);
997 break;
998 case HTYPE_Tellstick: {
999 CTellstick* tellstick;
1000 if (CTellstick::Create(&tellstick, ID, Mode1, Mode2)) {
1001 pHardware = tellstick;
1002 }
1003 }
1004 break;
1005 case HTYPE_EVOHOME_SCRIPT:
1006 pHardware = new CEvohomeScript(ID);
1007 break;
1008 case HTYPE_PiFace:
1009 pHardware = new CPiFace(ID);
1010 break;
1011 case HTYPE_System:
1012 pHardware = new CHardwareMonitor(ID);
1013 break;
1014 case HTYPE_RaspberryGPIO:
1015 //Raspberry Pi GPIO port access
1016 #ifdef WITH_GPIO
1017 pHardware = new CGpio(ID, Mode1, Mode2, Mode3);
1018 #endif
1019 break;
1020 case HTYPE_SysfsGpio:
1021 #ifdef WITH_GPIO
1022 pHardware = new CSysfsGpio(ID, Mode1, Mode2);
1023 #endif
1024 break;
1025 case HTYPE_Comm5TCP:
1026 //LAN
1027 pHardware = new Comm5TCP(ID, Address, Port);
1028 break;
1029 case HTYPE_CurrentCostMeterLAN:
1030 //LAN
1031 pHardware = new CurrentCostMeterTCP(ID, Address, Port);
1032 break;
1033 case HTYPE_DomoticzInternal:
1034 pHardware = new DomoticzInternal(ID);
1035 break;
1036 case HTYPE_OpenWebNetTCP:
1037 pHardware = new COpenWebNetTCP(ID, Address, Port, Password, Mode1);
1038 break;
1039 case HTYPE_BleBox:
1040 pHardware = new BleBox(ID, Mode1);
1041 break;
1042 case HTYPE_OpenWeatherMap:
1043 pHardware = new COpenWeatherMap(ID, Username, Password);
1044 break;
1045 case HTYPE_Ec3kMeterTCP:
1046 pHardware = new Ec3kMeterTCP(ID, Address, Port);
1047 break;
1048 case HTYPE_GoodweAPI:
1049 pHardware = new GoodweAPI(ID, Username, Mode1);
1050 break;
1051 case HTYPE_Yeelight:
1052 pHardware = new Yeelight(ID);
1053 break;
1054 case HTYPE_PythonPlugin:
1055 #ifdef ENABLE_PYTHON
1056 pHardware = m_pluginsystem.RegisterPlugin(ID, Name, Extra);
1057 #endif
1058 break;
1059 case HTYPE_XiaomiGateway:
1060 pHardware = new XiaomiGateway(ID);
1061 break;
1062 case HTYPE_Arilux:
1063 pHardware = new Arilux(ID);
1064 break;
1065 case HTYPE_OpenWebNetUSB:
1066 pHardware = new COpenWebNetUSB(ID, SerialPort, 115200);
1067 break;
1068 case HTYPE_IntergasInComfortLAN2RF:
1069 pHardware = new CInComfort(ID, Address, Port);
1070 break;
1071 case HTYPE_EVOHOME_WEB:
1072 pHardware = new CEvohomeWeb(ID, Username, Password, Mode1, Mode2, Mode3);
1073 break;
1074 case HTYPE_Rtl433:
1075 pHardware = new CRtl433(ID, Extra);
1076 break;
1077 case HTYPE_OnkyoAVTCP:
1078 pHardware = new OnkyoAVTCP(ID, Address, Port);
1079 break;
1080 case HTYPE_USBtinGateway:
1081 pHardware = new USBtin(ID, SerialPort, Mode1, Mode2);
1082 break;
1083 case HTYPE_EnphaseAPI:
1084 pHardware = new EnphaseAPI(ID, Address, Port);
1085 break;
1086 case HTYPE_Comm5SMTCP:
1087 pHardware = new Comm5SMTCP(ID, Address, Port);
1088 break;
1089 case HTYPE_EcoCompteur:
1090 pHardware = new CEcoCompteur(ID, Address, Port);
1091 break;
1092 case HTYPE_TTN_MQTT:
1093 pHardware = new CTTNMQTT(ID, Address, Port, Username, Password, Extra);
1094 break;
1095 case HTYPE_BuienRadar:
1096 pHardware = new CBuienRadar(ID, Mode1, Mode2, Password);
1097 break;
1098 case HTYPE_OctoPrint:
1099 pHardware = new COctoPrintMQTT(ID, Address, Port, Username, Password, Extra);
1100 break;
1101 }
1102
1103 if (pHardware)
1104 {
1105 pHardware->HwdType = Type;
1106 pHardware->m_Name = Name;
1107 pHardware->m_ShortName = Hardware_Short_Desc(Type);
1108 pHardware->m_DataTimeout = DataTimeout;
1109 AddDomoticzHardware(pHardware);
1110
1111 if (bDoStart)
1112 pHardware->Start();
1113 return true;
1114 }
1115 return false;
1116 }
1117
Start()1118 bool MainWorker::Start()
1119 {
1120 utsname my_uname;
1121 if (uname(&my_uname) == 0)
1122 {
1123 m_szSystemName = my_uname.sysname;
1124 std::transform(m_szSystemName.begin(), m_szSystemName.end(), m_szSystemName.begin(), ::tolower);
1125 }
1126
1127 if (!m_sql.OpenDatabase())
1128 {
1129 return false;
1130 }
1131
1132 HTTPClient::SetUserAgent(GenerateUserAgent());
1133 m_notifications.Init();
1134 GetSunSettings();
1135 GetAvailableWebThemes();
1136 #ifdef ENABLE_PYTHON
1137 if (m_sql.m_bEnableEventSystem)
1138 {
1139 m_pluginsystem.StartPluginSystem();
1140 }
1141 #endif
1142 AddAllDomoticzHardware();
1143 m_fibaropush.Start();
1144 m_httppush.Start();
1145 m_influxpush.Start();
1146 m_googlepubsubpush.Start();
1147 #ifdef PARSE_RFXCOM_DEVICE_LOG
1148 if (m_bStartHardware == false)
1149 m_bStartHardware = true;
1150 #endif
1151 // load notifications configuration
1152 m_notifications.LoadConfig();
1153
1154 if (m_webserver_settings.is_enabled()
1155 #ifdef WWW_ENABLE_SSL
1156 || m_secure_webserver_settings.is_enabled()
1157 #endif
1158 )
1159 {
1160 //Start WebServer
1161 #ifdef WWW_ENABLE_SSL
1162 if (!m_webservers.StartServers(m_webserver_settings, m_secure_webserver_settings, szWWWFolder, m_bIgnoreUsernamePassword, &m_sharedserver))
1163 #else
1164 if (!m_webservers.StartServers(m_webserver_settings, szWWWFolder, m_bIgnoreUsernamePassword, &m_sharedserver))
1165 #endif
1166 {
1167 #ifdef WIN32
1168 MessageBox(0, "Error starting webserver(s), check if ports are not in use!", MB_OK, MB_ICONERROR);
1169 #endif
1170 return false;
1171 }
1172 }
1173 int nValue = 0;
1174 if (m_sql.GetPreferencesVar("AuthenticationMethod", nValue))
1175 {
1176 m_webservers.SetAuthenticationMethod((http::server::_eAuthenticationMethod)nValue);
1177 }
1178 std::string sValue;
1179 if (m_sql.GetPreferencesVar("WebTheme", sValue))
1180 {
1181 m_webservers.SetWebTheme(sValue);
1182 }
1183
1184 m_webservers.SetWebRoot(szWebRoot);
1185 m_webservers.SetWebCompressionMode(g_wwwCompressMode);
1186
1187 //Start Scheduler
1188 m_scheduler.StartScheduler();
1189 m_cameras.ReloadCameras();
1190
1191 int rnvalue = 0;
1192 m_sql.GetPreferencesVar("RemoteSharedPort", rnvalue);
1193 if (rnvalue != 0)
1194 {
1195 char szPort[100];
1196 sprintf(szPort, "%d", rnvalue);
1197 m_sharedserver.sDecodeRXMessage.connect(boost::bind(&MainWorker::DecodeRXMessage, this, _1, _2, _3, _4));
1198 m_sharedserver.StartServer("::", szPort);
1199
1200 LoadSharedUsers();
1201 }
1202
1203 m_thread = std::make_shared<std::thread>(&MainWorker::Do_Work, this);
1204 SetThreadName(m_thread->native_handle(), "MainWorker");
1205 m_rxMessageThread = std::make_shared<std::thread>(&MainWorker::Do_Work_On_Rx_Messages, this);
1206 SetThreadName(m_rxMessageThread->native_handle(), "MainWorkerRxMsg");
1207 return (m_thread != nullptr) && (m_rxMessageThread != NULL);
1208 }
1209
1210
Stop()1211 bool MainWorker::Stop()
1212 {
1213 if (m_thread)
1214 {
1215 m_notificationsystem.NotifyWait(Notification::DZ_STOP, Notification::STATUS_INFO); // blocking call
1216 }
1217
1218 if (m_rxMessageThread) {
1219 // Stop RxMessage thread before hardware to avoid NULL pointer exception
1220 m_TaskRXMessage.RequestStop();
1221 UnlockRxMessageQueue();
1222 m_rxMessageThread->join();
1223 m_rxMessageThread.reset();
1224 }
1225 if (m_thread)
1226 {
1227 m_webservers.StopServers();
1228 m_sharedserver.StopServer();
1229 _log.Log(LOG_STATUS, "Stopping all hardware...");
1230 StopDomoticzHardware();
1231 m_scheduler.StopScheduler();
1232 m_eventsystem.StopEventSystem();
1233 m_notificationsystem.Stop();
1234 m_fibaropush.Stop();
1235 m_httppush.Stop();
1236 m_influxpush.Stop();
1237 m_googlepubsubpush.Stop();
1238 #ifdef ENABLE_PYTHON
1239 m_pluginsystem.StopPluginSystem();
1240 #endif
1241
1242 // m_cameras.StopCameraGrabber();
1243
1244 HTTPClient::Cleanup();
1245
1246 RequestStop();
1247 m_thread->join();
1248 m_thread.reset();
1249 }
1250 return true;
1251 }
1252
1253 #define HEX( x ) \
1254 std::setw(2) << std::setfill('0') << std::hex << std::uppercase << (int)( x )
1255
IsUpdateAvailable(const bool bIsForced)1256 bool MainWorker::IsUpdateAvailable(const bool bIsForced)
1257 {
1258 if (!g_bUseUpdater)
1259 return false;
1260
1261 if (!bIsForced)
1262 {
1263 int nValue = 0;
1264 m_sql.GetPreferencesVar("UseAutoUpdate", nValue);
1265 if (nValue != 1)
1266 {
1267 return false;
1268 }
1269 }
1270
1271 utsname my_uname;
1272 if (uname(&my_uname) < 0)
1273 return false;
1274
1275 std::string machine = my_uname.machine;
1276 if (machine == "armv6l")
1277 {
1278 //Seems like old arm systems can also use the new arm build
1279 machine = "armv7l";
1280 }
1281
1282 #ifdef DEBUG_DOWNLOAD
1283 m_szSystemName = "linux";
1284 machine = "armv7l";
1285 #endif
1286
1287 if ((m_szSystemName != "windows") && (machine != "armv6l") && (machine != "armv7l") && (machine != "x86_64") && (machine != "aarch64"))
1288 {
1289 //Only Raspberry Pi (Wheezy)/Ubuntu/windows/osx for now!
1290 return false;
1291 }
1292 time_t atime = mytime(NULL);
1293 if (!bIsForced)
1294 {
1295 if (atime - m_LastUpdateCheck < 12 * 3600)
1296 {
1297 return m_bHaveUpdate;
1298 }
1299 }
1300 m_LastUpdateCheck = atime;
1301
1302 int nValue;
1303 m_sql.GetPreferencesVar("ReleaseChannel", nValue);
1304 bool bIsBetaChannel = (nValue != 0);
1305
1306 std::string szURL;
1307 if (!bIsBetaChannel)
1308 {
1309 szURL = "https://www.domoticz.com/download.php?channel=stable&type=version&system=" + m_szSystemName + "&machine=" + machine;
1310 m_szDomoticzUpdateURL = "https://www.domoticz.com/download.php?channel=stable&type=release&system=" + m_szSystemName + "&machine=" + machine;
1311 m_szDomoticzUpdateChecksumURL = "https://www.domoticz.com/download.php?channel=stable&type=checksum&system=" + m_szSystemName + "&machine=" + machine;
1312 }
1313 else
1314 {
1315 szURL = "https://www.domoticz.com/download.php?channel=beta&type=version&system=" + m_szSystemName + "&machine=" + machine;
1316 m_szDomoticzUpdateURL = "https://www.domoticz.com/download.php?channel=beta&type=release&system=" + m_szSystemName + "&machine=" + machine;
1317 m_szDomoticzUpdateChecksumURL = "https://www.domoticz.com/download.php?channel=beta&type=checksum&system=" + m_szSystemName + "&machine=" + machine;
1318 }
1319
1320 std::string revfile;
1321
1322 if (!HTTPClient::GET(szURL, revfile))
1323 return false;
1324
1325 stdreplace(revfile, "\r\n", "\n");
1326 std::vector<std::string> strarray;
1327 StringSplit(revfile, "\n", strarray);
1328 if (strarray.size() < 1)
1329 return false;
1330 StringSplit(strarray[0], " ", strarray);
1331 if (strarray.size() != 3)
1332 return false;
1333
1334 m_iRevision = atoi(strarray[2].c_str());
1335 #ifdef DEBUG_DOWNLOAD
1336 m_bHaveUpdate = true;
1337 #else
1338 m_bHaveUpdate = ((iAppRevision != m_iRevision) && (iAppRevision < m_iRevision));
1339 #endif
1340 return m_bHaveUpdate;
1341 }
1342
StartDownloadUpdate()1343 bool MainWorker::StartDownloadUpdate()
1344 {
1345 #ifndef DEBUG_DOWNLOAD
1346 #ifdef WIN32
1347 return false; //managed by web gui
1348 #endif
1349 #endif
1350
1351 if (!IsUpdateAvailable(true))
1352 return false; //no new version available
1353
1354 m_bHaveDownloadedDomoticzUpdate = false;
1355 m_bHaveDownloadedDomoticzUpdateSuccessFull = false;
1356 m_bDoDownloadDomoticzUpdate = true;
1357 return true;
1358 }
1359
HandleAutomaticBackups()1360 void MainWorker::HandleAutomaticBackups()
1361 {
1362 int nValue = 0;
1363 if (!m_sql.GetPreferencesVar("UseAutoBackup", nValue))
1364 return;
1365 if (nValue != 1)
1366 return;
1367
1368 _log.Log(LOG_STATUS, "Starting automatic database backup procedure...");
1369
1370 std::stringstream backup_DirH;
1371 std::stringstream backup_DirD;
1372 std::stringstream backup_DirM;
1373
1374 #ifdef WIN32
1375 std::string sbackup_DirH = szUserDataFolder + "backups\\hourly\\";
1376 std::string sbackup_DirD = szUserDataFolder + "backups\\daily\\";
1377 std::string sbackup_DirM = szUserDataFolder + "backups\\monthly\\";
1378 #else
1379 std::string sbackup_DirH = szUserDataFolder + "backups/hourly/";
1380 std::string sbackup_DirD = szUserDataFolder + "backups/daily/";
1381 std::string sbackup_DirM = szUserDataFolder + "backups/monthly/";
1382 #endif
1383
1384
1385 //create folders if they not exists
1386 mkdir_deep(sbackup_DirH.c_str(), 0755);
1387 mkdir_deep(sbackup_DirD.c_str(), 0755);
1388 mkdir_deep(sbackup_DirM.c_str(), 0755);
1389
1390 time_t now = mytime(NULL);
1391 struct tm tm1;
1392 localtime_r(&now, &tm1);
1393 int hour = tm1.tm_hour;
1394 int day = tm1.tm_mday;
1395 int month = tm1.tm_mon;
1396
1397 int lastHourBackup = -1;
1398 int lastDayBackup = -1;
1399 int lastMonthBackup = -1;
1400
1401 m_sql.GetLastBackupNo("Hour", lastHourBackup);
1402 m_sql.GetLastBackupNo("Day", lastDayBackup);
1403 m_sql.GetLastBackupNo("Month", lastMonthBackup);
1404
1405 std::string szInstanceName = "domoticz";
1406 std::string szVar;
1407 if (m_sql.GetPreferencesVar("Title", szVar))
1408 {
1409 stdreplace(szVar, " ", "_");
1410 stdreplace(szVar, "/", "_");
1411 stdreplace(szVar, "\\", "_");
1412 if (!szVar.empty()) {
1413 szInstanceName = szVar;
1414 }
1415 }
1416
1417 DIR* lDir;
1418 Notification::_eStatus backupStatus;
1419 //struct dirent *ent;
1420
1421
1422 if ((lastHourBackup == -1) || (lastHourBackup != hour)) {
1423
1424 if ((lDir = opendir(sbackup_DirH.c_str())) != NULL)
1425 {
1426 Json::Value backupInfo;
1427 std::stringstream sTmp;
1428 sTmp << "backup-hour-" << std::setw(2) << std::setfill('0') << hour << "-" << szInstanceName << ".db";
1429
1430 backupInfo["type"] = "Hour";
1431 backupInfo["location"] = sbackup_DirH + sTmp.str();
1432 if (m_sql.BackupDatabase(backupInfo["location"].asString())) {
1433 m_sql.SetLastBackupNo(backupInfo["type"].asString().c_str(), hour);
1434
1435 backupStatus=Notification::STATUS_OK;
1436 }
1437 else {
1438 backupStatus = Notification::STATUS_ERROR;
1439 _log.Log(LOG_ERROR, "Error writing automatic hourly backup file");
1440 }
1441 closedir(lDir);
1442 backupInfo["duration"] = difftime(mytime(NULL),now);
1443 m_mainworker.m_notificationsystem.Notify(Notification::DZ_BACKUP_DONE, backupStatus, JSonToRawString(backupInfo));
1444 }
1445 else {
1446 _log.Log(LOG_ERROR, "Error accessing automatic backup directories");
1447 }
1448 }
1449 if ((lastDayBackup == -1) || (lastDayBackup != day)) {
1450
1451 if ((lDir = opendir(sbackup_DirD.c_str())) != NULL)
1452 {
1453 now = mytime(NULL);
1454 Json::Value backupInfo;
1455 std::stringstream sTmp;
1456 sTmp << "backup-day-" << std::setw(2) << std::setfill('0') << day << "-" << szInstanceName << ".db";
1457
1458 backupInfo["type"] = "Day";
1459 backupInfo["location"] = sbackup_DirD + sTmp.str();
1460 if (m_sql.BackupDatabase(backupInfo["location"].asString())) {
1461 m_sql.SetLastBackupNo(backupInfo["type"].asString().c_str(), day);
1462 backupStatus = Notification::STATUS_OK;
1463 }
1464 else {
1465 backupStatus = Notification::STATUS_ERROR;
1466 _log.Log(LOG_ERROR, "Error writing automatic daily backup file");
1467 }
1468 closedir(lDir);
1469 backupInfo["duration"] = difftime(mytime(NULL),now);
1470 m_mainworker.m_notificationsystem.Notify(Notification::DZ_BACKUP_DONE, backupStatus, JSonToRawString(backupInfo));
1471 }
1472 else {
1473 _log.Log(LOG_ERROR, "Error accessing automatic backup directories");
1474 }
1475 }
1476 if ((lastMonthBackup == -1) || (lastMonthBackup != month)) {
1477 if ((lDir = opendir(sbackup_DirM.c_str())) != NULL)
1478 {
1479 now = mytime(NULL);
1480 Json::Value backupInfo;
1481 std::stringstream sTmp;
1482 sTmp << "backup-month-" << std::setw(2) << std::setfill('0') << month + 1 << "-" << szInstanceName << ".db";
1483
1484 backupInfo["type"] = "Month";
1485 backupInfo["location"] = sbackup_DirM + sTmp.str();
1486 if (m_sql.BackupDatabase(backupInfo["location"].asString())) {
1487 m_sql.SetLastBackupNo(backupInfo["type"].asString().c_str(), month);
1488 backupStatus = Notification::STATUS_OK;
1489 }
1490 else {
1491 backupStatus = Notification::STATUS_ERROR;
1492 _log.Log(LOG_ERROR, "Error writing automatic monthly backup file");
1493 }
1494 closedir(lDir);
1495 backupInfo["duration"] = difftime(mytime(NULL),now);
1496 m_mainworker.m_notificationsystem.Notify(Notification::DZ_BACKUP_DONE, backupStatus, JSonToRawString(backupInfo));
1497 }
1498 else {
1499 _log.Log(LOG_ERROR, "Error accessing automatic backup directories");
1500 }
1501 }
1502 _log.Log(LOG_STATUS, "Ending automatic database backup procedure...");
1503 }
1504
ParseRFXLogFile()1505 void MainWorker::ParseRFXLogFile()
1506 {
1507 #ifdef PARSE_RFXCOM_DEVICE_LOG
1508 std::vector<std::string> _lines;
1509 std::ifstream myfile("C:\\RFXtrxLog.txt");
1510 if (myfile.is_open())
1511 {
1512 while (myfile.good())
1513 {
1514 std::string _line;
1515 getline(myfile, _line);
1516 size_t tpos = _line.find("=");
1517 if (tpos != std::string::npos)
1518 {
1519 _line = _line.substr(tpos + 1);
1520 tpos = _line.find(" ");
1521 if (tpos == 0)
1522 {
1523 _line = _line.substr(1);
1524 }
1525 }
1526 stdreplace(_line, " ", "");
1527 _lines.push_back(_line);
1528 }
1529 myfile.close();
1530 }
1531 int HWID = 999;
1532 //m_sql.DeleteHardware("999");
1533
1534 CDomoticzHardwareBase* pHardware = GetHardware(HWID);
1535 if (pHardware == NULL)
1536 {
1537 pHardware = new CDummy(HWID);
1538 //pHardware->sDecodeRXMessage.connect(boost::bind(&MainWorker::DecodeRXMessage, this, _1, _2, _3, _4));
1539 AddDomoticzHardware(pHardware);
1540 }
1541
1542 std::vector<std::string>::iterator itt;
1543 unsigned char rxbuffer[600];
1544 static const char* const lut = "0123456789ABCDEF";
1545 for (itt = _lines.begin(); itt != _lines.end(); ++itt)
1546 {
1547 std::string hexstring = *itt;
1548 if (hexstring.size() % 2 != 0)
1549 continue;//illegal
1550 int totbytes = hexstring.size() / 2;
1551 int ii = 0;
1552 for (ii = 0; ii < totbytes; ii++)
1553 {
1554 std::string hbyte = hexstring.substr((ii * 2), 2);
1555
1556 char a = hbyte[0];
1557 const char* p = std::lower_bound(lut, lut + 16, a);
1558 if (*p != a) throw std::invalid_argument("not a hex digit");
1559
1560 char b = hbyte[1];
1561 const char* q = std::lower_bound(lut, lut + 16, b);
1562 if (*q != b) throw std::invalid_argument("not a hex digit");
1563
1564 unsigned char uchar = ((p - lut) << 4) | (q - lut);
1565 rxbuffer[ii] = uchar;
1566 }
1567 if (ii == 0)
1568 continue;
1569 if (CRFXBase::CheckValidRFXData((const uint8_t*)&rxbuffer))
1570 {
1571 //pHardware->WriteToHardware((const char *)&rxbuffer, totbytes);
1572 DecodeRXMessage(pHardware, (const unsigned char*)&rxbuffer, NULL, 255);
1573 sleep_milliseconds(300);
1574 }
1575 else
1576 {
1577 _log.Log(LOG_ERROR, "Invalid data/length!");
1578 }
1579 }
1580 #endif
1581 }
1582
Do_Work()1583 void MainWorker::Do_Work()
1584 {
1585 int second_counter = 0;
1586 int heartbeat_counter = 0;
1587 while (!IsStopRequested(500))
1588 {
1589 if (m_bDoDownloadDomoticzUpdate)
1590 {
1591 m_bDoDownloadDomoticzUpdate = false;
1592
1593 _log.Log(LOG_STATUS, "Starting Upgrade progress...");
1594 #ifdef WIN32
1595 std::string outfile;
1596
1597 //First download the checksum file
1598 outfile = szStartupFolder + "update.tgz.sha256sum";
1599 bool bHaveDownloadedChecksum = HTTPClient::GETBinaryToFile(m_szDomoticzUpdateChecksumURL.c_str(), outfile.c_str());
1600 if (bHaveDownloadedChecksum)
1601 {
1602 //Next download the actual update
1603 outfile = szStartupFolder + "update.tgz";
1604 m_bHaveDownloadedDomoticzUpdateSuccessFull = HTTPClient::GETBinaryToFile(m_szDomoticzUpdateURL.c_str(), outfile.c_str());
1605 if (!m_bHaveDownloadedDomoticzUpdateSuccessFull)
1606 {
1607 m_UpdateStatusMessage = "Problem downloading update file!";
1608 }
1609 }
1610 else
1611 m_UpdateStatusMessage = "Problem downloading checksum file!";
1612 #else
1613 int nValue;
1614 m_sql.GetPreferencesVar("ReleaseChannel", nValue);
1615 bool bIsBetaChannel = (nValue != 0);
1616
1617 std::string scriptname = szUserDataFolder + "scripts/download_update.sh";
1618 std::string strparm = szUserDataFolder;
1619 if (bIsBetaChannel)
1620 strparm += " /beta";
1621
1622 std::string lscript = scriptname + " " + strparm;
1623 _log.Log(LOG_STATUS, "Starting: %s", lscript.c_str());
1624 int ret = system(lscript.c_str());
1625 m_bHaveDownloadedDomoticzUpdateSuccessFull = (ret == 0);
1626 #endif
1627 m_bHaveDownloadedDomoticzUpdate = true;
1628 }
1629
1630 second_counter++;
1631 if (second_counter < 2)
1632 continue;
1633 second_counter = 0;
1634
1635 if (m_bStartHardware)
1636 {
1637 m_hardwareStartCounter++;
1638 if (m_hardwareStartCounter >= 2)
1639 {
1640 m_bStartHardware = false;
1641 StartDomoticzHardware();
1642 #ifdef ENABLE_PYTHON
1643 m_pluginsystem.AllPluginsStarted();
1644 #endif
1645 ParseRFXLogFile();
1646 m_notificationsystem.Start();
1647 m_eventsystem.SetEnabled(m_sql.m_bEnableEventSystem);
1648 m_eventsystem.StartEventSystem();
1649 m_notificationsystem.Notify(Notification::DZ_START, Notification::STATUS_INFO);
1650 }
1651 }
1652 if (m_devicestorestart.size() > 0)
1653 {
1654 for (const auto& itt : m_devicestorestart)
1655 {
1656 int hwid = itt;
1657 std::stringstream sstr;
1658 sstr << hwid;
1659 std::string idx = sstr.str();
1660
1661 std::vector<std::vector<std::string> > result;
1662 result = m_sql.safe_query("SELECT Name FROM Hardware WHERE (ID=='%q')",
1663 idx.c_str());
1664 if (!result.empty())
1665 {
1666 std::vector<std::string> sd = result[0];
1667 std::string Name = sd[0];
1668 _log.Log(LOG_ERROR, "Restarting: %s", Name.c_str());
1669 RestartHardware(idx);
1670 }
1671 }
1672 m_devicestorestart.clear();
1673 }
1674
1675 if (m_SecCountdown > 0)
1676 {
1677 m_SecCountdown--;
1678 if (m_SecCountdown == 0)
1679 {
1680 SetInternalSecStatus();
1681 }
1682 }
1683
1684 time_t atime = mytime(NULL);
1685 struct tm ltime;
1686 localtime_r(&atime, <ime);
1687
1688 if (ltime.tm_min != m_ScheduleLastMinute)
1689 {
1690 if (difftime(atime, m_ScheduleLastMinuteTime) > 30) //avoid RTC/NTP clock drifts
1691 {
1692 m_ScheduleLastMinuteTime = atime;
1693 m_ScheduleLastMinute = ltime.tm_min;
1694
1695 tzset(); //this because localtime_r/localtime_s does not update for DST
1696
1697 //check for 5 minute schedule
1698 if (ltime.tm_min % m_sql.m_ShortLogInterval == 0)
1699 {
1700 m_sql.ScheduleShortlog();
1701 }
1702 std::string szPwdResetFile = szStartupFolder + "resetpwd";
1703 if (file_exist(szPwdResetFile.c_str()))
1704 {
1705 m_webservers.ClearUserPasswords();
1706 m_sql.UpdatePreferencesVar("WebUserName", "");
1707 m_sql.UpdatePreferencesVar("WebPassword", "");
1708 std::remove(szPwdResetFile.c_str());
1709 }
1710 m_notifications.CheckAndHandleLastUpdateNotification();
1711 }
1712 if (_log.NotificationLogsEnabled())
1713 {
1714 if ((ltime.tm_min % 5 == 0) || (m_bForceLogNotificationCheck))
1715 {
1716 m_bForceLogNotificationCheck = false;
1717 HandleLogNotifications();
1718 }
1719 }
1720 }
1721 if (ltime.tm_hour != m_ScheduleLastHour)
1722 {
1723 if (difftime(atime, m_ScheduleLastHourTime) > 30 * 60) //avoid RTC/NTP clock drifts
1724 {
1725 m_ScheduleLastHourTime = atime;
1726 m_ScheduleLastHour = ltime.tm_hour;
1727 GetSunSettings();
1728
1729 m_sql.CheckDeviceTimeout();
1730 m_sql.CheckBatteryLow();
1731
1732 //check for daily schedule
1733 if (ltime.tm_hour == 0)
1734 {
1735 if (atime - m_ScheduleLastDayTime > 12 * 60 * 60)
1736 {
1737 m_ScheduleLastDayTime = atime;
1738 m_sql.ScheduleDay();
1739 }
1740 }
1741 #ifdef WITH_OPENZWAVE
1742 if (ltime.tm_hour == 4)
1743 {
1744 //Heal the OpenZWave network
1745 std::lock_guard<std::mutex> l(m_devicemutex);
1746 std::vector<CDomoticzHardwareBase*>::iterator itt;
1747 for (itt = m_hardwaredevices.begin(); itt != m_hardwaredevices.end(); ++itt)
1748 {
1749 CDomoticzHardwareBase* pHardware = (*itt);
1750 if (pHardware->HwdType == HTYPE_OpenZWave)
1751 {
1752 COpenZWave* pZWave = reinterpret_cast<COpenZWave*>(pHardware);
1753 pZWave->NightlyNodeHeal();
1754 }
1755 }
1756 }
1757 #endif
1758 if ((ltime.tm_hour == 5) || (ltime.tm_hour == 17))
1759 {
1760 IsUpdateAvailable(true);//check for update
1761 }
1762 HandleAutomaticBackups();
1763 }
1764 }
1765 if (heartbeat_counter++ > 12)
1766 {
1767 heartbeat_counter = 0;
1768 m_LastHeartbeat = mytime(NULL);
1769 HeartbeatCheck();
1770 }
1771 }
1772 _log.Log(LOG_STATUS, "Mainworker Stopped...");
1773 }
1774
WriteToHardware(const int HwdID,const char * pdata,const uint8_t length)1775 bool MainWorker::WriteToHardware(const int HwdID, const char* pdata, const uint8_t length)
1776 {
1777 int hindex = FindDomoticzHardware(HwdID);
1778
1779 if (hindex == -1)
1780 return false;
1781
1782 return m_hardwaredevices[hindex]->WriteToHardware(pdata, length);
1783 }
1784
WriteMessageStart()1785 void MainWorker::WriteMessageStart()
1786 {
1787 _log.LogSequenceStart();
1788 }
1789
WriteMessageEnd()1790 void MainWorker::WriteMessageEnd()
1791 {
1792 _log.LogSequenceEnd(LOG_NORM);
1793 }
1794
WriteMessage(const char * szMessage)1795 void MainWorker::WriteMessage(const char* szMessage)
1796 {
1797 _log.LogSequenceAdd(szMessage);
1798 }
1799
WriteMessage(const char * szMessage,bool linefeed)1800 void MainWorker::WriteMessage(const char* szMessage, bool linefeed)
1801 {
1802 if (linefeed)
1803 _log.LogSequenceAdd(szMessage);
1804 else
1805 _log.LogSequenceAddNoLF(szMessage);
1806 }
1807
OnHardwareConnected(CDomoticzHardwareBase * pHardware)1808 void MainWorker::OnHardwareConnected(CDomoticzHardwareBase* pHardware)
1809 {
1810 if (
1811 (pHardware->HwdType != HTYPE_RFXtrx315) &&
1812 (pHardware->HwdType != HTYPE_RFXtrx433) &&
1813 (pHardware->HwdType != HTYPE_RFXtrx868) &&
1814 (pHardware->HwdType != HTYPE_RFXLAN)
1815 )
1816 {
1817 //enable receive
1818 pHardware->m_bEnableReceive = true;
1819 return;
1820 }
1821 CRFXBase* pRFXBase = reinterpret_cast<CRFXBase*>(pHardware);
1822 pRFXBase->SendResetCommand();
1823 }
1824
PerformRealActionFromDomoticzClient(const uint8_t * pRXCommand,CDomoticzHardwareBase ** pOriginalHardware)1825 uint64_t MainWorker::PerformRealActionFromDomoticzClient(const uint8_t* pRXCommand, CDomoticzHardwareBase** pOriginalHardware)
1826 {
1827 *pOriginalHardware = NULL;
1828 uint8_t devType = pRXCommand[1];
1829 uint8_t subType = pRXCommand[2];
1830 std::string ID = "";
1831 uint8_t Unit = 0;
1832 const tRBUF* pResponse = reinterpret_cast<const tRBUF*>(pRXCommand);
1833 char szTmp[300];
1834 std::vector<std::vector<std::string> > result;
1835
1836 switch (devType) {
1837 case pTypeLighting1:
1838 sprintf(szTmp, "%d", pResponse->LIGHTING1.housecode);
1839 ID = szTmp;
1840 Unit = pResponse->LIGHTING1.unitcode;
1841 break;
1842 case pTypeLighting2:
1843 sprintf(szTmp, "%X%02X%02X%02X", pResponse->LIGHTING2.id1, pResponse->LIGHTING2.id2, pResponse->LIGHTING2.id3, pResponse->LIGHTING2.id4);
1844 ID = szTmp;
1845 Unit = pResponse->LIGHTING2.unitcode;
1846 break;
1847 case pTypeLighting5:
1848 if (subType != sTypeEMW100)
1849 sprintf(szTmp, "%02X%02X%02X", pResponse->LIGHTING5.id1, pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
1850 else
1851 sprintf(szTmp, "%02X%02X", pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
1852 ID = szTmp;
1853 Unit = pResponse->LIGHTING5.unitcode;
1854 break;
1855 case pTypeLighting6:
1856 sprintf(szTmp, "%02X%02X%02X", pResponse->LIGHTING6.id1, pResponse->LIGHTING6.id2, pResponse->LIGHTING6.groupcode);
1857 ID = szTmp;
1858 Unit = pResponse->LIGHTING6.unitcode;
1859 break;
1860 case pTypeHomeConfort:
1861 sprintf(szTmp, "%02X%02X%02X%02X", pResponse->HOMECONFORT.id1, pResponse->HOMECONFORT.id2, pResponse->HOMECONFORT.id3, pResponse->HOMECONFORT.housecode);
1862 ID = szTmp;
1863 Unit = pResponse->HOMECONFORT.unitcode;
1864 break;
1865 case pTypeRadiator1:
1866 if (subType == sTypeSmartwaresSwitchRadiator)
1867 {
1868 sprintf(szTmp, "%X%02X%02X%02X", pResponse->RADIATOR1.id1, pResponse->RADIATOR1.id2, pResponse->RADIATOR1.id3, pResponse->RADIATOR1.id4);
1869 ID = szTmp;
1870 Unit = pResponse->RADIATOR1.unitcode;
1871 }
1872 break;
1873 case pTypeColorSwitch:
1874 {
1875 const _tColorSwitch* pLed = reinterpret_cast<const _tColorSwitch*>(pResponse);
1876 ID = "1";
1877 Unit = pLed->dunit;
1878 }
1879 break;
1880 case pTypeFS20:
1881 sprintf(szTmp, "%02X%02X", pResponse->FS20.hc1, pResponse->FS20.hc2);
1882 ID = szTmp;
1883 Unit = pResponse->FS20.addr;
1884 break;
1885 case pTypeCurtain:
1886 sprintf(szTmp, "%d", pResponse->CURTAIN1.housecode);
1887 ID = szTmp;
1888 Unit = pResponse->CURTAIN1.unitcode;
1889 break;
1890 case pTypeBlinds:
1891 sprintf(szTmp, "%02X%02X%02X", pResponse->BLINDS1.id1, pResponse->BLINDS1.id2, pResponse->BLINDS1.id3);
1892 ID = szTmp;
1893 Unit = pResponse->BLINDS1.unitcode;
1894 break;
1895 case pTypeRFY:
1896 sprintf(szTmp, "%02X%02X%02X", pResponse->RFY.id1, pResponse->RFY.id2, pResponse->RFY.id3);
1897 ID = szTmp;
1898 Unit = pResponse->RFY.unitcode;
1899 break;
1900 case pTypeSecurity1:
1901 sprintf(szTmp, "%02X%02X%02X", pResponse->SECURITY1.id1, pResponse->SECURITY1.id2, pResponse->SECURITY1.id3);
1902 ID = szTmp;
1903 Unit = 0;
1904 break;
1905 case pTypeSecurity2:
1906 sprintf(szTmp, "%02X%02X%02X%02X%02X%02X%02X%02X", pResponse->SECURITY2.id1, pResponse->SECURITY2.id2, pResponse->SECURITY2.id3, pResponse->SECURITY2.id4, pResponse->SECURITY2.id5, pResponse->SECURITY2.id6, pResponse->SECURITY2.id7, pResponse->SECURITY2.id8);
1907 ID = szTmp;
1908 Unit = 0;
1909 break;
1910 case pTypeChime:
1911 sprintf(szTmp, "%02X%02X", pResponse->CHIME.id1, pResponse->CHIME.id2);
1912 ID = szTmp;
1913 Unit = pResponse->CHIME.sound;
1914 break;
1915 case pTypeThermostat:
1916 {
1917 const _tThermostat* pMeter = reinterpret_cast<const _tThermostat*>(pResponse);
1918 sprintf(szTmp, "%X%02X%02X%02X", pMeter->id1, pMeter->id2, pMeter->id3, pMeter->id4);
1919 ID = szTmp;
1920 Unit = pMeter->dunit;
1921 }
1922 break;
1923 case pTypeThermostat2:
1924 ID = "1";
1925 Unit = pResponse->THERMOSTAT2.unitcode;
1926 break;
1927 case pTypeThermostat3:
1928 sprintf(szTmp, "%02X%02X%02X", pResponse->THERMOSTAT3.unitcode1, pResponse->THERMOSTAT3.unitcode2, pResponse->THERMOSTAT3.unitcode3);
1929 ID = szTmp;
1930 Unit = 0;
1931 break;
1932 case pTypeThermostat4:
1933 sprintf(szTmp, "%02X%02X%02X", pResponse->THERMOSTAT4.unitcode1, pResponse->THERMOSTAT4.unitcode2, pResponse->THERMOSTAT4.unitcode3);
1934 ID = szTmp;
1935 Unit = 0;
1936 break;
1937 case pTypeGeneralSwitch:
1938 {
1939 const _tGeneralSwitch* pSwitch = reinterpret_cast<const _tGeneralSwitch*>(pResponse);
1940 sprintf(szTmp, "%08X", pSwitch->id);
1941 ID = szTmp;
1942 Unit = pSwitch->unitcode;
1943 }
1944 break;
1945 default:
1946 return -1;
1947 }
1948
1949 if (ID != "")
1950 {
1951 // find our original hardware
1952 // if it is not a domoticz type, perform the actual command
1953
1954 result = m_sql.safe_query(
1955 "SELECT HardwareID,ID,Name,StrParam1,StrParam2,nValue,sValue FROM DeviceStatus WHERE (DeviceID='%q' AND Unit=%d AND Type=%d AND SubType=%d)",
1956 ID.c_str(), Unit, devType, subType);
1957 if (result.size() == 1)
1958 {
1959 std::vector<std::string> sd = result[0];
1960
1961 CDomoticzHardwareBase* pHardware = GetHardware(atoi(sd[0].c_str()));
1962 if (pHardware != NULL)
1963 {
1964 if (pHardware->HwdType != HTYPE_Domoticz)
1965 {
1966 *pOriginalHardware = pHardware;
1967 pHardware->WriteToHardware((const char*)pRXCommand, pRXCommand[0] + 1);
1968 std::stringstream s_strid;
1969 s_strid << std::dec << sd[1];
1970 uint64_t ullID;
1971 s_strid >> ullID;
1972 return ullID;
1973 }
1974 }
1975 }
1976 }
1977 return -1;
1978 }
1979
DecodeRXMessage(const CDomoticzHardwareBase * pHardware,const uint8_t * pRXCommand,const char * defaultName,const int BatteryLevel)1980 void MainWorker::DecodeRXMessage(const CDomoticzHardwareBase* pHardware, const uint8_t* pRXCommand, const char* defaultName, const int BatteryLevel)
1981 {
1982 if ((pHardware == NULL) || (pRXCommand == NULL))
1983 return;
1984 if ((pHardware->HwdType == HTYPE_Domoticz) && (pHardware->m_HwdID == 8765))
1985 {
1986 //Directly process the command
1987 std::lock_guard<std::mutex> l(m_decodeRXMessageMutex);
1988 ProcessRXMessage(pHardware, pRXCommand, defaultName, BatteryLevel);
1989 }
1990 else
1991 {
1992 // Submit command without waiting for the command to be processed
1993 PushRxMessage(pHardware, pRXCommand, defaultName, BatteryLevel);
1994 }
1995 }
1996
PushRxMessage(const CDomoticzHardwareBase * pHardware,const uint8_t * pRXCommand,const char * defaultName,const int BatteryLevel)1997 void MainWorker::PushRxMessage(const CDomoticzHardwareBase* pHardware, const uint8_t* pRXCommand, const char* defaultName, const int BatteryLevel)
1998 {
1999 // Check command, submit it without waiting for it to be processed
2000 CheckAndPushRxMessage(pHardware, pRXCommand, defaultName, BatteryLevel, false);
2001 }
2002
PushAndWaitRxMessage(const CDomoticzHardwareBase * pHardware,const uint8_t * pRXCommand,const char * defaultName,const int BatteryLevel)2003 void MainWorker::PushAndWaitRxMessage(const CDomoticzHardwareBase* pHardware, const uint8_t* pRXCommand, const char* defaultName, const int BatteryLevel)
2004 {
2005 // Check command, submit it and wait for it to be processed
2006 CheckAndPushRxMessage(pHardware, pRXCommand, defaultName, BatteryLevel, true);
2007 }
2008
CheckAndPushRxMessage(const CDomoticzHardwareBase * pHardware,const uint8_t * pRXCommand,const char * defaultName,const int BatteryLevel,const bool wait)2009 void MainWorker::CheckAndPushRxMessage(const CDomoticzHardwareBase* pHardware, const uint8_t* pRXCommand, const char* defaultName, const int BatteryLevel, const bool wait)
2010 {
2011 if ((pHardware == NULL) || (pRXCommand == NULL)) {
2012 _log.Log(LOG_ERROR, "RxQueue: cannot push message with undefined hardware (%s) or command (%s)",
2013 (pHardware == NULL) ? "null" : "not null",
2014 (pRXCommand == NULL) ? "null" : "not null");
2015 return;
2016 }
2017 if (pHardware->m_HwdID < 1) {
2018 _log.Log(LOG_ERROR, "RxQueue: cannot push message with invalid hardware id (id=%d, type=%d, name=%s)",
2019 pHardware->m_HwdID,
2020 pHardware->HwdType,
2021 pHardware->m_Name.c_str());
2022 return;
2023 }
2024
2025 // Build queue item
2026 _tRxQueueItem rxMessage;
2027 if (defaultName != NULL)
2028 {
2029 rxMessage.Name = defaultName;
2030 }
2031 rxMessage.BatteryLevel = BatteryLevel;
2032 rxMessage.rxMessageIdx = m_rxMessageIdx++;
2033 rxMessage.hardwareId = pHardware->m_HwdID;
2034 // defensive copy of the command
2035 rxMessage.vrxCommand.resize(pRXCommand[0] + 1);
2036 rxMessage.vrxCommand.insert(rxMessage.vrxCommand.begin(), pRXCommand, pRXCommand + pRXCommand[0] + 1);
2037 rxMessage.crc = 0x0;
2038 #ifdef DEBUG_RXQUEUE
2039 // CRC
2040 boost::crc_optimal<16, 0x1021, 0xFFFF, 0, false, false> crc_ccitt2;
2041 crc_ccitt2 = std::for_each(pRXCommand, pRXCommand + pRXCommand[0] + 1, crc_ccitt2);
2042 rxMessage.crc = crc_ccitt2();
2043 #endif
2044
2045 if (m_TaskRXMessage.IsStopRequested(0)) {
2046 // Server is stopping
2047 return;
2048 }
2049
2050 // Trigger
2051 rxMessage.trigger = NULL; // Should be initialized to NULL if trigger is no used
2052 if (wait) { // add trigger to wait for the message to be processed
2053 rxMessage.trigger = new queue_element_trigger();
2054 }
2055
2056 #ifdef DEBUG_RXQUEUE
2057 _log.Log(LOG_STATUS, "RxQueue: push a rxMessage(%lu) (hrdwId=%d, hrdwType=%d, hrdwName=%s, type=%02X, subtype=%02X)",
2058 rxMessage.rxMessageIdx,
2059 pHardware->m_HwdID,
2060 pHardware->HwdType,
2061 pHardware->Name.c_str(),
2062 pRXCommand[1],
2063 pRXCommand[2]);
2064 #endif
2065
2066 // Push item to queue
2067 m_rxMessageQueue.push(rxMessage);
2068
2069 if (rxMessage.trigger != NULL) {
2070 #ifdef DEBUG_RXQUEUE
2071 _log.Log(LOG_STATUS, "RxQueue: wait for rxMessage(%lu) to be processed...", rxMessage.rxMessageIdx);
2072 #endif
2073 while (!rxMessage.trigger->timed_wait(std::chrono::duration<int>(1))) {
2074 #ifdef DEBUG_RXQUEUE
2075 _log.Log(LOG_STATUS, "RxQueue: wait 1s for rxMessage(%lu) to be processed...", rxMessage.rxMessageIdx);
2076 #endif
2077 if (m_TaskRXMessage.IsStopRequested(0)) {
2078 // Server is stopping
2079 break;
2080 }
2081 }
2082 #ifdef DEBUG_RXQUEUE
2083 if (moreThanTimeout) {
2084 _log.Log(LOG_STATUS, "RxQueue: rxMessage(%lu) processed", rxMessage.rxMessageIdx);
2085 }
2086 #endif
2087 delete rxMessage.trigger;
2088 }
2089 }
2090
UnlockRxMessageQueue()2091 void MainWorker::UnlockRxMessageQueue()
2092 {
2093 #ifdef DEBUG_RXQUEUE
2094 _log.Log(LOG_STATUS, "RxQueue: unlock queue using dummy message");
2095 #endif
2096 // Push dummy message to unlock queue
2097 _tRxQueueItem rxMessage;
2098 rxMessage.rxMessageIdx = m_rxMessageIdx++;
2099 rxMessage.hardwareId = -1;
2100 rxMessage.trigger = NULL;
2101 rxMessage.BatteryLevel = 0;
2102 m_rxMessageQueue.push(rxMessage);
2103 }
2104
Do_Work_On_Rx_Messages()2105 void MainWorker::Do_Work_On_Rx_Messages()
2106 {
2107 _log.Log(LOG_STATUS, "RxQueue: queue worker started...");
2108
2109 while (!m_TaskRXMessage.IsStopRequested(0))
2110 {
2111 // Wait and pop next message or timeout
2112 _tRxQueueItem rxQItem;
2113 bool hasPopped = m_rxMessageQueue.timed_wait_and_pop<std::chrono::duration<int> >(rxQItem, std::chrono::duration<int>(5));
2114 // (if no message for 5 seconds, returns anyway to check m_TaskRXMessage.IsStopRequested)
2115
2116 if (!hasPopped) {
2117 // Timeout occurred : queue is empty
2118 #ifdef DEBUG_RXQUEUE
2119 //_log.Log(LOG_STATUS, "RxQueue: the queue has been empty for five seconds");
2120 #endif
2121 continue;
2122 }
2123 if (rxQItem.hardwareId == -1) {
2124 // dummy message
2125 #ifdef DEBUG_RXQUEUE
2126 _log.Log(LOG_STATUS, "RxQueue: dummy message popped");
2127 #endif
2128 continue;
2129 }
2130 if (rxQItem.hardwareId < 1) {
2131 _log.Log(LOG_ERROR, "RxQueue: cannot process invalid hardware id: (%d)", rxQItem.hardwareId);
2132 // cannot process message with invalid id or null message
2133 if (rxQItem.trigger != NULL) rxQItem.trigger->popped();
2134 continue;
2135 }
2136
2137 const CDomoticzHardwareBase* pHardware = GetHardware(rxQItem.hardwareId);
2138
2139 // Check pointers
2140 if (pHardware == NULL) {
2141 _log.Log(LOG_ERROR, "RxQueue: cannot retrieve hardware with id: %d", rxQItem.hardwareId);
2142 if (rxQItem.trigger != NULL) rxQItem.trigger->popped();
2143 continue;
2144 }
2145 if (rxQItem.vrxCommand.empty()) {
2146 _log.Log(LOG_ERROR, "RxQueue: cannot retrieve command with id: %d", rxQItem.hardwareId);
2147 if (rxQItem.trigger != NULL) rxQItem.trigger->popped();
2148 continue;
2149 }
2150
2151 const uint8_t* pRXCommand = &rxQItem.vrxCommand[0];
2152
2153 #ifdef DEBUG_RXQUEUE
2154 // CRC
2155 boost::uint16_t crc = rxQItem.crc;
2156 boost::crc_optimal<16, 0x1021, 0xFFFF, 0, false, false> crc_ccitt2;
2157 crc_ccitt2 = std::for_each(pRXCommand, pRXCommand + rxQItem.vrxCommand.size(), crc_ccitt2);
2158 if (crc != crc_ccitt2()) {
2159 _log.Log(LOG_ERROR, "RxQueue: cannot process invalid rxMessage(%lu) from hardware with id=%d (type %d)",
2160 rxQItem.rxMessageIdx,
2161 rxQItem.hardwareId,
2162 pHardware->HwdType);
2163 if (rxQItem.trigger != NULL) rxQItem.trigger->popped();
2164 continue;
2165 }
2166
2167 _log.Log(LOG_STATUS, "RxQueue: process a rxMessage(%lu) (hrdwId=%d, hrdwType=%d, hrdwName=%s, type=%02X, subtype=%02X)",
2168 rxQItem.rxMessageIdx,
2169 pHardware->m_HwdID,
2170 pHardware->HwdType,
2171 pHardware->Name.c_str(),
2172 pRXCommand[1],
2173 pRXCommand[2]);
2174 #endif
2175 ProcessRXMessage(pHardware, pRXCommand, rxQItem.Name.c_str(), rxQItem.BatteryLevel);
2176 if (rxQItem.trigger != NULL)
2177 {
2178 rxQItem.trigger->popped();
2179 }
2180 }
2181
2182 _log.Log(LOG_STATUS, "RxQueue: queue worker stopped...");
2183 }
2184
ProcessRXMessage(const CDomoticzHardwareBase * pHardware,const uint8_t * pRXCommand,const char * defaultName,const int BatteryLevel)2185 void MainWorker::ProcessRXMessage(const CDomoticzHardwareBase* pHardware, const uint8_t* pRXCommand, const char* defaultName, const int BatteryLevel)
2186 {
2187 // current date/time based on current system
2188 //size_t Len = pRXCommand[0] + 1;
2189
2190 const_cast<CDomoticzHardwareBase*>(pHardware)->SetHeartbeatReceived();
2191
2192 uint64_t DeviceRowIdx = (uint64_t)-1;
2193 std::string DeviceName = "";
2194 tcp::server::CTCPClient* pClient2Ignore = NULL;
2195
2196 if (pHardware->HwdType == HTYPE_Domoticz)
2197 {
2198 if (pHardware->m_HwdID == 8765) //did we receive it from our master?
2199 {
2200 CDomoticzHardwareBase* pOrgHardware = NULL;
2201 switch (pRXCommand[1])
2202 {
2203 case pTypeLighting1:
2204 case pTypeLighting2:
2205 case pTypeLighting3:
2206 case pTypeLighting4:
2207 case pTypeLighting5:
2208 case pTypeLighting6:
2209 case pTypeColorSwitch:
2210 case pTypeCurtain:
2211 case pTypeBlinds:
2212 case pTypeRFY:
2213 case pTypeSecurity1:
2214 case pTypeSecurity2:
2215 case pTypeChime:
2216 case pTypeThermostat:
2217 case pTypeThermostat2:
2218 case pTypeThermostat3:
2219 case pTypeThermostat4:
2220 case pTypeRadiator1:
2221 case pTypeGeneralSwitch:
2222 case pTypeHomeConfort:
2223 case pTypeFan:
2224 case pTypeFS20:
2225 case pTypeHunter:
2226 //we received a control message from a domoticz client,
2227 //and should actually perform this command ourself switch
2228 DeviceRowIdx = PerformRealActionFromDomoticzClient(pRXCommand, &pOrgHardware);
2229 if (DeviceRowIdx != (uint64_t)-1)
2230 {
2231 if (pOrgHardware != NULL)
2232 {
2233 DeviceRowIdx = -1;
2234 pClient2Ignore = (tcp::server::CTCPClient*)pHardware->m_pUserData;
2235 pHardware = pOrgHardware;
2236 }
2237 WriteMessage("Control Command, ", (pOrgHardware == NULL));
2238 }
2239 break;
2240 }
2241 }
2242 }
2243
2244 _tRxMessageProcessingResult procResult;
2245 procResult.DeviceName = "";
2246 procResult.DeviceRowIdx = -1;
2247 procResult.bProcessBatteryValue = true;
2248 if (DeviceRowIdx == (uint64_t)-1)
2249 {
2250 switch (pRXCommand[1])
2251 {
2252 case pTypeInterfaceMessage:
2253 decode_InterfaceMessage(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2254 break;
2255 case pTypeInterfaceControl:
2256 decode_InterfaceControl(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2257 break;
2258 case pTypeRecXmitMessage:
2259 decode_RecXmitMessage(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2260 break;
2261 case pTypeUndecoded:
2262 decode_UNDECODED(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2263 break;
2264 case pTypeLighting1:
2265 decode_Lighting1(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2266 break;
2267 case pTypeLighting2:
2268 decode_Lighting2(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2269 break;
2270 case pTypeLighting3:
2271 decode_Lighting3(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2272 break;
2273 case pTypeLighting4:
2274 decode_Lighting4(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2275 break;
2276 case pTypeLighting5:
2277 decode_Lighting5(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2278 break;
2279 case pTypeLighting6:
2280 decode_Lighting6(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2281 break;
2282 case pTypeFan:
2283 decode_Fan(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2284 break;
2285 case pTypeCurtain:
2286 decode_Curtain(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2287 break;
2288 case pTypeBlinds:
2289 decode_BLINDS1(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2290 break;
2291 case pTypeRFY:
2292 decode_RFY(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2293 break;
2294 case pTypeSecurity1:
2295 decode_Security1(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2296 break;
2297 case pTypeSecurity2:
2298 decode_Security2(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2299 break;
2300 case pTypeEvohome:
2301 decode_evohome1(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2302 break;
2303 case pTypeEvohomeZone:
2304 case pTypeEvohomeWater:
2305 decode_evohome2(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2306 break;
2307 case pTypeEvohomeRelay:
2308 decode_evohome3(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2309 break;
2310 case pTypeCamera:
2311 decode_Camera1(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2312 break;
2313 case pTypeRemote:
2314 decode_Remote(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2315 break;
2316 case pTypeThermostat: //own type
2317 decode_Thermostat(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2318 break;
2319 case pTypeThermostat1:
2320 decode_Thermostat1(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2321 break;
2322 case pTypeThermostat2:
2323 decode_Thermostat2(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2324 break;
2325 case pTypeThermostat3:
2326 decode_Thermostat3(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2327 break;
2328 case pTypeThermostat4:
2329 decode_Thermostat4(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2330 break;
2331 case pTypeRadiator1:
2332 decode_Radiator1(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2333 break;
2334 case pTypeTEMP:
2335 decode_Temp(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2336 break;
2337 case pTypeHUM:
2338 decode_Hum(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2339 break;
2340 case pTypeTEMP_HUM:
2341 decode_TempHum(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2342 break;
2343 case pTypeTEMP_RAIN:
2344 decode_TempRain(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2345 break;
2346 case pTypeBARO:
2347 decode_Baro(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2348 break;
2349 case pTypeTEMP_HUM_BARO:
2350 decode_TempHumBaro(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2351 break;
2352 case pTypeTEMP_BARO:
2353 decode_TempBaro(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2354 break;
2355 case pTypeRAIN:
2356 decode_Rain(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2357 break;
2358 case pTypeWIND:
2359 decode_Wind(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2360 break;
2361 case pTypeUV:
2362 decode_UV(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2363 break;
2364 case pTypeDT:
2365 decode_DateTime(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2366 break;
2367 case pTypeCURRENT:
2368 decode_Current(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2369 break;
2370 case pTypeENERGY:
2371 decode_Energy(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2372 break;
2373 case pTypeCURRENTENERGY:
2374 decode_Current_Energy(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2375 break;
2376 case pTypeGAS:
2377 decode_Gas(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2378 break;
2379 case pTypeWATER:
2380 decode_Water(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2381 break;
2382 case pTypeWEIGHT:
2383 decode_Weight(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2384 break;
2385 case pTypeRFXSensor:
2386 decode_RFXSensor(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2387 break;
2388 case pTypeRFXMeter:
2389 decode_RFXMeter(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2390 break;
2391 case pTypeP1Power:
2392 decode_P1MeterPower(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2393 break;
2394 case pTypeP1Gas:
2395 decode_P1MeterGas(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2396 break;
2397 case pTypeUsage:
2398 decode_Usage(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2399 break;
2400 case pTypeYouLess:
2401 decode_YouLessMeter(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2402 break;
2403 case pTypeAirQuality:
2404 decode_AirQuality(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2405 break;
2406 case pTypeRego6XXTemp:
2407 decode_Rego6XXTemp(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2408 break;
2409 case pTypeRego6XXValue:
2410 decode_Rego6XXValue(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2411 break;
2412 case pTypeFS20:
2413 decode_FS20(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2414 break;
2415 case pTypeLux:
2416 decode_Lux(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2417 break;
2418 case pTypeGeneral:
2419 decode_General(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2420 break;
2421 case pTypeChime:
2422 decode_Chime(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2423 break;
2424 case pTypeBBQ:
2425 decode_BBQ(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2426 break;
2427 case pTypePOWER:
2428 decode_Power(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2429 break;
2430 case pTypeColorSwitch:
2431 decode_ColorSwitch(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2432 break;
2433 case pTypeGeneralSwitch:
2434 decode_GeneralSwitch(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2435 break;
2436 case pTypeHomeConfort:
2437 decode_HomeConfort(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2438 break;
2439 case pTypeCARTELECTRONIC:
2440 decode_Cartelectronic(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2441 break;
2442 case pTypeASYNCPORT:
2443 decode_ASyncPort(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2444 break;
2445 case pTypeASYNCDATA:
2446 decode_ASyncData(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2447 break;
2448 case pTypeWEATHER:
2449 decode_Weather(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2450 break;
2451 case pTypeSOLAR:
2452 decode_Solar(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2453 break;
2454 case pTypeHunter:
2455 decode_Hunter(pHardware, reinterpret_cast<const tRBUF*>(pRXCommand), procResult);
2456 break;
2457 default:
2458 _log.Log(LOG_ERROR, "UNHANDLED PACKET TYPE: FS20 %02X", pRXCommand[1]);
2459 return;
2460 }
2461 DeviceRowIdx = procResult.DeviceRowIdx;
2462 DeviceName = procResult.DeviceName;
2463 }
2464
2465 if (DeviceRowIdx == (uint64_t)-1)
2466 return;
2467
2468 if ((BatteryLevel != -1) && (procResult.bProcessBatteryValue))
2469 {
2470 m_sql.safe_query("UPDATE DeviceStatus SET BatteryLevel=%d WHERE (ID==%" PRIu64 ")", BatteryLevel, DeviceRowIdx);
2471 m_eventsystem.UpdateBatteryLevel(DeviceRowIdx, BatteryLevel); //GizMoCuz, temporarily...
2472 }
2473
2474 if ((defaultName != NULL) && ((DeviceName == "Unknown") || (DeviceName.empty())))
2475 {
2476 if (strlen(defaultName) > 0)
2477 {
2478 DeviceName = defaultName;
2479 m_sql.safe_query("UPDATE DeviceStatus SET Name='%q' WHERE (ID==%" PRIu64 ")", defaultName, DeviceRowIdx);
2480 }
2481 }
2482
2483 if (pHardware->m_bOutputLog)
2484 {
2485 std::string sdevicetype = RFX_Type_Desc(pRXCommand[1], 1);
2486 if (pRXCommand[1] == pTypeGeneral)
2487 {
2488 const _tGeneralDevice* pMeter = reinterpret_cast<const _tGeneralDevice*>(pRXCommand);
2489 sdevicetype += "/" + std::string(RFX_Type_SubType_Desc(pMeter->type, pMeter->subtype));
2490 }
2491 std::stringstream sTmp;
2492 sTmp << "(" << pHardware->m_Name << ") " << sdevicetype << " (" << DeviceName << ")";
2493 WriteMessageStart();
2494 WriteMessage(sTmp.str().c_str());
2495 WriteMessageEnd();
2496 }
2497
2498 //TODO: Notify plugin?
2499
2500 //Send to connected Sharing Users
2501 m_sharedserver.SendToAll(pHardware->m_HwdID, DeviceRowIdx, (const char*)pRXCommand, pRXCommand[0] + 1, pClient2Ignore);
2502
2503 sOnDeviceReceived(pHardware->m_HwdID, DeviceRowIdx, DeviceName, pRXCommand);
2504 }
2505
decode_InterfaceMessage(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)2506 void MainWorker::decode_InterfaceMessage(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
2507 {
2508 char szTmp[100];
2509
2510 WriteMessageStart();
2511
2512 switch (pResponse->IRESPONSE.subtype)
2513 {
2514 case sTypeInterfaceCommand:
2515 {
2516 int mlen = pResponse->IRESPONSE.packetlength;
2517 WriteMessage("subtype = Interface Response");
2518 sprintf(szTmp, "Sequence nbr = %d", pResponse->IRESPONSE.seqnbr);
2519 WriteMessage(szTmp);
2520 switch (pResponse->IRESPONSE.cmnd)
2521 {
2522 case cmdSTATUS:
2523 case cmdSETMODE:
2524 case trxType310:
2525 case trxType315:
2526 case recType43392:
2527 case trxType43392:
2528 case trxType868:
2529 {
2530 WriteMessage("response on cmnd = ", false);
2531 switch (pResponse->IRESPONSE.cmnd)
2532 {
2533 case cmdSTATUS:
2534 WriteMessage("Get Status");
2535 break;
2536 case cmdSETMODE:
2537 WriteMessage("Set Mode");
2538 break;
2539 case trxType310:
2540 WriteMessage("Select 310MHz");
2541 break;
2542 case trxType315:
2543 WriteMessage("Select 315MHz");
2544 break;
2545 case recType43392:
2546 WriteMessage("Select 433.92MHz");
2547 break;
2548 case trxType43392:
2549 WriteMessage("Select 433.92MHz (E)");
2550 break;
2551 case trxType868:
2552 WriteMessage("Select 868.00MHz");
2553 break;
2554 default:
2555 WriteMessage("Error: unknown response");
2556 break;
2557 }
2558
2559 m_sql.UpdateRFXCOMHardwareDetails(pHardware->m_HwdID, pResponse->IRESPONSE.msg1, pResponse->IRESPONSE.msg2, pResponse->ICMND.msg3, pResponse->ICMND.msg4, pResponse->ICMND.msg5, pResponse->ICMND.msg6);
2560
2561 switch (pResponse->IRESPONSE.msg1)
2562 {
2563 case trxType310:
2564 WriteMessage("Transceiver type = 310MHz");
2565 break;
2566 case trxType315:
2567 WriteMessage("Receiver type = 315MHz");
2568 break;
2569 case recType43392:
2570 WriteMessage("Receiver type = 433.92MHz (receive only)");
2571 break;
2572 case trxType43392:
2573 WriteMessage("Transceiver type = 433.92MHz");
2574 break;
2575 case trxType868:
2576 WriteMessage("Receiver type = 868.00MHz");
2577 break;
2578 default:
2579 WriteMessage("Receiver type = unknown");
2580 break;
2581 }
2582 int FWType = 0;
2583 int FWVersion = 0;
2584 int NoiseLevel = 0;
2585 if (mlen > 13)
2586 {
2587 FWType = pResponse->IRESPONSE.msg10;
2588 FWVersion = pResponse->IRESPONSE.msg2 + 1000;
2589 }
2590 else
2591 {
2592 FWVersion = pResponse->IRESPONSE.msg2;
2593 if ((pResponse->IRESPONSE.msg1 == recType43392) && (FWVersion < 162))
2594 FWType = 0; //Type1 RFXrec
2595 else if ((pResponse->IRESPONSE.msg1 == recType43392) && (FWVersion < 162))
2596 FWType = 1; //Type1
2597 else if ((pResponse->IRESPONSE.msg1 == recType43392) && ((FWVersion > 162) && (FWVersion < 225)))
2598 FWType = 2; //Type2
2599 else
2600 FWType = 3; //Ext
2601 }
2602 sprintf(szTmp, "Firmware version = %d", FWVersion);
2603 WriteMessage(szTmp);
2604
2605 if (
2606 (pResponse->IRESPONSE.msg1 == recType43392) ||
2607 (pResponse->IRESPONSE.msg1 == trxType43392)
2608 )
2609 {
2610 WriteMessage("Firmware type = ", false);
2611 switch (FWType)
2612 {
2613 case FWtyperec:
2614 strcpy(szTmp, "Type1 RX");
2615 break;
2616 case FWtype1:
2617 strcpy(szTmp, "Type1");
2618 break;
2619 case FWtype2:
2620 strcpy(szTmp, "Type2");
2621 break;
2622 case FWtypeExt:
2623 strcpy(szTmp, "Ext");
2624 break;
2625 case FWtypeExt2:
2626 strcpy(szTmp, "Ext2");
2627 break;
2628 case FWtypePro1:
2629 strcpy(szTmp, "Pro1");
2630 NoiseLevel = static_cast<int>(pResponse->IRESPONSE.msg11);
2631 break;
2632 case FWtypePro2:
2633 strcpy(szTmp, "Pro2");
2634 NoiseLevel = static_cast<int>(pResponse->IRESPONSE.msg11);
2635 break;
2636 case FWtypeProXL1:
2637 strcpy(szTmp, "Pro XL1");
2638 NoiseLevel = static_cast<int>(pResponse->IRESPONSE.msg11);
2639 break;
2640 default:
2641 strcpy(szTmp, "?");
2642 break;
2643 }
2644 WriteMessage(szTmp);
2645 }
2646
2647 CRFXBase* pMyHardware = (CRFXBase*)pHardware;
2648 if (pMyHardware)
2649 {
2650 pMyHardware->m_Version = std::string(szTmp) + std::string("/") + std::to_string(FWVersion);
2651
2652 if (FWType >= FWtypePro1)
2653 {
2654 pMyHardware->m_NoiseLevel = NoiseLevel;
2655 sprintf(szTmp, "Noise Level: %d", pMyHardware->m_NoiseLevel);
2656 WriteMessage(szTmp);
2657 }
2658 if (FWType == FWtypeProXL1)
2659 {
2660 pMyHardware->SetAsyncType(pMyHardware->m_AsyncType);
2661 }
2662 }
2663
2664
2665 sprintf(szTmp, "Hardware version = %d.%d", pResponse->IRESPONSE.msg7, pResponse->IRESPONSE.msg8);
2666 WriteMessage(szTmp);
2667
2668 if (pResponse->IRESPONSE.msg1 != trxType868)
2669 {
2670 if (pResponse->IRESPONSE.UNDECODEDenabled)
2671 WriteMessage("Undec on");
2672 else
2673 WriteMessage("Undec off");
2674
2675 if (pResponse->IRESPONSE.X10enabled)
2676 WriteMessage("X10 enabled");
2677 else
2678 WriteMessage("X10 disabled");
2679
2680 if (pResponse->IRESPONSE.ARCenabled)
2681 WriteMessage("ARC enabled");
2682 else
2683 WriteMessage("ARC disabled");
2684
2685 if (pResponse->IRESPONSE.ACenabled)
2686 WriteMessage("AC enabled");
2687 else
2688 WriteMessage("AC disabled");
2689
2690 if (pResponse->IRESPONSE.HEEUenabled)
2691 WriteMessage("HomeEasy EU enabled");
2692 else
2693 WriteMessage("HomeEasy EU disabled");
2694
2695 if (pResponse->IRESPONSE.MEIANTECHenabled)
2696 WriteMessage("Meiantech/Atlantic enabled");
2697 else
2698 WriteMessage("Meiantech/Atlantic disabled");
2699
2700 if (pResponse->IRESPONSE.OREGONenabled)
2701 WriteMessage("Oregon Scientific enabled");
2702 else
2703 WriteMessage("Oregon Scientific disabled");
2704
2705 if (pResponse->IRESPONSE.ATIenabled)
2706 WriteMessage("ATI/Cartelectronic enabled");
2707 else
2708 WriteMessage("ATI/Cartelectronic disabled");
2709
2710 if (pResponse->IRESPONSE.VISONICenabled)
2711 WriteMessage("Visonic enabled");
2712 else
2713 WriteMessage("Visonic disabled");
2714
2715 if (pResponse->IRESPONSE.MERTIKenabled)
2716 WriteMessage("Mertik enabled");
2717 else
2718 WriteMessage("Mertik disabled");
2719
2720 if (pResponse->IRESPONSE.LWRFenabled)
2721 WriteMessage("AD enabled");
2722 else
2723 WriteMessage("AD disabled");
2724
2725 if (pResponse->IRESPONSE.HIDEKIenabled)
2726 WriteMessage("Hideki enabled");
2727 else
2728 WriteMessage("Hideki disabled");
2729
2730 if (pResponse->IRESPONSE.LACROSSEenabled)
2731 WriteMessage("La Crosse enabled");
2732 else
2733 WriteMessage("La Crosse disabled");
2734
2735 if (pResponse->IRESPONSE.LEGRANDenabled)
2736 WriteMessage("Legrand enabled");
2737 else
2738 WriteMessage("Legrand disabled");
2739
2740 if (pResponse->IRESPONSE.MSG4Reserved5)
2741 WriteMessage("MSG4Reserved5 enabled");
2742 else
2743 WriteMessage("MSG4Reserved5 disabled");
2744
2745 if (pResponse->IRESPONSE.BLINDST0enabled)
2746 WriteMessage("BlindsT0 enabled");
2747 else
2748 WriteMessage("BlindsT0 disabled");
2749
2750 if (pResponse->IRESPONSE.BLINDST1enabled)
2751 WriteMessage("BlindsT1 enabled");
2752 else
2753 WriteMessage("BlindsT1 disabled");
2754
2755 if (pResponse->IRESPONSE.AEenabled)
2756 WriteMessage("AE enabled");
2757 else
2758 WriteMessage("AE disabled");
2759
2760 if (pResponse->IRESPONSE.RUBICSONenabled)
2761 WriteMessage("RUBiCSON enabled");
2762 else
2763 WriteMessage("RUBiCSON disabled");
2764
2765 if (pResponse->IRESPONSE.FINEOFFSETenabled)
2766 WriteMessage("FineOffset enabled");
2767 else
2768 WriteMessage("FineOffset disabled");
2769
2770 if (pResponse->IRESPONSE.LIGHTING4enabled)
2771 WriteMessage("Lighting4 enabled");
2772 else
2773 WriteMessage("Lighting4 disabled");
2774
2775 if (pResponse->IRESPONSE.RSLenabled)
2776 WriteMessage("Conrad RSL enabled");
2777 else
2778 WriteMessage("Conrad RSL disabled");
2779
2780 if (pResponse->IRESPONSE.SXenabled)
2781 WriteMessage("ByronSX enabled");
2782 else
2783 WriteMessage("ByronSX disabled");
2784
2785 if (pResponse->IRESPONSE.IMAGINTRONIXenabled)
2786 WriteMessage("IMAGINTRONIX enabled");
2787 else
2788 WriteMessage("IMAGINTRONIX disabled");
2789
2790 if (pResponse->IRESPONSE.KEELOQenabled)
2791 WriteMessage("KEELOQ enabled");
2792 else
2793 WriteMessage("KEELOQ disabled");
2794
2795 if (pResponse->IRESPONSE.HCEnabled)
2796 WriteMessage("Home Confort enabled");
2797 else
2798 WriteMessage("Home Confort disabled");
2799 }
2800 else
2801 {
2802 //868
2803 if (pResponse->IRESPONSE868.UNDECODEDenabled)
2804 WriteMessage("Undec on");
2805 else
2806 WriteMessage("Undec off");
2807
2808 if (pResponse->IRESPONSE868.ALECTOenabled)
2809 WriteMessage("Alecto ACH2010 enabled");
2810
2811 if (pResponse->IRESPONSE868.ALECTO5500enabled)
2812 WriteMessage("Alecto WS5500 enabled");
2813
2814 if (pResponse->IRESPONSE868.LACROSSEenabled)
2815 WriteMessage("LA Crosse enabled");
2816
2817 if (pResponse->IRESPONSE868.DAVISEUenabled)
2818 WriteMessage("Davis EU enabled");
2819
2820 if (pResponse->IRESPONSE868.DAVISUSenabled)
2821 WriteMessage("Davis US enabled");
2822
2823 if (pResponse->IRESPONSE868.DAVISAUenabled)
2824 WriteMessage("Davis AU enabled");
2825
2826 if (pResponse->IRESPONSE868.FS20enabled)
2827 WriteMessage("FS20 enabled");
2828
2829 if (pResponse->IRESPONSE868.LWRFenabled)
2830 WriteMessage("LightwaveRF enabled");
2831
2832 if (pResponse->IRESPONSE868.EDISIOenabled)
2833 WriteMessage("Edisio enabled");
2834
2835 if (pResponse->IRESPONSE868.VISONICenabled)
2836 WriteMessage("Visonic enabled");
2837
2838 if (pResponse->IRESPONSE868.MEIANTECHenabled)
2839 WriteMessage("Meiantech enabled");
2840
2841 if (pResponse->IRESPONSE868.KEELOQenabled)
2842 WriteMessage("Keeloq enabled");
2843
2844 if (pResponse->IRESPONSE868.PROGUARDenabled)
2845 WriteMessage("Proguard enabled");
2846
2847 if (pResponse->IRESPONSE868.ITHOenabled)
2848 WriteMessage("Itho CVE RFT enabled");
2849
2850 if (pResponse->IRESPONSE868.ITHOecoenabled)
2851 WriteMessage("Itho CVE ECO RFT enabled");
2852
2853 if (pResponse->IRESPONSE868.HONEYWELLenabled)
2854 WriteMessage("Honeywell Chime enabled");
2855
2856 }
2857 }
2858 break;
2859 case cmdSAVE:
2860 WriteMessage("response on cmnd = Save");
2861 break;
2862 }
2863 break;
2864 }
2865 break;
2866 case sTypeUnknownRFYremote:
2867 WriteMessage("subtype = Unknown RFY remote! Use the Program command to create a remote in the RFXtrx433Ext");
2868 sprintf(szTmp, "Sequence nbr = %d", pResponse->IRESPONSE.seqnbr);
2869 WriteMessage(szTmp);
2870 break;
2871 case sTypeExtError:
2872 WriteMessage("subtype = No RFXtrx433E hardware detected");
2873 sprintf(szTmp, "Sequence nbr = %d", pResponse->IRESPONSE.seqnbr);
2874 WriteMessage(szTmp);
2875 break;
2876 case sTypeRFYremoteList:
2877 if ((pResponse->ICMND.xmitpwr == 0) && (pResponse->ICMND.msg3 == 0) && (pResponse->ICMND.msg4 == 0) && (pResponse->ICMND.msg5 == 0))
2878 {
2879 sprintf(szTmp, "subtype = RFY remote: %d is empty", pResponse->ICMND.freqsel);
2880 WriteMessage(szTmp);
2881 }
2882 else
2883 {
2884 sprintf(szTmp, "subtype = RFY remote: %d, ID: %02d%02d%02d, unitnbr: %d",
2885 pResponse->ICMND.freqsel,
2886 pResponse->ICMND.xmitpwr,
2887 pResponse->ICMND.msg3,
2888 pResponse->ICMND.msg4,
2889 pResponse->ICMND.msg5);
2890 WriteMessage(szTmp);
2891 }
2892 break;
2893 case sTypeASAremoteList:
2894 if ((pResponse->ICMND.xmitpwr == 0) && (pResponse->ICMND.msg3 == 0) && (pResponse->ICMND.msg4 == 0) && (pResponse->ICMND.msg5 == 0))
2895 {
2896 sprintf(szTmp, "subtype = ASA remote: %d is empty", pResponse->ICMND.freqsel);
2897 WriteMessage(szTmp);
2898 }
2899 else
2900 {
2901 sprintf(szTmp, "subtype = ASA remote: %d, ID: %02d%02d%02d, unitnbr: %d",
2902 pResponse->ICMND.freqsel,
2903 pResponse->ICMND.xmitpwr,
2904 pResponse->ICMND.msg3,
2905 pResponse->ICMND.msg4,
2906 pResponse->ICMND.msg5);
2907 WriteMessage(szTmp);
2908 }
2909 break;
2910 case sTypeInterfaceWrongCommand:
2911 if (pResponse->IRESPONSE.cmnd == 0x07)
2912 {
2913 WriteMessage("Please upgrade your RFXTrx Firmware!");
2914 }
2915 else
2916 {
2917 sprintf(szTmp, "subtype = Wrong command received from application (%d)", pResponse->IRESPONSE.cmnd);
2918 WriteMessage(szTmp);
2919 sprintf(szTmp, "Sequence nbr = %d", pResponse->IRESPONSE.seqnbr);
2920 WriteMessage(szTmp);
2921 }
2922 break;
2923 }
2924 WriteMessageEnd();
2925 procResult.DeviceRowIdx = -1;
2926 }
2927
decode_InterfaceControl(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)2928 void MainWorker::decode_InterfaceControl(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
2929 {
2930 char szTmp[100];
2931 WriteMessageStart();
2932 switch (pResponse->IRESPONSE.subtype)
2933 {
2934 case sTypeInterfaceCommand:
2935 WriteMessage("subtype = Interface Command");
2936 sprintf(szTmp, "Sequence nbr = %d", pResponse->IRESPONSE.seqnbr);
2937 WriteMessage(szTmp);
2938 switch (pResponse->IRESPONSE.cmnd)
2939 {
2940 case cmdRESET:
2941 WriteMessage("reset the receiver/transceiver");
2942 break;
2943 case cmdSTATUS:
2944 WriteMessage("return firmware versions and configuration of the interface");
2945 break;
2946 case cmdSETMODE:
2947 WriteMessage("set configuration of the interface");
2948 break;
2949 case cmdSAVE:
2950 WriteMessage("save receiving modes of the receiver/transceiver in non-volatile memory");
2951 break;
2952 case cmdStartRec:
2953 WriteMessage("start RFXtrx receiver");
2954 break;
2955 case trxType310:
2956 WriteMessage("select 310MHz in the 310/315 transceiver");
2957 break;
2958 case trxType315:
2959 WriteMessage("select 315MHz in the 310/315 transceiver");
2960 break;
2961 case recType43392:
2962 case trxType43392:
2963 WriteMessage("select 433.92MHz in the 433 transceiver");
2964 break;
2965 case trxType868:
2966 WriteMessage("select 868MHz in the 868 transceiver");
2967 break;
2968 }
2969 break;
2970 }
2971 WriteMessageEnd();
2972 procResult.DeviceRowIdx = -1;
2973 }
2974
decode_BateryLevel(bool bIsInPercentage,uint8_t level)2975 void MainWorker::decode_BateryLevel(bool bIsInPercentage, uint8_t level)
2976 {
2977 if (bIsInPercentage)
2978 {
2979 switch (level)
2980 {
2981 case 0:
2982 WriteMessage("Battery = 10%");
2983 break;
2984 case 1:
2985 WriteMessage("Battery = 20%");
2986 break;
2987 case 2:
2988 WriteMessage("Battery = 30%");
2989 break;
2990 case 3:
2991 WriteMessage("Battery = 40%");
2992 break;
2993 case 4:
2994 WriteMessage("Battery = 50%");
2995 break;
2996 case 5:
2997 WriteMessage("Battery = 60%");
2998 break;
2999 case 6:
3000 WriteMessage("Battery = 70%");
3001 break;
3002 case 7:
3003 WriteMessage("Battery = 80%");
3004 break;
3005 case 8:
3006 WriteMessage("Battery = 90%");
3007 break;
3008 case 9:
3009 WriteMessage("Battery = 100%");
3010 break;
3011 }
3012 }
3013 else
3014 {
3015 if (level == 0)
3016 {
3017 WriteMessage("Battery = Low");
3018 }
3019 else
3020 {
3021 WriteMessage("Battery = OK");
3022 }
3023 }
3024 }
3025
get_BateryLevel(const _eHardwareTypes HwdType,bool bIsInPercentage,uint8_t level)3026 uint8_t MainWorker::get_BateryLevel(const _eHardwareTypes HwdType, bool bIsInPercentage, uint8_t level)
3027 {
3028 if (HwdType == HTYPE_OpenZWave)
3029 {
3030 bIsInPercentage = true;
3031 }
3032 uint8_t ret = 0;
3033 if (bIsInPercentage)
3034 {
3035 if (level >= 0 && level <= 9)
3036 ret = (level + 1) * 10;
3037 }
3038 else
3039 {
3040 if (level == 0)
3041 {
3042 ret = 0;
3043 }
3044 else
3045 {
3046 ret = 100;
3047 }
3048 }
3049 return ret;
3050 }
3051
decode_Rain(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)3052 void MainWorker::decode_Rain(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
3053 {
3054 char szTmp[100];
3055 uint8_t devType = pTypeRAIN;
3056 uint8_t subType = pResponse->RAIN.subtype;
3057 std::string ID;
3058 sprintf(szTmp, "%d", (pResponse->RAIN.id1 * 256) + pResponse->RAIN.id2);
3059 ID = szTmp;
3060 uint8_t Unit = 0;
3061 uint8_t cmnd = 0;
3062 uint8_t SignalLevel = pResponse->RAIN.rssi;
3063 uint8_t BatteryLevel = get_BateryLevel(pHardware->HwdType, pResponse->RAIN.subtype == sTypeRAIN1, pResponse->RAIN.battery_level & 0x0F);
3064
3065 int Rainrate = (pResponse->RAIN.rainrateh * 256) + pResponse->RAIN.rainratel;
3066
3067 float TotalRain = float((pResponse->RAIN.raintotal1 * 65535) + (pResponse->RAIN.raintotal2 * 256) + pResponse->RAIN.raintotal3) / 10.0f;
3068
3069 if (subType == sTypeRAINByRate)
3070 {
3071 //calculate new Total
3072 TotalRain = 0;
3073
3074 std::vector<std::vector<std::string>> result;
3075
3076 //Get our index
3077 result = m_sql.safe_query(
3078 "SELECT ID FROM DeviceStatus WHERE (HardwareID=%d AND DeviceID='%q' AND Unit=%d AND Type=%d AND SubType=%d)", pHardware->m_HwdID, ID.c_str(), Unit, devType, subType);
3079 if (!result.empty())
3080 {
3081 uint64_t ulID = std::strtoull(result[0][0].c_str(), nullptr, 10);
3082
3083 time_t now = mytime(NULL);
3084 struct tm ltime;
3085 localtime_r(&now, <ime);
3086
3087 std::vector<std::vector<std::string>> result;
3088 result = m_sql.safe_query(
3089 "SELECT Rate, Date FROM Rain WHERE (DeviceRowID=%" PRIu64 " AND Date>='%04d-%02d-%02d') ORDER BY ROWID ASC",
3090 ulID, ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday);
3091 if (!result.empty())
3092 {
3093 time_t countTime;
3094 struct tm midnightTime;
3095 getMidnight(countTime, midnightTime);
3096
3097 for (const auto& itt : result)
3098 {
3099 std::vector<std::string> sd = itt;
3100
3101 float rate = (float)atof(sd[0].c_str()) / 10000.0f;
3102 std::string date = sd[1];
3103
3104 time_t rowtime;
3105 struct tm rowTimetm;
3106 ParseSQLdatetime(rowtime, rowTimetm, date);
3107
3108 int pastSeconds = (int)(rowtime - countTime);
3109
3110 float rateAdd = (rate / (float)3600 * (float)pastSeconds);
3111 TotalRain += rateAdd;
3112
3113 countTime = rowtime;
3114 }
3115 }
3116 }
3117 }
3118 else if (subType != sTypeRAINWU)
3119 {
3120 Rainrate = 0;
3121 //Calculate our own rainrate
3122 std::vector<std::vector<std::string>> result;
3123
3124 //Get our index
3125 result = m_sql.safe_query(
3126 "SELECT ID FROM DeviceStatus WHERE (HardwareID=%d AND DeviceID='%q' AND Unit=%d AND Type=%d AND SubType=%d)", pHardware->m_HwdID, ID.c_str(), Unit, devType, subType);
3127 if (!result.empty())
3128 {
3129 uint64_t ulID = std::strtoull(result[0][0].c_str(), nullptr, 10);
3130
3131 //Get Counter from one Hour ago
3132 time_t now = mytime(NULL);
3133 now -= 3600; //subtract one hour
3134 struct tm ltime;
3135 localtime_r(&now, <ime);
3136
3137 std::vector<std::vector<std::string>> result;
3138 result = m_sql.safe_query(
3139 "SELECT MIN(Total) FROM Rain WHERE (DeviceRowID=%" PRIu64 " AND Date>='%04d-%02d-%02d %02d:%02d:%02d')",
3140 ulID, ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday, ltime.tm_hour, ltime.tm_min, ltime.tm_sec);
3141 if (result.size() == 1)
3142 {
3143 float totalRainFallLastHour = TotalRain - static_cast<float>(atof(result[0][0].c_str()));
3144 Rainrate = round(totalRainFallLastHour * 100.0f);
3145 }
3146 }
3147 }
3148
3149 sprintf(szTmp, "%d;%.1f", Rainrate, TotalRain);
3150 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
3151 if (DevRowIdx == (uint64_t)-1)
3152 return;
3153
3154 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, cmnd, szTmp);
3155
3156 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
3157 {
3158 WriteMessageStart();
3159 switch (subType)
3160 {
3161 case sTypeRAIN1:
3162 WriteMessage("subtype = RAIN1 - RGR126/682/918/928");
3163 break;
3164 case sTypeRAIN2:
3165 WriteMessage("subtype = RAIN2 - PCR800");
3166 break;
3167 case sTypeRAIN3:
3168 WriteMessage("subtype = RAIN3 - TFA");
3169 break;
3170 case sTypeRAIN4:
3171 WriteMessage("subtype = RAIN4 - UPM RG700");
3172 break;
3173 case sTypeRAIN5:
3174 WriteMessage("subtype = RAIN5 - LaCrosse WS2300");
3175 break;
3176 case sTypeRAIN6:
3177 WriteMessage("subtype = RAIN6 - LaCrosse TX5");
3178 break;
3179 case sTypeRAIN7:
3180 WriteMessage("subtype = RAIN7 - Alecto");
3181 break;
3182 case sTypeRAIN8:
3183 WriteMessage("subtype = RAIN8 - Davis");
3184 break;
3185 case sTypeRAIN9:
3186 WriteMessage("subtype = RAIN9 - TFA 30.3233.01");
3187 break;
3188 case sTypeRAINWU:
3189 WriteMessage("subtype = Weather Underground (Total Rain)");
3190 break;
3191 default:
3192 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X : %02X", pResponse->RAIN.packettype, pResponse->RAIN.subtype);
3193 WriteMessage(szTmp);
3194 break;
3195 }
3196
3197 sprintf(szTmp, "Sequence nbr = %d", pResponse->RAIN.seqnbr);
3198 WriteMessage(szTmp);
3199
3200 sprintf(szTmp, "ID = %s", ID.c_str());
3201 WriteMessage(szTmp);
3202
3203 if (pResponse->RAIN.subtype == sTypeRAIN1)
3204 {
3205 sprintf(szTmp, "Rain rate = %d mm/h", Rainrate);
3206 WriteMessage(szTmp);
3207 }
3208 else if (pResponse->RAIN.subtype == sTypeRAIN2)
3209 {
3210 sprintf(szTmp, "Rain rate = %d mm/h", Rainrate);
3211 WriteMessage(szTmp);
3212 }
3213
3214 sprintf(szTmp, "Total rain = %.1f mm", TotalRain);
3215 WriteMessage(szTmp);
3216 sprintf(szTmp, "Signal level = %d", pResponse->RAIN.rssi);
3217 WriteMessage(szTmp);
3218
3219 decode_BateryLevel(pResponse->RAIN.subtype == sTypeRAIN1, pResponse->RAIN.battery_level & 0x0F);
3220 WriteMessageEnd();
3221 }
3222 procResult.DeviceRowIdx = DevRowIdx;
3223 }
3224
decode_Wind(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)3225 void MainWorker::decode_Wind(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
3226 {
3227 char szTmp[300];
3228 uint8_t devType = pTypeWIND;
3229 uint8_t subType = pResponse->WIND.subtype;
3230 uint16_t windID = (pResponse->WIND.id1 * 256) + pResponse->WIND.id2;
3231 sprintf(szTmp, "%d", windID);
3232 std::string ID = szTmp;
3233 uint8_t Unit = 0;
3234
3235 uint8_t cmnd = 0;
3236 uint8_t SignalLevel = pResponse->WIND.rssi;
3237 uint8_t BatteryLevel = get_BateryLevel(pHardware->HwdType, pResponse->WIND.subtype == sTypeWIND3, pResponse->WIND.battery_level & 0x0F);
3238
3239 double dDirection;
3240 dDirection = (double)(pResponse->WIND.directionh * 256) + pResponse->WIND.directionl;
3241 dDirection = m_wind_calculator[windID].AddValueAndReturnAvarage(dDirection);
3242
3243 std::string strDirection;
3244 if (dDirection > 348.75 || dDirection < 11.26)
3245 strDirection = "N";
3246 else if (dDirection < 33.76)
3247 strDirection = "NNE";
3248 else if (dDirection < 56.26)
3249 strDirection = "NE";
3250 else if (dDirection < 78.76)
3251 strDirection = "ENE";
3252 else if (dDirection < 101.26)
3253 strDirection = "E";
3254 else if (dDirection < 123.76)
3255 strDirection = "ESE";
3256 else if (dDirection < 146.26)
3257 strDirection = "SE";
3258 else if (dDirection < 168.76)
3259 strDirection = "SSE";
3260 else if (dDirection < 191.26)
3261 strDirection = "S";
3262 else if (dDirection < 213.76)
3263 strDirection = "SSW";
3264 else if (dDirection < 236.26)
3265 strDirection = "SW";
3266 else if (dDirection < 258.76)
3267 strDirection = "WSW";
3268 else if (dDirection < 281.26)
3269 strDirection = "W";
3270 else if (dDirection < 303.76)
3271 strDirection = "WNW";
3272 else if (dDirection < 326.26)
3273 strDirection = "NW";
3274 else if (dDirection < 348.76)
3275 strDirection = "NNW";
3276 else
3277 strDirection = "---";
3278
3279 dDirection = round(dDirection);
3280
3281 int intSpeed = (pResponse->WIND.av_speedh * 256) + pResponse->WIND.av_speedl;
3282 int intGust = (pResponse->WIND.gusth * 256) + pResponse->WIND.gustl;
3283
3284 if (pResponse->WIND.subtype == sTypeWIND6)
3285 {
3286 //LaCrosse WS2300
3287 //This sensor is only reporting gust, speed=gust
3288 intSpeed = intGust;
3289 }
3290
3291 m_wind_calculator[windID].SetSpeedGust(intSpeed, intGust);
3292
3293 float temp = 0, chill = 0;
3294 if (subType != sTypeWINDNoTempNoChill)
3295 {
3296 if (pResponse->WIND.subtype == sTypeWIND4)
3297 {
3298 if (!pResponse->WIND.tempsign)
3299 {
3300 temp = float((pResponse->WIND.temperatureh * 256) + pResponse->WIND.temperaturel) / 10.0f;
3301 }
3302 else
3303 {
3304 temp = -(float(((pResponse->WIND.temperatureh & 0x7F) * 256) + pResponse->WIND.temperaturel) / 10.0f);
3305 }
3306 if ((temp < -200) || (temp > 380))
3307 {
3308 WriteMessage(" Invalid Temperature");
3309 return;
3310 }
3311
3312 float AddjValue = 0.0f;
3313 float AddjMulti = 1.0f;
3314 m_sql.GetAddjustment(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, AddjValue, AddjMulti);
3315 temp += AddjValue;
3316
3317 if (!pResponse->WIND.chillsign)
3318 {
3319 chill = float((pResponse->WIND.chillh * 256) + pResponse->WIND.chilll) / 10.0f;
3320 }
3321 else
3322 {
3323 chill = -(float(((pResponse->WIND.chillh) & 0x7F) * 256 + pResponse->WIND.chilll) / 10.0f);
3324 }
3325 chill += AddjValue;
3326 }
3327 else if (pResponse->WIND.subtype == sTypeWINDNoTemp)
3328 {
3329 float AddjValue = 0.0f;
3330 float AddjMulti = 1.0f;
3331 m_sql.GetAddjustment(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, AddjValue, AddjMulti);
3332 temp += AddjValue;
3333
3334 if (!pResponse->WIND.chillsign)
3335 {
3336 chill = float((pResponse->WIND.chillh * 256) + pResponse->WIND.chilll) / 10.0f;
3337 }
3338 else
3339 {
3340 chill = -(float(((pResponse->WIND.chillh) & 0x7F) * 256 + pResponse->WIND.chilll) / 10.0f);
3341 }
3342 chill += AddjValue;
3343 }
3344 if (chill == 0)
3345 {
3346 float wspeedms = float(intSpeed) / 10.0f;
3347 if ((temp < 10.0) && (wspeedms >= 1.4))
3348 {
3349 float chillJatTI = 13.12f + 0.6215f * temp - 11.37f * pow(wspeedms * 3.6f, 0.16f) + 0.3965f * temp * pow(wspeedms * 3.6f, 0.16f);
3350 chill = chillJatTI;
3351 }
3352 }
3353 }
3354
3355 sprintf(szTmp, "%.2f;%s;%d;%d;%.1f;%.1f", dDirection, strDirection.c_str(), intSpeed, intGust, temp, chill);
3356 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
3357 if (DevRowIdx == (uint64_t)-1)
3358 return;
3359
3360 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, cmnd, szTmp);
3361
3362 uint64_t tID = ((uint64_t)(pHardware->m_HwdID & 0x7FFFFFFF) << 32) | (DevRowIdx & 0x7FFFFFFF);
3363 m_trend_calculator[tID].AddValueAndReturnTendency(static_cast<double>(chill), _tTrendCalculator::TAVERAGE_TEMP);
3364
3365 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
3366 {
3367 WriteMessageStart();
3368 switch (pResponse->WIND.subtype)
3369 {
3370 case sTypeWIND1:
3371 WriteMessage("subtype = WIND1 - WTGR800");
3372 break;
3373 case sTypeWIND2:
3374 WriteMessage("subtype = WIND2 - WGR800");
3375 break;
3376 case sTypeWIND3:
3377 WriteMessage("subtype = WIND3 - STR918/928, WGR918");
3378 break;
3379 case sTypeWIND4:
3380 WriteMessage("subtype = WIND4 - TFA");
3381 break;
3382 case sTypeWIND5:
3383 WriteMessage("subtype = WIND5 - UPM WDS500");
3384 break;
3385 case sTypeWIND6:
3386 WriteMessage("subtype = WIND6 - LaCrosse WS2300");
3387 break;
3388 case sTypeWIND7:
3389 WriteMessage("subtype = WIND7 - Alecto WS4500");
3390 break;
3391 case sTypeWINDNoTemp:
3392 WriteMessage("subtype = Weather Station");
3393 break;
3394 case sTypeWINDNoTempNoChill:
3395 WriteMessage("subtype = Wind (No Temp or Chill sensors");
3396 break;
3397 default:
3398 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->WIND.packettype, pResponse->WIND.subtype);
3399 WriteMessage(szTmp);
3400 break;
3401 }
3402
3403 sprintf(szTmp, "Sequence nbr = %d", pResponse->WIND.seqnbr);
3404 WriteMessage(szTmp);
3405 sprintf(szTmp, "ID = %s", ID.c_str());
3406 WriteMessage(szTmp);
3407
3408 sprintf(szTmp, "Direction = %d degrees %s", int(dDirection), strDirection.c_str());
3409 WriteMessage(szTmp);
3410
3411 if (pResponse->WIND.subtype != sTypeWIND5)
3412 {
3413 sprintf(szTmp, "Average speed = %.1f mtr/sec, %.2f km/hr, %.2f mph", float(intSpeed) / 10.0f, (float(intSpeed) * 0.36f), (float(intSpeed) * 0.223693629f));
3414 WriteMessage(szTmp);
3415 }
3416
3417 sprintf(szTmp, "Wind gust = %.1f mtr/sec, %.2f km/hr, %.2f mph", float(intGust) / 10.0f, (float(intGust) * 0.36f), (float(intGust) * 0.223693629f));
3418 WriteMessage(szTmp);
3419
3420 if (pResponse->WIND.subtype == sTypeWIND4)
3421 {
3422 sprintf(szTmp, "Temperature = %.1f C", temp);
3423 WriteMessage(szTmp);
3424
3425 sprintf(szTmp, "Chill = %.1f C", chill);
3426 WriteMessage(szTmp);
3427 }
3428 if (pResponse->WIND.subtype == sTypeWINDNoTemp)
3429 {
3430 sprintf(szTmp, "Chill = %.1f C", chill);
3431 WriteMessage(szTmp);
3432 }
3433
3434 sprintf(szTmp, "Signal level = %d", pResponse->WIND.rssi);
3435 WriteMessage(szTmp);
3436
3437 decode_BateryLevel(pResponse->WIND.subtype == sTypeWIND3, pResponse->WIND.battery_level & 0x0F);
3438 WriteMessageEnd();
3439 }
3440 procResult.DeviceRowIdx = DevRowIdx;
3441 }
3442
decode_Temp(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)3443 void MainWorker::decode_Temp(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
3444 {
3445 char szTmp[100];
3446 uint8_t devType = pTypeTEMP;
3447 uint8_t subType = pResponse->TEMP.subtype;
3448 sprintf(szTmp, "%d", (pResponse->TEMP.id1 * 256) + pResponse->TEMP.id2);
3449 std::string ID = szTmp;
3450 uint8_t Unit = pResponse->TEMP.id2;
3451
3452 uint8_t cmnd = 0;
3453 uint8_t SignalLevel = pResponse->TEMP.rssi;
3454 uint8_t BatteryLevel = 0;
3455 if ((pResponse->TEMP.battery_level & 0x0F) == 0)
3456 BatteryLevel = 0;
3457 else
3458 BatteryLevel = 100;
3459
3460 //Override battery level if hardware supports it
3461 if (pHardware->HwdType == HTYPE_OpenZWave)
3462 {
3463 BatteryLevel = pResponse->TEMP.battery_level * 10;
3464 }
3465 else if ((pHardware->HwdType == HTYPE_EnOceanESP2) || (pHardware->HwdType == HTYPE_EnOceanESP3))
3466 {
3467 BatteryLevel = 255;
3468 SignalLevel = 12;
3469 Unit = (pResponse->TEMP.rssi << 4) | pResponse->TEMP.battery_level;
3470 }
3471
3472 float temp;
3473 if (!pResponse->TEMP.tempsign)
3474 {
3475 temp = float((pResponse->TEMP.temperatureh * 256) + pResponse->TEMP.temperaturel) / 10.0f;
3476 }
3477 else
3478 {
3479 temp = -(float(((pResponse->TEMP.temperatureh & 0x7F) * 256) + pResponse->TEMP.temperaturel) / 10.0f);
3480 }
3481 if ((temp < -200) || (temp > 380))
3482 {
3483 WriteMessage(" Invalid Temperature");
3484 return;
3485 }
3486
3487 float AddjValue = 0.0f;
3488 float AddjMulti = 1.0f;
3489 m_sql.GetAddjustment(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, AddjValue, AddjMulti);
3490 temp += AddjValue;
3491
3492 sprintf(szTmp, "%.1f", temp);
3493 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
3494 if (DevRowIdx == (uint64_t)-1)
3495 return;
3496
3497 uint64_t tID = ((uint64_t)(pHardware->m_HwdID & 0x7FFFFFFF) << 32) | (DevRowIdx & 0x7FFFFFFF);
3498 m_trend_calculator[tID].AddValueAndReturnTendency(static_cast<double>(temp), _tTrendCalculator::TAVERAGE_TEMP);
3499
3500 bool bHandledNotification = false;
3501 uint8_t humidity = 0;
3502 if (pResponse->TEMP.subtype == sTypeTEMP5)
3503 {
3504 //check if we already had a humidity for this device, if so, keep it!
3505 char szTmp[300];
3506 std::vector<std::vector<std::string> > result;
3507
3508 result = m_sql.safe_query(
3509 "SELECT nValue,sValue FROM DeviceStatus WHERE (HardwareID=%d AND DeviceID='%q' AND Unit=%d AND Type=%d AND SubType=%d)",
3510 pHardware->m_HwdID, ID.c_str(), 1, pTypeHUM, sTypeHUM1);
3511 if (result.size() == 1)
3512 {
3513 m_sql.GetAddjustment(pHardware->m_HwdID, ID.c_str(), 2, pTypeTEMP_HUM, sTypeTH_LC_TC, AddjValue, AddjMulti);
3514 temp += AddjValue;
3515 humidity = atoi(result[0][0].c_str());
3516 uint8_t humidity_status = atoi(result[0][1].c_str());
3517 sprintf(szTmp, "%.1f;%d;%d", temp, humidity, humidity_status);
3518 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), 2, pTypeTEMP_HUM, sTypeTH_LC_TC, SignalLevel, BatteryLevel, 0, szTmp, procResult.DeviceName);
3519 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, pTypeTEMP_HUM, sTypeTH_LC_TC, szTmp);
3520
3521 bHandledNotification = true;
3522 }
3523 }
3524
3525 if (!bHandledNotification)
3526 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, temp);
3527
3528 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
3529 {
3530 WriteMessageStart();
3531 switch (pResponse->TEMP.subtype)
3532 {
3533 case sTypeTEMP1:
3534 WriteMessage("subtype = TEMP1 - THR128/138, THC138");
3535 sprintf(szTmp, " channel %d", pResponse->TEMP.id2);
3536 WriteMessage(szTmp);
3537 break;
3538 case sTypeTEMP2:
3539 WriteMessage("subtype = TEMP2 - THC238/268,THN132,THWR288,THRN122,THN122,AW129/131");
3540 sprintf(szTmp, " channel %d", pResponse->TEMP.id2);
3541 WriteMessage(szTmp);
3542 break;
3543 case sTypeTEMP3:
3544 WriteMessage("subtype = TEMP3 - THWR800");
3545 break;
3546 case sTypeTEMP4:
3547 WriteMessage("subtype = TEMP4 - RTHN318");
3548 sprintf(szTmp, " channel %d", pResponse->TEMP.id2);
3549 WriteMessage(szTmp);
3550 break;
3551 case sTypeTEMP5:
3552 WriteMessage("subtype = TEMP5 - LaCrosse TX2, TX3, TX4, TX17");
3553 break;
3554 case sTypeTEMP6:
3555 WriteMessage("subtype = TEMP6 - TS15C");
3556 break;
3557 case sTypeTEMP7:
3558 WriteMessage("subtype = TEMP7 - Viking 02811, Proove TSS330");
3559 break;
3560 case sTypeTEMP8:
3561 WriteMessage("subtype = TEMP8 - LaCrosse WS2300");
3562 break;
3563 case sTypeTEMP9:
3564 if (pResponse->TEMP.id2 & 0xFF)
3565 WriteMessage("subtype = TEMP9 - RUBiCSON 48659 stektermometer");
3566 else
3567 WriteMessage("subtype = TEMP9 - RUBiCSON 48695");
3568 break;
3569 case sTypeTEMP10:
3570 WriteMessage("subtype = TEMP10 - TFA 30.3133");
3571 break;
3572 case sTypeTEMP11:
3573 WriteMessage("subtype = WT0122 pool sensor");
3574 break;
3575 case sTypeTEMP_SYSTEM:
3576 WriteMessage("subtype = System");
3577 break;
3578 default:
3579 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->TEMP.packettype, pResponse->TEMP.subtype);
3580 WriteMessage(szTmp);
3581 break;
3582 }
3583
3584 sprintf(szTmp, "Sequence nbr = %d", pResponse->TEMP.seqnbr);
3585 WriteMessage(szTmp);
3586 sprintf(szTmp, "ID = %d", (pResponse->TEMP.id1 * 256) + pResponse->TEMP.id2);
3587 WriteMessage(szTmp);
3588
3589 sprintf(szTmp, "Temperature = %.1f C", temp);
3590 WriteMessage(szTmp);
3591
3592 sprintf(szTmp, "Signal level = %d", pResponse->TEMP.rssi);
3593 WriteMessage(szTmp);
3594
3595 if ((pResponse->TEMP.battery_level & 0x0F) == 0)
3596 WriteMessage("Battery = Low");
3597 else
3598 WriteMessage("Battery = OK");
3599 WriteMessageEnd();
3600 }
3601 procResult.DeviceRowIdx = DevRowIdx;
3602 }
3603
decode_Hum(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)3604 void MainWorker::decode_Hum(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
3605 {
3606 char szTmp[100];
3607 uint8_t devType = pTypeHUM;
3608 uint8_t subType = pResponse->HUM.subtype;
3609 sprintf(szTmp, "%d", (pResponse->HUM.id1 * 256) + pResponse->HUM.id2);
3610 std::string ID = szTmp;
3611 uint8_t Unit = 1;
3612
3613 uint8_t SignalLevel = pResponse->HUM.rssi;
3614 uint8_t BatteryLevel = 0;
3615 if ((pResponse->HUM.battery_level & 0x0F) == 0)
3616 BatteryLevel = 0;
3617 else
3618 BatteryLevel = 100;
3619 //Override battery level if hardware supports it
3620 if (pHardware->HwdType == HTYPE_OpenZWave)
3621 {
3622 BatteryLevel = pResponse->TEMP.battery_level;
3623 }
3624
3625 uint8_t humidity = pResponse->HUM.humidity;
3626 if (humidity > 100)
3627 {
3628 WriteMessage(" Invalid Humidity");
3629 return;
3630 }
3631
3632 sprintf(szTmp, "%d", pResponse->HUM.humidity_status);
3633 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, humidity, szTmp, procResult.DeviceName);
3634 if (DevRowIdx == (uint64_t)-1)
3635 return;
3636
3637 bool bHandledNotification = false;
3638 float temp = 0;
3639 if (pResponse->HUM.subtype == sTypeHUM1)
3640 {
3641 //check if we already had a humidity for this device, if so, keep it!
3642 char szTmp[300];
3643 std::vector<std::vector<std::string> > result;
3644
3645 result = m_sql.safe_query(
3646 "SELECT sValue FROM DeviceStatus WHERE (HardwareID=%d AND DeviceID='%q' AND Unit=%d AND Type=%d AND SubType=%d)",
3647 pHardware->m_HwdID, ID.c_str(), 0, pTypeTEMP, sTypeTEMP5);
3648 if (result.size() == 1)
3649 {
3650 temp = static_cast<float>(atof(result[0][0].c_str()));
3651 float AddjValue = 0.0f;
3652 float AddjMulti = 1.0f;
3653 m_sql.GetAddjustment(pHardware->m_HwdID, ID.c_str(), 2, pTypeTEMP_HUM, sTypeTH_LC_TC, AddjValue, AddjMulti);
3654 temp += AddjValue;
3655 sprintf(szTmp, "%.1f;%d;%d", temp, humidity, pResponse->HUM.humidity_status);
3656 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), 2, pTypeTEMP_HUM, sTypeTH_LC_TC, SignalLevel, BatteryLevel, 0, szTmp, procResult.DeviceName);
3657 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, pTypeTEMP_HUM, sTypeTH_LC_TC, subType, szTmp);
3658 bHandledNotification = true;
3659 }
3660 }
3661 if (!bHandledNotification)
3662 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, (const int)humidity);
3663
3664 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
3665 {
3666 WriteMessageStart();
3667 switch (pResponse->HUM.subtype)
3668 {
3669 case sTypeHUM1:
3670 WriteMessage("subtype = HUM1 - LaCrosse TX3");
3671 break;
3672 case sTypeHUM2:
3673 WriteMessage("subtype = HUM2 - LaCrosse WS2300");
3674 break;
3675 default:
3676 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->HUM.packettype, pResponse->HUM.subtype);
3677 WriteMessage(szTmp);
3678 break;
3679 }
3680
3681 sprintf(szTmp, "Sequence nbr = %d", pResponse->HUM.seqnbr);
3682 WriteMessage(szTmp);
3683 sprintf(szTmp, "ID = %d", (pResponse->HUM.id1 * 256) + pResponse->HUM.id2);
3684 WriteMessage(szTmp);
3685
3686 sprintf(szTmp, "Humidity = %d %%", pResponse->HUM.humidity);
3687 WriteMessage(szTmp);
3688
3689 switch (pResponse->HUM.humidity_status)
3690 {
3691 case humstat_normal:
3692 WriteMessage("Status = Normal");
3693 break;
3694 case humstat_comfort:
3695 WriteMessage("Status = Comfortable");
3696 break;
3697 case humstat_dry:
3698 WriteMessage("Status = Dry");
3699 break;
3700 case humstat_wet:
3701 WriteMessage("Status = Wet");
3702 break;
3703 }
3704
3705 sprintf(szTmp, "Signal level = %d", pResponse->HUM.rssi);
3706 WriteMessage(szTmp);
3707
3708 if ((pResponse->HUM.battery_level & 0x0F) == 0)
3709 WriteMessage("Battery = Low");
3710 else
3711 WriteMessage("Battery = OK");
3712 WriteMessageEnd();
3713 }
3714 procResult.DeviceRowIdx = DevRowIdx;
3715 }
3716
decode_TempHum(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)3717 void MainWorker::decode_TempHum(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
3718 {
3719 char szTmp[100];
3720 uint8_t devType = pTypeTEMP_HUM;
3721 uint8_t subType = pResponse->TEMP_HUM.subtype;
3722 std::string ID;
3723 sprintf(szTmp, "%d", (pResponse->TEMP_HUM.id1 * 256) + pResponse->TEMP_HUM.id2);
3724 ID = szTmp;
3725 uint8_t Unit = 0;
3726
3727 uint8_t cmnd = 0;
3728 uint8_t SignalLevel = pResponse->TEMP_HUM.rssi;
3729 uint8_t BatteryLevel = get_BateryLevel(pHardware->HwdType, pResponse->TEMP_HUM.subtype == sTypeTH8, pResponse->TEMP_HUM.battery_level);
3730
3731 //Get Channel(Unit)
3732 switch (pResponse->TEMP_HUM.subtype)
3733 {
3734 case sTypeTH1:
3735 case sTypeTH2:
3736 case sTypeTH3:
3737 case sTypeTH4:
3738 case sTypeTH6:
3739 case sTypeTH8:
3740 case sTypeTH10:
3741 case sTypeTH11:
3742 case sTypeTH12:
3743 case sTypeTH13:
3744 case sTypeTH14:
3745 Unit = pResponse->TEMP_HUM.id2;
3746 break;
3747 case sTypeTH5:
3748 case sTypeTH9:
3749 //no channel
3750 break;
3751 case sTypeTH7:
3752 if (pResponse->TEMP_HUM.id1 < 0x40)
3753 Unit = 1;
3754 else if (pResponse->TEMP_HUM.id1 < 0x60)
3755 Unit = 2;
3756 else if (pResponse->TEMP_HUM.id1 < 0x80)
3757 Unit = 3;
3758 else if ((pResponse->TEMP_HUM.id1 > 0x9F) && (pResponse->TEMP_HUM.id1 < 0xC0))
3759 Unit = 4;
3760 else if (pResponse->TEMP_HUM.id1 < 0xE0)
3761 Unit = 5;
3762 break;
3763 }
3764
3765 float temp;
3766 if (!pResponse->TEMP_HUM.tempsign)
3767 {
3768 temp = float((pResponse->TEMP_HUM.temperatureh * 256) + pResponse->TEMP_HUM.temperaturel) / 10.0f;
3769 }
3770 else
3771 {
3772 temp = -(float(((pResponse->TEMP_HUM.temperatureh & 0x7F) * 256) + pResponse->TEMP_HUM.temperaturel) / 10.0f);
3773 }
3774 if ((temp < -200) || (temp > 380))
3775 {
3776 WriteMessage(" Invalid Temperature");
3777 return;
3778 }
3779
3780 float AddjValue = 0.0f;
3781 float AddjMulti = 1.0f;
3782 m_sql.GetAddjustment(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, AddjValue, AddjMulti);
3783 temp += AddjValue;
3784
3785 int Humidity = (int)pResponse->TEMP_HUM.humidity;
3786 uint8_t HumidityStatus = pResponse->TEMP_HUM.humidity_status;
3787
3788 if (Humidity > 100)
3789 {
3790 WriteMessage(" Invalid Humidity");
3791 return;
3792 }
3793 /*
3794 AddjValue=0.0f;
3795 AddjMulti=1.0f;
3796 m_sql.GetAddjustment2(pHardware->m_HwdID, ID.c_str(),Unit,devType,subType,AddjValue,AddjMulti);
3797 Humidity+=int(AddjValue);
3798 if (Humidity>100)
3799 Humidity=100;
3800 if (Humidity<0)
3801 Humidity=0;
3802 */
3803 sprintf(szTmp, "%.1f;%d;%d", temp, Humidity, HumidityStatus);
3804 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
3805 if (DevRowIdx == (uint64_t)-1)
3806 return;
3807
3808 uint64_t tID = ((uint64_t)(pHardware->m_HwdID & 0x7FFFFFFF) << 32) | (DevRowIdx & 0x7FFFFFFF);
3809 m_trend_calculator[tID].AddValueAndReturnTendency(static_cast<double>(temp), _tTrendCalculator::TAVERAGE_TEMP);
3810
3811 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, cmnd, szTmp);
3812
3813 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
3814 {
3815 WriteMessageStart();
3816 switch (pResponse->TEMP_HUM.subtype)
3817 {
3818 case sTypeTH1:
3819 WriteMessage("subtype = TH1 - THGN122/123/132,THGR122/228/238/268");
3820 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM.id2);
3821 WriteMessage(szTmp);
3822 break;
3823 case sTypeTH2:
3824 WriteMessage("subtype = TH2 - THGR810,THGN800");
3825 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM.id2);
3826 WriteMessage(szTmp);
3827 break;
3828 case sTypeTH3:
3829 WriteMessage("subtype = TH3 - RTGR328");
3830 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM.id2);
3831 WriteMessage(szTmp);
3832 break;
3833 case sTypeTH4:
3834 WriteMessage("subtype = TH4 - THGR328");
3835 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM.id2);
3836 WriteMessage(szTmp);
3837 break;
3838 case sTypeTH5:
3839 WriteMessage("subtype = TH5 - WTGR800");
3840 break;
3841 case sTypeTH6:
3842 WriteMessage("subtype = TH6 - THGR918/928,THGRN228,THGN500");
3843 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM.id2);
3844 WriteMessage(szTmp);
3845 break;
3846 case sTypeTH7:
3847 WriteMessage("subtype = TH7 - Cresta, TFA TS34C");
3848 if (pResponse->TEMP_HUM.id1 < 0x40)
3849 WriteMessage(" channel 1");
3850 else if (pResponse->TEMP_HUM.id1 < 0x60)
3851 WriteMessage(" channel 2");
3852 else if (pResponse->TEMP_HUM.id1 < 0x80)
3853 WriteMessage(" channel 3");
3854 else if ((pResponse->TEMP_HUM.id1 > 0x9F) && (pResponse->TEMP_HUM.id1 < 0xC0))
3855 WriteMessage(" channel 4");
3856 else if (pResponse->TEMP_HUM.id1 < 0xE0)
3857 WriteMessage(" channel 5");
3858 else
3859 WriteMessage(" channel ??");
3860 break;
3861 case sTypeTH8:
3862 WriteMessage("subtype = TH8 - WT260,WT260H,WT440H,WT450,WT450H");
3863 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM.id2);
3864 WriteMessage(szTmp);
3865 break;
3866 case sTypeTH9:
3867 WriteMessage("subtype = TH9 - Viking 02038, 02035 (02035 has no humidity), TSS320");
3868 break;
3869 case sTypeTH10:
3870 WriteMessage("subtype = TH10 - Rubicson/IW008T/TX95");
3871 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM.id2);
3872 WriteMessage(szTmp);
3873 break;
3874 case sTypeTH11:
3875 WriteMessage("subtype = TH11 - Oregon EW109");
3876 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM.id2);
3877 WriteMessage(szTmp);
3878 break;
3879 case sTypeTH12:
3880 WriteMessage("subtype = TH12 - Imagintronix/Opus TX300");
3881 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM.id2);
3882 WriteMessage(szTmp);
3883 break;
3884 case sTypeTH13:
3885 WriteMessage("subtype = TH13 - Alecto WS1700 and compatibles");
3886 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM.id2);
3887 WriteMessage(szTmp);
3888 break;
3889 case sTypeTH14:
3890 WriteMessage("subtype = TH14 - Alecto");
3891 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM.id2);
3892 WriteMessage(szTmp);
3893 break;
3894 default:
3895 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->TEMP_HUM.packettype, pResponse->TEMP_HUM.subtype);
3896 WriteMessage(szTmp);
3897 break;
3898 }
3899
3900 sprintf(szTmp, "Sequence nbr = %d", pResponse->TEMP_HUM.seqnbr);
3901 WriteMessage(szTmp);
3902 sprintf(szTmp, "ID = %s", ID.c_str());
3903 WriteMessage(szTmp);
3904
3905 double tvalue = ConvertTemperature(temp, m_sql.m_tempsign[0]);
3906 sprintf(szTmp, "Temperature = %.1f C", tvalue);
3907 WriteMessage(szTmp);
3908 sprintf(szTmp, "Humidity = %d %%", Humidity);
3909 WriteMessage(szTmp);
3910
3911 switch (pResponse->TEMP_HUM.humidity_status)
3912 {
3913 case humstat_normal:
3914 WriteMessage("Status = Normal");
3915 break;
3916 case humstat_comfort:
3917 WriteMessage("Status = Comfortable");
3918 break;
3919 case humstat_dry:
3920 WriteMessage("Status = Dry");
3921 break;
3922 case humstat_wet:
3923 WriteMessage("Status = Wet");
3924 break;
3925 }
3926
3927 sprintf(szTmp, "Signal level = %d", pResponse->TEMP_HUM.rssi);
3928 WriteMessage(szTmp);
3929
3930 decode_BateryLevel(pResponse->TEMP_HUM.subtype == sTypeTH8, pResponse->TEMP_HUM.battery_level);
3931 WriteMessageEnd();
3932 }
3933 procResult.DeviceRowIdx = DevRowIdx;
3934 }
3935
decode_TempHumBaro(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)3936 void MainWorker::decode_TempHumBaro(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
3937 {
3938 char szTmp[100];
3939 uint8_t devType = pTypeTEMP_HUM_BARO;
3940 uint8_t subType = pResponse->TEMP_HUM_BARO.subtype;
3941 sprintf(szTmp, "%d", (pResponse->TEMP_HUM_BARO.id1 * 256) + pResponse->TEMP_HUM_BARO.id2);
3942 std::string ID = szTmp;
3943 uint8_t Unit = pResponse->TEMP_HUM_BARO.id2;
3944 uint8_t cmnd = 0;
3945 uint8_t SignalLevel = pResponse->TEMP_HUM_BARO.rssi;
3946 uint8_t BatteryLevel;
3947 if ((pResponse->TEMP_HUM_BARO.battery_level & 0x0F) == 0)
3948 BatteryLevel = 0;
3949 else
3950 BatteryLevel = 100;
3951 //Override battery level if hardware supports it
3952 if (pHardware->HwdType == HTYPE_OpenZWave)
3953 {
3954 BatteryLevel = pResponse->TEMP.battery_level;
3955 }
3956
3957 float temp;
3958 if (!pResponse->TEMP_HUM_BARO.tempsign)
3959 {
3960 temp = float((pResponse->TEMP_HUM_BARO.temperatureh * 256) + pResponse->TEMP_HUM_BARO.temperaturel) / 10.0f;
3961 }
3962 else
3963 {
3964 temp = -(float(((pResponse->TEMP_HUM_BARO.temperatureh & 0x7F) * 256) + pResponse->TEMP_HUM_BARO.temperaturel) / 10.0f);
3965 }
3966 if ((temp < -200) || (temp > 380))
3967 {
3968 WriteMessage(" Invalid Temperature");
3969 return;
3970 }
3971
3972 float AddjValue = 0.0f;
3973 float AddjMulti = 1.0f;
3974 m_sql.GetAddjustment(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, AddjValue, AddjMulti);
3975 temp += AddjValue;
3976
3977 uint8_t Humidity = pResponse->TEMP_HUM_BARO.humidity;
3978 uint8_t HumidityStatus = pResponse->TEMP_HUM_BARO.humidity_status;
3979
3980 if (Humidity > 100)
3981 {
3982 WriteMessage(" Invalid Humidity");
3983 return;
3984 }
3985
3986 int barometer = (pResponse->TEMP_HUM_BARO.baroh * 256) + pResponse->TEMP_HUM_BARO.barol;
3987
3988 int forcast = pResponse->TEMP_HUM_BARO.forecast;
3989 float fbarometer = (float)barometer;
3990
3991 m_sql.GetAddjustment2(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, AddjValue, AddjMulti);
3992 barometer += int(AddjValue);
3993
3994 if (pResponse->TEMP_HUM_BARO.subtype == sTypeTHBFloat)
3995 {
3996 if ((barometer < 8000) || (barometer > 12000))
3997 {
3998 WriteMessage(" Invalid Barometer");
3999 return;
4000 }
4001 fbarometer = float((pResponse->TEMP_HUM_BARO.baroh * 256) + pResponse->TEMP_HUM_BARO.barol) / 10.0f;
4002 fbarometer += AddjValue;
4003 sprintf(szTmp, "%.1f;%d;%d;%.1f;%d", temp, Humidity, HumidityStatus, fbarometer, forcast);
4004 }
4005 else
4006 {
4007 if ((barometer < 800) || (barometer > 1200))
4008 {
4009 WriteMessage(" Invalid Barometer");
4010 return;
4011 }
4012 sprintf(szTmp, "%.1f;%d;%d;%d;%d", temp, Humidity, HumidityStatus, barometer, forcast);
4013 }
4014 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
4015 if (DevRowIdx == (uint64_t)-1)
4016 return;
4017
4018 uint64_t tID = ((uint64_t)(pHardware->m_HwdID & 0x7FFFFFFF) << 32) | (DevRowIdx & 0x7FFFFFFF);
4019 m_trend_calculator[tID].AddValueAndReturnTendency(static_cast<double>(temp), _tTrendCalculator::TAVERAGE_TEMP);
4020
4021 //calculate Altitude
4022 //float seaLevelPressure=101325.0f;
4023 //float altitude = 44330.0f * (1.0f - pow(fbarometer / seaLevelPressure, 0.1903f));
4024
4025 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, cmnd, szTmp);
4026
4027 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
4028 {
4029 WriteMessageStart();
4030 switch (pResponse->TEMP_HUM_BARO.subtype)
4031 {
4032 case sTypeTHB1:
4033 WriteMessage("subtype = THB1 - BTHR918, BTHGN129");
4034 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM_BARO.id2);
4035 WriteMessage(szTmp);
4036 break;
4037 case sTypeTHB2:
4038 WriteMessage("subtype = THB2 - BTHR918N, BTHR968");
4039 sprintf(szTmp, " channel %d", pResponse->TEMP_HUM_BARO.id2);
4040 WriteMessage(szTmp);
4041 break;
4042 case sTypeTHBFloat:
4043 WriteMessage("subtype = Weather Station");
4044 break;
4045 default:
4046 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->TEMP_HUM_BARO.packettype, pResponse->TEMP_HUM_BARO.subtype);
4047 WriteMessage(szTmp);
4048 break;
4049 }
4050
4051 sprintf(szTmp, "Sequence nbr = %d", pResponse->TEMP_HUM_BARO.seqnbr);
4052 WriteMessage(szTmp);
4053
4054 sprintf(szTmp, "ID = %d", (pResponse->TEMP_HUM_BARO.id1 * 256) + pResponse->TEMP_HUM_BARO.id2);
4055 WriteMessage(szTmp);
4056
4057 double tvalue = ConvertTemperature(temp, m_sql.m_tempsign[0]);
4058 sprintf(szTmp, "Temperature = %.1f C", tvalue);
4059 WriteMessage(szTmp);
4060
4061 sprintf(szTmp, "Humidity = %d %%", pResponse->TEMP_HUM_BARO.humidity);
4062 WriteMessage(szTmp);
4063
4064 switch (pResponse->TEMP_HUM_BARO.humidity_status)
4065 {
4066 case humstat_normal:
4067 WriteMessage("Status = Normal");
4068 break;
4069 case humstat_comfort:
4070 WriteMessage("Status = Comfortable");
4071 break;
4072 case humstat_dry:
4073 WriteMessage("Status = Dry");
4074 break;
4075 case humstat_wet:
4076 WriteMessage("Status = Wet");
4077 break;
4078 }
4079
4080 if (pResponse->TEMP_HUM_BARO.subtype == sTypeTHBFloat)
4081 sprintf(szTmp, "Barometer = %.1f hPa", float((pResponse->TEMP_HUM_BARO.baroh * 256) + pResponse->TEMP_HUM_BARO.barol) / 10.0f);
4082 else
4083 sprintf(szTmp, "Barometer = %d hPa", (pResponse->TEMP_HUM_BARO.baroh * 256) + pResponse->TEMP_HUM_BARO.barol);
4084 WriteMessage(szTmp);
4085
4086 switch (pResponse->TEMP_HUM_BARO.forecast)
4087 {
4088 case baroForecastNoInfo:
4089 WriteMessage("Forecast = No information available");
4090 break;
4091 case baroForecastSunny:
4092 WriteMessage("Forecast = Sunny");
4093 break;
4094 case baroForecastPartlyCloudy:
4095 WriteMessage("Forecast = Partly Cloudy");
4096 break;
4097 case baroForecastCloudy:
4098 WriteMessage("Forecast = Cloudy");
4099 break;
4100 case baroForecastRain:
4101 WriteMessage("Forecast = Rain");
4102 break;
4103 }
4104
4105 sprintf(szTmp, "Signal level = %d", pResponse->TEMP_HUM_BARO.rssi);
4106 WriteMessage(szTmp);
4107
4108 if ((pResponse->TEMP_HUM_BARO.battery_level & 0x0F) == 0)
4109 WriteMessage("Battery = Low");
4110 else
4111 WriteMessage("Battery = OK");
4112 WriteMessageEnd();
4113 }
4114 procResult.DeviceRowIdx = DevRowIdx;
4115 }
4116
decode_TempBaro(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)4117 void MainWorker::decode_TempBaro(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
4118 {
4119 char szTmp[100];
4120 uint8_t devType = pTypeTEMP_BARO;
4121 uint8_t subType = sTypeBMP085;
4122 _tTempBaro* pTempBaro = (_tTempBaro*)pResponse;
4123
4124 sprintf(szTmp, "%d", pTempBaro->id1);
4125 std::string ID = szTmp;
4126 uint8_t Unit = 1;
4127 uint8_t cmnd = 0;
4128 uint8_t SignalLevel = 12;
4129 uint8_t BatteryLevel;
4130 BatteryLevel = 100;
4131
4132 float temp = pTempBaro->temp;
4133 if ((temp < -200) || (temp > 380))
4134 {
4135 WriteMessage(" Invalid Temperature");
4136 return;
4137 }
4138
4139 float AddjValue = 0.0f;
4140 float AddjMulti = 1.0f;
4141 m_sql.GetAddjustment(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, AddjValue, AddjMulti);
4142 temp += AddjValue;
4143
4144 float fbarometer = pTempBaro->baro;
4145 int forcast = pTempBaro->forecast;
4146 m_sql.GetAddjustment2(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, AddjValue, AddjMulti);
4147 fbarometer += AddjValue;
4148
4149 sprintf(szTmp, "%.1f;%.1f;%d;%.2f", temp, fbarometer, forcast, pTempBaro->altitude);
4150 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
4151 if (DevRowIdx == (uint64_t)-1)
4152 return;
4153
4154 uint64_t tID = ((uint64_t)(pHardware->m_HwdID & 0x7FFFFFFF) << 32) | (DevRowIdx & 0x7FFFFFFF);
4155 m_trend_calculator[tID].AddValueAndReturnTendency(static_cast<double>(temp), _tTrendCalculator::TAVERAGE_TEMP);
4156
4157 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, cmnd, szTmp);
4158
4159 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
4160 {
4161 WriteMessageStart();
4162 switch (pResponse->TEMP_HUM_BARO.subtype)
4163 {
4164 case sTypeBMP085:
4165 WriteMessage("subtype = BMP085 I2C");
4166 sprintf(szTmp, " channel %d", pTempBaro->id1);
4167 WriteMessage(szTmp);
4168 break;
4169 default:
4170 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", devType, subType);
4171 WriteMessage(szTmp);
4172 break;
4173 }
4174
4175 sprintf(szTmp, "Temperature = %.1f C", temp);
4176 WriteMessage(szTmp);
4177
4178 sprintf(szTmp, "Barometer = %.1f hPa", fbarometer);
4179 WriteMessage(szTmp);
4180
4181 switch (pTempBaro->forecast)
4182 {
4183 case baroForecastNoInfo:
4184 WriteMessage("Forecast = No information available");
4185 break;
4186 case baroForecastSunny:
4187 WriteMessage("Forecast = Sunny");
4188 break;
4189 case baroForecastPartlyCloudy:
4190 WriteMessage("Forecast = Partly Cloudy");
4191 break;
4192 case baroForecastCloudy:
4193 WriteMessage("Forecast = Cloudy");
4194 break;
4195 case baroForecastRain:
4196 WriteMessage("Forecast = Rain");
4197 break;
4198 }
4199
4200 if (pResponse->TEMP_HUM_BARO.subtype == sTypeBMP085)
4201 {
4202 sprintf(szTmp, "Altitude = %.2f meter", pTempBaro->altitude);
4203 WriteMessage(szTmp);
4204 }
4205 WriteMessageEnd();
4206 }
4207 procResult.DeviceRowIdx = DevRowIdx;
4208 }
4209
decode_TempRain(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)4210 void MainWorker::decode_TempRain(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
4211 {
4212 char szTmp[100];
4213
4214 //We are (also) going to split this device into two separate sensors (temp + rain)
4215
4216 uint8_t devType = pTypeTEMP_RAIN;
4217 uint8_t subType = pResponse->TEMP_RAIN.subtype;
4218
4219 sprintf(szTmp, "%d", (pResponse->TEMP_RAIN.id1 * 256) + pResponse->TEMP_RAIN.id2);
4220 std::string ID = szTmp;
4221 int Unit = pResponse->TEMP_RAIN.id2;
4222 int cmnd = 0;
4223
4224 uint8_t SignalLevel = pResponse->TEMP_RAIN.rssi;
4225 uint8_t BatteryLevel = 0;
4226 if ((pResponse->TEMP_RAIN.battery_level & 0x0F) == 0)
4227 BatteryLevel = 0;
4228 else
4229 BatteryLevel = 100;
4230
4231 float temp;
4232 if (!pResponse->TEMP_RAIN.tempsign)
4233 {
4234 temp = float((pResponse->TEMP_RAIN.temperatureh * 256) + pResponse->TEMP_RAIN.temperaturel) / 10.0f;
4235 }
4236 else
4237 {
4238 temp = -(float(((pResponse->TEMP_RAIN.temperatureh & 0x7F) * 256) + pResponse->TEMP_RAIN.temperaturel) / 10.0f);
4239 }
4240
4241 float AddjValue = 0.0f;
4242 float AddjMulti = 1.0f;
4243 m_sql.GetAddjustment(pHardware->m_HwdID, ID.c_str(), Unit, pTypeTEMP, sTypeTEMP3, AddjValue, AddjMulti);
4244 temp += AddjValue;
4245
4246 if ((temp < -200) || (temp > 380))
4247 {
4248 WriteMessage(" Invalid Temperature");
4249 return;
4250 }
4251 float TotalRain = float((pResponse->TEMP_RAIN.raintotal1 * 256) + pResponse->TEMP_RAIN.raintotal2) / 10.0f;
4252
4253 sprintf(szTmp, "%.1f;%.1f", temp, TotalRain);
4254 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
4255 if (DevRowIdx == (uint64_t)-1)
4256 return;
4257
4258 uint64_t tID = ((uint64_t)(pHardware->m_HwdID & 0x7FFFFFFF) << 32) | (DevRowIdx & 0x7FFFFFFF);
4259 m_trend_calculator[tID].AddValueAndReturnTendency(static_cast<double>(temp), _tTrendCalculator::TAVERAGE_TEMP);
4260
4261 sprintf(szTmp, "%.1f", temp);
4262 uint64_t DevRowIdxTemp = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, pTypeTEMP, sTypeTEMP3, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
4263 m_notifications.CheckAndHandleNotification(DevRowIdxTemp, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, pTypeTEMP, sTypeTEMP3, temp);
4264
4265 sprintf(szTmp, "%d;%.1f", 0, TotalRain);
4266 uint64_t DevRowIdxRain = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, pTypeRAIN, sTypeRAIN3, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
4267 m_notifications.CheckAndHandleNotification(DevRowIdxRain, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, pTypeRAIN, sTypeRAIN3, cmnd, szTmp);
4268
4269 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
4270 {
4271 WriteMessageStart();
4272 switch (pResponse->TEMP_RAIN.subtype)
4273 {
4274 case sTypeTR1:
4275 WriteMessage("Subtype = Alecto WS1200");
4276 break;
4277 }
4278 sprintf(szTmp, "Sequence nbr = %d", pResponse->TEMP_RAIN.seqnbr);
4279 WriteMessage(szTmp);
4280 sprintf(szTmp, "ID = %d", (pResponse->TEMP_RAIN.id1 * 256) + pResponse->TEMP_RAIN.id2);
4281 WriteMessage(szTmp);
4282
4283 sprintf(szTmp, "Temperature = %.1f C", temp);
4284 WriteMessage(szTmp);
4285 sprintf(szTmp, "Total Rain = %.1f mm", TotalRain);
4286 WriteMessage(szTmp);
4287
4288 sprintf(szTmp, "Signal level = %d", pResponse->TEMP_RAIN.rssi);
4289 WriteMessage(szTmp);
4290
4291 if ((pResponse->TEMP_RAIN.battery_level & 0x0F) == 0)
4292 WriteMessage("Battery = Low");
4293 else
4294 WriteMessage("Battery = OK");
4295 WriteMessageEnd();
4296 }
4297
4298 procResult.DeviceRowIdx = DevRowIdx;
4299 }
4300
decode_UV(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)4301 void MainWorker::decode_UV(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
4302 {
4303 char szTmp[100];
4304 uint8_t devType = pTypeUV;
4305 uint8_t subType = pResponse->UV.subtype;
4306 std::string ID;
4307 sprintf(szTmp, "%d", (pResponse->UV.id1 * 256) + pResponse->UV.id2);
4308 ID = szTmp;
4309 uint8_t Unit = 0;
4310 uint8_t cmnd = 0;
4311 uint8_t SignalLevel = pResponse->UV.rssi;
4312 uint8_t BatteryLevel;
4313 if ((pResponse->UV.battery_level & 0x0F) == 0)
4314 BatteryLevel = 0;
4315 else
4316 BatteryLevel = 100;
4317 float Level = float(pResponse->UV.uv) / 10.0f;
4318 if (Level > 30)
4319 {
4320 WriteMessage(" Invalid UV");
4321 return;
4322 }
4323 float temp = 0;
4324 if (pResponse->UV.subtype == sTypeUV3)
4325 {
4326 if (!pResponse->UV.tempsign)
4327 {
4328 temp = float((pResponse->UV.temperatureh * 256) + pResponse->UV.temperaturel) / 10.0f;
4329 }
4330 else
4331 {
4332 temp = -(float(((pResponse->UV.temperatureh & 0x7F) * 256) + pResponse->UV.temperaturel) / 10.0f);
4333 }
4334 if ((temp < -200) || (temp > 380))
4335 {
4336 WriteMessage(" Invalid Temperature");
4337 return;
4338 }
4339
4340 float AddjValue = 0.0f;
4341 float AddjMulti = 1.0f;
4342 m_sql.GetAddjustment(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, AddjValue, AddjMulti);
4343 temp += AddjValue;
4344 }
4345
4346 sprintf(szTmp, "%.1f;%.1f", Level, temp);
4347 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
4348 if (DevRowIdx == (uint64_t)-1)
4349 return;
4350
4351 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, cmnd, szTmp);
4352
4353 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
4354 {
4355 WriteMessageStart();
4356 switch (pResponse->UV.subtype)
4357 {
4358 case sTypeUV1:
4359 WriteMessage("Subtype = UV1 - UVN128, UV138");
4360 break;
4361 case sTypeUV2:
4362 WriteMessage("Subtype = UV2 - UVN800");
4363 break;
4364 case sTypeUV3:
4365 WriteMessage("Subtype = UV3 - TFA");
4366 break;
4367 default:
4368 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->UV.packettype, pResponse->UV.subtype);
4369 WriteMessage(szTmp);
4370 break;
4371 }
4372
4373 sprintf(szTmp, "Sequence nbr = %d", pResponse->UV.seqnbr);
4374 WriteMessage(szTmp);
4375 sprintf(szTmp, "ID = %d", (pResponse->UV.id1 * 256) + pResponse->UV.id2);
4376 WriteMessage(szTmp);
4377
4378 sprintf(szTmp, "Level = %.1f UVI", Level);
4379 WriteMessage(szTmp);
4380
4381 if (pResponse->UV.subtype == sTypeUV3)
4382 {
4383 sprintf(szTmp, "Temperature = %.1f C", temp);
4384 WriteMessage(szTmp);
4385 }
4386
4387 if (pResponse->UV.uv < 3)
4388 WriteMessage("Description = Low");
4389 else if (pResponse->UV.uv < 6)
4390 WriteMessage("Description = Medium");
4391 else if (pResponse->UV.uv < 8)
4392 WriteMessage("Description = High");
4393 else if (pResponse->UV.uv < 11)
4394 WriteMessage("Description = Very high");
4395 else
4396 WriteMessage("Description = Dangerous");
4397
4398 sprintf(szTmp, "Signal level = %d", pResponse->UV.rssi);
4399 WriteMessage(szTmp);
4400
4401 if ((pResponse->UV.battery_level & 0x0F) == 0)
4402 WriteMessage("Battery = Low");
4403 else
4404 WriteMessage("Battery = OK");
4405 WriteMessageEnd();
4406 }
4407 procResult.DeviceRowIdx = DevRowIdx;
4408 }
4409
decode_FS20(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)4410 void MainWorker::decode_FS20(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
4411 {
4412 //uint8_t devType=pTypeFS20;
4413
4414 char szTmp[100];
4415 uint8_t devType = pTypeFS20;
4416 uint8_t subType = pResponse->FS20.subtype;
4417
4418 sprintf(szTmp, "%02X%02X", pResponse->FS20.hc1, pResponse->FS20.hc2);
4419 std::string ID = szTmp;
4420
4421 uint8_t Unit = pResponse->FS20.addr;
4422 uint8_t cmnd = pResponse->FS20.cmd1;
4423 uint8_t SignalLevel = pResponse->FS20.rssi;
4424
4425 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, procResult.DeviceName);
4426 if (DevRowIdx == (uint64_t)-1)
4427 return;
4428 CheckSceneCode(DevRowIdx, devType, subType, cmnd, "", procResult.DeviceName);
4429
4430 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
4431 {
4432 WriteMessageStart();
4433 switch (pResponse->FS20.subtype)
4434 {
4435 case sTypeFS20:
4436 WriteMessage("subtype = FS20");
4437 sprintf(szTmp, "Sequence nbr = %d", pResponse->FS20.seqnbr);
4438 WriteMessage(szTmp);
4439 sprintf(szTmp, "House code = %02X%02X", pResponse->FS20.hc1, pResponse->FS20.hc2);
4440 WriteMessage(szTmp);
4441 sprintf(szTmp, "Address = %02X", pResponse->FS20.addr);
4442 WriteMessage(szTmp);
4443
4444 WriteMessage("Cmd1 = ", false);
4445
4446 switch (pResponse->FS20.cmd1 & 0x1F)
4447 {
4448 case 0x0:
4449 WriteMessage("Off");
4450 break;
4451 case 0x1:
4452 WriteMessage("dim level 1 = 6.25%");
4453 break;
4454 case 0x2:
4455 WriteMessage("dim level 2 = 12.5%");
4456 break;
4457 case 0x3:
4458 WriteMessage("dim level 3 = 18.75%");
4459 break;
4460 case 0x4:
4461 WriteMessage("dim level 4 = 25%");
4462 break;
4463 case 0x5:
4464 WriteMessage("dim level 5 = 31.25%");
4465 break;
4466 case 0x6:
4467 WriteMessage("dim level 6 = 37.5%");
4468 break;
4469 case 0x7:
4470 WriteMessage("dim level 7 = 43.75%");
4471 break;
4472 case 0x8:
4473 WriteMessage("dim level 8 = 50%");
4474 break;
4475 case 0x9:
4476 WriteMessage("dim level 9 = 56.25%");
4477 break;
4478 case 0xA:
4479 WriteMessage("dim level 10 = 62.5%");
4480 break;
4481 case 0xB:
4482 WriteMessage("dim level 11 = 68.75%");
4483 break;
4484 case 0xC:
4485 WriteMessage("dim level 12 = 75%");
4486 break;
4487 case 0xD:
4488 WriteMessage("dim level 13 = 81.25%");
4489 break;
4490 case 0xE:
4491 WriteMessage("dim level 14 = 87.5%");
4492 break;
4493 case 0xF:
4494 WriteMessage("dim level 15 = 93.75%");
4495 break;
4496 case 0x10:
4497 WriteMessage("On (100%)");
4498 break;
4499 case 0x11:
4500 WriteMessage("On ( at last dim level set)");
4501 break;
4502 case 0x12:
4503 WriteMessage("Toggle between Off and On (last dim level set)");
4504 break;
4505 case 0x13:
4506 WriteMessage("Bright one step");
4507 break;
4508 case 0x14:
4509 WriteMessage("Dim one step");
4510 break;
4511 case 0x15:
4512 WriteMessage("Start dim cycle");
4513 break;
4514 case 0x16:
4515 WriteMessage("Program(Timer)");
4516 break;
4517 case 0x17:
4518 WriteMessage("Request status from a bidirectional device");
4519 break;
4520 case 0x18:
4521 WriteMessage("Off for timer period");
4522 break;
4523 case 0x19:
4524 WriteMessage("On (100%) for timer period");
4525 break;
4526 case 0x1A:
4527 WriteMessage("On ( at last dim level set) for timer period");
4528 break;
4529 case 0x1B:
4530 WriteMessage("Reset");
4531 break;
4532 default:
4533 sprintf(szTmp, "ERROR: Unknown command = %02X", pResponse->FS20.cmd1);
4534 WriteMessage(szTmp);
4535 break;
4536 }
4537
4538 if ((pResponse->FS20.cmd1 & 0x80) == 0)
4539 WriteMessage(" command to receiver");
4540 else
4541 WriteMessage(" response from receiver");
4542
4543 if ((pResponse->FS20.cmd1 & 0x40) == 0)
4544 WriteMessage(" unidirectional command");
4545 else
4546 WriteMessage(" bidirectional command");
4547
4548 if ((pResponse->FS20.cmd1 & 0x20) == 0)
4549 WriteMessage(" additional cmd2 byte not present");
4550 else
4551 WriteMessage(" additional cmd2 byte present");
4552
4553 if ((pResponse->FS20.cmd1 & 0x20) != 0)
4554 {
4555 sprintf(szTmp, "Cmd2 = %02X", pResponse->FS20.cmd2);
4556 WriteMessage(szTmp);
4557 }
4558 break;
4559 case sTypeFHT8V:
4560 WriteMessage("subtype = FHT 8V valve");
4561
4562 sprintf(szTmp, "Sequence nbr = %d", pResponse->FS20.seqnbr);
4563 WriteMessage(szTmp);
4564 sprintf(szTmp, "House code = %02X%02X", pResponse->FS20.hc1, pResponse->FS20.hc2);
4565 WriteMessage(szTmp);
4566 sprintf(szTmp, "Address = %02X", pResponse->FS20.addr);
4567 WriteMessage(szTmp);
4568
4569 WriteMessage("Cmd1 = ", false);
4570
4571 if ((pResponse->FS20.cmd1 & 0x80) == 0)
4572 WriteMessage("new command");
4573 else
4574 WriteMessage("repeated command");
4575
4576 if ((pResponse->FS20.cmd1 & 0x40) == 0)
4577 WriteMessage(" unidirectional command");
4578 else
4579 WriteMessage(" bidirectional command");
4580
4581 if ((pResponse->FS20.cmd1 & 0x20) == 0)
4582 WriteMessage(" additional cmd2 byte not present");
4583 else
4584 WriteMessage(" additional cmd2 byte present");
4585
4586 if ((pResponse->FS20.cmd1 & 0x10) == 0)
4587 WriteMessage(" battery empty beep not enabled");
4588 else
4589 WriteMessage(" enable battery empty beep");
4590
4591 switch (pResponse->FS20.cmd1 & 0xF)
4592 {
4593 case 0x0:
4594 WriteMessage(" Synchronize now");
4595 sprintf(szTmp, "Cmd2 = valve position: %02X is %.2f %%", pResponse->FS20.cmd2, float(pResponse->FS20.cmd2) / 2.55f);
4596 WriteMessage(szTmp);
4597 break;
4598 case 0x1:
4599 WriteMessage(" open valve");
4600 break;
4601 case 0x2:
4602 WriteMessage(" close valve");
4603 break;
4604 case 0x6:
4605 WriteMessage(" open valve at percentage level");
4606 sprintf(szTmp, "Cmd2 = valve position: %02X is %.2f %%", pResponse->FS20.cmd2, float(pResponse->FS20.cmd2) / 2.55f);
4607 WriteMessage(szTmp);
4608 break;
4609 case 0x8:
4610 WriteMessage(" relative offset (cmd2 bit 7=direction, bit 5-0 offset value)");
4611 break;
4612 case 0xA:
4613 WriteMessage(" decalcification cycle");
4614 sprintf(szTmp, "Cmd2 = valve position: %02X is %.2f %%", pResponse->FS20.cmd2, float(pResponse->FS20.cmd2) / 2.55f);
4615 WriteMessage(szTmp);
4616 break;
4617 case 0xC:
4618 WriteMessage(" synchronization active");
4619 sprintf(szTmp, "Cmd2 = count down is %d seconds", pResponse->FS20.cmd2 >> 1);
4620 WriteMessage(szTmp);
4621 break;
4622 case 0xE:
4623 WriteMessage(" test, drive valve and produce an audible signal");
4624 break;
4625 case 0xF:
4626 WriteMessage(" pair valve (cmd2 bit 7-1 is count down in seconds, bit 0=1)");
4627 sprintf(szTmp, "Cmd2 = count down is %d seconds", pResponse->FS20.cmd2 >> 1);
4628 WriteMessage(szTmp);
4629 break;
4630 default:
4631 sprintf(szTmp, "ERROR: Unknown command = %02X", pResponse->FS20.cmd1);
4632 WriteMessage(szTmp);
4633 break;
4634 }
4635 break;
4636 case sTypeFHT80:
4637 WriteMessage("subtype = FHT80 door/window sensor");
4638 sprintf(szTmp, "Sequence nbr = %d", pResponse->FS20.seqnbr);
4639 WriteMessage(szTmp);
4640 sprintf(szTmp, "House code = %02X%02X", pResponse->FS20.hc1, pResponse->FS20.hc2);
4641 WriteMessage(szTmp);
4642 sprintf(szTmp, "Address = %02X", pResponse->FS20.addr);
4643 WriteMessage(szTmp);
4644
4645 WriteMessage("Cmd1 = ", false);
4646
4647 switch (pResponse->FS20.cmd1 & 0xF)
4648 {
4649 case 0x1:
4650 WriteMessage("sensor opened");
4651 break;
4652 case 0x2:
4653 WriteMessage("sensor closed");
4654 break;
4655 case 0xC:
4656 WriteMessage("synchronization active");
4657 break;
4658 default:
4659 sprintf(szTmp, "ERROR: Unknown command = %02X", pResponse->FS20.cmd1);
4660 WriteMessage(szTmp);
4661 break;
4662 }
4663
4664 if ((pResponse->FS20.cmd1 & 0x80) == 0)
4665 WriteMessage(" new command");
4666 else
4667 WriteMessage(" repeated command");
4668 break;
4669 default:
4670 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->FS20.packettype, pResponse->FS20.subtype);
4671 WriteMessage(szTmp);
4672 break;
4673 }
4674 sprintf(szTmp, "Signal level = %d", pResponse->FS20.rssi);
4675 WriteMessage(szTmp);
4676 WriteMessageEnd();
4677 }
4678
4679 procResult.DeviceRowIdx = DevRowIdx;
4680 }
4681
decode_Lighting1(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)4682 void MainWorker::decode_Lighting1(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
4683 {
4684 char szTmp[100];
4685 uint8_t devType = pTypeLighting1;
4686 uint8_t subType = pResponse->LIGHTING1.subtype;
4687 sprintf(szTmp, "%d", pResponse->LIGHTING1.housecode);
4688 std::string ID = szTmp;
4689 uint8_t Unit = pResponse->LIGHTING1.unitcode;
4690 uint8_t cmnd = pResponse->LIGHTING1.cmnd;
4691 uint8_t SignalLevel = pResponse->LIGHTING1.rssi;
4692
4693 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, procResult.DeviceName);
4694 if (DevRowIdx == (uint64_t)-1)
4695 return;
4696 CheckSceneCode(DevRowIdx, devType, subType, cmnd, "", procResult.DeviceName);
4697
4698 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
4699 {
4700 WriteMessageStart();
4701 switch (pResponse->LIGHTING1.subtype)
4702 {
4703 case sTypeX10:
4704 WriteMessage("subtype = X10");
4705 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING1.seqnbr);
4706 WriteMessage(szTmp);
4707 sprintf(szTmp, "housecode = %c", pResponse->LIGHTING1.housecode);
4708 WriteMessage(szTmp);
4709 sprintf(szTmp, "unitcode = %d", pResponse->LIGHTING1.unitcode);
4710 WriteMessage(szTmp);
4711 WriteMessage("Command = ", false);
4712 switch (pResponse->LIGHTING1.cmnd)
4713 {
4714 case light1_sOff:
4715 WriteMessage("Off");
4716 break;
4717 case light1_sOn:
4718 WriteMessage("On");
4719 break;
4720 case light1_sDim:
4721 WriteMessage("Dim");
4722 break;
4723 case light1_sBright:
4724 WriteMessage("Bright");
4725 break;
4726 case light1_sAllOn:
4727 WriteMessage("All On");
4728 break;
4729 case light1_sAllOff:
4730 WriteMessage("All Off");
4731 break;
4732 default:
4733 WriteMessage("UNKNOWN");
4734 break;
4735 }
4736 break;
4737 case sTypeARC:
4738 WriteMessage("subtype = ARC");
4739 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING1.seqnbr);
4740 WriteMessage(szTmp);
4741 sprintf(szTmp, "housecode = %c", pResponse->LIGHTING1.housecode);
4742 WriteMessage(szTmp);
4743 sprintf(szTmp, "unitcode = %d", pResponse->LIGHTING1.unitcode);
4744 WriteMessage(szTmp);
4745 WriteMessage("Command = ", false);
4746 switch (pResponse->LIGHTING1.cmnd)
4747 {
4748 case light1_sOff:
4749 WriteMessage("Off");
4750 break;
4751 case light1_sOn:
4752 WriteMessage("On");
4753 break;
4754 case light1_sAllOn:
4755 WriteMessage("All On");
4756 break;
4757 case light1_sAllOff:
4758 WriteMessage("All Off");
4759 break;
4760 case light1_sChime:
4761 WriteMessage("Chime");
4762 break;
4763 default:
4764 WriteMessage("UNKNOWN");
4765 break;
4766 }
4767 break;
4768 case sTypeAB400D:
4769 case sTypeWaveman:
4770 case sTypeEMW200:
4771 case sTypeIMPULS:
4772 case sTypeRisingSun:
4773 case sTypeEnergenie:
4774 case sTypeEnergenie5:
4775 case sTypeGDR2:
4776 case sTypeHQ:
4777 case sTypeOase:
4778 //decoding of these types is only implemented for use by simulate and verbose
4779 //these types are not received by the RFXtrx433
4780 switch (pResponse->LIGHTING1.subtype)
4781 {
4782 case sTypeAB400D:
4783 WriteMessage("subtype = ELRO AB400");
4784 break;
4785 case sTypeWaveman:
4786 WriteMessage("subtype = Waveman");
4787 break;
4788 case sTypeEMW200:
4789 WriteMessage("subtype = EMW200");
4790 break;
4791 case sTypeIMPULS:
4792 WriteMessage("subtype = IMPULS");
4793 break;
4794 case sTypeRisingSun:
4795 WriteMessage("subtype = RisingSun");
4796 break;
4797 case sTypeEnergenie:
4798 WriteMessage("subtype = Energenie-ENER010");
4799 break;
4800 case sTypeEnergenie5:
4801 WriteMessage("subtype = Energenie 5-gang");
4802 break;
4803 case sTypeGDR2:
4804 WriteMessage("subtype = COCO GDR2");
4805 break;
4806 case sTypeHQ:
4807 WriteMessage("subtype = HQ COCO-20");
4808 break;
4809 case sTypeOase:
4810 WriteMessage("subtype = Oase Inscenio");
4811 break;
4812 }
4813 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING1.seqnbr);
4814 WriteMessage(szTmp);
4815 sprintf(szTmp, "housecode = %c", pResponse->LIGHTING1.housecode);
4816 WriteMessage(szTmp);
4817 sprintf(szTmp, "unitcode = %d", pResponse->LIGHTING1.unitcode);
4818 WriteMessage(szTmp);
4819 WriteMessage("Command = ", false);
4820
4821 switch (pResponse->LIGHTING1.cmnd)
4822 {
4823 case light1_sOff:
4824 WriteMessage("Off");
4825 break;
4826 case light1_sOn:
4827 WriteMessage("On");
4828 break;
4829 default:
4830 WriteMessage("UNKNOWN");
4831 break;
4832 }
4833 break;
4834 case sTypePhilips:
4835 //decoding of this type is only implemented for use by simulate and verbose
4836 //this type is not received by the RFXtrx433
4837 WriteMessage("subtype = Philips SBC");
4838 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING1.seqnbr);
4839 WriteMessage(szTmp);
4840 sprintf(szTmp, "housecode = %c", pResponse->LIGHTING1.housecode);
4841 WriteMessage(szTmp);
4842 sprintf(szTmp, "unitcode = %d", pResponse->LIGHTING1.unitcode);
4843 WriteMessage(szTmp);
4844 WriteMessage("Command = ", false);
4845
4846 switch (pResponse->LIGHTING1.cmnd)
4847 {
4848 case light1_sOff:
4849 WriteMessage("Off");
4850 break;
4851 case light1_sOn:
4852 WriteMessage("On");
4853 break;
4854 case light1_sAllOff:
4855 WriteMessage("All Off");
4856 break;
4857 case light1_sAllOn:
4858 WriteMessage("All On");
4859 break;
4860 default:
4861 WriteMessage("UNKNOWN");
4862 break;
4863 }
4864 break;
4865 default:
4866 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->LIGHTING1.packettype, pResponse->LIGHTING1.subtype);
4867 WriteMessage(szTmp);
4868 break;
4869 }
4870 sprintf(szTmp, "Signal level = %d", pResponse->LIGHTING1.rssi);
4871 WriteMessage(szTmp);
4872 WriteMessageEnd();
4873 }
4874 procResult.DeviceRowIdx = DevRowIdx;
4875 }
4876
decode_Lighting2(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)4877 void MainWorker::decode_Lighting2(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
4878 {
4879 char szTmp[100];
4880 uint8_t devType = pTypeLighting2;
4881 uint8_t subType = pResponse->LIGHTING2.subtype;
4882 sprintf(szTmp, "%X%02X%02X%02X", pResponse->LIGHTING2.id1, pResponse->LIGHTING2.id2, pResponse->LIGHTING2.id3, pResponse->LIGHTING2.id4);
4883 std::string ID = szTmp;
4884 uint8_t Unit = pResponse->LIGHTING2.unitcode;
4885 uint8_t cmnd = pResponse->LIGHTING2.cmnd;
4886 uint8_t level = pResponse->LIGHTING2.level;
4887 uint8_t SignalLevel = pResponse->LIGHTING2.rssi;
4888
4889 sprintf(szTmp, "%d", level);
4890 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, szTmp, procResult.DeviceName);
4891
4892 bool isGroupCommand = ((cmnd == light2_sGroupOff) || (cmnd == light2_sGroupOn));
4893 uint8_t single_cmnd = cmnd;
4894
4895 if (isGroupCommand)
4896 {
4897 single_cmnd = (cmnd == light2_sGroupOff) ? light2_sOff : light2_sOn;
4898
4899 // We write the GROUP_CMD into the log to differentiate between manual turn off/on and group_off/group_on
4900 m_sql.UpdateValueLighting2GroupCmd(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, szTmp, procResult.DeviceName);
4901
4902 //set the status of all lights with the same code to on/off
4903 m_sql.Lighting2GroupCmd(ID, subType, single_cmnd);
4904 }
4905
4906 if (DevRowIdx == (uint64_t)-1) {
4907 // not found nothing to do
4908 return;
4909 }
4910 CheckSceneCode(DevRowIdx, devType, subType, single_cmnd, szTmp, procResult.DeviceName);
4911
4912 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
4913 {
4914 WriteMessageStart();
4915 switch (pResponse->LIGHTING2.subtype)
4916 {
4917 case sTypeAC:
4918 case sTypeHEU:
4919 case sTypeANSLUT:
4920 switch (pResponse->LIGHTING2.subtype)
4921 {
4922 case sTypeAC:
4923 WriteMessage("subtype = AC");
4924 break;
4925 case sTypeHEU:
4926 WriteMessage("subtype = HomeEasy EU");
4927 break;
4928 case sTypeANSLUT:
4929 WriteMessage("subtype = ANSLUT");
4930 break;
4931 }
4932 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING2.seqnbr);
4933 WriteMessage(szTmp);
4934 sprintf(szTmp, "ID = %s", ID.c_str());
4935 WriteMessage(szTmp);
4936 sprintf(szTmp, "Unit = %d", Unit);
4937 WriteMessage(szTmp);
4938 WriteMessage("Command = ", false);
4939 switch (pResponse->LIGHTING2.cmnd)
4940 {
4941 case light2_sOff:
4942 WriteMessage("Off");
4943 break;
4944 case light2_sOn:
4945 WriteMessage("On");
4946 break;
4947 case light2_sSetLevel:
4948 sprintf(szTmp, "Set Level: %d", level);
4949 WriteMessage(szTmp);
4950 break;
4951 case light2_sGroupOff:
4952 WriteMessage("Group Off");
4953 break;
4954 case light2_sGroupOn:
4955 WriteMessage("Group On");
4956 break;
4957 case light2_sSetGroupLevel:
4958 sprintf(szTmp, "Set Group Level: %d", level);
4959 WriteMessage(szTmp);
4960 break;
4961 case gswitch_sStop:
4962 WriteMessage("Stop");
4963 break;
4964 default:
4965 WriteMessage("UNKNOWN");
4966 break;
4967 }
4968 break;
4969 default:
4970 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->LIGHTING2.packettype, pResponse->LIGHTING2.subtype);
4971 WriteMessage(szTmp);
4972 break;
4973 }
4974 WriteMessageEnd();
4975 }
4976 procResult.DeviceRowIdx = DevRowIdx;
4977 }
4978
4979 //not in dbase yet
decode_Lighting3(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)4980 void MainWorker::decode_Lighting3(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
4981 {
4982 WriteMessageStart();
4983 WriteMessage("");
4984
4985 char szTmp[100];
4986
4987 switch (pResponse->LIGHTING3.subtype)
4988 {
4989 case sTypeKoppla:
4990 WriteMessage("subtype = Ikea Koppla");
4991 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING3.seqnbr);
4992 WriteMessage(szTmp);
4993 WriteMessage("Command = ", false);
4994 switch (pResponse->LIGHTING3.cmnd)
4995 {
4996 case 0x0:
4997 WriteMessage("Off");
4998 break;
4999 case 0x1:
5000 WriteMessage("On");
5001 break;
5002 case 0x20:
5003 sprintf(szTmp, "Set Level: %d", pResponse->LIGHTING3.channel10_9);
5004 WriteMessage(szTmp);
5005 break;
5006 case 0x21:
5007 WriteMessage("Program");
5008 break;
5009 default:
5010 if ((pResponse->LIGHTING3.cmnd >= 0x10) && (pResponse->LIGHTING3.cmnd < 0x18))
5011 WriteMessage("Dim");
5012 else if ((pResponse->LIGHTING3.cmnd >= 0x18) && (pResponse->LIGHTING3.cmnd < 0x20))
5013 WriteMessage("Bright");
5014 else
5015 WriteMessage("UNKNOWN");
5016 break;
5017 }
5018 break;
5019 default:
5020 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->LIGHTING3.packettype, pResponse->LIGHTING3.subtype);
5021 WriteMessage(szTmp);
5022 break;
5023 }
5024 sprintf(szTmp, "Signal level = %d", pResponse->LIGHTING3.rssi);
5025 WriteMessage(szTmp);
5026 WriteMessageEnd();
5027 procResult.DeviceRowIdx = -1;
5028 }
5029
decode_Lighting4(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)5030 void MainWorker::decode_Lighting4(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
5031 {
5032 char szTmp[100];
5033 uint8_t devType = pTypeLighting4;
5034 uint8_t subType = pResponse->LIGHTING4.subtype;
5035 sprintf(szTmp, "%02X%02X%02X", pResponse->LIGHTING4.cmd1, pResponse->LIGHTING4.cmd2, pResponse->LIGHTING4.cmd3);
5036 std::string ID = szTmp;
5037 int Unit = 0;
5038 uint8_t cmnd = 1; //only 'On' supported
5039 uint8_t SignalLevel = pResponse->LIGHTING4.rssi;
5040 sprintf(szTmp, "%d", (pResponse->LIGHTING4.pulseHigh * 256) + pResponse->LIGHTING4.pulseLow);
5041 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, szTmp, procResult.DeviceName);
5042 if (DevRowIdx == (uint64_t)-1)
5043 return;
5044 CheckSceneCode(DevRowIdx, devType, subType, cmnd, szTmp, procResult.DeviceName);
5045
5046 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
5047 {
5048 WriteMessageStart();
5049 switch (pResponse->LIGHTING4.subtype)
5050 {
5051 case sTypePT2262:
5052 WriteMessage("subtype = PT2262");
5053 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING4.seqnbr);
5054 WriteMessage(szTmp);
5055 sprintf(szTmp, "Code = %02X%02X%02X", pResponse->LIGHTING4.cmd1, pResponse->LIGHTING4.cmd2, pResponse->LIGHTING4.cmd3);
5056 WriteMessage(szTmp);
5057
5058 WriteMessage("S1- S24 = ", false);
5059 if ((pResponse->LIGHTING4.cmd1 & 0x80) == 0)
5060 WriteMessage("0", false);
5061 else
5062 WriteMessage("1", false);
5063
5064 if ((pResponse->LIGHTING4.cmd1 & 0x40) == 0)
5065 WriteMessage("0", false);
5066 else
5067 WriteMessage("1", false);
5068
5069 if ((pResponse->LIGHTING4.cmd1 & 0x20) == 0)
5070 WriteMessage("0", false);
5071 else
5072 WriteMessage("1", false);
5073
5074 if ((pResponse->LIGHTING4.cmd1 & 0x10) == 0)
5075 WriteMessage("0 ", false);
5076 else
5077 WriteMessage("1 ", false);
5078
5079
5080 if ((pResponse->LIGHTING4.cmd1 & 0x08) == 0)
5081 WriteMessage("0", false);
5082 else
5083 WriteMessage("1", false);
5084
5085 if ((pResponse->LIGHTING4.cmd1 & 0x04) == 0)
5086 WriteMessage("0", false);
5087 else
5088 WriteMessage("1", false);
5089
5090 if ((pResponse->LIGHTING4.cmd1 & 0x02) == 0)
5091 WriteMessage("0", false);
5092 else
5093 WriteMessage("1", false);
5094
5095 if ((pResponse->LIGHTING4.cmd1 & 0x01) == 0)
5096 WriteMessage("0 ", false);
5097 else
5098 WriteMessage("1 ", false);
5099
5100
5101 if ((pResponse->LIGHTING4.cmd2 & 0x80) == 0)
5102 WriteMessage("0", false);
5103 else
5104 WriteMessage("1", false);
5105
5106 if ((pResponse->LIGHTING4.cmd2 & 0x40) == 0)
5107 WriteMessage("0", false);
5108 else
5109 WriteMessage("1", false);
5110
5111 if ((pResponse->LIGHTING4.cmd2 & 0x20) == 0)
5112 WriteMessage("0", false);
5113 else
5114 WriteMessage("1", false);
5115
5116 if ((pResponse->LIGHTING4.cmd2 & 0x10) == 0)
5117 WriteMessage("0 ", false);
5118 else
5119 WriteMessage("1 ", false);
5120
5121
5122 if ((pResponse->LIGHTING4.cmd2 & 0x08) == 0)
5123 WriteMessage("0", false);
5124 else
5125 WriteMessage("1", false);
5126
5127 if ((pResponse->LIGHTING4.cmd2 & 0x04) == 0)
5128 WriteMessage("0", false);
5129 else
5130 WriteMessage("1", false);
5131
5132 if ((pResponse->LIGHTING4.cmd2 & 0x02) == 0)
5133 WriteMessage("0", false);
5134 else
5135 WriteMessage("1", false);
5136
5137 if ((pResponse->LIGHTING4.cmd2 & 0x01) == 0)
5138 WriteMessage("0 ", false);
5139 else
5140 WriteMessage("1 ", false);
5141
5142
5143 if ((pResponse->LIGHTING4.cmd3 & 0x80) == 0)
5144 WriteMessage("0", false);
5145 else
5146 WriteMessage("1", false);
5147
5148 if ((pResponse->LIGHTING4.cmd3 & 0x40) == 0)
5149 WriteMessage("0", false);
5150 else
5151 WriteMessage("1", false);
5152
5153 if ((pResponse->LIGHTING4.cmd3 & 0x20) == 0)
5154 WriteMessage("0", false);
5155 else
5156 WriteMessage("1", false);
5157
5158 if ((pResponse->LIGHTING4.cmd3 & 0x10) == 0)
5159 WriteMessage("0 ", false);
5160 else
5161 WriteMessage("1 ", false);
5162
5163
5164 if ((pResponse->LIGHTING4.cmd3 & 0x08) == 0)
5165 WriteMessage("0", false);
5166 else
5167 WriteMessage("1", false);
5168
5169 if ((pResponse->LIGHTING4.cmd3 & 0x04) == 0)
5170 WriteMessage("0", false);
5171 else
5172 WriteMessage("1", false);
5173
5174 if ((pResponse->LIGHTING4.cmd3 & 0x02) == 0)
5175 WriteMessage("0", false);
5176 else
5177 WriteMessage("1", false);
5178
5179 if ((pResponse->LIGHTING4.cmd3 & 0x01) == 0)
5180 WriteMessage("0");
5181 else
5182 WriteMessage("1");
5183
5184 sprintf(szTmp, "Pulse = %d usec", (pResponse->LIGHTING4.pulseHigh * 256) + pResponse->LIGHTING4.pulseLow);
5185 WriteMessage(szTmp);
5186 break;
5187 default:
5188 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->LIGHTING4.packettype, pResponse->LIGHTING4.subtype);
5189 WriteMessage(szTmp);
5190 break;
5191 }
5192 sprintf(szTmp, "Signal level = %d", pResponse->LIGHTING4.rssi);
5193 WriteMessage(szTmp);
5194 WriteMessageEnd();
5195 }
5196 procResult.DeviceRowIdx = DevRowIdx;
5197 }
5198
decode_Lighting5(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)5199 void MainWorker::decode_Lighting5(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
5200 {
5201 char szTmp[100];
5202 uint8_t devType = pTypeLighting5;
5203 uint8_t subType = pResponse->LIGHTING5.subtype;
5204 if ((subType != sTypeEMW100) && (subType != sTypeLivolo) && (subType != sTypeLivolo1to10) && (subType != sTypeRGB432W) && (subType != sTypeKangtai))
5205 sprintf(szTmp, "%02X%02X%02X", pResponse->LIGHTING5.id1, pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5206 else
5207 sprintf(szTmp, "%02X%02X", pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5208 std::string ID = szTmp;
5209 uint8_t Unit = pResponse->LIGHTING5.unitcode;
5210 uint8_t cmnd = pResponse->LIGHTING5.cmnd;
5211 float flevel;
5212 if (subType == sTypeLivolo)
5213 flevel = (100.0f / 7.0f) * float(pResponse->LIGHTING5.level);
5214 else if (subType == sTypeLightwaveRF)
5215 flevel = (100.0f / 31.0f) * float(pResponse->LIGHTING5.level);
5216 else
5217 flevel = (100.0f / 7.0f) * float(pResponse->LIGHTING5.level);
5218 uint8_t SignalLevel = pResponse->LIGHTING5.rssi;
5219
5220 bool bDoUpdate = true;
5221 if ((subType == sTypeTRC02) || (subType == sTypeTRC02_2) || (subType == sTypeAoke) || (subType == sTypeEurodomest))
5222 {
5223 if (
5224 (pResponse->LIGHTING5.cmnd != light5_sOff) &&
5225 (pResponse->LIGHTING5.cmnd != light5_sOn) &&
5226 (pResponse->LIGHTING5.cmnd != light5_sGroupOff) &&
5227 (pResponse->LIGHTING5.cmnd != light5_sGroupOn)
5228 )
5229 {
5230 bDoUpdate = false;
5231 }
5232 }
5233 uint64_t DevRowIdx = -1;
5234 if (bDoUpdate)
5235 {
5236 sprintf(szTmp, "%d", pResponse->LIGHTING5.level);
5237 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, szTmp, procResult.DeviceName);
5238 if (DevRowIdx == (uint64_t)-1)
5239 return;
5240 CheckSceneCode(DevRowIdx, devType, subType, cmnd, szTmp, procResult.DeviceName);
5241 }
5242
5243 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
5244 {
5245 WriteMessageStart();
5246 switch (pResponse->LIGHTING5.subtype)
5247 {
5248 case sTypeLightwaveRF:
5249 WriteMessage("subtype = LightwaveRF");
5250 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5251 WriteMessage(szTmp);
5252 sprintf(szTmp, "ID = %02X%02X%02X", pResponse->LIGHTING5.id1, pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5253 WriteMessage(szTmp);
5254 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5255 WriteMessage(szTmp);
5256 WriteMessage("Command = ", false);
5257 switch (pResponse->LIGHTING5.cmnd)
5258 {
5259 case light5_sOff:
5260 WriteMessage("Off");
5261 break;
5262 case light5_sOn:
5263 WriteMessage("On");
5264 break;
5265 case light5_sGroupOff:
5266 WriteMessage("Group Off");
5267 break;
5268 case light5_sMood1:
5269 WriteMessage("Group Mood 1");
5270 break;
5271 case light5_sMood2:
5272 WriteMessage("Group Mood 2");
5273 break;
5274 case light5_sMood3:
5275 WriteMessage("Group Mood 3");
5276 break;
5277 case light5_sMood4:
5278 WriteMessage("Group Mood 4");
5279 break;
5280 case light5_sMood5:
5281 WriteMessage("Group Mood 5");
5282 break;
5283 case light5_sUnlock:
5284 WriteMessage("Unlock");
5285 break;
5286 case light5_sLock:
5287 WriteMessage("Lock");
5288 break;
5289 case light5_sAllLock:
5290 WriteMessage("All lock");
5291 break;
5292 case light5_sClose:
5293 WriteMessage("Close inline relay");
5294 break;
5295 case light5_sStop:
5296 WriteMessage("Stop inline relay");
5297 break;
5298 case light5_sOpen:
5299 WriteMessage("Open inline relay");
5300 break;
5301 case light5_sSetLevel:
5302 sprintf(szTmp, "Set dim level to: %.2f %%", flevel);
5303 WriteMessage(szTmp);
5304 break;
5305 case light5_sColourPalette:
5306 if (pResponse->LIGHTING5.level == 0)
5307 WriteMessage("Color Palette (Even command)");
5308 else
5309 WriteMessage("Color Palette (Odd command)");
5310 break;
5311 case light5_sColourTone:
5312 if (pResponse->LIGHTING5.level == 0)
5313 WriteMessage("Color Tone (Even command)");
5314 else
5315 WriteMessage("Color Tone (Odd command)");
5316 break;
5317 case light5_sColourCycle:
5318 if (pResponse->LIGHTING5.level == 0)
5319 WriteMessage("Color Cycle (Even command)");
5320 else
5321 WriteMessage("Color Cycle (Odd command)");
5322 break;
5323 default:
5324 WriteMessage("UNKNOWN");
5325 break;
5326 }
5327 break;
5328 case sTypeEMW100:
5329 WriteMessage("subtype = EMW100");
5330 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5331 WriteMessage(szTmp);
5332 sprintf(szTmp, "ID = %02X%02X", pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5333 WriteMessage(szTmp);
5334 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5335 WriteMessage(szTmp);
5336 WriteMessage("Command = ", false);
5337 switch (pResponse->LIGHTING5.cmnd)
5338 {
5339 case light5_sOff:
5340 WriteMessage("Off");
5341 break;
5342 case light5_sOn:
5343 WriteMessage("On");
5344 break;
5345 case light5_sLearn:
5346 WriteMessage("Learn");
5347 break;
5348 default:
5349 WriteMessage("UNKNOWN");
5350 break;
5351 }
5352 break;
5353 case sTypeBBSB:
5354 WriteMessage("subtype = BBSB new");
5355 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5356 WriteMessage(szTmp);
5357 sprintf(szTmp, "ID = %02X%02X%02X", pResponse->LIGHTING5.id1, pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5358 WriteMessage(szTmp);
5359 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5360 WriteMessage(szTmp);
5361 WriteMessage("Command = ", false);
5362 switch (pResponse->LIGHTING5.cmnd)
5363 {
5364 case light5_sOff:
5365 WriteMessage("Off");
5366 break;
5367 case light5_sOn:
5368 WriteMessage("On");
5369 break;
5370 case light5_sGroupOff:
5371 WriteMessage("Group Off");
5372 break;
5373 case light5_sGroupOn:
5374 WriteMessage("Group On");
5375 break;
5376 default:
5377 WriteMessage("UNKNOWN");
5378 break;
5379 }
5380 break;
5381 case sTypeRSL:
5382 WriteMessage("subtype = Conrad RSL");
5383 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5384 WriteMessage(szTmp);
5385 sprintf(szTmp, "ID = %02X%02X%02X", pResponse->LIGHTING5.id1, pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5386 WriteMessage(szTmp);
5387 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5388 WriteMessage(szTmp);
5389 WriteMessage("Command = ", false);
5390 switch (pResponse->LIGHTING5.cmnd)
5391 {
5392 case light5_sOff:
5393 WriteMessage("Off");
5394 break;
5395 case light5_sOn:
5396 WriteMessage("On");
5397 break;
5398 case light5_sGroupOff:
5399 WriteMessage("Group Off");
5400 break;
5401 case light5_sGroupOn:
5402 WriteMessage("Group On");
5403 break;
5404 default:
5405 WriteMessage("UNKNOWN");
5406 break;
5407 }
5408 break;
5409 case sTypeLivolo:
5410 WriteMessage("subtype = Livolo Dimmer");
5411 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5412 WriteMessage(szTmp);
5413 sprintf(szTmp, "ID = %02X%02X%02X", pResponse->LIGHTING5.id1, pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5414 WriteMessage(szTmp);
5415 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5416 WriteMessage(szTmp);
5417 WriteMessage("Command = ", false);
5418 switch (pResponse->LIGHTING5.cmnd)
5419 {
5420 case light5_sOff:
5421 WriteMessage("Off");
5422 break;
5423 case light5_sOn:
5424 WriteMessage("On");
5425 break;
5426 case light5_sGroupOff:
5427 WriteMessage("Group Off");
5428 break;
5429 case light5_sGroupOn:
5430 WriteMessage("Group On");
5431 break;
5432 default:
5433 WriteMessage("UNKNOWN");
5434 break;
5435 }
5436 break;
5437 case sTypeLivolo1to10:
5438 WriteMessage("subtype = Livolo On/Off module");
5439 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5440 WriteMessage(szTmp);
5441 sprintf(szTmp, "ID = %02X%02X", pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5442 WriteMessage(szTmp);
5443 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5444 WriteMessage(szTmp);
5445 WriteMessage("Command = ", false);
5446 switch (pResponse->LIGHTING5.cmnd)
5447 {
5448 case light5_sLivoloAllOff:
5449 WriteMessage("Off");
5450 break;
5451 case light5_sLivoloGang1Toggle:
5452 WriteMessage("Toggle");
5453 break;
5454 default:
5455 WriteMessage("UNKNOWN");
5456 break;
5457 }
5458 break;
5459 case sTypeRGB432W:
5460 WriteMessage("subtype = RGB432W");
5461 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5462 WriteMessage(szTmp);
5463 sprintf(szTmp, "ID = %02X%02X", pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5464 WriteMessage(szTmp);
5465 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5466 WriteMessage(szTmp);
5467 WriteMessage("Command = ", false);
5468 switch (pResponse->LIGHTING5.cmnd)
5469 {
5470 case light5_sRGBoff:
5471 WriteMessage("Off");
5472 break;
5473 case light5_sRGBon:
5474 WriteMessage("On");
5475 break;
5476 case light5_sRGBbright:
5477 WriteMessage("Bright+");
5478 break;
5479 case light5_sRGBdim:
5480 WriteMessage("Bright-");
5481 break;
5482 case light5_sRGBcolorplus:
5483 WriteMessage("Color+");
5484 break;
5485 case light5_sRGBcolormin:
5486 WriteMessage("Color-");
5487 break;
5488 default:
5489 sprintf(szTmp, "Color = = %d", pResponse->LIGHTING5.cmnd);
5490 WriteMessage(szTmp);
5491 break;
5492 }
5493 break;
5494 case sTypeTRC02:
5495 case sTypeTRC02_2:
5496 if (pResponse->LIGHTING5.subtype == sTypeTRC02)
5497 WriteMessage("subtype = TRC02 (RGB)");
5498 else
5499 WriteMessage("subtype = TRC02_2 (RGB)");
5500 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5501 WriteMessage(szTmp);
5502 sprintf(szTmp, "ID = %02X%02X%02X", pResponse->LIGHTING5.id1, pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5503 WriteMessage(szTmp);
5504 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5505 WriteMessage(szTmp);
5506 WriteMessage("Command = ", false);
5507 switch (pResponse->LIGHTING5.cmnd)
5508 {
5509 case light5_sOff:
5510 WriteMessage("Off");
5511 break;
5512 case light5_sOn:
5513 WriteMessage("On");
5514 break;
5515 case light5_sRGBbright:
5516 WriteMessage("Bright+");
5517 break;
5518 case light5_sRGBdim:
5519 WriteMessage("Bright-");
5520 break;
5521 case light5_sRGBcolorplus:
5522 WriteMessage("Color+");
5523 break;
5524 case light5_sRGBcolormin:
5525 WriteMessage("Color-");
5526 break;
5527 default:
5528 sprintf(szTmp, "Color = %d", pResponse->LIGHTING5.cmnd);
5529 WriteMessage(szTmp);
5530 break;
5531 }
5532 break;
5533 case sTypeAoke:
5534 WriteMessage("subtype = Aoke");
5535 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5536 WriteMessage(szTmp);
5537 sprintf(szTmp, "ID = %02X%02X", pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5538 WriteMessage(szTmp);
5539 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5540 WriteMessage(szTmp);
5541 WriteMessage("Command = ", false);
5542 switch (pResponse->LIGHTING5.cmnd)
5543 {
5544 case light5_sOff:
5545 WriteMessage("Off");
5546 break;
5547 case light5_sOn:
5548 WriteMessage("On");
5549 break;
5550 default:
5551 WriteMessage("UNKNOWN");
5552 break;
5553 }
5554 break;
5555 case sTypeEurodomest:
5556 WriteMessage("subtype = Eurodomest");
5557 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5558 WriteMessage(szTmp);
5559 sprintf(szTmp, "ID = %02X%02X", pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5560 WriteMessage(szTmp);
5561 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5562 WriteMessage(szTmp);
5563 WriteMessage("Command = ", false);
5564 switch (pResponse->LIGHTING5.cmnd)
5565 {
5566 case light5_sOff:
5567 WriteMessage("Off");
5568 break;
5569 case light5_sOn:
5570 WriteMessage("On");
5571 break;
5572 case light5_sGroupOff:
5573 WriteMessage("Group Off");
5574 break;
5575 case light5_sGroupOn:
5576 WriteMessage("Group On");
5577 break;
5578 default:
5579 WriteMessage("UNKNOWN");
5580 break;
5581 }
5582 break;
5583 case sTypeLegrandCAD:
5584 WriteMessage("subtype = Legrand CAD");
5585 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5586 WriteMessage(szTmp);
5587 sprintf(szTmp, "ID = %02X%02X", pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5588 WriteMessage(szTmp);
5589 WriteMessage("Command = Toggle");
5590 break;
5591 case sTypeAvantek:
5592 WriteMessage("subtype = Avantek");
5593 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5594 WriteMessage(szTmp);
5595 sprintf(szTmp, "ID = %02X%02X%02X", pResponse->LIGHTING5.id1, pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5596 WriteMessage(szTmp);
5597 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5598 WriteMessage(szTmp);
5599 WriteMessage("Command = ", false);
5600 switch (pResponse->LIGHTING5.cmnd)
5601 {
5602 case light5_sOff:
5603 WriteMessage("Off");
5604 break;
5605 case light5_sOn:
5606 WriteMessage("On");
5607 break;
5608 case light5_sGroupOff:
5609 WriteMessage("Group Off");
5610 break;
5611 case light5_sGroupOn:
5612 WriteMessage("Group On");
5613 break;
5614 default:
5615 WriteMessage("Unknown");
5616 break;
5617 }
5618 break;
5619 case sTypeIT:
5620 WriteMessage("subtype = Intertek,FA500,PROmax");
5621 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5622 WriteMessage(szTmp);
5623 sprintf(szTmp, "ID = %02X%02X%02X", pResponse->LIGHTING5.id1, pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5624 WriteMessage(szTmp);
5625 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5626 WriteMessage(szTmp);
5627 WriteMessage("Command = ", false);
5628 switch (pResponse->LIGHTING5.cmnd)
5629 {
5630 case light5_sOff:
5631 WriteMessage("Off");
5632 break;
5633 case light5_sOn:
5634 WriteMessage("On");
5635 break;
5636 case light5_sGroupOff:
5637 WriteMessage("Group Off");
5638 break;
5639 case light5_sGroupOn:
5640 WriteMessage("Group On");
5641 break;
5642 case light5_sSetLevel:
5643 sprintf(szTmp, "Set dim level to: %.2f %%", flevel);
5644 WriteMessage(szTmp);
5645 break;
5646 default:
5647 WriteMessage("UNKNOWN");
5648 break;
5649 }
5650 break;
5651 case sTypeKangtai:
5652 WriteMessage("subtype = Kangtai / Cotech");
5653 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING5.seqnbr);
5654 WriteMessage(szTmp);
5655 sprintf(szTmp, "ID = %02X%02X%02X", pResponse->LIGHTING5.id1, pResponse->LIGHTING5.id2, pResponse->LIGHTING5.id3);
5656 WriteMessage(szTmp);
5657 sprintf(szTmp, "Unit = %d", pResponse->LIGHTING5.unitcode);
5658 WriteMessage(szTmp);
5659 WriteMessage("Command = ", false);
5660 switch (pResponse->LIGHTING5.cmnd)
5661 {
5662 case light5_sOff:
5663 WriteMessage("Off");
5664 break;
5665 case light5_sOn:
5666 WriteMessage("On");
5667 break;
5668 case light5_sGroupOff:
5669 WriteMessage("Group Off");
5670 break;
5671 case light5_sGroupOn:
5672 WriteMessage("Group On");
5673 break;
5674 default:
5675 WriteMessage("UNKNOWN");
5676 break;
5677 }
5678 break;
5679 default:
5680 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->LIGHTING5.packettype, pResponse->LIGHTING5.subtype);
5681 WriteMessage(szTmp);
5682 break;
5683 }
5684 sprintf(szTmp, "Signal level = %d", pResponse->LIGHTING5.rssi);
5685 WriteMessage(szTmp);
5686 WriteMessageEnd();
5687 }
5688 procResult.DeviceRowIdx = DevRowIdx;
5689 }
5690
decode_Lighting6(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)5691 void MainWorker::decode_Lighting6(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
5692 {
5693 char szTmp[100];
5694 uint8_t devType = pTypeLighting6;
5695 uint8_t subType = pResponse->LIGHTING6.subtype;
5696 sprintf(szTmp, "%02X%02X%02X", pResponse->LIGHTING6.id1, pResponse->LIGHTING6.id2, pResponse->LIGHTING6.groupcode);
5697 std::string ID = szTmp;
5698 uint8_t Unit = pResponse->LIGHTING6.unitcode;
5699 uint8_t cmnd = pResponse->LIGHTING6.cmnd;
5700 uint8_t rfu = pResponse->LIGHTING6.seqnbr2;
5701 uint8_t SignalLevel = pResponse->LIGHTING6.rssi;
5702
5703 sprintf(szTmp, "%d", rfu);
5704 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, szTmp, procResult.DeviceName);
5705 if (DevRowIdx == (uint64_t)-1)
5706 return;
5707 CheckSceneCode(DevRowIdx, devType, subType, cmnd, szTmp, procResult.DeviceName);
5708
5709 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
5710 {
5711 WriteMessageStart();
5712 switch (pResponse->LIGHTING6.subtype)
5713 {
5714 case sTypeBlyss:
5715 WriteMessage("subtype = Blyss");
5716 sprintf(szTmp, "Sequence nbr = %d", pResponse->LIGHTING6.seqnbr);
5717 WriteMessage(szTmp);
5718 sprintf(szTmp, "ID = %02X%02X", pResponse->LIGHTING6.id1, pResponse->LIGHTING6.id2);
5719 WriteMessage(szTmp);
5720 sprintf(szTmp, "groupcode = %d", pResponse->LIGHTING6.groupcode);
5721 WriteMessage(szTmp);
5722 sprintf(szTmp, "unitcode = %d", pResponse->LIGHTING6.unitcode);
5723 WriteMessage(szTmp);
5724 WriteMessage("Command = ", false);
5725 switch (pResponse->LIGHTING6.cmnd)
5726 {
5727 case light6_sOff:
5728 WriteMessage("Off");
5729 break;
5730 case light6_sOn:
5731 WriteMessage("On");
5732 break;
5733 case light6_sGroupOff:
5734 WriteMessage("Group Off");
5735 break;
5736 case light6_sGroupOn:
5737 WriteMessage("Group On");
5738 break;
5739 default:
5740 WriteMessage("UNKNOWN");
5741 break;
5742 }
5743 sprintf(szTmp, "Command seqnbr= %d", pResponse->LIGHTING6.cmndseqnbr);
5744 WriteMessage(szTmp);
5745 sprintf(szTmp, "seqnbr2 = %d", pResponse->LIGHTING6.seqnbr2);
5746 WriteMessage(szTmp);
5747 break;
5748 default:
5749 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->LIGHTING6.packettype, pResponse->LIGHTING6.subtype);
5750 WriteMessage(szTmp);
5751 break;
5752 }
5753 sprintf(szTmp, "Signal level = %d", pResponse->LIGHTING6.rssi);
5754 WriteMessage(szTmp);
5755 WriteMessageEnd();
5756 }
5757 procResult.DeviceRowIdx = DevRowIdx;
5758 }
5759
decode_Fan(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)5760 void MainWorker::decode_Fan(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
5761 {
5762 char szTmp[100];
5763 uint8_t devType = pTypeFan;
5764 uint8_t subType = pResponse->FAN.subtype;
5765 sprintf(szTmp, "%02X%02X%02X", pResponse->FAN.id1, pResponse->FAN.id2, pResponse->FAN.id3);
5766 std::string ID = szTmp;
5767 uint8_t Unit = 0;
5768 uint8_t cmnd = pResponse->FAN.cmnd;
5769 uint8_t SignalLevel = pResponse->FAN.rssi;
5770
5771 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, procResult.DeviceName);
5772 if (DevRowIdx == (uint64_t)-1)
5773 return;
5774 CheckSceneCode(DevRowIdx, devType, subType, cmnd, szTmp, procResult.DeviceName);
5775
5776 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
5777 {
5778 WriteMessageStart();
5779 switch (pResponse->FAN.subtype)
5780 {
5781 case sTypeSiemensSF01:
5782 WriteMessage("subtype = Siemens SF01");
5783 sprintf(szTmp, "Sequence nbr = %d", pResponse->FAN.seqnbr);
5784 WriteMessage(szTmp);
5785 sprintf(szTmp, "ID = %02X%02X", pResponse->FAN.id2, pResponse->FAN.id3);
5786 WriteMessage(szTmp);
5787 WriteMessage("Command = ", false);
5788 switch (pResponse->FAN.cmnd)
5789 {
5790 case fan_sTimer:
5791 WriteMessage("Timer");
5792 break;
5793 case fan_sMin:
5794 WriteMessage("-");
5795 break;
5796 case fan_sLearn:
5797 WriteMessage("Learn");
5798 break;
5799 case fan_sPlus:
5800 WriteMessage("+");
5801 break;
5802 case fan_sConfirm:
5803 WriteMessage("Confirm");
5804 break;
5805 case fan_sLight:
5806 WriteMessage("Light");
5807 break;
5808 default:
5809 WriteMessage("UNKNOWN");
5810 break;
5811 }
5812 break;
5813 case sTypeItho:
5814 WriteMessage("subtype = Itho CVE RFT");
5815 sprintf(szTmp, "Sequence nbr = %d", pResponse->FAN.seqnbr);
5816 WriteMessage(szTmp);
5817 sprintf(szTmp, "ID = %02X%02X%02X", pResponse->FAN.id1, pResponse->FAN.id2, pResponse->FAN.id3);
5818 WriteMessage(szTmp);
5819 WriteMessage("Command = ", false);
5820 switch (pResponse->FAN.cmnd)
5821 {
5822 case fan_Itho1:
5823 WriteMessage("1");
5824 break;
5825 case fan_Itho2:
5826 WriteMessage("2");
5827 break;
5828 case fan_Itho3:
5829 WriteMessage("3");
5830 break;
5831 case fan_IthoTimer:
5832 WriteMessage("Timer");
5833 break;
5834 case fan_IthoNotAtHome:
5835 WriteMessage("Not at Home");
5836 break;
5837 case fan_IthoLearn:
5838 WriteMessage("Learn");
5839 break;
5840 case fan_IthoEraseAll:
5841 WriteMessage("Erase all remotes");
5842 break;
5843 default:
5844 WriteMessage("UNKNOWN");
5845 break;
5846 }
5847 break;
5848 case sTypeLucciAir:
5849 WriteMessage("subtype = Lucci Air");
5850 break;
5851 case sTypeSeavTXS4:
5852 WriteMessage("subtype = SEAV TXS4");
5853 break;
5854 case sTypeWestinghouse:
5855 WriteMessage("subtype = Westinghouse");
5856 break;
5857 case sTypeLucciAirDC:
5858 WriteMessage("subtype = Lucci Air DC");
5859 break;
5860 case sTypeCasafan:
5861 WriteMessage("subtype = Casafan");
5862 break;
5863 case sTypeFT1211R:
5864 WriteMessage("subtype = FT1211R");
5865 break;
5866 case sTypeFalmec:
5867 WriteMessage("subtype = Falmec");
5868 break;
5869 case sTypeLucciAirDCII:
5870 WriteMessage("subtype = Lucci Air DC II");
5871 break;
5872 default:
5873 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->LIGHTING6.packettype, pResponse->LIGHTING6.subtype);
5874 WriteMessage(szTmp);
5875 break;
5876 }
5877 sprintf(szTmp, "Signal level = %d", pResponse->LIGHTING6.rssi);
5878 WriteMessage(szTmp);
5879 WriteMessageEnd();
5880 }
5881 procResult.DeviceRowIdx = DevRowIdx;
5882 }
5883
decode_HomeConfort(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)5884 void MainWorker::decode_HomeConfort(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
5885 {
5886 char szTmp[100];
5887 uint8_t devType = pTypeHomeConfort;
5888 uint8_t subType = pResponse->HOMECONFORT.subtype;
5889 sprintf(szTmp, "%02X%02X%02X%02X", pResponse->HOMECONFORT.id1, pResponse->HOMECONFORT.id2, pResponse->HOMECONFORT.id3, pResponse->HOMECONFORT.housecode);
5890 std::string ID = szTmp;
5891 uint8_t Unit = pResponse->HOMECONFORT.unitcode;
5892 uint8_t cmnd = pResponse->HOMECONFORT.cmnd;
5893 uint8_t SignalLevel = pResponse->HOMECONFORT.rssi;
5894
5895 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, procResult.DeviceName);
5896
5897 bool isGroupCommand = ((cmnd == HomeConfort_sGroupOff) || (cmnd == HomeConfort_sGroupOn));
5898 uint8_t single_cmnd = cmnd;
5899
5900 if (isGroupCommand)
5901 {
5902 single_cmnd = (cmnd == HomeConfort_sGroupOff) ? HomeConfort_sOff : HomeConfort_sOn;
5903
5904 // We write the GROUP_CMD into the log to differentiate between manual turn off/on and group_off/group_on
5905 m_sql.UpdateValueHomeConfortGroupCmd(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, szTmp, procResult.DeviceName);
5906
5907 //set the status of all lights with the same code to on/off
5908 m_sql.HomeConfortGroupCmd(ID, subType, single_cmnd);
5909 }
5910
5911 if (DevRowIdx == (uint64_t)-1)
5912 return;
5913 CheckSceneCode(DevRowIdx, devType, subType, cmnd, "", procResult.DeviceName);
5914
5915 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
5916 {
5917 WriteMessageStart();
5918 switch (pResponse->HOMECONFORT.subtype)
5919 {
5920 case sTypeHomeConfortTEL010:
5921 WriteMessage("subtype = TEL-010");
5922 sprintf(szTmp, "Sequence nbr = %d", pResponse->HOMECONFORT.seqnbr);
5923 WriteMessage(szTmp);
5924 sprintf(szTmp, "ID = %02X%02X%02X", pResponse->HOMECONFORT.id1, pResponse->HOMECONFORT.id2, pResponse->HOMECONFORT.id3);
5925 WriteMessage(szTmp);
5926 sprintf(szTmp, "housecode = %d", pResponse->HOMECONFORT.housecode);
5927 WriteMessage(szTmp);
5928 sprintf(szTmp, "unitcode = %d", pResponse->HOMECONFORT.unitcode);
5929 WriteMessage(szTmp);
5930 WriteMessage("Command = ", false);
5931 switch (pResponse->HOMECONFORT.cmnd)
5932 {
5933 case HomeConfort_sOff:
5934 WriteMessage("Off");
5935 break;
5936 case HomeConfort_sOn:
5937 WriteMessage("On");
5938 break;
5939 case HomeConfort_sGroupOff:
5940 WriteMessage("Group Off");
5941 break;
5942 case HomeConfort_sGroupOn:
5943 WriteMessage("Group On");
5944 break;
5945 default:
5946 WriteMessage("UNKNOWN");
5947 break;
5948 }
5949 break;
5950 default:
5951 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->HOMECONFORT.packettype, pResponse->HOMECONFORT.subtype);
5952 WriteMessage(szTmp);
5953 break;
5954 }
5955 sprintf(szTmp, "Signal level = %d", pResponse->HOMECONFORT.rssi);
5956 WriteMessage(szTmp);
5957 WriteMessageEnd();
5958 }
5959 procResult.DeviceRowIdx = DevRowIdx;
5960 }
5961
decode_ColorSwitch(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)5962 void MainWorker::decode_ColorSwitch(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
5963 {
5964 char szTmp[300];
5965 const _tColorSwitch* pLed = reinterpret_cast<const _tColorSwitch*>(pResponse);
5966 uint8_t devType = pTypeColorSwitch;
5967 uint8_t subType = pLed->subtype;
5968 if (pLed->id == 1)
5969 sprintf(szTmp, "%d", 1);
5970 else
5971 sprintf(szTmp, "%08X", (unsigned int)pLed->id);
5972 std::string ID = szTmp;
5973 uint8_t Unit = pLed->dunit;
5974 uint8_t cmnd = pLed->command;
5975 uint32_t value = pLed->value;
5976 _tColor color = pLed->color;
5977
5978 char szValueTmp[100];
5979 sprintf(szValueTmp, "%u", value);
5980 std::string sValue = szValueTmp;
5981 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, 12, -1, cmnd, sValue.c_str(), procResult.DeviceName);
5982 if (DevRowIdx == (uint64_t)-1)
5983 return;
5984 CheckSceneCode(DevRowIdx, devType, subType, cmnd, szTmp, procResult.DeviceName);
5985
5986 // TODO: Why don't we let database update be handled by CSQLHelper::UpdateValue?
5987 if (cmnd == Color_SetBrightnessLevel || cmnd == Color_SetColor)
5988 {
5989 std::vector<std::vector<std::string> > result;
5990 result = m_sql.safe_query(
5991 "SELECT ID,Name FROM DeviceStatus WHERE (HardwareID=%d AND DeviceID='%q' AND Unit=%d AND Type=%d AND SubType=%d)",
5992 pHardware->m_HwdID, ID.c_str(), Unit, devType, subType);
5993 if (!result.empty())
5994 {
5995 uint64_t ulID = std::strtoull(result[0][0].c_str(), nullptr, 10);
5996
5997 //store light level
5998 m_sql.safe_query(
5999 "UPDATE DeviceStatus SET LastLevel='%d' WHERE (ID = %" PRIu64 ")",
6000 value,
6001 ulID);
6002 }
6003
6004 }
6005
6006 if (cmnd == Color_SetColor)
6007 {
6008 std::vector<std::vector<std::string> > result;
6009 result = m_sql.safe_query(
6010 "SELECT ID,Name FROM DeviceStatus WHERE (HardwareID=%d AND DeviceID='%q' AND Unit=%d AND Type=%d AND SubType=%d)",
6011 pHardware->m_HwdID, ID.c_str(), Unit, devType, subType);
6012 if (!result.empty())
6013 {
6014 uint64_t ulID = std::strtoull(result[0][0].c_str(), nullptr, 10);
6015
6016 //store color in database
6017 m_sql.safe_query(
6018 "UPDATE DeviceStatus SET Color='%q' WHERE (ID = %" PRIu64 ")",
6019 color.toJSONString().c_str(),
6020 ulID);
6021 }
6022
6023 }
6024
6025 procResult.DeviceRowIdx = DevRowIdx;
6026 }
6027
decode_Chime(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)6028 void MainWorker::decode_Chime(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
6029 {
6030 char szTmp[100];
6031 uint8_t devType = pTypeChime;
6032 uint8_t subType = pResponse->CHIME.subtype;
6033 sprintf(szTmp, "%02X%02X", pResponse->CHIME.id1, pResponse->CHIME.id2);
6034 std::string ID = szTmp;
6035 uint8_t Unit = pResponse->CHIME.sound;
6036 uint8_t cmnd = pResponse->CHIME.sound;
6037 uint8_t SignalLevel = pResponse->CHIME.rssi;
6038
6039 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, procResult.DeviceName);
6040 if (DevRowIdx == (uint64_t)-1)
6041 return;
6042 CheckSceneCode(DevRowIdx, devType, subType, cmnd, "", procResult.DeviceName);
6043
6044 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
6045 {
6046 WriteMessageStart();
6047 switch (pResponse->CHIME.subtype)
6048 {
6049 case sTypeByronSX:
6050 WriteMessage("subtype = Byron SX");
6051 sprintf(szTmp, "Sequence nbr = %d", pResponse->CHIME.seqnbr);
6052 WriteMessage(szTmp);
6053 sprintf(szTmp, "ID = %02X%02X", pResponse->CHIME.id1, pResponse->CHIME.id2);
6054 WriteMessage(szTmp);
6055 WriteMessage("Sound = ", false);
6056 switch (pResponse->CHIME.sound)
6057 {
6058 case chime_sound0:
6059 case chime_sound4:
6060 WriteMessage("Tubular 3 notes");
6061 break;
6062 case chime_sound1:
6063 case chime_sound5:
6064 WriteMessage("Big Ben");
6065 break;
6066 case chime_sound2:
6067 case chime_sound6:
6068 WriteMessage("Tubular 3 notes");
6069 break;
6070 case chime_sound3:
6071 case chime_sound7:
6072 WriteMessage("Solo");
6073 break;
6074 default:
6075 WriteMessage("UNKNOWN?");
6076 break;
6077 }
6078 break;
6079 case sTypeByronMP001:
6080 WriteMessage("subtype = Byron MP001");
6081 sprintf(szTmp, "Sequence nbr = %d", pResponse->CHIME.seqnbr);
6082 WriteMessage(szTmp);
6083 sprintf(szTmp, "ID = %02X%02X", pResponse->CHIME.id1, pResponse->CHIME.id2);
6084 WriteMessage(szTmp);
6085 sprintf(szTmp, "Sound = %d", pResponse->CHIME.sound);
6086 WriteMessage(szTmp);
6087
6088 if ((pResponse->CHIME.id1 & 0x40) == 0x40)
6089 WriteMessage("Switch 1 = Off");
6090 else
6091 WriteMessage("Switch 1 = On");
6092
6093 if ((pResponse->CHIME.id1 & 0x10) == 0x10)
6094 WriteMessage("Switch 2 = Off");
6095 else
6096 WriteMessage("Switch 2 = On");
6097
6098 if ((pResponse->CHIME.id1 & 0x04) == 0x04)
6099 WriteMessage("Switch 3 = Off");
6100 else
6101 WriteMessage("Switch 3 = On");
6102
6103 if ((pResponse->CHIME.id1 & 0x01) == 0x01)
6104 WriteMessage("Switch 4 = Off");
6105 else
6106 WriteMessage("Switch 4 = On");
6107
6108 if ((pResponse->CHIME.id2 & 0x40) == 0x40)
6109 WriteMessage("Switch 5 = Off");
6110 else
6111 WriteMessage("Switch 5 = On");
6112
6113 if ((pResponse->CHIME.id2 & 0x10) == 0x10)
6114 WriteMessage("Switch 6 = Off");
6115 else
6116 WriteMessage("Switch 6 = On");
6117 break;
6118 case sTypeSelectPlus:
6119 WriteMessage("subtype = SelectPlus200689101");
6120 sprintf(szTmp, "Sequence nbr = %d", pResponse->CHIME.seqnbr);
6121 WriteMessage(szTmp);
6122 sprintf(szTmp, "ID = %02X%02X", pResponse->CHIME.id1, pResponse->CHIME.id2);
6123 WriteMessage(szTmp);
6124 break;
6125 case sTypeByronBY:
6126 WriteMessage("subtype = SelectPlus200689103");
6127 sprintf(szTmp, "Sequence nbr = %d", pResponse->CHIME.seqnbr);
6128 WriteMessage(szTmp);
6129 sprintf(szTmp, "ID = %02X%02X", pResponse->CHIME.id1, pResponse->CHIME.id2);
6130 WriteMessage(szTmp);
6131 break;
6132 case sTypeEnvivo:
6133 WriteMessage("subtype = Envivo");
6134 sprintf(szTmp, "Sequence nbr = %d", pResponse->CHIME.seqnbr);
6135 WriteMessage(szTmp);
6136 sprintf(szTmp, "ID = %02X%02X", pResponse->CHIME.id1, pResponse->CHIME.id2);
6137 WriteMessage(szTmp);
6138 break;
6139 case sTypeAlfawise:
6140 WriteMessage("subtype = Alfawise");
6141 sprintf(szTmp, "Sequence nbr = %d", pResponse->CHIME.seqnbr);
6142 WriteMessage(szTmp);
6143 sprintf(szTmp, "ID = %02X%02X", pResponse->CHIME.id1, pResponse->CHIME.id2);
6144 WriteMessage(szTmp);
6145 break;
6146 default:
6147 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->CHIME.packettype, pResponse->CHIME.subtype);
6148 WriteMessage(szTmp);
6149 break;
6150 }
6151 sprintf(szTmp, "Signal level = %d", pResponse->CHIME.rssi);
6152 WriteMessage(szTmp);
6153 WriteMessageEnd();
6154 }
6155 procResult.DeviceRowIdx = DevRowIdx;
6156 }
6157
6158
decode_UNDECODED(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)6159 void MainWorker::decode_UNDECODED(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
6160 {
6161 char szTmp[100];
6162
6163 WriteMessage("UNDECODED ", false);
6164
6165 switch (pResponse->UNDECODED.subtype)
6166 {
6167 case sTypeUac:
6168 WriteMessage("AC:", false);
6169 break;
6170 case sTypeUarc:
6171 WriteMessage("ARC:", false);
6172 break;
6173 case sTypeUati:
6174 WriteMessage("ATI:", false);
6175 break;
6176 case sTypeUhideki:
6177 WriteMessage("HIDEKI:", false);
6178 break;
6179 case sTypeUlacrosse:
6180 WriteMessage("LACROSSE:", false);
6181 break;
6182 case sTypeUad:
6183 WriteMessage("AD:", false);
6184 break;
6185 case sTypeUmertik:
6186 WriteMessage("MERTIK:", false);
6187 break;
6188 case sTypeUoregon1:
6189 WriteMessage("OREGON1:", false);
6190 break;
6191 case sTypeUoregon2:
6192 WriteMessage("OREGON2:", false);
6193 break;
6194 case sTypeUoregon3:
6195 WriteMessage("OREGON3:", false);
6196 break;
6197 case sTypeUproguard:
6198 WriteMessage("PROGUARD:", false);
6199 break;
6200 case sTypeUvisonic:
6201 WriteMessage("VISONIC:", false);
6202 break;
6203 case sTypeUnec:
6204 WriteMessage("NEC:", false);
6205 break;
6206 case sTypeUfs20:
6207 WriteMessage("FS20:", false);
6208 break;
6209 case sTypeUblinds:
6210 WriteMessage("Blinds:", false);
6211 break;
6212 case sTypeUrubicson:
6213 WriteMessage("RUBICSON:", false);
6214 break;
6215 case sTypeUae:
6216 WriteMessage("AE:", false);
6217 break;
6218 case sTypeUfineoffset:
6219 WriteMessage("FineOffset:", false);
6220 break;
6221 case sTypeUrgb:
6222 WriteMessage("RGB:", false);
6223 break;
6224 case sTypeUrfy:
6225 WriteMessage("RFY:", false);
6226 break;
6227 default:
6228 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->UNDECODED.packettype, pResponse->UNDECODED.subtype);
6229 WriteMessage(szTmp);
6230 break;
6231 }
6232 std::stringstream sHexDump;
6233 uint8_t* pRXBytes = (uint8_t*)&pResponse->UNDECODED.msg1;
6234 for (int i = 0; i < pResponse->UNDECODED.packetlength - 3; i++)
6235 {
6236 sHexDump << HEX(pRXBytes[i]);
6237 }
6238 WriteMessage(sHexDump.str().c_str());
6239 procResult.DeviceRowIdx = -1;
6240 }
6241
6242
decode_RecXmitMessage(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)6243 void MainWorker::decode_RecXmitMessage(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
6244 {
6245 char szTmp[100];
6246
6247 switch (pResponse->RXRESPONSE.subtype)
6248 {
6249 case sTypeReceiverLockError:
6250 WriteMessage("subtype = Receiver lock error");
6251 sprintf(szTmp, "Sequence nbr = %d", pResponse->RXRESPONSE.seqnbr);
6252 WriteMessage(szTmp);
6253 break;
6254 case sTypeTransmitterResponse:
6255 WriteMessage("subtype = Transmitter Response");
6256 sprintf(szTmp, "Sequence nbr = %d", pResponse->RXRESPONSE.seqnbr);
6257 WriteMessage(szTmp);
6258
6259 switch (pResponse->RXRESPONSE.msg)
6260 {
6261 case 0x0:
6262 WriteMessage("response = ACK, data correct transmitted");
6263 break;
6264 case 0x1:
6265 WriteMessage("response = ACK, but transmit started after 6 seconds delay anyway with RF receive data detected");
6266 break;
6267 case 0x2:
6268 WriteMessage("response = NAK, transmitter did not lock on the requested transmit frequency");
6269 break;
6270 case 0x3:
6271 WriteMessage("response = NAK, AC address zero in id1-id4 not allowed");
6272 break;
6273 default:
6274 sprintf(szTmp, "ERROR: Unexpected message type= %02X", pResponse->RXRESPONSE.msg);
6275 WriteMessage(szTmp);
6276 break;
6277 }
6278 break;
6279 default:
6280 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->RXRESPONSE.packettype, pResponse->RXRESPONSE.subtype);
6281 WriteMessage(szTmp);
6282 break;
6283 }
6284 procResult.DeviceRowIdx = -1;
6285 }
6286
decode_Curtain(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)6287 void MainWorker::decode_Curtain(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
6288 {
6289 char szTmp[100];
6290 uint8_t devType = pTypeCurtain;
6291 uint8_t subType = pResponse->CURTAIN1.subtype;
6292 sprintf(szTmp, "%d", pResponse->CURTAIN1.housecode);
6293 std::string ID = szTmp;
6294 uint8_t Unit = pResponse->CURTAIN1.unitcode;
6295 uint8_t cmnd = pResponse->CURTAIN1.cmnd;
6296 uint8_t SignalLevel = 9;
6297
6298 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, procResult.DeviceName);
6299 if (DevRowIdx == (uint64_t)-1)
6300 return;
6301
6302 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
6303 {
6304 WriteMessageStart();
6305 char szTmp[100];
6306
6307 switch (pResponse->CURTAIN1.subtype)
6308 {
6309 case sTypeHarrison:
6310 WriteMessage("subtype = Harrison");
6311 break;
6312 default:
6313 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X:", pResponse->CURTAIN1.packettype, pResponse->CURTAIN1.subtype);
6314 WriteMessage(szTmp);
6315 break;
6316 }
6317 sprintf(szTmp, "Sequence nbr = %d", pResponse->CURTAIN1.seqnbr);
6318 WriteMessage(szTmp);
6319
6320 sprintf(szTmp, "Housecode = %d", pResponse->CURTAIN1.housecode);
6321 WriteMessage(szTmp);
6322
6323 sprintf(szTmp, "Unit = %d", pResponse->CURTAIN1.unitcode);
6324 WriteMessage(szTmp);
6325
6326 WriteMessage("Command = ", false);
6327
6328 switch (pResponse->CURTAIN1.cmnd)
6329 {
6330 case curtain_sOpen:
6331 WriteMessage("Open");
6332 break;
6333 case curtain_sStop:
6334 WriteMessage("Stop");
6335 break;
6336 case curtain_sClose:
6337 WriteMessage("Close");
6338 break;
6339 default:
6340 WriteMessage("UNKNOWN");
6341 break;
6342 }
6343 WriteMessageEnd();
6344 }
6345 procResult.DeviceRowIdx = DevRowIdx;
6346 }
6347
decode_BLINDS1(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)6348 void MainWorker::decode_BLINDS1(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
6349 {
6350 char szTmp[100];
6351 uint8_t devType = pTypeBlinds;
6352 uint8_t subType = pResponse->BLINDS1.subtype;
6353
6354 sprintf(szTmp, "%02X%02X%02X%02X", pResponse->BLINDS1.id1, pResponse->BLINDS1.id2, pResponse->BLINDS1.id3, pResponse->BLINDS1.id4);
6355
6356 std::string ID = szTmp;
6357 uint8_t Unit = pResponse->BLINDS1.unitcode;
6358 uint8_t cmnd = pResponse->BLINDS1.cmnd;
6359 uint8_t SignalLevel = pResponse->BLINDS1.rssi;
6360
6361 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, procResult.DeviceName);
6362 if (DevRowIdx == (uint64_t)-1)
6363 return;
6364 CheckSceneCode(DevRowIdx, devType, subType, cmnd, szTmp, procResult.DeviceName);
6365
6366 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
6367 {
6368 WriteMessageStart();
6369 char szTmp[100];
6370
6371 switch (pResponse->BLINDS1.subtype)
6372 {
6373 case sTypeBlindsT0:
6374 WriteMessage("subtype = Safy / RollerTrol / Hasta new");
6375 break;
6376 case sTypeBlindsT1:
6377 WriteMessage("subtype = Hasta old");
6378 break;
6379 case sTypeBlindsT2:
6380 WriteMessage("subtype = A-OK RF01");
6381 break;
6382 case sTypeBlindsT3:
6383 WriteMessage("subtype = A-OK AC114");
6384 break;
6385 case sTypeBlindsT4:
6386 WriteMessage("subtype = RAEX");
6387 break;
6388 case sTypeBlindsT5:
6389 WriteMessage("subtype = Media Mount");
6390 break;
6391 case sTypeBlindsT6:
6392 WriteMessage("subtype = DC106, YOOHA, Rohrmotor24 RMF");
6393 break;
6394 case sTypeBlindsT7:
6395 WriteMessage("subtype = Forest");
6396 break;
6397 case sTypeBlindsT8:
6398 WriteMessage("subtype = Chamberlain CS4330CN");
6399 break;
6400 case sTypeBlindsT9:
6401 WriteMessage("subtype = Sunpery");
6402 break;
6403 case sTypeBlindsT10:
6404 WriteMessage("subtype = Dolat DLM-1");
6405 break;
6406 case sTypeBlindsT11:
6407 WriteMessage("subtype = ASP");
6408 break;
6409 case sTypeBlindsT12:
6410 WriteMessage("subtype = Confexx");
6411 break;
6412 case sTypeBlindsT13:
6413 WriteMessage("subtype = Screenline");
6414 break;
6415 case sTypeBlindsT14:
6416 WriteMessage("subtype = Hualite");
6417 break;
6418 case sTypeBlindsT15:
6419 WriteMessage("subtype = RFU");
6420 break;
6421 case sTypeBlindsT16:
6422 WriteMessage("subtype = Zemismart");
6423 break;
6424 case sTypeBlindsT17:
6425 WriteMessage("subtype = Gaposa");
6426 break;
6427 case sTypeBlindsT18:
6428 WriteMessage("subtype = Cherubini");
6429 break;
6430 default:
6431 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X:", pResponse->BLINDS1.packettype, pResponse->BLINDS1.subtype);
6432 WriteMessage(szTmp);
6433 break;
6434 }
6435 sprintf(szTmp, "Sequence nbr = %d", pResponse->BLINDS1.seqnbr);
6436 WriteMessage(szTmp);
6437
6438 sprintf(szTmp, "id1-3 = %02X%02X%02X", pResponse->BLINDS1.id1, pResponse->BLINDS1.id2, pResponse->BLINDS1.id3);
6439 WriteMessage(szTmp);
6440
6441 if ((subType == sTypeBlindsT6) || (subType == sTypeBlindsT7))
6442 {
6443 sprintf(szTmp, "id4 = %02X", pResponse->BLINDS1.id4);
6444 WriteMessage(szTmp);
6445 }
6446
6447 if (pResponse->BLINDS1.unitcode == 0)
6448 WriteMessage("Unit = All");
6449 else
6450 {
6451 sprintf(szTmp, "Unit = %d", pResponse->BLINDS1.unitcode);
6452 WriteMessage(szTmp);
6453 }
6454
6455 WriteMessage("Command = ", false);
6456
6457 switch (pResponse->BLINDS1.cmnd)
6458 {
6459 case blinds_sOpen:
6460 WriteMessage("Open");
6461 break;
6462 case blinds_sStop:
6463 WriteMessage("Stop");
6464 break;
6465 case blinds_sClose:
6466 WriteMessage("Close");
6467 break;
6468 case blinds_sConfirm:
6469 WriteMessage("Confirm");
6470 break;
6471 case blinds_sLimit:
6472 WriteMessage("Set Limit");
6473 if (pResponse->BLINDS1.subtype == sTypeBlindsT4)
6474 WriteMessage("Set Upper Limit");
6475 else
6476 WriteMessage("Set Limit");
6477 break;
6478 case blinds_slowerLimit:
6479 WriteMessage("Set Lower Limit");
6480 break;
6481 case blinds_sDeleteLimits:
6482 WriteMessage("Delete Limits");
6483 break;
6484 case blinds_sChangeDirection:
6485 WriteMessage("Change Direction");
6486 break;
6487 case blinds_sLeft:
6488 WriteMessage("Left");
6489 break;
6490 case blinds_sRight:
6491 WriteMessage("Right");
6492 break;
6493 default:
6494 WriteMessage("UNKNOWN");
6495 break;
6496 }
6497 sprintf(szTmp, "Signal level = %d", pResponse->BLINDS1.rssi);
6498 WriteMessage(szTmp);
6499 WriteMessageEnd();
6500 }
6501 procResult.DeviceRowIdx = DevRowIdx;
6502 }
6503
decode_RFY(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)6504 void MainWorker::decode_RFY(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
6505 {
6506 char szTmp[100];
6507 uint8_t devType = pTypeRFY;
6508 uint8_t subType = pResponse->RFY.subtype;
6509 sprintf(szTmp, "%02X%02X%02X", pResponse->RFY.id1, pResponse->RFY.id2, pResponse->RFY.id3);
6510 std::string ID = szTmp;
6511 uint8_t Unit = pResponse->RFY.unitcode;
6512 uint8_t cmnd = pResponse->RFY.cmnd;
6513 uint8_t SignalLevel = pResponse->RFY.rssi;
6514
6515 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, procResult.DeviceName);
6516 if (DevRowIdx == (uint64_t)-1)
6517 return;
6518 CheckSceneCode(DevRowIdx, devType, subType, cmnd, szTmp, procResult.DeviceName);
6519
6520 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
6521 {
6522 WriteMessageStart();
6523 char szTmp[100];
6524
6525 switch (pResponse->RFY.subtype)
6526 {
6527 case sTypeRFY:
6528 WriteMessage("subtype = RFY");
6529 break;
6530 case sTypeRFY2:
6531 WriteMessage("subtype = RFY2");
6532 break;
6533 case sTypeRFYext:
6534 WriteMessage("subtype = RFY-Ext");
6535 break;
6536 case sTypeASA:
6537 WriteMessage("subtype = ASA");
6538 break;
6539 default:
6540 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X:", pResponse->RFY.packettype, pResponse->RFY.subtype);
6541 WriteMessage(szTmp);
6542 break;
6543 }
6544 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFY.seqnbr);
6545 WriteMessage(szTmp);
6546
6547 sprintf(szTmp, "id1-3 = %02X%02X%02X", pResponse->RFY.id1, pResponse->RFY.id2, pResponse->RFY.id3);
6548 WriteMessage(szTmp);
6549
6550 if (pResponse->RFY.unitcode == 0)
6551 WriteMessage("Unit = All");
6552 else
6553 {
6554 sprintf(szTmp, "Unit = %d", pResponse->RFY.unitcode);
6555 WriteMessage(szTmp);
6556 }
6557
6558 sprintf(szTmp, "rfu1 = %02X", pResponse->RFY.rfu1);
6559 WriteMessage(szTmp);
6560 sprintf(szTmp, "rfu2 = %02X", pResponse->RFY.rfu2);
6561 WriteMessage(szTmp);
6562 sprintf(szTmp, "rfu3 = %02X", pResponse->RFY.rfu3);
6563 WriteMessage(szTmp);
6564
6565 WriteMessage("Command = ", false);
6566
6567 switch (pResponse->RFY.cmnd)
6568 {
6569 case rfy_sStop:
6570 WriteMessage("Stop");
6571 break;
6572 case rfy_sUp:
6573 WriteMessage("Up");
6574 break;
6575 case rfy_sUpStop:
6576 WriteMessage("Up + Stop");
6577 break;
6578 case rfy_sDown:
6579 WriteMessage("Down");
6580 break;
6581 case rfy_sDownStop:
6582 WriteMessage("Down + Stop");
6583 break;
6584 case rfy_sUpDown:
6585 WriteMessage("Up + Down");
6586 break;
6587 case rfy_sListRemotes:
6588 WriteMessage("List remotes");
6589 case rfy_sProgram:
6590 WriteMessage("Program");
6591 break;
6592 case rfy_s2SecProgram:
6593 WriteMessage("2 seconds: Program");
6594 break;
6595 case rfy_s7SecProgram:
6596 WriteMessage("7 seconds: Program");
6597 break;
6598 case rfy_s2SecStop:
6599 WriteMessage("2 seconds: Stop");
6600 break;
6601 case rfy_s5SecStop:
6602 WriteMessage("5 seconds: Stop");
6603 break;
6604 case rfy_s5SecUpDown:
6605 WriteMessage("5 seconds: Up + Down");
6606 break;
6607 case rfy_sEraseThis:
6608 WriteMessage("Erase this remote");
6609 break;
6610 case rfy_sEraseAll:
6611 WriteMessage("Erase all remotes");
6612 break;
6613 case rfy_s05SecUp:
6614 WriteMessage("< 0.5 seconds: up");
6615 break;
6616 case rfy_s05SecDown:
6617 WriteMessage("< 0.5 seconds: down");
6618 break;
6619 case rfy_s2SecUp:
6620 WriteMessage("> 2 seconds: up");
6621 break;
6622 case rfy_s2SecDown:
6623 WriteMessage("> 2 seconds: down");
6624 break;
6625 default:
6626 WriteMessage("UNKNOWN");
6627 break;
6628 }
6629 sprintf(szTmp, "Signal level = %d", pResponse->RFY.rssi);
6630 WriteMessage(szTmp);
6631 WriteMessageEnd();
6632 }
6633 procResult.DeviceRowIdx = DevRowIdx;
6634 }
6635
decode_evohome1(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)6636 void MainWorker::decode_evohome1(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
6637 {
6638 char szTmp[100];
6639 const _tEVOHOME1* pEvo = reinterpret_cast<const _tEVOHOME1*>(pResponse);
6640 uint8_t devType = pTypeEvohome;
6641 uint8_t subType = pEvo->subtype;
6642 std::stringstream szID;
6643 if (pHardware->HwdType == HTYPE_EVOHOME_SERIAL || pHardware->HwdType == HTYPE_EVOHOME_TCP)
6644 szID << std::hex << (int)RFX_GETID3(pEvo->id1, pEvo->id2, pEvo->id3);
6645 else //GB3: web based evohome uses decimal device ID's
6646 szID << std::dec << (int)RFX_GETID3(pEvo->id1, pEvo->id2, pEvo->id3);
6647 std::string ID(szID.str());
6648 uint8_t Unit = 0;
6649 uint8_t cmnd = pEvo->status;
6650 uint8_t SignalLevel = 255;//Unknown
6651 uint8_t BatteryLevel = 255;//Unknown
6652
6653 std::string szUntilDate;
6654 if (pEvo->mode == CEvohomeBase::cmTmp)//temporary
6655 szUntilDate = CEvohomeDateTime::GetISODate(pEvo);
6656
6657 CEvohomeBase* pEvoHW = (CEvohomeBase*)pHardware;
6658
6659 //FIXME A similar check is also done in switch modal do we want to forward the ooc flag and rely on this check entirely?
6660 std::vector<std::vector<std::string> > result;
6661 result = m_sql.safe_query(
6662 "SELECT HardwareID, DeviceID,Unit,Type,SubType,SwitchType,StrParam1,nValue,sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID == '%q')",
6663 pHardware->m_HwdID, ID.c_str());
6664 bool bNewDev = false;
6665 std::string name;
6666 if (!result.empty())
6667 {
6668 std::vector<std::string> sd = result[0];
6669 if (atoi(sd[7].c_str()) == cmnd && sd[8] == szUntilDate)
6670 return;
6671 }
6672 else
6673 {
6674 bNewDev = true;
6675 if (!pEvoHW)
6676 return;
6677 name = pEvoHW->GetControllerName();
6678 if (name.empty())
6679 return;
6680 }
6681
6682 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szUntilDate.c_str(), procResult.DeviceName, pEvo->action != 0);
6683 if (DevRowIdx == (uint64_t)-1)
6684 return;
6685 if (bNewDev)
6686 {
6687 m_sql.safe_query("UPDATE DeviceStatus SET Name='%q' WHERE (ID == %" PRIu64 ")",
6688 name.c_str(), DevRowIdx);
6689 procResult.DeviceName = name;
6690 }
6691
6692 CheckSceneCode(DevRowIdx, devType, subType, cmnd, "", procResult.DeviceName);
6693 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
6694 {
6695 WriteMessageStart();
6696 switch (pEvo->subtype)
6697 {
6698 case sTypeEvohome:
6699 WriteMessage("subtype = Evohome");
6700 break;
6701 default:
6702 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pEvo->type, pEvo->subtype);
6703 WriteMessage(szTmp);
6704 break;
6705 }
6706
6707 if (pHardware->HwdType == HTYPE_EVOHOME_SERIAL || pHardware->HwdType == HTYPE_EVOHOME_TCP)
6708 sprintf(szTmp, "id = %02X:%02X:%02X", pEvo->id1, pEvo->id2, pEvo->id3);
6709 else //GB3: web based evohome uses decimal device ID's
6710 sprintf(szTmp, "id = %u", (int)RFX_GETID3(pEvo->id1, pEvo->id2, pEvo->id3));
6711 WriteMessage(szTmp);
6712 sprintf(szTmp, "action = %d", (int)pEvo->action);
6713 WriteMessage(szTmp);
6714 WriteMessage("status = ");
6715 WriteMessage(pEvoHW->GetControllerModeName(pEvo->status));
6716
6717 WriteMessageEnd();
6718 }
6719 procResult.DeviceRowIdx = DevRowIdx;
6720 }
6721
decode_evohome2(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)6722 void MainWorker::decode_evohome2(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
6723 {
6724 char szTmp[100];
6725 const _tEVOHOME2* pEvo = reinterpret_cast<const _tEVOHOME2*>(pResponse);
6726 uint8_t cmnd = 0;
6727 uint8_t SignalLevel = 255;//Unknown
6728 uint8_t BatteryLevel = 255;//Unknown
6729
6730 //Get Device details
6731 std::vector<std::vector<std::string> > result;
6732 if (pEvo->type == pTypeEvohomeZone && pEvo->zone > 12) //Allow for additional Zone Temp devices which require DeviceID
6733 {
6734 result = m_sql.safe_query(
6735 "SELECT HardwareID, DeviceID,Unit,Type,SubType,sValue,BatteryLevel "
6736 "FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID == '%x') AND (Type==%d)",
6737 pHardware->m_HwdID, (int)RFX_GETID3(pEvo->id1, pEvo->id2, pEvo->id3), (int)pEvo->type);
6738 }
6739 else if (pEvo->zone)//if unit number is available the id3 will be the controller device id
6740 {
6741 result = m_sql.safe_query(
6742 "SELECT HardwareID, DeviceID,Unit,Type,SubType,sValue,BatteryLevel "
6743 "FROM DeviceStatus WHERE (HardwareID==%d) AND (Unit == %d) AND (Type==%d)",
6744 pHardware->m_HwdID, (int)pEvo->zone, (int)pEvo->type);
6745 }
6746 else//unit number not available then id3 should be the zone device id
6747 {
6748 result = m_sql.safe_query(
6749 "SELECT HardwareID, DeviceID,Unit,Type,SubType,sValue,BatteryLevel "
6750 "FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID == '%x') AND (Type==%d)",
6751 pHardware->m_HwdID, (int)RFX_GETID3(pEvo->id1, pEvo->id2, pEvo->id3), (int)pEvo->type);
6752 }
6753 if (result.size() < 1 && !pEvo->zone)
6754 return;
6755
6756 CEvohomeBase* pEvoHW = (CEvohomeBase*)pHardware;
6757 bool bNewDev = false;
6758 std::string name, szDevID;
6759 std::stringstream szID;
6760 uint8_t Unit;
6761 uint8_t dType;
6762 uint8_t dSubType;
6763 std::string szUpdateStat;
6764 if (!result.empty())
6765 {
6766 std::vector<std::string> sd = result[0];
6767 szDevID = sd[1];
6768 Unit = atoi(sd[2].c_str());
6769 dType = atoi(sd[3].c_str());
6770 dSubType = atoi(sd[4].c_str());
6771 szUpdateStat = sd[5];
6772 BatteryLevel = atoi(sd[6].c_str());
6773 }
6774 else
6775 {
6776 bNewDev = true;
6777 Unit = pEvo->zone;//should always be non zero
6778 dType = pEvo->type;
6779 dSubType = pEvo->subtype;
6780
6781 szID << std::hex << (int)RFX_GETID3(pEvo->id1, pEvo->id2, pEvo->id3);
6782 szDevID = szID.str();
6783
6784 if (!pEvoHW)
6785 return;
6786 if (dType == pTypeEvohomeWater)
6787 name = "Hot Water";
6788 else if (dType == pTypeEvohomeZone && !szDevID.empty())
6789 name = "Zone Temp";
6790 else
6791 name = pEvoHW->GetZoneName(Unit - 1);
6792 if (name.empty())
6793 return;
6794 szUpdateStat = "0.0;0.0;Auto";
6795 }
6796
6797 if (pEvo->updatetype == CEvohomeBase::updBattery)
6798 BatteryLevel = pEvo->battery_level;
6799 else
6800 {
6801 if (dType == pTypeEvohomeWater && pEvo->updatetype == pEvoHW->updSetPoint)
6802 sprintf(szTmp, "%s", pEvo->temperature ? "On" : "Off");
6803 else
6804 sprintf(szTmp, "%.2f", pEvo->temperature / 100.0f);
6805
6806 std::vector<std::string> strarray;
6807 StringSplit(szUpdateStat, ";", strarray);
6808 if (strarray.size() >= 3)
6809 {
6810 if (pEvo->updatetype == pEvoHW->updSetPoint)//SetPoint
6811 {
6812 strarray[1] = szTmp;
6813 if (pEvo->mode <= pEvoHW->zmTmp)//for the moment only update this if we get a valid setpoint mode as we can now send setpoint on its own
6814 {
6815 int nControllerMode = pEvo->controllermode;
6816 if (dType == pTypeEvohomeWater && (nControllerMode == pEvoHW->cmEvoHeatingOff || nControllerMode == pEvoHW->cmEvoAutoWithEco || nControllerMode == pEvoHW->cmEvoCustom))//dhw has no economy mode and does not turn off for heating off also appears custom does not support the dhw zone
6817 nControllerMode = pEvoHW->cmEvoAuto;
6818 if (pEvo->mode == pEvoHW->zmAuto || nControllerMode == pEvoHW->cmEvoHeatingOff)//if zonemode is auto (followschedule) or controllermode is heatingoff
6819 strarray[2] = pEvoHW->GetWebAPIModeName(nControllerMode);//the web front end ultimately uses these names for images etc.
6820 else
6821 strarray[2] = pEvoHW->GetZoneModeName(pEvo->mode);
6822 if (pEvo->mode == pEvoHW->zmTmp)
6823 {
6824 std::string szISODate(CEvohomeDateTime::GetISODate(pEvo));
6825 if (strarray.size() < 4) //add or set until
6826 strarray.push_back(szISODate);
6827 else
6828 strarray[3] = szISODate;
6829 }
6830 else if ((pEvo->mode == pEvoHW->zmAuto) && (pHardware->HwdType == HTYPE_EVOHOME_WEB))
6831 {
6832 strarray[2] = "FollowSchedule";
6833 if ((pEvo->year != 0) && (pEvo->year != 0xFFFF))
6834 {
6835 std::string szISODate(CEvohomeDateTime::GetISODate(pEvo));
6836 if (strarray.size() < 4) //add or set until
6837 strarray.push_back(szISODate);
6838 else
6839 strarray[3] = szISODate;
6840 }
6841
6842 }
6843 else
6844 if (strarray.size() >= 4) //remove until
6845 strarray.resize(3);
6846 }
6847 }
6848 else if (pEvo->updatetype == pEvoHW->updOverride)
6849 {
6850 strarray[2] = pEvoHW->GetZoneModeName(pEvo->mode);
6851 if (strarray.size() >= 4) //remove until
6852 strarray.resize(3);
6853 }
6854 else
6855 strarray[0] = szTmp;
6856 szUpdateStat = boost::algorithm::join(strarray, ";");
6857 }
6858 }
6859 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, szDevID.c_str(), Unit, dType, dSubType, SignalLevel, BatteryLevel, cmnd, szUpdateStat.c_str(), procResult.DeviceName);
6860 if (DevRowIdx == (uint64_t)-1)
6861 return;
6862 if (bNewDev)
6863 {
6864 m_sql.safe_query("UPDATE DeviceStatus SET Name='%q' WHERE (ID == %" PRIu64 ")",
6865 name.c_str(), DevRowIdx);
6866 procResult.DeviceName = name;
6867 }
6868 procResult.DeviceRowIdx = DevRowIdx;
6869 }
6870
decode_evohome3(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)6871 void MainWorker::decode_evohome3(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
6872 {
6873 char szTmp[100];
6874 const _tEVOHOME3* pEvo = reinterpret_cast<const _tEVOHOME3*>(pResponse);
6875 uint8_t devType = pTypeEvohomeRelay;
6876 uint8_t subType = pEvo->subtype;
6877 std::stringstream szID;
6878 int nDevID = (int)RFX_GETID3(pEvo->id1, pEvo->id2, pEvo->id3);
6879 szID << std::hex << nDevID;
6880 std::string ID(szID.str());
6881 uint8_t Unit = pEvo->devno;
6882 uint8_t cmnd = (pEvo->demand > 0) ? light1_sOn : light1_sOff;
6883 sprintf(szTmp, "%d", pEvo->demand);
6884 std::string szDemand(szTmp);
6885 uint8_t SignalLevel = 255;//Unknown
6886 uint8_t BatteryLevel = 255;//Unknown
6887
6888 if (Unit == 0xFF && nDevID == 0)
6889 return;
6890 //Get Device details (devno or devid not available)
6891 bool bNewDev = false;
6892 std::vector<std::vector<std::string> > result;
6893 if (Unit == 0xFF)
6894 result = m_sql.safe_query(
6895 "SELECT HardwareID,DeviceID,Unit,Type,SubType,nValue,sValue,BatteryLevel "
6896 "FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID == '%q')",
6897 pHardware->m_HwdID, ID.c_str());
6898 else
6899 result = m_sql.safe_query(
6900 "SELECT HardwareID,DeviceID,Unit,Type,SubType,nValue,sValue,BatteryLevel "
6901 "FROM DeviceStatus WHERE (HardwareID==%d) AND (Unit == '%d') AND (Type==%d) AND (DeviceID == '%q')",
6902 pHardware->m_HwdID, (int)Unit, (int)pEvo->type, ID.c_str());
6903 if (!result.empty())
6904 {
6905 if (pEvo->demand == 0xFF)//we sometimes get a 0418 message after the initial device creation but it will mess up the logging as we don't have a demand
6906 return;
6907 uint8_t cur_cmnd = atoi(result[0][5].c_str());
6908 BatteryLevel = atoi(result[0][7].c_str());
6909
6910 if (pEvo->updatetype == CEvohomeBase::updBattery)
6911 {
6912 BatteryLevel = pEvo->battery_level;
6913 szDemand = result[0][6];
6914 cmnd = (atoi(szDemand.c_str()) > 0) ? light1_sOn : light1_sOff;
6915 }
6916 if (Unit == 0xFF)
6917 {
6918 Unit = atoi(result[0][2].c_str());
6919 szDemand = result[0][6];
6920 if (cmnd == cur_cmnd)
6921 return;
6922 }
6923 else if (nDevID == 0)
6924 {
6925 ID = result[0][1];
6926 }
6927 }
6928 else
6929 {
6930 if (Unit == 0xFF || (nDevID == 0 && Unit > 12))
6931 return;
6932 bNewDev = true;
6933 if (pEvo->demand == 0xFF)//0418 allows us to associate unit and deviceid but no state information other messages only contain one or the other
6934 szDemand = "0";
6935 if (pEvo->updatetype == CEvohomeBase::updBattery)
6936 BatteryLevel = pEvo->battery_level;
6937 }
6938
6939 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szDemand.c_str(), procResult.DeviceName);
6940 if (DevRowIdx == (uint64_t)-1)
6941 return;
6942
6943 if (bNewDev && (Unit == 0xF9 || Unit == 0xFA || Unit == 0xFC || Unit <= 12))
6944 {
6945 if (Unit == 0xF9)
6946 procResult.DeviceName = "CH Valve";
6947 else if (Unit == 0xFA)
6948 procResult.DeviceName = "DHW Valve";
6949 else if (Unit == 0xFC)
6950 {
6951 if (pEvo->id1 >> 2 == CEvohomeID::devBridge) // Evohome OT Bridge
6952 procResult.DeviceName = "Boiler (OT Bridge)";
6953 else
6954 procResult.DeviceName = "Boiler";
6955 }
6956 else if (Unit <= 12)
6957 procResult.DeviceName = "Zone";
6958 std::vector<std::vector<std::string> > result;
6959 result = m_sql.safe_query(
6960 "UPDATE DeviceStatus SET Name='%q' WHERE (ID == %" PRIu64 ")",
6961 procResult.DeviceName.c_str(), DevRowIdx);
6962 }
6963
6964 CheckSceneCode(DevRowIdx, devType, subType, cmnd, "", procResult.DeviceName);
6965 procResult.DeviceRowIdx = DevRowIdx;
6966 }
6967
decode_Security1(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)6968 void MainWorker::decode_Security1(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
6969 {
6970 char szTmp[100];
6971 uint8_t devType = pTypeSecurity1;
6972 uint8_t subType = pResponse->SECURITY1.subtype;
6973 std::string ID;
6974 sprintf(szTmp, "%02X%02X%02X", pResponse->SECURITY1.id1, pResponse->SECURITY1.id2, pResponse->SECURITY1.id3);
6975 ID = szTmp;
6976 uint8_t Unit = 0;
6977 uint8_t cmnd = pResponse->SECURITY1.status;
6978 uint8_t SignalLevel = pResponse->SECURITY1.rssi;
6979 uint8_t BatteryLevel = get_BateryLevel(pHardware->HwdType, false, pResponse->SECURITY1.battery_level & 0x0F);
6980 if (
6981 (pResponse->SECURITY1.subtype == sTypeKD101) ||
6982 (pResponse->SECURITY1.subtype == sTypeSA30) ||
6983 (pResponse->SECURITY1.subtype == sTypeRM174RF) ||
6984 (pResponse->SECURITY1.subtype == sTypeDomoticzSecurity)
6985 )
6986 {
6987 //KD101 & SA30 do not support battery low indication
6988 BatteryLevel = 255;
6989 }
6990
6991 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, procResult.DeviceName);
6992 if (DevRowIdx == (uint64_t)-1)
6993 return;
6994 CheckSceneCode(DevRowIdx, devType, subType, cmnd, "", procResult.DeviceName);
6995
6996 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
6997 {
6998 WriteMessageStart();
6999 switch (pResponse->SECURITY1.subtype)
7000 {
7001 case sTypeSecX10:
7002 WriteMessage("subtype = X10 security");
7003 break;
7004 case sTypeSecX10M:
7005 WriteMessage("subtype = X10 security motion");
7006 break;
7007 case sTypeSecX10R:
7008 WriteMessage("subtype = X10 security remote");
7009 break;
7010 case sTypeKD101:
7011 WriteMessage("subtype = KD101 smoke detector");
7012 break;
7013 case sTypePowercodeSensor:
7014 WriteMessage("subtype = Visonic PowerCode sensor - primary contact");
7015 break;
7016 case sTypePowercodeMotion:
7017 WriteMessage("subtype = Visonic PowerCode motion");
7018 break;
7019 case sTypeCodesecure:
7020 WriteMessage("subtype = Visonic CodeSecure");
7021 break;
7022 case sTypePowercodeAux:
7023 WriteMessage("subtype = Visonic PowerCode sensor - auxiliary contact");
7024 break;
7025 case sTypeMeiantech:
7026 WriteMessage("subtype = Meiantech/Atlantic/Aidebao");
7027 break;
7028 case sTypeSA30:
7029 WriteMessage("subtype = Alecto SA30 smoke detector");
7030 break;
7031 case sTypeDomoticzSecurity:
7032 WriteMessage("subtype = Security Panel");
7033 break;
7034 default:
7035 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->SECURITY1.packettype, pResponse->SECURITY1.subtype);
7036 WriteMessage(szTmp);
7037 break;
7038 }
7039
7040 sprintf(szTmp, "Sequence nbr = %d", pResponse->SECURITY1.seqnbr);
7041 WriteMessage(szTmp);
7042 sprintf(szTmp, "id1-3 = %02X:%02X:%02X", pResponse->SECURITY1.id1, pResponse->SECURITY1.id2, pResponse->SECURITY1.id3);
7043 WriteMessage(szTmp);
7044
7045 WriteMessage("status = ", false);
7046
7047 switch (pResponse->SECURITY1.status)
7048 {
7049 case sStatusNormal:
7050 WriteMessage("Normal");
7051 break;
7052 case sStatusNormalDelayed:
7053 WriteMessage("Normal Delayed");
7054 break;
7055 case sStatusAlarm:
7056 WriteMessage("Alarm");
7057 break;
7058 case sStatusAlarmDelayed:
7059 WriteMessage("Alarm Delayed");
7060 break;
7061 case sStatusMotion:
7062 WriteMessage("Motion");
7063 break;
7064 case sStatusNoMotion:
7065 WriteMessage("No Motion");
7066 break;
7067 case sStatusPanic:
7068 WriteMessage("Panic");
7069 break;
7070 case sStatusPanicOff:
7071 WriteMessage("Panic End");
7072 break;
7073 case sStatusArmAway:
7074 if (pResponse->SECURITY1.subtype == sTypeMeiantech)
7075 WriteMessage("Group2 or ", false);
7076 WriteMessage("Arm Away");
7077 break;
7078 case sStatusArmAwayDelayed:
7079 WriteMessage("Arm Away Delayed");
7080 break;
7081 case sStatusArmHome:
7082 if (pResponse->SECURITY1.subtype == sTypeMeiantech)
7083 WriteMessage("Group3 or ", false);
7084 WriteMessage("Arm Home");
7085 break;
7086 case sStatusArmHomeDelayed:
7087 WriteMessage("Arm Home Delayed");
7088 break;
7089 case sStatusDisarm:
7090 if (pResponse->SECURITY1.subtype == sTypeMeiantech)
7091 WriteMessage("Group1 or ", false);
7092 WriteMessage("Disarm");
7093 break;
7094 case sStatusLightOff:
7095 WriteMessage("Light Off");
7096 break;
7097 case sStatusLightOn:
7098 WriteMessage("Light On");
7099 break;
7100 case sStatusLight2Off:
7101 WriteMessage("Light 2 Off");
7102 break;
7103 case sStatusLight2On:
7104 WriteMessage("Light 2 On");
7105 break;
7106 case sStatusDark:
7107 WriteMessage("Dark detected");
7108 break;
7109 case sStatusLight:
7110 WriteMessage("Light Detected");
7111 break;
7112 case sStatusBatLow:
7113 WriteMessage("Battery low MS10 or XX18 sensor");
7114 break;
7115 case sStatusPairKD101:
7116 WriteMessage("Pair KD101");
7117 break;
7118 case sStatusNormalTamper:
7119 WriteMessage("Normal + Tamper");
7120 break;
7121 case sStatusNormalDelayedTamper:
7122 WriteMessage("Normal Delayed + Tamper");
7123 break;
7124 case sStatusAlarmTamper:
7125 WriteMessage("Alarm + Tamper");
7126 break;
7127 case sStatusAlarmDelayedTamper:
7128 WriteMessage("Alarm Delayed + Tamper");
7129 break;
7130 case sStatusMotionTamper:
7131 WriteMessage("Motion + Tamper");
7132 break;
7133 case sStatusNoMotionTamper:
7134 WriteMessage("No Motion + Tamper");
7135 break;
7136 }
7137
7138 if (
7139 (pResponse->SECURITY1.subtype != sTypeKD101) && //KD101 & SA30 does not support battery low indication
7140 (pResponse->SECURITY1.subtype != sTypeSA30)
7141 )
7142 {
7143 if ((pResponse->SECURITY1.battery_level & 0xF) == 0)
7144 WriteMessage("battery level = Low");
7145 else
7146 WriteMessage("battery level = OK");
7147 }
7148 sprintf(szTmp, "Signal level = %d", pResponse->SECURITY1.rssi);
7149 WriteMessage(szTmp);
7150 WriteMessageEnd();
7151 }
7152 procResult.DeviceRowIdx = DevRowIdx;
7153 }
7154
decode_Security2(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)7155 void MainWorker::decode_Security2(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
7156 {
7157 char szTmp[100];
7158 uint8_t devType = pTypeSecurity2;
7159 uint8_t subType = pResponse->SECURITY2.subtype;
7160 std::string ID;
7161 sprintf(szTmp, "%02X%02X%02X%02X%02X%02X%02X%02X", pResponse->SECURITY2.id1, pResponse->SECURITY2.id2, pResponse->SECURITY2.id3, pResponse->SECURITY2.id4, pResponse->SECURITY2.id5, pResponse->SECURITY2.id6, pResponse->SECURITY2.id7, pResponse->SECURITY2.id8);
7162 ID = szTmp;
7163 uint8_t Unit = 0;
7164 uint8_t cmnd = 0;// pResponse->SECURITY2.cmnd;
7165 uint8_t SignalLevel = pResponse->SECURITY2.rssi;
7166 uint8_t BatteryLevel = get_BateryLevel(pHardware->HwdType, false, pResponse->SECURITY2.battery_level & 0x0F);
7167
7168 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, procResult.DeviceName);
7169 if (DevRowIdx == (uint64_t)-1)
7170 return;
7171 CheckSceneCode(DevRowIdx, devType, subType, cmnd, "", procResult.DeviceName);
7172
7173 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
7174 {
7175 WriteMessageStart();
7176 switch (pResponse->SECURITY2.subtype)
7177 {
7178 case sTypeSec2Classic:
7179 WriteMessage("subtype = Keeloq Classic");
7180 break;
7181 default:
7182 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->SECURITY2.packettype, pResponse->SECURITY2.subtype);
7183 WriteMessage(szTmp);
7184 break;
7185 }
7186
7187 sprintf(szTmp, "Sequence nbr = %d", pResponse->SECURITY2.seqnbr);
7188 WriteMessage(szTmp);
7189 sprintf(szTmp, "id1-8 = %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", pResponse->SECURITY2.id1, pResponse->SECURITY2.id2, pResponse->SECURITY2.id3, pResponse->SECURITY2.id4, pResponse->SECURITY2.id5, pResponse->SECURITY2.id6, pResponse->SECURITY2.id7, pResponse->SECURITY2.id8);
7190 WriteMessage(szTmp);
7191
7192 if ((pResponse->SECURITY2.battery_level & 0xF) == 0)
7193 WriteMessage("battery level = Low");
7194 else
7195 WriteMessage("battery level = OK");
7196
7197 sprintf(szTmp, "Signal level = %d", pResponse->SECURITY2.rssi);
7198 WriteMessage(szTmp);
7199 WriteMessageEnd();
7200 }
7201 procResult.DeviceRowIdx = DevRowIdx;
7202 }
7203
7204 //not in dbase yet
decode_Camera1(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)7205 void MainWorker::decode_Camera1(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
7206 {
7207 WriteMessage("");
7208
7209 //uint8_t devType=pTypeCamera;
7210
7211 char szTmp[100];
7212
7213 switch (pResponse->CAMERA1.subtype)
7214 {
7215 case sTypeNinja:
7216 WriteMessage("subtype = X10 Ninja/Robocam");
7217 sprintf(szTmp, "Sequence nbr = %d", pResponse->CAMERA1.seqnbr);
7218 WriteMessage(szTmp);
7219
7220 WriteMessage("Command = ", false);
7221
7222 switch (pResponse->CAMERA1.cmnd)
7223 {
7224 case camera_sLeft:
7225 WriteMessage("Left");
7226 break;
7227 case camera_sRight:
7228 WriteMessage("Right");
7229 break;
7230 case camera_sUp:
7231 WriteMessage("Up");
7232 break;
7233 case camera_sDown:
7234 WriteMessage("Down");
7235 break;
7236 case camera_sPosition1:
7237 WriteMessage("Position 1");
7238 break;
7239 case camera_sProgramPosition1:
7240 WriteMessage("Position 1 program");
7241 break;
7242 case camera_sPosition2:
7243 WriteMessage("Position 2");
7244 break;
7245 case camera_sProgramPosition2:
7246 WriteMessage("Position 2 program");
7247 break;
7248 case camera_sPosition3:
7249 WriteMessage("Position 3");
7250 break;
7251 case camera_sProgramPosition3:
7252 WriteMessage("Position 3 program");
7253 break;
7254 case camera_sPosition4:
7255 WriteMessage("Position 4");
7256 break;
7257 case camera_sProgramPosition4:
7258 WriteMessage("Position 4 program");
7259 break;
7260 case camera_sCenter:
7261 WriteMessage("Center");
7262 break;
7263 case camera_sProgramCenterPosition:
7264 WriteMessage("Center program");
7265 break;
7266 case camera_sSweep:
7267 WriteMessage("Sweep");
7268 break;
7269 case camera_sProgramSweep:
7270 WriteMessage("Sweep program");
7271 break;
7272 default:
7273 WriteMessage("UNKNOWN");
7274 break;
7275 }
7276 sprintf(szTmp, "Housecode = %d", pResponse->CAMERA1.housecode);
7277 WriteMessage(szTmp);
7278 break;
7279 default:
7280 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->CAMERA1.packettype, pResponse->CAMERA1.subtype);
7281 WriteMessage(szTmp);
7282 break;
7283 }
7284 sprintf(szTmp, "Signal level = %d", pResponse->CAMERA1.rssi);
7285 WriteMessage(szTmp);
7286 procResult.DeviceRowIdx = -1;
7287 }
7288
decode_Remote(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)7289 void MainWorker::decode_Remote(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
7290 {
7291 char szTmp[100];
7292 uint8_t devType = pTypeRemote;
7293 uint8_t subType = pResponse->REMOTE.subtype;
7294 sprintf(szTmp, "%d", pResponse->REMOTE.id);
7295 std::string ID = szTmp;
7296 uint8_t Unit = pResponse->REMOTE.cmnd;
7297 uint8_t cmnd = light2_sOn;
7298 uint8_t SignalLevel = pResponse->REMOTE.rssi;
7299
7300 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, procResult.DeviceName);
7301 if (DevRowIdx == (uint64_t)-1)
7302 return;
7303 CheckSceneCode(DevRowIdx, devType, subType, cmnd, "", procResult.DeviceName);
7304
7305 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
7306 {
7307 WriteMessageStart();
7308 switch (pResponse->REMOTE.subtype)
7309 {
7310 case sTypeATI:
7311 WriteMessage("subtype = ATI Remote Wonder");
7312 sprintf(szTmp, "Sequence nbr = %d", pResponse->REMOTE.seqnbr);
7313 WriteMessage(szTmp);
7314 sprintf(szTmp, "ID = %d", pResponse->REMOTE.id);
7315 WriteMessage(szTmp);
7316 switch (pResponse->REMOTE.cmnd)
7317 {
7318 case 0x0:
7319 WriteMessage("Command = A");
7320 break;
7321 case 0x1:
7322 WriteMessage("Command = B");
7323 break;
7324 case 0x2:
7325 WriteMessage("Command = power");
7326 break;
7327 case 0x3:
7328 WriteMessage("Command = TV");
7329 break;
7330 case 0x4:
7331 WriteMessage("Command = DVD");
7332 break;
7333 case 0x5:
7334 WriteMessage("Command = ?");
7335 break;
7336 case 0x6:
7337 WriteMessage("Command = Guide");
7338 break;
7339 case 0x7:
7340 WriteMessage("Command = Drag");
7341 break;
7342 case 0x8:
7343 WriteMessage("Command = VOL+");
7344 break;
7345 case 0x9:
7346 WriteMessage("Command = VOL-");
7347 break;
7348 case 0xA:
7349 WriteMessage("Command = MUTE");
7350 break;
7351 case 0xB:
7352 WriteMessage("Command = CHAN+");
7353 break;
7354 case 0xC:
7355 WriteMessage("Command = CHAN-");
7356 break;
7357 case 0xD:
7358 WriteMessage("Command = 1");
7359 break;
7360 case 0xE:
7361 WriteMessage("Command = 2");
7362 break;
7363 case 0xF:
7364 WriteMessage("Command = 3");
7365 break;
7366 case 0x10:
7367 WriteMessage("Command = 4");
7368 break;
7369 case 0x11:
7370 WriteMessage("Command = 5");
7371 break;
7372 case 0x12:
7373 WriteMessage("Command = 6");
7374 break;
7375 case 0x13:
7376 WriteMessage("Command = 7");
7377 break;
7378 case 0x14:
7379 WriteMessage("Command = 8");
7380 break;
7381 case 0x15:
7382 WriteMessage("Command = 9");
7383 break;
7384 case 0x16:
7385 WriteMessage("Command = txt");
7386 break;
7387 case 0x17:
7388 WriteMessage("Command = 0");
7389 break;
7390 case 0x18:
7391 WriteMessage("Command = snapshot ESC");
7392 break;
7393 case 0x19:
7394 WriteMessage("Command = C");
7395 break;
7396 case 0x1A:
7397 WriteMessage("Command = ^");
7398 break;
7399 case 0x1B:
7400 WriteMessage("Command = D");
7401 break;
7402 case 0x1C:
7403 WriteMessage("Command = TV/RADIO");
7404 break;
7405 case 0x1D:
7406 WriteMessage("Command = <");
7407 break;
7408 case 0x1E:
7409 WriteMessage("Command = OK");
7410 break;
7411 case 0x1F:
7412 WriteMessage("Command = >");
7413 break;
7414 case 0x20:
7415 WriteMessage("Command = <-");
7416 break;
7417 case 0x21:
7418 WriteMessage("Command = E");
7419 break;
7420 case 0x22:
7421 WriteMessage("Command = v");
7422 break;
7423 case 0x23:
7424 WriteMessage("Command = F");
7425 break;
7426 case 0x24:
7427 WriteMessage("Command = Rewind");
7428 break;
7429 case 0x25:
7430 WriteMessage("Command = Play");
7431 break;
7432 case 0x26:
7433 WriteMessage("Command = Fast forward");
7434 break;
7435 case 0x27:
7436 WriteMessage("Command = Record");
7437 break;
7438 case 0x28:
7439 WriteMessage("Command = Stop");
7440 break;
7441 case 0x29:
7442 WriteMessage("Command = Pause");
7443 break;
7444 case 0x2C:
7445 WriteMessage("Command = TV");
7446 break;
7447 case 0x2D:
7448 WriteMessage("Command = VCR");
7449 break;
7450 case 0x2E:
7451 WriteMessage("Command = RADIO");
7452 break;
7453 case 0x2F:
7454 WriteMessage("Command = TV Preview");
7455 break;
7456 case 0x30:
7457 WriteMessage("Command = Channel list");
7458 break;
7459 case 0x31:
7460 WriteMessage("Command = Video Desktop");
7461 break;
7462 case 0x32:
7463 WriteMessage("Command = red");
7464 break;
7465 case 0x33:
7466 WriteMessage("Command = green");
7467 break;
7468 case 0x34:
7469 WriteMessage("Command = yellow");
7470 break;
7471 case 0x35:
7472 WriteMessage("Command = blue");
7473 break;
7474 case 0x36:
7475 WriteMessage("Command = rename TAB");
7476 break;
7477 case 0x37:
7478 WriteMessage("Command = Acquire image");
7479 break;
7480 case 0x38:
7481 WriteMessage("Command = edit image");
7482 break;
7483 case 0x39:
7484 WriteMessage("Command = Full screen");
7485 break;
7486 case 0x3A:
7487 WriteMessage("Command = DVD Audio");
7488 break;
7489 case 0x70:
7490 WriteMessage("Command = Cursor-left");
7491 break;
7492 case 0x71:
7493 WriteMessage("Command = Cursor-right");
7494 break;
7495 case 0x72:
7496 WriteMessage("Command = Cursor-up");
7497 break;
7498 case 0x73:
7499 WriteMessage("Command = Cursor-down");
7500 break;
7501 case 0x74:
7502 WriteMessage("Command = Cursor-up-left");
7503 break;
7504 case 0x75:
7505 WriteMessage("Command = Cursor-up-right");
7506 break;
7507 case 0x76:
7508 WriteMessage("Command = Cursor-down-right");
7509 break;
7510 case 0x77:
7511 WriteMessage("Command = Cursor-down-left");
7512 break;
7513 case 0x78:
7514 WriteMessage("Command = V");
7515 break;
7516 case 0x79:
7517 WriteMessage("Command = V-End");
7518 break;
7519 case 0x7C:
7520 WriteMessage("Command = X");
7521 break;
7522 case 0x7D:
7523 WriteMessage("Command = X-End");
7524 break;
7525 default:
7526 WriteMessage("Command = unknown");
7527 break;
7528 }
7529 break;
7530 case sTypeATIplus:
7531 WriteMessage("subtype = ATI Remote Wonder Plus");
7532 sprintf(szTmp, "Sequence nbr = %d", pResponse->REMOTE.seqnbr);
7533 WriteMessage(szTmp);
7534 sprintf(szTmp, "ID = %d", pResponse->REMOTE.id);
7535 WriteMessage(szTmp);
7536
7537 WriteMessage("Command = ", false);
7538 switch (pResponse->REMOTE.cmnd)
7539 {
7540 case 0x0:
7541 WriteMessage("A", false);
7542 break;
7543 case 0x1:
7544 WriteMessage("B", false);
7545 break;
7546 case 0x2:
7547 WriteMessage("power", false);
7548 break;
7549 case 0x3:
7550 WriteMessage("TV", false);
7551 break;
7552 case 0x4:
7553 WriteMessage("DVD", false);
7554 break;
7555 case 0x5:
7556 WriteMessage("?", false);
7557 break;
7558 case 0x6:
7559 WriteMessage("Guide", false);
7560 break;
7561 case 0x7:
7562 WriteMessage("Drag", false);
7563 break;
7564 case 0x8:
7565 WriteMessage("VOL+", false);
7566 break;
7567 case 0x9:
7568 WriteMessage("VOL-", false);
7569 break;
7570 case 0xA:
7571 WriteMessage("MUTE", false);
7572 break;
7573 case 0xB:
7574 WriteMessage("CHAN+", false);
7575 break;
7576 case 0xC:
7577 WriteMessage("CHAN-", false);
7578 break;
7579 case 0xD:
7580 WriteMessage("1", false);
7581 break;
7582 case 0xE:
7583 WriteMessage("2", false);
7584 break;
7585 case 0xF:
7586 WriteMessage("3", false);
7587 break;
7588 case 0x10:
7589 WriteMessage("4", false);
7590 break;
7591 case 0x11:
7592 WriteMessage("5", false);
7593 break;
7594 case 0x12:
7595 WriteMessage("6", false);
7596 break;
7597 case 0x13:
7598 WriteMessage("7", false);
7599 break;
7600 case 0x14:
7601 WriteMessage("8", false);
7602 break;
7603 case 0x15:
7604 WriteMessage("9", false);
7605 break;
7606 case 0x16:
7607 WriteMessage("txt", false);
7608 break;
7609 case 0x17:
7610 WriteMessage("0", false);
7611 break;
7612 case 0x18:
7613 WriteMessage("Open Setup Menu", false);
7614 break;
7615 case 0x19:
7616 WriteMessage("C", false);
7617 break;
7618 case 0x1A:
7619 WriteMessage("^", false);
7620 break;
7621 case 0x1B:
7622 WriteMessage("D", false);
7623 break;
7624 case 0x1C:
7625 WriteMessage("FM", false);
7626 break;
7627 case 0x1D:
7628 WriteMessage("<", false);
7629 break;
7630 case 0x1E:
7631 WriteMessage("OK", false);
7632 break;
7633 case 0x1F:
7634 WriteMessage(">", false);
7635 break;
7636 case 0x20:
7637 WriteMessage("Max/Restore window", false);
7638 break;
7639 case 0x21:
7640 WriteMessage("E", false);
7641 break;
7642 case 0x22:
7643 WriteMessage("v", false);
7644 break;
7645 case 0x23:
7646 WriteMessage("F", false);
7647 break;
7648 case 0x24:
7649 WriteMessage("Rewind", false);
7650 break;
7651 case 0x25:
7652 WriteMessage("Play", false);
7653 break;
7654 case 0x26:
7655 WriteMessage("Fast forward", false);
7656 break;
7657 case 0x27:
7658 WriteMessage("Record", false);
7659 break;
7660 case 0x28:
7661 WriteMessage("Stop", false);
7662 break;
7663 case 0x29:
7664 WriteMessage("Pause", false);
7665 break;
7666 case 0x2A:
7667 WriteMessage("TV2", false);
7668 break;
7669 case 0x2B:
7670 WriteMessage("Clock", false);
7671 break;
7672 case 0x2C:
7673 WriteMessage("i", false);
7674 break;
7675 case 0x2D:
7676 WriteMessage("ATI", false);
7677 break;
7678 case 0x2E:
7679 WriteMessage("RADIO", false);
7680 break;
7681 case 0x2F:
7682 WriteMessage("TV Preview", false);
7683 break;
7684 case 0x30:
7685 WriteMessage("Channel list", false);
7686 break;
7687 case 0x31:
7688 WriteMessage("Video Desktop", false);
7689 break;
7690 case 0x32:
7691 WriteMessage("red", false);
7692 break;
7693 case 0x33:
7694 WriteMessage("green", false);
7695 break;
7696 case 0x34:
7697 WriteMessage("yellow", false);
7698 break;
7699 case 0x35:
7700 WriteMessage("blue", false);
7701 break;
7702 case 0x36:
7703 WriteMessage("rename TAB", false);
7704 break;
7705 case 0x37:
7706 WriteMessage("Acquire image", false);
7707 break;
7708 case 0x38:
7709 WriteMessage("edit image", false);
7710 break;
7711 case 0x39:
7712 WriteMessage("Full screen", false);
7713 break;
7714 case 0x3A:
7715 WriteMessage("DVD Audio", false);
7716 break;
7717 case 0x70:
7718 WriteMessage("Cursor-left", false);
7719 break;
7720 case 0x71:
7721 WriteMessage("Cursor-right", false);
7722 break;
7723 case 0x72:
7724 WriteMessage("Cursor-up", false);
7725 break;
7726 case 0x73:
7727 WriteMessage("Cursor-down", false);
7728 break;
7729 case 0x74:
7730 WriteMessage("Cursor-up-left", false);
7731 break;
7732 case 0x75:
7733 WriteMessage("Cursor-up-right", false);
7734 break;
7735 case 0x76:
7736 WriteMessage("Cursor-down-right", false);
7737 break;
7738 case 0x77:
7739 WriteMessage("Cursor-down-left", false);
7740 break;
7741 case 0x78:
7742 WriteMessage("Left Mouse Button", false);
7743 break;
7744 case 0x79:
7745 WriteMessage("V-End", false);
7746 break;
7747 case 0x7C:
7748 WriteMessage("Right Mouse Button", false);
7749 break;
7750 case 0x7D:
7751 WriteMessage("X-End", false);
7752 break;
7753 default:
7754 WriteMessage("unknown", false);
7755 break;
7756 }
7757 if ((pResponse->REMOTE.toggle & 1) == 1)
7758 WriteMessage(" (button press = odd)");
7759 else
7760 WriteMessage(" (button press = even)");
7761 break;
7762 case sTypeATIrw2:
7763 WriteMessage("subtype = ATI Remote Wonder II");
7764 sprintf(szTmp, "Sequence nbr = %d", pResponse->REMOTE.seqnbr);
7765 WriteMessage(szTmp);
7766 sprintf(szTmp, "ID = %d", pResponse->REMOTE.id);
7767 WriteMessage(szTmp);
7768 WriteMessage("Command type = ", false);
7769
7770 switch (pResponse->REMOTE.cmndtype & 0x0E)
7771 {
7772 case 0x0:
7773 WriteMessage("PC");
7774 break;
7775 case 0x2:
7776 WriteMessage("AUX1");
7777 break;
7778 case 0x4:
7779 WriteMessage("AUX2");
7780 break;
7781 case 0x6:
7782 WriteMessage("AUX3");
7783 break;
7784 case 0x8:
7785 WriteMessage("AUX4");
7786 break;
7787 default:
7788 WriteMessage("unknown");
7789 break;
7790 }
7791 WriteMessage("Command = ", false);
7792 switch (pResponse->REMOTE.cmnd)
7793 {
7794 case 0x0:
7795 WriteMessage("A", false);
7796 break;
7797 case 0x1:
7798 WriteMessage("B", false);
7799 break;
7800 case 0x2:
7801 WriteMessage("power", false);
7802 break;
7803 case 0x3:
7804 WriteMessage("TV", false);
7805 break;
7806 case 0x4:
7807 WriteMessage("DVD", false);
7808 break;
7809 case 0x5:
7810 WriteMessage("?", false);
7811 break;
7812 case 0x7:
7813 WriteMessage("Drag", false);
7814 break;
7815 case 0x8:
7816 WriteMessage("VOL+", false);
7817 break;
7818 case 0x9:
7819 WriteMessage("VOL-", false);
7820 break;
7821 case 0xA:
7822 WriteMessage("MUTE", false);
7823 break;
7824 case 0xB:
7825 WriteMessage("CHAN+", false);
7826 break;
7827 case 0xC:
7828 WriteMessage("CHAN-", false);
7829 break;
7830 case 0xD:
7831 WriteMessage("1", false);
7832 break;
7833 case 0xE:
7834 WriteMessage("2", false);
7835 break;
7836 case 0xF:
7837 WriteMessage("3", false);
7838 break;
7839 case 0x10:
7840 WriteMessage("4", false);
7841 break;
7842 case 0x11:
7843 WriteMessage("5", false);
7844 break;
7845 case 0x12:
7846 WriteMessage("6", false);
7847 break;
7848 case 0x13:
7849 WriteMessage("7", false);
7850 break;
7851 case 0x14:
7852 WriteMessage("8", false);
7853 break;
7854 case 0x15:
7855 WriteMessage("9", false);
7856 break;
7857 case 0x16:
7858 WriteMessage("txt", false);
7859 break;
7860 case 0x17:
7861 WriteMessage("0", false);
7862 break;
7863 case 0x18:
7864 WriteMessage("Open Setup Menu", false);
7865 break;
7866 case 0x19:
7867 WriteMessage("C", false);
7868 break;
7869 case 0x1A:
7870 WriteMessage("^", false);
7871 break;
7872 case 0x1B:
7873 WriteMessage("D", false);
7874 break;
7875 case 0x1C:
7876 WriteMessage("TV/RADIO", false);
7877 break;
7878 case 0x1D:
7879 WriteMessage("<", false);
7880 break;
7881 case 0x1E:
7882 WriteMessage("OK", false);
7883 break;
7884 case 0x1F:
7885 WriteMessage(">", false);
7886 break;
7887 case 0x20:
7888 WriteMessage("Max/Restore window", false);
7889 break;
7890 case 0x21:
7891 WriteMessage("E", false);
7892 break;
7893 case 0x22:
7894 WriteMessage("v", false);
7895 break;
7896 case 0x23:
7897 WriteMessage("F", false);
7898 break;
7899 case 0x24:
7900 WriteMessage("Rewind", false);
7901 break;
7902 case 0x25:
7903 WriteMessage("Play", false);
7904 break;
7905 case 0x26:
7906 WriteMessage("Fast forward", false);
7907 break;
7908 case 0x27:
7909 WriteMessage("Record", false);
7910 break;
7911 case 0x28:
7912 WriteMessage("Stop", false);
7913 break;
7914 case 0x29:
7915 WriteMessage("Pause", false);
7916 break;
7917 case 0x2C:
7918 WriteMessage("i", false);
7919 break;
7920 case 0x2D:
7921 WriteMessage("ATI", false);
7922 break;
7923 case 0x3B:
7924 WriteMessage("PC", false);
7925 break;
7926 case 0x3C:
7927 WriteMessage("AUX1", false);
7928 break;
7929 case 0x3D:
7930 WriteMessage("AUX2", false);
7931 break;
7932 case 0x3E:
7933 WriteMessage("AUX3", false);
7934 break;
7935 case 0x3F:
7936 WriteMessage("AUX4", false);
7937 break;
7938 case 0x70:
7939 WriteMessage("Cursor-left", false);
7940 break;
7941 case 0x71:
7942 WriteMessage("Cursor-right", false);
7943 break;
7944 case 0x72:
7945 WriteMessage("Cursor-up", false);
7946 break;
7947 case 0x73:
7948 WriteMessage("Cursor-down", false);
7949 break;
7950 case 0x74:
7951 WriteMessage("Cursor-up-left", false);
7952 break;
7953 case 0x75:
7954 WriteMessage("Cursor-up-right", false);
7955 break;
7956 case 0x76:
7957 WriteMessage("Cursor-down-right", false);
7958 break;
7959 case 0x77:
7960 WriteMessage("Cursor-down-left", false);
7961 break;
7962 case 0x78:
7963 WriteMessage("Left Mouse Button", false);
7964 break;
7965 case 0x7C:
7966 WriteMessage("Right Mouse Button", false);
7967 break;
7968 default:
7969 WriteMessage("unknown", false);
7970 break;
7971 }
7972 if ((pResponse->REMOTE.toggle & 1) == 1)
7973 WriteMessage(" (button press = odd)");
7974 else
7975 WriteMessage(" (button press = even)");
7976 break;
7977 case sTypeMedion:
7978 WriteMessage("subtype = Medion Remote");
7979 sprintf(szTmp, "Sequence nbr = %d", pResponse->REMOTE.seqnbr);
7980 WriteMessage(szTmp);
7981 sprintf(szTmp, "ID = %d", pResponse->REMOTE.id);
7982 WriteMessage(szTmp);
7983
7984 WriteMessage("Command = ", false);
7985
7986 switch (pResponse->REMOTE.cmnd)
7987 {
7988 case 0x0:
7989 WriteMessage("Mute");
7990 break;
7991 case 0x1:
7992 WriteMessage("B");
7993 break;
7994 case 0x2:
7995 WriteMessage("power");
7996 break;
7997 case 0x3:
7998 WriteMessage("TV");
7999 break;
8000 case 0x4:
8001 WriteMessage("DVD");
8002 break;
8003 case 0x5:
8004 WriteMessage("Photo");
8005 break;
8006 case 0x6:
8007 WriteMessage("Music");
8008 break;
8009 case 0x7:
8010 WriteMessage("Drag");
8011 break;
8012 case 0x8:
8013 WriteMessage("VOL-");
8014 break;
8015 case 0x9:
8016 WriteMessage("VOL+");
8017 break;
8018 case 0xA:
8019 WriteMessage("MUTE");
8020 break;
8021 case 0xB:
8022 WriteMessage("CHAN+");
8023 break;
8024 case 0xC:
8025 WriteMessage("CHAN-");
8026 break;
8027 case 0xD:
8028 WriteMessage("1");
8029 break;
8030 case 0xE:
8031 WriteMessage("2");
8032 break;
8033 case 0xF:
8034 WriteMessage("3");
8035 break;
8036 case 0x10:
8037 WriteMessage("4");
8038 break;
8039 case 0x11:
8040 WriteMessage("5");
8041 break;
8042 case 0x12:
8043 WriteMessage("6");
8044 break;
8045 case 0x13:
8046 WriteMessage("7");
8047 break;
8048 case 0x14:
8049 WriteMessage("8");
8050 break;
8051 case 0x15:
8052 WriteMessage("9");
8053 break;
8054 case 0x16:
8055 WriteMessage("txt");
8056 break;
8057 case 0x17:
8058 WriteMessage("0");
8059 break;
8060 case 0x18:
8061 WriteMessage("snapshot ESC");
8062 break;
8063 case 0x19:
8064 WriteMessage("DVD MENU");
8065 break;
8066 case 0x1A:
8067 WriteMessage("^");
8068 break;
8069 case 0x1B:
8070 WriteMessage("Setup");
8071 break;
8072 case 0x1C:
8073 WriteMessage("TV/RADIO");
8074 break;
8075 case 0x1D:
8076 WriteMessage("<");
8077 break;
8078 case 0x1E:
8079 WriteMessage("OK");
8080 break;
8081 case 0x1F:
8082 WriteMessage(">");
8083 break;
8084 case 0x20:
8085 WriteMessage("<-");
8086 break;
8087 case 0x21:
8088 WriteMessage("E");
8089 break;
8090 case 0x22:
8091 WriteMessage("v");
8092 break;
8093 case 0x23:
8094 WriteMessage("F");
8095 break;
8096 case 0x24:
8097 WriteMessage("Rewind");
8098 break;
8099 case 0x25:
8100 WriteMessage("Play");
8101 break;
8102 case 0x26:
8103 WriteMessage("Fast forward");
8104 break;
8105 case 0x27:
8106 WriteMessage("Record");
8107 break;
8108 case 0x28:
8109 WriteMessage("Stop");
8110 break;
8111 case 0x29:
8112 WriteMessage("Pause");
8113 break;
8114 case 0x2C:
8115 WriteMessage("TV");
8116 break;
8117 case 0x2D:
8118 WriteMessage("VCR");
8119 break;
8120 case 0x2E:
8121 WriteMessage("RADIO");
8122 break;
8123 case 0x2F:
8124 WriteMessage("TV Preview");
8125 break;
8126 case 0x30:
8127 WriteMessage("Channel list");
8128 break;
8129 case 0x31:
8130 WriteMessage("Video Desktop");
8131 break;
8132 case 0x32:
8133 WriteMessage("red");
8134 break;
8135 case 0x33:
8136 WriteMessage("green");
8137 break;
8138 case 0x34:
8139 WriteMessage("yellow");
8140 break;
8141 case 0x35:
8142 WriteMessage("blue");
8143 break;
8144 case 0x36:
8145 WriteMessage("rename TAB");
8146 break;
8147 case 0x37:
8148 WriteMessage("Acquire image");
8149 break;
8150 case 0x38:
8151 WriteMessage("edit image");
8152 break;
8153 case 0x39:
8154 WriteMessage("Full screen");
8155 break;
8156 case 0x3A:
8157 WriteMessage("DVD Audio");
8158 break;
8159 case 0x70:
8160 WriteMessage("Cursor-left");
8161 break;
8162 case 0x71:
8163 WriteMessage("Cursor-right");
8164 break;
8165 case 0x72:
8166 WriteMessage("Cursor-up");
8167 break;
8168 case 0x73:
8169 WriteMessage("Cursor-down");
8170 break;
8171 case 0x74:
8172 WriteMessage("Cursor-up-left");
8173 break;
8174 case 0x75:
8175 WriteMessage("Cursor-up-right");
8176 break;
8177 case 0x76:
8178 WriteMessage("Cursor-down-right");
8179 break;
8180 case 0x77:
8181 WriteMessage("Cursor-down-left");
8182 break;
8183 case 0x78:
8184 WriteMessage("V");
8185 break;
8186 case 0x79:
8187 WriteMessage("V-End");
8188 break;
8189 case 0x7C:
8190 WriteMessage("X");
8191 break;
8192 case 0x7D:
8193 WriteMessage("X-End");
8194 break;
8195 default:
8196 WriteMessage("unknown");
8197 break;
8198 }
8199 break;
8200 case sTypePCremote:
8201 WriteMessage("subtype = PC Remote");
8202 sprintf(szTmp, "Sequence nbr = %d", pResponse->REMOTE.seqnbr);
8203 WriteMessage(szTmp);
8204 sprintf(szTmp, "ID = %d", pResponse->REMOTE.id);
8205 WriteMessage(szTmp);
8206 WriteMessage("Command = ", false);
8207 switch (pResponse->REMOTE.cmnd)
8208 {
8209 case 0x2:
8210 WriteMessage("0");
8211 break;
8212 case 0x82:
8213 WriteMessage("1");
8214 break;
8215 case 0xD1:
8216 WriteMessage("MP3");
8217 break;
8218 case 0x42:
8219 WriteMessage("2");
8220 break;
8221 case 0xD2:
8222 WriteMessage("DVD");
8223 break;
8224 case 0xC2:
8225 WriteMessage("3");
8226 break;
8227 case 0xD3:
8228 WriteMessage("CD");
8229 break;
8230 case 0x22:
8231 WriteMessage("4");
8232 break;
8233 case 0xD4:
8234 WriteMessage("PC or SHIFT-4");
8235 break;
8236 case 0xA2:
8237 WriteMessage("5");
8238 break;
8239 case 0xD5:
8240 WriteMessage("SHIFT-5");
8241 break;
8242 case 0x62:
8243 WriteMessage("6");
8244 break;
8245 case 0xE2:
8246 WriteMessage("7");
8247 break;
8248 case 0x12:
8249 WriteMessage("8");
8250 break;
8251 case 0x92:
8252 WriteMessage("9");
8253 break;
8254 case 0xC0:
8255 WriteMessage("CH-");
8256 break;
8257 case 0x40:
8258 WriteMessage("CH+");
8259 break;
8260 case 0xE0:
8261 WriteMessage("VOL-");
8262 break;
8263 case 0x60:
8264 WriteMessage("VOL+");
8265 break;
8266 case 0xA0:
8267 WriteMessage("MUTE");
8268 break;
8269 case 0x3A:
8270 WriteMessage("INFO");
8271 break;
8272 case 0x38:
8273 WriteMessage("REW");
8274 break;
8275 case 0xB8:
8276 WriteMessage("FF");
8277 break;
8278 case 0xB0:
8279 WriteMessage("PLAY");
8280 break;
8281 case 0x64:
8282 WriteMessage("PAUSE");
8283 break;
8284 case 0x63:
8285 WriteMessage("STOP");
8286 break;
8287 case 0xB6:
8288 WriteMessage("MENU");
8289 break;
8290 case 0xFF:
8291 WriteMessage("REC");
8292 break;
8293 case 0xC9:
8294 WriteMessage("EXIT");
8295 break;
8296 case 0xD8:
8297 WriteMessage("TEXT");
8298 break;
8299 case 0xD9:
8300 WriteMessage("SHIFT-TEXT");
8301 break;
8302 case 0xF2:
8303 WriteMessage("TELETEXT");
8304 break;
8305 case 0xD7:
8306 WriteMessage("SHIFT-TELETEXT");
8307 break;
8308 case 0xBA:
8309 WriteMessage("A+B");
8310 break;
8311 case 0x52:
8312 WriteMessage("ENT");
8313 break;
8314 case 0xD6:
8315 WriteMessage("SHIFT-ENT");
8316 break;
8317 case 0x70:
8318 WriteMessage("Cursor-left");
8319 break;
8320 case 0x71:
8321 WriteMessage("Cursor-right");
8322 break;
8323 case 0x72:
8324 WriteMessage("Cursor-up");
8325 break;
8326 case 0x73:
8327 WriteMessage("Cursor-down");
8328 break;
8329 case 0x74:
8330 WriteMessage("Cursor-up-left");
8331 break;
8332 case 0x75:
8333 WriteMessage("Cursor-up-right");
8334 break;
8335 case 0x76:
8336 WriteMessage("Cursor-down-right");
8337 break;
8338 case 0x77:
8339 WriteMessage("Cursor-down-left");
8340 break;
8341 case 0x78:
8342 WriteMessage("Left mouse");
8343 break;
8344 case 0x79:
8345 WriteMessage("Left mouse-End");
8346 break;
8347 case 0x7B:
8348 WriteMessage("Drag");
8349 break;
8350 case 0x7C:
8351 WriteMessage("Right mouse");
8352 break;
8353 case 0x7D:
8354 WriteMessage("Right mouse-End");
8355 break;
8356 default:
8357 WriteMessage("unknown");
8358 break;
8359 }
8360 break;
8361 default:
8362 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->REMOTE.packettype, pResponse->REMOTE.subtype);
8363 WriteMessage(szTmp);
8364 break;
8365 }
8366 sprintf(szTmp, "Signal level = %d", pResponse->REMOTE.rssi);
8367 WriteMessage(szTmp);
8368 WriteMessageEnd();
8369 }
8370 procResult.DeviceRowIdx = DevRowIdx;
8371 }
8372
decode_Thermostat1(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)8373 void MainWorker::decode_Thermostat1(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
8374 {
8375 char szTmp[100];
8376 uint8_t devType = pTypeThermostat1;
8377 uint8_t subType = pResponse->THERMOSTAT1.subtype;
8378 std::string ID;
8379 sprintf(szTmp, "%d", (pResponse->THERMOSTAT1.id1 * 256) + pResponse->THERMOSTAT1.id2);
8380 ID = szTmp;
8381 uint8_t Unit = 0;
8382 uint8_t cmnd = 0;
8383 uint8_t SignalLevel = pResponse->THERMOSTAT1.rssi;
8384 uint8_t BatteryLevel = 255;
8385
8386 uint8_t temp = pResponse->THERMOSTAT1.temperature;
8387 uint8_t set_point = pResponse->THERMOSTAT1.set_point;
8388 uint8_t mode = (pResponse->THERMOSTAT1.mode & 0x80);
8389 uint8_t status = (pResponse->THERMOSTAT1.status & 0x03);
8390
8391 sprintf(szTmp, "%d;%d;%d;%d", temp, set_point, mode, status);
8392 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
8393 if (DevRowIdx == (uint64_t)-1)
8394 return;
8395
8396 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
8397 {
8398 WriteMessageStart();
8399 switch (pResponse->THERMOSTAT1.subtype)
8400 {
8401 case sTypeDigimax:
8402 WriteMessage("subtype = Digimax");
8403 break;
8404 case sTypeDigimaxShort:
8405 WriteMessage("subtype = Digimax with short format");
8406 break;
8407 default:
8408 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->THERMOSTAT1.packettype, pResponse->THERMOSTAT1.subtype);
8409 WriteMessage(szTmp);
8410 break;
8411 }
8412
8413 sprintf(szTmp, "Sequence nbr = %d", pResponse->THERMOSTAT1.seqnbr);
8414 WriteMessage(szTmp);
8415 sprintf(szTmp, "ID = %d", (pResponse->THERMOSTAT1.id1 * 256) + pResponse->THERMOSTAT1.id2);
8416 WriteMessage(szTmp);
8417 sprintf(szTmp, "Temperature = %d C", pResponse->THERMOSTAT1.temperature);
8418 WriteMessage(szTmp);
8419
8420 if (pResponse->THERMOSTAT1.subtype == sTypeDigimax)
8421 {
8422 sprintf(szTmp, "Set = %d C", pResponse->THERMOSTAT1.set_point);
8423 WriteMessage(szTmp);
8424
8425 if ((pResponse->THERMOSTAT1.mode & 0x80) == 0)
8426 WriteMessage("Mode = heating");
8427 else
8428 WriteMessage("Mode = Cooling");
8429
8430 switch (pResponse->THERMOSTAT1.status & 0x03)
8431 {
8432 case 0:
8433 WriteMessage("Status = no status available");
8434 break;
8435 case 1:
8436 WriteMessage("Status = demand");
8437 break;
8438 case 2:
8439 WriteMessage("Status = no demand");
8440 break;
8441 case 3:
8442 WriteMessage("Status = initializing");
8443 break;
8444 }
8445 }
8446
8447 sprintf(szTmp, "Signal level = %d", pResponse->THERMOSTAT1.rssi);
8448 WriteMessage(szTmp);
8449 WriteMessageEnd();
8450 }
8451 procResult.DeviceRowIdx = DevRowIdx;
8452 }
8453
decode_Thermostat2(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)8454 void MainWorker::decode_Thermostat2(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
8455 {
8456 char szTmp[100];
8457 uint8_t devType = pTypeThermostat2;
8458 uint8_t subType = pResponse->THERMOSTAT2.subtype;
8459 std::string ID;
8460 ID = "1";
8461 uint8_t Unit = pResponse->THERMOSTAT2.unitcode;
8462 uint8_t cmnd = pResponse->THERMOSTAT2.cmnd;
8463 uint8_t SignalLevel = pResponse->THERMOSTAT2.rssi;
8464 uint8_t BatteryLevel = 255;
8465
8466 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, procResult.DeviceName);
8467 if (DevRowIdx == (uint64_t)-1)
8468 return;
8469 CheckSceneCode(DevRowIdx, devType, subType, cmnd, "", procResult.DeviceName);
8470
8471 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
8472 {
8473 WriteMessageStart();
8474 switch (pResponse->THERMOSTAT2.subtype)
8475 {
8476 case sTypeHE105:
8477 WriteMessage("subtype = HE105");
8478 break;
8479 case sTypeRTS10:
8480 WriteMessage("subtype = RTS10");
8481 break;
8482 default:
8483 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->THERMOSTAT2.packettype, pResponse->THERMOSTAT2.subtype);
8484 WriteMessage(szTmp);
8485 break;
8486 }
8487
8488 sprintf(szTmp, "Sequence nbr = %d", pResponse->THERMOSTAT2.seqnbr);
8489 WriteMessage(szTmp);
8490
8491 sprintf(szTmp, "Unit code = 0x%02X", pResponse->THERMOSTAT2.unitcode);
8492 WriteMessage(szTmp);
8493
8494 switch (pResponse->THERMOSTAT2.cmnd)
8495 {
8496 case thermostat2_sOff:
8497 WriteMessage("Command = Off");
8498 break;
8499 case thermostat2_sOn:
8500 WriteMessage("Command = On");
8501 break;
8502 default:
8503 WriteMessage("Command = unknown");
8504 break;
8505 }
8506
8507 sprintf(szTmp, "Signal level = %d", pResponse->THERMOSTAT2.rssi);
8508 WriteMessage(szTmp);
8509 WriteMessageEnd();
8510 }
8511 procResult.DeviceRowIdx = DevRowIdx;
8512 }
8513
decode_Thermostat3(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)8514 void MainWorker::decode_Thermostat3(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
8515 {
8516 char szTmp[100];
8517 uint8_t devType = pTypeThermostat3;
8518 uint8_t subType = pResponse->THERMOSTAT3.subtype;
8519 std::string ID;
8520 sprintf(szTmp, "%02X%02X%02X", pResponse->THERMOSTAT3.unitcode1, pResponse->THERMOSTAT3.unitcode2, pResponse->THERMOSTAT3.unitcode3);
8521 ID = szTmp;
8522 uint8_t Unit = 0;
8523 uint8_t cmnd = pResponse->THERMOSTAT3.cmnd;
8524 uint8_t SignalLevel = pResponse->THERMOSTAT3.rssi;
8525 uint8_t BatteryLevel = 255;
8526
8527 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, procResult.DeviceName);
8528 if (DevRowIdx == (uint64_t)-1)
8529 return;
8530 CheckSceneCode(DevRowIdx, devType, subType, cmnd, "", procResult.DeviceName);
8531
8532 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
8533 {
8534 WriteMessageStart();
8535 switch (pResponse->THERMOSTAT3.subtype)
8536 {
8537 case sTypeMertikG6RH4T1:
8538 WriteMessage("subtype = Mertik G6R-H4T1");
8539 break;
8540 case sTypeMertikG6RH4TB:
8541 WriteMessage("subtype = Mertik G6R-H4TB");
8542 break;
8543 case sTypeMertikG6RH4TD:
8544 WriteMessage("subtype = Mertik G6R-H4TD");
8545 break;
8546 case sTypeMertikG6RH4S:
8547 WriteMessage("subtype = Mertik G6R-H4S");
8548 break;
8549 default:
8550 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->THERMOSTAT3.packettype, pResponse->THERMOSTAT3.subtype);
8551 WriteMessage(szTmp);
8552 break;
8553 }
8554
8555 sprintf(szTmp, "Sequence nbr = %d", pResponse->THERMOSTAT3.seqnbr);
8556 WriteMessage(szTmp);
8557
8558 sprintf(szTmp, "ID = 0x%02X%02X%02X", pResponse->THERMOSTAT3.unitcode1, pResponse->THERMOSTAT3.unitcode2, pResponse->THERMOSTAT3.unitcode3);
8559 WriteMessage(szTmp);
8560
8561 switch (pResponse->THERMOSTAT3.cmnd)
8562 {
8563 case thermostat3_sOff:
8564 WriteMessage("Command = Off");
8565 break;
8566 case thermostat3_sOn:
8567 WriteMessage("Command = On");
8568 break;
8569 case thermostat3_sUp:
8570 WriteMessage("Command = Up");
8571 break;
8572 case thermostat3_sDown:
8573 WriteMessage("Command = Down");
8574 break;
8575 case thermostat3_sRunUp:
8576 if (pResponse->THERMOSTAT3.subtype == sTypeMertikG6RH4T1)
8577 WriteMessage("Command = Run Up");
8578 else
8579 WriteMessage("Command = 2nd Off");
8580 break;
8581 case thermostat3_sRunDown:
8582 if (pResponse->THERMOSTAT3.subtype == sTypeMertikG6RH4T1)
8583 WriteMessage("Command = Run Down");
8584 else
8585 WriteMessage("Command = 2nd On");
8586 break;
8587 case thermostat3_sStop:
8588 if (pResponse->THERMOSTAT3.subtype == sTypeMertikG6RH4T1)
8589 WriteMessage("Command = Stop");
8590 else
8591 WriteMessage("Command = unknown");
8592 default:
8593 WriteMessage("Command = unknown");
8594 break;
8595 }
8596
8597 sprintf(szTmp, "Signal level = %d", pResponse->THERMOSTAT3.rssi);
8598 WriteMessage(szTmp);
8599 WriteMessageEnd();
8600 }
8601 procResult.DeviceRowIdx = DevRowIdx;
8602 }
8603
decode_Thermostat4(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)8604 void MainWorker::decode_Thermostat4(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
8605 {
8606 char szTmp[100];
8607 uint8_t devType = pTypeThermostat4;
8608 uint8_t subType = pResponse->THERMOSTAT4.subtype;
8609 std::string ID;
8610 sprintf(szTmp, "%02X%02X%02X", pResponse->THERMOSTAT4.unitcode1, pResponse->THERMOSTAT4.unitcode2, pResponse->THERMOSTAT4.unitcode3);
8611 ID = szTmp;
8612 uint8_t Unit = 0;
8613 uint8_t SignalLevel = pResponse->THERMOSTAT4.rssi;
8614 uint8_t BatteryLevel = 255;
8615 sprintf(szTmp, "%d;%d;%d;%d;%d;%d",
8616 pResponse->THERMOSTAT4.beep,
8617 pResponse->THERMOSTAT4.fan1_speed,
8618 pResponse->THERMOSTAT4.fan2_speed,
8619 pResponse->THERMOSTAT4.fan3_speed,
8620 pResponse->THERMOSTAT4.flame_power,
8621 pResponse->THERMOSTAT4.mode
8622 );
8623
8624 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, szTmp, procResult.DeviceName);
8625 if (DevRowIdx == (uint64_t)-1)
8626 return;
8627
8628 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
8629 {
8630 WriteMessageStart();
8631 switch (pResponse->THERMOSTAT4.subtype)
8632 {
8633 case sTypeMCZ1:
8634 WriteMessage("subtype = MCZ pellet stove 1 fan model");
8635 break;
8636 case sTypeMCZ2:
8637 WriteMessage("subtype = MCZ pellet stove 2 fan model");
8638 break;
8639 case sTypeMCZ3:
8640 WriteMessage("subtype = MCZ pellet stove 3 fan model");
8641 break;
8642 default:
8643 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->THERMOSTAT4.packettype, pResponse->THERMOSTAT4.subtype);
8644 WriteMessage(szTmp);
8645 break;
8646 }
8647
8648 sprintf(szTmp, "Sequence nbr = %d", pResponse->THERMOSTAT4.seqnbr);
8649 WriteMessage(szTmp);
8650
8651 sprintf(szTmp, "ID = 0x%02X%02X%02X", pResponse->THERMOSTAT4.unitcode1, pResponse->THERMOSTAT4.unitcode2, pResponse->THERMOSTAT4.unitcode3);
8652 WriteMessage(szTmp);
8653
8654 if (pResponse->THERMOSTAT4.beep)
8655 WriteMessage("Beep = Yes");
8656 else
8657 WriteMessage("Beep = No");
8658
8659 if (pResponse->THERMOSTAT4.fan1_speed == 6)
8660 strcpy(szTmp, "Fan 1 Speed = Auto");
8661 else
8662 sprintf(szTmp, "Fan 1 Speed = %d", pResponse->THERMOSTAT4.fan1_speed);
8663 WriteMessage(szTmp);
8664
8665 if (pResponse->THERMOSTAT4.fan2_speed == 6)
8666 strcpy(szTmp, "Fan 2 Speed = Auto");
8667 else
8668 sprintf(szTmp, "Fan 2 Speed = %d", pResponse->THERMOSTAT4.fan2_speed);
8669 WriteMessage(szTmp);
8670
8671 if (pResponse->THERMOSTAT4.fan3_speed == 6)
8672 strcpy(szTmp, "Fan 3 Speed = Auto");
8673 else
8674 sprintf(szTmp, "Fan 3 Speed = %d", pResponse->THERMOSTAT4.fan3_speed);
8675 WriteMessage(szTmp);
8676
8677 sprintf(szTmp, "Flame power = %d", pResponse->THERMOSTAT4.flame_power);
8678 WriteMessage(szTmp);
8679
8680 switch (pResponse->THERMOSTAT4.mode)
8681 {
8682 case thermostat4_sOff:
8683 WriteMessage("Command = Off");
8684 break;
8685 case thermostat4_sManual:
8686 WriteMessage("Command = Manual");
8687 break;
8688 case thermostat4_sAuto:
8689 WriteMessage("Command = Auto");
8690 break;
8691 case thermostat4_sEco:
8692 WriteMessage("Command = Eco");
8693 break;
8694 default:
8695 WriteMessage("Command = unknown");
8696 break;
8697 }
8698
8699 sprintf(szTmp, "Signal level = %d", pResponse->THERMOSTAT3.rssi);
8700 WriteMessage(szTmp);
8701 WriteMessageEnd();
8702 }
8703 procResult.DeviceRowIdx = DevRowIdx;
8704 }
8705
decode_Radiator1(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)8706 void MainWorker::decode_Radiator1(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
8707 {
8708 char szTmp[100];
8709 uint8_t devType = pTypeRadiator1;
8710 uint8_t subType = pResponse->RADIATOR1.subtype;
8711 std::string ID;
8712 sprintf(szTmp, "%X%02X%02X%02X", pResponse->RADIATOR1.id1, pResponse->RADIATOR1.id2, pResponse->RADIATOR1.id3, pResponse->RADIATOR1.id4);
8713 ID = szTmp;
8714 uint8_t Unit = pResponse->RADIATOR1.unitcode;
8715 uint8_t cmnd = pResponse->RADIATOR1.cmnd;
8716 uint8_t SignalLevel = pResponse->RADIATOR1.rssi;
8717 uint8_t BatteryLevel = 255;
8718
8719 sprintf(szTmp, "%d.%d", pResponse->RADIATOR1.temperature, pResponse->RADIATOR1.tempPoint5);
8720 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
8721 if (DevRowIdx == (uint64_t)-1)
8722 return;
8723
8724 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
8725 {
8726 WriteMessageStart();
8727 switch (pResponse->RADIATOR1.subtype)
8728 {
8729 case sTypeSmartwares:
8730 WriteMessage("subtype = Smartwares");
8731 break;
8732 case sTypeSmartwaresSwitchRadiator:
8733 WriteMessage("subtype = Smartwares Radiator Switch");
8734 break;
8735 default:
8736 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->RADIATOR1.packettype, pResponse->RADIATOR1.subtype);
8737 WriteMessage(szTmp);
8738 break;
8739 }
8740
8741 sprintf(szTmp, "Sequence nbr = %d", pResponse->THERMOSTAT3.seqnbr);
8742 WriteMessage(szTmp);
8743
8744 sprintf(szTmp, "ID = %X%02X%02X%02X", pResponse->RADIATOR1.id1, pResponse->RADIATOR1.id2, pResponse->RADIATOR1.id3, pResponse->RADIATOR1.id4);
8745 WriteMessage(szTmp);
8746 sprintf(szTmp, "Unit = %d", pResponse->RADIATOR1.unitcode);
8747 WriteMessage(szTmp);
8748
8749 switch (pResponse->RADIATOR1.cmnd)
8750 {
8751 case Radiator1_sNight:
8752 WriteMessage("Command = Night/Off");
8753 break;
8754 case Radiator1_sDay:
8755 WriteMessage("Command = Day/On");
8756 break;
8757 case Radiator1_sSetTemp:
8758 WriteMessage("Command = Set Temperature");
8759 break;
8760 default:
8761 WriteMessage("Command = unknown");
8762 break;
8763 }
8764
8765 sprintf(szTmp, "Temp = %d.%d", pResponse->RADIATOR1.temperature, pResponse->RADIATOR1.tempPoint5);
8766 WriteMessage(szTmp);
8767 sprintf(szTmp, "Signal level = %d", pResponse->RADIATOR1.rssi);
8768 WriteMessage(szTmp);
8769 WriteMessageEnd();
8770 }
8771 procResult.DeviceRowIdx = DevRowIdx;
8772 }
8773
8774 //not in dbase yet
decode_Baro(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)8775 void MainWorker::decode_Baro(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
8776 {
8777 //uint8_t devType=pTypeBARO;
8778
8779 WriteMessageStart();
8780 WriteMessage("Not implemented");
8781 WriteMessageEnd();
8782 procResult.DeviceRowIdx = -1;
8783 }
8784
8785 //not in dbase yet
decode_DateTime(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)8786 void MainWorker::decode_DateTime(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
8787 {
8788 WriteMessage("");
8789
8790 //uint8_t devType=pTypeDT;
8791
8792 char szTmp[100];
8793
8794 switch (pResponse->DT.subtype)
8795 {
8796 case sTypeDT1:
8797 WriteMessage("Subtype = DT1 - RTGR328N");
8798 break;
8799 default:
8800 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->DT.packettype, pResponse->DT.subtype);
8801 WriteMessage(szTmp);
8802 break;
8803 }
8804 sprintf(szTmp, "Sequence nbr = %d", pResponse->DT.seqnbr);
8805 WriteMessage(szTmp);
8806 sprintf(szTmp, "ID = %d", (pResponse->DT.id1 * 256) + pResponse->DT.id2);
8807 WriteMessage(szTmp);
8808
8809 WriteMessage("Day of week = ", false);
8810
8811 switch (pResponse->DT.dow)
8812 {
8813 case 1:
8814 WriteMessage(" Sunday");
8815 break;
8816 case 2:
8817 WriteMessage(" Monday");
8818 break;
8819 case 3:
8820 WriteMessage(" Tuesday");
8821 break;
8822 case 4:
8823 WriteMessage(" Wednesday");
8824 break;
8825 case 5:
8826 WriteMessage(" Thursday");
8827 break;
8828 case 6:
8829 WriteMessage(" Friday");
8830 break;
8831 case 7:
8832 WriteMessage(" Saturday");
8833 break;
8834 }
8835 sprintf(szTmp, "Date yy/mm/dd = %02d/%02d/%02d", pResponse->DT.yy, pResponse->DT.mm, pResponse->DT.dd);
8836 WriteMessage(szTmp);
8837 sprintf(szTmp, "Time = %02d:%02d:%02d", pResponse->DT.hr, pResponse->DT.min, pResponse->DT.sec);
8838 WriteMessage(szTmp);
8839 sprintf(szTmp, "Signal level = %d", pResponse->DT.rssi);
8840 WriteMessage(szTmp);
8841 if ((pResponse->DT.battery_level & 0x0F) == 0)
8842 WriteMessage("Battery = Low");
8843 else
8844 WriteMessage("Battery = OK");
8845 procResult.DeviceRowIdx = -1;
8846 }
8847
decode_Current(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)8848 void MainWorker::decode_Current(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
8849 {
8850 char szTmp[100];
8851 uint8_t devType = pTypeCURRENT;
8852 uint8_t subType = pResponse->CURRENT.subtype;
8853 std::string ID;
8854 sprintf(szTmp, "%d", (pResponse->CURRENT.id1 * 256) + pResponse->CURRENT.id2);
8855 ID = szTmp;
8856 uint8_t Unit = 0;
8857 uint8_t cmnd = 0;
8858 uint8_t SignalLevel = pResponse->CURRENT.rssi;
8859 uint8_t BatteryLevel = get_BateryLevel(pHardware->HwdType, false, pResponse->CURRENT.battery_level & 0x0F);
8860
8861 float CurrentChannel1 = float((pResponse->CURRENT.ch1h * 256) + pResponse->CURRENT.ch1l) / 10.0f;
8862 float CurrentChannel2 = float((pResponse->CURRENT.ch2h * 256) + pResponse->CURRENT.ch2l) / 10.0f;
8863 float CurrentChannel3 = float((pResponse->CURRENT.ch3h * 256) + pResponse->CURRENT.ch3l) / 10.0f;
8864 sprintf(szTmp, "%.1f;%.1f;%.1f", CurrentChannel1, CurrentChannel2, CurrentChannel3);
8865 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
8866 if (DevRowIdx == (uint64_t)-1)
8867 return;
8868
8869 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, cmnd, szTmp);
8870
8871 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
8872 {
8873 WriteMessageStart();
8874 switch (pResponse->CURRENT.subtype)
8875 {
8876 case sTypeELEC1:
8877 WriteMessage("subtype = ELEC1 - OWL CM113, Electrisave, cent-a-meter");
8878 break;
8879 default:
8880 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->CURRENT.packettype, pResponse->CURRENT.subtype);
8881 WriteMessage(szTmp);
8882 break;
8883 }
8884
8885 sprintf(szTmp, "Sequence nbr = %d", pResponse->CURRENT.seqnbr);
8886 WriteMessage(szTmp);
8887 sprintf(szTmp, "ID = %d", (pResponse->CURRENT.id1 * 256) + pResponse->CURRENT.id2);
8888 WriteMessage(szTmp);
8889 sprintf(szTmp, "Count = %d", pResponse->CURRENT.id2);//m_rxbuffer[5]);
8890 WriteMessage(szTmp);
8891 sprintf(szTmp, "Channel 1 = %.1f ampere", CurrentChannel1);
8892 WriteMessage(szTmp);
8893 sprintf(szTmp, "Channel 2 = %.1f ampere", CurrentChannel2);
8894 WriteMessage(szTmp);
8895 sprintf(szTmp, "Channel 3 = %.1f ampere", CurrentChannel3);
8896 WriteMessage(szTmp);
8897
8898 sprintf(szTmp, "Signal level = %d", pResponse->CURRENT.rssi);
8899 WriteMessage(szTmp);
8900
8901 if ((pResponse->CURRENT.battery_level & 0xF) == 0)
8902 WriteMessage("Battery = Low");
8903 else
8904 WriteMessage("Battery = OK");
8905 WriteMessageEnd();
8906 }
8907 procResult.DeviceRowIdx = DevRowIdx;
8908 }
8909
decode_Energy(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)8910 void MainWorker::decode_Energy(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
8911 {
8912 uint8_t subType = pResponse->ENERGY.subtype;
8913 uint8_t SignalLevel = pResponse->ENERGY.rssi;
8914 uint8_t BatteryLevel = get_BateryLevel(pHardware->HwdType, false, pResponse->ENERGY.battery_level & 0x0F);
8915
8916 long instant = (pResponse->ENERGY.instant1 * 0x1000000) + (pResponse->ENERGY.instant2 * 0x10000) + (pResponse->ENERGY.instant3 * 0x100) + pResponse->ENERGY.instant4;
8917
8918 double total = (
8919 double(pResponse->ENERGY.total1) * 0x10000000000ULL +
8920 double(pResponse->ENERGY.total2) * 0x100000000ULL +
8921 double(pResponse->ENERGY.total3) * 0x1000000 +
8922 double(pResponse->ENERGY.total4) * 0x10000 +
8923 double(pResponse->ENERGY.total5) * 0x100 +
8924 double(pResponse->ENERGY.total6)
8925 ) / 223.666;
8926
8927 if (pResponse->ENERGY.subtype == sTypeELEC3)
8928 {
8929 if (total == 0)
8930 {
8931 char szTmp[20];
8932 std::string ID;
8933 sprintf(szTmp, "%08X", (pResponse->ENERGY.id1 * 256) + pResponse->ENERGY.id2);
8934 ID = szTmp;
8935
8936 //Retrieve last total from current record
8937 int nValue;
8938 subType = sTypeKwh; // sensor type changed during recording
8939 uint8_t devType = pTypeGeneral; // Device reported as General and not Energy
8940 uint8_t Unit = 1; // in decode_general() Unit is set to 1
8941 std::string sValue;
8942 struct tm LastUpdateTime;
8943 if (!m_sql.GetLastValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, nValue, sValue, LastUpdateTime))
8944 return;
8945 std::vector<std::string> strarray;
8946 StringSplit(sValue, ";", strarray);
8947 if (strarray.size() != 2)
8948 return;
8949 total = atof(strarray[1].c_str());
8950 }
8951 }
8952
8953 //Translate this sensor type to the new kWh sensor type
8954 _tGeneralDevice gdevice;
8955 gdevice.intval1 = (pResponse->ENERGY.id1 * 256) + pResponse->ENERGY.id2;
8956 gdevice.subtype = sTypeKwh;
8957 gdevice.floatval1 = (float)instant;
8958 gdevice.floatval2 = (float)total;
8959
8960 int voltage = 230;
8961 m_sql.GetPreferencesVar("ElectricVoltage", voltage);
8962 if (voltage != 230)
8963 {
8964 float mval = float(voltage) / 230.0f;
8965 gdevice.floatval1 *= mval;
8966 gdevice.floatval2 *= mval;
8967 }
8968
8969 decode_General(pHardware, (const tRBUF*)&gdevice, procResult, SignalLevel, BatteryLevel);
8970 procResult.bProcessBatteryValue = false;
8971 }
8972
decode_Power(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)8973 void MainWorker::decode_Power(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
8974 {
8975 char szTmp[100];
8976 uint8_t devType = pTypePOWER;
8977 uint8_t subType = pResponse->POWER.subtype;
8978 std::string ID;
8979 sprintf(szTmp, "%d", (pResponse->POWER.id1 * 256) + pResponse->POWER.id2);
8980 ID = szTmp;
8981 uint8_t Unit = 0;
8982 uint8_t cmnd = 0;
8983 uint8_t SignalLevel = pResponse->POWER.rssi;
8984 uint8_t BatteryLevel = 255;
8985
8986 float Voltage = (float)pResponse->POWER.voltage;
8987 double current = ((pResponse->POWER.currentH * 256) + pResponse->POWER.currentL) / 100.0;
8988 double instant = ((pResponse->POWER.powerH * 256) + pResponse->POWER.powerL) / 10.0;// Watt
8989 double usage = ((pResponse->POWER.energyH * 256) + pResponse->POWER.energyL) / 100.0; //kWh
8990 double powerfactor = pResponse->POWER.pf / 100.0;
8991 float frequency = (float)pResponse->POWER.freq; //Hz
8992
8993 sprintf(szTmp, "%ld;%.2f", long(round(instant)), usage * 1000.0);
8994 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
8995 if (DevRowIdx == (uint64_t)-1)
8996 return;
8997 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, cmnd, szTmp);
8998
8999 //Voltage
9000 sprintf(szTmp, "%.3f", Voltage);
9001 std::string tmpDevName;
9002 uint64_t DevRowIdxAlt = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), 1, pTypeGeneral, sTypeVoltage, SignalLevel, BatteryLevel, cmnd, szTmp, tmpDevName);
9003 if (DevRowIdxAlt == (uint64_t)-1)
9004 return;
9005 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, tmpDevName, 1, pTypeGeneral, sTypeVoltage, Voltage);
9006
9007 //Powerfactor
9008 sprintf(szTmp, "%.2f", (float)powerfactor);
9009 DevRowIdxAlt = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), 2, pTypeGeneral, sTypePercentage, SignalLevel, BatteryLevel, cmnd, szTmp, tmpDevName);
9010 if (DevRowIdxAlt == (uint64_t)-1)
9011 return;
9012 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, tmpDevName, 2, pTypeGeneral, sTypePercentage, (float)powerfactor);
9013
9014 //Frequency
9015 sprintf(szTmp, "%.2f", (float)frequency);
9016 DevRowIdxAlt = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), 3, pTypeGeneral, sTypePercentage, SignalLevel, BatteryLevel, cmnd, szTmp, tmpDevName);
9017 if (DevRowIdxAlt == (uint64_t)-1)
9018 return;
9019 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, tmpDevName, 3, pTypeGeneral, sTypePercentage, frequency);
9020
9021 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9022 {
9023 WriteMessageStart();
9024 switch (pResponse->POWER.subtype)
9025 {
9026 case sTypeELEC5:
9027 WriteMessage("subtype = ELEC5 - Revolt");
9028 break;
9029 }
9030
9031 sprintf(szTmp, "Sequence nbr = %d", pResponse->POWER.seqnbr);
9032 WriteMessage(szTmp);
9033 sprintf(szTmp, "ID = %d", (pResponse->POWER.id1 * 256) + pResponse->POWER.id2);
9034 WriteMessage(szTmp);
9035
9036 sprintf(szTmp, "Voltage = %g Volt", Voltage);
9037 WriteMessage(szTmp);
9038 sprintf(szTmp, "Current = %.2f Ampere", current);
9039 WriteMessage(szTmp);
9040
9041 sprintf(szTmp, "Instant usage = %.2f Watt", instant);
9042 WriteMessage(szTmp);
9043 sprintf(szTmp, "total usage = %.2f kWh", usage);
9044 WriteMessage(szTmp);
9045
9046 sprintf(szTmp, "Power factor = %.2f", powerfactor);
9047 WriteMessage(szTmp);
9048 sprintf(szTmp, "Frequency = %g Hz", frequency);
9049 WriteMessage(szTmp);
9050
9051 sprintf(szTmp, "Signal level = %d", pResponse->POWER.rssi);
9052 WriteMessage(szTmp);
9053 WriteMessageEnd();
9054 }
9055 procResult.DeviceRowIdx = DevRowIdx;
9056 }
9057
decode_Current_Energy(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9058 void MainWorker::decode_Current_Energy(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9059 {
9060 char szTmp[100];
9061 uint8_t devType = pTypeCURRENTENERGY;
9062 uint8_t subType = pResponse->CURRENT_ENERGY.subtype;
9063 std::string ID;
9064 sprintf(szTmp, "%d", (pResponse->CURRENT_ENERGY.id1 * 256) + pResponse->CURRENT_ENERGY.id2);
9065 ID = szTmp;
9066 uint8_t Unit = 0;
9067 uint8_t cmnd = 0;
9068 uint8_t SignalLevel = pResponse->CURRENT_ENERGY.rssi;
9069 uint8_t BatteryLevel = get_BateryLevel(pHardware->HwdType, false, pResponse->CURRENT_ENERGY.battery_level & 0x0F);
9070
9071 float CurrentChannel1 = float((pResponse->CURRENT_ENERGY.ch1h * 256) + pResponse->CURRENT_ENERGY.ch1l) / 10.0f;
9072 float CurrentChannel2 = float((pResponse->CURRENT_ENERGY.ch2h * 256) + pResponse->CURRENT_ENERGY.ch2l) / 10.0f;
9073 float CurrentChannel3 = float((pResponse->CURRENT_ENERGY.ch3h * 256) + pResponse->CURRENT_ENERGY.ch3l) / 10.0f;
9074
9075 double usage = 0;
9076
9077 if (pResponse->CURRENT_ENERGY.count != 0)
9078 {
9079 //no usage provided, get the last usage
9080 std::vector<std::vector<std::string> > result2;
9081 result2 = m_sql.safe_query(
9082 "SELECT nValue,sValue FROM DeviceStatus WHERE (HardwareID=%d AND DeviceID='%q' AND Unit=%d AND Type=%d AND SubType=%d)",
9083 pHardware->m_HwdID, ID.c_str(), int(Unit), int(devType), int(subType));
9084 if (!result2.empty())
9085 {
9086 std::vector<std::string> strarray;
9087 StringSplit(result2[0][1], ";", strarray);
9088 if (strarray.size() == 4)
9089 {
9090 usage = atof(strarray[3].c_str());
9091 }
9092 }
9093 }
9094 else
9095 {
9096 usage = (
9097 double(pResponse->CURRENT_ENERGY.total1) * 0x10000000000ULL +
9098 double(pResponse->CURRENT_ENERGY.total2) * 0x100000000ULL +
9099 double(pResponse->CURRENT_ENERGY.total3) * 0x1000000 +
9100 double(pResponse->CURRENT_ENERGY.total4) * 0x10000 +
9101 double(pResponse->CURRENT_ENERGY.total5) * 0x100 +
9102 pResponse->CURRENT_ENERGY.total6
9103 ) / 223.666;
9104
9105 if (usage == 0)
9106 {
9107 //That should not be, let's get the previous value
9108 //no usage provided, get the last usage
9109 std::vector<std::vector<std::string> > result2;
9110 result2 = m_sql.safe_query(
9111 "SELECT nValue,sValue FROM DeviceStatus WHERE (HardwareID=%d AND DeviceID='%q' AND Unit=%d AND Type=%d AND SubType=%d)",
9112 pHardware->m_HwdID, ID.c_str(), int(Unit), int(devType), int(subType));
9113 if (!result2.empty())
9114 {
9115 std::vector<std::string> strarray;
9116 StringSplit(result2[0][1], ";", strarray);
9117 if (strarray.size() == 4)
9118 {
9119 usage = atof(strarray[3].c_str());
9120 }
9121 }
9122 }
9123
9124 int voltage = 230;
9125 m_sql.GetPreferencesVar("ElectricVoltage", voltage);
9126
9127 sprintf(szTmp, "%ld;%.2f", (long)round((CurrentChannel1 + CurrentChannel2 + CurrentChannel3) * voltage), usage);
9128 m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, pTypeENERGY, sTypeELEC3, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
9129 }
9130 sprintf(szTmp, "%.1f;%.1f;%.1f;%.3f", CurrentChannel1, CurrentChannel2, CurrentChannel3, usage);
9131 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
9132 if (DevRowIdx == (uint64_t)-1)
9133 return;
9134
9135 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, cmnd, szTmp);
9136
9137 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9138 {
9139 WriteMessageStart();
9140 switch (pResponse->CURRENT_ENERGY.subtype)
9141 {
9142 case sTypeELEC4:
9143 WriteMessage("subtype = ELEC4 - OWL CM180i");
9144 break;
9145 default:
9146 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->CURRENT_ENERGY.packettype, pResponse->CURRENT_ENERGY.subtype);
9147 WriteMessage(szTmp);
9148 break;
9149 }
9150
9151 sprintf(szTmp, "Sequence nbr = %d", pResponse->CURRENT_ENERGY.seqnbr);
9152 WriteMessage(szTmp);
9153 sprintf(szTmp, "ID = %d", (pResponse->CURRENT_ENERGY.id1 * 256) + pResponse->CURRENT_ENERGY.id2);
9154 WriteMessage(szTmp);
9155 sprintf(szTmp, "Count = %d", pResponse->CURRENT_ENERGY.count);
9156 WriteMessage(szTmp);
9157 float ampereChannel1, ampereChannel2, ampereChannel3;
9158 ampereChannel1 = float((pResponse->CURRENT_ENERGY.ch1h * 256) + pResponse->CURRENT_ENERGY.ch1l) / 10.0f;
9159 ampereChannel2 = float((pResponse->CURRENT_ENERGY.ch2h * 256) + pResponse->CURRENT_ENERGY.ch2l) / 10.0f;
9160 ampereChannel3 = float((pResponse->CURRENT_ENERGY.ch3h * 256) + pResponse->CURRENT_ENERGY.ch3l) / 10.0f;
9161 sprintf(szTmp, "Channel 1 = %.1f ampere", ampereChannel1);
9162 WriteMessage(szTmp);
9163 sprintf(szTmp, "Channel 2 = %.1f ampere", ampereChannel2);
9164 WriteMessage(szTmp);
9165 sprintf(szTmp, "Channel 3 = %.1f ampere", ampereChannel3);
9166 WriteMessage(szTmp);
9167
9168 if (pResponse->CURRENT_ENERGY.count == 0)
9169 {
9170 sprintf(szTmp, "total usage = %.3f Wh", usage);
9171 WriteMessage(szTmp);
9172 }
9173
9174 sprintf(szTmp, "Signal level = %d", pResponse->CURRENT_ENERGY.rssi);
9175 WriteMessage(szTmp);
9176
9177 if ((pResponse->CURRENT_ENERGY.battery_level & 0xF) == 0)
9178 WriteMessage("Battery = Low");
9179 else
9180 WriteMessage("Battery = OK");
9181 WriteMessageEnd();
9182 }
9183 procResult.DeviceRowIdx = DevRowIdx;
9184 }
9185
9186 //not in dbase yet
decode_Gas(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9187 void MainWorker::decode_Gas(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9188 {
9189 WriteMessage("");
9190
9191 //uint8_t devType=pTypeGAS;
9192
9193 WriteMessage("Not implemented");
9194
9195 procResult.DeviceRowIdx = -1;
9196 }
9197
9198 //not in dbase yet
decode_Water(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9199 void MainWorker::decode_Water(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9200 {
9201 WriteMessage("");
9202
9203 //uint8_t devType=pTypeWATER;
9204
9205 WriteMessage("Not implemented");
9206
9207 procResult.DeviceRowIdx = -1;
9208 }
9209
decode_Weight(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9210 void MainWorker::decode_Weight(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9211 {
9212 char szTmp[100];
9213 uint8_t devType = pTypeWEIGHT;
9214 uint8_t subType = pResponse->WEIGHT.subtype;
9215 uint16_t weightID = (pResponse->WEIGHT.id1 * 256) + pResponse->WEIGHT.id2;
9216 std::string ID;
9217 sprintf(szTmp, "%d", weightID);
9218 ID = szTmp;
9219 uint8_t Unit = 0;
9220 uint8_t cmnd = 0;
9221 uint8_t SignalLevel = pResponse->WEIGHT.rssi;
9222 uint8_t BatteryLevel = 255;
9223 float weight = (float(pResponse->WEIGHT.weighthigh) * 25.6f) + (float(pResponse->WEIGHT.weightlow) / 10.0f);
9224
9225 float AddjValue = 0.0f;
9226 float AddjMulti = 1.0f;
9227 m_sql.GetAddjustment(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, AddjValue, AddjMulti);
9228 weight += AddjValue;
9229
9230 sprintf(szTmp, "%.1f", weight);
9231 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
9232 if (DevRowIdx == (uint64_t)-1)
9233 return;
9234
9235 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, weight);
9236
9237 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9238 {
9239 WriteMessageStart();
9240 switch (pResponse->WEIGHT.subtype)
9241 {
9242 case sTypeWEIGHT1:
9243 WriteMessage("subtype = BWR102");
9244 break;
9245 case sTypeWEIGHT2:
9246 WriteMessage("subtype = GR101");
9247 break;
9248 default:
9249 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type = %02X:%02X", pResponse->WEIGHT.packettype, pResponse->WEIGHT.subtype);
9250 WriteMessage(szTmp);
9251 break;
9252 }
9253
9254 sprintf(szTmp, "Sequence nbr = %d", pResponse->WEIGHT.seqnbr);
9255 WriteMessage(szTmp);
9256 sprintf(szTmp, "ID = %d", (pResponse->WEIGHT.id1 * 256) + pResponse->WEIGHT.id2);
9257 WriteMessage(szTmp);
9258 sprintf(szTmp, "Weight = %.1f kg", (float(pResponse->WEIGHT.weighthigh) * 25.6f) + (float(pResponse->WEIGHT.weightlow) / 10));
9259 WriteMessage(szTmp);
9260 sprintf(szTmp, "Signal level = %d", pResponse->WEIGHT.rssi);
9261 WriteMessage(szTmp);
9262 WriteMessageEnd();
9263 }
9264 procResult.DeviceRowIdx = DevRowIdx;
9265 }
9266
decode_RFXSensor(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9267 void MainWorker::decode_RFXSensor(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9268 {
9269 char szTmp[100];
9270 uint8_t devType = pTypeRFXSensor;
9271 uint8_t subType = pResponse->RFXSENSOR.subtype;
9272 std::string ID;
9273 sprintf(szTmp, "%d", pResponse->RFXSENSOR.id);
9274 ID = szTmp;
9275 uint8_t Unit = 0;
9276 uint8_t cmnd = 0;
9277 uint8_t SignalLevel = pResponse->RFXSENSOR.rssi;
9278 uint8_t BatteryLevel = 255;
9279
9280 if ((pHardware->HwdType == HTYPE_EnOceanESP2) || (pHardware->HwdType == HTYPE_EnOceanESP3))
9281 {
9282 BatteryLevel = 255;
9283 SignalLevel = 12;
9284 Unit = (pResponse->RFXSENSOR.rssi << 4) | pResponse->RFXSENSOR.filler;
9285 }
9286
9287 float temp = 0;
9288 int volt = 0;
9289 switch (pResponse->RFXSENSOR.subtype)
9290 {
9291 case sTypeRFXSensorTemp:
9292 {
9293 if ((pResponse->RFXSENSOR.msg1 & 0x80) == 0) //positive temperature?
9294 temp = float((pResponse->RFXSENSOR.msg1 * 256) + pResponse->RFXSENSOR.msg2) / 100.0f;
9295 else
9296 temp = -(float(((pResponse->RFXSENSOR.msg1 & 0x7F) * 256) + pResponse->RFXSENSOR.msg2) / 100.0f);
9297 float AddjValue = 0.0f;
9298 float AddjMulti = 1.0f;
9299 m_sql.GetAddjustment(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, AddjValue, AddjMulti);
9300 temp += AddjValue;
9301 sprintf(szTmp, "%.1f", temp);
9302 }
9303 break;
9304 case sTypeRFXSensorAD:
9305 case sTypeRFXSensorVolt:
9306 {
9307 volt = (pResponse->RFXSENSOR.msg1 * 256) + pResponse->RFXSENSOR.msg2;
9308 if (
9309 (pHardware->HwdType == HTYPE_RFXLAN) ||
9310 (pHardware->HwdType == HTYPE_RFXtrx315) ||
9311 (pHardware->HwdType == HTYPE_RFXtrx433) ||
9312 (pHardware->HwdType == HTYPE_RFXtrx868)
9313 )
9314 {
9315 volt *= 10;
9316 }
9317 sprintf(szTmp, "%d", volt);
9318 }
9319 break;
9320 }
9321 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
9322 if (DevRowIdx == (uint64_t)-1)
9323 return;
9324
9325 switch (pResponse->RFXSENSOR.subtype)
9326 {
9327 case sTypeRFXSensorTemp:
9328 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, temp);
9329 break;
9330 case sTypeRFXSensorAD:
9331 case sTypeRFXSensorVolt:
9332 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, (float)volt);
9333 break;
9334 }
9335
9336 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9337 {
9338 WriteMessageStart();
9339 switch (pResponse->RFXSENSOR.subtype)
9340 {
9341 case sTypeRFXSensorTemp:
9342 WriteMessage("subtype = Temperature");
9343 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXSENSOR.seqnbr);
9344 WriteMessage(szTmp);
9345 sprintf(szTmp, "ID = %d", pResponse->RFXSENSOR.id);
9346 WriteMessage(szTmp);
9347
9348 if ((pResponse->RFXSENSOR.msg1 & 0x80) == 0) //positive temperature?
9349 {
9350 sprintf(szTmp, "Temperature = %.2f C", float((pResponse->RFXSENSOR.msg1 * 256) + pResponse->RFXSENSOR.msg2) / 100.0f);
9351 WriteMessage(szTmp);
9352 }
9353 else
9354 {
9355 sprintf(szTmp, "Temperature = -%.2f C", float(((pResponse->RFXSENSOR.msg1 & 0x7F) * 256) + pResponse->RFXSENSOR.msg2) / 100.0f);
9356 WriteMessage(szTmp);
9357 }
9358 break;
9359 case sTypeRFXSensorAD:
9360 WriteMessage("subtype = A/D");
9361 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXSENSOR.seqnbr);
9362 WriteMessage(szTmp);
9363 sprintf(szTmp, "ID = %d", pResponse->RFXSENSOR.id);
9364 WriteMessage(szTmp);
9365 sprintf(szTmp, "volt = %d mV", (pResponse->RFXSENSOR.msg1 * 256) + pResponse->RFXSENSOR.msg2);
9366 WriteMessage(szTmp);
9367 break;
9368 case sTypeRFXSensorVolt:
9369 WriteMessage("subtype = Voltage");
9370 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXSENSOR.seqnbr);
9371 WriteMessage(szTmp);
9372 sprintf(szTmp, "ID = %d", pResponse->RFXSENSOR.id);
9373 WriteMessage(szTmp);
9374 sprintf(szTmp, "volt = %d mV", (pResponse->RFXSENSOR.msg1 * 256) + pResponse->RFXSENSOR.msg2);
9375 WriteMessage(szTmp);
9376 break;
9377 case sTypeRFXSensorMessage:
9378 WriteMessage("subtype = Message");
9379 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXSENSOR.seqnbr);
9380 WriteMessage(szTmp);
9381 sprintf(szTmp, "ID = %d", pResponse->RFXSENSOR.id);
9382 WriteMessage(szTmp);
9383 switch (pResponse->RFXSENSOR.msg2)
9384 {
9385 case 0x1:
9386 WriteMessage("msg = sensor addresses incremented");
9387 break;
9388 case 0x2:
9389 WriteMessage("msg = battery low detected");
9390 break;
9391 case 0x81:
9392 WriteMessage("msg = no 1-wire device connected");
9393 break;
9394 case 0x82:
9395 WriteMessage("msg = 1-Wire ROM CRC error");
9396 break;
9397 case 0x83:
9398 WriteMessage("msg = 1-Wire device connected is not a DS18B20 or DS2438");
9399 break;
9400 case 0x84:
9401 WriteMessage("msg = no end of read signal received from 1-Wire device");
9402 break;
9403 case 0x85:
9404 WriteMessage("msg = 1-Wire scratch pad CRC error");
9405 break;
9406 default:
9407 WriteMessage("ERROR: unknown message");
9408 break;
9409 }
9410 sprintf(szTmp, "msg = %d", (pResponse->RFXSENSOR.msg1 * 256) + pResponse->RFXSENSOR.msg2);
9411 WriteMessage(szTmp);
9412 break;
9413 default:
9414 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->RFXSENSOR.packettype, pResponse->RFXSENSOR.subtype);
9415 WriteMessage(szTmp);
9416 break;
9417 }
9418 sprintf(szTmp, "Signal level = %d", pResponse->RFXSENSOR.rssi);
9419 WriteMessage(szTmp);
9420 WriteMessageEnd();
9421 }
9422 procResult.DeviceRowIdx = DevRowIdx;
9423 }
9424
decode_RFXMeter(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9425 void MainWorker::decode_RFXMeter(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9426 {
9427 uint64_t DevRowIdx = -1;
9428 char szTmp[100];
9429 uint8_t devType = pTypeRFXMeter;
9430 uint8_t subType = pResponse->RFXMETER.subtype;
9431 if (subType == sTypeRFXMeterCount)
9432 {
9433 std::string ID;
9434 sprintf(szTmp, "%d", (pResponse->RFXMETER.id1 * 256) + pResponse->RFXMETER.id2);
9435 ID = szTmp;
9436 uint8_t Unit = 0;
9437 uint8_t cmnd = 0;
9438 uint8_t SignalLevel = pResponse->RFXMETER.rssi;
9439 uint8_t BatteryLevel = 255;
9440
9441 unsigned long counter = (pResponse->RFXMETER.count1 << 24) + (pResponse->RFXMETER.count2 << 16) + (pResponse->RFXMETER.count3 << 8) + pResponse->RFXMETER.count4;
9442 //float RFXPwr = float(counter) / 1000.0f;
9443
9444 sprintf(szTmp, "%lu", counter);
9445 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
9446 if (DevRowIdx == (uint64_t)-1)
9447 return;
9448 }
9449
9450 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9451 {
9452 WriteMessageStart();
9453 unsigned long counter;
9454
9455 switch (pResponse->RFXMETER.subtype)
9456 {
9457 case sTypeRFXMeterCount:
9458 WriteMessage("subtype = RFXMeter counter");
9459 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXMETER.seqnbr);
9460 WriteMessage(szTmp);
9461 sprintf(szTmp, "ID = %d", (pResponse->RFXMETER.id1 * 256) + pResponse->RFXMETER.id2);
9462 WriteMessage(szTmp);
9463 counter = (pResponse->RFXMETER.count1 << 24) + (pResponse->RFXMETER.count2 << 16) + (pResponse->RFXMETER.count3 << 8) + pResponse->RFXMETER.count4;
9464 sprintf(szTmp, "Counter = %lu", counter);
9465 WriteMessage(szTmp);
9466 sprintf(szTmp, "if RFXPwr = %.3f kWh", float(counter) / 1000.0f);
9467 WriteMessage(szTmp);
9468 break;
9469 case sTypeRFXMeterInterval:
9470 WriteMessage("subtype = RFXMeter new interval time set");
9471 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXMETER.seqnbr);
9472 WriteMessage(szTmp);
9473 sprintf(szTmp, "ID = %d", (pResponse->RFXMETER.id1 * 256) + pResponse->RFXMETER.id2);
9474 WriteMessage(szTmp);
9475 WriteMessage("Interval time = ", false);
9476
9477 switch (pResponse->RFXMETER.count3)
9478 {
9479 case 0x1:
9480 WriteMessage("30 seconds");
9481 break;
9482 case 0x2:
9483 WriteMessage("1 minute");
9484 break;
9485 case 0x4:
9486 WriteMessage("6 minutes");
9487 break;
9488 case 0x8:
9489 WriteMessage("12 minutes");
9490 break;
9491 case 0x10:
9492 WriteMessage("15 minutes");
9493 break;
9494 case 0x20:
9495 WriteMessage("30 minutes");
9496 break;
9497 case 0x40:
9498 WriteMessage("45 minutes");
9499 break;
9500 case 0x80:
9501 WriteMessage("1 hour");
9502 break;
9503 }
9504 break;
9505 case sTypeRFXMeterCalib:
9506 switch (pResponse->RFXMETER.count2 & 0xC0)
9507 {
9508 case 0x0:
9509 WriteMessage("subtype = Calibrate mode for channel 1");
9510 break;
9511 case 0x40:
9512 WriteMessage("subtype = Calibrate mode for channel 2");
9513 break;
9514 case 0x80:
9515 WriteMessage("subtype = Calibrate mode for channel 3");
9516 break;
9517 }
9518 sprintf(szTmp, "ID = %d", (pResponse->RFXMETER.id1 * 256) + pResponse->RFXMETER.id2);
9519 WriteMessage(szTmp);
9520 counter = (((pResponse->RFXMETER.count2 & 0x3F) << 16) + (pResponse->RFXMETER.count3 << 8) + pResponse->RFXMETER.count4) / 1000;
9521 sprintf(szTmp, "Calibrate cnt = %lu msec", counter);
9522 WriteMessage(szTmp);
9523
9524 sprintf(szTmp, "RFXPwr = %.3f kW", 1.0f / (float(16 * counter) / (3600000.0f / 62.5f)));
9525 WriteMessage(szTmp);
9526 break;
9527 case sTypeRFXMeterAddr:
9528 WriteMessage("subtype = New address set, push button for next address");
9529 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXMETER.seqnbr);
9530 WriteMessage(szTmp);
9531 sprintf(szTmp, "ID = %d", (pResponse->RFXMETER.id1 * 256) + pResponse->RFXMETER.id2);
9532 WriteMessage(szTmp);
9533 break;
9534 case sTypeRFXMeterCounterReset:
9535 switch (pResponse->RFXMETER.count2 & 0xC0)
9536 {
9537 case 0x0:
9538 WriteMessage("subtype = Push the button for next mode within 5 seconds or else RESET COUNTER channel 1 will be executed");
9539 break;
9540 case 0x40:
9541 WriteMessage("subtype = Push the button for next mode within 5 seconds or else RESET COUNTER channel 2 will be executed");
9542 break;
9543 case 0x80:
9544 WriteMessage("subtype = Push the button for next mode within 5 seconds or else RESET COUNTER channel 3 will be executed");
9545 break;
9546 }
9547 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXMETER.seqnbr);
9548 WriteMessage(szTmp);
9549 sprintf(szTmp, "ID = %d", (pResponse->RFXMETER.id1 * 256) + pResponse->RFXMETER.id2);
9550 WriteMessage(szTmp);
9551 break;
9552 case sTypeRFXMeterCounterSet:
9553 switch (pResponse->RFXMETER.count2 & 0xC0)
9554 {
9555 case 0x0:
9556 WriteMessage("subtype = Counter channel 1 is reset to zero");
9557 break;
9558 case 0x40:
9559 WriteMessage("subtype = Counter channel 2 is reset to zero");
9560 break;
9561 case 0x80:
9562 WriteMessage("subtype = Counter channel 3 is reset to zero");
9563 break;
9564 }
9565 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXMETER.seqnbr);
9566 WriteMessage(szTmp);
9567 sprintf(szTmp, "ID = %d", (pResponse->RFXMETER.id1 * 256) + pResponse->RFXMETER.id2);
9568 WriteMessage(szTmp);
9569 counter = (pResponse->RFXMETER.count1 << 24) + (pResponse->RFXMETER.count2 << 16) + (pResponse->RFXMETER.count3 << 8) + pResponse->RFXMETER.count4;
9570 sprintf(szTmp, "Counter = %lu", counter);
9571 WriteMessage(szTmp);
9572 break;
9573 case sTypeRFXMeterSetInterval:
9574 WriteMessage("subtype = Push the button for next mode within 5 seconds or else SET INTERVAL MODE will be entered");
9575 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXMETER.seqnbr);
9576 WriteMessage(szTmp);
9577 sprintf(szTmp, "ID = %d", (pResponse->RFXMETER.id1 * 256) + pResponse->RFXMETER.id2);
9578 WriteMessage(szTmp);
9579 break;
9580 case sTypeRFXMeterSetCalib:
9581 switch (pResponse->RFXMETER.count2 & 0xC0)
9582 {
9583 case 0x0:
9584 WriteMessage("subtype = Push the button for next mode within 5 seconds or else CALIBRATION mode for channel 1 will be executed");
9585 break;
9586 case 0x40:
9587 WriteMessage("subtype = Push the button for next mode within 5 seconds or else CALIBRATION mode for channel 2 will be executed");
9588 break;
9589 case 0x80:
9590 WriteMessage("subtype = Push the button for next mode within 5 seconds or else CALIBRATION mode for channel 3 will be executed");
9591 break;
9592 }
9593 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXMETER.seqnbr);
9594 WriteMessage(szTmp);
9595 sprintf(szTmp, "ID = %d", (pResponse->RFXMETER.id1 * 256) + pResponse->RFXMETER.id2);
9596 WriteMessage(szTmp);
9597 break;
9598 case sTypeRFXMeterSetAddr:
9599 WriteMessage("subtype = Push the button for next mode within 5 seconds or else SET ADDRESS MODE will be entered");
9600 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXMETER.seqnbr);
9601 WriteMessage(szTmp);
9602 sprintf(szTmp, "ID = %d", (pResponse->RFXMETER.id1 * 256) + pResponse->RFXMETER.id2);
9603 WriteMessage(szTmp);
9604 break;
9605 case sTypeRFXMeterIdent:
9606 WriteMessage("subtype = RFXMeter identification");
9607 sprintf(szTmp, "Sequence nbr = %d", pResponse->RFXMETER.seqnbr);
9608 WriteMessage(szTmp);
9609 sprintf(szTmp, "ID = %d", (pResponse->RFXMETER.id1 * 256) + pResponse->RFXMETER.id2);
9610 WriteMessage(szTmp);
9611 sprintf(szTmp, "FW version = %02X", pResponse->RFXMETER.count3);
9612 WriteMessage(szTmp);
9613 WriteMessage("Interval time = ", false);
9614
9615 switch (pResponse->RFXMETER.count4)
9616 {
9617 case 0x1:
9618 WriteMessage("30 seconds");
9619 break;
9620 case 0x2:
9621 WriteMessage("1 minute");
9622 break;
9623 case 0x4:
9624 WriteMessage("6 minutes");
9625 break;
9626 case 0x8:
9627 WriteMessage("12 minutes");
9628 break;
9629 case 0x10:
9630 WriteMessage("15 minutes");
9631 break;
9632 case 0x20:
9633 WriteMessage("30 minutes");
9634 break;
9635 case 0x40:
9636 WriteMessage("45 minutes");
9637 break;
9638 case 0x80:
9639 WriteMessage("1 hour");
9640 break;
9641 }
9642 break;
9643 default:
9644 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->RFXMETER.packettype, pResponse->RFXMETER.subtype);
9645 WriteMessage(szTmp);
9646 break;
9647 }
9648 sprintf(szTmp, "Signal level = %d", pResponse->RFXMETER.rssi);
9649 WriteMessage(szTmp);
9650 WriteMessageEnd();
9651 }
9652 procResult.DeviceRowIdx = DevRowIdx;
9653 }
9654
decode_P1MeterPower(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9655 void MainWorker::decode_P1MeterPower(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9656 {
9657 char szTmp[200];
9658 const _tP1Power* p1Power = reinterpret_cast<const _tP1Power*>(pResponse);
9659
9660 if (p1Power->len != sizeof(_tP1Power) - 1)
9661 return;
9662
9663 uint8_t devType = p1Power->type;
9664 uint8_t subType = p1Power->subtype;
9665 std::string ID;
9666 sprintf(szTmp, "%d", p1Power->ID);
9667 ID = szTmp;
9668
9669 uint8_t Unit = subType;
9670 uint8_t cmnd = 0;
9671 uint8_t SignalLevel = 12;
9672 uint8_t BatteryLevel = 255;
9673
9674 sprintf(szTmp, "%u;%u;%u;%u;%u;%u",
9675 p1Power->powerusage1,
9676 p1Power->powerusage2,
9677 p1Power->powerdeliv1,
9678 p1Power->powerdeliv2,
9679 p1Power->usagecurrent,
9680 p1Power->delivcurrent
9681 );
9682 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
9683 if (DevRowIdx == (uint64_t)-1)
9684 return;
9685
9686 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, cmnd, szTmp);
9687
9688 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9689 {
9690 WriteMessageStart();
9691 switch (p1Power->subtype)
9692 {
9693 case sTypeP1Power:
9694 WriteMessage("subtype = P1 Smart Meter Power");
9695
9696 sprintf(szTmp, "powerusage1 = %.3f kWh", float(p1Power->powerusage1) / 1000.0f);
9697 WriteMessage(szTmp);
9698 sprintf(szTmp, "powerusage2 = %.3f kWh", float(p1Power->powerusage2) / 1000.0f);
9699 WriteMessage(szTmp);
9700
9701 sprintf(szTmp, "powerdeliv1 = %.3f kWh", float(p1Power->powerdeliv1) / 1000.0f);
9702 WriteMessage(szTmp);
9703 sprintf(szTmp, "powerdeliv2 = %.3f kWh", float(p1Power->powerdeliv2) / 1000.0f);
9704 WriteMessage(szTmp);
9705
9706 sprintf(szTmp, "current usage = %03u Watt", p1Power->usagecurrent);
9707 WriteMessage(szTmp);
9708 sprintf(szTmp, "current deliv = %03u Watt", p1Power->delivcurrent);
9709 WriteMessage(szTmp);
9710 break;
9711 default:
9712 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", p1Power->type, p1Power->subtype);
9713 WriteMessage(szTmp);
9714 break;
9715 }
9716 WriteMessageEnd();
9717 }
9718 procResult.DeviceRowIdx = DevRowIdx;
9719 }
9720
decode_P1MeterGas(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9721 void MainWorker::decode_P1MeterGas(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9722 {
9723 char szTmp[200];
9724 const _tP1Gas* p1Gas = reinterpret_cast<const _tP1Gas*>(pResponse);
9725 if (p1Gas->len != sizeof(_tP1Gas) - 1)
9726 return;
9727
9728 uint8_t devType = p1Gas->type;
9729 uint8_t subType = p1Gas->subtype;
9730 std::string ID;
9731 sprintf(szTmp, "%d", p1Gas->ID);
9732 ID = szTmp;
9733 uint8_t Unit = subType;
9734 uint8_t cmnd = 0;
9735 uint8_t SignalLevel = 12;
9736 uint8_t BatteryLevel = 255;
9737
9738 sprintf(szTmp, "%u", p1Gas->gasusage);
9739 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
9740 if (DevRowIdx == (uint64_t)-1)
9741 return;
9742
9743 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9744 {
9745 WriteMessageStart();
9746 switch (p1Gas->subtype)
9747 {
9748 case sTypeP1Gas:
9749 WriteMessage("subtype = P1 Smart Meter Gas");
9750
9751 sprintf(szTmp, "gasusage = %.3f m3", float(p1Gas->gasusage) / 1000.0f);
9752 WriteMessage(szTmp);
9753 break;
9754 default:
9755 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", p1Gas->type, p1Gas->subtype);
9756 WriteMessage(szTmp);
9757 break;
9758 }
9759 WriteMessageEnd();
9760 }
9761 procResult.DeviceRowIdx = DevRowIdx;
9762 }
9763
decode_YouLessMeter(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9764 void MainWorker::decode_YouLessMeter(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9765 {
9766 char szTmp[200];
9767 const CYouLess::YouLessMeter* pMeter = reinterpret_cast<const CYouLess::YouLessMeter*>(pResponse);
9768 uint8_t devType = pMeter->type;
9769 uint8_t subType = pMeter->subtype;
9770 sprintf(szTmp, "%d", pMeter->ID1);
9771 std::string ID = szTmp;
9772 uint8_t Unit = subType;
9773 uint8_t cmnd = 0;
9774 uint8_t SignalLevel = 12;
9775 uint8_t BatteryLevel = 255;
9776
9777 sprintf(szTmp, "%lu;%lu",
9778 pMeter->powerusage,
9779 pMeter->usagecurrent
9780 );
9781 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
9782 if (DevRowIdx == (uint64_t)-1)
9783 return;
9784
9785 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, cmnd, szTmp);
9786
9787 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9788 {
9789 WriteMessageStart();
9790 switch (pMeter->subtype)
9791 {
9792 case sTypeYouLess:
9793 WriteMessage("subtype = YouLess Meter");
9794
9795 sprintf(szTmp, "powerusage = %.3f kWh", float(pMeter->powerusage) / 1000.0f);
9796 WriteMessage(szTmp);
9797 sprintf(szTmp, "current usage = %03lu Watt", pMeter->usagecurrent);
9798 WriteMessage(szTmp);
9799 break;
9800 default:
9801 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pMeter->type, pMeter->subtype);
9802 WriteMessage(szTmp);
9803 break;
9804 }
9805 WriteMessageEnd();
9806 }
9807 procResult.DeviceRowIdx = DevRowIdx;
9808 }
9809
decode_Rego6XXTemp(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9810 void MainWorker::decode_Rego6XXTemp(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9811 {
9812 char szTmp[200];
9813 const _tRego6XXTemp* pRego = reinterpret_cast<const _tRego6XXTemp*>(pResponse);
9814 uint8_t devType = pRego->type;
9815 uint8_t subType = pRego->subtype;
9816 std::string ID = pRego->ID;
9817 uint8_t Unit = subType;
9818 uint8_t cmnd = 0;
9819 uint8_t SignalLevel = 12;
9820 uint8_t BatteryLevel = 255;
9821
9822 sprintf(szTmp, "%.1f",
9823 pRego->temperature
9824 );
9825 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
9826 if (DevRowIdx == (uint64_t)-1)
9827 return;
9828 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, pRego->temperature);
9829
9830 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9831 {
9832 WriteMessageStart();
9833 WriteMessage("subtype = Rego6XX Temp");
9834
9835 sprintf(szTmp, "Temp = %.1f", pRego->temperature);
9836 WriteMessage(szTmp);
9837 WriteMessageEnd();
9838 }
9839 procResult.DeviceRowIdx = DevRowIdx;
9840 }
9841
decode_Rego6XXValue(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9842 void MainWorker::decode_Rego6XXValue(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9843 {
9844 char szTmp[200];
9845 const _tRego6XXStatus* pRego = reinterpret_cast<const _tRego6XXStatus*>(pResponse);
9846 uint8_t devType = pRego->type;
9847 uint8_t subType = pRego->subtype;
9848 std::string ID = pRego->ID;
9849 uint8_t Unit = subType;
9850 int numValue = pRego->value;
9851 uint8_t SignalLevel = 12;
9852 uint8_t BatteryLevel = 255;
9853
9854 sprintf(szTmp, "%d",
9855 pRego->value
9856 );
9857
9858 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, numValue, szTmp, procResult.DeviceName);
9859 if (DevRowIdx == (uint64_t)-1)
9860 return;
9861
9862 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9863 {
9864 WriteMessageStart();
9865 switch (pRego->subtype)
9866 {
9867 case sTypeRego6XXStatus:
9868 WriteMessage("subtype = Rego6XX Status");
9869 sprintf(szTmp, "Status = %d", pRego->value);
9870 WriteMessage(szTmp);
9871 break;
9872 case sTypeRego6XXCounter:
9873 WriteMessage("subtype = Rego6XX Counter");
9874 sprintf(szTmp, "Counter = %d", pRego->value);
9875 WriteMessage(szTmp);
9876 break;
9877 }
9878 WriteMessageEnd();
9879 }
9880 procResult.DeviceRowIdx = DevRowIdx;
9881 }
9882
decode_AirQuality(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9883 void MainWorker::decode_AirQuality(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9884 {
9885 char szTmp[200];
9886 const _tAirQualityMeter* pMeter = reinterpret_cast<const _tAirQualityMeter*>(pResponse);
9887 uint8_t devType = pMeter->type;
9888 uint8_t subType = pMeter->subtype;
9889 sprintf(szTmp, "%d", pMeter->id1);
9890 std::string ID = szTmp;
9891 uint8_t Unit = pMeter->id2;
9892 //uint8_t cmnd=0;
9893 uint8_t SignalLevel = 12;
9894 uint8_t BatteryLevel = 255;
9895
9896 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, pMeter->airquality, procResult.DeviceName);
9897 if (DevRowIdx == (uint64_t)-1)
9898 return;
9899
9900 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, (const int)pMeter->airquality);
9901
9902 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9903 {
9904 WriteMessageStart();
9905 switch (pMeter->subtype)
9906 {
9907 case sTypeVoltcraft:
9908 WriteMessage("subtype = Voltcraft CO-20");
9909
9910 sprintf(szTmp, "CO2 = %d ppm", pMeter->airquality);
9911 WriteMessage(szTmp);
9912 if (pMeter->airquality < 700)
9913 strcpy(szTmp, "Quality = Excellent");
9914 else if (pMeter->airquality < 900)
9915 strcpy(szTmp, "Quality = Good");
9916 else if (pMeter->airquality < 1100)
9917 strcpy(szTmp, "Quality = Fair");
9918 else if (pMeter->airquality < 1600)
9919 strcpy(szTmp, "Quality = Mediocre");
9920 else
9921 strcpy(szTmp, "Quality = Bad");
9922 WriteMessage(szTmp);
9923 break;
9924 default:
9925 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pMeter->type, pMeter->subtype);
9926 WriteMessage(szTmp);
9927 break;
9928 }
9929 WriteMessageEnd();
9930 }
9931 procResult.DeviceRowIdx = DevRowIdx;
9932 }
9933
decode_Usage(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9934 void MainWorker::decode_Usage(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9935 {
9936 char szTmp[200];
9937 const _tUsageMeter* pMeter = reinterpret_cast<const _tUsageMeter*>(pResponse);
9938 uint8_t devType = pMeter->type;
9939 uint8_t subType = pMeter->subtype;
9940 sprintf(szTmp, "%X%02X%02X%02X", pMeter->id1, pMeter->id2, pMeter->id3, pMeter->id4);
9941 std::string ID = szTmp;
9942 uint8_t Unit = pMeter->dunit;
9943 uint8_t cmnd = 0;
9944 uint8_t SignalLevel = 12;
9945 uint8_t BatteryLevel = 255;
9946
9947 sprintf(szTmp, "%.1f", pMeter->fusage);
9948
9949 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
9950 if (DevRowIdx == (uint64_t)-1)
9951 return;
9952
9953 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, pMeter->fusage);
9954
9955 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9956 {
9957 WriteMessageStart();
9958 switch (pMeter->subtype)
9959 {
9960 case sTypeElectric:
9961 WriteMessage("subtype = Electric");
9962
9963 sprintf(szTmp, "Usage = %.1f W", pMeter->fusage);
9964 WriteMessage(szTmp);
9965 break;
9966 default:
9967 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pMeter->type, pMeter->subtype);
9968 WriteMessage(szTmp);
9969 break;
9970 }
9971 WriteMessageEnd();
9972 }
9973 procResult.DeviceRowIdx = DevRowIdx;
9974 }
9975
decode_Lux(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)9976 void MainWorker::decode_Lux(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
9977 {
9978 char szTmp[200];
9979 const _tLightMeter* pMeter = reinterpret_cast<const _tLightMeter*>(pResponse);
9980 uint8_t devType = pMeter->type;
9981 uint8_t subType = pMeter->subtype;
9982 sprintf(szTmp, "%X%02X%02X%02X", pMeter->id1, pMeter->id2, pMeter->id3, pMeter->id4);
9983 std::string ID = szTmp;
9984 uint8_t Unit = pMeter->dunit;
9985 uint8_t cmnd = 0;
9986 uint8_t SignalLevel = 12;
9987 uint8_t BatteryLevel = pMeter->battery_level;
9988
9989 sprintf(szTmp, "%.0f", pMeter->fLux);
9990
9991 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
9992 if (DevRowIdx == (uint64_t)-1)
9993 return;
9994
9995 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, pMeter->fLux);
9996
9997 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
9998 {
9999 WriteMessageStart();
10000 switch (pMeter->subtype)
10001 {
10002 case sTypeLux:
10003 WriteMessage("subtype = Lux");
10004
10005 sprintf(szTmp, "Lux = %.1f W", pMeter->fLux);
10006 WriteMessage(szTmp);
10007 break;
10008 default:
10009 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pMeter->type, pMeter->subtype);
10010 WriteMessage(szTmp);
10011 break;
10012 }
10013 WriteMessageEnd();
10014 }
10015 procResult.DeviceRowIdx = DevRowIdx;
10016 }
10017
decode_Thermostat(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)10018 void MainWorker::decode_Thermostat(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
10019 {
10020 char szTmp[200];
10021 const _tThermostat* pMeter = reinterpret_cast<const _tThermostat*>(pResponse);
10022 uint8_t devType = pMeter->type;
10023 uint8_t subType = pMeter->subtype;
10024 sprintf(szTmp, "%X%02X%02X%02X", pMeter->id1, pMeter->id2, pMeter->id3, pMeter->id4);
10025 std::string ID = szTmp;
10026 uint8_t Unit = pMeter->dunit;
10027 uint8_t cmnd = 0;
10028 uint8_t SignalLevel = 12;
10029 uint8_t BatteryLevel = pMeter->battery_level;
10030
10031 switch (pMeter->subtype)
10032 {
10033 case sTypeThermSetpoint:
10034 sprintf(szTmp, "%.2f", pMeter->temp);
10035 break;
10036 default:
10037 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pMeter->type, pMeter->subtype);
10038 WriteMessage(szTmp);
10039 return;
10040 }
10041
10042 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10043 if (DevRowIdx == (uint64_t)-1)
10044 return;
10045
10046 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, pMeter->temp);
10047
10048 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
10049 {
10050 WriteMessageStart();
10051 double tvalue = ConvertTemperature(pMeter->temp, m_sql.m_tempsign[0]);
10052 switch (pMeter->subtype)
10053 {
10054 case sTypeThermSetpoint:
10055 WriteMessage("subtype = SetPoint");
10056 sprintf(szTmp, "Temp = %.2f", tvalue);
10057 WriteMessage(szTmp);
10058 break;
10059 default:
10060 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pMeter->type, pMeter->subtype);
10061 WriteMessage(szTmp);
10062 break;
10063 }
10064 WriteMessageEnd();
10065 }
10066 procResult.DeviceRowIdx = DevRowIdx;
10067 }
10068
decode_General(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult,const uint8_t SignalLevel,const uint8_t BatteryLevel)10069 void MainWorker::decode_General(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult, const uint8_t SignalLevel, const uint8_t BatteryLevel)
10070 {
10071 char szTmp[200];
10072 const _tGeneralDevice* pMeter = reinterpret_cast<const _tGeneralDevice*>(pResponse);
10073 uint8_t devType = pMeter->type;
10074 uint8_t subType = pMeter->subtype;
10075
10076 if (
10077 (subType == sTypeVoltage) ||
10078 (subType == sTypeCurrent) ||
10079 (subType == sTypePercentage) ||
10080 (subType == sTypeWaterflow) ||
10081 (subType == sTypePressure) ||
10082 (subType == sTypeZWaveClock) ||
10083 (subType == sTypeZWaveThermostatMode) ||
10084 (subType == sTypeZWaveThermostatFanMode) ||
10085 (subType == sTypeZWaveThermostatOperatingState) ||
10086 (subType == sTypeFan) ||
10087 (subType == sTypeTextStatus) ||
10088 (subType == sTypeSoundLevel) ||
10089 (subType == sTypeBaro) ||
10090 (subType == sTypeDistance) ||
10091 (subType == sTypeSoilMoisture) ||
10092 (subType == sTypeCustom) ||
10093 (subType == sTypeKwh) ||
10094 (subType == sTypeZWaveAlarm)
10095 )
10096 {
10097 sprintf(szTmp, "%08X", (unsigned int)pMeter->intval1);
10098 }
10099 else
10100 {
10101 sprintf(szTmp, "%d", pMeter->id);
10102
10103 }
10104 std::string ID = szTmp;
10105 uint8_t Unit = 1;
10106 uint8_t cmnd = 0;
10107 strcpy(szTmp, "");
10108
10109 uint64_t DevRowIdx = -1;
10110
10111 if (subType == sTypeVisibility)
10112 {
10113 sprintf(szTmp, "%.1f", pMeter->floatval1);
10114 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10115 if (DevRowIdx == (uint64_t)-1)
10116 return;
10117 }
10118 else if (subType == sTypeDistance)
10119 {
10120 sprintf(szTmp, "%.1f", pMeter->floatval1);
10121 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10122 if (DevRowIdx == (uint64_t)-1)
10123 return;
10124 }
10125 else if (subType == sTypeSolarRadiation)
10126 {
10127 sprintf(szTmp, "%.1f", pMeter->floatval1);
10128 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10129 if (DevRowIdx == (uint64_t)-1)
10130 return;
10131 }
10132 else if (subType == sTypeSoilMoisture)
10133 {
10134 cmnd = pMeter->intval2;
10135 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, procResult.DeviceName);
10136 if (DevRowIdx == (uint64_t)-1)
10137 return;
10138 }
10139 else if (subType == sTypeLeafWetness)
10140 {
10141 cmnd = pMeter->intval1;
10142 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, procResult.DeviceName);
10143 if (DevRowIdx == (uint64_t)-1)
10144 return;
10145 }
10146 else if (subType == sTypeVoltage)
10147 {
10148 sprintf(szTmp, "%.3f", pMeter->floatval1);
10149 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10150 if (DevRowIdx == (uint64_t)-1)
10151 return;
10152 }
10153 else if (subType == sTypeCurrent)
10154 {
10155 sprintf(szTmp, "%.3f", pMeter->floatval1);
10156 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10157 if (DevRowIdx == (uint64_t)-1)
10158 return;
10159 }
10160 else if (subType == sTypeBaro)
10161 {
10162 sprintf(szTmp, "%.02f;%d", pMeter->floatval1, pMeter->intval2);
10163 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10164 if (DevRowIdx == (uint64_t)-1)
10165 return;
10166 }
10167 else if (subType == sTypePressure)
10168 {
10169 sprintf(szTmp, "%.1f", pMeter->floatval1);
10170 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10171 if (DevRowIdx == (uint64_t)-1)
10172 return;
10173 }
10174 else if (subType == sTypePercentage)
10175 {
10176 sprintf(szTmp, "%.2f", pMeter->floatval1);
10177 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10178 if (DevRowIdx == (uint64_t)-1)
10179 return;
10180 }
10181 else if (subType == sTypeWaterflow)
10182 {
10183 sprintf(szTmp, "%.2f", pMeter->floatval1);
10184 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10185 if (DevRowIdx == (uint64_t)-1)
10186 return;
10187 }
10188 else if (subType == sTypeFan)
10189 {
10190 sprintf(szTmp, "%d", pMeter->intval2);
10191 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10192 if (DevRowIdx == (uint64_t)-1)
10193 return;
10194 }
10195 else if (subType == sTypeSoundLevel)
10196 {
10197 sprintf(szTmp, "%d", pMeter->intval2);
10198 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10199 if (DevRowIdx == (uint64_t)-1)
10200 return;
10201 }
10202 else if (subType == sTypeZWaveClock)
10203 {
10204 int tintval = pMeter->intval2;
10205 int day = tintval / (24 * 60); tintval -= (day * 24 * 60);
10206 int hour = tintval / (60); tintval -= (hour * 60);
10207 int minute = tintval;
10208 sprintf(szTmp, "%d;%d;%d", day, hour, minute);
10209 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10210 }
10211 else if ((subType == sTypeZWaveThermostatMode) || (subType == sTypeZWaveThermostatFanMode) || (subType == sTypeZWaveThermostatOperatingState))
10212 {
10213 cmnd = (uint8_t)pMeter->intval2;
10214 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, procResult.DeviceName);
10215 }
10216 else if (subType == sTypeKwh)
10217 {
10218 sprintf(szTmp, "%.3f;%.3f", pMeter->floatval1, pMeter->floatval2);
10219 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10220 }
10221 else if (subType == sTypeAlert)
10222 {
10223 if (strcmp(pMeter->text, ""))
10224 sprintf(szTmp, "(%d) %s", pMeter->intval1, pMeter->text);
10225 else
10226 sprintf(szTmp, "%d", pMeter->intval1);
10227 cmnd = pMeter->intval1;
10228 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10229 if (DevRowIdx == (uint64_t)-1)
10230 return;
10231 }
10232 else if (subType == sTypeCustom)
10233 {
10234 sprintf(szTmp, "%.4f", pMeter->floatval1);
10235 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10236 if (DevRowIdx == (uint64_t)-1)
10237 return;
10238 }
10239 else if (subType == sTypeZWaveAlarm)
10240 {
10241 Unit = pMeter->id;
10242 cmnd = pMeter->intval2;
10243 strcpy(szTmp, pMeter->text);
10244 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10245 if (DevRowIdx == (uint64_t)-1)
10246 return;
10247 }
10248 else if (subType == sTypeTextStatus)
10249 {
10250 strcpy(szTmp, pMeter->text);
10251 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, szTmp, procResult.DeviceName);
10252 }
10253 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, cmnd, szTmp);
10254
10255 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
10256 {
10257 WriteMessageStart();
10258 switch (pMeter->subtype)
10259 {
10260 case sTypeVisibility:
10261 WriteMessage("subtype = Visibility");
10262 sprintf(szTmp, "Visibility = %.1f km", pMeter->floatval1);
10263 WriteMessage(szTmp);
10264 break;
10265 case sTypeDistance:
10266 WriteMessage("subtype = Distance");
10267 sprintf(szTmp, "Distance = %.1f cm", pMeter->floatval1);
10268 WriteMessage(szTmp);
10269 break;
10270 case sTypeSolarRadiation:
10271 WriteMessage("subtype = Solar Radiation");
10272 sprintf(szTmp, "Radiation = %.1f Watt/m2", pMeter->floatval1);
10273 WriteMessage(szTmp);
10274 break;
10275 case sTypeSoilMoisture:
10276 WriteMessage("subtype = Soil Moisture");
10277 sprintf(szTmp, "Moisture = %d cb", pMeter->intval2);
10278 WriteMessage(szTmp);
10279 break;
10280 case sTypeLeafWetness:
10281 WriteMessage("subtype = Leaf Wetness");
10282 sprintf(szTmp, "Wetness = %d", pMeter->intval1);
10283 WriteMessage(szTmp);
10284 break;
10285 case sTypeVoltage:
10286 WriteMessage("subtype = Voltage");
10287 sprintf(szTmp, "Voltage = %.3f V", pMeter->floatval1);
10288 WriteMessage(szTmp);
10289 break;
10290 case sTypeCurrent:
10291 WriteMessage("subtype = Current");
10292 sprintf(szTmp, "Current = %.3f V", pMeter->floatval1);
10293 WriteMessage(szTmp);
10294 break;
10295 case sTypePressure:
10296 WriteMessage("subtype = Pressure");
10297 sprintf(szTmp, "Pressure = %.1f bar", pMeter->floatval1);
10298 WriteMessage(szTmp);
10299 break;
10300 case sTypeBaro:
10301 WriteMessage("subtype = Barometric Pressure");
10302 sprintf(szTmp, "Pressure = %.1f hPa", pMeter->floatval1);
10303 WriteMessage(szTmp);
10304 break;
10305 case sTypeFan:
10306 WriteMessage("subtype = Fan");
10307 sprintf(szTmp, "Speed = %d RPM", pMeter->intval2);
10308 WriteMessage(szTmp);
10309 break;
10310 case sTypeSoundLevel:
10311 WriteMessage("subtype = Sound Level");
10312 sprintf(szTmp, "Sound Level = %d dB", pMeter->intval2);
10313 WriteMessage(szTmp);
10314 break;
10315 case sTypeZWaveClock:
10316 {
10317 int tintval = pMeter->intval2;
10318 int day = tintval / (24 * 60); tintval -= (day * 24 * 60);
10319 int hour = tintval / (60); tintval -= (hour * 60);
10320 int minute = tintval;
10321 WriteMessage("subtype = Thermostat Clock");
10322 sprintf(szTmp, "Clock = %s %02d:%02d", ZWave_Clock_Days(day), hour, minute);
10323 WriteMessage(szTmp);
10324 }
10325 break;
10326 case sTypeZWaveThermostatMode:
10327 WriteMessage("subtype = Thermostat Mode");
10328 //sprintf(szTmp, "Mode = %d (%s)", pMeter->intval2, ZWave_Thermostat_Modes[pMeter->intval2]);
10329 sprintf(szTmp, "Mode = %d", pMeter->intval2);
10330 WriteMessage(szTmp);
10331 break;
10332 case sTypeZWaveThermostatFanMode:
10333 WriteMessage("subtype = Thermostat Fan Mode");
10334 sprintf(szTmp, "Mode = %d (%s)", pMeter->intval2, ZWave_Thermostat_Fan_Modes[pMeter->intval2]);
10335 WriteMessage(szTmp);
10336 break;
10337 case sTypeZWaveThermostatOperatingState:
10338 WriteMessage("subtype = Thermostat Operating State");
10339 sprintf(szTmp, "State = %d", pMeter->intval2);
10340 WriteMessage(szTmp);
10341 break;
10342 case sTypePercentage:
10343 WriteMessage("subtype = Percentage");
10344 sprintf(szTmp, "Percentage = %.2f", pMeter->floatval1);
10345 WriteMessage(szTmp);
10346 break;
10347 case sTypeWaterflow:
10348 WriteMessage("subtype = Waterflow");
10349 sprintf(szTmp, "l/min = %.2f", pMeter->floatval1);
10350 WriteMessage(szTmp);
10351 break;
10352 case sTypeKwh:
10353 WriteMessage("subtype = kWh");
10354 sprintf(szTmp, "Instant = %.3f", pMeter->floatval1);
10355 WriteMessage(szTmp);
10356 sprintf(szTmp, "Counter = %.3f", pMeter->floatval2 / 1000.0f);
10357 WriteMessage(szTmp);
10358 break;
10359 case sTypeAlert:
10360 WriteMessage("subtype = Alert");
10361 sprintf(szTmp, "Alert = %d", pMeter->intval1);
10362 WriteMessage(szTmp);
10363 break;
10364 case sTypeCustom:
10365 WriteMessage("subtype = Custom Sensor");
10366 sprintf(szTmp, "Value = %g", pMeter->floatval1);
10367 WriteMessage(szTmp);
10368 break;
10369 case sTypeZWaveAlarm:
10370 WriteMessage("subtype = Alarm");
10371 sprintf(szTmp, "Level = %d (0x%02X) %s", pMeter->intval2, pMeter->intval2, pMeter->text);
10372 WriteMessage(szTmp);
10373 break;
10374 case sTypeTextStatus:
10375 WriteMessage("subtype = Text");
10376 sprintf(szTmp, "Text = %s", pMeter->text);
10377 WriteMessage(szTmp);
10378 break;
10379 default:
10380 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pMeter->type, pMeter->subtype);
10381 WriteMessage(szTmp);
10382 break;
10383 }
10384 WriteMessageEnd();
10385 }
10386 procResult.DeviceRowIdx = DevRowIdx;
10387 }
10388
decode_GeneralSwitch(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)10389 void MainWorker::decode_GeneralSwitch(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
10390 {
10391 char szTmp[200];
10392 const _tGeneralSwitch* pSwitch = reinterpret_cast<const _tGeneralSwitch*>(pResponse);
10393 uint8_t devType = pSwitch->type;
10394 uint8_t subType = pSwitch->subtype;
10395
10396 sprintf(szTmp, "%08X", pSwitch->id);
10397 std::string ID = szTmp;
10398 uint8_t Unit = pSwitch->unitcode;
10399 uint8_t cmnd = pSwitch->cmnd;
10400 uint8_t level = pSwitch->level;
10401 uint8_t SignalLevel = pSwitch->rssi;
10402
10403 sprintf(szTmp, "%d", level);
10404 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, -1, cmnd, szTmp, procResult.DeviceName);
10405 if (DevRowIdx == (uint64_t)-1)
10406 return;
10407 uint8_t check_cmnd = cmnd;
10408 if ((cmnd == gswitch_sGroupOff) || (cmnd == gswitch_sGroupOn))
10409 check_cmnd = (cmnd == gswitch_sGroupOff) ? gswitch_sOff : gswitch_sOn;
10410 CheckSceneCode(DevRowIdx, devType, subType, check_cmnd, szTmp, procResult.DeviceName);
10411
10412 if ((cmnd == gswitch_sGroupOff) || (cmnd == gswitch_sGroupOn))
10413 {
10414 //set the status of all lights with the same code to on/off
10415 m_sql.GeneralSwitchGroupCmd(ID, subType, (cmnd == gswitch_sGroupOff) ? gswitch_sOff : gswitch_sOn);
10416 }
10417
10418 procResult.DeviceRowIdx = DevRowIdx;
10419 }
10420
10421 //BBQ sensor has two temperature sensors, add them as two temperature devices
decode_BBQ(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)10422 void MainWorker::decode_BBQ(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
10423 {
10424 char szTmp[100];
10425 uint8_t devType = pTypeBBQ;
10426 uint8_t subType = pResponse->BBQ.subtype;
10427
10428 sprintf(szTmp, "%d", 1);//(pResponse->BBQ.id1 * 256) + pResponse->BBQ.id2); //this because every time you turn the device on, you get a new ID
10429 std::string ID = szTmp;
10430
10431 //The transmitter and receiver are negotiating a new ID every 15/20 minutes,
10432 //for this we need to work with fixed ID's
10433 uint8_t Unit = 1;// pResponse->BBQ.id2;
10434
10435 uint8_t cmnd = 0;
10436 uint8_t SignalLevel = pResponse->BBQ.rssi;
10437 uint8_t BatteryLevel = 0;
10438 if ((pResponse->BBQ.battery_level & 0x0F) == 0)
10439 BatteryLevel = 0;
10440 else
10441 BatteryLevel = 100;
10442
10443 uint64_t DevRowIdx = 0;
10444
10445 float temp1, temp2;
10446 temp1 = float((pResponse->BBQ.sensor1h * 256) + pResponse->BBQ.sensor1l);// / 10.0f;
10447 temp2 = float((pResponse->BBQ.sensor2h * 256) + pResponse->BBQ.sensor2l);// / 10.0f;
10448
10449 sprintf(szTmp, "%.0f;%.0f", temp1, temp2);
10450 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10451 if (DevRowIdx == (uint64_t)-1)
10452 return;
10453 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
10454 {
10455 WriteMessageStart();
10456 switch (pResponse->BBQ.subtype)
10457 {
10458 case sTypeBBQ1:
10459 WriteMessage("subtype = Maverick ET-732/733");
10460 break;
10461 default:
10462 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->BBQ.packettype, pResponse->BBQ.subtype);
10463 WriteMessage(szTmp);
10464 break;
10465 }
10466
10467 sprintf(szTmp, "Sequence nbr = %d", pResponse->BBQ.seqnbr);
10468 WriteMessage(szTmp);
10469 sprintf(szTmp, "ID = %d", (pResponse->BBQ.id1 * 256) + pResponse->BBQ.id2);
10470 WriteMessage(szTmp);
10471
10472 sprintf(szTmp, "Sensor1 Temp = %.1f C", temp1);
10473 WriteMessage(szTmp);
10474 sprintf(szTmp, "Sensor2 Temp = %.1f C", temp2);
10475 WriteMessage(szTmp);
10476
10477 sprintf(szTmp, "Signal level = %d", pResponse->BBQ.rssi);
10478 WriteMessage(szTmp);
10479
10480 if ((pResponse->BBQ.battery_level & 0x0F) == 0)
10481 WriteMessage("Battery = Low");
10482 else
10483 WriteMessage("Battery = OK");
10484 WriteMessageEnd();
10485 }
10486
10487 //Send the two sensors
10488
10489 //Temp
10490 RBUF tsen;
10491 memset(&tsen, 0, sizeof(RBUF));
10492 tsen.TEMP.packetlength = sizeof(tsen.TEMP) - 1;
10493 tsen.TEMP.packettype = pTypeTEMP;
10494 tsen.TEMP.subtype = sTypeTEMP6;
10495 tsen.TEMP.battery_level = 9;
10496 tsen.TEMP.rssi = SignalLevel;
10497 tsen.TEMP.id1 = 0;
10498 tsen.TEMP.id2 = 1;
10499
10500 tsen.TEMP.tempsign = (temp1 >= 0) ? 0 : 1;
10501 int at10 = round(std::abs(temp1 * 10.0f));
10502 tsen.TEMP.temperatureh = (BYTE)(at10 / 256);
10503 at10 -= (tsen.TEMP.temperatureh * 256);
10504 tsen.TEMP.temperaturel = (BYTE)(at10);
10505 _tRxMessageProcessingResult tmpProcResult1;
10506 tmpProcResult1.DeviceName = "";
10507 tmpProcResult1.DeviceRowIdx = -1;
10508 decode_Temp(pHardware, (const tRBUF*)&tsen.TEMP, tmpProcResult1);
10509
10510 tsen.TEMP.id1 = 0;
10511 tsen.TEMP.id2 = 2;
10512
10513 tsen.TEMP.tempsign = (temp2 >= 0) ? 0 : 1;
10514 at10 = round(std::abs(temp2 * 10.0f));
10515 tsen.TEMP.temperatureh = (BYTE)(at10 / 256);
10516 at10 -= (tsen.TEMP.temperatureh * 256);
10517 tsen.TEMP.temperaturel = (BYTE)(at10);
10518 _tRxMessageProcessingResult tmpProcResult2;
10519 tmpProcResult2.DeviceName = "";
10520 tmpProcResult2.DeviceRowIdx = -1;
10521 decode_Temp(pHardware, (const tRBUF*)&tsen.TEMP, tmpProcResult2);
10522
10523 procResult.DeviceRowIdx = DevRowIdx;
10524 }
10525
decode_Cartelectronic(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)10526 void MainWorker::decode_Cartelectronic(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
10527 {
10528 char szTmp[100];
10529 std::string ID;
10530
10531 sprintf(szTmp, "%llu", ((unsigned long long)(pResponse->TIC.id1) << 32) + (pResponse->TIC.id2 << 24) + (pResponse->TIC.id3 << 16) + (pResponse->TIC.id4 << 8) + (pResponse->TIC.id5));
10532 ID = szTmp;
10533 //uint8_t Unit = 0;
10534 //uint8_t cmnd = 0;
10535
10536 uint8_t subType = pResponse->TIC.subtype;
10537
10538 switch (subType)
10539 {
10540 case sTypeTIC:
10541 decode_CartelectronicTIC(pHardware, pResponse, procResult);
10542 WriteMessage("Cartelectronic TIC received");
10543 break;
10544 case sTypeCEencoder:
10545 decode_CartelectronicEncoder(pHardware, pResponse, procResult);
10546 WriteMessage("Cartelectronic Encoder received");
10547 break;
10548 default:
10549 WriteMessage("Cartelectronic protocol not supported");
10550 break;
10551 }
10552 }
10553
decode_ASyncPort(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)10554 void MainWorker::decode_ASyncPort(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
10555 {
10556 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
10557 {
10558 WriteMessageStart();
10559
10560 char szTmp[100];
10561 //uint8_t subType = pResponse->ASYNCPORT.subtype;
10562
10563 switch (pResponse->ASYNCPORT.subtype)
10564 {
10565 case sTypeASYNCconfig:
10566 WriteMessage("subtype = Async port configure");
10567 break;
10568 default:
10569 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->ASYNCPORT.packettype, pResponse->ASYNCPORT.subtype);
10570 WriteMessage(szTmp);
10571 break;
10572 }
10573
10574 sprintf(szTmp, "Sequence nbr = %d", pResponse->ASYNCPORT.seqnbr);
10575 WriteMessage(szTmp);
10576
10577 WriteMessage("Command = ", false);
10578 switch (pResponse->ASYNCPORT.cmnd)
10579 {
10580 case asyncdisable:
10581 WriteMessage("Disable");
10582 break;
10583 case asyncreceiveP1:
10584 WriteMessage("Enable P1 Receive");
10585 break;
10586 case asyncreceiveTeleinfo:
10587 WriteMessage("Enable Teleinfo Recieve");
10588 break;
10589 case asyncreceiveRAW:
10590 WriteMessage("Enable Raw Receive");
10591 break;
10592 default:
10593 sprintf(szTmp, "ERROR: Unknown command type for Packet type= %02X:%02X", pResponse->ASYNCPORT.packettype, pResponse->ASYNCPORT.subtype);
10594 WriteMessage(szTmp);
10595 break;
10596 }
10597
10598 if (pResponse->ASYNCPORT.cmnd != asyncdisable)
10599 {
10600 WriteMessage("Baudrate = ", false);
10601 switch (pResponse->ASYNCPORT.baudrate)
10602 {
10603 case asyncbaud110:
10604 WriteMessage("110");
10605 break;
10606 case asyncbaud300:
10607 WriteMessage("300");
10608 break;
10609 case asyncbaud600:
10610 WriteMessage("600");
10611 break;
10612 case asyncbaud1200:
10613 WriteMessage("1200");
10614 break;
10615 case asyncbaud2400:
10616 WriteMessage("2400");
10617 break;
10618 case asyncbaud4800:
10619 WriteMessage("4800");
10620 break;
10621 case asyncbaud9600:
10622 WriteMessage("9600");
10623 break;
10624 case asyncbaud14400:
10625 WriteMessage("14400");
10626 break;
10627 case asyncbaud19200:
10628 WriteMessage("19200");
10629 break;
10630 case asyncbaud38400:
10631 WriteMessage("38400");
10632 break;
10633 case asyncbaud57600:
10634 WriteMessage("57600");
10635 break;
10636 case asyncbaud115200:
10637 WriteMessage("115200");
10638 break;
10639 default:
10640 sprintf(szTmp, "ERROR: Unknown baudrate type for Packet type= %02X:%02X", pResponse->ASYNCPORT.packettype, pResponse->ASYNCPORT.subtype);
10641 WriteMessage(szTmp);
10642 break;
10643 }
10644 WriteMessage("Parity = ", false);
10645 switch (pResponse->ASYNCPORT.parity)
10646 {
10647 case asyncParityNo:
10648 WriteMessage("None");
10649 break;
10650 case asyncParityOdd:
10651 WriteMessage("Odd");
10652 break;
10653 case asyncParityEven:
10654 WriteMessage("Even");
10655 break;
10656 default:
10657 sprintf(szTmp, "ERROR: Unknown partity type for Packet type= %02X:%02X", pResponse->ASYNCPORT.packettype, pResponse->ASYNCPORT.subtype);
10658 WriteMessage(szTmp);
10659 break;
10660 }
10661 WriteMessage("Databits = ", false);
10662 switch (pResponse->ASYNCPORT.databits)
10663 {
10664 case asyncDatabits7:
10665 WriteMessage("7");
10666 break;
10667 case asyncDatabits8:
10668 WriteMessage("8");
10669 break;
10670 default:
10671 sprintf(szTmp, "ERROR: Unknown databits type for Packet type= %02X:%02X", pResponse->ASYNCPORT.packettype, pResponse->ASYNCPORT.subtype);
10672 WriteMessage(szTmp);
10673 break;
10674 }
10675 WriteMessage("Stopbits = ", false);
10676 switch (pResponse->ASYNCPORT.stopbits)
10677 {
10678 case asyncStopbits1:
10679 WriteMessage("1");
10680 break;
10681 case asyncStopbits2:
10682 WriteMessage("2");
10683 break;
10684 default:
10685 sprintf(szTmp, "ERROR: Unknown stopbits type for Packet type= %02X:%02X", pResponse->ASYNCPORT.packettype, pResponse->ASYNCPORT.subtype);
10686 WriteMessage(szTmp);
10687 break;
10688 }
10689 WriteMessage("Polarity = ", false);
10690 switch (pResponse->ASYNCPORT.polarity)
10691 {
10692 case asyncPolarityNormal:
10693 WriteMessage("Normal");
10694 break;
10695 case asyncPolarityInvers:
10696 WriteMessage("Inverted");
10697 break;
10698 default:
10699 sprintf(szTmp, "ERROR: Unknown stopbits type for Packet type= %02X:%02X", pResponse->ASYNCPORT.packettype, pResponse->ASYNCPORT.subtype);
10700 WriteMessage(szTmp);
10701 break;
10702 }
10703 }
10704 WriteMessageEnd();
10705 }
10706 }
10707
decode_ASyncData(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)10708 void MainWorker::decode_ASyncData(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
10709 {
10710 if (
10711 (pHardware->m_HwdID == 999) ||
10712 (pHardware->HwdType == HTYPE_RFXtrx315) ||
10713 (pHardware->HwdType == HTYPE_RFXtrx433) ||
10714 (pHardware->HwdType == HTYPE_RFXtrx868) ||
10715 (pHardware->HwdType == HTYPE_RFXLAN)
10716 )
10717 {
10718 CRFXBase* pRFXBase = (CRFXBase*)pHardware;
10719 const uint8_t* pData = reinterpret_cast<const uint8_t*>(&pResponse->ASYNCDATA.datachar[0]);
10720 int Len = pResponse->ASYNCDATA.packetlength - 3;
10721 pRFXBase->Parse_Async_Data(pData, Len);
10722 }
10723 }
10724
decode_CartelectronicTIC(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)10725 void MainWorker::decode_CartelectronicTIC(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
10726 {
10727 //Contract Options
10728 typedef enum {
10729 OP_NOT_DEFINED,
10730 OP_BASE,
10731 OP_CREUSE,
10732 OP_EJP,
10733 OP_TEMPO
10734 } Contract;
10735
10736 //Running time
10737 typedef enum {
10738 PER_NOT_DEFINED,
10739 PER_ALL_HOURS, //TH..
10740 PER_LOWCOST_HOURS, //HC..
10741 PER_HIGHCOST_HOURS, //HP..
10742 PER_NORMAL_HOURS, //HN..
10743 PER_MOBILE_PEAK_HOURS, //PM..
10744 PER_BLUE_LOWCOST_HOURS, //HCJB
10745 PER_WHITE_LOWCOST_HOURS, //HCJW
10746 PER_RED_LOWCOST_HOURS, //HCJR
10747 PER_BLUE_HIGHCOST_HOURS, //HPJB
10748 PER_WHITE_HIGHCOST_HOURS, //HPJW
10749 PER_RED_HIGHCOST_HOURS //HPJR
10750 } PeriodTime;
10751
10752 char szTmp[100];
10753 uint32_t counter1 = 0;
10754 uint32_t counter2 = 0;
10755 unsigned int apparentPower = 0;
10756 unsigned int counter1ApparentPower = 0;
10757 unsigned int counter2ApparentPower = 0;
10758 uint8_t unitCounter1 = 0;
10759 uint8_t unitCounter2 = 1;
10760 uint8_t cmnd = 0;
10761 std::string ID;
10762
10763 uint8_t devType = pTypeGeneral;
10764 uint8_t subType = sTypeKwh;
10765 uint8_t SignalLevel = pResponse->TIC.rssi;
10766
10767 uint8_t BatteryLevel = (pResponse->TIC.battery_level + 1) * 10;
10768
10769 // If no error
10770 if ((pResponse->TIC.state & 0x04) == 0)
10771 {
10772 // Id of the counter
10773 uint64_t uint64ID = ((uint64_t)pResponse->TIC.id1 << 32) +
10774 ((uint64_t)pResponse->TIC.id2 << 24) +
10775 ((uint64_t)pResponse->TIC.id3 << 16) +
10776 ((uint64_t)pResponse->TIC.id4 << 8) +
10777 (uint64_t)(pResponse->TIC.id5);
10778
10779 sprintf(szTmp, "%.12" PRIu64, uint64ID);
10780 ID = szTmp;
10781
10782 // Contract Type
10783 Contract contractType = (Contract)(pResponse->TIC.contract_type >> 4);
10784
10785 // Period
10786 PeriodTime period = (PeriodTime)(pResponse->TIC.contract_type & 0x0f);
10787
10788 // Apparent Power
10789 if ((pResponse->TIC.state & 0x02) != 0) // Only if this one is present
10790 {
10791 apparentPower = (pResponse->TIC.power_H << 8) + pResponse->TIC.power_L;
10792
10793 sprintf(szTmp, "%u", apparentPower);
10794 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), 1, pTypeUsage, sTypeElectric, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10795
10796 if (DevRowIdx == (uint64_t)-1)
10797 return;
10798
10799 m_notifications.CheckAndHandleNotification(DevRowIdx, procResult.DeviceName, pTypeUsage, sTypeElectric, NTYPE_ENERGYINSTANT, (const float)apparentPower);
10800 }
10801
10802 switch (contractType)
10803 {
10804 // BASE CONTRACT
10805 case OP_BASE:
10806 {
10807 unitCounter1 = 0;
10808 counter1ApparentPower = apparentPower;
10809 }
10810 break;
10811
10812 // LOW/HIGH PERIOD
10813 case OP_CREUSE:
10814 {
10815 unitCounter1 = 0;
10816
10817 if (period == PER_LOWCOST_HOURS)
10818 {
10819 counter1ApparentPower = apparentPower;
10820 counter2ApparentPower = 0;
10821 }
10822 if (period == PER_HIGHCOST_HOURS)
10823 {
10824 counter1ApparentPower = 0;
10825 counter2ApparentPower = apparentPower;
10826 }
10827
10828 // Counter 2
10829 counter2 = (pResponse->TIC.counter2_0 << 24) + (pResponse->TIC.counter2_1 << 16) + (pResponse->TIC.counter2_2 << 8) + (pResponse->TIC.counter2_3);
10830 sprintf(szTmp, "%u;%d", counter2ApparentPower, counter2);
10831
10832 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), 1, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10833
10834 if (DevRowIdx == (uint64_t)-1)
10835 return;
10836
10837 m_notifications.CheckAndHandleNotification(DevRowIdx, procResult.DeviceName, devType, subType, NTYPE_TODAYENERGY, (float)counter2);
10838 //----------------------------
10839 }
10840 break;
10841
10842 // EJP
10843 case OP_EJP:
10844 {
10845 unitCounter1 = 0;
10846 // Counter 2
10847 counter2 = (pResponse->TIC.counter2_0 << 24) + (pResponse->TIC.counter2_1 << 16) + (pResponse->TIC.counter2_2 << 8) + (pResponse->TIC.counter2_3);
10848
10849 sprintf(szTmp, "%u;%d", counter2ApparentPower, counter2);
10850 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), 1, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10851
10852 if (DevRowIdx == (uint64_t)-1)
10853 return;
10854
10855 m_notifications.CheckAndHandleNotification(DevRowIdx, procResult.DeviceName, devType, subType, NTYPE_TODAYENERGY, (float)counter2);
10856 //----------------------------
10857 }
10858 break;
10859
10860 // TEMPO Contracts
10861 // Total of 6 counters. Theses counters depends of the time period received. For each period time, only 2 counters are sended.
10862 case OP_TEMPO:
10863 {
10864 switch (period)
10865 {
10866 case PER_BLUE_LOWCOST_HOURS:
10867 counter1ApparentPower = apparentPower;
10868 counter2ApparentPower = 0;
10869 unitCounter1 = 0;
10870 unitCounter2 = 1;
10871 break;
10872 case PER_BLUE_HIGHCOST_HOURS:
10873 counter1ApparentPower = 0;
10874 counter2ApparentPower = apparentPower;
10875 unitCounter1 = 0;
10876 unitCounter2 = 1;
10877 break;
10878 case PER_WHITE_LOWCOST_HOURS:
10879 counter1ApparentPower = apparentPower;
10880 counter2ApparentPower = 0;
10881 unitCounter1 = 2;
10882 unitCounter2 = 3;
10883 break;
10884 case PER_WHITE_HIGHCOST_HOURS:
10885 counter1ApparentPower = 0;
10886 counter2ApparentPower = apparentPower;
10887 unitCounter1 = 2;
10888 unitCounter2 = 3;
10889 break;
10890 case PER_RED_LOWCOST_HOURS:
10891 counter1ApparentPower = apparentPower;
10892 counter2ApparentPower = 0;
10893 unitCounter1 = 4;
10894 unitCounter2 = 5;
10895 break;
10896 case PER_RED_HIGHCOST_HOURS:
10897 counter1ApparentPower = 0;
10898 counter2ApparentPower = apparentPower;
10899 unitCounter1 = 4;
10900 unitCounter2 = 5;
10901 break;
10902 default:
10903 break;
10904 }
10905
10906 // Counter 2
10907 counter2 = (pResponse->TIC.counter2_0 << 24) + (pResponse->TIC.counter2_1 << 16) + (pResponse->TIC.counter2_2 << 8) + (pResponse->TIC.counter2_3);
10908
10909 sprintf(szTmp, "%u;%d", counter2ApparentPower, counter2);
10910 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), unitCounter2, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10911
10912 if (DevRowIdx == (uint64_t)-1)
10913 return;
10914
10915 m_notifications.CheckAndHandleNotification(DevRowIdx, procResult.DeviceName, devType, subType, NTYPE_TODAYENERGY, (float)counter2);
10916 //----------------------------
10917 }
10918 break;
10919 default:
10920 break;
10921 }
10922
10923 // Counter 1
10924 counter1 = (pResponse->TIC.counter1_0 << 24) + (pResponse->TIC.counter1_1 << 16) + (pResponse->TIC.counter1_2 << 8) + (pResponse->TIC.counter1_3);
10925
10926 sprintf(szTmp, "%u;%d", counter1ApparentPower, counter1);
10927 uint64_t DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), unitCounter1, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10928
10929 if (DevRowIdx == (uint64_t)-1)
10930 return;
10931
10932 m_notifications.CheckAndHandleNotification(DevRowIdx, procResult.DeviceName, devType, subType, NTYPE_TODAYENERGY, (float)counter1);
10933 //----------------------------
10934 }
10935 else
10936 {
10937 WriteMessage("TeleInfo not connected");
10938 }
10939 }
10940
decode_CartelectronicEncoder(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)10941 void MainWorker::decode_CartelectronicEncoder(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
10942 {
10943 char szTmp[100];
10944 uint32_t counter1 = 0;
10945 uint32_t counter2 = 0;
10946 //int apparentPower = 0;
10947 uint8_t Unit = 0;
10948 uint8_t cmnd = 0;
10949 uint64_t DevRowIdx = 0;
10950 std::string ID;
10951
10952 uint8_t devType = pTypeRFXMeter;
10953 uint8_t subType = sTypeRFXMeterCount;
10954 uint8_t SignalLevel = pResponse->CEENCODER.rssi;
10955
10956 uint8_t BatteryLevel = (pResponse->CEENCODER.battery_level + 1) * 10;
10957
10958 // Id of the module
10959 sprintf(szTmp, "%d", ((uint32_t)(pResponse->CEENCODER.id1 << 24) + (pResponse->CEENCODER.id2 << 16) + (pResponse->CEENCODER.id3 << 8) + pResponse->CEENCODER.id4));
10960 ID = szTmp;
10961
10962 // Counter 1
10963 counter1 = (pResponse->CEENCODER.counter1_0 << 24) + (pResponse->CEENCODER.counter1_1 << 16) + (pResponse->CEENCODER.counter1_2 << 8) + (pResponse->CEENCODER.counter1_3);
10964
10965 sprintf(szTmp, "%d", counter1);
10966 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10967 if (DevRowIdx == (uint64_t)-1)
10968 return;
10969 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, Unit, devType, subType, (float)counter1);
10970
10971 // Counter 2
10972 counter2 = (pResponse->CEENCODER.counter2_0 << 24) + (pResponse->CEENCODER.counter2_1 << 16) + (pResponse->CEENCODER.counter2_2 << 8) + (pResponse->CEENCODER.counter2_3);
10973
10974 sprintf(szTmp, "%d", counter2);
10975 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), 1, devType, subType, SignalLevel, BatteryLevel, cmnd, szTmp, procResult.DeviceName);
10976 if (DevRowIdx == (uint64_t)-1)
10977 return;
10978 m_notifications.CheckAndHandleNotification(DevRowIdx, pHardware->m_HwdID, ID, procResult.DeviceName, 1, devType, subType, (float)counter2);
10979 }
10980
decode_Weather(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)10981 void MainWorker::decode_Weather(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
10982 {
10983 uint16_t windID = (pResponse->WEATHER.id1 * 256) + pResponse->WEATHER.id2;
10984 char szTmp[100];
10985 sprintf(szTmp, "%d", windID);
10986 std::string ID = szTmp;
10987
10988 //uint8_t devType = pTypeWEATHER;
10989 uint8_t subType = pResponse->WEATHER.subtype;
10990 //uint8_t Unit = 0;
10991 //uint8_t cmnd = 0;
10992 uint8_t SignalLevel = pResponse->WEATHER.rssi;
10993 uint8_t BatteryLevel = get_BateryLevel(pHardware->HwdType, false, pResponse->WEATHER.battery_level & 0x0F);
10994
10995 procResult.DeviceRowIdx = -1;
10996
10997 CRFXBase* pRFXDevice = (CRFXBase*)pHardware;
10998
10999 //Wind
11000 int intDirection = (pResponse->WEATHER.directionhigh * 256) + pResponse->WEATHER.directionlow;
11001 float intSpeed = float((pResponse->WEATHER.av_speedhigh * 256) + pResponse->WEATHER.av_speedlow) / 10.0f;
11002 float intGust = float((pResponse->WEATHER.gusthigh * 256) + pResponse->WEATHER.gustlow) / 10.0f;
11003
11004 float temp = 0, chill = 0;
11005 if (!pResponse->WEATHER.temperaturesign)
11006 {
11007 temp = float((pResponse->WEATHER.temperaturehigh * 256) + pResponse->WEATHER.temperaturelow) / 10.0f;
11008 }
11009 else
11010 {
11011 temp = -(float(((pResponse->WEATHER.temperaturehigh & 0x7F) * 256) + pResponse->WEATHER.temperaturelow) / 10.0f);
11012 }
11013 if ((temp < -200) || (temp > 380))
11014 {
11015 WriteMessage(" Invalid Temperature");
11016 return;
11017 }
11018
11019 bool bHaveChill = false;
11020 if (1 == 0)// subType == sTypeWEATHERx)
11021 {
11022 if (!pResponse->WEATHER.chillsign)
11023 {
11024 chill = float((pResponse->WEATHER.chillhigh * 256) + pResponse->WEATHER.chilllow) / 10.0f;
11025 }
11026 else
11027 {
11028 chill = -(float(((pResponse->WEATHER.chillhigh) & 0x7F) * 256 + pResponse->WEATHER.chilllow) / 10.0f);
11029 }
11030 bHaveChill = true;
11031 }
11032 pRFXDevice->SendWind(windID, BatteryLevel, intDirection, intSpeed, intGust, temp, chill, true, bHaveChill, procResult.DeviceName, SignalLevel);
11033
11034 if (subType == sTypeWEATHER2)
11035 {
11036 int Humidity = (int)pResponse->WEATHER.humidity;
11037 //uint8_t HumidityStatus = pResponse->WEATHER.humidity_status;
11038
11039 //MySensorsBase *pMySensorDevice = reinterpret_cast<MySensorsBase*>(pHardware);
11040
11041 pRFXDevice->SendTempHumSensor(windID, BatteryLevel, temp, Humidity, procResult.DeviceName, SignalLevel);
11042 }
11043
11044 //Rain
11045 if ((subType == sTypeWEATHER1) || (subType == sTypeWEATHER2))
11046 {
11047 float TotalRain = 0;
11048
11049 if (subType == sTypeWEATHER1)
11050 {
11051 TotalRain = float((pResponse->WEATHER.raintotal2 * 256) + (pResponse->WEATHER.raintotal3)) * 0.3f;
11052 }
11053 else if (subType == sTypeWEATHER2)
11054 {
11055 TotalRain = float((pResponse->WEATHER.raintotal2 * 256) + (pResponse->WEATHER.raintotal3)) * 0.254f;
11056 }
11057 pRFXDevice->SendRainSensor(windID, BatteryLevel, TotalRain, procResult.DeviceName, SignalLevel);
11058 }
11059
11060 //UV
11061 if (subType == sTypeWEATHER2)
11062 {
11063 float UV = (float)pResponse->WEATHER.uv;
11064 pRFXDevice->SendUVSensor(windID, 1, BatteryLevel, UV, procResult.DeviceName, SignalLevel);
11065 }
11066
11067 //Solar
11068 if (subType == sTypeWEATHER2)
11069 {
11070 float radiation = (float)((pResponse->WEATHER.solarhigh * 256) + pResponse->WEATHER.solarlow);
11071 pRFXDevice->SendSolarRadiationSensor((const uint8_t)windID, BatteryLevel, radiation, procResult.DeviceName);
11072 }
11073 }
11074
decode_Solar(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)11075 void MainWorker::decode_Solar(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
11076 {
11077 uint8_t SignalLevel = pResponse->SOLAR.rssi;
11078 uint8_t BatteryLevel = get_BateryLevel(pHardware->HwdType, false, pResponse->SOLAR.battery_level & 0x0F);
11079
11080 _tGeneralDevice gdevice;
11081 gdevice.subtype = sTypeSolarRadiation;
11082 gdevice.intval1 = (pResponse->SOLAR.id1 * 256) + pResponse->SOLAR.id2;
11083 gdevice.id = (uint8_t)gdevice.intval1;
11084 gdevice.floatval1 = float((pResponse->SOLAR.solarhigh * 256) + float(pResponse->SOLAR.solarlow)) / 100.f;
11085 decode_General(pHardware, pResponse, procResult, SignalLevel, BatteryLevel);
11086 procResult.bProcessBatteryValue = false;
11087 }
11088
decode_Hunter(const CDomoticzHardwareBase * pHardware,const tRBUF * pResponse,_tRxMessageProcessingResult & procResult)11089 void MainWorker::decode_Hunter(const CDomoticzHardwareBase* pHardware, const tRBUF* pResponse, _tRxMessageProcessingResult& procResult)
11090 {
11091 uint8_t devType = pResponse->HUNTER.packettype;
11092 uint8_t subType = pResponse->HUNTER.subtype;
11093 uint8_t SignalLevel = pResponse->HUNTER.rssi;
11094 uint8_t BatteryLevel = 255;
11095
11096 uint8_t Unit = 0;
11097 uint8_t cmnd = pResponse->HUNTER.cmnd;
11098 uint64_t DevRowIdx = 0;
11099 std::string ID;
11100
11101 char szTmp[50];
11102 sprintf(szTmp, "%02X%02X%02X%02X%02X%02X", pResponse->HUNTER.id1, pResponse->HUNTER.id2, pResponse->HUNTER.id3, pResponse->HUNTER.id4, pResponse->HUNTER.id5, pResponse->HUNTER.id6);
11103 ID = szTmp;
11104
11105 DevRowIdx = m_sql.UpdateValue(pHardware->m_HwdID, ID.c_str(), Unit, devType, subType, SignalLevel, BatteryLevel, cmnd, procResult.DeviceName);
11106 if (DevRowIdx == (uint64_t)-1)
11107 return;
11108
11109 CheckSceneCode(DevRowIdx, devType, subType, cmnd, szTmp, procResult.DeviceName);
11110
11111 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
11112 {
11113 WriteMessageStart();
11114 switch (pResponse->HUNTER.subtype)
11115 {
11116 case sTypeHunterfan:
11117 WriteMessage("subtype = Hunter Fan");
11118 sprintf(szTmp, "Sequence nbr = %d", pResponse->HUNTER.seqnbr);
11119 WriteMessage(szTmp);
11120 sprintf(szTmp, "ID = %s", ID.c_str());
11121 WriteMessage(szTmp);
11122 WriteMessage("Command = ", false);
11123 switch (pResponse->HUNTER.cmnd)
11124 {
11125 case HunterOff:
11126 WriteMessage("Off");
11127 break;
11128 case HunterLight:
11129 WriteMessage("Light");
11130 break;
11131 case HunterSpeed1:
11132 WriteMessage("Low");
11133 break;
11134 case HunterSpeed2:
11135 WriteMessage("Medium");
11136 break;
11137 case HunterSpeed3:
11138 WriteMessage("High");
11139 break;
11140 case HunterProgram:
11141 WriteMessage("Learn");
11142 break;
11143 default:
11144 WriteMessage("UNKNOWN");
11145 break;
11146 }
11147 break;
11148 default:
11149 sprintf(szTmp, "ERROR: Unknown Sub type for Packet type= %02X:%02X", pResponse->LIGHTING6.packettype, pResponse->LIGHTING6.subtype);
11150 WriteMessage(szTmp);
11151 break;
11152 }
11153 sprintf(szTmp, "Signal level = %d", pResponse->LIGHTING6.rssi);
11154 WriteMessage(szTmp);
11155 WriteMessageEnd();
11156 }
11157 procResult.DeviceRowIdx = DevRowIdx;
11158 }
11159
GetSensorData(const uint64_t idx,int & nValue,std::string & sValue)11160 bool MainWorker::GetSensorData(const uint64_t idx, int& nValue, std::string& sValue)
11161 {
11162 std::vector<std::vector<std::string> > result;
11163 char szTmp[100];
11164 result = m_sql.safe_query("SELECT [Type],[SubType],[nValue],[sValue],[SwitchType] FROM DeviceStatus WHERE (ID==%" PRIu64 ")", idx);
11165 if (result.empty())
11166 return false;
11167 std::vector<std::string> sd = result[0];
11168 int devType = atoi(sd[0].c_str());
11169 int subType = atoi(sd[1].c_str());
11170 nValue = atoi(sd[2].c_str());
11171 sValue = sd[3];
11172 _eMeterType metertype = (_eMeterType)atoi(sd[4].c_str());
11173
11174 //Special cases
11175 if ((devType == pTypeP1Power) && (subType == sTypeP1Power))
11176 {
11177 std::vector<std::string> results;
11178 StringSplit(sValue, ";", results);
11179 if (results.size() < 6)
11180 return false; //invalid data
11181 //Return usage or delivery
11182 long usagecurrent = atol(results[4].c_str());
11183 long delivcurrent = atol(results[5].c_str());
11184 std::stringstream ssvalue;
11185 if (delivcurrent > 0)
11186 {
11187 ssvalue << "-" << delivcurrent;
11188 }
11189 else
11190 {
11191 ssvalue << usagecurrent;
11192 }
11193 nValue = 0;
11194 sValue = ssvalue.str();
11195 }
11196 else if ((devType == pTypeP1Gas) && (subType == sTypeP1Gas))
11197 {
11198 float GasDivider = 1000.0f;
11199 //get lowest value of today
11200 time_t now = mytime(NULL);
11201 struct tm tm1;
11202 localtime_r(&now, &tm1);
11203
11204 struct tm ltime;
11205 ltime.tm_isdst = tm1.tm_isdst;
11206 ltime.tm_hour = 0;
11207 ltime.tm_min = 0;
11208 ltime.tm_sec = 0;
11209 ltime.tm_year = tm1.tm_year;
11210 ltime.tm_mon = tm1.tm_mon;
11211 ltime.tm_mday = tm1.tm_mday;
11212
11213 char szDate[40];
11214 sprintf(szDate, "%04d-%02d-%02d", ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday);
11215
11216 std::vector<std::vector<std::string> > result2;
11217 strcpy(szTmp, "0");
11218 result2 = m_sql.safe_query("SELECT MIN(Value) FROM Meter WHERE (DeviceRowID='%" PRIu64 "' AND Date>='%q')", idx, szDate);
11219 if (!result2.empty())
11220 {
11221 std::vector<std::string> sd2 = result2[0];
11222 unsigned long long total_min_gas = std::strtoull(sd2[0].c_str(), nullptr, 10);
11223 unsigned long long gasactual = std::strtoull(sValue.c_str(), nullptr, 10);
11224 unsigned long long total_real_gas = gasactual - total_min_gas;
11225 float musage = float(total_real_gas) / GasDivider;
11226 sprintf(szTmp, "%.03f", musage);
11227 }
11228 else
11229 {
11230 sprintf(szTmp, "%.03f", 0.0f);
11231 }
11232 nValue = 0;
11233 sValue = szTmp;
11234 }
11235 else if (devType == pTypeRFXMeter)
11236 {
11237 float EnergyDivider = 1000.0f;
11238 float GasDivider = 100.0f;
11239 //float WaterDivider = 100.0f;
11240 int tValue;
11241 if (m_sql.GetPreferencesVar("MeterDividerEnergy", tValue))
11242 {
11243 EnergyDivider = float(tValue);
11244 }
11245 if (m_sql.GetPreferencesVar("MeterDividerGas", tValue))
11246 {
11247 GasDivider = float(tValue);
11248 }
11249 //if (m_sql.GetPreferencesVar("MeterDividerWater", tValue))
11250 //{
11251 //WaterDivider = float(tValue);
11252 //}
11253
11254 //get value of today
11255 time_t now = mytime(NULL);
11256 struct tm tm1;
11257 localtime_r(&now, &tm1);
11258
11259 struct tm ltime;
11260 ltime.tm_isdst = tm1.tm_isdst;
11261 ltime.tm_hour = 0;
11262 ltime.tm_min = 0;
11263 ltime.tm_sec = 0;
11264 ltime.tm_year = tm1.tm_year;
11265 ltime.tm_mon = tm1.tm_mon;
11266 ltime.tm_mday = tm1.tm_mday;
11267
11268 char szDate[40];
11269 sprintf(szDate, "%04d-%02d-%02d", ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday);
11270
11271 std::vector<std::vector<std::string> > result2;
11272 strcpy(szTmp, "0");
11273 result2 = m_sql.safe_query("SELECT MIN(Value), MAX(Value) FROM Meter WHERE (DeviceRowID='%" PRIu64 "' AND Date>='%q')", idx, szDate);
11274 if (!result2.empty())
11275 {
11276 std::vector<std::string> sd2 = result2[0];
11277
11278 unsigned long long total_min = std::strtoull(sd2[0].c_str(), nullptr, 10);
11279 unsigned long long total_max = std::strtoull(sd2[1].c_str(), nullptr, 10);
11280 unsigned long long total_real = total_max - total_min;
11281 sprintf(szTmp, "%llu", total_real);
11282
11283 float musage = 0;
11284 switch (metertype)
11285 {
11286 case MTYPE_ENERGY:
11287 case MTYPE_ENERGY_GENERATED:
11288 musage = float(total_real) / EnergyDivider;
11289 sprintf(szTmp, "%.03f", musage);
11290 break;
11291 case MTYPE_GAS:
11292 musage = float(total_real) / GasDivider;
11293 sprintf(szTmp, "%.03f", musage);
11294 break;
11295 case MTYPE_WATER:
11296 sprintf(szTmp, "%llu", total_real);
11297 break;
11298 case MTYPE_COUNTER:
11299 sprintf(szTmp, "%llu", total_real);
11300 break;
11301 /*
11302 default:
11303 strcpy(szTmp, "?");
11304 break;
11305 */
11306 }
11307 }
11308 nValue = 0;
11309 sValue = szTmp;
11310 }
11311 return true;
11312 }
11313
SwitchLightInt(const std::vector<std::string> & sd,std::string switchcmd,int level,const _tColor color,const bool IsTesting,const std::string & User)11314 bool MainWorker::SwitchLightInt(const std::vector<std::string>& sd, std::string switchcmd, int level, const _tColor color, const bool IsTesting, const std::string& User)
11315 {
11316 unsigned long ID;
11317 std::stringstream s_strid;
11318 s_strid << std::hex << sd[1];
11319 s_strid >> ID;
11320 uint8_t ID1 = (uint8_t)((ID & 0xFF000000) >> 24);
11321 uint8_t ID2 = (uint8_t)((ID & 0x00FF0000) >> 16);
11322 uint8_t ID3 = (uint8_t)((ID & 0x0000FF00) >> 8);
11323 uint8_t ID4 = (uint8_t)((ID & 0x000000FF));
11324
11325 int HardwareID = atoi(sd[0].c_str());
11326
11327 _log.Debug(DEBUG_NORM, "MAIN SwitchLightInt : switchcmd:%s level:%d HWid:%d sd:%s %s %s %s %s %s", switchcmd.c_str(), level, HardwareID,
11328 sd[0].c_str(), sd[1].c_str(), sd[2].c_str(), sd[3].c_str(), sd[4].c_str(), sd[5].c_str());
11329
11330 int hindex = FindDomoticzHardware(HardwareID);
11331 if (hindex == -1)
11332 {
11333 _log.Log(LOG_ERROR, "Switch command not send!, Hardware device disabled or not found!");
11334 return false;
11335 }
11336 CDomoticzHardwareBase* pHardware = GetHardware(HardwareID);
11337 if (pHardware == NULL)
11338 return false;
11339
11340 m_szLastSwitchUser = User;
11341
11342 if (pHardware->HwdType == HTYPE_DomoticzInternal)
11343 {
11344 //Special cases
11345 if (ID == 0x00148702)
11346 {
11347 int iSecStatus = 2;
11348 if (switchcmd == "Disarm")
11349 iSecStatus = 0;
11350 else if (switchcmd == "Arm Home")
11351 iSecStatus = 1;
11352 else if (switchcmd == "Arm Away")
11353 iSecStatus = 2;
11354 else
11355 return false;
11356 UpdateDomoticzSecurityStatus(iSecStatus);
11357 return true;
11358 }
11359 }
11360
11361 uint8_t Unit = atoi(sd[2].c_str());
11362 uint8_t dType = atoi(sd[3].c_str());
11363 uint8_t dSubType = atoi(sd[4].c_str());
11364 _eSwitchType switchtype = (_eSwitchType)atoi(sd[5].c_str());
11365 std::map<std::string, std::string> options = m_sql.BuildDeviceOptions(sd[10].c_str());
11366
11367 //when asking for Toggle, just switch to the opposite value
11368 if (switchcmd == "Toggle") {
11369 //Request current state of switch
11370 std::string lstatus = "";
11371 int llevel = 0;
11372 bool bHaveDimmer = false;
11373 bool bHaveGroupCmd = false;
11374 int maxDimLevel = 0;
11375
11376 int nValue = atoi(sd[7].c_str());
11377 std::string sValue = sd[8];
11378
11379 GetLightStatus(dType, dSubType, switchtype, nValue, sValue, lstatus, llevel, bHaveDimmer, maxDimLevel, bHaveGroupCmd);
11380 //Flip the status
11381 switchcmd = (IsLightSwitchOn(lstatus) == true) ? "Off" : "On";
11382 }
11383
11384 // If dimlevel is 0 or no dimlevel, turn switch off
11385 if (level <= 0 && switchcmd == "Set Level")
11386 switchcmd = "Off";
11387
11388 //when level is invalid or command is "On", replace level with "LastLevel"
11389 if (switchcmd == "On" || level < 0)
11390 {
11391 //Get LastLevel
11392 std::vector<std::vector<std::string> > result;
11393 result = m_sql.safe_query(
11394 "SELECT LastLevel FROM DeviceStatus WHERE (HardwareID=%d AND DeviceID='%q' AND Unit=%d AND Type=%d AND SubType=%d)", HardwareID, sd[1].c_str(), Unit, int(dType), int(dSubType));
11395 if (result.size() == 1)
11396 {
11397 level = atoi(result[0][0].c_str());
11398 }
11399 _log.Debug(DEBUG_NORM, "MAIN SwitchLightInt : switchcmd==\"On\" || level < 0, new level:%d", level);
11400 }
11401 // TODO: Something smarter if level is not valid?
11402 level = std::max(level, 0);
11403
11404 //
11405 // For plugins all the specific logic below is irrelevent
11406 // so just send the full details to the plugin so that it can take appropriate action
11407 //
11408 if (pHardware->HwdType == HTYPE_PythonPlugin)
11409 {
11410 #ifdef ENABLE_PYTHON
11411 // Special case when color is passed from timer or scene
11412 if ((switchcmd == "On") || (switchcmd == "Set Level"))
11413 {
11414 if (color.mode != ColorModeNone)
11415 {
11416 switchcmd = "Set Color";
11417 }
11418 }
11419 ((Plugins::CPlugin*)m_hardwaredevices[hindex])->SendCommand(Unit, switchcmd, level, color);
11420 #endif
11421 return true;
11422 }
11423
11424 switch (dType)
11425 {
11426 case pTypeLighting1:
11427 {
11428 tRBUF lcmd;
11429 lcmd.LIGHTING1.packetlength = sizeof(lcmd.LIGHTING1) - 1;
11430 lcmd.LIGHTING1.packettype = dType;
11431 lcmd.LIGHTING1.subtype = dSubType;
11432 lcmd.LIGHTING1.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
11433 lcmd.LIGHTING1.housecode = atoi(sd[1].c_str());
11434 lcmd.LIGHTING1.unitcode = Unit;
11435 lcmd.LIGHTING1.filler = 0;
11436 lcmd.LIGHTING1.rssi = 12;
11437
11438 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.LIGHTING1.cmnd, options))
11439 return false;
11440 if (switchtype == STYPE_Doorbell)
11441 {
11442 int rnvalue = 0;
11443 m_sql.GetPreferencesVar("DoorbellCommand", rnvalue);
11444 if (rnvalue == 0)
11445 lcmd.LIGHTING1.cmnd = light1_sChime;
11446 else
11447 lcmd.LIGHTING1.cmnd = light1_sOn;
11448 }
11449
11450 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.LIGHTING1)))
11451 return false;
11452 if (!IsTesting) {
11453 //send to internal for now (later we use the ACK)
11454 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11455 }
11456 return true;
11457 }
11458 break;
11459 case pTypeLighting2:
11460 {
11461 tRBUF lcmd;
11462 lcmd.LIGHTING2.packetlength = sizeof(lcmd.LIGHTING2) - 1;
11463 lcmd.LIGHTING2.packettype = dType;
11464 lcmd.LIGHTING2.subtype = dSubType;
11465 lcmd.LIGHTING2.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
11466 lcmd.LIGHTING2.id1 = ID1;
11467 lcmd.LIGHTING2.id2 = ID2;
11468 lcmd.LIGHTING2.id3 = ID3;
11469 lcmd.LIGHTING2.id4 = ID4;
11470 lcmd.LIGHTING2.unitcode = Unit;
11471 lcmd.LIGHTING2.filler = 0;
11472 lcmd.LIGHTING2.rssi = 12;
11473
11474 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.LIGHTING2.cmnd, options))
11475 return false;
11476 if (switchtype == STYPE_Doorbell) {
11477 int rnvalue = 0;
11478 m_sql.GetPreferencesVar("DoorbellCommand", rnvalue);
11479 if (rnvalue == 0)
11480 lcmd.LIGHTING2.cmnd = light2_sGroupOn;
11481 else
11482 lcmd.LIGHTING2.cmnd = light2_sOn;
11483 level = 15;
11484 }
11485 else if (switchtype == STYPE_X10Siren) {
11486 level = 15;
11487 }
11488 else if ((switchtype == STYPE_BlindsPercentage) || (switchtype == STYPE_BlindsPercentageInverted)) {
11489 if (lcmd.LIGHTING2.cmnd == light2_sSetLevel)
11490 {
11491 if (level == 15)
11492 {
11493 lcmd.LIGHTING2.cmnd = light2_sOn;
11494 }
11495 else if (level == 0)
11496 {
11497 lcmd.LIGHTING2.cmnd = light2_sOff;
11498 }
11499 }
11500 }
11501 else if (switchtype == STYPE_Media)
11502 {
11503 if (switchcmd == "Set Volume") {
11504 level = (level < 0) ? 0 : level;
11505 level = (level > 100) ? 100 : level;
11506 }
11507 }
11508 else
11509 level = (level > 15) ? 15 : level;
11510
11511 lcmd.LIGHTING2.level = (uint8_t)level;
11512 //Special Teach-In for EnOcean Dimmers
11513 if ((pHardware->HwdType == HTYPE_EnOceanESP2) && (IsTesting) && (switchtype == STYPE_Dimmer))
11514 {
11515 CEnOceanESP2* pEnocean = reinterpret_cast<CEnOceanESP2*>(pHardware);
11516 pEnocean->SendDimmerTeachIn((const char*)&lcmd, sizeof(lcmd.LIGHTING1));
11517 }
11518 else if ((pHardware->HwdType == HTYPE_EnOceanESP3) && (IsTesting) && (switchtype == STYPE_Dimmer))
11519 {
11520 CEnOceanESP3* pEnocean = reinterpret_cast<CEnOceanESP3*>(pHardware);
11521 pEnocean->SendDimmerTeachIn((const char*)&lcmd, sizeof(lcmd.LIGHTING1));
11522 }
11523 else
11524 {
11525 if (switchtype != STYPE_Motion) //dont send actual motion off command
11526 {
11527 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.LIGHTING2)))
11528 return false;
11529 }
11530 }
11531
11532 if (!IsTesting) {
11533 //send to internal for now (later we use the ACK)
11534 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11535 }
11536 return true;
11537 }
11538 break;
11539 case pTypeLighting3:
11540 if (level > 9)
11541 level = 9;
11542 break;
11543 case pTypeLighting4:
11544 {
11545 tRBUF lcmd;
11546 lcmd.LIGHTING4.packetlength = sizeof(lcmd.LIGHTING4) - 1;
11547 lcmd.LIGHTING4.packettype = dType;
11548 lcmd.LIGHTING4.subtype = dSubType;
11549 lcmd.LIGHTING4.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
11550 lcmd.LIGHTING4.cmd1 = ID2;
11551 lcmd.LIGHTING4.cmd2 = ID3;
11552 lcmd.LIGHTING4.cmd3 = ID4;
11553 lcmd.LIGHTING4.filler = 0;
11554 lcmd.LIGHTING4.rssi = 12;
11555
11556 //Get Pulse timing
11557 std::vector<std::vector<std::string> > result;
11558 result = m_sql.safe_query(
11559 "SELECT sValue FROM DeviceStatus WHERE (HardwareID=%d AND DeviceID='%q' AND Unit=%d AND Type=%d AND SubType=%d)", HardwareID, sd[1].c_str(), Unit, int(dType), int(dSubType));
11560 if (result.size() == 1)
11561 {
11562 int pulsetimeing = atoi(result[0][0].c_str());
11563 lcmd.LIGHTING4.pulseHigh = pulsetimeing / 256;
11564 lcmd.LIGHTING4.pulseLow = pulsetimeing & 0xFF;
11565 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.LIGHTING4)))
11566 return false;
11567 if (!IsTesting) {
11568 //send to internal for now (later we use the ACK)
11569 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11570 }
11571 return true;
11572 }
11573 return false;
11574 }
11575 break;
11576 case pTypeLighting5:
11577 {
11578 tRBUF lcmd;
11579 lcmd.LIGHTING5.packetlength = sizeof(lcmd.LIGHTING5) - 1;
11580 lcmd.LIGHTING5.packettype = dType;
11581 lcmd.LIGHTING5.subtype = dSubType;
11582 lcmd.LIGHTING5.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
11583 lcmd.LIGHTING5.id1 = ID2;
11584 lcmd.LIGHTING5.id2 = ID3;
11585 lcmd.LIGHTING5.id3 = ID4;
11586 lcmd.LIGHTING5.unitcode = Unit;
11587 lcmd.LIGHTING5.filler = 0;
11588 lcmd.LIGHTING5.rssi = 12;
11589
11590 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.LIGHTING5.cmnd, options))
11591 return false;
11592 if (switchtype == STYPE_Doorbell)
11593 {
11594 int rnvalue = 0;
11595 m_sql.GetPreferencesVar("DoorbellCommand", rnvalue);
11596 if (rnvalue == 0)
11597 lcmd.LIGHTING5.cmnd = light5_sGroupOn;
11598 else
11599 lcmd.LIGHTING5.cmnd = light5_sOn;
11600 level = 31;
11601 }
11602 else if (switchtype == STYPE_X10Siren)
11603 {
11604 level = 31;
11605 }
11606 if (level > 31)
11607 level = 31;
11608 lcmd.LIGHTING5.level = (uint8_t)level;
11609 if (dSubType == sTypeLivolo)
11610 {
11611 if ((switchcmd == "Set Level") && (level == 0))
11612 {
11613 switchcmd = "Off";
11614 GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.LIGHTING5.cmnd, options);
11615 }
11616 if (switchcmd != "Off")
11617 {
11618 //Special Case, turn off first
11619 uint8_t oldCmd = lcmd.LIGHTING5.cmnd;
11620 lcmd.LIGHTING5.cmnd = light5_sLivoloAllOff;
11621 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.LIGHTING5)))
11622 return false;
11623 lcmd.LIGHTING5.cmnd = oldCmd;
11624 }
11625 if (switchcmd == "Set Level")
11626 {
11627 //dim value we have to send multiple times
11628 for (int iDim = 0; iDim < level; iDim++)
11629 {
11630 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.LIGHTING5)))
11631 return false;
11632 }
11633 }
11634 else
11635 {
11636 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.LIGHTING5)))
11637 return false;
11638 }
11639 }
11640 else if ((dSubType == sTypeTRC02) || (dSubType == sTypeTRC02_2))
11641 {
11642 //int oldlevel = level;
11643 if (switchcmd != "Off")
11644 {
11645 if (color.mode == ColorModeRGB)
11646 {
11647 switchcmd = "Set Color";
11648 }
11649 }
11650 if ((switchcmd == "Off") ||
11651 (switchcmd == "On") || //Special Case, turn off first to ensure light is in normal mode
11652 (switchcmd == "Set Color"))
11653 {
11654 uint8_t oldCmd = lcmd.LIGHTING5.cmnd;
11655 lcmd.LIGHTING5.cmnd = light5_sRGBoff;
11656 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.LIGHTING5)))
11657 return false;
11658 lcmd.LIGHTING5.cmnd = oldCmd;
11659 sleep_milliseconds(100);
11660 }
11661 if ((switchcmd == "On") || (switchcmd == "Set Color"))
11662 {
11663 //turn on
11664 lcmd.LIGHTING5.cmnd = light5_sRGBon;
11665 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.LIGHTING5)))
11666 return false;
11667 sleep_milliseconds(100);
11668
11669 if (switchcmd == "Set Color")
11670 {
11671 if (color.mode == ColorModeRGB)
11672 {
11673 float hsb[3];
11674 rgb2hsb(color.r, color.g, color.b, hsb);
11675 switchcmd = "Set Color";
11676
11677 float dval = 126.0f * hsb[0]; // Color Range is 0x06..0x84
11678 lcmd.LIGHTING5.cmnd = light5_sRGBcolormin + 1 + round(dval);
11679 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.LIGHTING5)))
11680 return false;
11681 }
11682 }
11683 }
11684 }
11685 else
11686 {
11687 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.LIGHTING5)))
11688 return false;
11689 }
11690 if (!IsTesting) {
11691 //send to internal for now (later we use the ACK)
11692 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11693 }
11694 return true;
11695 }
11696 break;
11697 case pTypeLighting6:
11698 {
11699 tRBUF lcmd;
11700 lcmd.LIGHTING6.packetlength = sizeof(lcmd.LIGHTING6) - 1;
11701 lcmd.LIGHTING6.packettype = dType;
11702 lcmd.LIGHTING6.subtype = dSubType;
11703 lcmd.LIGHTING6.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
11704 lcmd.LIGHTING6.seqnbr2 = 0;
11705 lcmd.LIGHTING6.id1 = ID2;
11706 lcmd.LIGHTING6.id2 = ID3;
11707 lcmd.LIGHTING6.groupcode = ID4;
11708 lcmd.LIGHTING6.unitcode = Unit;
11709 lcmd.LIGHTING6.cmndseqnbr = m_hardwaredevices[hindex]->m_SeqNr % 4;
11710 lcmd.LIGHTING6.filler = 0;
11711 lcmd.LIGHTING6.rssi = 12;
11712
11713 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.LIGHTING6.cmnd, options))
11714 return false;
11715 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.LIGHTING6)))
11716 return false;
11717 if (!IsTesting) {
11718 //send to internal for now (later we use the ACK)
11719 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11720 }
11721 return true;
11722 }
11723 break;
11724 case pTypeFS20:
11725 {
11726 tRBUF lcmd;
11727 lcmd.FS20.packetlength = sizeof(lcmd.FS20) - 1;
11728 lcmd.FS20.packettype = dType;
11729 lcmd.FS20.subtype = dSubType;
11730 lcmd.FS20.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
11731 lcmd.FS20.hc1 = ID3;
11732 lcmd.FS20.hc2 = ID4;
11733 lcmd.FS20.addr = Unit;
11734 lcmd.FS20.filler = 0;
11735 lcmd.FS20.rssi = 12;
11736 lcmd.FS20.cmd2 = 0;
11737 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.FS20.cmd1, options))
11738 return false;
11739 level = (level > 15) ? 15 : level;
11740
11741 if (level > 0)
11742 {
11743 lcmd.FS20.cmd1 = fs20_sDimlevel_1 + level;
11744 }
11745
11746 if (switchtype != STYPE_Motion) //dont send actual motion off command
11747 {
11748 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.FS20)))
11749 return false;
11750 }
11751
11752 if (!IsTesting) {
11753 //send to internal for now (later we use the ACK)
11754 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11755 }
11756 return true;
11757 }
11758 break;
11759 case pTypeHomeConfort:
11760 {
11761 tRBUF lcmd;
11762 lcmd.HOMECONFORT.packetlength = sizeof(lcmd.HOMECONFORT) - 1;
11763 lcmd.HOMECONFORT.packettype = dType;
11764 lcmd.HOMECONFORT.subtype = dSubType;
11765 lcmd.HOMECONFORT.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
11766 lcmd.HOMECONFORT.id1 = ID1;
11767 lcmd.HOMECONFORT.id2 = ID2;
11768 lcmd.HOMECONFORT.id3 = ID3;
11769 lcmd.HOMECONFORT.housecode = ID4;
11770 lcmd.HOMECONFORT.unitcode = Unit;
11771 lcmd.HOMECONFORT.filler = 0;
11772 lcmd.HOMECONFORT.rssi = 12;
11773
11774 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.HOMECONFORT.cmnd, options))
11775 return false;
11776 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.HOMECONFORT)))
11777 return false;
11778 if (!IsTesting) {
11779 //send to internal for now (later we use the ACK)
11780 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11781 }
11782 return true;
11783 }
11784 break;
11785 case pTypeFan:
11786 {
11787 tRBUF lcmd;
11788 lcmd.FAN.packetlength = sizeof(lcmd.FAN) - 1;
11789 lcmd.FAN.packettype = dType;
11790 lcmd.FAN.subtype = dSubType;
11791 lcmd.FAN.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
11792 lcmd.FAN.id1 = ID2;
11793 lcmd.FAN.id2 = ID3;
11794 lcmd.FAN.id3 = ID4;
11795 lcmd.FAN.filler = 0;
11796 lcmd.FAN.rssi = 12;
11797
11798 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.FAN.cmnd, options))
11799 return false;
11800 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.FAN)))
11801 return false;
11802 if (!IsTesting) {
11803 //send to internal for now (later we use the ACK)
11804 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11805 }
11806 return true;
11807 }
11808 break;
11809 case pTypeColorSwitch:
11810 {
11811 _tColorSwitch lcmd;
11812 lcmd.subtype = dSubType;
11813 lcmd.id = ID;
11814 lcmd.dunit = Unit;
11815 lcmd.color = color;
11816 level = std::min(100, level);
11817 level = std::max(0, level);
11818 lcmd.value = level;
11819
11820 //Special case when color is passed from timer or scene
11821 if ((switchcmd == "On") || (switchcmd == "Set Level"))
11822 {
11823 if (color.mode != ColorModeNone)
11824 {
11825 switchcmd = "Set Color";
11826 }
11827 }
11828 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.command, options))
11829 return false;
11830 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(_tColorSwitch)))
11831 return false;
11832 if (!IsTesting) {
11833 //send to internal for now (later we use the ACK)
11834 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11835 }
11836 return true;
11837 }
11838 break;
11839 case pTypeSecurity1:
11840 {
11841 tRBUF lcmd;
11842 lcmd.SECURITY1.packetlength = sizeof(lcmd.SECURITY1) - 1;
11843 lcmd.SECURITY1.packettype = dType;
11844 lcmd.SECURITY1.subtype = dSubType;
11845 lcmd.SECURITY1.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
11846 lcmd.SECURITY1.battery_level = 9;
11847 lcmd.SECURITY1.id1 = ID2;
11848 lcmd.SECURITY1.id2 = ID3;
11849 lcmd.SECURITY1.id3 = ID4;
11850 lcmd.SECURITY1.rssi = 12;
11851 switch (dSubType)
11852 {
11853 case sTypeKD101:
11854 case sTypeSA30:
11855 {
11856 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.SECURITY1.status, options))
11857 return false;
11858 //send it twice
11859 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.SECURITY1)))
11860 return false;
11861 sleep_milliseconds(500);
11862 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.SECURITY1)))
11863 return false;
11864 if (!IsTesting) {
11865 //send to internal for now (later we use the ACK)
11866 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11867 }
11868 }
11869 break;
11870 case sTypeSecX10M:
11871 case sTypeSecX10R:
11872 case sTypeSecX10:
11873 case sTypeMeiantech:
11874 {
11875 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.SECURITY1.status, options))
11876 return false;
11877 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.SECURITY1)))
11878 return false;
11879 if (!IsTesting) {
11880 //send to internal for now (later we use the ACK)
11881 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11882 }
11883 }
11884 break;
11885 }
11886 return true;
11887 }
11888 break;
11889 case pTypeSecurity2:
11890 {
11891 BYTE kCodes[9];
11892 if (sd[1].size() < 8 * 2)
11893 {
11894 return false;
11895 }
11896 for (int ii = 0; ii < 8; ii++)
11897 {
11898 std::string sHex = sd[1].substr(ii * 2, 2);
11899 std::stringstream s_strid;
11900 int iHex = 0;
11901 s_strid << std::hex << sHex;
11902 s_strid >> iHex;
11903 kCodes[ii] = (BYTE)iHex;
11904
11905 }
11906 tRBUF lcmd;
11907 lcmd.SECURITY2.packetlength = sizeof(lcmd.SECURITY2) - 1;
11908 lcmd.SECURITY2.packettype = dType;
11909 lcmd.SECURITY2.subtype = dSubType;
11910 lcmd.SECURITY2.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
11911 lcmd.SECURITY2.id1 = kCodes[0];
11912 lcmd.SECURITY2.id2 = kCodes[1];
11913 lcmd.SECURITY2.id3 = kCodes[2];
11914 lcmd.SECURITY2.id4 = kCodes[3];
11915 lcmd.SECURITY2.id5 = kCodes[4];
11916 lcmd.SECURITY2.id6 = kCodes[5];
11917 lcmd.SECURITY2.id7 = kCodes[6];
11918 lcmd.SECURITY2.id8 = kCodes[7];
11919
11920 lcmd.SECURITY2.id9 = 0;//bat full
11921 lcmd.SECURITY2.battery_level = 9;
11922 lcmd.SECURITY2.rssi = 12;
11923
11924 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.SECURITY2)))
11925 return false;
11926 if (!IsTesting) {
11927 //send to internal for now (later we use the ACK)
11928 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11929 }
11930 return true;
11931 }
11932 break;
11933 case pTypeHunter:
11934 {
11935 BYTE kCodes[6];
11936 if (sd[1].size() < 6 * 2)
11937 {
11938 return false;
11939 }
11940 for (int ii = 0; ii < 6; ii++)
11941 {
11942 std::string sHex = sd[1].substr(ii * 2, 2);
11943 std::stringstream s_strid;
11944 int iHex = 0;
11945 s_strid << std::hex << sHex;
11946 s_strid >> iHex;
11947 kCodes[ii] = (BYTE)iHex;
11948 }
11949 tRBUF lcmd;
11950 lcmd.HUNTER.packetlength = sizeof(lcmd.HUNTER) - 1;
11951 lcmd.HUNTER.packettype = dType;
11952 lcmd.HUNTER.subtype = dSubType;
11953 lcmd.HUNTER.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
11954 lcmd.HUNTER.id1 = kCodes[0];
11955 lcmd.HUNTER.id2 = kCodes[1];
11956 lcmd.HUNTER.id3 = kCodes[2];
11957 lcmd.HUNTER.id4 = kCodes[3];
11958 lcmd.HUNTER.id5 = kCodes[4];
11959 lcmd.HUNTER.id6 = kCodes[5];
11960 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.HUNTER.cmnd, options))
11961 return false;
11962 lcmd.HUNTER.rssi = 12;
11963
11964 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.SECURITY2)))
11965 return false;
11966 if (!IsTesting) {
11967 //send to internal for now (later we use the ACK)
11968 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11969 }
11970 return true;
11971 }
11972 break;
11973 case pTypeCurtain:
11974 {
11975 tRBUF lcmd;
11976 lcmd.CURTAIN1.packetlength = sizeof(lcmd.CURTAIN1) - 1;
11977 lcmd.CURTAIN1.packettype = dType;
11978 lcmd.CURTAIN1.subtype = dSubType;
11979 lcmd.CURTAIN1.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
11980 lcmd.CURTAIN1.housecode = atoi(sd[1].c_str());
11981 lcmd.CURTAIN1.unitcode = Unit;
11982 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.CURTAIN1.cmnd, options))
11983 return false;
11984 lcmd.CURTAIN1.filler = 0;
11985
11986 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.CURTAIN1)))
11987 return false;
11988 if (!IsTesting) {
11989 //send to internal for now (later we use the ACK)
11990 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
11991 }
11992 return true;
11993 }
11994 break;
11995 case pTypeBlinds:
11996 {
11997 tRBUF lcmd;
11998 lcmd.BLINDS1.packetlength = sizeof(lcmd.BLINDS1) - 1;
11999 lcmd.BLINDS1.packettype = dType;
12000 lcmd.BLINDS1.subtype = dSubType;
12001 lcmd.BLINDS1.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
12002 lcmd.BLINDS1.id1 = ID1;
12003 lcmd.BLINDS1.id2 = ID2;
12004 lcmd.BLINDS1.id3 = ID3;
12005 lcmd.BLINDS1.id4 = 0;
12006 if (
12007 (dSubType == sTypeBlindsT0)
12008 || (dSubType == sTypeBlindsT1)
12009 || (dSubType == sTypeBlindsT3)
12010 || (dSubType == sTypeBlindsT8)
12011 || (dSubType == sTypeBlindsT12)
12012 || (dSubType == sTypeBlindsT13)
12013 || (dSubType == sTypeBlindsT14)
12014 || (dSubType == sTypeBlindsT15)
12015 || (dSubType == sTypeBlindsT16)
12016 || (dSubType == sTypeBlindsT17)
12017 || (dSubType == sTypeBlindsT18)
12018 )
12019 {
12020 lcmd.BLINDS1.unitcode = Unit;
12021 }
12022 else if ((dSubType == sTypeBlindsT6) || (dSubType == sTypeBlindsT7) || (dSubType == sTypeBlindsT9))
12023 {
12024 lcmd.BLINDS1.unitcode = Unit;
12025 lcmd.BLINDS1.id4 = ID4;
12026 }
12027 else
12028 {
12029 lcmd.BLINDS1.unitcode = 0;
12030 }
12031 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.BLINDS1.cmnd, options))
12032 return false;
12033 level = 15;
12034 lcmd.BLINDS1.filler = 0;
12035 lcmd.BLINDS1.rssi = 12;
12036 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.BLINDS1)))
12037 return false;
12038 if (!IsTesting) {
12039 //send to internal for now (later we use the ACK)
12040 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
12041 }
12042 return true;
12043 }
12044 break;
12045 case pTypeRFY:
12046 {
12047 tRBUF lcmd;
12048 lcmd.BLINDS1.packetlength = sizeof(lcmd.RFY) - 1;
12049 lcmd.BLINDS1.packettype = dType;
12050 lcmd.BLINDS1.subtype = dSubType;
12051 lcmd.RFY.id1 = ID2;
12052 lcmd.RFY.id2 = ID3;
12053 lcmd.RFY.id3 = ID4;
12054 lcmd.RFY.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
12055 lcmd.RFY.unitcode = Unit;
12056
12057 if (IsTesting)
12058 {
12059 lcmd.RFY.cmnd = rfy_sProgram;
12060 }
12061 else
12062 {
12063 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.RFY.cmnd, options))
12064 return false;
12065 }
12066
12067 if (lcmd.BLINDS1.subtype == sTypeRFY2)
12068 {
12069 //Special case for protocol version 2
12070 lcmd.BLINDS1.subtype = sTypeRFY;
12071 if (lcmd.RFY.cmnd == rfy_sUp)
12072 lcmd.RFY.cmnd = rfy_s2SecUp;
12073 else if (lcmd.RFY.cmnd == rfy_sDown)
12074 lcmd.RFY.cmnd = rfy_s2SecDown;
12075 }
12076
12077 level = 15;
12078 lcmd.RFY.filler = 0;
12079 lcmd.RFY.rssi = 12;
12080 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.RFY)))
12081 return false;
12082 if (!IsTesting) {
12083 //send to internal for now (later we use the ACK)
12084 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
12085 }
12086 return true;
12087 }
12088 break;
12089 case pTypeChime:
12090 {
12091 tRBUF lcmd;
12092 lcmd.CHIME.packetlength = sizeof(lcmd.CHIME) - 1;
12093 lcmd.CHIME.packettype = dType;
12094 lcmd.CHIME.subtype = dSubType;
12095 lcmd.CHIME.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
12096 lcmd.CHIME.id1 = ID3;
12097 lcmd.CHIME.id2 = ID4;
12098 level = 15;
12099 lcmd.CHIME.sound = Unit;
12100 lcmd.CHIME.filler = 0;
12101 lcmd.CHIME.rssi = 12;
12102 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.CHIME)))
12103 return false;
12104 if (!IsTesting) {
12105 //send to internal for now (later we use the ACK)
12106 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
12107 }
12108 return true;
12109 }
12110 break;
12111 case pTypeThermostat2:
12112 {
12113 tRBUF lcmd;
12114 lcmd.THERMOSTAT2.packetlength = sizeof(lcmd.REMOTE) - 1;
12115 lcmd.THERMOSTAT2.packettype = dType;
12116 lcmd.THERMOSTAT2.subtype = dSubType;
12117 lcmd.THERMOSTAT2.unitcode = Unit;
12118 lcmd.THERMOSTAT2.cmnd = Unit;
12119 lcmd.THERMOSTAT2.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
12120
12121 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.THERMOSTAT2.cmnd, options))
12122 return false;
12123
12124 lcmd.THERMOSTAT2.filler = 0;
12125 lcmd.THERMOSTAT2.rssi = 12;
12126 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.THERMOSTAT2)))
12127 return false;
12128 if (!IsTesting) {
12129 //send to internal for now (later we use the ACK)
12130 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
12131 }
12132 return true;
12133 }
12134 break;
12135 case pTypeThermostat3:
12136 {
12137 tRBUF lcmd;
12138 lcmd.THERMOSTAT3.packetlength = sizeof(lcmd.THERMOSTAT3) - 1;
12139 lcmd.THERMOSTAT3.packettype = dType;
12140 lcmd.THERMOSTAT3.subtype = dSubType;
12141 lcmd.THERMOSTAT3.unitcode1 = ID2;
12142 lcmd.THERMOSTAT3.unitcode2 = ID3;
12143 lcmd.THERMOSTAT3.unitcode3 = ID4;
12144 lcmd.THERMOSTAT3.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
12145 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.THERMOSTAT3.cmnd, options))
12146 return false;
12147 level = 15;
12148 lcmd.THERMOSTAT3.filler = 0;
12149 lcmd.THERMOSTAT3.rssi = 12;
12150 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.THERMOSTAT3)))
12151 return false;
12152 if (!IsTesting) {
12153 //send to internal for now (later we use the ACK)
12154 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
12155 }
12156 return true;
12157 }
12158 break;
12159 case pTypeThermostat4:
12160 {
12161 _log.Log(LOG_ERROR, "Thermostat 4 not implemented yet!");
12162 /*
12163 tRBUF lcmd;
12164 lcmd.THERMOSTAT4.packetlength = sizeof(lcmd.THERMOSTAT3) - 1;
12165 lcmd.THERMOSTAT4.packettype = dType;
12166 lcmd.THERMOSTAT4.subtype = dSubType;
12167 lcmd.THERMOSTAT4.unitcode1 = ID2;
12168 lcmd.THERMOSTAT4.unitcode2 = ID3;
12169 lcmd.THERMOSTAT4.unitcode3 = ID4;
12170 lcmd.THERMOSTAT4.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
12171 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.THERMOSTAT4.mode, options))
12172 return false;
12173 level = 15;
12174 lcmd.THERMOSTAT4.filler = 0;
12175 lcmd.THERMOSTAT4.rssi = 12;
12176 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.THERMOSTAT4)))
12177 return false;
12178 if (!IsTesting) {
12179 //send to internal for now (later we use the ACK)
12180 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t *)&lcmd, NULL, -1);
12181 }
12182 */
12183 return true;
12184 }
12185 break;
12186 case pTypeRemote:
12187 {
12188 tRBUF lcmd;
12189 lcmd.REMOTE.packetlength = sizeof(lcmd.REMOTE) - 1;
12190 lcmd.REMOTE.packettype = dType;
12191 lcmd.REMOTE.subtype = dSubType;
12192 lcmd.REMOTE.id = ID4;
12193 lcmd.REMOTE.cmnd = Unit;
12194 lcmd.REMOTE.cmndtype = 0;
12195 lcmd.REMOTE.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
12196 lcmd.REMOTE.toggle = 0;
12197 lcmd.REMOTE.rssi = 12;
12198 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.REMOTE)))
12199 return false;
12200 if (!IsTesting) {
12201 //send to internal for now (later we use the ACK)
12202 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
12203 }
12204 return true;
12205 }
12206 break;
12207 case pTypeEvohomeRelay:
12208 {
12209 _tEVOHOME3 lcmd;
12210 memset(&lcmd, 0, sizeof(_tEVOHOME3));
12211 lcmd.len = sizeof(_tEVOHOME3) - 1;
12212 lcmd.type = pTypeEvohomeRelay;
12213 lcmd.subtype = sTypeEvohomeRelay;
12214 RFX_SETID3(ID, lcmd.id1, lcmd.id2, lcmd.id3)
12215 lcmd.devno = Unit;
12216 if (switchcmd == "On")
12217 lcmd.demand = 200;
12218 else
12219 lcmd.demand = level;
12220
12221 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(_tEVOHOME3)))
12222 return false;
12223 if (!IsTesting) {
12224 //send to internal for now (later we use the ACK)
12225 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
12226 }
12227 return true;
12228 }
12229 break;
12230 case pTypeRadiator1:
12231 tRBUF lcmd;
12232 lcmd.RADIATOR1.packetlength = sizeof(lcmd.RADIATOR1) - 1;
12233 lcmd.RADIATOR1.packettype = pTypeRadiator1;
12234 lcmd.RADIATOR1.subtype = sTypeSmartwares;
12235 lcmd.RADIATOR1.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
12236 lcmd.RADIATOR1.id1 = ID1;
12237 lcmd.RADIATOR1.id2 = ID2;
12238 lcmd.RADIATOR1.id3 = ID3;
12239 lcmd.RADIATOR1.id4 = ID4;
12240 lcmd.RADIATOR1.unitcode = Unit;
12241 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, lcmd.RADIATOR1.cmnd, options))
12242 return false;
12243 if (level > 15)
12244 level = 15;
12245 lcmd.RADIATOR1.temperature = 0;
12246 lcmd.RADIATOR1.tempPoint5 = 0;
12247 lcmd.RADIATOR1.filler = 0;
12248 lcmd.RADIATOR1.rssi = 12;
12249 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.RADIATOR1)))
12250 return false;
12251
12252 if (!IsTesting) {
12253 //send to internal for now (later we use the ACK)
12254 lcmd.RADIATOR1.subtype = sTypeSmartwaresSwitchRadiator;
12255 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&lcmd, NULL, -1);
12256 }
12257 return true;
12258 case pTypeGeneralSwitch:
12259 {
12260
12261 _tGeneralSwitch gswitch;
12262 gswitch.type = dType;
12263 gswitch.subtype = dSubType;
12264 gswitch.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
12265 gswitch.id = ID;
12266 gswitch.unitcode = Unit;
12267
12268 if (!GetLightCommand(dType, dSubType, switchtype, switchcmd, gswitch.cmnd, options))
12269 return false;
12270
12271 if ((switchtype != STYPE_Selector) && (dSubType != sSwitchGeneralSwitch))
12272 {
12273 level = (level > 99) ? 99 : level;
12274 }
12275
12276 if (switchtype == STYPE_Doorbell) {
12277 int rnvalue = 0;
12278 m_sql.GetPreferencesVar("DoorbellCommand", rnvalue);
12279 if (rnvalue == 0)
12280 lcmd.LIGHTING2.cmnd = gswitch_sGroupOn;
12281 else
12282 lcmd.LIGHTING2.cmnd = gswitch_sOn;
12283 level = 15;
12284 }
12285 else if (switchtype == STYPE_Selector)
12286 {
12287 if ((switchcmd == "Set Level") || (switchcmd == "Set Group Level")) {
12288 std::map<std::string, std::string> statuses;
12289 GetSelectorSwitchStatuses(options, statuses);
12290 int maxLevel = statuses.size() * 10;
12291
12292 level = (level < 0) ? 0 : level;
12293 level = (level > maxLevel) ? maxLevel : level;
12294
12295 std::stringstream sslevel;
12296 sslevel << level;
12297 if (statuses[sslevel.str()].empty()) {
12298 _log.Log(LOG_ERROR, "Setting a wrong level value %d to Selector device %lu", level, ID);
12299 }
12300 }
12301 }
12302 else if (((switchtype == STYPE_BlindsPercentage) ||
12303 (switchtype == STYPE_BlindsPercentageInverted)) &&
12304 (gswitch.cmnd == gswitch_sSetLevel) && (level == 100))
12305 gswitch.cmnd = gswitch_sOn;
12306
12307 gswitch.level = (uint8_t)level;
12308 gswitch.rssi = 12;
12309 if (switchtype != STYPE_Motion) //dont send actual motion off command
12310 {
12311 if (!WriteToHardware(HardwareID, (const char*)&gswitch, sizeof(_tGeneralSwitch)))
12312 return false;
12313 }
12314 if (!IsTesting) {
12315 //send to internal for now (later we use the ACK)
12316 PushAndWaitRxMessage(m_hardwaredevices[hindex], (const uint8_t*)&gswitch, NULL, -1);
12317 }
12318 }
12319 return true;
12320 }
12321 return false;
12322 }
12323
SwitchModal(const std::string & idx,const std::string & status,const std::string & action,const std::string & ooc,const std::string & until)12324 bool MainWorker::SwitchModal(const std::string& idx, const std::string& status, const std::string& action, const std::string& ooc, const std::string& until)
12325 {
12326 //Get Device details
12327 std::vector<std::vector<std::string> > result;
12328 result = m_sql.safe_query(
12329 "SELECT HardwareID, DeviceID,Unit,Type,SubType,SwitchType,StrParam1,nValue FROM DeviceStatus WHERE (ID == '%q')",
12330 idx.c_str());
12331 if (result.empty())
12332 return false;
12333 std::vector<std::string> sd = result[0];
12334
12335 int nStatus = 0;
12336 if (status == "Away")
12337 nStatus = CEvohomeBase::cmEvoAway;
12338 else if (status == "AutoWithEco")
12339 nStatus = CEvohomeBase::cmEvoAutoWithEco;
12340 else if (status == "DayOff")
12341 nStatus = CEvohomeBase::cmEvoDayOff;
12342 else if (status == "Custom")
12343 nStatus = CEvohomeBase::cmEvoCustom;
12344 else if (status == "Auto")
12345 nStatus = CEvohomeBase::cmEvoAuto;
12346 else if (status == "HeatingOff")
12347 nStatus = CEvohomeBase::cmEvoHeatingOff;
12348
12349 int nValue = atoi(sd[7].c_str());
12350 if (ooc == "1" && nValue == nStatus)
12351 return false;//FIXME not an error ... status = (already set)
12352
12353 int HardwareID = atoi(sd[0].c_str());
12354 int hindex = FindDomoticzHardware(HardwareID);
12355 if (hindex == -1)
12356 return false;
12357
12358 //uint8_t Unit = atoi(sd[2].c_str());
12359 //uint8_t dType = atoi(sd[3].c_str());
12360 //uint8_t dSubType = atoi(sd[4].c_str());
12361 //_eSwitchType switchtype = (_eSwitchType)atoi(sd[5].c_str());
12362
12363 CDomoticzHardwareBase* pHardware = GetHardware(HardwareID);
12364 if (pHardware == NULL)
12365 return false;
12366
12367
12368 unsigned long ID;
12369 std::stringstream s_strid;
12370 if (pHardware->HwdType == HTYPE_EVOHOME_SERIAL || pHardware->HwdType == HTYPE_EVOHOME_TCP)
12371 s_strid << std::hex << sd[1];
12372 else //GB3: web based evohome uses decimal device ID's. We need to convert those to hex here to fit the 3-byte ID defined in the message struct
12373 s_strid << std::hex << std::dec << sd[1];
12374 s_strid >> ID;
12375
12376 //Update Domoticz evohome Device
12377 _tEVOHOME1 tsen;
12378 memset(&tsen, 0, sizeof(_tEVOHOME1));
12379 tsen.len = sizeof(_tEVOHOME1) - 1;
12380 tsen.type = pTypeEvohome;
12381 tsen.subtype = sTypeEvohome;
12382 RFX_SETID3(ID, tsen.id1, tsen.id2, tsen.id3)
12383 tsen.action = (action == "1") ? 1 : 0;
12384 tsen.status = nStatus;
12385
12386 tsen.mode = until.empty() ? CEvohomeBase::cmPerm : CEvohomeBase::cmTmp;
12387 if (tsen.mode == CEvohomeBase::cmTmp)
12388 CEvohomeDateTime::DecodeISODate(tsen, until.c_str());
12389 WriteToHardware(HardwareID, (const char*)&tsen, sizeof(_tEVOHOME1));
12390
12391 //the latency on the scripted solution is quite bad so it's good to see the update happening...ideally this would go to an 'updating' status (also useful to update database if we ever use this as a pure virtual device)
12392 PushRxMessage(pHardware, (const uint8_t*)&tsen, NULL, 255);
12393 return true;
12394 }
12395
SwitchLight(const std::string & idx,const std::string & switchcmd,const std::string & level,const std::string & color,const std::string & ooc,const int ExtraDelay,const std::string & User)12396 bool MainWorker::SwitchLight(const std::string& idx, const std::string& switchcmd, const std::string& level, const std::string& color, const std::string& ooc, const int ExtraDelay, const std::string& User)
12397 {
12398 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10);
12399 int ilevel = -1;
12400 if (level != "")
12401 ilevel = atoi(level.c_str());
12402
12403 return SwitchLight(ID, switchcmd, ilevel, _tColor(color), atoi(ooc.c_str()) != 0, ExtraDelay, User);
12404 }
12405
SwitchLight(const uint64_t idx,const std::string & switchcmd,const int level,_tColor color,const bool ooc,const int ExtraDelay,const std::string & User)12406 bool MainWorker::SwitchLight(const uint64_t idx, const std::string& switchcmd, const int level, _tColor color, const bool ooc, const int ExtraDelay, const std::string& User)
12407 {
12408 //Get Device details
12409 _log.Debug(DEBUG_NORM, "MAIN SwitchLight idx:%" PRId64 " cmd:%s lvl:%d ", idx, switchcmd.c_str(), level);
12410 std::vector<std::vector<std::string> > result;
12411 result = m_sql.safe_query(
12412 "SELECT HardwareID,DeviceID,Unit,Type,SubType,SwitchType,AddjValue2,nValue,sValue,Name,Options FROM DeviceStatus WHERE (ID == %" PRIu64 ")",
12413 idx);
12414 if (result.empty())
12415 return false;
12416
12417 std::vector<std::string> sd = result[0];
12418
12419 //uint8_t dType = atoi(sd[3].c_str());
12420 //uint8_t dSubType = atoi(sd[4].c_str());
12421 _eSwitchType switchtype = (_eSwitchType)atoi(sd[5].c_str());
12422 int iOnDelay = atoi(sd[6].c_str());
12423 int nValue = atoi(sd[7].c_str());
12424 std::string sValue = sd[8].c_str();
12425 std::string devName = sd[9].c_str();
12426 //std::string sOptions = sd[10].c_str();
12427
12428 bool bIsOn = IsLightSwitchOn(switchcmd);
12429 if (ooc)//Only on change
12430 {
12431 int nNewVal = bIsOn ? 1 : 0;//Is that everything we need here
12432 if ((switchtype == STYPE_Selector) && (nValue == nNewVal) && (level == atoi(sValue.c_str()))) {
12433 return true;
12434 }
12435 else if (nValue == nNewVal) {
12436 return true;//FIXME no return code for already set
12437 }
12438 }
12439 //Check if we have an On-Delay, if yes, add it to the tasker
12440 if (((bIsOn) && (iOnDelay != 0)) || ExtraDelay)
12441 {
12442 if (iOnDelay + ExtraDelay != 0)
12443 {
12444 _log.Log(LOG_NORM, "Delaying switch [%s] action (%s) for %d seconds", devName.c_str(), switchcmd.c_str(), iOnDelay + ExtraDelay);
12445 }
12446 m_sql.AddTaskItem(_tTaskItem::SwitchLightEvent(static_cast<float>(iOnDelay + ExtraDelay), idx, switchcmd, level, color, "Switch with Delay", User));
12447 return true;
12448 }
12449 else
12450 return SwitchLightInt(sd, switchcmd, level, color, false, User);
12451 }
12452
SetSetPoint(const std::string & idx,const float TempValue,const std::string & newMode,const std::string & until)12453 bool MainWorker::SetSetPoint(const std::string& idx, const float TempValue, const std::string& newMode, const std::string& until)
12454 {
12455 //Get Device details
12456 std::vector<std::vector<std::string> > result;
12457 result = m_sql.safe_query(
12458 "SELECT HardwareID, DeviceID,Unit,Type,SubType,SwitchType,StrParam1,ID FROM DeviceStatus WHERE (ID == '%q')",
12459 idx.c_str());
12460 if (result.empty())
12461 return false;
12462
12463 std::vector<std::string> sd = result[0];
12464 int HardwareID = atoi(sd[0].c_str());
12465 int hindex = FindDomoticzHardware(HardwareID);
12466 if (hindex == -1)
12467 return false;
12468
12469 CDomoticzHardwareBase* pHardware = GetHardware(HardwareID);
12470 if (pHardware == NULL)
12471 return false;
12472
12473 if (pHardware->HwdType != HTYPE_EVOHOME_SCRIPT && pHardware->HwdType != HTYPE_EVOHOME_SERIAL && pHardware->HwdType != HTYPE_EVOHOME_WEB && pHardware->HwdType != HTYPE_EVOHOME_TCP)
12474 return SetSetPointInt(sd, TempValue);
12475
12476 int nEvoMode = 0;
12477 if (newMode == "PermanentOverride" || newMode.empty())
12478 nEvoMode = CEvohomeBase::zmPerm;
12479 else if (newMode == "TemporaryOverride")
12480 nEvoMode = CEvohomeBase::zmTmp;
12481
12482 //_log.Log(LOG_DEBUG, "Set point %s %f '%s' '%s'", idx.c_str(), TempValue, newMode.c_str(), until.c_str());
12483
12484 unsigned long ID;
12485 std::stringstream s_strid;
12486 if (pHardware->HwdType == HTYPE_EVOHOME_SERIAL || pHardware->HwdType == HTYPE_EVOHOME_TCP)
12487 s_strid << std::hex << sd[1];
12488 else //GB3: web based evohome uses decimal device ID's. We need to convert those to hex here to fit the 3-byte ID defined in the message struct
12489 s_strid << std::hex << std::dec << sd[1];
12490 s_strid >> ID;
12491
12492
12493 uint8_t Unit = atoi(sd[2].c_str());
12494 uint8_t dType = atoi(sd[3].c_str());
12495 uint8_t dSubType = atoi(sd[4].c_str());
12496 //_eSwitchType switchtype=(_eSwitchType)atoi(sd[5].c_str());
12497
12498 if (pHardware->HwdType == HTYPE_EVOHOME_SCRIPT || pHardware->HwdType == HTYPE_EVOHOME_SERIAL || pHardware->HwdType == HTYPE_EVOHOME_WEB || pHardware->HwdType == HTYPE_EVOHOME_TCP)
12499 {
12500 _tEVOHOME2 tsen;
12501 memset(&tsen, 0, sizeof(_tEVOHOME2));
12502 tsen.len = sizeof(_tEVOHOME2) - 1;
12503 tsen.type = dType;
12504 tsen.subtype = dSubType;
12505 RFX_SETID3(ID, tsen.id1, tsen.id2, tsen.id3)
12506 tsen.zone = Unit;//controller is 0 so let our zones start from 1...
12507 tsen.updatetype = CEvohomeBase::updSetPoint;//setpoint
12508 tsen.temperature = static_cast<int16_t>((dType == pTypeEvohomeWater) ? TempValue : TempValue * 100.0f);
12509 tsen.mode = nEvoMode;
12510 if (nEvoMode == CEvohomeBase::zmTmp)
12511 CEvohomeDateTime::DecodeISODate(tsen, until.c_str());
12512 WriteToHardware(HardwareID, (const char*)&tsen, sizeof(_tEVOHOME2));
12513
12514 //Pass across the current controller mode if we're going to update as per the hw device
12515 result = m_sql.safe_query(
12516 "SELECT Name,DeviceID,nValue FROM DeviceStatus WHERE (HardwareID==%d) AND (Unit==0)",
12517 HardwareID);
12518 if (!result.empty())
12519 {
12520 sd = result[0];
12521 tsen.controllermode = atoi(sd[2].c_str());
12522 }
12523 //the latency on the scripted solution is quite bad so it's good to see the update happening...ideally this would go to an 'updating' status (also useful to update database if we ever use this as a pure virtual device)
12524 PushAndWaitRxMessage(pHardware, (const uint8_t*)&tsen, NULL, -1);
12525 }
12526 return true;
12527 }
12528
SetSetPointInt(const std::vector<std::string> & sd,const float TempValue)12529 bool MainWorker::SetSetPointInt(const std::vector<std::string>& sd, const float TempValue)
12530 {
12531 int HardwareID = atoi(sd[0].c_str());
12532 int hindex = FindDomoticzHardware(HardwareID);
12533 if (hindex == -1)
12534 return false;
12535
12536 unsigned long ID;
12537 std::stringstream s_strid;
12538 s_strid << std::hex << sd[1];
12539 s_strid >> ID;
12540 uint8_t ID1 = (uint8_t)((ID & 0xFF000000) >> 24);
12541 uint8_t ID2 = (uint8_t)((ID & 0x00FF0000) >> 16);
12542 uint8_t ID3 = (uint8_t)((ID & 0x0000FF00) >> 8);
12543 uint8_t ID4 = (uint8_t)((ID & 0x000000FF));
12544
12545 uint8_t Unit = atoi(sd[2].c_str());
12546 uint8_t dType = atoi(sd[3].c_str());
12547 uint8_t dSubType = atoi(sd[4].c_str());
12548 //_eSwitchType switchtype = (_eSwitchType)atoi(sd[5].c_str());
12549
12550 CDomoticzHardwareBase* pHardware = GetHardware(HardwareID);
12551 if (pHardware == NULL)
12552 return false;
12553 //
12554 // For plugins all the specific logic below is irrelevent
12555 // so just send the full details to the plugin so that it can take appropriate action
12556 //
12557 if (pHardware->HwdType == HTYPE_PythonPlugin)
12558 {
12559 #ifdef ENABLE_PYTHON
12560 ((Plugins::CPlugin*)pHardware)->SendCommand(Unit, "Set Level", TempValue);
12561 #endif
12562 }
12563 else if (
12564 (pHardware->HwdType == HTYPE_OpenThermGateway) ||
12565 (pHardware->HwdType == HTYPE_OpenThermGatewayTCP) ||
12566 (pHardware->HwdType == HTYPE_ICYTHERMOSTAT) ||
12567 (pHardware->HwdType == HTYPE_TOONTHERMOSTAT) ||
12568 (pHardware->HwdType == HTYPE_AtagOne) ||
12569 (pHardware->HwdType == HTYPE_NEST) ||
12570 (pHardware->HwdType == HTYPE_Nest_OAuthAPI) ||
12571 (pHardware->HwdType == HTYPE_ANNATHERMOSTAT) ||
12572 (pHardware->HwdType == HTYPE_THERMOSMART) ||
12573 (pHardware->HwdType == HTYPE_Tado) ||
12574 (pHardware->HwdType == HTYPE_EVOHOME_SCRIPT) ||
12575 (pHardware->HwdType == HTYPE_EVOHOME_SERIAL) ||
12576 (pHardware->HwdType == HTYPE_EVOHOME_TCP) ||
12577 (pHardware->HwdType == HTYPE_EVOHOME_WEB) ||
12578 (pHardware->HwdType == HTYPE_Netatmo) ||
12579 (pHardware->HwdType == HTYPE_NefitEastLAN) ||
12580 (pHardware->HwdType == HTYPE_IntergasInComfortLAN2RF) ||
12581 (pHardware->HwdType == HTYPE_OpenWebNetTCP)
12582 )
12583 {
12584 if (pHardware->HwdType == HTYPE_OpenThermGateway)
12585 {
12586 OTGWSerial* pGateway = reinterpret_cast<OTGWSerial*>(pHardware);
12587 pGateway->SetSetpoint(ID4, TempValue);
12588 }
12589 else if (pHardware->HwdType == HTYPE_OpenThermGatewayTCP)
12590 {
12591 OTGWTCP* pGateway = reinterpret_cast<OTGWTCP*>(pHardware);
12592 pGateway->SetSetpoint(ID4, TempValue);
12593 }
12594 else if (pHardware->HwdType == HTYPE_ICYTHERMOSTAT)
12595 {
12596 CICYThermostat* pGateway = reinterpret_cast<CICYThermostat*>(pHardware);
12597 pGateway->SetSetpoint(ID4, TempValue);
12598 }
12599 else if (pHardware->HwdType == HTYPE_TOONTHERMOSTAT)
12600 {
12601 CToonThermostat* pGateway = reinterpret_cast<CToonThermostat*>(pHardware);
12602 pGateway->SetSetpoint(ID4, TempValue);
12603 }
12604 else if (pHardware->HwdType == HTYPE_AtagOne)
12605 {
12606 CAtagOne* pGateway = reinterpret_cast<CAtagOne*>(pHardware);
12607 pGateway->SetSetpoint(ID4, TempValue);
12608 }
12609 else if (pHardware->HwdType == HTYPE_NEST)
12610 {
12611 CNest* pGateway = reinterpret_cast<CNest*>(pHardware);
12612 pGateway->SetSetpoint(ID4, TempValue);
12613 }
12614 else if (pHardware->HwdType == HTYPE_Nest_OAuthAPI)
12615 {
12616 CNestOAuthAPI* pGateway = reinterpret_cast<CNestOAuthAPI*>(pHardware);
12617 pGateway->SetSetpoint(ID4, TempValue);
12618 }
12619 else if (pHardware->HwdType == HTYPE_ANNATHERMOSTAT)
12620 {
12621 CAnnaThermostat* pGateway = reinterpret_cast<CAnnaThermostat*>(pHardware);
12622 pGateway->SetSetpoint(ID4, TempValue);
12623 }
12624 else if (pHardware->HwdType == HTYPE_THERMOSMART)
12625 {
12626 CThermosmart* pGateway = reinterpret_cast<CThermosmart*>(pHardware);
12627 pGateway->SetSetpoint(ID4, TempValue);
12628 }
12629 else if (pHardware->HwdType == HTYPE_Tado)
12630 {
12631 CTado* pGateway = reinterpret_cast<CTado*>(pHardware);
12632 pGateway->SetSetpoint(ID4, TempValue);
12633 }
12634 else if (pHardware->HwdType == HTYPE_Netatmo)
12635 {
12636 CNetatmo* pGateway = reinterpret_cast<CNetatmo*>(pHardware);
12637 pGateway->SetSetpoint(ID, TempValue);
12638 }
12639 else if (pHardware->HwdType == HTYPE_NefitEastLAN)
12640 {
12641 CNefitEasy* pGateway = reinterpret_cast<CNefitEasy*>(pHardware);
12642 pGateway->SetSetpoint(ID2, TempValue);
12643 }
12644 else if (pHardware->HwdType == HTYPE_EVOHOME_SCRIPT || pHardware->HwdType == HTYPE_EVOHOME_SERIAL || pHardware->HwdType == HTYPE_EVOHOME_WEB || pHardware->HwdType == HTYPE_EVOHOME_TCP)
12645 {
12646 SetSetPoint(sd[7], TempValue, "PermanentOverride", "");
12647 }
12648 else if (pHardware->HwdType == HTYPE_IntergasInComfortLAN2RF)
12649 {
12650 CInComfort* pGateway = reinterpret_cast<CInComfort*>(pHardware);
12651 pGateway->SetSetpoint(ID4, TempValue);
12652 }
12653 else if (pHardware->HwdType == HTYPE_OpenWebNetTCP)
12654 {
12655 COpenWebNetTCP* pGateway = reinterpret_cast<COpenWebNetTCP*>(pHardware);
12656 return pGateway->SetSetpoint(ID, TempValue);
12657 }
12658 }
12659 else
12660 {
12661 if (dType == pTypeRadiator1)
12662 {
12663 tRBUF lcmd;
12664 lcmd.RADIATOR1.packetlength = sizeof(lcmd.RADIATOR1) - 1;
12665 lcmd.RADIATOR1.packettype = dType;
12666 lcmd.RADIATOR1.subtype = dSubType;
12667 lcmd.RADIATOR1.seqnbr = m_hardwaredevices[hindex]->m_SeqNr++;
12668 lcmd.RADIATOR1.id1 = ID1;
12669 lcmd.RADIATOR1.id2 = ID2;
12670 lcmd.RADIATOR1.id3 = ID3;
12671 lcmd.RADIATOR1.id4 = ID4;
12672 lcmd.RADIATOR1.unitcode = Unit;
12673 lcmd.RADIATOR1.filler = 0;
12674 lcmd.RADIATOR1.rssi = 12;
12675 lcmd.RADIATOR1.cmnd = Radiator1_sSetTemp;
12676
12677 char szTemp[20];
12678 sprintf(szTemp, "%.1f", TempValue);
12679 std::vector<std::string> strarray;
12680 StringSplit(szTemp, ".", strarray);
12681 lcmd.RADIATOR1.temperature = (uint8_t)atoi(strarray[0].c_str());
12682 lcmd.RADIATOR1.tempPoint5 = (uint8_t)atoi(strarray[1].c_str());
12683 if (!WriteToHardware(HardwareID, (const char*)&lcmd, sizeof(lcmd.RADIATOR1)))
12684 return false;
12685 PushAndWaitRxMessage(pHardware, (const uint8_t*)&lcmd, NULL, -1);
12686 }
12687 else
12688 {
12689 float tempDest = TempValue;
12690 unsigned char tSign = m_sql.m_tempsign[0];
12691 if (tSign == 'F')
12692 {
12693 //Convert to Celsius
12694 tempDest = static_cast<float>(ConvertToCelsius(tempDest));
12695 }
12696
12697 _tThermostat tmeter;
12698 tmeter.subtype = sTypeThermSetpoint;
12699 tmeter.id1 = ID1;
12700 tmeter.id2 = ID2;
12701 tmeter.id3 = ID3;
12702 tmeter.id4 = ID4;
12703 tmeter.dunit = 1;
12704 tmeter.temp = tempDest;
12705 if (!WriteToHardware(HardwareID, (const char*)&tmeter, sizeof(_tThermostat)))
12706 return false;
12707 if (pHardware->HwdType == HTYPE_Dummy)
12708 {
12709 //Also put it in the database, as this devices does not send updates
12710 PushAndWaitRxMessage(pHardware, (const uint8_t*)&tmeter, NULL, -1);
12711 }
12712 }
12713 }
12714 return true;
12715 }
12716
SetSetPoint(const std::string & idx,const float TempValue)12717 bool MainWorker::SetSetPoint(const std::string& idx, const float TempValue)
12718 {
12719 //Get Device details
12720 std::vector<std::vector<std::string> > result;
12721 result = m_sql.safe_query(
12722 "SELECT HardwareID, DeviceID,Unit,Type,SubType,SwitchType,StrParam1,ID FROM DeviceStatus WHERE (ID == '%q')",
12723 idx.c_str());
12724 if (result.empty())
12725 return false;
12726
12727 std::vector<std::string> sd = result[0];
12728 return SetSetPointInt(sd, TempValue);
12729 }
12730
SetClockInt(const std::vector<std::string> & sd,const std::string & clockstr)12731 bool MainWorker::SetClockInt(const std::vector<std::string>& sd, const std::string& clockstr)
12732 {
12733 #ifdef WITH_OPENZWAVE
12734 int HardwareID = atoi(sd[0].c_str());
12735 int hindex = FindDomoticzHardware(HardwareID);
12736 if (hindex == -1)
12737 return false;
12738
12739 unsigned long ID;
12740 std::stringstream s_strid;
12741 s_strid << std::hex << sd[1];
12742 s_strid >> ID;
12743 CDomoticzHardwareBase* pHardware = GetHardware(HardwareID);
12744 if (pHardware == NULL)
12745 return false;
12746 if (pHardware->HwdType == HTYPE_OpenZWave)
12747 {
12748 std::vector<std::string> splitresults;
12749 StringSplit(clockstr, ";", splitresults);
12750 if (splitresults.size() != 3)
12751 return false;
12752 int day = atoi(splitresults[0].c_str());
12753 int hour = atoi(splitresults[1].c_str());
12754 int minute = atoi(splitresults[2].c_str());
12755
12756 _tGeneralDevice tmeter;
12757 tmeter.subtype = sTypeZWaveClock;
12758 tmeter.intval1 = ID;
12759 tmeter.intval2 = (day * (24 * 60)) + (hour * 60) + minute;
12760 if (!WriteToHardware(HardwareID, (const char*)&tmeter, sizeof(_tGeneralDevice)))
12761 return false;
12762 }
12763 #endif
12764 return true;
12765 }
12766
SetClock(const std::string & idx,const std::string & clockstr)12767 bool MainWorker::SetClock(const std::string& idx, const std::string& clockstr)
12768 {
12769 //Get Device details
12770 std::vector<std::vector<std::string> > result;
12771 result = m_sql.safe_query(
12772 "SELECT HardwareID, DeviceID,Unit,Type,SubType,SwitchType FROM DeviceStatus WHERE (ID == '%q')",
12773 idx.c_str());
12774 if (result.empty())
12775 return false;
12776
12777 std::vector<std::string> sd = result[0];
12778 return SetClockInt(sd, clockstr);
12779 }
12780
SetZWaveThermostatModeInt(const std::vector<std::string> & sd,const int tMode)12781 bool MainWorker::SetZWaveThermostatModeInt(const std::vector<std::string>& sd, const int tMode)
12782 {
12783 #ifdef WITH_OPENZWAVE
12784 int HardwareID = atoi(sd[0].c_str());
12785 int hindex = FindDomoticzHardware(HardwareID);
12786 if (hindex == -1)
12787 return false;
12788
12789 unsigned long ID;
12790 std::stringstream s_strid;
12791 s_strid << std::hex << sd[1];
12792 s_strid >> ID;
12793 CDomoticzHardwareBase* pHardware = GetHardware(HardwareID);
12794 if (pHardware == NULL)
12795 return false;
12796 if (pHardware->HwdType == HTYPE_OpenZWave)
12797 {
12798 _tGeneralDevice tmeter;
12799 tmeter.subtype = sTypeZWaveThermostatMode;
12800 tmeter.intval1 = ID;
12801 tmeter.intval2 = tMode;
12802 if (!WriteToHardware(HardwareID, (const char*)&tmeter, sizeof(_tGeneralDevice)))
12803 return false;
12804 }
12805 #endif
12806 return true;
12807 }
12808
SetZWaveThermostatFanModeInt(const std::vector<std::string> & sd,const int fMode)12809 bool MainWorker::SetZWaveThermostatFanModeInt(const std::vector<std::string>& sd, const int fMode)
12810 {
12811 #ifdef WITH_OPENZWAVE
12812 int HardwareID = atoi(sd[0].c_str());
12813 int hindex = FindDomoticzHardware(HardwareID);
12814 if (hindex == -1)
12815 return false;
12816
12817 unsigned long ID;
12818 std::stringstream s_strid;
12819 s_strid << std::hex << sd[1];
12820 s_strid >> ID;
12821 CDomoticzHardwareBase* pHardware = GetHardware(HardwareID);
12822 if (pHardware == NULL)
12823 return false;
12824 if (pHardware->HwdType == HTYPE_OpenZWave)
12825 {
12826 _tGeneralDevice tmeter;
12827 tmeter.subtype = sTypeZWaveThermostatFanMode;
12828 tmeter.intval1 = ID;
12829 tmeter.intval2 = fMode;
12830 if (!WriteToHardware(HardwareID, (const char*)&tmeter, sizeof(_tGeneralDevice)))
12831 return false;
12832 }
12833 #endif
12834 return true;
12835 }
12836
SetZWaveThermostatMode(const std::string & idx,const int tMode)12837 bool MainWorker::SetZWaveThermostatMode(const std::string& idx, const int tMode)
12838 {
12839 //Get Device details
12840 std::vector<std::vector<std::string> > result;
12841 result = m_sql.safe_query(
12842 "SELECT HardwareID, DeviceID,Unit,Type,SubType,SwitchType FROM DeviceStatus WHERE (ID == '%q')",
12843 idx.c_str());
12844 if (result.empty())
12845 return false;
12846
12847 std::vector<std::string> sd = result[0];
12848 return SetZWaveThermostatModeInt(sd, tMode);
12849 }
12850
SetZWaveThermostatFanMode(const std::string & idx,const int fMode)12851 bool MainWorker::SetZWaveThermostatFanMode(const std::string& idx, const int fMode)
12852 {
12853 //Get Device details
12854 std::vector<std::vector<std::string> > result;
12855 result = m_sql.safe_query(
12856 "SELECT HardwareID, DeviceID,Unit,Type,SubType,SwitchType FROM DeviceStatus WHERE (ID == '%q')",
12857 idx.c_str());
12858 if (result.empty())
12859 return false;
12860
12861 std::vector<std::string> sd = result[0];
12862 return SetZWaveThermostatFanModeInt(sd, fMode);
12863 }
12864
SetThermostatState(const std::string & idx,const int newState)12865 bool MainWorker::SetThermostatState(const std::string& idx, const int newState)
12866 {
12867 //Get Device details
12868 std::vector<std::vector<std::string> > result;
12869 result = m_sql.safe_query(
12870 "SELECT HardwareID, DeviceID,Unit,Type,SubType,SwitchType FROM DeviceStatus WHERE (ID == '%q')",
12871 idx.c_str());
12872 if (result.empty())
12873 return false;
12874 int HardwareID = atoi(result[0][0].c_str());
12875 int hindex = FindDomoticzHardware(HardwareID);
12876 if (hindex == -1)
12877 return false;
12878
12879 CDomoticzHardwareBase* pHardware = GetHardware(HardwareID);
12880 if (pHardware == NULL)
12881 return false;
12882 if (pHardware->HwdType == HTYPE_TOONTHERMOSTAT)
12883 {
12884 CToonThermostat* pGateway = reinterpret_cast<CToonThermostat*>(pHardware);
12885 pGateway->SetProgramState(newState);
12886 return true;
12887 }
12888 if (pHardware->HwdType == HTYPE_AtagOne)
12889 {
12890 //CAtagOne *pGateway = reinterpret_cast<CAtagOne*>(pHardware);
12891 //pGateway->SetProgramState(newState);
12892 return true;
12893 }
12894 else if (pHardware->HwdType == HTYPE_NEST)
12895 {
12896 CNest* pGateway = reinterpret_cast<CNest*>(pHardware);
12897 pGateway->SetProgramState(newState);
12898 return true;
12899 }
12900 else if (pHardware->HwdType == HTYPE_Nest_OAuthAPI)
12901 {
12902 CNestOAuthAPI* pGateway = reinterpret_cast<CNestOAuthAPI*>(pHardware);
12903 pGateway->SetProgramState(newState);
12904 return true;
12905 }
12906 else if (pHardware->HwdType == HTYPE_ANNATHERMOSTAT)
12907 {
12908 CAnnaThermostat* pGateway = reinterpret_cast<CAnnaThermostat*>(pHardware);
12909 pGateway->SetProgramState(newState);
12910 return true;
12911 }
12912 else if (pHardware->HwdType == HTYPE_THERMOSMART)
12913 {
12914 //CThermosmart *pGateway = reinterpret_cast<CThermosmart *>(pHardware);
12915 //pGateway->SetProgramState(newState);
12916 return true;
12917 }
12918 else if (pHardware->HwdType == HTYPE_Netatmo)
12919 {
12920 CNetatmo* pGateway = reinterpret_cast<CNetatmo*>(pHardware);
12921 int tIndex = atoi(idx.c_str());
12922 pGateway->SetProgramState(tIndex, newState);
12923 return true;
12924 }
12925 else if (pHardware->HwdType == HTYPE_IntergasInComfortLAN2RF)
12926 {
12927 CInComfort* pGateway = reinterpret_cast<CInComfort*>(pHardware);
12928 pGateway->SetProgramState(newState);
12929 return true;
12930 }
12931 return false;
12932 }
12933
12934
12935 //returns if a device activates a scene
DoesDeviceActiveAScene(const uint64_t DevRowIdx,const int Cmnd)12936 bool MainWorker::DoesDeviceActiveAScene(const uint64_t DevRowIdx, const int Cmnd)
12937 {
12938 //check for scene code
12939 std::vector<std::vector<std::string> > result;
12940
12941 result = m_sql.safe_query("SELECT Activators, SceneType FROM Scenes WHERE (Activators!='')");
12942 if (!result.empty())
12943 {
12944 for (const auto& itt : result)
12945 {
12946 std::vector<std::string> sd = itt;
12947
12948 int SceneType = atoi(sd[1].c_str());
12949
12950 std::vector<std::string> arrayActivators;
12951 StringSplit(sd[0], ";", arrayActivators);
12952 for (const auto& ittAct : arrayActivators)
12953 {
12954 std::string sCodeCmd = ittAct;
12955
12956 std::vector<std::string> arrayCode;
12957 StringSplit(sCodeCmd, ":", arrayCode);
12958
12959 std::string sID = arrayCode[0];
12960 std::string sCode = "";
12961 if (arrayCode.size() == 2)
12962 {
12963 sCode = arrayCode[1];
12964 }
12965
12966 uint64_t aID = std::strtoull(sID.c_str(), nullptr, 10);
12967 if (aID == DevRowIdx)
12968 {
12969 if ((SceneType == SGTYPE_GROUP) || (sCode.empty()))
12970 return true;
12971 int iCode = atoi(sCode.c_str());
12972 if (iCode == Cmnd)
12973 return true;
12974 }
12975 }
12976 }
12977 }
12978 return false;
12979 }
12980
SwitchScene(const std::string & idx,const std::string & switchcmd,const std::string & User)12981 bool MainWorker::SwitchScene(const std::string& idx, const std::string& switchcmd, const std::string& User)
12982 {
12983 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10);
12984
12985 return SwitchScene(ID, switchcmd, User);
12986 }
12987
SwitchScene(const uint64_t idx,std::string switchcmd,const std::string & User)12988 bool MainWorker::SwitchScene(const uint64_t idx, std::string switchcmd, const std::string& User)
12989 {
12990 std::vector<std::vector<std::string> > result;
12991 int nValue = (switchcmd == "On") ? 1 : 0;
12992
12993 std::string Name = "Unknown?";
12994 _eSceneGroupType scenetype = SGTYPE_SCENE;
12995 std::string onaction = "";
12996 std::string offaction = "";
12997 std::string status = "";
12998
12999 //Get Scene details
13000 result = m_sql.safe_query("SELECT Name, SceneType, OnAction, OffAction, nValue FROM Scenes WHERE (ID == %" PRIu64 ")", idx);
13001 if (!result.empty())
13002 {
13003 std::vector<std::string> sds = result[0];
13004 Name = sds[0];
13005 scenetype = (_eSceneGroupType)atoi(sds[1].c_str());
13006 onaction = sds[2];
13007 offaction = sds[3];
13008 status = sds[4];
13009
13010 if (scenetype == SGTYPE_GROUP)
13011 {
13012 //when asking for Toggle, just switch to the opposite value
13013 if (switchcmd == "Toggle") {
13014 nValue = (atoi(status.c_str()) == 0 ? 1 : 0);
13015 switchcmd = (nValue == 1 ? "On" : "Off");
13016 }
13017 }
13018 m_sql.HandleOnOffAction((nValue == 1), onaction, offaction);
13019 }
13020
13021 m_sql.safe_query("INSERT INTO SceneLog (SceneRowID, nValue, User) VALUES ('%" PRIu64 "', '%d', '%q')", idx, nValue, User.c_str());
13022
13023 std::string szLastUpdate = TimeToString(NULL, TF_DateTime);
13024 m_sql.safe_query("UPDATE Scenes SET nValue=%d, LastUpdate='%q' WHERE (ID == %" PRIu64 ")",
13025 nValue,
13026 szLastUpdate.c_str(),
13027 idx);
13028
13029 //Check if we need to email a snapshot of a Camera
13030 std::string emailserver;
13031 int n2Value;
13032 if (m_sql.GetPreferencesVar("EmailServer", n2Value, emailserver))
13033 {
13034 if (emailserver != "")
13035 {
13036 result = m_sql.safe_query(
13037 "SELECT CameraRowID, DevSceneDelay FROM CamerasActiveDevices WHERE (DevSceneType==1) AND (DevSceneRowID==%" PRIu64 ") AND (DevSceneWhen==%d)",
13038 idx,
13039 !nValue
13040 );
13041 if (!result.empty())
13042 {
13043 for (const auto& ittCam : result)
13044 {
13045 std::vector<std::string> sd = ittCam;
13046 std::string camidx = sd[0];
13047 int delay = atoi(sd[1].c_str());
13048 std::string subject;
13049 if (scenetype == SGTYPE_SCENE)
13050 subject = Name + " Activated";
13051 else
13052 subject = Name + " Status: " + switchcmd;
13053 m_sql.AddTaskItem(_tTaskItem::EmailCameraSnapshot(static_cast<float>(delay + 1), camidx, subject));
13054 }
13055 }
13056 }
13057 }
13058
13059 _log.Log(LOG_NORM, "Activating Scene/Group: [%s]", Name.c_str());
13060
13061 bool bEventTrigger = true;
13062 if (m_sql.m_bEnableEventSystem)
13063 bEventTrigger = m_eventsystem.UpdateSceneGroup(idx, nValue, szLastUpdate);
13064
13065 // Notify listeners
13066 sOnSwitchScene(idx, Name);
13067
13068 //now switch all attached devices, and only the onces that do not trigger a scene
13069 result = m_sql.safe_query(
13070 "SELECT DeviceRowID, Cmd, Level, Color, OnDelay, OffDelay FROM SceneDevices WHERE (SceneRowID == %" PRIu64 ") ORDER BY [Order] ASC", idx);
13071 if (result.empty())
13072 return true; //no devices in the scene
13073
13074 for (const auto& itt : result)
13075 {
13076 std::vector<std::string> sd = itt;
13077
13078 int cmd = atoi(sd[1].c_str());
13079 int level = atoi(sd[2].c_str());
13080 _tColor color(sd[3]);
13081 int ondelay = atoi(sd[4].c_str());
13082 int offdelay = atoi(sd[5].c_str());
13083 std::vector<std::vector<std::string> > result2;
13084 result2 = m_sql.safe_query(
13085 "SELECT HardwareID, DeviceID,Unit,Type,SubType,SwitchType, nValue, sValue, Name FROM DeviceStatus WHERE (ID == '%q')", sd[0].c_str());
13086 if (!result2.empty())
13087 {
13088 std::vector<std::string> sd2 = result2[0];
13089 //uint8_t rnValue = atoi(sd2[6].c_str());
13090 std::string sValue = sd2[7];
13091 //uint8_t Unit = atoi(sd2[2].c_str());
13092 uint8_t dType = atoi(sd2[3].c_str());
13093 uint8_t dSubType = atoi(sd2[4].c_str());
13094 std::string DeviceName = sd2[8];
13095 _eSwitchType switchtype = (_eSwitchType)atoi(sd2[5].c_str());
13096
13097 //Check if this device will not activate a scene
13098 uint64_t dID = std::strtoull(sd[0].c_str(), nullptr, 10);
13099 if (DoesDeviceActiveAScene(dID, cmd))
13100 {
13101 _log.Log(LOG_ERROR, "Skipping sensor '%s' because this triggers another scene!", DeviceName.c_str());
13102 continue;
13103 }
13104
13105 std::string lstatus = switchcmd;
13106 int llevel = 0;
13107 bool bHaveDimmer = false;
13108 bool bHaveGroupCmd = false;
13109 int maxDimLevel = 0;
13110
13111 GetLightStatus(dType, dSubType, switchtype, cmd, sValue, lstatus, llevel, bHaveDimmer, maxDimLevel, bHaveGroupCmd);
13112
13113 if (scenetype == SGTYPE_GROUP)
13114 {
13115 lstatus = ((switchcmd == "On") || (switchcmd == "Group On") || (switchcmd == "Chime") || (switchcmd == "All On")) ? "On" : "Off";
13116 }
13117 _log.Log(LOG_NORM, "Activating Scene/Group Device: %s (%s)", DeviceName.c_str(), lstatus.c_str());
13118
13119
13120 int ilevel = maxDimLevel - 1; // Why -1?
13121
13122 if (
13123 ((switchtype == STYPE_Dimmer) ||
13124 (switchtype == STYPE_BlindsPercentage) ||
13125 (switchtype == STYPE_BlindsPercentageInverted) ||
13126 (switchtype == STYPE_Selector)
13127 ) && (maxDimLevel != 0))
13128 {
13129 if (lstatus == "On")
13130 {
13131 lstatus = "Set Level";
13132 float fLevel = (maxDimLevel / 100.0f) * level;
13133 if (fLevel > 100)
13134 fLevel = 100;
13135 ilevel = round(fLevel);
13136 }
13137 if (switchtype == STYPE_Selector) {
13138 if (lstatus != "Set Level") {
13139 ilevel = 0;
13140 }
13141 ilevel = round(ilevel / 10.0f) * 10; // select only multiples of 10
13142 if (ilevel == 0) {
13143 lstatus = "Off";
13144 }
13145 }
13146 }
13147
13148 int idx = atoi(sd[0].c_str());
13149 if (switchtype != STYPE_PushOn)
13150 {
13151 int delay = (lstatus == "Off") ? offdelay : ondelay;
13152 if (m_sql.m_bEnableEventSystem && !bEventTrigger)
13153 m_eventsystem.SetEventTrigger(idx, m_eventsystem.REASON_DEVICE, static_cast<float>(delay));
13154 SwitchLight(idx, lstatus, ilevel, color, false, delay, User);
13155 if (scenetype == SGTYPE_SCENE)
13156 {
13157 if ((lstatus != "Off") && (offdelay > 0))
13158 {
13159 //switch with on delay, and off delay
13160 if (m_sql.m_bEnableEventSystem && !bEventTrigger)
13161 m_eventsystem.SetEventTrigger(idx, m_eventsystem.REASON_DEVICE, static_cast<float>(ondelay + offdelay));
13162 SwitchLight(idx, "Off", ilevel, color, false, ondelay + offdelay, User);
13163 }
13164 }
13165 }
13166 else
13167 {
13168 if (m_sql.m_bEnableEventSystem && !bEventTrigger)
13169 m_eventsystem.SetEventTrigger(idx, m_eventsystem.REASON_DEVICE, static_cast<float>(ondelay));
13170 SwitchLight(idx, "On", ilevel, color, false, ondelay, User);
13171 }
13172 sleep_milliseconds(50);
13173 }
13174 }
13175 return true;
13176 }
13177
CheckSceneCode(const uint64_t DevRowIdx,const uint8_t dType,const uint8_t dSubType,const int nValue,const char * sValue,const std::string & User)13178 void MainWorker::CheckSceneCode(const uint64_t DevRowIdx, const uint8_t dType, const uint8_t dSubType, const int nValue, const char* sValue, const std::string& User)
13179 {
13180 //check for scene code
13181 std::vector<std::vector<std::string> > result;
13182
13183 result = m_sql.safe_query("SELECT ID, Activators, SceneType FROM Scenes WHERE (Activators!='')");
13184 if (!result.empty())
13185 {
13186 for (const auto& itt : result)
13187 {
13188 std::vector<std::string> sd = itt;
13189
13190 std::vector<std::string> arrayActivators;
13191 StringSplit(sd[1], ";", arrayActivators);
13192 for (const auto& ittAct : arrayActivators)
13193 {
13194 std::string sCodeCmd = ittAct;
13195
13196 std::vector<std::string> arrayCode;
13197 StringSplit(sCodeCmd, ":", arrayCode);
13198
13199 std::string sID = arrayCode[0];
13200 std::string sCode = "";
13201 if (arrayCode.size() == 2)
13202 {
13203 sCode = arrayCode[1];
13204 }
13205
13206 uint64_t aID = std::strtoull(sID.c_str(), nullptr, 10);
13207 if (aID == DevRowIdx)
13208 {
13209 uint64_t ID = std::strtoull(sd[0].c_str(), nullptr, 10);
13210 int scenetype = atoi(sd[2].c_str());
13211 int rnValue = nValue;
13212
13213 if ((scenetype == SGTYPE_SCENE) && (!sCode.empty()))
13214 {
13215 //Also check code
13216 int iCode = atoi(sCode.c_str());
13217 if (iCode != nValue)
13218 continue;
13219 rnValue = 1; //A Scene can only be activated (On)
13220 }
13221
13222 std::string lstatus = "";
13223 int llevel = 0;
13224 bool bHaveDimmer = false;
13225 bool bHaveGroupCmd = false;
13226 int maxDimLevel = 0;
13227
13228 GetLightStatus(dType, dSubType, STYPE_OnOff, rnValue, sValue, lstatus, llevel, bHaveDimmer, maxDimLevel, bHaveGroupCmd);
13229 std::string switchcmd = (IsLightSwitchOn(lstatus) == true) ? "On" : "Off";
13230
13231 m_sql.AddTaskItem(_tTaskItem::SwitchSceneEvent(0.2f, ID, switchcmd, "SceneTrigger", User));
13232 }
13233 }
13234 }
13235 }
13236 }
13237
LoadSharedUsers()13238 void MainWorker::LoadSharedUsers()
13239 {
13240 std::vector<tcp::server::_tRemoteShareUser> users;
13241
13242 std::vector<std::vector<std::string> > result;
13243 std::vector<std::vector<std::string> > result2;
13244
13245 result = m_sql.safe_query("SELECT ID, Username, Password FROM USERS WHERE ((RemoteSharing==1) AND (Active==1))");
13246 if (!result.empty())
13247 {
13248 for (const auto& itt : result)
13249 {
13250 std::vector<std::string> sd = itt;
13251 tcp::server::_tRemoteShareUser suser;
13252 suser.Username = base64_decode(sd[1]);
13253 suser.Password = sd[2];
13254
13255 //Get User Devices
13256 result2 = m_sql.safe_query("SELECT DeviceRowID FROM SharedDevices WHERE (SharedUserID == '%q')", sd[0].c_str());
13257 if (!result2.empty())
13258 {
13259 for (const auto& itt2 : result2)
13260 {
13261 std::vector<std::string> sd2 = itt2;
13262 uint64_t ID = std::strtoull(sd2[0].c_str(), nullptr, 10);
13263 suser.Devices.push_back(ID);
13264 }
13265 }
13266 users.push_back(suser);
13267 }
13268 }
13269 m_sharedserver.SetRemoteUsers(users);
13270 m_sharedserver.stopAllClients();
13271 }
13272
SetInternalSecStatus()13273 void MainWorker::SetInternalSecStatus()
13274 {
13275 m_eventsystem.WWWUpdateSecurityState(m_SecStatus);
13276
13277 //Update Domoticz Security Device
13278 RBUF tsen;
13279 memset(&tsen, 0, sizeof(RBUF));
13280 tsen.SECURITY1.packetlength = sizeof(tsen.TEMP) - 1;
13281 tsen.SECURITY1.packettype = pTypeSecurity1;
13282 tsen.SECURITY1.subtype = sTypeDomoticzSecurity;
13283 tsen.SECURITY1.battery_level = 9;
13284 tsen.SECURITY1.rssi = 12;
13285 tsen.SECURITY1.id1 = 0x14;
13286 tsen.SECURITY1.id2 = 0x87;
13287 tsen.SECURITY1.id3 = 0x02;
13288 tsen.SECURITY1.seqnbr = 1;
13289 if (m_SecStatus == SECSTATUS_DISARMED)
13290 tsen.SECURITY1.status = sStatusNormal;
13291 else if (m_SecStatus == SECSTATUS_ARMEDHOME)
13292 tsen.SECURITY1.status = sStatusArmHome;
13293 else
13294 tsen.SECURITY1.status = sStatusArmAway;
13295
13296 if (_log.IsDebugLevelEnabled(DEBUG_RECEIVED))
13297 {
13298 _log.Log(LOG_NORM, "(System) Domoticz Security Status");
13299 }
13300
13301 CDomoticzHardwareBase* pHardware = GetHardwareByType(HTYPE_DomoticzInternal);
13302 PushAndWaitRxMessage(pHardware, (const uint8_t*)&tsen, "Domoticz Security Panel", -1);
13303 }
13304
UpdateDomoticzSecurityStatus(const int iSecStatus)13305 void MainWorker::UpdateDomoticzSecurityStatus(const int iSecStatus)
13306 {
13307 m_SecCountdown = -1; //cancel possible previous delay
13308 m_SecStatus = iSecStatus;
13309
13310 m_sql.UpdatePreferencesVar("SecStatus", iSecStatus);
13311
13312 int nValue = 0;
13313 m_sql.GetPreferencesVar("SecOnDelay", nValue);
13314
13315 if ((nValue == 0) || (iSecStatus == SECSTATUS_DISARMED))
13316 {
13317 //Do it Directly
13318 SetInternalSecStatus();
13319 }
13320 else
13321 {
13322 //Schedule It
13323 m_SecCountdown = nValue;
13324 }
13325 }
13326
ForceLogNotificationCheck()13327 void MainWorker::ForceLogNotificationCheck()
13328 {
13329 m_bForceLogNotificationCheck = true;
13330 }
13331
HandleLogNotifications()13332 void MainWorker::HandleLogNotifications()
13333 {
13334 std::list<CLogger::_tLogLineStruct> _loglines = _log.GetNotificationLogs();
13335 if (_loglines.empty())
13336 return;
13337 //Assemble notification message
13338
13339 std::stringstream sstr;
13340 std::list<CLogger::_tLogLineStruct>::const_iterator itt;
13341 std::string sTopic;
13342
13343 if (_loglines.size() > 1)
13344 {
13345 sTopic = "Domoticz: Multiple errors received in the last 5 minutes";
13346 sstr << "Multiple errors received in the last 5 minutes:<br><br>";
13347 }
13348 else
13349 {
13350 itt = _loglines.begin();
13351 sTopic = "Domoticz: " + itt->logmessage;
13352 }
13353
13354 for (itt = _loglines.begin(); itt != _loglines.end(); ++itt)
13355 {
13356 sstr << itt->logmessage << "<br>";
13357 }
13358 m_sql.AddTaskItem(_tTaskItem::SendEmail(1, sTopic, sstr.str()));
13359 }
13360
HeartbeatUpdate(const std::string & component,bool critical)13361 void MainWorker::HeartbeatUpdate(const std::string& component, bool critical /*= true*/)
13362 {
13363 std::lock_guard<std::mutex> l(m_heartbeatmutex);
13364 time_t now = time(0);
13365 auto itt = m_componentheartbeats.find(component);
13366 if (itt != m_componentheartbeats.end()) {
13367 itt->second.first = now;
13368 }
13369 else {
13370 m_componentheartbeats[component] = std::make_pair(now, critical);
13371 }
13372 }
13373
HeartbeatRemove(const std::string & component)13374 void MainWorker::HeartbeatRemove(const std::string& component)
13375 {
13376 std::lock_guard<std::mutex> l(m_heartbeatmutex);
13377 auto itt = m_componentheartbeats.find(component);
13378 if (itt != m_componentheartbeats.end()) {
13379 m_componentheartbeats.erase(itt);
13380 }
13381 }
13382
HeartbeatCheck()13383 void MainWorker::HeartbeatCheck()
13384 {
13385 std::lock_guard<std::mutex> l(m_heartbeatmutex);
13386 std::lock_guard<std::mutex> l2(m_devicemutex);
13387
13388 m_devicestorestart.clear();
13389
13390 time_t now;
13391 mytime(&now);
13392
13393 for (const auto& itt : m_componentheartbeats)
13394 {
13395 double diff = difftime(now, itt.second.first);
13396 if (diff > 60)
13397 {
13398 _log.Log(LOG_ERROR, "%s thread seems to have ended unexpectedly (last update %f seconds ago)", itt.first.c_str(), diff);
13399 /* GizMoCuz: This causes long operations to crash (Like Issue #3011)
13400 if (itt.second.second) // If the stalled component is marked as critical, call abort / raise signal
13401 {
13402 if (!IsDebuggerPresent())
13403 {
13404 #ifdef WIN32
13405 abort();
13406 #else
13407 raise(SIGUSR1);
13408 #endif
13409 }
13410 }
13411 */
13412 }
13413 }
13414
13415 //Check hardware heartbeats
13416 std::vector<CDomoticzHardwareBase*>::const_iterator itt;
13417 for (itt = m_hardwaredevices.begin(); itt != m_hardwaredevices.end(); ++itt)
13418 {
13419 CDomoticzHardwareBase* pHardware = (CDomoticzHardwareBase*)(*itt);
13420 if (!pHardware->m_bSkipReceiveCheck)
13421 {
13422 //Skip Dummy Hardware
13423 bool bDoCheck = (pHardware->HwdType != HTYPE_Dummy) && (pHardware->HwdType != HTYPE_EVOHOME_SCRIPT);
13424 if (bDoCheck)
13425 {
13426 //Check Thread Timeout
13427 double diff = difftime(now, pHardware->m_LastHeartbeat);
13428 //_log.Log(LOG_STATUS, "%d last checking %.2lf seconds ago", iterator->first, dif);
13429 if (diff > 60)
13430 {
13431 std::vector<std::vector<std::string> > result;
13432 result = m_sql.safe_query("SELECT Name FROM Hardware WHERE (ID='%d')", pHardware->m_HwdID);
13433 if (result.size() == 1)
13434 {
13435 std::vector<std::string> sd = result[0];
13436 _log.Log(LOG_ERROR, "%s hardware (%d) thread seems to have ended unexpectedly", sd[0].c_str(), pHardware->m_HwdID);
13437 }
13438 }
13439 }
13440
13441 if (pHardware->m_DataTimeout > 0)
13442 {
13443 //Check Receive Timeout
13444 double diff = difftime(now, pHardware->m_LastHeartbeatReceive);
13445 bool bHaveDataTimeout = (diff > pHardware->m_DataTimeout);
13446 if (!bHaveDataTimeout)
13447 {
13448 if (
13449 (pHardware->HwdType == HTYPE_RFXLAN)
13450 || (pHardware->HwdType == HTYPE_RFXtrx315)
13451 || (pHardware->HwdType == HTYPE_RFXtrx433)
13452 || (pHardware->HwdType == HTYPE_RFXtrx868)
13453 )
13454 {
13455 const CRFXBase* pRFXBase = static_cast<CRFXBase*>(pHardware);
13456 if (pRFXBase->m_LastP1Received != 0)
13457 {
13458 diff = difftime(now, pRFXBase->m_LastP1Received);
13459 bHaveDataTimeout = (diff > pHardware->m_DataTimeout);
13460 }
13461 }
13462 }
13463 if (bHaveDataTimeout)
13464 {
13465 std::string sDataTimeout = "";
13466 int totNum = 0;
13467 if (pHardware->m_DataTimeout < 60) {
13468 totNum = pHardware->m_DataTimeout;
13469 sDataTimeout = "Seconds";
13470 }
13471 else if (pHardware->m_DataTimeout < 3600) {
13472 totNum = pHardware->m_DataTimeout / 60;
13473 if (totNum == 1) {
13474 sDataTimeout = "Minute";
13475 }
13476 else {
13477 sDataTimeout = "Minutes";
13478 }
13479 }
13480 else if (pHardware->m_DataTimeout < 86400) {
13481 totNum = pHardware->m_DataTimeout / 3600;
13482 if (totNum == 1) {
13483 sDataTimeout = "Hour";
13484 }
13485 else {
13486 sDataTimeout = "Hours";
13487 }
13488 }
13489 else {
13490 totNum = pHardware->m_DataTimeout / 60;
13491 if (totNum == 1) {
13492 sDataTimeout = "Day";
13493 }
13494 else {
13495 sDataTimeout = "Days";
13496 }
13497 }
13498
13499 _log.Log(LOG_ERROR, "%s hardware (%d) nothing received for more than %d %s!....", pHardware->m_Name.c_str(), pHardware->m_HwdID, totNum, sDataTimeout.c_str());
13500 m_devicestorestart.push_back(pHardware->m_HwdID);
13501 }
13502 }
13503
13504 }
13505 }
13506 }
13507
UpdateDevice(const int DevIdx,int nValue,std::string & sValue,const int signallevel,const int batterylevel,const bool parseTrigger)13508 bool MainWorker::UpdateDevice(const int DevIdx, int nValue, std::string& sValue, const int signallevel, const int batterylevel, const bool parseTrigger)
13509 {
13510 // Get the raw device parameters
13511 std::vector<std::vector<std::string> > result;
13512 result = m_sql.safe_query("SELECT HardwareID, DeviceID, Unit, Type, SubType FROM DeviceStatus WHERE (ID==%d)", DevIdx);
13513 if (result.empty())
13514 return false;
13515
13516 int HardwareID = std::stoi(result[0][0]);
13517 std::string DeviceID = result[0][1];
13518 int unit = std::stoi(result[0][2]);
13519 int devType = std::stoi(result[0][3]);
13520 int subType = std::stoi(result[0][4]);
13521
13522 return UpdateDevice(HardwareID, DeviceID, unit, devType, subType, nValue, sValue, signallevel, batterylevel, parseTrigger);
13523 }
13524
UpdateDevice(const int HardwareID,const std::string & DeviceID,const int unit,const int devType,const int subType,int nValue,std::string & sValue,const int signallevel,const int batterylevel,const bool parseTrigger)13525 bool MainWorker::UpdateDevice(const int HardwareID, const std::string& DeviceID, const int unit, const int devType, const int subType, int nValue, std::string& sValue, const int signallevel, const int batterylevel, const bool parseTrigger)
13526 {
13527 CDomoticzHardwareBase* pHardware = GetHardware(HardwareID);
13528
13529 // Prevent hazardous modification of DB from JSON calls
13530 if (!m_sql.DoesDeviceExist(HardwareID, DeviceID.c_str(), unit, devType, subType))
13531 return false;
13532
13533 g_bUseEventTrigger = parseTrigger;
13534
13535 unsigned long ID = 0;
13536 std::stringstream s_strid;
13537 s_strid << std::hex << DeviceID;
13538 s_strid >> ID;
13539
13540 float temp = 12345.0f;
13541
13542 if (pHardware)
13543 {
13544 if (devType == pTypeLighting2)
13545 {
13546 //Update as Lighting 2
13547 unsigned long ID;
13548 std::stringstream s_strid;
13549 s_strid << std::hex << DeviceID;
13550 s_strid >> ID;
13551 uint8_t ID1 = (uint8_t)((ID & 0xFF000000) >> 24);
13552 uint8_t ID2 = (uint8_t)((ID & 0x00FF0000) >> 16);
13553 uint8_t ID3 = (uint8_t)((ID & 0x0000FF00) >> 8);
13554 uint8_t ID4 = (uint8_t)((ID & 0x000000FF));
13555
13556 tRBUF lcmd;
13557 memset(&lcmd, 0, sizeof(RBUF));
13558 lcmd.LIGHTING2.packetlength = sizeof(lcmd.LIGHTING2) - 1;
13559 lcmd.LIGHTING2.packettype = pTypeLighting2;
13560 lcmd.LIGHTING2.subtype = subType;
13561 lcmd.LIGHTING2.id1 = ID1;
13562 lcmd.LIGHTING2.id2 = ID2;
13563 lcmd.LIGHTING2.id3 = ID3;
13564 lcmd.LIGHTING2.id4 = ID4;
13565 lcmd.LIGHTING2.unitcode = (uint8_t)unit;
13566 lcmd.LIGHTING2.cmnd = (uint8_t)nValue;
13567 lcmd.LIGHTING2.level = (uint8_t)atoi(sValue.c_str());
13568 lcmd.LIGHTING2.filler = 0;
13569 lcmd.LIGHTING2.rssi = signallevel;
13570 DecodeRXMessage(pHardware, (const uint8_t*)&lcmd.LIGHTING2, NULL, batterylevel);
13571 g_bUseEventTrigger = true;
13572 return true;
13573 }
13574
13575 if (
13576 (devType == pTypeTEMP)
13577 || (devType == pTypeTEMP_HUM)
13578 || (devType == pTypeTEMP_HUM_BARO)
13579 || (devType == pTypeBARO)
13580 )
13581 {
13582 //Adjustment value
13583 float AddjValue = 0.0f;
13584 float AddjMulti = 1.0f;
13585 m_sql.GetAddjustment(HardwareID, DeviceID.c_str(), unit, devType, subType, AddjValue, AddjMulti);
13586
13587 char szTmp[100];
13588 std::vector<std::string> strarray;
13589
13590 if (devType == pTypeTEMP)
13591 {
13592 temp = static_cast<float>(atof(sValue.c_str()));
13593 temp += AddjValue;
13594 sprintf(szTmp, "%.2f", temp);
13595 sValue = szTmp;
13596 }
13597 else if (devType == pTypeTEMP_HUM)
13598 {
13599 StringSplit(sValue, ";", strarray);
13600 if (strarray.size() == 3)
13601 {
13602 temp = static_cast<float>(atof(strarray[0].c_str()));
13603 temp += AddjValue;
13604 sprintf(szTmp, "%.2f;%s;%s", temp, strarray[1].c_str(), strarray[2].c_str());
13605 sValue = szTmp;
13606 }
13607 }
13608 else if (devType == pTypeTEMP_HUM_BARO)
13609 {
13610 StringSplit(sValue, ";", strarray);
13611 if (strarray.size() == 5)
13612 {
13613 temp = static_cast<float>(atof(strarray[0].c_str()));
13614 float fbarometer = static_cast<float>(atof(strarray[3].c_str()));
13615 temp += AddjValue;
13616
13617 AddjValue = 0.0f;
13618 AddjMulti = 1.0f;
13619 m_sql.GetAddjustment2(HardwareID, DeviceID.c_str(), unit, devType, subType, AddjValue, AddjMulti);
13620 fbarometer += AddjValue;
13621
13622 if (subType == sTypeTHBFloat)
13623 {
13624 sprintf(szTmp, "%.2f;%s;%s;%.1f;%s", temp, strarray[1].c_str(), strarray[2].c_str(), fbarometer, strarray[4].c_str());
13625 }
13626 else
13627 {
13628 sprintf(szTmp, "%.2f;%s;%s;%d;%s", temp, strarray[1].c_str(), strarray[2].c_str(), (int)rint(fbarometer), strarray[4].c_str());
13629 }
13630 sValue = szTmp;
13631 }
13632 }
13633 }
13634 }
13635
13636 std::string devname = "Unknown";
13637 const uint64_t devidx = m_sql.UpdateValue(
13638 HardwareID,
13639 DeviceID.c_str(),
13640 (const uint8_t)unit,
13641 (const uint8_t)devType,
13642 (const uint8_t)subType,
13643 signallevel,//signal level,
13644 batterylevel,//battery level
13645 nValue,
13646 sValue.c_str(),
13647 devname,
13648 false
13649 );
13650 if (devidx == (uint64_t)-1)
13651 {
13652 g_bUseEventTrigger = true;
13653 return false;
13654 }
13655
13656 if (pHardware)
13657 {
13658 if (
13659 (pHardware->HwdType == HTYPE_MySensorsUSB) ||
13660 (pHardware->HwdType == HTYPE_MySensorsTCP) ||
13661 (pHardware->HwdType == HTYPE_MySensorsMQTT)
13662 )
13663 {
13664 unsigned long ID;
13665 std::stringstream s_strid;
13666 s_strid << std::hex << DeviceID;
13667 s_strid >> ID;
13668 uint8_t NodeID = (uint8_t)((ID & 0x0000FF00) >> 8);
13669 uint8_t ChildID = (uint8_t)((ID & 0x000000FF));
13670
13671 MySensorsBase* pMySensorDevice = reinterpret_cast<MySensorsBase*>(pHardware);
13672 pMySensorDevice->SendTextSensorValue(NodeID, ChildID, sValue);
13673 }
13674 }
13675
13676 //Calculate temperature trend
13677 if (temp != 12345.0f)
13678 {
13679 uint64_t tID = ((uint64_t)(HardwareID & 0x7FFFFFFF) << 32) | (devidx & 0x7FFFFFFF);
13680 m_trend_calculator[tID].AddValueAndReturnTendency(static_cast<double>(temp), _tTrendCalculator::TAVERAGE_TEMP);
13681 }
13682
13683 #ifdef ENABLE_PYTHON
13684 // notify plugin
13685 m_pluginsystem.DeviceModified(devidx);
13686 #endif
13687
13688 // signal connected devices (MQTT, fibaro, http push ... ) about the update
13689 sOnDeviceReceived(HardwareID, devidx, devname, nullptr);
13690
13691 std::stringstream sidx;
13692 sidx << devidx;
13693
13694 if (
13695 ((devType == pTypeThermostat) && (subType == sTypeThermSetpoint)) ||
13696 ((devType == pTypeRadiator1) && (subType == sTypeSmartwares))
13697 )
13698 {
13699 _log.Log(LOG_NORM, "Sending SetPoint to device....");
13700 SetSetPoint(sidx.str(), static_cast<float>(atof(sValue.c_str())));
13701 }
13702 else if ((devType == pTypeGeneral) && (subType == sTypeZWaveThermostatMode))
13703 {
13704 _log.Log(LOG_NORM, "Sending Thermostat Mode to device....");
13705 SetZWaveThermostatMode(sidx.str(), nValue);
13706 }
13707 else if ((devType == pTypeGeneral) && (subType == sTypeZWaveThermostatFanMode))
13708 {
13709 _log.Log(LOG_NORM, "Sending Thermostat Fan Mode to device....");
13710 SetZWaveThermostatFanMode(sidx.str(), nValue);
13711 }
13712 else if (pHardware) {
13713 //Handle Notification
13714 m_notifications.CheckAndHandleNotification(devidx, HardwareID, DeviceID, devname, unit, devType, subType, nValue, sValue);
13715 }
13716
13717 g_bUseEventTrigger = true;
13718
13719 return true;
13720 }
13721