1 #include "stdafx.h"
2 #include "EnOceanESP3.h"
3 #include "../main/Logger.h"
4 #include "../main/Helper.h"
5 #include "../main/RFXtrx.h"
6 #include "../main/SQLHelper.h"
7 
8 #include <string>
9 #include <algorithm>
10 #include <iostream>
11 #include <boost/bind.hpp>
12 #include "hardwaretypes.h"
13 #include "../main/localtime_r.h"
14 
15 #include <boost/exception/diagnostic_information.hpp>
16 #include <cmath>
17 #include <ctime>
18 
19 #if _DEBUG
20 	#define ENOCEAN_BUTTON_DEBUG
21 #endif
22 
23 #define ENABLE_LOGGING
24 
25 #define ENOCEAN_RETRY_DELAY 30
26 
27 //Write/Read has to be done in sync with ESP3
28 
29 #define ESP3_SYNC 0x55
30 #define ESP3_HEADER_LENGTH 0x4
31 
32 #define round(a) ( int ) ( a + .5 )
33 
34 extern const char* Get_EnoceanManufacturer(unsigned long ID);
35 extern const char* Get_Enocean4BSType(const int Org, const int Func, const int Type);
36 
37 // the following lines are taken from EO300I API header file
38 
39 //polynomial G(x) = x8 + x2 + x1 + x0 is used to generate the CRC8 table
40 const unsigned char crc8table[256] = {
41 	0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
42 	0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
43 	0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
44 	0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
45 	0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5,
46 	0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
47 	0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85,
48 	0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
49 	0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
50 	0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
51 	0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2,
52 	0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
53 	0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32,
54 	0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
55 	0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
56 	0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
57 	0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c,
58 	0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
59 	0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
60 	0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
61 	0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
62 	0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
63 	0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c,
64 	0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
65 	0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b,
66 	0x76, 0x71, 0x78, 0x7f, 0x6A, 0x6d, 0x64, 0x63,
67 	0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
68 	0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
69 	0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb,
70 	0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8D, 0x84, 0x83,
71 	0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb,
72 	0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3
73 };
74 
75 #define proc_crc8(crc, data) (crc8table[crc ^ data])
76 
77 #define SER_SYNCH_CODE 0x55
78 #define SER_HEADER_NR_BYTES 0x04
79 
80 //! Packet structure (ESP3)
81 typedef struct
82 {
83 	// Amount of raw data bytes to be received. The most significant byte is sent/received first
84 	unsigned short u16DataLength;
85 	// Amount of optional data bytes to be received
86 	unsigned char u8OptionLength;
87 	// Packe type code
88 	unsigned char u8Type;
89 	// Data buffer: raw data + optional bytes
90 	unsigned char *u8DataBuffer;
91 } PACKET_SERIAL_TYPE;
92 
93 //! Packet type (ESP3)
94 typedef enum
95 {
96 	PACKET_RESERVED 			= 0x00,	//! Reserved
97 	PACKET_RADIO 				= 0x01,	//! Radio telegram
98 	PACKET_RESPONSE				= 0x02,	//! Response to any packet
99 	PACKET_RADIO_SUB_TEL		= 0x03,	//! Radio sub telegram (EnOcean internal function )
100 	PACKET_EVENT 				= 0x04,	//! Event message
101 	PACKET_COMMON_COMMAND 		= 0x05,	//! Common command
102 	PACKET_SMART_ACK_COMMAND	= 0x06,	//! Smart Ack command
103 	PACKET_REMOTE_MAN_COMMAND	= 0x07,	//! Remote management command
104 	PACKET_PRODUCTION_COMMAND	= 0x08,	//! Production command
105 	PACKET_RADIO_MESSAGE		= 0x09,	//! Radio message (chained radio telegrams)
106 	PACKET_RADIO_ADVANCED		= 0x0a  //! Advanced Protocol radio telegram
107 
108 } PACKET_TYPE;
109 
110 //! Response type
111 typedef enum
112 {
113 	RET_OK 					= 0x00, //! OK ... command is understood and triggered
114 	RET_ERROR 				= 0x01, //! There is an error occured
115 	RET_NOT_SUPPORTED 		= 0x02, //! The functionality is not supported by that implementation
116 	RET_WRONG_PARAM 		= 0x03, //! There was a wrong parameter in the command
117 	RET_OPERATION_DENIED 	= 0x04, //! Example: memory access denied (code-protected)
118 	RET_USER				= 0x80	//! Return codes greater than 0x80 are used for commands with special return information, not commonly useable.
119 } RESPONSE_TYPE;
120 
121 //! Common command enum
122 typedef enum
123 {
124 	CO_WR_SLEEP			= 1,	//! Order to enter in energy saving mode
125 	CO_WR_RESET			= 2,	//! Order to reset the device
126 	CO_RD_VERSION		= 3,	//! Read the device (SW) version / (HW) version, chip ID etc.
127 	CO_RD_SYS_LOG		= 4,	//! Read system log from device databank
128 	CO_WR_SYS_LOG		= 5,	//! Reset System log from device databank
129 	CO_WR_BIST			= 6,	//! Perform Flash BIST operation
130 	CO_WR_IDBASE		= 7,	//! Write ID range base number
131 	CO_RD_IDBASE		= 8,	//! Read ID range base number
132 	CO_WR_REPEATER		= 9,	//! Write Repeater Level off,1,2
133 	CO_RD_REPEATER		= 10,	//! Read Repeater Level off,1,2
134 	CO_WR_FILTER_ADD	= 11,	//! Add filter to filter list
135 	CO_WR_FILTER_DEL	= 12,	//! Delete filter from filter list
136 	CO_WR_FILTER_DEL_ALL= 13,	//! Delete filters
137 	CO_WR_FILTER_ENABLE	= 14,	//! Enable/Disable supplied filters
138 	CO_RD_FILTER		= 15,	//! Read supplied filters
139 	CO_WR_WAIT_MATURITY	= 16,	//! Waiting till end of maturity time before received radio telegrams will transmitted
140 	CO_WR_SUBTEL		= 17,	//! Enable/Disable transmitting additional subtelegram info
141 	CO_WR_MEM			= 18,	//! Write x bytes of the Flash, XRAM, RAM0 ….
142 	CO_RD_MEM			= 19,	//! Read x bytes of the Flash, XRAM, RAM0 ….
143 	CO_RD_MEM_ADDRESS	= 20,	//! Feedback about the used address and length of the config area and the Smart Ack Table
144 	CO_RD_SECURITY		= 21,	//! Read security informations (level, keys)
145 	CO_WR_SECURITY		= 22,	//! Write security informations (level, keys)
146 } COMMON_COMMAND_TYPE;
147 
148 typedef enum {
149 	RORG_ST = 0x30, //Secure telegram
150 	RORG_ST_WE = 0x31, //Secure telegram with encapsulation
151 	RORG_STT_FW = 0x35, //Secure Teach-In telegram for switch
152 	RORG_4BS = 0xA5,
153 	RORG_ADT = 0xA6,
154 	RORG_SM_REC = 0xA7,
155 	RORG_GP_SD = 0xB3, //Generic Profiles selective data
156 	RORG_SM_LRN_REQ = 0xC6,
157 	RORG_SM_LRN_ANS = 0xC7,
158 	RORG_SM_ACK_SGNL = 0xD0, //Smart Acknowledge Signal telegram
159 	RORG_MSC = 0xD1, // Manufacturer Specific Communicatio
160 	RORG_VLD = 0xD2, // Variable length data telegram
161 	RORG_UTI = 0xD4, //Universal Teach-In EEP based
162 	RORG_1BS = 0xD5,
163 	RORG_RPS = 0xF6,
164 	RORG_SYS_EX = 0xC5,
165 } ESP3_RORG;
166 
167 //! Function return codes
168 typedef enum
169 {
170 	//! <b>0</b> - Action performed. No problem detected
171 	OK=0,
172 	//! <b>1</b> - Action couldn't be carried out within a certain time.
173 	TIME_OUT,
174 	//! <b>2</b> - The write/erase/verify process failed, the flash page seems to be corrupted
175 	FLASH_HW_ERROR,
176 	//! <b>3</b> - A new UART/SPI byte received
177 	NEW_RX_BYTE,
178 	//! <b>4</b> - No new UART/SPI byte received
179 	NO_RX_BYTE,
180 	//! <b>5</b> - New telegram received
181 	NEW_RX_TEL,
182 	//! <b>6</b> - No new telegram received
183 	NO_RX_TEL,
184 	//! <b>7</b> - Checksum not valid
185 	NOT_VALID_CHKSUM,
186 	//! <b>8</b> - Telegram not valid
187 	NOT_VALID_TEL,
188 	//! <b>9</b> - Buffer full, no space in Tx or Rx buffer
189 	BUFF_FULL,
190 	//! <b>10</b> - Address is out of memory
191 	ADDR_OUT_OF_MEM,
192 	//! <b>11</b> - Invalid function parameter
193 	NOT_VALID_PARAM,
194 	//! <b>12</b> - Built in self test failed
195 	BIST_FAILED,
196 	//! <b>13</b> - Before entering power down, the short term timer had timed out.
197 	ST_TIMEOUT_BEFORE_SLEEP,
198 	//! <b>14</b> - Maximum number of filters reached, no more filter possible
199 	MAX_FILTER_REACHED,
200 	//! <b>15</b> - Filter to delete not found
201 	FILTER_NOT_FOUND,
202 	//! <b>16</b> - BaseID out of range
203 	BASEID_OUT_OF_RANGE,
204 	//! <b>17</b> - BaseID was changed 10 times, no more changes are allowed
205 	BASEID_MAX_REACHED,
206 	//! <b>18</b> - XTAL is not stable
207 	XTAL_NOT_STABLE,
208 	//! <b>19</b> - No telegram for transmission in queue
209 	NO_TX_TEL,
210 	//!	<b>20</b> - Waiting before sending broadcast message
211 	TELEGRAM_WAIT,
212 	//!	<b>21</b> - Generic out of range return code
213 	OUT_OF_RANGE,
214 	//!	<b>22</b> - Function was not executed due to sending lock
215 	LOCK_SET,
216 	//! <b>23</b> - New telegram transmitted
217 	NEW_TX_TEL
218 } RETURN_TYPE;
219 // end of lines from EO300I API header file
220 
221 /**
222  * @defgroup bitmasks Bitmasks for various fields.
223  * There are two definitions for every bit mask. First, the bit mask itself
224  * and also the number of necessary shifts.
225  * @{
226  */
227 /**
228  * @defgroup status_rps Status of telegram (for RPS telegrams)
229  * Bitmasks for the status-field, if ORG = RPS.
230  * @{
231  */
232 #define S_RPS_T21 0x20
233 #define S_RPS_T21_SHIFT 5
234 #define S_RPS_NU  0x10
235 #define S_RPS_NU_SHIFT 4
236 #define S_RPS_RPC 0x0F
237 #define S_RPS_RPC_SHIFT 0
238 /*@}*/
239 
240 #define F60201_R1_MASK 0xE0
241 #define F60201_R1_SHIFT 5
242 #define F60201_EB_MASK 0x10
243 #define F60201_EB_SHIFT 4
244 #define F60201_R2_MASK 0x0E
245 #define F60201_R2_SHIFT 1
246 #define F60201_SA_MASK 0x01
247 #define F60201_SA_SHIFT 0
248 
249 #define F60201_BUTTON_A1 0
250 #define F60201_BUTTON_A0 1
251 #define F60201_BUTTON_B1 2
252 #define F60201_BUTTON_B0 3
253 
254 /**
255  * @defgroup status_rpc Status of telegram (for 1BS, 4BS, HRC or 6DT telegrams)
256  * Bitmasks for the status-field, if ORG = 1BS, 4BS, HRC or 6DT.
257  * @{
258  */
259 #define S_RPC 0x0F
260 #define S_RPC_SHIFT 0
261 /*@}*/
262 
263 /**
264  * @defgroup data3 Meaning of data_byte 3 (for RPS telegrams, NU = 1)
265  * Bitmasks for the data_byte3-field, if ORG = RPS and NU = 1.
266  * Specification can be found at:
267  *      https://www.enocean.com/fileadmin/redaktion/enocean_alliance/pdf/EnOcean_Equipment_Profiles_EEP_V2.6.3_public.pdf
268  * @{
269  */
270 
271 	//!	Rocker ID Mask
272 #define DB3_RPS_NU_RID 0xC0
273 #define DB3_RPS_NU_RID_SHIFT 6
274 
275 //!	Button ID Mask
276 #define DB3_RPS_NU_BID 0xE0
277 #define DB3_RPS_NU_BID_SHIFT 5
278 
279 //!	Up Down Mask
280 #define DB3_RPS_NU_UD  0x20
281 #define DB3_RPS_NU_UD_SHIFT  5
282 
283 //!	Pressed Mask
284 #define DB3_RPS_NU_PR  0x10
285 #define DB3_RPS_NU_PR_SHIFT 4
286 
287 //!	Second Rocker ID Mask
288 #define DB3_RPS_NU_SRID 0x0C
289 #define DB3_RPS_NU_SRID_SHIFT 2
290 
291 //!	Second Button ID Mask
292 #define DB3_RPS_NU_SBID 0x0E
293 #define DB3_RPS_NU_SBID_SHIFT 1
294 
295 //!	Second UpDown Mask
296 #define DB3_RPS_NU_SUD 0x02
297 #define DB3_RPS_NU_SUD_SHIFT 1
298 
299 //!	Second Action Mask
300 #define DB3_RPS_NU_SA 0x01
301 #define DB3_RPS_NU_SA_SHIFT 0
302 
303 /*@}*/
304 
305 /**
306  * @defgroup data3_1 Meaning of data_byte 3 (for RPS telegrams, NU = 0)
307  * Bitmasks for the data_byte3-field, if ORG = RPS and NU = 0.
308  * @{
309  */
310 #define DB3_RPS_BUTTONS 0xE0
311 #define DB3_RPS_BUTTONS_SHIFT 5
312 #define DB3_RPS_PR 0x10
313 #define DB3_RPS_PR_SHIFT 4
314 /*@}*/
315 
316 /**
317  * @defgroup data0 Meaning of data_byte 0 (for 4BS telegrams)
318  * Bitmasks for the data_byte0-field, if ORG = 4BS.
319  * @{
320  */
321 #define DB0_4BS_DI_3 0x08
322 #define DB0_4BS_DI_3_SHIFT 3
323 #define DB0_4BS_DI_2 0x04
324 #define DB0_4BS_DI_2_SHIFT 2
325 #define DB0_4BS_DI_1 0x02
326 #define DB0_4BS_DI_1_SHIFT 1
327 #define DB0_4BS_DI_0 0x01
328 #define DB0_4BS_DI_0_SHIFT 0
329 /*@}*/
330 
331 /**
332  * @defgroup data3_hrc Meaning of data_byte 3 (for HRC telegrams)
333  * Bitmasks for the data_byte3-field, if ORG = HRC.
334  * @{
335  */
336 #define DB3_HRC_RID 0xC0
337 #define DB3_HRC_RID_SHIFT 6
338 #define DB3_HRC_UD  0x20
339 #define DB3_HRC_UD_SHIFT 5
340 #define DB3_HRC_PR  0x10
341 #define DB3_HRC_PR_SHIFT 4
342 #define DB3_HRC_SR  0x08
343 #define DB3_HRC_SR_SHIFT 3
344 
345 // 2016-01-31 Stéphane Guillard : added 4BS learn bit definitions below
346 #define RORG_4BS_TEACHIN_LRN_BIT (1 << 3)
347 #define RORG_4BS_TEACHIN_EEP_BIT (1 << 7)
348 
sendFrame(unsigned char frametype,unsigned char * databuf,unsigned short datalen,unsigned char * optdata,unsigned char optdatalen)349 bool CEnOceanESP3::sendFrame(unsigned char frametype, unsigned char *databuf, unsigned short datalen, unsigned char *optdata, unsigned char optdatalen)
350 {
351 	unsigned char crc=0;
352 	unsigned char buf[1024];
353 	int len=0;
354 
355 	buf[len++]=SER_SYNCH_CODE;
356 	buf[len++]=(datalen >> 8) & 0xff; // len
357 	buf[len++]=datalen & 0xff;
358 	buf[len++]=optdatalen;
359 	buf[len++]=frametype;
360 	crc = proc_crc8(crc, buf[1]);
361 	crc = proc_crc8(crc, buf[2]);
362 	crc = proc_crc8(crc, buf[3]);
363 	crc = proc_crc8(crc, buf[4]);
364 	buf[len++]=crc;
365 	crc = 0;
366 	for (int i=0;i<datalen;i++) {
367 		buf[len]=databuf[i];
368 		crc=proc_crc8(crc, buf[len++]);
369 	}
370 	for (int i=0;i<optdatalen;i++) {
371 		buf[len]=optdata[i];
372 		crc=proc_crc8(crc, buf[len++]);
373 	}
374 	buf[len++]=crc;
375 	write((const char*)&buf,len);
376 	return true;
377 }
378 
sendFrameQueue(unsigned char frametype,unsigned char * databuf,unsigned short datalen,unsigned char * optdata,unsigned char optdatalen)379 bool CEnOceanESP3::sendFrameQueue(unsigned char frametype, unsigned char *databuf, unsigned short datalen, unsigned char *optdata, unsigned char optdatalen)
380 {
381 	unsigned char crc=0;
382 	unsigned char buf[1024];
383 	int len=0;
384 
385 	buf[len++]=SER_SYNCH_CODE;
386 	buf[len++]=(datalen >> 8) & 0xff; // len
387 	buf[len++]=datalen & 0xff;
388 	buf[len++]=optdatalen;
389 	buf[len++]=frametype;
390 	crc = proc_crc8(crc, buf[1]);
391 	crc = proc_crc8(crc, buf[2]);
392 	crc = proc_crc8(crc, buf[3]);
393 	crc = proc_crc8(crc, buf[4]);
394 	buf[len++]=crc;
395 	crc = 0;
396 	for (int i=0;i<datalen;i++) {
397 		buf[len]=databuf[i];
398 		crc=proc_crc8(crc, buf[len++]);
399 	}
400 	for (int i=0;i<optdatalen;i++) {
401 		buf[len]=optdata[i];
402 		crc=proc_crc8(crc, buf[len++]);
403 	}
404 	buf[len++]=crc;
405 	Add2SendQueue((const char*)&buf,len);
406 	return true;
407 }
408 
CEnOceanESP3(const int ID,const std::string & devname,const int type)409 CEnOceanESP3::CEnOceanESP3(const int ID, const std::string& devname, const int type)
410 {
411 	m_HwdID=ID;
412 	m_szSerialPort=devname;
413     m_Type = type;
414 	m_bufferpos=0;
415 	memset(&m_buffer,0,sizeof(m_buffer));
416 	m_id_base=0;
417 	m_receivestate=ERS_SYNCBYTE;
418 
419 	//Test
420 	//m_ReceivedPacketType = 0x01;
421 	//m_DataSize = 0x0A;
422 	//m_OptionalDataSize = 0x07;
423 	//m_bufferpos = 0;
424 	//m_buffer[m_bufferpos++] = 0xA5;
425 	//ParseData();
426 }
427 
~CEnOceanESP3()428 CEnOceanESP3::~CEnOceanESP3()
429 {
430 
431 }
432 
StartHardware()433 bool CEnOceanESP3::StartHardware()
434 {
435 	RequestStart();
436 
437 	Init();
438 
439 	m_retrycntr=ENOCEAN_RETRY_DELAY*5; //will force reconnect first thing
440 
441 	//Start worker thread
442 	m_thread = std::make_shared<std::thread>(&CEnOceanESP3::Do_Work, this);
443 	SetThreadNameInt(m_thread->native_handle());
444 
445 	return (m_thread != nullptr);
446 }
447 
StopHardware()448 bool CEnOceanESP3::StopHardware()
449 {
450 	if (m_thread)
451 	{
452 		RequestStop();
453 		m_thread->join();
454 		m_thread.reset();
455 	}
456 	m_bIsStarted=false;
457 	return true;
458 }
459 
Init()460 void CEnOceanESP3::Init()
461 {
462 	ReloadVLDNodes();
463 }
464 
ReloadVLDNodes()465 void CEnOceanESP3::ReloadVLDNodes()
466 {
467 	m_VLDNodes.clear();
468 	std::vector<std::vector<std::string> > result;
469 	result = m_sql.safe_query("SELECT ID, DeviceID, Manufacturer, Profile, [Type] FROM EnoceanSensors WHERE (HardwareID==%d)", m_HwdID);
470 	if (!result.empty())
471 	{
472 		for (const auto & itt : result)
473 		{
474 			std::vector<std::string> sd = itt;
475 			_tVLDNode node;
476 			node.idx = atoi(sd[0].c_str());
477 			node.manufacturer = atoi(sd[2].c_str());
478 			node.profile = (uint8_t)atoi(sd[3].c_str());
479 			node.type = (uint8_t)atoi(sd[4].c_str());
480 
481 			//convert to hex, and we have our ID
482 			std::stringstream s_strid;
483 			s_strid << std::hex << std::uppercase << sd[1];
484 			uint32_t devid;
485 			s_strid >> devid;
486 			m_VLDNodes[devid] = node;
487 		}
488 	}
489 }
490 
Do_Work()491 void CEnOceanESP3::Do_Work()
492 {
493 	int msec_counter=0;
494 	int sec_counter = 0;
495 
496 	_log.Log(LOG_STATUS, "EnOcean: Worker started...");
497 
498 	while (!IsStopRequested(200))
499 	{
500 		msec_counter++;
501 		if (msec_counter == 5)
502 		{
503 			msec_counter = 0;
504 			sec_counter++;
505 			if (sec_counter % 12 == 0)
506 			{
507 				m_LastHeartbeat = mytime(NULL);
508 			}
509 		}
510 
511 		if (!isOpen())
512 		{
513 			if (m_retrycntr==0)
514 			{
515 				_log.Log(LOG_STATUS,"EnOcean: serial retrying in %d seconds...", ENOCEAN_RETRY_DELAY);
516 			}
517 			m_retrycntr++;
518 			if (m_retrycntr/5>=ENOCEAN_RETRY_DELAY)
519 			{
520 				m_retrycntr=0;
521 				m_bufferpos=0;
522 				OpenSerialDevice();
523 			}
524 		}
525 		if (m_sendqueue.size()>0)
526 		{
527 			std::lock_guard<std::mutex> l(m_sendMutex);
528 
529 			std::vector<std::string>::iterator itt=m_sendqueue.begin();
530 			if (itt!=m_sendqueue.end())
531 			{
532 				std::string sBytes=*itt;
533 				write(sBytes.c_str(),sBytes.size());
534 				m_sendqueue.erase(itt);
535 			}
536 		}
537 	}
538 	terminate();
539 
540 	_log.Log(LOG_STATUS,"EnOcean: Worker stopped...");
541 }
542 
Add2SendQueue(const char * pData,const size_t length)543 void CEnOceanESP3::Add2SendQueue(const char* pData, const size_t length)
544 {
545 #ifdef ENABLE_LOGGING
546 	std::stringstream sstr;
547 
548 	for (size_t idx = 0; idx < length; idx++)
549 	{
550 		sstr << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << (((unsigned int)pData[idx]) & 0xFF);
551 		if (idx != length - 1)
552 			sstr << " ";
553 	}
554 	_log.Log(LOG_STATUS,"EnOcean Send: %s",sstr.str().c_str());
555 #endif
556 
557 	std::string sBytes;
558 	sBytes.insert(0,pData,length);
559 	std::lock_guard<std::mutex> l(m_sendMutex);
560 	m_sendqueue.push_back(sBytes);
561 }
562 
563 
OpenSerialDevice()564 bool CEnOceanESP3::OpenSerialDevice()
565 {
566 	//Try to open the Serial Port
567 	try
568 	{
569 		open(m_szSerialPort, 57600); //ECP3 open with 57600
570 		_log.Log(LOG_STATUS,"EnOcean: Using serial port: %s", m_szSerialPort.c_str());
571 	}
572 	catch (boost::exception & e)
573 	{
574 		_log.Log(LOG_ERROR,"EnOcean: Error opening serial port!");
575 #ifdef _DEBUG
576 		_log.Log(LOG_ERROR,"-----------------\n%s\n----------------", boost::diagnostic_information(e).c_str());
577 #else
578 		(void)e;
579 #endif
580 		return false;
581 	}
582 	catch ( ... )
583 	{
584 		_log.Log(LOG_ERROR,"EnOcean: Error opening serial port!!!");
585 		return false;
586 	}
587 	m_bIsStarted=true;
588 
589 	m_receivestate=ERS_SYNCBYTE;
590 	setReadCallback(boost::bind(&CEnOceanESP3::readCallback, this, _1, _2));
591 	sOnConnected(this);
592 
593 	uint8_t buf[100];
594 
595 	//Request BASE_ID
596 	m_bBaseIDRequested=true;
597 	buf[0] = CO_RD_IDBASE;
598 	sendFrameQueue(PACKET_COMMON_COMMAND,buf,1,NULL,0);
599 
600 	//Request Version
601 	buf[0] = CO_RD_VERSION;
602 	sendFrameQueue(PACKET_COMMON_COMMAND,buf,1,NULL,0);
603 
604 	return true;
605 }
606 
readCallback(const char * data,size_t len)607 void CEnOceanESP3::readCallback(const char *data, size_t len)
608 {
609 	size_t ii=0;
610 
611 	while (ii<len)
612 	{
613 		const unsigned char c = data[ii];
614 
615 		switch (m_receivestate)
616 		{
617 		case ERS_SYNCBYTE:
618 			if (c!=0x55)
619 				return;
620 			m_receivestate = ERS_HEADER;
621 			m_bufferpos=0;
622 			break;
623 		case ERS_HEADER:
624 			m_buffer[m_bufferpos++]=c;
625 			if (m_bufferpos==5)
626 			{
627 				m_DataSize=(m_buffer[0]<<8)|m_buffer[1];
628 				m_OptionalDataSize=m_buffer[2];
629 				m_ReceivedPacketType=m_buffer[3];
630 				unsigned char CRCH=m_buffer[4];
631 
632 				unsigned char crc=0;
633 				crc = proc_crc8(crc, m_buffer[0]);
634 				crc = proc_crc8(crc, m_buffer[1]);
635 				crc = proc_crc8(crc, m_buffer[2]);
636 				crc = proc_crc8(crc, m_buffer[3]);
637 
638 				if (CRCH==crc)
639 				{
640 					m_bufferpos=0;
641 					m_wantedlength=m_DataSize+m_OptionalDataSize;
642 					m_receivestate = ERS_DATA;
643 				}
644 				else
645 				{
646 					_log.Log(LOG_ERROR,"EnOcean: Frame Checksum Error!...");
647 					m_receivestate = ERS_SYNCBYTE;
648 				}
649 			}
650 			break;
651 		case ERS_DATA:
652 			m_buffer[m_bufferpos++] = c;
653 			if (m_bufferpos>=m_wantedlength)
654 			{
655 				m_receivestate = ERS_CHECKSUM;
656 			}
657 			break;
658 		case ERS_CHECKSUM:
659 			{
660 				unsigned char CRCD=c;
661 				unsigned char crc=0;
662 				for (int iCheck=0; iCheck<m_wantedlength; iCheck++)
663 					crc = proc_crc8(crc, m_buffer[iCheck]);
664 				if (CRCD==crc)
665 				{
666 					ParseData();
667 				}
668 				m_receivestate = ERS_SYNCBYTE;
669 			}
670 			break;
671 		}
672 		ii++;
673 	}
674 
675 }
676 
WriteToHardware(const char * pdata,const unsigned char)677 bool CEnOceanESP3::WriteToHardware(const char *pdata, const unsigned char /*length*/)
678 {
679 	if (m_id_base==0)
680 		return false;
681 	if (!isOpen())
682 		return false;
683 	RBUF *tsen=(RBUF*)pdata;
684 	if (tsen->LIGHTING2.packettype!=pTypeLighting2)
685 		return false; //only allowed to control switches
686 
687 	unsigned long sID=(tsen->LIGHTING2.id1<<24)|(tsen->LIGHTING2.id2<<16)|(tsen->LIGHTING2.id3<<8)|tsen->LIGHTING2.id4;
688 	if ((sID<m_id_base)||(sID>m_id_base+129))
689 	{
690 		_log.Log(LOG_ERROR,"EnOcean (1): Can not switch with this DeviceID, use a switch created with our id_base!...");
691 		return false;
692 	}
693 
694 	unsigned char RockerID=0;
695 	unsigned char Pressed=1;
696 
697 	if (tsen->LIGHTING2.unitcode < 10)
698 	{
699 		RockerID = tsen->LIGHTING2.unitcode - 1;
700 	}
701 	else
702 		return false;//double not supported yet!
703 
704 
705 	//First we need to find out if this is a Dimmer switch,
706 	//because they are threaded differently
707 	bool bIsDimmer=false;
708 	uint8_t LastLevel=0;
709 	std::vector<std::vector<std::string> > result;
710 	char szDeviceID[20];
711 	sprintf(szDeviceID,"%08X",(unsigned int)sID);
712 	result = m_sql.safe_query("SELECT SwitchType,LastLevel FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Unit==%d)", m_HwdID, szDeviceID, int(tsen->LIGHTING2.unitcode));
713 	if (result.size()>0)
714 	{
715 		_eSwitchType switchtype=(_eSwitchType)atoi(result[0][0].c_str());
716 		if (switchtype==STYPE_Dimmer)
717 			bIsDimmer=true;
718 		LastLevel=(uint8_t)atoi(result[0][1].c_str());
719 	}
720 
721 	uint8_t iLevel=tsen->LIGHTING2.level;
722 	int cmnd=tsen->LIGHTING2.cmnd;
723 	int orgcmd=cmnd;
724 	if ((tsen->LIGHTING2.level==0)&&(!bIsDimmer))
725 		cmnd=light2_sOff;
726 	else
727 	{
728 		if (cmnd==light2_sOn)
729 		{
730 			iLevel=LastLevel;
731 		}
732 		else
733 		{
734 			//scale to 0 - 100 %
735 			iLevel=tsen->LIGHTING2.level;
736 			if (iLevel>15)
737 				iLevel=15;
738 			float fLevel=(100.0f/15.0f)*float(iLevel);
739 			if (fLevel>99.0f)
740 				fLevel=100.0f;
741 			iLevel=(uint8_t)(fLevel);
742 		}
743 		cmnd=light2_sSetLevel;
744 	}
745 
746 	//char buff[512];
747 	//sprintf(buff,"cmnd: %d, level: %d, orgcmd: %d",cmnd, iLevel, orgcmd);
748 	//_log.Log(LOG_ERROR,buff);
749 	unsigned char buf[100];
750 	//unsigned char optbuf[100];
751 
752 	if(!bIsDimmer)
753 	{
754 		// on/off switch without dimming capability: Profile F6-02-01
755 		// cf. EnOcean Equipment Profiles v2.6.5 page 11 (RPS format) & 14
756 		unsigned char UpDown = 1;
757 
758 		buf[0] = RORG_RPS;
759 
760 		UpDown = ((orgcmd != light2_sOff) && (orgcmd != light2_sGroupOff));
761 
762 		switch(RockerID)
763 		{
764 			case 0:	// Button A
765 						if(UpDown)
766 							buf[1] = F60201_BUTTON_A1 << F60201_R1_SHIFT;
767 						else
768 							buf[1] = F60201_BUTTON_A0 << F60201_R1_SHIFT;
769 						break;
770 
771 			case 1:	// Button B
772 						if(UpDown)
773 							buf[1] = F60201_BUTTON_B1 << F60201_R1_SHIFT;
774 						else
775 							buf[1] = F60201_BUTTON_B0 << F60201_R1_SHIFT;
776 						break;
777 
778 			default:
779 						return false;	// not supported
780 		}
781 
782 		buf[1] |= F60201_EB_MASK;		// button is pressed
783 
784 		buf[2]=(sID >> 24) & 0xff;		// Sender ID
785 		buf[3]=(sID >> 16) & 0xff;
786 		buf[4]=(sID >> 8) & 0xff;
787 		buf[5]=sID & 0xff;
788 
789 		buf[6] = S_RPS_T21|S_RPS_NU;	// press button			// b5=T21, b4=NU, b3-b0= RepeaterCount
790 
791 		//char buff[512];
792 		//sprintf(buff,"%02X %02X %02X %02X %02X %02X %02X",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6]);
793 		//_log.Log(LOG_ERROR,buff);
794 
795 		sendFrameQueue(PACKET_RADIO,buf,7,NULL,0);
796 
797 		//Next command is send a bit later (button release)
798 		buf[1] = 0;				// no button press
799 		buf[6] = S_RPS_T21;	// release button			// b5=T21, b4=NU, b3-b0= RepeaterCount
800 		//sprintf(buff,"%02X %02X %02X %02X %02X %02X %02X",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6]);
801 		//_log.Log(LOG_ERROR,buff);
802 
803 		sendFrameQueue(PACKET_RADIO,buf,7,NULL,0);
804 	}
805 	else
806 	{
807 		// on/off switch with dimming capability: Profile A5-38-02
808 		// cf. EnOcean Equipment Profiles v2.6.5 page 12 (4BS format) & 103
809 		buf[0]=0xa5;
810 		buf[1]=0x2;
811 		buf[2]=100;	//level
812 		buf[3]=1;	//speed
813 		buf[4]=0x09; // Dim Off
814 
815 		buf[5]=(sID >> 24) & 0xff;
816 		buf[6]=(sID >> 16) & 0xff;
817 		buf[7]=(sID >> 8) & 0xff;
818 		buf[8]=sID & 0xff;
819 
820 		buf[9]=0x30; // status
821 
822 		if (cmnd!=light2_sSetLevel)
823 		{
824 			//On/Off
825 			unsigned char UpDown = 1;
826 			UpDown = ((cmnd != light2_sOff) && (cmnd != light2_sGroupOff));
827 
828 			buf[1] = (RockerID<<DB3_RPS_NU_RID_SHIFT) | (UpDown<<DB3_RPS_NU_UD_SHIFT) | (Pressed<<DB3_RPS_NU_PR_SHIFT);//0x30;
829 			buf[9] = 0x30;
830 
831 			sendFrameQueue(PACKET_RADIO,buf,10,NULL,0);
832 
833 			//char buff[512];
834 			//sprintf(buff,"%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9]);
835 			//_log.Log(LOG_ERROR,buff);
836 
837 			//Next command is send a bit later (button release)
838 			buf[1] = 0;
839 			buf[9] = 0x20;
840 			//sprintf(buff,"%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9]);
841 			//_log.Log(LOG_ERROR,buff);
842 			sendFrameQueue(PACKET_RADIO,buf,10,NULL,0);
843 		}
844 		else
845 		{
846 			//Send dim value
847 
848 			//Dim On DATA_BYTE0 = 0x09
849 			//Dim Off DATA_BYTE0 = 0x08
850 
851 			buf[1]=2;
852 			buf[2]=iLevel;
853 			buf[3]=1;//very fast dimming
854 
855 			if ((iLevel==0)||(orgcmd==light2_sOff))
856 				buf[4]=0x08; //Dim Off
857 			else
858 				buf[4]=0x09;//Dim On
859 
860 			sendFrameQueue(PACKET_RADIO,buf,10,NULL,0);
861 		}
862 	}
863 
864 	return true;
865 }
866 
SendDimmerTeachIn(const char * pdata,const unsigned char)867 void CEnOceanESP3::SendDimmerTeachIn(const char *pdata, const unsigned char /*length*/)
868 {
869 	if (m_id_base==0)
870 		return;
871 	if (isOpen()) {
872 		RBUF *tsen = (RBUF*)pdata;
873 		if (tsen->LIGHTING2.packettype != pTypeLighting2)
874 			return; //only allowed to control switches
875 		unsigned long sID = (tsen->LIGHTING2.id1 << 24) | (tsen->LIGHTING2.id2 << 16) | (tsen->LIGHTING2.id3 << 8) | tsen->LIGHTING2.id4;
876 		if ((sID<m_id_base) || (sID>m_id_base + 129))
877 		{
878 			_log.Log(LOG_ERROR, "EnOcean (2): Can not switch with this DeviceID, use a switch created with our id_base!...");
879 			return;
880 		}
881 
882 		unsigned char buf[100];
883 		buf[0] = 0xa5;
884 		buf[1] = 0x2;
885 		buf[2] = 0;
886 		buf[3] = 0;
887 		buf[4] = 0x0; // DB0.3=0 -> teach in
888 
889 		buf[5] = (sID >> 24) & 0xff;
890 		buf[6] = (sID >> 16) & 0xff;
891 		buf[7] = (sID >> 8) & 0xff;
892 		buf[8] = sID & 0xff;
893 
894 		buf[9] = 0x30; // status
895 
896 		if (tsen->LIGHTING2.unitcode < 10)
897 		{
898 			unsigned char RockerID = 0;
899 			//unsigned char UpDown = 1;
900 			//unsigned char Pressed = 1;
901 			RockerID = tsen->LIGHTING2.unitcode - 1;
902 		}
903 		else
904 		{
905 			return;//double not supported yet!
906 		}
907 		sendFrame(PACKET_RADIO,buf,10,NULL,0);
908 	}
909 }
910 
GetValueRange(const float InValue,const float ScaleMax,const float ScaleMin,const float RangeMax,const float RangeMin)911 float CEnOceanESP3::GetValueRange(const float InValue, const float ScaleMax, const float ScaleMin, const float RangeMax, const float RangeMin)
912 {
913 	float vscale=ScaleMax-ScaleMin;
914 	if (vscale==0)
915 		return 0.0f;
916 	float vrange=RangeMax-RangeMin;
917 	if (vrange==0)
918 		return 0.0f;
919 	float multiplyer=vscale/vrange;
920 	return multiplyer*(InValue-RangeMin)+ScaleMin;
921 }
922 
ParseData()923 bool CEnOceanESP3::ParseData()
924 {
925 #ifdef ENABLE_LOGGING
926 	std::stringstream sstr;
927 
928 	sstr << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << (unsigned int)m_ReceivedPacketType << " (";
929 	sstr << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << (unsigned int)m_DataSize << "/";
930 	sstr << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << (unsigned int)m_OptionalDataSize << ") ";
931 
932 	for (int idx=0;idx<m_bufferpos;idx++)
933 	{
934 		sstr << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << (unsigned int)m_buffer[idx];
935 		if (idx!=m_bufferpos-1)
936 			sstr << " ";
937 	}
938 	_log.Log(LOG_STATUS,"EnOcean: %s",sstr.str().c_str());
939 #endif
940 
941 	if (m_ReceivedPacketType==PACKET_RESPONSE)
942 	{
943 		//Response
944 		unsigned char ResponseCode=m_buffer[0];
945 		if (ResponseCode!=0)
946 		{
947 			std::string szError="Unknown?";
948 			switch (ResponseCode)
949 			{
950 			case RET_ERROR:
951 				szError="RET_ERROR";
952 				break;
953 			case RET_NOT_SUPPORTED:
954 				szError="RET_NOT_SUPPORTED";
955 				break;
956 			case RET_WRONG_PARAM:
957 				szError="RET_WRONG_PARAM";
958 				break;
959 			case RET_OPERATION_DENIED:
960 				szError="RET_OPERATION_DENIED";
961 				break;
962 			}
963 			_log.Log(LOG_ERROR,"EnOcean: Response Error (Code: %d, %s)",ResponseCode,szError.c_str());
964 			return false;
965 		}
966 		if ((m_bBaseIDRequested)&&(m_bufferpos==6))
967 		{
968 			m_bBaseIDRequested=false;
969 			m_id_base = (m_buffer[1] << 24) + (m_buffer[2] << 16) + (m_buffer[3] << 8) + m_buffer[4];
970 			//unsigned char changes_left=m_buffer[5];
971 			_log.Log(LOG_STATUS,"EnOcean: Transceiver ID_Base: 0x%08lx",m_id_base);
972 		}
973 		if (m_bufferpos==33)
974 		{
975 			//Version Information
976 			_log.Log(LOG_STATUS,"EnOcean: Version_Info, App: %02x.%02x.%02x.%02x, API: %02x.%02x.%02x.%02x, ChipID: %02x.%02x.%02x.%02x, ChipVersion: %02x.%02x.%02x.%02x, Description: %s",
977 				m_buffer[1],m_buffer[2],m_buffer[3],m_buffer[4],
978 				m_buffer[5],m_buffer[6],m_buffer[7],m_buffer[8],
979 				m_buffer[9],m_buffer[10],m_buffer[11],m_buffer[12],
980 				m_buffer[13],m_buffer[14],m_buffer[15],m_buffer[16],
981 				(const char*)&m_buffer+17
982 				);
983 		}
984 		return true;
985 	}
986 	else if (m_ReceivedPacketType==PACKET_RADIO)
987 		ParseRadioDatagram();
988 	else
989 	{
990 		char szTmp[100];
991 		sprintf(szTmp,"Unhandled Packet Type (0x%02x)",m_ReceivedPacketType);
992 		_log.Log(LOG_STATUS, "%s", szTmp);
993 	}
994 /*
995 	enocean_data_structure *pFrame=(enocean_data_structure*)&m_buffer;
996 	unsigned char Checksum=enocean_calc_checksum(pFrame);
997 	if (Checksum!=pFrame->CHECKSUM)
998 		return false; //checksum Mismatch!
999 
1000 	long id = (pFrame->ID_BYTE3 << 24) + (pFrame->ID_BYTE2 << 16) + (pFrame->ID_BYTE1 << 8) + pFrame->ID_BYTE0;
1001 	char szDeviceID[20];
1002 	sprintf(szDeviceID,"%08X",(unsigned int)id);
1003 
1004 	//Handle possible OK/Errors
1005 	bool bStopProcessing=false;
1006 	if (pFrame->H_SEQ_LENGTH==0x8B)
1007 	{
1008 		switch (pFrame->ORG)
1009 		{
1010 		case 0x58:
1011 			//OK
1012 #ifdef _DEBUG
1013 			_log.Log(LOG_NORM,"EnOcean: OK");
1014 #endif
1015 			bStopProcessing=true;
1016 			break;
1017 		case 0x28:
1018 			_log.Log(LOG_ERROR,"EnOcean: ERR_MODEM_NOTWANTEDACK");
1019 			bStopProcessing=true;
1020 			break;
1021 		case 0x29:
1022 			_log.Log(LOG_ERROR,"EnOcean: ERR_MODEM_NOTACK");
1023 			bStopProcessing=true;
1024 			break;
1025 		case 0x0C:
1026 			_log.Log(LOG_ERROR,"EnOcean: ERR_MODEM_DUP_ID");
1027 			bStopProcessing=true;
1028 			break;
1029 		case 0x08:
1030 			_log.Log(LOG_ERROR,"EnOcean: Error in H_SEQ");
1031 			bStopProcessing=true;
1032 			break;
1033 		case 0x09:
1034 			_log.Log(LOG_ERROR,"EnOcean: Error in LENGTH");
1035 			bStopProcessing=true;
1036 			break;
1037 		case 0x0A:
1038 			_log.Log(LOG_ERROR,"EnOcean: Error in CHECKSUM");
1039 			bStopProcessing=true;
1040 			break;
1041 		case 0x0B:
1042 			_log.Log(LOG_ERROR,"EnOcean: Error in ORG");
1043 			bStopProcessing=true;
1044 			break;
1045 		case 0x22:
1046 			_log.Log(LOG_ERROR,"EnOcean: ERR_TX_IDRANGE");
1047 			bStopProcessing=true;
1048 			break;
1049 		case 0x1A:
1050 			_log.Log(LOG_ERROR,"EnOcean: ERR_ IDRANGE");
1051 			bStopProcessing=true;
1052 			break;
1053 		}
1054 	}
1055 	if (bStopProcessing)
1056 		return true;
1057 
1058 	switch (pFrame->ORG)
1059 	{
1060 	case C_ORG_INF_IDBASE:
1061 		m_id_base = (pFrame->DATA_BYTE3 << 24) + (pFrame->DATA_BYTE2 << 16) + (pFrame->DATA_BYTE1 << 8) + pFrame->DATA_BYTE0;
1062 		_log.Log(LOG_STATUS,"EnOcean: Transceiver ID_Base: 0x%08x",m_id_base);
1063 		break;
1064 	case C_ORG_RPS:
1065 		if (pFrame->STATUS & S_RPS_NU) {
1066 			//Rocker
1067 			// NU == 1, N-Message
1068 			unsigned char RockerID=(pFrame->DATA_BYTE3 & DB3_RPS_NU_RID) >> DB3_RPS_NU_RID_SHIFT;
1069 			unsigned char UpDown=(pFrame->DATA_BYTE3 & DB3_RPS_NU_UD) >> DB3_RPS_NU_UD_SHIFT;
1070 			unsigned char Pressed=(pFrame->DATA_BYTE3 & DB3_RPS_NU_PR)>>DB3_RPS_NU_PR_SHIFT;
1071 			unsigned char SecondRockerID=(pFrame->DATA_BYTE3 & DB3_RPS_NU_SRID)>>DB3_RPS_NU_SRID_SHIFT;
1072 			unsigned char SecondUpDown=(pFrame->DATA_BYTE3 & DB3_RPS_NU_SUD)>>DB3_RPS_NU_SUD_SHIFT;
1073 			unsigned char SecondAction=(pFrame->DATA_BYTE3 & DB3_RPS_NU_SA)>>DB3_RPS_NU_SA_SHIFT;
1074 #ifdef _DEBUG
1075 			_log.Log(LOG_NORM,"Received RPS N-Message Node 0x%08x Rocker ID: %i UD: %i Pressed: %i Second Rocker ID: %i SUD: %i Second Action: %i",
1076 				id,
1077 				RockerID,
1078 				UpDown,
1079 				Pressed,
1080 				SecondRockerID,
1081 				SecondUpDown,
1082 				SecondAction);
1083 #endif
1084 			//We distinguish 3 types of buttons from a switch: Left/Right/Left+Right
1085 			if (Pressed==1)
1086 			{
1087 				RBUF tsen;
1088 				memset(&tsen,0,sizeof(RBUF));
1089 				tsen.LIGHTING2.packetlength=sizeof(tsen.LIGHTING2)-1;
1090 				tsen.LIGHTING2.packettype=pTypeLighting2;
1091 				tsen.LIGHTING2.subtype=sTypeAC;
1092 				tsen.LIGHTING2.seqnbr=0;
1093 				tsen.LIGHTING2.id1=(BYTE)pFrame->ID_BYTE3;
1094 				tsen.LIGHTING2.id2=(BYTE)pFrame->ID_BYTE2;
1095 				tsen.LIGHTING2.id3=(BYTE)pFrame->ID_BYTE1;
1096 				tsen.LIGHTING2.id4=(BYTE)pFrame->ID_BYTE0;
1097 				tsen.LIGHTING2.level=0;
1098 				tsen.LIGHTING2.rssi=12;
1099 
1100 				if (SecondAction==0)
1101 				{
1102 					//Left/Right Up/Down
1103 					tsen.LIGHTING2.unitcode=RockerID+1;
1104 					tsen.LIGHTING2.cmnd=(UpDown==1)?light2_sOn:light2_sOff;
1105 				}
1106 				else
1107 				{
1108 					//Left+Right Up/Down
1109 					tsen.LIGHTING2.unitcode=SecondRockerID+10;
1110 					tsen.LIGHTING2.cmnd=(SecondUpDown==1)?light2_sOn:light2_sOff;
1111 				}
1112 				sDecodeRXMessage(this, (const unsigned char *)&tsen.LIGHTING2, NULL, 255);
1113 			}
1114 		}
1115 		break;
1116 	case C_ORG_4BS:
1117 		break;
1118 	default:
1119 		{
1120 			char *pszHumenTxt=enocean_hexToHuman(pFrame);
1121 			if (pszHumenTxt)
1122 			{
1123 				_log.Log(LOG_NORM, "EnOcean: %s", pszHumenTxt);
1124 				free(pszHumenTxt);
1125 			}
1126 		}
1127 		break;
1128 	}
1129 */
1130     return true;
1131 }
1132 
ParseRadioDatagram()1133 void CEnOceanESP3::ParseRadioDatagram()
1134 {
1135 	char szTmp[100];
1136 	if (m_OptionalDataSize == 7)
1137 	{
1138 		sprintf(szTmp,"destination: 0x%02x%02x%02x%02x RSSI: %i",
1139 			m_buffer[m_DataSize+1],m_buffer[m_DataSize+2],m_buffer[m_DataSize+3],m_buffer[m_DataSize+4],
1140 			(100-m_buffer[m_DataSize+5])
1141 			);
1142 	}
1143 	else {
1144 		sprintf(szTmp, "Optional data size: %i",m_OptionalDataSize);
1145 	}
1146 	_log.Log(LOG_NORM, "EnOcean: %s", szTmp);
1147 	switch (m_buffer[0])
1148 	{
1149 		case RORG_1BS: // 1 byte communication (Contacts/Switches)
1150 			{
1151 				sprintf(szTmp,"1BS data: Sender id: 0x%02x%02x%02x%02x Data: %02x",
1152 					m_buffer[2],m_buffer[3],m_buffer[4],m_buffer[5],
1153 					m_buffer[0]
1154 				);
1155 
1156 				_log.Log(LOG_NORM, "EnOcean: %s", szTmp);
1157 
1158 				unsigned char DATA_BYTE0 = m_buffer[1];
1159 
1160 				unsigned char ID_BYTE3  = m_buffer[2];
1161 				unsigned char ID_BYTE2  = m_buffer[3];
1162 				unsigned char ID_BYTE1  = m_buffer[4];
1163 				unsigned char ID_BYTE0  = m_buffer[5];
1164 
1165 				int UpDown=(DATA_BYTE0&1)==0;
1166 
1167 				RBUF tsen;
1168 				memset(&tsen,0,sizeof(RBUF));
1169 				tsen.LIGHTING2.packetlength=sizeof(tsen.LIGHTING2)-1;
1170 				tsen.LIGHTING2.packettype=pTypeLighting2;
1171 				tsen.LIGHTING2.subtype=sTypeAC;
1172 				tsen.LIGHTING2.seqnbr=0;
1173 
1174 				tsen.LIGHTING2.id1=(BYTE)ID_BYTE3;
1175 				tsen.LIGHTING2.id2=(BYTE)ID_BYTE2;
1176 				tsen.LIGHTING2.id3=(BYTE)ID_BYTE1;
1177 				tsen.LIGHTING2.id4=(BYTE)ID_BYTE0;
1178 				tsen.LIGHTING2.level=0;
1179 				tsen.LIGHTING2.rssi=12;
1180 				tsen.LIGHTING2.unitcode=1;
1181 				tsen.LIGHTING2.cmnd=(UpDown==1)?light2_sOn:light2_sOff;
1182 				sDecodeRXMessage(this, (const unsigned char *)&tsen.LIGHTING2, NULL, 255);
1183 			}
1184 			break;
1185 		case RORG_4BS: // 4 byte communication
1186 			{
1187 				sprintf(szTmp,"4BS data: Sender id: 0x%02x%02x%02x%02x Status: %02x Data: %02x",
1188 					m_buffer[5],m_buffer[6],m_buffer[7],m_buffer[8],
1189 					m_buffer[9],
1190 					m_buffer[3]
1191 				);
1192 				_log.Log(LOG_NORM, "EnOcean: %s", szTmp);
1193 
1194 				unsigned char DATA_BYTE3 = m_buffer[1];
1195 				unsigned char DATA_BYTE2 = m_buffer[2];
1196 				unsigned char DATA_BYTE1 = m_buffer[3];
1197 				unsigned char DATA_BYTE0 = m_buffer[4];
1198 
1199 				unsigned char ID_BYTE3  = m_buffer[5];
1200 				unsigned char ID_BYTE2  = m_buffer[6];
1201 				unsigned char ID_BYTE1  = m_buffer[7];
1202 				unsigned char ID_BYTE0  = m_buffer[8];
1203 
1204 				long id = (ID_BYTE3 << 24) + (ID_BYTE2 << 16) + (ID_BYTE1 << 8) + ID_BYTE0;
1205 				char szDeviceID[20];
1206 				sprintf(szDeviceID,"%08X",(unsigned int)id);
1207 
1208 				if ((DATA_BYTE0 & RORG_4BS_TEACHIN_LRN_BIT) == 0)	// LRN_BIT is 0 -> Teach-in datagram
1209 				{
1210 					int manufacturer;
1211 					int profile;
1212 					int ttype;
1213 
1214 					// 2016-01-31 Stéphane Guillard : added handling of this case:
1215 					if ((DATA_BYTE0 & RORG_4BS_TEACHIN_EEP_BIT) == 0)
1216 					{
1217 						// RORG_4BS_TEACHIN_EEP_BIT is 0 -> Teach-in Variant 1 : data doesn't contain EEP and Manufacturer ID
1218 						// An EEP profile must be manually allocated per sender ID (see EEP 2.6.2 specification §3.3 p173/197)
1219 						_log.Log(LOG_NORM, "EnOcean: 4BS, Variant 1 Teach-in diagram: Sender_ID: 0x%08lX", id);
1220 						_log.Log(LOG_NORM, "Teach-in data contains no EEP profile. Created generic A5-02-05 profile (0/40°C temp sensor); please adjust by hand using Setup button on EnOcean adapter in Setup/Hardware menu");
1221 
1222 						manufacturer = 0x7FF;			// Generic
1223 						profile = 2;					// == T4BSTable[4].Func: Temperature Sensor Range 0C to +40C
1224 						ttype = 5;						// == T4BSTable[4].Type
1225 					}
1226 					else
1227 					{
1228 						// RORG_4BS_TEACHIN_EEP_BIT is 1 -> Teach-in Variant 2 : data contains EEP and Manufacturer ID
1229 
1230 						//DB3		DB3/2	DB2/1			DB0
1231 						//Profile	Type	Manufacturer-ID	RORG_4BS_TEACHIN_EEP_BIT		RE2		RE1				RORG_4BS_TEACHIN_LRN_BIT
1232 						//6 Bit		7 Bit	11 Bit			1Bit		1Bit	1Bit	1Bit	1Bit	1Bit	1Bit	1Bit
1233 
1234 						// Extract manufacturer, profile and type from data
1235 						manufacturer = ((DATA_BYTE2 & 7) << 8) | DATA_BYTE1;
1236 						profile = DATA_BYTE3 >> 2;
1237 						ttype = ((DATA_BYTE3 & 3) << 5) | (DATA_BYTE2 >> 3);
1238 
1239 						_log.Log(LOG_NORM,"EnOcean: 4BS, Variant 2 Teach-in diagram: Sender_ID: 0x%08lX\nManufacturer: 0x%02x (%s)\nProfile: 0x%02X\nType: 0x%02X (%s)",
1240 							id, manufacturer,Get_EnoceanManufacturer(manufacturer),
1241 							profile,ttype,Get_Enocean4BSType(0xA5,profile,ttype));
1242  					}
1243 
1244 					// Search the sensor in database
1245 					std::vector<std::vector<std::string> > result;
1246 					result = m_sql.safe_query("SELECT ID FROM EnoceanSensors WHERE (HardwareID==%d) AND (DeviceID=='%q')", m_HwdID, szDeviceID);
1247 					if (result.size()<1)
1248 					{
1249 						// If not found, add it to the database
1250 						m_sql.safe_query("INSERT INTO EnoceanSensors (HardwareID, DeviceID, Manufacturer, Profile, [Type]) VALUES (%d,'%q',%d,%d,%d)", m_HwdID, szDeviceID, manufacturer, profile, ttype);
1251 						_log.Log(LOG_NORM, "EnOcean: Sender_ID 0x%08lX inserted in the database", id);
1252 					}
1253 					else
1254 						_log.Log(LOG_NORM, "EnOcean: Sender_ID 0x%08lX already in the database", id);
1255 					ReloadVLDNodes();
1256 				}
1257 				else	// RORG_4BS_TEACHIN_LRN_BIT is 1 -> Data datagram
1258 				{
1259 					//Following sensors need to have had a teach-in
1260 					std::vector<std::vector<std::string> > result;
1261 					result = m_sql.safe_query("SELECT ID, Manufacturer, Profile, [Type] FROM EnoceanSensors WHERE (HardwareID==%d) AND (DeviceID=='%q')", m_HwdID, szDeviceID);
1262 					if (result.size()<1)
1263 					{
1264 						_log.Log(LOG_NORM, "EnOcean: Need Teach-In for %s", szDeviceID);
1265 						return;
1266 					}
1267 					int Manufacturer=atoi(result[0][1].c_str());
1268 					int Profile=atoi(result[0][2].c_str());
1269 					int iType=atoi(result[0][3].c_str());
1270 
1271 					const std::string szST=Get_Enocean4BSType(0xA5,Profile,iType);
1272 
1273 					if (szST=="AMR.Counter")
1274 					{
1275 						//0xA5, 0x12, 0x00, "Counter"
1276 						unsigned long cvalue=(DATA_BYTE3<<16)|(DATA_BYTE2<<8)|(DATA_BYTE1);
1277 						RBUF tsen;
1278 						memset(&tsen,0,sizeof(RBUF));
1279 						tsen.RFXMETER.packetlength=sizeof(tsen.RFXMETER)-1;
1280 						tsen.RFXMETER.packettype=pTypeRFXMeter;
1281 						tsen.RFXMETER.subtype=sTypeRFXMeterCount;
1282 						tsen.RFXMETER.rssi=12;
1283 						tsen.RFXMETER.id1=ID_BYTE2;
1284 						tsen.RFXMETER.id2=ID_BYTE1;
1285 						tsen.RFXMETER.count1 = (BYTE)((cvalue & 0xFF000000) >> 24);
1286 						tsen.RFXMETER.count2 = (BYTE)((cvalue & 0x00FF0000) >> 16);
1287 						tsen.RFXMETER.count3 = (BYTE)((cvalue & 0x0000FF00) >> 8);
1288 						tsen.RFXMETER.count4 = (BYTE)(cvalue & 0x000000FF);
1289 						sDecodeRXMessage(this, (const unsigned char *)&tsen.RFXMETER, NULL, 255);
1290 					}
1291 					else if (szST=="AMR.Electricity")
1292 					{
1293 						//0xA5, 0x12, 0x01, "Electricity"
1294 						int cvalue=(DATA_BYTE3<<16)|(DATA_BYTE2<<8)|(DATA_BYTE1);
1295 						_tUsageMeter umeter;
1296 						umeter.id1=(BYTE)ID_BYTE3;
1297 						umeter.id2=(BYTE)ID_BYTE2;
1298 						umeter.id3=(BYTE)ID_BYTE1;
1299 						umeter.id4=(BYTE)ID_BYTE0;
1300 						umeter.dunit=1;
1301 						umeter.fusage=(float)cvalue;
1302 						sDecodeRXMessage(this, (const unsigned char *)&umeter, NULL, 255);
1303 					}
1304 					else if (szST=="AMR.Gas")
1305 					{
1306 						//0xA5, 0x12, 0x02, "Gas"
1307 						unsigned long cvalue=(DATA_BYTE3<<16)|(DATA_BYTE2<<8)|(DATA_BYTE1);
1308 						RBUF tsen;
1309 						memset(&tsen,0,sizeof(RBUF));
1310 						tsen.RFXMETER.packetlength=sizeof(tsen.RFXMETER)-1;
1311 						tsen.RFXMETER.packettype=pTypeRFXMeter;
1312 						tsen.RFXMETER.subtype=sTypeRFXMeterCount;
1313 						tsen.RFXMETER.rssi=12;
1314 						tsen.RFXMETER.id1=ID_BYTE2;
1315 						tsen.RFXMETER.id2=ID_BYTE1;
1316 						tsen.RFXMETER.count1 = (BYTE)((cvalue & 0xFF000000) >> 24);
1317 						tsen.RFXMETER.count2 = (BYTE)((cvalue & 0x00FF0000) >> 16);
1318 						tsen.RFXMETER.count3 = (BYTE)((cvalue & 0x0000FF00) >> 8);
1319 						tsen.RFXMETER.count4 = (BYTE)(cvalue & 0x000000FF);
1320 						sDecodeRXMessage(this, (const unsigned char *)&tsen.RFXMETER, NULL, 255);
1321 					}
1322 					else if (szST=="AMR.Water")
1323 					{
1324 						//0xA5, 0x12, 0x03, "Water"
1325 						unsigned long cvalue=(DATA_BYTE3<<16)|(DATA_BYTE2<<8)|(DATA_BYTE1);
1326 						RBUF tsen;
1327 						memset(&tsen,0,sizeof(RBUF));
1328 						tsen.RFXMETER.packetlength=sizeof(tsen.RFXMETER)-1;
1329 						tsen.RFXMETER.packettype=pTypeRFXMeter;
1330 						tsen.RFXMETER.subtype=sTypeRFXMeterCount;
1331 						tsen.RFXMETER.rssi=12;
1332 						tsen.RFXMETER.id1=ID_BYTE2;
1333 						tsen.RFXMETER.id2=ID_BYTE1;
1334 						tsen.RFXMETER.count1 = (BYTE)((cvalue & 0xFF000000) >> 24);
1335 						tsen.RFXMETER.count2 = (BYTE)((cvalue & 0x00FF0000) >> 16);
1336 						tsen.RFXMETER.count3 = (BYTE)((cvalue & 0x0000FF00) >> 8);
1337 						tsen.RFXMETER.count4 = (BYTE)(cvalue & 0x000000FF);
1338 						sDecodeRXMessage(this, (const unsigned char *)&tsen.RFXMETER, NULL, 255);
1339 					}
1340 					else if (szST.find("RoomOperatingPanel") == 0)
1341 					{
1342 						if (iType<0x0E)
1343 						{
1344 							// Room Sensor and Control Unit (EEP A5-10-01 ... A5-10-0D)
1345 							// [Eltako FTR55D, FTR55H, Thermokon SR04 *, Thanos SR *, untested]
1346 							// DATA_BYTE3 is the fan speed or night reduction for Eltako
1347 							// DATA_BYTE2 is the setpoint where 0x00 = min ... 0xFF = max or
1348 							// reference temperature for Eltako where 0x00 = 0°C ... 0xFF = 40°C
1349 							// DATA_BYTE1 is the temperature where 0x00 = +40°C ... 0xFF = 0°C
1350 							// DATA_BYTE0_bit_0 is the occupy button, pushbutton or slide switch
1351 							float temp=GetValueRange(DATA_BYTE1,0,40);
1352 							if (Manufacturer == 0x0D)
1353 							{
1354 								//Eltako
1355 								int nightReduction = 0;
1356 								if (DATA_BYTE3 == 0x06)
1357 									nightReduction = 1;
1358 								else if (DATA_BYTE3 == 0x0C)
1359 									nightReduction = 2;
1360 								else if (DATA_BYTE3 == 0x13)
1361 									nightReduction = 3;
1362 								else if (DATA_BYTE3 == 0x19)
1363 									nightReduction = 4;
1364 								else if (DATA_BYTE3 == 0x1F)
1365 									nightReduction = 5;
1366 								//float setpointTemp=GetValueRange(DATA_BYTE2,40);
1367 							}
1368 							else
1369 							{
1370 								int fspeed = 3;
1371 								if (DATA_BYTE3 >= 145)
1372 									fspeed = 2;
1373 								else if (DATA_BYTE3 >= 165)
1374 									fspeed = 1;
1375 								else if (DATA_BYTE3 >= 190)
1376 									fspeed = 0;
1377 								else if (DATA_BYTE3 >= 210)
1378 									fspeed = -1; //auto
1379 								//int iswitch = DATA_BYTE0 & 1;
1380 							}
1381 							RBUF tsen;
1382 							memset(&tsen,0,sizeof(RBUF));
1383 							tsen.TEMP.packetlength=sizeof(tsen.TEMP)-1;
1384 							tsen.TEMP.packettype=pTypeTEMP;
1385 							tsen.TEMP.subtype=sTypeTEMP10;
1386 							tsen.TEMP.id1=ID_BYTE2;
1387 							tsen.TEMP.id2=ID_BYTE1;
1388 							tsen.TEMP.battery_level=ID_BYTE0&0x0F;
1389 							tsen.TEMP.rssi=(ID_BYTE0&0xF0)>>4;
1390 
1391 							tsen.TEMP.tempsign=(temp>=0)?0:1;
1392 							int at10=round(std::abs(temp*10.0f));
1393 							tsen.TEMP.temperatureh=(BYTE)(at10/256);
1394 							at10-=(tsen.TEMP.temperatureh*256);
1395 							tsen.TEMP.temperaturel=(BYTE)(at10);
1396 							sDecodeRXMessage(this, (const unsigned char *)&tsen.TEMP, NULL, -1);
1397 						}
1398 					}
1399 					else if (szST == "LightSensor.01")
1400 					{
1401 						// Light Sensor (EEP A5-06-01)
1402 						// [Eltako FAH60, FAH63, FIH63, Thermokon SR65 LI, untested]
1403 						// DATA_BYTE3 is the voltage where 0x00 = 0 V ... 0xFF = 5.1 V
1404 						// DATA_BYTE3 is the low illuminance for Eltako devices where
1405 						// min 0x00 = 0 lx, max 0xFF = 100 lx, if DATA_BYTE2 = 0
1406 						// DATA_BYTE2 is the illuminance (ILL2) where min 0x00 = 300 lx, max 0xFF = 30000 lx
1407 						// DATA_BYTE1 is the illuminance (ILL1) where min 0x00 = 600 lx, max 0xFF = 60000 lx
1408 						// DATA_BYTE0_bit_0 is Range select where 0 = ILL1, 1 = ILL2
1409 						float lux =0;
1410 						if (Manufacturer == 0x0D)
1411 						{
1412 							if(DATA_BYTE2 == 0) {
1413 								lux=GetValueRange(DATA_BYTE3,100);
1414 							} else {
1415 								lux=GetValueRange(DATA_BYTE2,30000,300);
1416 							}
1417 						} else {
1418 							float voltage=GetValueRange(DATA_BYTE3,5100); //mV
1419 							if(DATA_BYTE0 & 1) {
1420 								lux=GetValueRange(DATA_BYTE2,30000,300);
1421 							} else {
1422 								lux=GetValueRange(DATA_BYTE1,60000,600);
1423 							}
1424 							RBUF tsen;
1425 							memset(&tsen,0,sizeof(RBUF));
1426 							tsen.RFXSENSOR.packetlength=sizeof(tsen.RFXSENSOR)-1;
1427 							tsen.RFXSENSOR.packettype=pTypeRFXSensor;
1428 							tsen.RFXSENSOR.subtype=sTypeRFXSensorVolt;
1429 							tsen.RFXSENSOR.id=ID_BYTE1;
1430 							tsen.RFXSENSOR.filler=ID_BYTE0&0x0F;
1431 							tsen.RFXSENSOR.rssi=(ID_BYTE0&0xF0)>>4;
1432 							tsen.RFXSENSOR.msg1 = (BYTE)(voltage/256);
1433 							tsen.RFXSENSOR.msg2 = (BYTE)(voltage-(tsen.RFXSENSOR.msg1*256));
1434 							sDecodeRXMessage(this, (const unsigned char *)&tsen.RFXSENSOR, NULL, 255);
1435 						}
1436 						_tLightMeter lmeter;
1437 						lmeter.id1=(BYTE)ID_BYTE3;
1438 						lmeter.id2=(BYTE)ID_BYTE2;
1439 						lmeter.id3=(BYTE)ID_BYTE1;
1440 						lmeter.id4=(BYTE)ID_BYTE0;
1441 						lmeter.dunit=1;
1442 						lmeter.fLux=lux;
1443 						sDecodeRXMessage(this, (const unsigned char *)&lmeter, NULL, 255);
1444 					}
1445 					else if (szST.find("Temperature")==0)
1446 					{
1447 						//(EPP A5-02 01/30)
1448 						float ScaleMax=0;
1449 						float ScaleMin=0;
1450 						if (iType==0x01) { ScaleMin=-40; ScaleMax=0; }
1451 						else if (iType==0x02) { ScaleMin=-30; ScaleMax=10; }
1452 						else if (iType==0x03) { ScaleMin=-20; ScaleMax=20; }
1453 						else if (iType==0x04) { ScaleMin=-10; ScaleMax=30; }
1454 						else if (iType==0x05) { ScaleMin=0; ScaleMax=40; }
1455 						else if (iType==0x06) { ScaleMin=10; ScaleMax=50; }
1456 						else if (iType==0x07) { ScaleMin=20; ScaleMax=60; }
1457 						else if (iType==0x08) { ScaleMin=30; ScaleMax=70; }
1458 						else if (iType==0x09) { ScaleMin=40; ScaleMax=80; }
1459 						else if (iType==0x0A) { ScaleMin=50; ScaleMax=90; }
1460 						else if (iType==0x0B) { ScaleMin=60; ScaleMax=100; }
1461 						else if (iType==0x10) { ScaleMin=-60; ScaleMax=20; }
1462 						else if (iType==0x11) { ScaleMin=-50; ScaleMax=30; }
1463 						else if (iType==0x12) { ScaleMin=-40; ScaleMax=40; }
1464 						else if (iType==0x13) { ScaleMin=-30; ScaleMax=50; }
1465 						else if (iType==0x14) { ScaleMin=-20; ScaleMax=60; }
1466 						else if (iType==0x15) { ScaleMin=-10; ScaleMax=70; }
1467 						else if (iType==0x16) { ScaleMin=0; ScaleMax=80; }
1468 						else if (iType==0x17) { ScaleMin=10; ScaleMax=90; }
1469 						else if (iType==0x18) { ScaleMin=20; ScaleMax=100; }
1470 						else if (iType==0x19) { ScaleMin=30; ScaleMax=110; }
1471 						else if (iType==0x1A) { ScaleMin=40; ScaleMax=120; }
1472 						else if (iType==0x1B) { ScaleMin=50; ScaleMax=130; }
1473 						else if (iType==0x20) { ScaleMin=-10; ScaleMax=41.2f; }
1474 						else if (iType==0x30) { ScaleMin=-40; ScaleMax=62.3f; }
1475 
1476 						float temp;
1477 						if (iType<0x20)
1478 							temp=GetValueRange(DATA_BYTE1,ScaleMax,ScaleMin,0,255);
1479 						else
1480 							temp=GetValueRange(float(((DATA_BYTE2&3)<<8)|DATA_BYTE1),ScaleMax,ScaleMin); //10bit
1481 						RBUF tsen;
1482 						memset(&tsen,0,sizeof(RBUF));
1483 						tsen.TEMP.packetlength=sizeof(tsen.TEMP)-1;
1484 						tsen.TEMP.packettype=pTypeTEMP;
1485 						tsen.TEMP.subtype=sTypeTEMP10;
1486 						tsen.TEMP.id1=ID_BYTE2;
1487 						tsen.TEMP.id2=ID_BYTE1;
1488 						tsen.TEMP.battery_level=ID_BYTE0&0x0F;
1489 						tsen.TEMP.rssi=(ID_BYTE0&0xF0)>>4;
1490 
1491 						tsen.TEMP.tempsign=(temp>=0)?0:1;
1492 						int at10=round(std::abs(temp*10.0f));
1493 						tsen.TEMP.temperatureh=(BYTE)(at10/256);
1494 						at10-=(tsen.TEMP.temperatureh*256);
1495 						tsen.TEMP.temperaturel=(BYTE)(at10);
1496 						sDecodeRXMessage(this, (const unsigned char *)&tsen.TEMP, NULL, -1);
1497 					}
1498 					else if (szST.find("TempHum")==0)
1499 					{
1500 						//(EPP A5-04 01/02)
1501 						float ScaleMax = 0;
1502 						float ScaleMin = 0;
1503 						if (iType == 0x01) { ScaleMin = 0; ScaleMax = 40; }
1504 						else if (iType == 0x02) { ScaleMin = -20; ScaleMax = 60; }
1505 						else if (iType == 0x03) { ScaleMin = -20; ScaleMax = 60; } //10bit?
1506 
1507 						float temp = GetValueRange(DATA_BYTE1, ScaleMax, ScaleMin,250,0);
1508 						float hum = GetValueRange(DATA_BYTE2, 100);
1509 						RBUF tsen;
1510 						memset(&tsen,0,sizeof(RBUF));
1511 						tsen.TEMP_HUM.packetlength=sizeof(tsen.TEMP_HUM)-1;
1512 						tsen.TEMP_HUM.packettype=pTypeTEMP_HUM;
1513 						tsen.TEMP_HUM.subtype=sTypeTH5;
1514 						tsen.TEMP_HUM.rssi=12;
1515 						tsen.TEMP_HUM.id1=ID_BYTE2;
1516 						tsen.TEMP_HUM.id2=ID_BYTE1;
1517 						tsen.TEMP_HUM.battery_level=9;
1518 						tsen.TEMP_HUM.tempsign=(temp>=0)?0:1;
1519 						int at10=round(std::abs(temp*10.0f));
1520 						tsen.TEMP_HUM.temperatureh=(BYTE)(at10/256);
1521 						at10-=(tsen.TEMP_HUM.temperatureh*256);
1522 						tsen.TEMP_HUM.temperaturel=(BYTE)(at10);
1523 						tsen.TEMP_HUM.humidity=(BYTE)hum;
1524 						tsen.TEMP_HUM.humidity_status=Get_Humidity_Level(tsen.TEMP_HUM.humidity);
1525 						sDecodeRXMessage(this, (const unsigned char *)&tsen.TEMP_HUM, NULL, -1);
1526 					}
1527 					else if (szST == "OccupancySensor.01")
1528 					{
1529 						//(EPP A5-07-01)
1530 						if (DATA_BYTE3 < 251)
1531 						{
1532 							RBUF tsen;
1533 
1534 							if (DATA_BYTE0 & 1)
1535 							{
1536 								//Voltage supported
1537 								float voltage = GetValueRange(DATA_BYTE3, 5.0f, 0, 250, 0);
1538 								memset(&tsen, 0, sizeof(RBUF));
1539 								tsen.RFXSENSOR.packetlength = sizeof(tsen.RFXSENSOR) - 1;
1540 								tsen.RFXSENSOR.packettype = pTypeRFXSensor;
1541 								tsen.RFXSENSOR.subtype = sTypeRFXSensorVolt;
1542 								tsen.RFXSENSOR.id = ID_BYTE1;
1543 								tsen.RFXSENSOR.filler = ID_BYTE0 & 0x0F;
1544 								tsen.RFXSENSOR.rssi = (ID_BYTE0 & 0xF0) >> 4;
1545 								tsen.RFXSENSOR.msg1 = (BYTE)(voltage / 256);
1546 								tsen.RFXSENSOR.msg2 = (BYTE)(voltage - (tsen.RFXSENSOR.msg1 * 256));
1547 								sDecodeRXMessage(this, (const unsigned char *)&tsen.RFXSENSOR, NULL, 255);
1548 							}
1549 
1550 							bool bPIROn = (DATA_BYTE1 > 127);
1551 							memset(&tsen, 0, sizeof(RBUF));
1552 							tsen.LIGHTING2.packetlength = sizeof(tsen.LIGHTING2) - 1;
1553 							tsen.LIGHTING2.packettype = pTypeLighting2;
1554 							tsen.LIGHTING2.subtype = sTypeAC;
1555 							tsen.LIGHTING2.seqnbr = 0;
1556 
1557 							tsen.LIGHTING2.id1 = (BYTE)ID_BYTE3;
1558 							tsen.LIGHTING2.id2 = (BYTE)ID_BYTE2;
1559 							tsen.LIGHTING2.id3 = (BYTE)ID_BYTE1;
1560 							tsen.LIGHTING2.id4 = (BYTE)ID_BYTE0;
1561 							tsen.LIGHTING2.level = 0;
1562 							tsen.LIGHTING2.rssi = 12;
1563 							tsen.LIGHTING2.unitcode = 1;
1564 							tsen.LIGHTING2.cmnd = (bPIROn) ? light2_sOn : light2_sOff;
1565 							sDecodeRXMessage(this, (const unsigned char *)&tsen.LIGHTING2, NULL, 255);
1566 						}
1567 						else {
1568 							//Error code
1569 						}
1570 					}
1571 					else if (szST == "OccupancySensor.02")
1572 					{
1573 						//(EPP A5-07-02)
1574 						if (DATA_BYTE3 < 251)
1575 						{
1576 							RBUF tsen;
1577 
1578 							float voltage = GetValueRange(DATA_BYTE3, 5.0f, 0, 250, 0);
1579 							memset(&tsen, 0, sizeof(RBUF));
1580 							tsen.RFXSENSOR.packetlength = sizeof(tsen.RFXSENSOR) - 1;
1581 							tsen.RFXSENSOR.packettype = pTypeRFXSensor;
1582 							tsen.RFXSENSOR.subtype = sTypeRFXSensorVolt;
1583 							tsen.RFXSENSOR.id = ID_BYTE1;
1584 							tsen.RFXSENSOR.filler = ID_BYTE0 & 0x0F;
1585 							tsen.RFXSENSOR.rssi = (ID_BYTE0 & 0xF0) >> 4;
1586 							tsen.RFXSENSOR.msg1 = (BYTE)(voltage / 256);
1587 							tsen.RFXSENSOR.msg2 = (BYTE)(voltage - (tsen.RFXSENSOR.msg1 * 256));
1588 							sDecodeRXMessage(this, (const unsigned char *)&tsen.RFXSENSOR, NULL, 255);
1589 
1590 							bool bPIROn = (DATA_BYTE0 & 0x80)!=0;
1591 							memset(&tsen, 0, sizeof(RBUF));
1592 							tsen.LIGHTING2.packetlength = sizeof(tsen.LIGHTING2) - 1;
1593 							tsen.LIGHTING2.packettype = pTypeLighting2;
1594 							tsen.LIGHTING2.subtype = sTypeAC;
1595 							tsen.LIGHTING2.seqnbr = 0;
1596 
1597 							tsen.LIGHTING2.id1 = (BYTE)ID_BYTE3;
1598 							tsen.LIGHTING2.id2 = (BYTE)ID_BYTE2;
1599 							tsen.LIGHTING2.id3 = (BYTE)ID_BYTE1;
1600 							tsen.LIGHTING2.id4 = (BYTE)ID_BYTE0;
1601 							tsen.LIGHTING2.level = 0;
1602 							tsen.LIGHTING2.rssi = 12;
1603 							tsen.LIGHTING2.unitcode = 1;
1604 							tsen.LIGHTING2.cmnd = (bPIROn) ? light2_sOn : light2_sOff;
1605 							sDecodeRXMessage(this, (const unsigned char *)&tsen.LIGHTING2, NULL, 255);
1606 						}
1607 						else {
1608 							//Error code
1609 						}
1610 					}
1611 					else if (szST == "OccupancySensor.03")
1612 					{
1613 						//(EPP A5-07-03)
1614 						if (DATA_BYTE3 < 251)
1615 						{
1616 							RBUF tsen;
1617 
1618 							float voltage = GetValueRange(DATA_BYTE3, 5.0f, 0, 250, 0);
1619 							memset(&tsen, 0, sizeof(RBUF));
1620 							tsen.RFXSENSOR.packetlength = sizeof(tsen.RFXSENSOR) - 1;
1621 							tsen.RFXSENSOR.packettype = pTypeRFXSensor;
1622 							tsen.RFXSENSOR.subtype = sTypeRFXSensorVolt;
1623 							tsen.RFXSENSOR.id = ID_BYTE1;
1624 							tsen.RFXSENSOR.filler = ID_BYTE0 & 0x0F;
1625 							tsen.RFXSENSOR.rssi = (ID_BYTE0 & 0xF0) >> 4;
1626 							tsen.RFXSENSOR.msg1 = (BYTE)(voltage / 256);
1627 							tsen.RFXSENSOR.msg2 = (BYTE)(voltage - (tsen.RFXSENSOR.msg1 * 256));
1628 							sDecodeRXMessage(this, (const unsigned char *)&tsen.RFXSENSOR, NULL, 255);
1629 
1630 							int lux = (DATA_BYTE2 << 2) | (DATA_BYTE1>>6);
1631 							if (lux > 1000)
1632 								lux = 1000;
1633 							_tLightMeter lmeter;
1634 							lmeter.id1 = (BYTE)ID_BYTE3;
1635 							lmeter.id2 = (BYTE)ID_BYTE2;
1636 							lmeter.id3 = (BYTE)ID_BYTE1;
1637 							lmeter.id4 = (BYTE)ID_BYTE0;
1638 							lmeter.dunit = 1;
1639 							lmeter.fLux = (float)lux;
1640 							sDecodeRXMessage(this, (const unsigned char *)&lmeter, NULL, 255);
1641 
1642 							bool bPIROn = (DATA_BYTE0 & 0x80)!=0;
1643 							memset(&tsen, 0, sizeof(RBUF));
1644 							tsen.LIGHTING2.packetlength = sizeof(tsen.LIGHTING2) - 1;
1645 							tsen.LIGHTING2.packettype = pTypeLighting2;
1646 							tsen.LIGHTING2.subtype = sTypeAC;
1647 							tsen.LIGHTING2.seqnbr = 0;
1648 
1649 							tsen.LIGHTING2.id1 = (BYTE)ID_BYTE3;
1650 							tsen.LIGHTING2.id2 = (BYTE)ID_BYTE2;
1651 							tsen.LIGHTING2.id3 = (BYTE)ID_BYTE1;
1652 							tsen.LIGHTING2.id4 = (BYTE)ID_BYTE0;
1653 							tsen.LIGHTING2.level = 0;
1654 							tsen.LIGHTING2.rssi = 12;
1655 							tsen.LIGHTING2.unitcode = 1;
1656 							tsen.LIGHTING2.cmnd = (bPIROn) ? light2_sOn : light2_sOff;
1657 							sDecodeRXMessage(this, (const unsigned char *)&tsen.LIGHTING2, NULL, 255);
1658 						}
1659 						else {
1660 							//Error code
1661 						}
1662 					}
1663 					else if (szST.find("GasSensor.04")==0)
1664 					{
1665 						//(EPP A5-09-04 CO2 Gas Sensor with Temp and Humidity)
1666 						// DB3 = Humidity in 0.5% steps, 0...200 -> 0...100% RH (0x51 = 40%)
1667 						// DB2 = CO2 concentration in 10 ppm steps, 0...255 -> 0...2550 ppm (0x39 = 570 ppm)
1668 						// DB1 = Temperature in 0.2C steps, 0...255 -> 0...51 C (0x7B = 24.6 C)
1669 						// DB0 = flags (DB0.3: 1=data, 0=teach-in; DB0.2: 1=Hum Sensor available, 0=no Hum; DB0.1: 1=Temp sensor available, 0=No Temp; DB0.0 not used)
1670 						// mBuffer[15] is RSSI as -dBm (ie value of 100 means "-100 dBm"), but RssiLevel is in the range 0...15 (or reported as 12 if not known)
1671 						// Battery level is not reported by device, so use fixed value of 9 as per other sensor functions
1672 
1673 						// TODO: Check sensor availability flags and only report humidity and/or temp if available.
1674 						// TODO: Report actual RSSI (scaled from dBm to 0...15 RSSI ?)
1675 
1676 						float temp = GetValueRange(DATA_BYTE1, 51, 0, 255, 0);
1677 						float hum = GetValueRange(DATA_BYTE3, 100, 0, 200, 0);
1678 						int co2 = (int)GetValueRange(DATA_BYTE2, 2550, 0, 255, 0);
1679 						int NodeID = (ID_BYTE2 << 8) + ID_BYTE1;
1680 
1681 						// Report battery level as 9 and RSSI as 12
1682 						SendTempHumSensor(NodeID, 9, temp, round(hum), "GasSensor.04", 12);
1683 						SendAirQualitySensor((NodeID & 0xFF00) >> 8, NodeID & 0xFF, 9, co2, "GasSensor.04");
1684 					}
1685 				}
1686 			}
1687 			break;
1688 		case RORG_RPS: // repeated switch communication
1689 			{
1690 #ifdef ENOCEAN_BUTTON_DEBUG
1691 				sprintf(szTmp, "RPS data: Sender id: 0x%02x%02x%02x%02x Status: %02x Data: %02x",
1692 					m_buffer[2],m_buffer[3],m_buffer[4],m_buffer[5],
1693 					m_buffer[6],
1694 					m_buffer[1]
1695 				);
1696 				_log.Log(LOG_NORM, "EnOcean: %s", szTmp);
1697 				if (m_buffer[6] & (1 << 2))
1698 				{
1699 					_log.Log(LOG_NORM, "EnOcean: T21");
1700 				}
1701 #endif // ENOCEAN_BUTTON_DEBUG
1702 
1703 				unsigned char STATUS=m_buffer[6];
1704 
1705 				unsigned char T21 = (m_buffer[6] & S_RPS_T21) >> S_RPS_T21_SHIFT;
1706 				unsigned char NU = (m_buffer[6] & S_RPS_NU) >> S_RPS_NU_SHIFT;
1707 
1708 				unsigned char ID_BYTE3=m_buffer[2];
1709 				unsigned char ID_BYTE2=m_buffer[3];
1710 				unsigned char ID_BYTE1=m_buffer[4];
1711 				unsigned char ID_BYTE0=m_buffer[5];
1712 				long id = (ID_BYTE3 << 24) + (ID_BYTE2 << 16) + (ID_BYTE1 << 8) + ID_BYTE0;
1713 				char szDeviceID[20];
1714 				sprintf(szDeviceID,"%08X",(unsigned int)id);
1715 
1716 				// if a button is attached to a module, we should ignore it else its datagram will conflict with status reported by the module using VLD datagram
1717 				std::vector<std::vector<std::string> > result;
1718 				result = m_sql.safe_query("SELECT ID, Profile, [Type] FROM EnoceanSensors WHERE (HardwareID==%d) AND (DeviceID=='%q')", m_HwdID, szDeviceID);
1719 				if (result.size() == 1)
1720 				{
1721 					// hardware device was already teached-in
1722 					int Profile=atoi(result[0][1].c_str());
1723 					int iType=atoi(result[0][2].c_str());
1724 					if( (Profile == 0x01) &&						// profile 1 (D2-01) is Electronic switches and dimmers with Energy Measurement and Local Control
1725 						 ((iType == 0x0F) || (iType == 0x12))	// type 0F and 12 have external switch/push button control, it means they also act as rocker
1726 						)
1727 					{
1728 #ifdef ENOCEAN_BUTTON_DEBUG
1729 						_log.Log(LOG_STATUS,"EnOcean: %s, ignore button press", szDeviceID);
1730 #endif // ENOCEAN_BUTTON_DEBUG
1731 						break;
1732 					}
1733 				}
1734 
1735 				// Whether we use the ButtonID reporting with ON/OFF
1736 				bool useButtonIDs = true;
1737 
1738 				if (STATUS & S_RPS_NU)
1739 				{
1740 					//Rocker
1741 
1742 					unsigned char DATA_BYTE3=m_buffer[1];
1743 
1744 					// NU == 1, N-Message
1745 					unsigned char ButtonID = (DATA_BYTE3 & DB3_RPS_NU_BID) >> DB3_RPS_NU_BID_SHIFT;
1746 					unsigned char RockerID = (DATA_BYTE3 & DB3_RPS_NU_RID) >> DB3_RPS_NU_RID_SHIFT;
1747 					unsigned char UpDown=(DATA_BYTE3 & DB3_RPS_NU_UD)  >> DB3_RPS_NU_UD_SHIFT;
1748 					unsigned char Pressed=(DATA_BYTE3 & DB3_RPS_NU_PR) >> DB3_RPS_NU_PR_SHIFT;
1749 
1750 					unsigned char SecondButtonID = (DATA_BYTE3 & DB3_RPS_NU_SBID) >> DB3_RPS_NU_SBID_SHIFT;
1751 					unsigned char SecondRockerID = (DATA_BYTE3 & DB3_RPS_NU_SRID) >> DB3_RPS_NU_SRID_SHIFT;
1752 					unsigned char SecondUpDown=(DATA_BYTE3 & DB3_RPS_NU_SUD)>>DB3_RPS_NU_SUD_SHIFT;
1753 					unsigned char SecondAction=(DATA_BYTE3 & DB3_RPS_NU_SA)>>DB3_RPS_NU_SA_SHIFT;
1754 
1755 #ifdef ENOCEAN_BUTTON_DEBUG
1756 					_log.Log(LOG_NORM,
1757 						"EnOcean: Received RPS N-Message   message: 0x%02X Node 0x%08x RockerID: %i ButtonID: %i Pressed: %i UD: %i Second Rocker ID: %i SecondButtonID: %i SUD: %i Second Action: %i",
1758 						DATA_BYTE3,
1759 						id,
1760 						RockerID,
1761 						ButtonID,
1762 						UpDown,
1763 						Pressed,
1764 						SecondRockerID,
1765 						SecondButtonID,
1766 						SecondUpDown,
1767 						SecondAction);
1768 #endif // ENOCEAN_BUTTON_DEBUG
1769 
1770 					//We distinguish 3 types of buttons from a switch: Left/Right/Left+Right
1771 					if (Pressed==1)
1772 					{
1773 						RBUF tsen;
1774 						memset(&tsen,0,sizeof(RBUF));
1775 						tsen.LIGHTING2.packetlength=sizeof(tsen.LIGHTING2)-1;
1776 						tsen.LIGHTING2.packettype=pTypeLighting2;
1777 						tsen.LIGHTING2.subtype=sTypeAC;
1778 						tsen.LIGHTING2.seqnbr=0;
1779 
1780 						tsen.LIGHTING2.id1=(BYTE)ID_BYTE3;
1781 						tsen.LIGHTING2.id2=(BYTE)ID_BYTE2;
1782 						tsen.LIGHTING2.id3=(BYTE)ID_BYTE1;
1783 						tsen.LIGHTING2.id4=(BYTE)ID_BYTE0;
1784 						tsen.LIGHTING2.level=0;
1785 						tsen.LIGHTING2.rssi=12;
1786 
1787 						if (SecondAction==0)
1788 						{
1789 							if (useButtonIDs)
1790 							{
1791 								//Left/Right Pressed
1792 								tsen.LIGHTING2.unitcode = ButtonID + 1;
1793 								tsen.LIGHTING2.cmnd     = light2_sOn; // the button is pressed, so we don't get an OFF message here
1794 							}
1795 							else
1796 							{
1797 								//Left/Right Up/Down
1798 								tsen.LIGHTING2.unitcode = RockerID + 1;
1799 								tsen.LIGHTING2.cmnd     = (UpDown == 1) ? light2_sOn : light2_sOff;
1800 							}
1801 						}
1802 						else
1803 						{
1804 							if (useButtonIDs)
1805 							{
1806 								//Left+Right Pressed
1807 								tsen.LIGHTING2.unitcode = ButtonID + 10;
1808 								tsen.LIGHTING2.cmnd     = light2_sOn;  // the button is pressed, so we don't get an OFF message here
1809 							}
1810 							else
1811 							{
1812 								//Left+Right Up/Down
1813 								tsen.LIGHTING2.unitcode = SecondRockerID + 10;
1814 								tsen.LIGHTING2.cmnd     = (SecondUpDown == 1) ? light2_sOn : light2_sOff;
1815 							}
1816 						}
1817 
1818 #ifdef ENOCEAN_BUTTON_DEBUG
1819 						_log.Log(LOG_NORM, "EnOcean message: 0x%02X Node 0x%08x UnitID: %02X cmd: %02X ",
1820 							DATA_BYTE3,
1821 							id,
1822 							tsen.LIGHTING2.unitcode,
1823 							tsen.LIGHTING2.cmnd
1824 							);
1825 #endif //ENOCEAN_BUTTON_DEBUG
1826 
1827 						sDecodeRXMessage(this, (const unsigned char *)&tsen.LIGHTING2, NULL, 255);
1828 					}
1829 				}
1830 				else
1831 				{
1832 					if ((T21 == 1) && (NU == 0))
1833 					{
1834 						unsigned char DATA_BYTE3 = m_buffer[1];
1835 
1836 						unsigned char ButtonID = (DATA_BYTE3 & DB3_RPS_BUTTONS) >> DB3_RPS_BUTTONS_SHIFT;
1837 						unsigned char Pressed = (DATA_BYTE3 & DB3_RPS_PR) >> DB3_RPS_PR_SHIFT;
1838 
1839 						unsigned char UpDown = !((DATA_BYTE3 == 0xD0) || (DATA_BYTE3 == 0xF0));
1840 
1841 #ifdef ENOCEAN_BUTTON_DEBUG
1842 						_log.Log(LOG_NORM, "EnOcean: Received RPS T21-Message message: 0x%02X Node 0x%08x ButtonID: %i Pressed: %i UD: %i",
1843 							DATA_BYTE3,
1844 							id,
1845 							ButtonID,
1846 							Pressed,
1847 							UpDown);
1848 #endif //ENOCEAN_BUTTON_DEBUG
1849 
1850 						RBUF tsen;
1851 						memset(&tsen, 0, sizeof(RBUF));
1852 						tsen.LIGHTING2.packetlength = sizeof(tsen.LIGHTING2) - 1;
1853 						tsen.LIGHTING2.packettype = pTypeLighting2;
1854 						tsen.LIGHTING2.subtype = sTypeAC;
1855 						tsen.LIGHTING2.seqnbr = 0;
1856 
1857 						tsen.LIGHTING2.id1 = (BYTE)ID_BYTE3;
1858 						tsen.LIGHTING2.id2 = (BYTE)ID_BYTE2;
1859 						tsen.LIGHTING2.id3 = (BYTE)ID_BYTE1;
1860 						tsen.LIGHTING2.id4 = (BYTE)ID_BYTE0;
1861 						tsen.LIGHTING2.level = 0;
1862 						tsen.LIGHTING2.rssi = 12;
1863 
1864 						if (useButtonIDs)
1865 						{
1866 							// It's the release message of any button pressed before
1867 							tsen.LIGHTING2.unitcode = 0; // does not matter, since we are using a group command
1868 							tsen.LIGHTING2.cmnd = (Pressed == 1) ? light2_sGroupOn : light2_sGroupOff;
1869 						}
1870 						else
1871 						{
1872 							tsen.LIGHTING2.unitcode = 1;
1873 							tsen.LIGHTING2.cmnd = (UpDown == 1) ? light2_sOn : light2_sOff;
1874 						}
1875 #ifdef ENOCEAN_BUTTON_DEBUG
1876 
1877 						_log.Log(LOG_NORM, "EnOcean message: 0x%02X Node 0x%08x UnitID: %02X cmd: %02X ",
1878 							DATA_BYTE3,
1879 							id,
1880 							tsen.LIGHTING2.unitcode,
1881 							tsen.LIGHTING2.cmnd);
1882 
1883 #endif // ENOCEAN_BUTTON_DEBUG
1884 
1885 						sDecodeRXMessage(this, (const unsigned char *)&tsen.LIGHTING2, NULL, 255);
1886 					}
1887 				}
1888 			}
1889 			break;
1890 
1891 		case RORG_UTI:
1892 				// Universal teach-in (0xD4)
1893 				{
1894 					unsigned char uni_bi_directional_communication = (m_buffer[1] >> 7) & 1;		// 0=mono, 1= bi
1895 					unsigned char eep_teach_in_response_expected = (m_buffer[1] >> 6) & 1;			// 0=yes, 1=no
1896 					unsigned char teach_in_request = (m_buffer[1] >> 4) & 3;								// 0= request, 1= deletion request, 2=request or deletion request, 3=not used
1897 					unsigned char cmd = m_buffer[1] & 0x0F;
1898 
1899 					if(cmd == 0x0)
1900 					{
1901 						// EEP Teach-In Query (UTE Message / CMD 0x0)
1902 
1903 						unsigned char nb_channel = m_buffer[2];
1904 						unsigned int manID = ((unsigned int)(m_buffer[4] & 0x7)) << 8 | (m_buffer[3]);
1905 						unsigned char type = m_buffer[5];
1906 						unsigned char func = m_buffer[6];
1907 						unsigned char rorg = m_buffer[7];
1908 
1909 						unsigned char ID_BYTE3=m_buffer[8];
1910 						unsigned char ID_BYTE2=m_buffer[9];
1911 						unsigned char ID_BYTE1=m_buffer[10];
1912 						unsigned char ID_BYTE0=m_buffer[11];
1913 						long id = (ID_BYTE3 << 24) + (ID_BYTE2 << 16) + (ID_BYTE1 << 8) + ID_BYTE0;
1914 
1915 						_log.Log(LOG_NORM, "EnOcean: teach-in request received from %08lX (manufacturer: %03X). number of channels: %d, device profile: %02X-%02X-%02X", id, manID, nb_channel, rorg,func,type);
1916 
1917 						// Record EnOcean device profile
1918 						{
1919 							char szDeviceID[20];
1920 							std::vector<std::vector<std::string> > result;
1921 							sprintf(szDeviceID,"%08X",(unsigned int)id);
1922 							result = m_sql.safe_query("SELECT ID FROM EnoceanSensors WHERE (HardwareID==%d) AND (DeviceID=='%q')", m_HwdID, szDeviceID);
1923 							if (result.size()<1)
1924 							{
1925 								// If not found, add it to the database
1926 								m_sql.safe_query("INSERT INTO EnoceanSensors (HardwareID, DeviceID, Manufacturer, Profile, [Type]) VALUES (%d,'%q',%d,%d,%d)", m_HwdID, szDeviceID, manID, func, type);
1927 								_log.Log(LOG_NORM, "EnOcean: Sender_ID 0x%08lX inserted in the database", id);
1928 							}
1929 							else
1930 								_log.Log(LOG_NORM, "EnOcean: Sender_ID 0x%08lX already in the database", id);
1931 							ReloadVLDNodes();
1932 						}
1933 
1934 						if((rorg == 0xD2) && (func == 0x01) && ( (type == 0x12) || (type == 0x0F) ))
1935 						{
1936 							unsigned char nbc;
1937 
1938 							for(nbc = 0; nbc < nb_channel; nbc ++)
1939 							{
1940 								RBUF tsen;
1941 
1942 								memset(&tsen,0,sizeof(RBUF));
1943 								tsen.LIGHTING2.packetlength=sizeof(tsen.LIGHTING2)-1;
1944 								tsen.LIGHTING2.packettype=pTypeLighting2;
1945 								tsen.LIGHTING2.subtype=sTypeAC;
1946 								tsen.LIGHTING2.seqnbr=0;
1947 
1948 								tsen.LIGHTING2.id1=(BYTE)ID_BYTE3;
1949 								tsen.LIGHTING2.id2=(BYTE)ID_BYTE2;
1950 								tsen.LIGHTING2.id3=(BYTE)ID_BYTE1;
1951 								tsen.LIGHTING2.id4=(BYTE)ID_BYTE0;
1952 								tsen.LIGHTING2.level=0;
1953 								tsen.LIGHTING2.rssi=12;
1954 
1955 								tsen.LIGHTING2.unitcode = nbc + 1;
1956 								tsen.LIGHTING2.cmnd     = light2_sOff;
1957 
1958 #ifdef ENOCEAN_BUTTON_DEBUG
1959 								_log.Log(LOG_NORM, "EnOcean message: 0xD4 Node 0x%08x UnitID: %02X cmd: %02X ",
1960 											id,
1961 											tsen.LIGHTING2.unitcode,
1962 											tsen.LIGHTING2.cmnd
1963 										);
1964 #endif //ENOCEAN_BUTTON_DEBUG
1965 
1966 								_log.Log(LOG_NORM, "EnOcean: channel = %d", nbc+1);
1967 								sDecodeRXMessage(this, (const unsigned char *)&tsen.LIGHTING2, NULL, 255);
1968 							}
1969 							return;
1970 						}
1971 						break;
1972 					}
1973 
1974 					_log.Log(LOG_NORM, "EnOcean: Unhandled RORG (%02x), uni_bi (%02x [1=bidir]), response_expected (%02x [0=yes]), request (%02x), cmd (%02x)", m_buffer[0], uni_bi_directional_communication,eep_teach_in_response_expected, teach_in_request, cmd);
1975 				}
1976 			break;
1977 
1978 		case RORG_VLD:
1979 			{
1980 				unsigned char DATA_BYTE3=m_buffer[1];
1981 				unsigned char func = (m_buffer[1] >> 2) & 0x3F;
1982 				unsigned char type = ((m_buffer[2] >> 3) & 0x1F) | ((m_buffer[1] & 0x03) << 5);
1983 
1984 				if (m_DataSize > 7)
1985 				{
1986 					unsigned char ID_BYTE3 = m_buffer[m_DataSize - 5];
1987 					unsigned char ID_BYTE2 = m_buffer[m_DataSize - 4];
1988 					unsigned char ID_BYTE1 = m_buffer[m_DataSize - 3];
1989 					unsigned char ID_BYTE0 = m_buffer[m_DataSize - 2];
1990 					unsigned long id = (ID_BYTE3 << 24) + (ID_BYTE2 << 16) + (ID_BYTE1 << 8) + ID_BYTE0;
1991 
1992 					auto itt = m_VLDNodes.find(id);
1993 					if (itt != m_VLDNodes.end())
1994 					{
1995 						uint8_t Profile = itt->second.profile;
1996 						uint8_t iType = itt->second.type;
1997 
1998 						// D2-03-0A Push Button – Single Button
1999 						_log.Log(LOG_NORM, "EnOcean message VLD: Profile: %02X Type: %02X", Profile, iType);
2000 
2001 						switch (Profile)
2002 						{
2003 						case 0x03:
2004 							//Light, Switching + Blind Control
2005 							if (iType == 0x0A)
2006 							{
2007 								int battery = (int)double((255.0 / 100.0)*m_buffer[1]);
2008 								unsigned char DATA_BYTE0 = m_buffer[2]; //1 = simple press, 2=double press, 3=long press, 4=press release
2009 								SendGeneralSwitch(id, DATA_BYTE0, battery, 1, 0, "Switch", 12);
2010 								return;
2011 							}
2012 							break;
2013 						}
2014 					}
2015 				}
2016 				_log.Log(LOG_NORM, "EnOcean message VLD: func: %02X Type: %02X", func, type);
2017 				if (func == 0x01)
2018 				{
2019 					// D2-01 Electr. switches/dimmers, Energy Meas. / Local Ctrl
2020 					switch (type)
2021 					{
2022 					case 0x0C:	// D2-01-0C
2023 					{
2024 						unsigned char channel = m_buffer[2] & 0x7;
2025 
2026 						unsigned char dim_power = m_buffer[3] & 0x7F;		// 0=off, 0x64=100%
2027 
2028 						unsigned char ID_BYTE3 = m_buffer[4];
2029 						unsigned char ID_BYTE2 = m_buffer[5];
2030 						unsigned char ID_BYTE1 = m_buffer[6];
2031 						unsigned char ID_BYTE0 = m_buffer[7];
2032 						long id = (ID_BYTE3 << 24) + (ID_BYTE2 << 16) + (ID_BYTE1 << 8) + ID_BYTE0;
2033 
2034 						// report status only if it is a known device else we may have an incorrect profile
2035 						char szDeviceID[20];
2036 						std::vector<std::vector<std::string> > result;
2037 						sprintf(szDeviceID, "%08X", (unsigned int)id);
2038 
2039 						result = m_sql.safe_query("SELECT ID, Manufacturer, Profile, [Type] FROM EnoceanSensors WHERE (HardwareID==%d) AND (DeviceID=='%q')", m_HwdID, szDeviceID);
2040 						if (result.size() < 1)
2041 						{
2042 							_log.Log(LOG_NORM, "EnOcean: Need Teach-In for %s", szDeviceID);
2043 							return;
2044 						}
2045 
2046 						RBUF tsen;
2047 						memset(&tsen, 0, sizeof(RBUF));
2048 						tsen.LIGHTING2.packetlength = sizeof(tsen.LIGHTING2) - 1;
2049 						tsen.LIGHTING2.packettype = pTypeLighting2;
2050 						tsen.LIGHTING2.subtype = sTypeAC;
2051 						tsen.LIGHTING2.seqnbr = 0;
2052 
2053 						tsen.LIGHTING2.id1 = (BYTE)ID_BYTE3;
2054 						tsen.LIGHTING2.id2 = (BYTE)ID_BYTE2;
2055 						tsen.LIGHTING2.id3 = (BYTE)ID_BYTE1;
2056 						tsen.LIGHTING2.id4 = (BYTE)ID_BYTE0;
2057 						tsen.LIGHTING2.level = dim_power;
2058 						tsen.LIGHTING2.rssi = 12;
2059 
2060 						tsen.LIGHTING2.unitcode = channel + 1;
2061 						tsen.LIGHTING2.cmnd = (dim_power > 0) ? light2_sOn : light2_sOff;
2062 
2063 #ifdef ENOCEAN_BUTTON_DEBUG
2064 						_log.Log(LOG_NORM, "EnOcean message: 0x%02X Node 0x%08x UnitID: %02X cmd: %02X ",
2065 							DATA_BYTE3,
2066 							id,
2067 							tsen.LIGHTING2.unitcode,
2068 							tsen.LIGHTING2.cmnd
2069 						);
2070 #endif //ENOCEAN_BUTTON_DEBUG
2071 
2072 						// Never learn device from D2-01-0C because subtype may be incorrect
2073 						sDecodeRXMessage(this, (const unsigned char *)&tsen.LIGHTING2, NULL, 255);
2074 
2075 						// Note: if a device uses simultaneously RPS and VLD (ex: nodon inwall module), it can be partially initialized.
2076 						//			Domoticz will show device status but some functions may not work because EnoceanSensors table has no info on this device (until teach-in is performed)
2077 						//       If a device has local control (ex: nodon inwall module with physically attached switched), domoticz will record the local control as unit 0.
2078 						//       Ex: nodon inwall 2 channels will show 3 entries. Unit 0 is the local switch, 1 is the first channel, 2 is the second channel.
2079 						//			(I only have attached a switch on the first channel, I have no idea which unit number a switch on the 2nd channel will have)
2080 						return;
2081 					}
2082 					break;
2083 					}
2084 				}
2085 				else if (func == 0x02)
2086 				{
2087 					// D2-02 Temp. Sensor, Light, Occupancy, SmokeType
2088 				}
2089 				else if (func == 0x03)
2090 				{
2091 					// D2-03
2092 					switch (type)
2093 					{
2094 					case 0x00:	// D2-03-00 Light, Switching and Blind Control Type
2095 						break;
2096 					case 0x0A:	// D2-03-0A Push Button – Single Button
2097 						break;
2098 					case 0x10:	// D2-03-10 Mechanical Handle
2099 						break;
2100 					case 0x20:	// D2-03-20 Beacon with Vibration Detection
2101 						break;
2102 					}
2103 				}
2104 			}
2105 		default:
2106 			_log.Log(LOG_NORM, "EnOcean: Unhandled RORG (%02x)", m_buffer[0]);
2107 			break;
2108 	}
2109 }
2110