1 #include "stdafx.h"
2 #include <iostream>
3 #include "DomoticzHardware.h"
4 #include "../main/Logger.h"
5 #include "../main/localtime_r.h"
6 #include "../main/Helper.h"
7 #include "../main/RFXtrx.h"
8 #include "../main/SQLHelper.h"
9 #include "../main/mainworker.h"
10 #include "hardwaretypes.h"
11 #include "HardwareCereal.h"
12 
13 #define round(a) ( int ) ( a + .5 )
14 
CDomoticzHardwareBase()15 CDomoticzHardwareBase::CDomoticzHardwareBase()
16 {
17 	mytime(&m_LastHeartbeat);
18 	mytime(&m_LastHeartbeatReceive);
19 };
20 
~CDomoticzHardwareBase()21 CDomoticzHardwareBase::~CDomoticzHardwareBase()
22 {
23 }
24 
CustomCommand(const uint64_t,const std::string &)25 bool CDomoticzHardwareBase::CustomCommand(const uint64_t /*idx*/, const std::string& /*sCommand*/)
26 {
27 	return false;
28 }
29 
Start()30 bool CDomoticzHardwareBase::Start()
31 {
32 	m_iHBCounter = 0;
33 	m_bIsStarted = StartHardware();
34 	return m_bIsStarted;
35 }
36 
Stop()37 bool CDomoticzHardwareBase::Stop()
38 {
39 	m_bIsStarted = (!StopHardware());
40 	return (!m_bIsStarted);
41 }
42 
Restart()43 bool CDomoticzHardwareBase::Restart()
44 {
45 	if (StopHardware())
46 	{
47 		m_bIsStarted = StartHardware();
48 		return m_bIsStarted;
49 	}
50 	return false;
51 }
52 
RestartWithDelay(const long seconds)53 bool CDomoticzHardwareBase::RestartWithDelay(const long seconds)
54 {
55 	if (StopHardware())
56 	{
57 		sleep_seconds(seconds);
58 		m_bIsStarted = StartHardware();
59 		return m_bIsStarted;
60 	}
61 	return false;
62 }
63 
EnableOutputLog(const bool bEnableLog)64 void CDomoticzHardwareBase::EnableOutputLog(const bool bEnableLog)
65 {
66 	m_bOutputLog = bEnableLog;
67 }
68 
StartHeartbeatThread()69 void CDomoticzHardwareBase::StartHeartbeatThread()
70 {
71 	StartHeartbeatThread("Domoticz_HBWork");
72 }
73 
StartHeartbeatThread(const char * ThreadName)74 void CDomoticzHardwareBase::StartHeartbeatThread(const char* ThreadName)
75 {
76 	m_Heartbeatthread = std::make_shared<std::thread>(&CDomoticzHardwareBase::Do_Heartbeat_Work, this);
77 	SetThreadName(m_Heartbeatthread->native_handle(), ThreadName);
78 }
79 
80 
StopHeartbeatThread()81 void CDomoticzHardwareBase::StopHeartbeatThread()
82 {
83 	if (m_Heartbeatthread)
84 	{
85 		RequestStop();
86 		m_Heartbeatthread->join();
87 		// Wait a while. The read thread might be reading. Adding this prevents a pointer error in the async serial class.
88 		sleep_milliseconds(10);
89 		m_Heartbeatthread.reset();
90 	}
91 }
92 
Do_Heartbeat_Work()93 void CDomoticzHardwareBase::Do_Heartbeat_Work()
94 {
95 	int secCounter = 0;
96 	int hbCounter = 0;
97 	while (!IsStopRequested(200))
98 	{
99 		secCounter++;
100 		if (secCounter == 5)
101 		{
102 			secCounter = 0;
103 			hbCounter++;
104 			if (hbCounter % 12 == 0) {
105 				mytime(&m_LastHeartbeat);
106 			}
107 		}
108 	}
109 }
110 
SetHeartbeatReceived()111 void CDomoticzHardwareBase::SetHeartbeatReceived()
112 {
113 	mytime(&m_LastHeartbeatReceive);
114 }
115 
HandleHBCounter(const int iInterval)116 void CDomoticzHardwareBase::HandleHBCounter(const int iInterval)
117 {
118 	m_iHBCounter++;
119 	if (m_iHBCounter % iInterval == 0)
120 	{
121 		SetHeartbeatReceived();
122 	}
123 }
124 
SetThreadNameInt(const std::thread::native_handle_type & thread)125 int CDomoticzHardwareBase::SetThreadNameInt(const std::thread::native_handle_type& thread)
126 {
127 	return SetThreadName(thread, m_ShortName.c_str());
128 }
129 
130 //Log Helper functions
131 #define MAX_LOG_LINE_LENGTH (2048*3)
Log(const _eLogLevel level,const std::string & sLogline)132 void CDomoticzHardwareBase::Log(const _eLogLevel level, const std::string& sLogline)
133 {
134 	_log.Log(level, "%s: %s", m_ShortName.c_str(), sLogline.c_str());
135 }
136 
Log(const _eLogLevel level,const char * logline,...)137 void CDomoticzHardwareBase::Log(const _eLogLevel level, const char* logline, ...)
138 {
139 	va_list argList;
140 	char cbuffer[MAX_LOG_LINE_LENGTH];
141 	va_start(argList, logline);
142 	vsnprintf(cbuffer, sizeof(cbuffer), logline, argList);
143 	va_end(argList);
144 	_log.Log(level, "%s: %s", m_ShortName.c_str(), cbuffer);
145 }
146 
Debug(const _eDebugLevel level,const std::string & sLogline)147 void CDomoticzHardwareBase::Debug(const _eDebugLevel level, const std::string& sLogline)
148 {
149 	_log.Debug(level, "%s: %s", m_ShortName.c_str(), sLogline.c_str());
150 }
151 
Debug(const _eDebugLevel level,const char * logline,...)152 void CDomoticzHardwareBase::Debug(const _eDebugLevel level, const char* logline, ...)
153 {
154 	va_list argList;
155 	char cbuffer[MAX_LOG_LINE_LENGTH];
156 	va_start(argList, logline);
157 	vsnprintf(cbuffer, sizeof(cbuffer), logline, argList);
158 	va_end(argList);
159 	_log.Debug(level, "%s: %s", m_ShortName.c_str(), cbuffer);
160 }
161 
162 //Sensor Helpers
SendTempSensor(const int NodeID,const int BatteryLevel,const float temperature,const std::string & defaultname,const int RssiLevel)163 void CDomoticzHardwareBase::SendTempSensor(const int NodeID, const int BatteryLevel, const float temperature, const std::string& defaultname, const int RssiLevel /* =12 */)
164 {
165 	RBUF tsen;
166 	memset(&tsen, 0, sizeof(RBUF));
167 	tsen.TEMP.packetlength = sizeof(tsen.TEMP) - 1;
168 	tsen.TEMP.packettype = pTypeTEMP;
169 	tsen.TEMP.subtype = sTypeTEMP5;
170 	tsen.TEMP.battery_level = BatteryLevel;
171 	tsen.TEMP.rssi = RssiLevel;
172 	tsen.TEMP.id1 = (NodeID & 0xFF00) >> 8;
173 	tsen.TEMP.id2 = NodeID & 0xFF;
174 	tsen.TEMP.tempsign = (temperature >= 0) ? 0 : 1;
175 	int at10 = round(std::abs(temperature * 10.0f));
176 	tsen.TEMP.temperatureh = (BYTE)(at10 / 256);
177 	at10 -= (tsen.TEMP.temperatureh * 256);
178 	tsen.TEMP.temperaturel = (BYTE)(at10);
179 	sDecodeRXMessage(this, (const unsigned char*)& tsen.TEMP, defaultname.c_str(), BatteryLevel);
180 }
181 
SendHumiditySensor(const int NodeID,const int BatteryLevel,const int humidity,const std::string & defaultname,const int RssiLevel)182 void CDomoticzHardwareBase::SendHumiditySensor(const int NodeID, const int BatteryLevel, const int humidity, const std::string& defaultname, const int RssiLevel /* =12 */)
183 {
184 	RBUF tsen;
185 	memset(&tsen, 0, sizeof(RBUF));
186 	tsen.HUM.packetlength = sizeof(tsen.HUM) - 1;
187 	tsen.HUM.packettype = pTypeHUM;
188 	tsen.HUM.subtype = sTypeHUM1;
189 	tsen.HUM.battery_level = BatteryLevel;
190 	tsen.HUM.rssi = RssiLevel;
191 	tsen.HUM.id1 = (NodeID & 0xFF00) >> 8;
192 	tsen.HUM.id2 = NodeID & 0xFF;
193 	tsen.HUM.humidity = (BYTE)humidity;
194 	tsen.HUM.humidity_status = Get_Humidity_Level(tsen.HUM.humidity);
195 	sDecodeRXMessage(this, (const unsigned char*)& tsen.HUM, defaultname.c_str(), BatteryLevel);
196 }
197 
SendBaroSensor(const int NodeID,const int ChildID,const int BatteryLevel,const float pressure,const int forecast,const std::string & defaultname)198 void CDomoticzHardwareBase::SendBaroSensor(const int NodeID, const int ChildID, const int BatteryLevel, const float pressure, const int forecast, const std::string& defaultname)
199 {
200 	_tGeneralDevice gdevice;
201 	gdevice.subtype = sTypeBaro;
202 	gdevice.intval1 = (NodeID << 8) | ChildID;
203 	gdevice.intval2 = forecast;
204 	gdevice.floatval1 = pressure;
205 	sDecodeRXMessage(this, (const unsigned char*)& gdevice, defaultname.c_str(), BatteryLevel);
206 }
207 
SendTempHumSensor(const int NodeID,const int BatteryLevel,const float temperature,const int humidity,const std::string & defaultname,const int RssiLevel)208 void CDomoticzHardwareBase::SendTempHumSensor(const int NodeID, const int BatteryLevel, const float temperature, const int humidity, const std::string& defaultname, const int RssiLevel /* =12 */)
209 {
210 	RBUF tsen;
211 	memset(&tsen, 0, sizeof(RBUF));
212 	tsen.TEMP_HUM.packetlength = sizeof(tsen.TEMP_HUM) - 1;
213 	tsen.TEMP_HUM.packettype = pTypeTEMP_HUM;
214 	tsen.TEMP_HUM.subtype = sTypeTH5;
215 	tsen.TEMP_HUM.battery_level = BatteryLevel;
216 	tsen.TEMP_HUM.rssi = RssiLevel;
217 	tsen.TEMP_HUM.id1 = (NodeID & 0xFF00) >> 8;
218 	tsen.TEMP_HUM.id2 = NodeID & 0xFF;
219 
220 	tsen.TEMP_HUM.tempsign = (temperature >= 0) ? 0 : 1;
221 	int at10 = round(std::abs(temperature * 10.0f));
222 	tsen.TEMP_HUM.temperatureh = (BYTE)(at10 / 256);
223 	at10 -= (tsen.TEMP_HUM.temperatureh * 256);
224 	tsen.TEMP_HUM.temperaturel = (BYTE)(at10);
225 	tsen.TEMP_HUM.humidity = (BYTE)humidity;
226 	tsen.TEMP_HUM.humidity_status = Get_Humidity_Level(tsen.TEMP_HUM.humidity);
227 
228 	sDecodeRXMessage(this, (const unsigned char*)& tsen.TEMP_HUM, defaultname.c_str(), BatteryLevel);
229 }
230 
SendTempHumBaroSensor(const int NodeID,const int BatteryLevel,const float temperature,const int humidity,const float pressure,int forecast,const std::string & defaultname,const int RssiLevel)231 void CDomoticzHardwareBase::SendTempHumBaroSensor(const int NodeID, const int BatteryLevel, const float temperature, const int humidity, const float pressure, int forecast, const std::string& defaultname, const int RssiLevel /* =12 */)
232 {
233 	RBUF tsen;
234 	memset(&tsen, 0, sizeof(RBUF));
235 	tsen.TEMP_HUM_BARO.packetlength = sizeof(tsen.TEMP_HUM_BARO) - 1;
236 	tsen.TEMP_HUM_BARO.packettype = pTypeTEMP_HUM_BARO;
237 	tsen.TEMP_HUM_BARO.subtype = sTypeTHB1;
238 	tsen.TEMP_HUM_BARO.battery_level = BatteryLevel;
239 	tsen.TEMP_HUM_BARO.rssi = RssiLevel;
240 	tsen.TEMP_HUM_BARO.id1 = (NodeID & 0xFF00) >> 8;
241 	tsen.TEMP_HUM_BARO.id2 = NodeID & 0xFF;
242 
243 	tsen.TEMP_HUM_BARO.tempsign = (temperature >= 0) ? 0 : 1;
244 	int at10 = round(std::abs(temperature * 10.0f));
245 	tsen.TEMP_HUM_BARO.temperatureh = (BYTE)(at10 / 256);
246 	at10 -= (tsen.TEMP_HUM_BARO.temperatureh * 256);
247 	tsen.TEMP_HUM_BARO.temperaturel = (BYTE)(at10);
248 	tsen.TEMP_HUM_BARO.humidity = (BYTE)humidity;
249 	tsen.TEMP_HUM_BARO.humidity_status = Get_Humidity_Level(tsen.TEMP_HUM.humidity);
250 
251 	int ab10 = round(pressure);
252 	tsen.TEMP_HUM_BARO.baroh = (BYTE)(ab10 / 256);
253 	ab10 -= (tsen.TEMP_HUM_BARO.baroh * 256);
254 	tsen.TEMP_HUM_BARO.barol = (BYTE)(ab10);
255 
256 	tsen.TEMP_HUM_BARO.forecast = (BYTE)forecast;
257 
258 	sDecodeRXMessage(this, (const unsigned char*)& tsen.TEMP_HUM_BARO, defaultname.c_str(), BatteryLevel);
259 }
260 
SendTempHumBaroSensorFloat(const int NodeID,const int BatteryLevel,const float temperature,const int humidity,const float pressure,const uint8_t forecast,const std::string & defaultname,const int RssiLevel)261 void CDomoticzHardwareBase::SendTempHumBaroSensorFloat(const int NodeID, const int BatteryLevel, const float temperature, const int humidity, const float pressure, const uint8_t forecast, const std::string& defaultname, const int RssiLevel /* =12 */)
262 {
263 	RBUF tsen;
264 	memset(&tsen, 0, sizeof(RBUF));
265 	tsen.TEMP_HUM_BARO.packetlength = sizeof(tsen.TEMP_HUM_BARO) - 1;
266 	tsen.TEMP_HUM_BARO.packettype = pTypeTEMP_HUM_BARO;
267 	tsen.TEMP_HUM_BARO.subtype = sTypeTHBFloat;
268 	tsen.TEMP_HUM_BARO.battery_level = 9;
269 	tsen.TEMP_HUM_BARO.rssi = RssiLevel;
270 	tsen.TEMP_HUM_BARO.id1 = (NodeID & 0xFF00) >> 8;
271 	tsen.TEMP_HUM_BARO.id2 = NodeID & 0xFF;
272 
273 	tsen.TEMP_HUM_BARO.tempsign = (temperature >= 0) ? 0 : 1;
274 	int at10 = round(std::abs(temperature * 10.0f));
275 	tsen.TEMP_HUM_BARO.temperatureh = (BYTE)(at10 / 256);
276 	at10 -= (tsen.TEMP_HUM_BARO.temperatureh * 256);
277 	tsen.TEMP_HUM_BARO.temperaturel = (BYTE)(at10);
278 	tsen.TEMP_HUM_BARO.humidity = (BYTE)humidity;
279 	tsen.TEMP_HUM_BARO.humidity_status = Get_Humidity_Level(tsen.TEMP_HUM.humidity);
280 
281 	int ab10 = round(pressure * 10.0f);
282 	tsen.TEMP_HUM_BARO.baroh = (BYTE)(ab10 / 256);
283 	ab10 -= (tsen.TEMP_HUM_BARO.baroh * 256);
284 	tsen.TEMP_HUM_BARO.barol = (BYTE)(ab10);
285 	tsen.TEMP_HUM_BARO.forecast = forecast;
286 
287 	sDecodeRXMessage(this, (const unsigned char*)& tsen.TEMP_HUM_BARO, defaultname.c_str(), BatteryLevel);
288 }
289 
SendTempBaroSensor(const uint8_t NodeID,const int BatteryLevel,const float temperature,const float pressure,const std::string & defaultname)290 void CDomoticzHardwareBase::SendTempBaroSensor(const uint8_t NodeID, const int BatteryLevel, const float temperature, const float pressure, const std::string& defaultname)
291 {
292 	_tTempBaro tsensor;
293 	tsensor.id1 = NodeID;
294 	tsensor.temp = temperature;
295 	tsensor.baro = pressure;
296 	tsensor.altitude = 188;
297 
298 	//this is probably not good, need to take the rising/falling of the pressure into account?
299 	//any help would be welcome!
300 
301 	tsensor.forecast = baroForecastNoInfo;
302 	if (tsensor.baro < 1000)
303 		tsensor.forecast = baroForecastRain;
304 	else if (tsensor.baro < 1020)
305 		tsensor.forecast = baroForecastCloudy;
306 	else if (tsensor.baro < 1030)
307 		tsensor.forecast = baroForecastPartlyCloudy;
308 	else
309 		tsensor.forecast = baroForecastSunny;
310 	sDecodeRXMessage(this, (const unsigned char*)& tsensor, defaultname.c_str(), BatteryLevel);
311 }
312 
SendSetPointSensor(const uint8_t NodeID,const uint8_t ChildID,const unsigned char SensorID,const float Temp,const std::string & defaultname)313 void CDomoticzHardwareBase::SendSetPointSensor(const uint8_t NodeID, const uint8_t ChildID, const unsigned char SensorID, const float Temp, const std::string& defaultname)
314 {
315 	_tThermostat thermos;
316 	thermos.subtype = sTypeThermSetpoint;
317 	thermos.id1 = 0;
318 	thermos.id2 = NodeID;
319 	thermos.id3 = ChildID;
320 	thermos.id4 = SensorID;
321 	thermos.dunit = 1;
322 
323 	thermos.temp = Temp;
324 
325 	sDecodeRXMessage(this, (const unsigned char*)& thermos, defaultname.c_str(), -1);
326 }
327 
328 
SendDistanceSensor(const int NodeID,const int ChildID,const int BatteryLevel,const float distance,const std::string & defaultname)329 void CDomoticzHardwareBase::SendDistanceSensor(const int NodeID, const int ChildID, const int BatteryLevel, const float distance, const std::string& defaultname)
330 {
331 	_tGeneralDevice gdevice;
332 	gdevice.subtype = sTypeDistance;
333 	gdevice.intval1 = (NodeID << 8) | ChildID;
334 	gdevice.floatval1 = distance;
335 	sDecodeRXMessage(this, (const unsigned char*)& gdevice, defaultname.c_str(), BatteryLevel);
336 }
337 
SendTextSensor(const int NodeID,const int ChildID,const int BatteryLevel,const std::string & textMessage,const std::string & defaultname)338 void CDomoticzHardwareBase::SendTextSensor(const int NodeID, const int ChildID, const int BatteryLevel, const std::string& textMessage, const std::string& defaultname)
339 {
340 	_tGeneralDevice gdevice;
341 	gdevice.subtype = sTypeTextStatus;
342 	gdevice.intval1 = (NodeID << 8) | ChildID;
343 	std::string sstatus = textMessage;
344 	if (sstatus.size() > 63)
345 		sstatus = sstatus.substr(0, 63);
346 	strcpy(gdevice.text, sstatus.c_str());
347 	sDecodeRXMessage(this, (const unsigned char*)& gdevice, defaultname.c_str(), BatteryLevel);
348 }
349 
GetTextSensorText(const int NodeID,const int ChildID,bool & bExists)350 std::string CDomoticzHardwareBase::GetTextSensorText(const int NodeID, const int ChildID, bool& bExists)
351 {
352 	bExists = false;
353 	std::string ret = "";
354 
355 	std::vector<std::vector<std::string> > result;
356 
357 	char szTmp[30];
358 	sprintf(szTmp, "%08X", (NodeID << 8) | ChildID);
359 
360 	result = m_sql.safe_query("SELECT sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Type==%d) AND (Subtype==%d)",
361 		m_HwdID, szTmp, int(pTypeGeneral), int(sTypeTextStatus));
362 	if (!result.empty())
363 	{
364 		bExists = true;
365 		ret = result[0][0];
366 	}
367 	return ret;
368 }
369 
SendRainSensor(const int NodeID,const int BatteryLevel,const float RainCounter,const std::string & defaultname,const int RssiLevel)370 void CDomoticzHardwareBase::SendRainSensor(const int NodeID, const int BatteryLevel, const float RainCounter, const std::string& defaultname, const int RssiLevel /* =12 */)
371 {
372 	RBUF tsen;
373 	memset(&tsen, 0, sizeof(RBUF));
374 	tsen.RAIN.packetlength = sizeof(tsen.RAIN) - 1;
375 	tsen.RAIN.packettype = pTypeRAIN;
376 	tsen.RAIN.subtype = sTypeRAIN3;
377 	tsen.RAIN.battery_level = BatteryLevel;
378 	tsen.RAIN.rssi = RssiLevel;
379 	tsen.RAIN.id1 = (NodeID & 0xFF00) >> 8;
380 	tsen.RAIN.id2 = NodeID & 0xFF;
381 
382 	tsen.RAIN.rainrateh = 0;
383 	tsen.RAIN.rainratel = 0;
384 
385 	uint64_t tr10 = int((float(RainCounter) * 10.0f));
386 
387 	tsen.RAIN.raintotal1 = (BYTE)(tr10 / 65535);
388 	tr10 -= (tsen.RAIN.raintotal1 * 65535);
389 	tsen.RAIN.raintotal2 = (BYTE)(tr10 / 256);
390 	tr10 -= (tsen.RAIN.raintotal2 * 256);
391 	tsen.RAIN.raintotal3 = (BYTE)(tr10);
392 	sDecodeRXMessage(this, (const unsigned char*)& tsen.RAIN, defaultname.c_str(), BatteryLevel);
393 }
394 
SendRainSensorWU(const int NodeID,const int BatteryLevel,const float RainCounter,const float LastHour,const std::string & defaultname,const int RssiLevel)395 void CDomoticzHardwareBase::SendRainSensorWU(const int NodeID, const int BatteryLevel, const float RainCounter, const float LastHour, const std::string& defaultname, const int RssiLevel)
396 {
397 	RBUF tsen;
398 	memset(&tsen, 0, sizeof(RBUF));
399 	tsen.RAIN.packetlength = sizeof(tsen.RAIN) - 1;
400 	tsen.RAIN.packettype = pTypeRAIN;
401 	tsen.RAIN.subtype = sTypeRAINWU;
402 	tsen.RAIN.battery_level = 9;
403 	tsen.RAIN.rssi = 12;
404 	tsen.RAIN.id1 = 0;
405 	tsen.RAIN.id2 = 1;
406 
407 	tsen.RAIN.rainrateh = 0;
408 	tsen.RAIN.rainratel = 0;
409 
410 	if (LastHour != 0)
411 	{
412 		uint64_t at10 = int((float(LastHour) * 10.0f));
413 		tsen.RAIN.rainrateh = (BYTE)(at10 / 256);
414 		at10 -= (tsen.RAIN.rainrateh * 256);
415 		tsen.RAIN.rainratel = (BYTE)(at10);
416 	}
417 
418 	int tr10 = int((float(RainCounter) * 10.0f));
419 	tsen.RAIN.raintotal1 = 0;
420 	tsen.RAIN.raintotal2 = (BYTE)(tr10 / 256);
421 	tr10 -= (tsen.RAIN.raintotal2 * 256);
422 	tsen.RAIN.raintotal3 = (BYTE)(tr10);
423 
424 	sDecodeRXMessage(this, (const unsigned char*)& tsen.RAIN, defaultname.c_str(), BatteryLevel);
425 }
426 
SendRainRateSensor(const int NodeID,const int BatteryLevel,const float RainRate,const std::string & defaultname,const int RssiLevel)427 void CDomoticzHardwareBase::SendRainRateSensor(const int NodeID, const int BatteryLevel, const float RainRate, const std::string& defaultname, const int RssiLevel /* =12 */)
428 {
429 	RBUF tsen;
430 	memset(&tsen, 0, sizeof(RBUF));
431 	tsen.RAIN.packetlength = sizeof(tsen.RAIN) - 1;
432 	tsen.RAIN.packettype = pTypeRAIN;
433 	tsen.RAIN.subtype = sTypeRAINByRate;
434 	tsen.RAIN.battery_level = BatteryLevel;
435 	tsen.RAIN.rssi = RssiLevel;
436 	tsen.RAIN.id1 = (NodeID & 0xFF00) >> 8;
437 	tsen.RAIN.id2 = NodeID & 0xFF;
438 
439 	int at10 = round(std::abs(RainRate * 10000.0f));
440 	tsen.RAIN.rainrateh = (BYTE)(at10 / 256);
441 	at10 -= (tsen.RAIN.rainrateh * 256);
442 	tsen.RAIN.rainratel = (BYTE)(at10);
443 
444 	tsen.RAIN.raintotal1 = 0;
445 	tsen.RAIN.raintotal2 = 0;
446 	tsen.RAIN.raintotal3 = 0;
447 
448 	sDecodeRXMessage(this, (const unsigned char*)& tsen.RAIN, defaultname.c_str(), BatteryLevel);
449 }
450 
GetRainSensorValue(const int NodeID,bool & bExists)451 float CDomoticzHardwareBase::GetRainSensorValue(const int NodeID, bool& bExists)
452 {
453 	char szIdx[10];
454 	sprintf(szIdx, "%d", NodeID & 0xFFFF);
455 	int Unit = 0;
456 
457 	std::vector<std::vector<std::string> > results;
458 	results = m_sql.safe_query("SELECT ID,sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Unit == %d) AND (Type==%d) AND (Subtype==%d)", m_HwdID, szIdx, Unit, int(pTypeRAIN), int(sTypeRAIN3));
459 	if (results.size() < 1)
460 	{
461 		bExists = false;
462 		return 0.0f;
463 	}
464 	std::vector<std::string> splitresults;
465 	StringSplit(results[0][1], ";", splitresults);
466 	if (splitresults.size() != 2)
467 	{
468 		bExists = false;
469 		return 0.0f;
470 	}
471 	bExists = true;
472 	return (float)atof(splitresults[1].c_str());
473 }
474 
GetWindSensorValue(const int NodeID,int & WindDir,float & WindSpeed,float & WindGust,float & WindTemp,float & WindChill,bool bHaveWindTemp,bool & bExists)475 bool CDomoticzHardwareBase::GetWindSensorValue(const int NodeID, int& WindDir, float& WindSpeed, float& WindGust, float& WindTemp, float& WindChill, bool bHaveWindTemp, bool& bExists)
476 {
477 	char szIdx[10];
478 	sprintf(szIdx, "%d", NodeID & 0xFFFF);
479 	int Unit = 0;
480 
481 	std::vector<std::vector<std::string> > results;
482 	if (!bHaveWindTemp)
483 		results = m_sql.safe_query("SELECT ID,sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Unit == %d) AND (Type==%d) AND (Subtype==%d)", m_HwdID, szIdx, Unit, int(pTypeWIND), int(sTypeWINDNoTemp));
484 	else
485 		results = m_sql.safe_query("SELECT ID,sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Unit == %d) AND (Type==%d) AND (Subtype==%d)", m_HwdID, szIdx, Unit, int(pTypeWIND), int(sTypeWIND4));
486 	if (results.size() < 1)
487 	{
488 		bExists = false;
489 		return 0.0f;
490 	}
491 	std::vector<std::string> splitresults;
492 	StringSplit(results[0][1], ";", splitresults);
493 
494 	if (splitresults.size() != 6)
495 	{
496 		bExists = false;
497 		return 0.0f;
498 	}
499 	bExists = true;
500 	WindDir = (int)atof(splitresults[0].c_str());
501 	WindSpeed = (float)atof(splitresults[2].c_str());
502 	WindGust = (float)atof(splitresults[3].c_str());
503 	WindTemp = (float)atof(splitresults[4].c_str());
504 	WindChill = (float)atof(splitresults[5].c_str());
505 	return bExists;
506 }
507 
SendWattMeter(const uint8_t NodeID,const uint8_t ChildID,const int BatteryLevel,const float musage,const std::string & defaultname)508 void CDomoticzHardwareBase::SendWattMeter(const uint8_t NodeID, const uint8_t ChildID, const int BatteryLevel, const float musage, const std::string& defaultname)
509 {
510 	_tUsageMeter umeter;
511 	umeter.id1 = 0;
512 	umeter.id2 = 0;
513 	umeter.id3 = 0;
514 	umeter.id4 = NodeID;
515 	umeter.dunit = ChildID;
516 	umeter.fusage = musage;
517 	sDecodeRXMessage(this, (const unsigned char*)& umeter, defaultname.c_str(), BatteryLevel);
518 }
519 
520 //Obsolete, we should not call this anymore
521 //when all calls are removed, we should delete this function
SendKwhMeterOldWay(const int NodeID,const int ChildID,const int BatteryLevel,const double musage,const double mtotal,const std::string & defaultname)522 void CDomoticzHardwareBase::SendKwhMeterOldWay(const int NodeID, const int ChildID, const int BatteryLevel, const double musage, const double mtotal, const std::string& defaultname)
523 {
524 	SendKwhMeter(NodeID, ChildID, BatteryLevel, musage * 1000, mtotal, defaultname);
525 }
526 
SendKwhMeter(const int NodeID,const int ChildID,const int BatteryLevel,const double musage,const double mtotal,const std::string & defaultname)527 void CDomoticzHardwareBase::SendKwhMeter(const int NodeID, const int ChildID, const int BatteryLevel, const double musage, const double mtotal, const std::string& defaultname)
528 {
529 	_tGeneralDevice gdevice;
530 	gdevice.subtype = sTypeKwh;
531 	gdevice.intval1 = (NodeID << 8) | ChildID;
532 	gdevice.floatval1 = (float)musage;
533 	gdevice.floatval2 = (float)(mtotal * 1000.0);
534 	sDecodeRXMessage(this, (const unsigned char*)& gdevice, defaultname.c_str(), BatteryLevel);
535 }
536 
GetKwhMeter(const int NodeID,const int ChildID,bool & bExists)537 double CDomoticzHardwareBase::GetKwhMeter(const int NodeID, const int ChildID, bool& bExists)
538 {
539 	int dID = (NodeID << 8) | ChildID;
540 	char szTmp[30];
541 	sprintf(szTmp, "%08X", dID);
542 
543 	std::vector<std::vector<std::string> > result;
544 	result = m_sql.safe_query("SELECT ID FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Type==%d) AND (Subtype==%d)",
545 		m_HwdID, szTmp, int(pTypeGeneral), int(sTypeKwh));
546 	if (result.empty())
547 	{
548 		bExists = false;
549 		return 0;
550 	}
551 	result = m_sql.safe_query("SELECT MAX(Counter) FROM Meter_Calendar WHERE (DeviceRowID=='%q')", result[0][0].c_str());
552 	if (result.empty())
553 	{
554 		bExists = false;
555 		return 0.0f;
556 	}
557 	bExists = true;
558 	return (float)atof(result[0][0].c_str());
559 }
560 
SendMeterSensor(const int NodeID,const int ChildID,const int BatteryLevel,const float metervalue,const std::string & defaultname,const int RssiLevel)561 void CDomoticzHardwareBase::SendMeterSensor(const int NodeID, const int ChildID, const int BatteryLevel, const float metervalue, const std::string& defaultname, const int RssiLevel /* =12 */)
562 {
563 	unsigned long counter = (unsigned long)(metervalue * 1000.0f);
564 	RBUF tsen;
565 	memset(&tsen, 0, sizeof(RBUF));
566 	tsen.RFXMETER.packetlength = sizeof(tsen.RFXMETER) - 1;
567 	tsen.RFXMETER.packettype = pTypeRFXMeter;
568 	tsen.RFXMETER.subtype = sTypeRFXMeterCount;
569 	tsen.RFXMETER.rssi = RssiLevel;
570 	tsen.RFXMETER.id1 = (BYTE)NodeID;
571 	tsen.RFXMETER.id2 = (BYTE)ChildID;
572 
573 	tsen.RFXMETER.count1 = (BYTE)((counter & 0xFF000000) >> 24);
574 	tsen.RFXMETER.count2 = (BYTE)((counter & 0x00FF0000) >> 16);
575 	tsen.RFXMETER.count3 = (BYTE)((counter & 0x0000FF00) >> 8);
576 	tsen.RFXMETER.count4 = (BYTE)(counter & 0x000000FF);
577 	sDecodeRXMessage(this, (const unsigned char*)& tsen.RFXMETER, defaultname.c_str(), BatteryLevel);
578 }
579 
SendLuxSensor(const uint8_t NodeID,const uint8_t ChildID,const uint8_t BatteryLevel,const float Lux,const std::string & defaultname)580 void CDomoticzHardwareBase::SendLuxSensor(const uint8_t NodeID, const uint8_t ChildID, const uint8_t BatteryLevel, const float Lux, const std::string& defaultname)
581 {
582 	_tLightMeter lmeter;
583 	lmeter.id1 = 0;
584 	lmeter.id2 = 0;
585 	lmeter.id3 = 0;
586 	lmeter.id4 = NodeID;
587 	lmeter.dunit = ChildID;
588 	lmeter.fLux = Lux;
589 	lmeter.battery_level = BatteryLevel;
590 	sDecodeRXMessage(this, (const unsigned char*)& lmeter, defaultname.c_str(), BatteryLevel);
591 }
592 
SendAirQualitySensor(const uint8_t NodeID,const uint8_t ChildID,const int BatteryLevel,const int AirQuality,const std::string & defaultname)593 void CDomoticzHardwareBase::SendAirQualitySensor(const uint8_t NodeID, const uint8_t ChildID, const int BatteryLevel, const int AirQuality, const std::string& defaultname)
594 {
595 	_tAirQualityMeter meter;
596 	meter.len = sizeof(_tAirQualityMeter) - 1;
597 	meter.type = pTypeAirQuality;
598 	meter.subtype = sTypeVoltcraft;
599 	meter.airquality = AirQuality;
600 	meter.id1 = NodeID;
601 	meter.id2 = ChildID;
602 	sDecodeRXMessage(this, (const unsigned char*)& meter, defaultname.c_str(), BatteryLevel);
603 }
604 
SendUsageSensor(const uint8_t NodeID,const uint8_t ChildID,const int BatteryLevel,const float Usage,const std::string & defaultname)605 void CDomoticzHardwareBase::SendUsageSensor(const uint8_t NodeID, const uint8_t ChildID, const int BatteryLevel, const float Usage, const std::string& defaultname)
606 {
607 	_tUsageMeter umeter;
608 	umeter.id1 = 0;
609 	umeter.id2 = 0;
610 	umeter.id3 = 0;
611 	umeter.id4 = NodeID;
612 	umeter.dunit = ChildID;
613 	umeter.fusage = Usage;
614 	sDecodeRXMessage(this, (const unsigned char*)& umeter, defaultname.c_str(), BatteryLevel);
615 }
616 
SendSwitchIfNotExists(const int NodeID,const uint8_t ChildID,const int BatteryLevel,const bool bOn,const double Level,const std::string & defaultname)617 void CDomoticzHardwareBase::SendSwitchIfNotExists(const int NodeID, const uint8_t ChildID, const int BatteryLevel, const bool bOn, const double Level, const std::string& defaultname)
618 {
619 	//make device ID
620 	unsigned char ID1 = (unsigned char)((NodeID & 0xFF000000) >> 24);
621 	unsigned char ID2 = (unsigned char)((NodeID & 0xFF0000) >> 16);
622 	unsigned char ID3 = (unsigned char)((NodeID & 0xFF00) >> 8);
623 	unsigned char ID4 = (unsigned char)NodeID & 0xFF;
624 
625 	char szIdx[10];
626 	sprintf(szIdx, "%X%02X%02X%02X", ID1, ID2, ID3, ID4);
627 	std::vector<std::vector<std::string> > result;
628 	result = m_sql.safe_query("SELECT Name,nValue,sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Unit == %d) AND (Type==%d) AND (Subtype==%d)",
629 		m_HwdID, szIdx, ChildID, int(pTypeLighting2), int(sTypeAC));
630 	if (result.empty())
631 	{
632 		SendSwitch(NodeID, ChildID, BatteryLevel, bOn, Level, defaultname);
633 	}
634 }
635 
SendSwitchUnchecked(const int NodeID,const uint8_t ChildID,const int BatteryLevel,const bool bOn,const double Level,const std::string & defaultname,const int RssiLevel)636 void CDomoticzHardwareBase::SendSwitchUnchecked(const int NodeID, const uint8_t ChildID, const int BatteryLevel, const bool bOn, const double Level, const std::string& defaultname, const int RssiLevel /* =12 */)
637 {
638 	double rlevel = (16.0 / 100.0) * Level;
639 	uint8_t level = (uint8_t)(rlevel);
640 
641 	//make device ID
642 	unsigned char ID1 = (unsigned char)((NodeID & 0xFF000000) >> 24);
643 	unsigned char ID2 = (unsigned char)((NodeID & 0xFF0000) >> 16);
644 	unsigned char ID3 = (unsigned char)((NodeID & 0xFF00) >> 8);
645 	unsigned char ID4 = (unsigned char)NodeID & 0xFF;
646 
647 	//Send as Lighting 2
648 	tRBUF lcmd;
649 	memset(&lcmd, 0, sizeof(RBUF));
650 	lcmd.LIGHTING2.packetlength = sizeof(lcmd.LIGHTING2) - 1;
651 	lcmd.LIGHTING2.packettype = pTypeLighting2;
652 	lcmd.LIGHTING2.subtype = sTypeAC;
653 	lcmd.LIGHTING2.id1 = ID1;
654 	lcmd.LIGHTING2.id2 = ID2;
655 	lcmd.LIGHTING2.id3 = ID3;
656 	lcmd.LIGHTING2.id4 = ID4;
657 	lcmd.LIGHTING2.unitcode = ChildID;
658 	if (!bOn)
659 	{
660 		lcmd.LIGHTING2.cmnd = light2_sOff;
661 	}
662 	else
663 	{
664 		if (level != 0)
665 			lcmd.LIGHTING2.cmnd = light2_sSetLevel;
666 		else
667 			lcmd.LIGHTING2.cmnd = light2_sOn;
668 	}
669 	lcmd.LIGHTING2.level = level;
670 	lcmd.LIGHTING2.filler = 0;
671 	lcmd.LIGHTING2.rssi = RssiLevel;
672 	sDecodeRXMessage(this, (const unsigned char*)& lcmd.LIGHTING2, defaultname.c_str(), BatteryLevel);
673 }
674 
675 
SendSwitch(const int NodeID,const uint8_t ChildID,const int BatteryLevel,const bool bOn,const double Level,const std::string & defaultname,const int RssiLevel)676 void CDomoticzHardwareBase::SendSwitch(const int NodeID, const uint8_t ChildID, const int BatteryLevel, const bool bOn, const double Level, const std::string& defaultname, const int RssiLevel /* =12 */)
677 {
678 	double rlevel = (16.0 / 100.0) * Level;
679 	int level = int(rlevel);
680 
681 	//make device ID
682 	unsigned char ID1 = (unsigned char)((NodeID & 0xFF000000) >> 24);
683 	unsigned char ID2 = (unsigned char)((NodeID & 0xFF0000) >> 16);
684 	unsigned char ID3 = (unsigned char)((NodeID & 0xFF00) >> 8);
685 	unsigned char ID4 = (unsigned char)NodeID & 0xFF;
686 
687 	char szIdx[10];
688 	sprintf(szIdx, "%X%02X%02X%02X", ID1, ID2, ID3, ID4);
689 	std::vector<std::vector<std::string> > result;
690 	result = m_sql.safe_query("SELECT Name,nValue,sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Unit == %d) AND (Type==%d) AND (Subtype==%d)",
691 		m_HwdID, szIdx, ChildID, int(pTypeLighting2), int(sTypeAC));
692 	if (!result.empty())
693 	{
694 		//check if we have a change, if not do not update it
695 		int nvalue = atoi(result[0][1].c_str());
696 		if ((!bOn) && (nvalue == light2_sOff))
697 			return;
698 		if ((bOn && (nvalue != light2_sOff)))
699 		{
700 			//Check Level
701 			int slevel = atoi(result[0][2].c_str());
702 			if (slevel == level)
703 				return;
704 		}
705 	}
706 	SendSwitchUnchecked(NodeID, ChildID, BatteryLevel, bOn, Level, defaultname, RssiLevel);
707 }
708 
SendBlindSensor(const uint8_t NodeID,const uint8_t ChildID,const int BatteryLevel,const uint8_t Command,const std::string & defaultname,const int RssiLevel)709 void CDomoticzHardwareBase::SendBlindSensor(const uint8_t NodeID, const uint8_t ChildID, const int BatteryLevel, const uint8_t Command, const std::string& defaultname, const int RssiLevel /* =12 */)
710 {
711 	//Send as Blinds
712 	tRBUF lcmd;
713 	memset(&lcmd, 0, sizeof(RBUF));
714 	lcmd.BLINDS1.packetlength = sizeof(lcmd.LIGHTING2) - 1;
715 	lcmd.BLINDS1.packettype = pTypeBlinds;
716 	lcmd.BLINDS1.subtype = sTypeBlindsT0;
717 	lcmd.BLINDS1.id1 = 0;
718 	lcmd.BLINDS1.id2 = 0;
719 	lcmd.BLINDS1.id3 = NodeID;
720 	lcmd.BLINDS1.id4 = 0;
721 	lcmd.BLINDS1.unitcode = ChildID;
722 	lcmd.BLINDS1.cmnd = Command;
723 	lcmd.BLINDS1.filler = 0;
724 	lcmd.BLINDS1.rssi = RssiLevel;
725 	sDecodeRXMessage(this, (const unsigned char*)& lcmd.BLINDS1, defaultname.c_str(), BatteryLevel);
726 }
727 
SendRGBWSwitch(const int NodeID,const uint8_t ChildID,const int BatteryLevel,const int Level,const bool bIsRGBW,const std::string & defaultname)728 void CDomoticzHardwareBase::SendRGBWSwitch(const int NodeID, const uint8_t ChildID, const int BatteryLevel, const int Level, const bool bIsRGBW, const std::string& defaultname)
729 {
730 	int level = int(Level);
731 	uint8_t subType = (bIsRGBW == true) ? sTypeColor_RGB_W : sTypeColor_RGB;
732 	if (defaultname == "LIVCOL")
733 		subType = sTypeColor_LivCol;
734 	//Send as ColorSwitch
735 	_tColorSwitch lcmd;
736 	lcmd.id = NodeID;
737 	lcmd.subtype = subType;
738 	if (level == 0)
739 		lcmd.command = Color_LedOff;
740 	else
741 		lcmd.command = Color_LedOn;
742 	lcmd.dunit = ChildID;
743 	lcmd.value = (uint32_t)level;
744 	sDecodeRXMessage(this, (const unsigned char*)& lcmd, defaultname.c_str(), BatteryLevel);
745 }
746 
SendVoltageSensor(const int NodeID,const uint32_t ChildID,const int BatteryLevel,const float Volt,const std::string & defaultname)747 void CDomoticzHardwareBase::SendVoltageSensor(const int NodeID, const uint32_t ChildID, const int BatteryLevel, const float Volt, const std::string& defaultname)
748 {
749 	_tGeneralDevice gDevice;
750 	gDevice.subtype = sTypeVoltage;
751 	gDevice.id = ChildID;
752 	gDevice.intval1 = (NodeID << 8) | ChildID;
753 	gDevice.floatval1 = Volt;
754 	sDecodeRXMessage(this, (const unsigned char*)& gDevice, defaultname.c_str(), BatteryLevel);
755 }
756 
SendCurrentSensor(const int NodeID,const int BatteryLevel,const float Current1,const float Current2,const float Current3,const std::string & defaultname,const int RssiLevel)757 void CDomoticzHardwareBase::SendCurrentSensor(const int NodeID, const int BatteryLevel, const float Current1, const float Current2, const float Current3, const std::string& defaultname, const int RssiLevel /* =12 */)
758 {
759 	tRBUF tsen;
760 	memset(&tsen, 0, sizeof(RBUF));
761 	tsen.CURRENT.packetlength = sizeof(tsen.CURRENT) - 1;
762 	tsen.CURRENT.packettype = pTypeCURRENT;
763 	tsen.CURRENT.subtype = sTypeELEC1;
764 	tsen.CURRENT.rssi = RssiLevel;
765 	tsen.CURRENT.id1 = (NodeID & 0xFF00) >> 8;
766 	tsen.CURRENT.id2 = NodeID & 0xFF;
767 	tsen.CURRENT.battery_level = BatteryLevel;
768 
769 	int at10 = round(std::abs(Current1 * 10.0f));
770 	tsen.CURRENT.ch1h = (BYTE)(at10 / 256);
771 	at10 -= (tsen.TEMP.temperatureh * 256);
772 	tsen.CURRENT.ch1l = (BYTE)(at10);
773 
774 	at10 = round(std::abs(Current2 * 10.0f));
775 	tsen.CURRENT.ch2h = (BYTE)(at10 / 256);
776 	at10 -= (tsen.TEMP.temperatureh * 256);
777 	tsen.CURRENT.ch2l = (BYTE)(at10);
778 
779 	at10 = round(std::abs(Current3 * 10.0f));
780 	tsen.CURRENT.ch3h = (BYTE)(at10 / 256);
781 	at10 -= (tsen.TEMP.temperatureh * 256);
782 	tsen.CURRENT.ch3l = (BYTE)(at10);
783 
784 	sDecodeRXMessage(this, (const unsigned char*)& tsen.CURRENT, defaultname.c_str(), BatteryLevel);
785 }
786 
SendPercentageSensor(const int NodeID,const uint8_t ChildID,const int BatteryLevel,const float Percentage,const std::string & defaultname)787 void CDomoticzHardwareBase::SendPercentageSensor(const int NodeID, const uint8_t ChildID, const int BatteryLevel, const float Percentage, const std::string& defaultname)
788 {
789 	_tGeneralDevice gDevice;
790 	gDevice.subtype = sTypePercentage;
791 	gDevice.id = ChildID;
792 	gDevice.intval1 = NodeID;
793 	gDevice.floatval1 = Percentage;
794 	sDecodeRXMessage(this, (const unsigned char*)& gDevice, defaultname.c_str(), BatteryLevel);
795 }
796 
CheckPercentageSensorExists(const int NodeID,const int)797 bool CDomoticzHardwareBase::CheckPercentageSensorExists(const int NodeID, const int /*ChildID*/)
798 {
799 	std::vector<std::vector<std::string> > result;
800 	char szTmp[30];
801 	sprintf(szTmp, "%08X", (unsigned int)NodeID);
802 	result = m_sql.safe_query("SELECT Name FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Type==%d) AND (Subtype==%d)",
803 		m_HwdID, szTmp, int(pTypeGeneral), int(sTypePercentage));
804 	return (!result.empty());
805 }
806 
SendWaterflowSensor(const int NodeID,const uint8_t ChildID,const int BatteryLevel,const float LPM,const std::string & defaultname)807 void CDomoticzHardwareBase::SendWaterflowSensor(const int NodeID, const uint8_t ChildID, const int BatteryLevel, const float LPM, const std::string& defaultname)
808 {
809 	_tGeneralDevice gDevice;
810 	gDevice.subtype = sTypeWaterflow;
811 	gDevice.id = ChildID;
812 	gDevice.intval1 = (NodeID << 8) | ChildID;
813 	gDevice.floatval1 = LPM;
814 	sDecodeRXMessage(this, (const unsigned char*)& gDevice, defaultname.c_str(), BatteryLevel);
815 }
816 
SendVisibilitySensor(const int NodeID,const int ChildID,const int BatteryLevel,const float Visibility,const std::string & defaultname)817 void CDomoticzHardwareBase::SendVisibilitySensor(const int NodeID, const int ChildID, const int BatteryLevel, const float Visibility, const std::string& defaultname)
818 {
819 	_tGeneralDevice gDevice;
820 	gDevice.subtype = sTypeVisibility;
821 	gDevice.id = ChildID;
822 	gDevice.intval1 = (NodeID << 8) | ChildID;
823 	gDevice.floatval1 = Visibility;
824 	sDecodeRXMessage(this, (const unsigned char*)& gDevice, defaultname.c_str(), BatteryLevel);
825 }
826 
SendCustomSensor(const int NodeID,const uint8_t ChildID,const int BatteryLevel,const float CustomValue,const std::string & defaultname,const std::string & defaultLabel)827 void CDomoticzHardwareBase::SendCustomSensor(const int NodeID, const uint8_t ChildID, const int BatteryLevel, const float CustomValue, const std::string& defaultname, const std::string& defaultLabel)
828 {
829 
830 	_tGeneralDevice gDevice;
831 	gDevice.subtype = sTypeCustom;
832 	gDevice.id = ChildID;
833 	gDevice.intval1 = (NodeID << 8) | ChildID;
834 	gDevice.floatval1 = CustomValue;
835 
836 	char szTmp[9];
837 	sprintf(szTmp, "%08X", gDevice.intval1);
838 	std::vector<std::vector<std::string> > result;
839 	result = m_sql.safe_query("SELECT Name FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Type==%d) AND (Subtype==%d)",
840 		m_HwdID, szTmp, int(pTypeGeneral), int(sTypeCustom));
841 	bool bDoesExists = !result.empty();
842 
843 	if (bDoesExists)
844 		sDecodeRXMessage(this, (const unsigned char*)& gDevice, defaultname.c_str(), BatteryLevel);
845 	else
846 	{
847 		m_mainworker.PushAndWaitRxMessage(this, (const unsigned char*)& gDevice, defaultname.c_str(), BatteryLevel);
848 		//Set the Label
849 		std::string soptions = "1;" + defaultLabel;
850 		m_sql.safe_query("UPDATE DeviceStatus SET Options='%q' WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Type==%d) AND (Subtype==%d)",
851 			soptions.c_str(), m_HwdID, szTmp, int(pTypeGeneral), int(sTypeCustom));
852 	}
853 }
854 
855 //wind direction is in steps of 22.5 degrees (360/16)
SendWind(const int NodeID,const int BatteryLevel,const int WindDir,const float WindSpeed,const float WindGust,const float WindTemp,const float WindChill,const bool bHaveWindTemp,const bool bHaveWindChill,const std::string & defaultname,const int RssiLevel)856 void CDomoticzHardwareBase::SendWind(const int NodeID, const int BatteryLevel, const int WindDir, const float WindSpeed, const float WindGust, const float WindTemp, const float WindChill, const bool bHaveWindTemp, const bool bHaveWindChill, const std::string& defaultname, const int RssiLevel /* =12 */)
857 {
858 	RBUF tsen;
859 	memset(&tsen, 0, sizeof(RBUF));
860 	tsen.WIND.packetlength = sizeof(tsen.WIND) - 1;
861 	tsen.WIND.packettype = pTypeWIND;
862 
863 	if ((!bHaveWindTemp) && (!bHaveWindChill))
864 		tsen.WIND.subtype = sTypeWINDNoTempNoChill;
865 	else if (!bHaveWindTemp)
866 		tsen.WIND.subtype = sTypeWINDNoTemp;
867 	else
868 		tsen.WIND.subtype = sTypeWIND4;
869 
870 	tsen.WIND.battery_level = BatteryLevel;
871 	tsen.WIND.rssi = RssiLevel;
872 	tsen.WIND.id1 = (NodeID & 0xFF00) >> 8;
873 	tsen.WIND.id2 = NodeID & 0xFF;
874 
875 	int aw = WindDir;
876 	tsen.WIND.directionh = (BYTE)(aw / 256);
877 	aw -= (tsen.WIND.directionh * 256);
878 	tsen.WIND.directionl = (BYTE)(aw);
879 
880 	int sw = round(WindSpeed * 10.0f);
881 	tsen.WIND.av_speedh = (BYTE)(sw / 256);
882 	sw -= (tsen.WIND.av_speedh * 256);
883 	tsen.WIND.av_speedl = (BYTE)(sw);
884 
885 	int gw = round(WindGust * 10.0f);
886 	tsen.WIND.gusth = (BYTE)(gw / 256);
887 	gw -= (tsen.WIND.gusth * 256);
888 	tsen.WIND.gustl = (BYTE)(gw);
889 
890 	if (!bHaveWindTemp)
891 	{
892 		//No temp, only chill
893 		tsen.WIND.tempsign = (WindChill >= 0) ? 0 : 1;
894 		tsen.WIND.chillsign = (WindChill >= 0) ? 0 : 1;
895 		int at10 = round(std::abs(WindChill * 10.0f));
896 		tsen.WIND.temperatureh = (BYTE)(at10 / 256);
897 		tsen.WIND.chillh = (BYTE)(at10 / 256);
898 		at10 -= (tsen.WIND.chillh * 256);
899 		tsen.WIND.temperaturel = (BYTE)(at10);
900 		tsen.WIND.chilll = (BYTE)(at10);
901 	}
902 	else
903 	{
904 		//temp+chill
905 		tsen.WIND.tempsign = (WindTemp >= 0) ? 0 : 1;
906 		int at10 = round(std::abs(WindTemp * 10.0f));
907 		tsen.WIND.temperatureh = (BYTE)(at10 / 256);
908 		at10 -= (tsen.WIND.temperatureh * 256);
909 		tsen.WIND.temperaturel = (BYTE)(at10);
910 
911 		tsen.WIND.chillsign = (WindChill >= 0) ? 0 : 1;
912 		at10 = round(std::abs(WindChill * 10.0f));
913 		tsen.WIND.chillh = (BYTE)(at10 / 256);
914 		at10 -= (tsen.WIND.chillh * 256);
915 		tsen.WIND.chilll = (BYTE)(at10);
916 	}
917 
918 	sDecodeRXMessage(this, (const unsigned char*)& tsen.WIND, defaultname.c_str(), BatteryLevel);
919 }
920 
SendPressureSensor(const int NodeID,const int ChildID,const int BatteryLevel,const float pressure,const std::string & defaultname)921 void CDomoticzHardwareBase::SendPressureSensor(const int NodeID, const int ChildID, const int BatteryLevel, const float pressure, const std::string& defaultname)
922 {
923 	_tGeneralDevice gdevice;
924 	gdevice.subtype = sTypePressure;
925 	gdevice.intval1 = (NodeID << 8) | ChildID;
926 	gdevice.floatval1 = pressure;
927 	sDecodeRXMessage(this, (const unsigned char*)& gdevice, defaultname.c_str(), BatteryLevel);
928 }
929 
SendSolarRadiationSensor(const unsigned char NodeID,const int BatteryLevel,const float radiation,const std::string & defaultname)930 void CDomoticzHardwareBase::SendSolarRadiationSensor(const unsigned char NodeID, const int BatteryLevel, const float radiation, const std::string& defaultname)
931 {
932 	_tGeneralDevice gdevice;
933 	gdevice.subtype = sTypeSolarRadiation;
934 	gdevice.id = NodeID;
935 	gdevice.floatval1 = radiation;
936 	sDecodeRXMessage(this, (const unsigned char*)& gdevice, defaultname.c_str(), BatteryLevel);
937 }
938 
SendSoundSensor(const int NodeID,const int BatteryLevel,const int sLevel,const std::string & defaultname)939 void CDomoticzHardwareBase::SendSoundSensor(const int NodeID, const int BatteryLevel, const int sLevel, const std::string& defaultname)
940 {
941 	_tGeneralDevice gDevice;
942 	gDevice.subtype = sTypeSoundLevel;
943 	gDevice.id = 1;
944 	gDevice.intval1 = NodeID;
945 	gDevice.intval2 = sLevel;
946 	sDecodeRXMessage(this, (const unsigned char*)& gDevice, defaultname.c_str(), BatteryLevel);
947 }
948 
SendAlertSensor(const int NodeID,const int BatteryLevel,const int alertLevel,const std::string & message,const std::string & defaultname)949 void CDomoticzHardwareBase::SendAlertSensor(const int NodeID, const int BatteryLevel, const int alertLevel, const std::string& message, const std::string& defaultname)
950 {
951 	_tGeneralDevice gDevice;
952 	gDevice.subtype = sTypeAlert;
953 	gDevice.id = (unsigned char)NodeID;
954 	gDevice.intval1 = alertLevel;
955 	sprintf(gDevice.text, "%.63s", message.c_str());
956 	sDecodeRXMessage(this, (const unsigned char*)& gDevice, defaultname.c_str(), BatteryLevel);
957 }
958 
SendGeneralSwitch(const int NodeID,const int ChildID,const int BatteryLevel,const uint8_t SwitchState,const uint8_t Level,const std::string & defaultname,const int RssiLevel)959 void CDomoticzHardwareBase::SendGeneralSwitch(const int NodeID, const int ChildID, const int BatteryLevel, const uint8_t SwitchState, const uint8_t Level, const std::string& defaultname, const int RssiLevel)
960 {
961 	_tGeneralSwitch gSwitch;
962 	gSwitch.id = NodeID;
963 	gSwitch.unitcode = ChildID;
964 	gSwitch.cmnd = SwitchState;
965 	gSwitch.level = Level;
966 	gSwitch.rssi = (uint8_t)RssiLevel;
967 	sDecodeRXMessage(this, (const unsigned char*)& gSwitch, defaultname.c_str(), BatteryLevel);
968 }
969 
SendMoistureSensor(const int NodeID,const int BatteryLevel,const int mLevel,const std::string & defaultname)970 void CDomoticzHardwareBase::SendMoistureSensor(const int NodeID, const int BatteryLevel, const int mLevel, const std::string& defaultname)
971 {
972 	_tGeneralDevice gDevice;
973 	gDevice.subtype = sTypeSoilMoisture;
974 	gDevice.id = 1;
975 	gDevice.intval1 = NodeID;
976 	gDevice.intval2 = mLevel;
977 	sDecodeRXMessage(this, (const unsigned char*)& gDevice, defaultname.c_str(), BatteryLevel);
978 }
979 
SendUVSensor(const int NodeID,const int ChildID,const int BatteryLevel,const float UVI,const std::string & defaultname,const int RssiLevel)980 void CDomoticzHardwareBase::SendUVSensor(const int NodeID, const int ChildID, const int BatteryLevel, const float UVI, const std::string& defaultname, const int RssiLevel /* =12 */)
981 {
982 	RBUF tsen;
983 	memset(&tsen, 0, sizeof(RBUF));
984 	tsen.UV.packetlength = sizeof(tsen.UV) - 1;
985 	tsen.UV.packettype = pTypeUV;
986 	tsen.UV.subtype = sTypeUV1;
987 	tsen.UV.battery_level = BatteryLevel;
988 	tsen.UV.rssi = RssiLevel;
989 	tsen.UV.id1 = (unsigned char)NodeID;
990 	tsen.UV.id2 = (unsigned char)ChildID;
991 
992 	tsen.UV.uv = (BYTE)round(UVI * 10);
993 	sDecodeRXMessage(this, (const unsigned char*)& tsen.UV, defaultname.c_str(), BatteryLevel);
994 }
995 
SendZWaveAlarmSensor(const int NodeID,const uint8_t InstanceID,const int BatteryLevel,const uint8_t aType,const int aValue,const std::string & alarmLabel,const std::string & defaultname)996 void CDomoticzHardwareBase::SendZWaveAlarmSensor(const int NodeID, const uint8_t InstanceID, const int BatteryLevel, const uint8_t aType, const int aValue, const std::string& alarmLabel, const std::string& defaultname)
997 {
998 	uint8_t ID1 = 0;
999 	uint8_t ID2 = (unsigned char)((NodeID & 0xFF00) >> 8);
1000 	uint8_t ID3 = (unsigned char)NodeID & 0xFF;
1001 	uint8_t ID4 = InstanceID;
1002 
1003 	unsigned long lID = (ID1 << 24) + (ID2 << 16) + (ID3 << 8) + ID4;
1004 
1005 	_tGeneralDevice gDevice;
1006 	gDevice.subtype = sTypeZWaveAlarm;
1007 	gDevice.id = aType;
1008 	gDevice.intval1 = (int)(lID);
1009 	gDevice.intval2 = aValue;
1010 
1011 	int maxChars = (alarmLabel.size() < sizeof(_tGeneralDevice::text) - 1) ? alarmLabel.size() : sizeof(_tGeneralDevice::text) - 1;
1012 	strncpy(gDevice.text, alarmLabel.c_str(), maxChars);
1013 	gDevice.text[maxChars] = 0;
1014 
1015 	sDecodeRXMessage(this, (const unsigned char*)& gDevice, defaultname.c_str(), BatteryLevel);
1016 }
1017 
SendFanSensor(const int Idx,const int BatteryLevel,const int FanSpeed,const std::string & defaultname)1018 void CDomoticzHardwareBase::SendFanSensor(const int Idx, const int BatteryLevel, const int FanSpeed, const std::string& defaultname)
1019 {
1020 	_tGeneralDevice gDevice;
1021 	gDevice.subtype = sTypeFan;
1022 	gDevice.id = 1;
1023 	gDevice.intval1 = Idx;
1024 	gDevice.intval2 = FanSpeed;
1025 	sDecodeRXMessage(this, (const unsigned char*)& gDevice, defaultname.c_str(), BatteryLevel);
1026 }
1027