Skip to content

Commit 959ac49

Browse files
committed
Implemented: KMTronic USB/WEB relay hardware
1 parent 5e0a01b commit 959ac49

20 files changed

+686
-14
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ hardware/GpioPin.cpp
187187
hardware/HardwareMonitor.cpp
188188
hardware/HarmonyHub.cpp
189189
hardware/ICYThermostat.cpp
190+
hardware/KMTronicBase.cpp
191+
hardware/KMTronicSerial.cpp
192+
hardware/KMTronicTCP.cpp
190193
hardware/Limitless.cpp
191194
hardware/Meteostick.cpp
192195
hardware/MochadTCP.cpp

History.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ Version 2.0.xxxx (xxxx 2015)
8383
- Fixed: Blockly, possible saving of 'ghost' events
8484
- Implemented: Sanity check for OpenZWave NetworkKey Length
8585
- Implemented: OTGW, MsgID=14 and MsgID=17 (if reported)
86+
- Implemented: KMTronic USB/WEB relay hardware
8687

8788
Version 2.0.2284 (February 22th 2015)
8889
- Fixed: Firefox, RGBW/Setpoint popup

hardware/DomoticzHardware.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ class CDomoticzHardwareBase
8484
friend class FritzboxTCP;
8585
friend class CETH8020;
8686
friend class CRFLink;
87+
friend class KMTronicBase;
88+
friend class KMTronicSerial;
89+
friend class KMTronicTCP;
8790

8891
virtual bool StartHardware()=0;
8992
virtual bool StopHardware()=0;

hardware/KMTronicBase.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#include "stdafx.h"
2+
#include "KMTronicBase.h"
3+
#include "../main/Logger.h"
4+
#include "../main/Helper.h"
5+
#include "../main/RFXtrx.h"
6+
#include "../main/SQLHelper.h"
7+
#include "../main/localtime_r.h"
8+
#include "hardwaretypes.h"
9+
#include <string>
10+
#include <sstream>
11+
#include <algorithm>
12+
#include <iostream>
13+
#include <boost/bind.hpp>
14+
15+
#include <ctime>
16+
17+
#define round(a) ( int ) ( a + .5 )
18+
19+
20+
KMTronicBase::KMTronicBase(void)
21+
{
22+
m_bufferpos = 0;
23+
m_TotRelais = 0;
24+
for (int ii = 0; ii < Max_KMTronic_Relais; ii++)
25+
{
26+
m_bRelaisStatus[ii] = false;
27+
}
28+
}
29+
30+
31+
KMTronicBase::~KMTronicBase(void)
32+
{
33+
}
34+
35+
void KMTronicBase::ParseData(const unsigned char *pData, int Len)
36+
{
37+
int ii=0;
38+
while (ii<Len)
39+
{
40+
const unsigned char c = pData[ii];
41+
if(c == 0x0d)
42+
{
43+
ii++;
44+
continue;
45+
}
46+
47+
if(c == 0x0a || m_bufferpos == sizeof(m_buffer) - 1)
48+
{
49+
// discard newline, close string, parse line and clear it.
50+
if(m_bufferpos > 0) m_buffer[m_bufferpos] = 0;
51+
ParseLine();
52+
m_bufferpos = 0;
53+
}
54+
else
55+
{
56+
m_buffer[m_bufferpos] = c;
57+
m_bufferpos++;
58+
}
59+
ii++;
60+
}
61+
}
62+
63+
64+
bool KMTronicBase::WriteToHardware(const char *pdata, const unsigned char length)
65+
{
66+
tRBUF *pCmd = (tRBUF *)pdata;
67+
if (pCmd->LIGHTING2.packettype == pTypeLighting2)
68+
{
69+
//Light command
70+
71+
int node_id = pCmd->LIGHTING2.id4;
72+
if (node_id > Max_KMTronic_Relais)
73+
return false;
74+
75+
if ((pCmd->LIGHTING2.cmnd == light2_sOn) || (pCmd->LIGHTING2.cmnd == light2_sOff))
76+
{
77+
unsigned char SendBuf[3];
78+
SendBuf[0] = 0xFF;
79+
SendBuf[1] = node_id;
80+
SendBuf[2] = (pCmd->LIGHTING2.cmnd == light2_sOn) ? 1 : 0;
81+
WriteInt(SendBuf, 3,false);
82+
return true;
83+
}
84+
85+
}
86+
return false;
87+
}
88+
89+
90+
void KMTronicBase::ParseLine()
91+
{
92+
if (m_bufferpos<2)
93+
return;
94+
}
95+

hardware/KMTronicBase.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#pragma once
2+
3+
#include "DomoticzHardware.h"
4+
5+
#define Max_KMTronic_Relais 8
6+
7+
class KMTronicBase : public CDomoticzHardwareBase
8+
{
9+
friend class KMTronicSerial;
10+
friend class KMTronicTCP;
11+
public:
12+
KMTronicBase(void);
13+
~KMTronicBase(void);
14+
std::string m_szSerialPort;
15+
unsigned int m_iBaudRate;
16+
bool WriteToHardware(const char *pdata, const unsigned char length);
17+
private:
18+
virtual bool WriteInt(const unsigned char *data, const size_t len, const bool bWaitForReturn) = 0;
19+
void ParseData(const unsigned char *pData, int Len);
20+
void ParseLine();
21+
22+
static const int readBufferSize=1028;
23+
unsigned char m_buffer[readBufferSize];
24+
int m_bufferpos;
25+
26+
bool m_bDoInitialQuery;
27+
int m_TotRelais;
28+
bool m_bRelaisStatus[Max_KMTronic_Relais];
29+
};
30+

hardware/KMTronicSerial.cpp

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
#include "stdafx.h"
2+
#include "KMTronicSerial.h"
3+
#include "../main/Logger.h"
4+
#include "../main/Helper.h"
5+
#include "../main/RFXtrx.h"
6+
#include "../main/localtime_r.h"
7+
#include "P1MeterBase.h"
8+
#include "hardwaretypes.h"
9+
#include <string>
10+
#include <algorithm>
11+
#include <iostream>
12+
#include <boost/bind.hpp>
13+
14+
#include <ctime>
15+
16+
//#define DEBUG_KMTronic
17+
18+
#define RETRY_DELAY 30
19+
20+
KMTronicSerial::KMTronicSerial(const int ID, const std::string& devname)
21+
{
22+
m_HwdID=ID;
23+
m_szSerialPort=devname;
24+
m_iBaudRate = 9600;
25+
m_stoprequested = false;
26+
}
27+
28+
KMTronicSerial::~KMTronicSerial()
29+
{
30+
clearReadCallback();
31+
}
32+
33+
bool KMTronicSerial::StartHardware()
34+
{
35+
m_bDoInitialQuery = true;
36+
m_iQueryState = 0;
37+
38+
m_retrycntr = RETRY_DELAY; //will force reconnect first thing
39+
40+
//Start worker thread
41+
m_thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&KMTronicSerial::Do_Work, this)));
42+
43+
return (m_thread != NULL);
44+
45+
return true;
46+
}
47+
48+
bool KMTronicSerial::StopHardware()
49+
{
50+
m_stoprequested = true;
51+
if (m_thread != NULL)
52+
m_thread->join();
53+
// Wait a while. The read thread might be reading. Adding this prevents a pointer error in the async serial class.
54+
sleep_milliseconds(10);
55+
if (isOpen())
56+
{
57+
try {
58+
clearReadCallback();
59+
close();
60+
doClose();
61+
setErrorStatus(true);
62+
}
63+
catch (...)
64+
{
65+
//Don't throw from a Stop command
66+
}
67+
}
68+
m_bIsStarted = false;
69+
return true;
70+
}
71+
72+
void KMTronicSerial::Do_Work()
73+
{
74+
while (!m_stoprequested)
75+
{
76+
sleep_seconds(1);
77+
time_t atime = mytime(NULL);
78+
struct tm ltime;
79+
localtime_r(&atime, &ltime);
80+
if (ltime.tm_sec % 12 == 0) {
81+
mytime(&m_LastHeartbeat);
82+
}
83+
84+
if (m_stoprequested)
85+
break;
86+
if (!isOpen())
87+
{
88+
if (m_retrycntr == 0)
89+
{
90+
_log.Log(LOG_STATUS, "KMTronic: retrying in %d seconds...", RETRY_DELAY);
91+
}
92+
m_retrycntr++;
93+
if (m_retrycntr >= RETRY_DELAY)
94+
{
95+
m_retrycntr = 0;
96+
if (OpenSerialDevice())
97+
{
98+
GetRelayStates();
99+
}
100+
}
101+
}
102+
}
103+
_log.Log(LOG_STATUS, "KMTronic: Serial Worker stopped...");
104+
}
105+
106+
bool KMTronicSerial::OpenSerialDevice()
107+
{
108+
//Try to open the Serial Port
109+
try
110+
{
111+
_log.Log(LOG_STATUS, "KMTronic: Using serial port: %s", m_szSerialPort.c_str());
112+
#ifndef WIN32
113+
openOnlyBaud(
114+
m_szSerialPort,
115+
m_iBaudRate,
116+
boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none),
117+
boost::asio::serial_port_base::character_size(8)
118+
);
119+
#else
120+
open(
121+
m_szSerialPort,
122+
m_iBaudRate,
123+
boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none),
124+
boost::asio::serial_port_base::character_size(8)
125+
);
126+
#endif
127+
}
128+
catch (boost::exception & e)
129+
{
130+
_log.Log(LOG_ERROR, "KMTronic: Error opening serial port!");
131+
#ifdef _DEBUG
132+
_log.Log(LOG_ERROR, "-----------------\n%s\n-----------------", boost::diagnostic_information(e).c_str());
133+
#endif
134+
return false;
135+
}
136+
catch (...)
137+
{
138+
_log.Log(LOG_ERROR, "KMTronic: Error opening serial port!!!");
139+
return false;
140+
}
141+
m_bIsStarted = true;
142+
m_bufferpos = 0;
143+
setReadCallback(boost::bind(&KMTronicSerial::readCallback, this, _1, _2));
144+
sOnConnected(this);
145+
return true;
146+
}
147+
148+
void KMTronicSerial::readCallback(const char *data, size_t len)
149+
{
150+
boost::lock_guard<boost::mutex> l(readQueueMutex);
151+
if (!m_bIsStarted)
152+
return;
153+
154+
if (len > sizeof(m_buffer))
155+
return;
156+
157+
m_bHaveReceived = true;
158+
159+
if (!m_bEnableReceive)
160+
return; //receiving not enabled
161+
162+
memcpy(m_buffer, data, len);
163+
m_bufferpos = len;
164+
}
165+
166+
bool KMTronicSerial::WriteInt(const unsigned char *data, const size_t len, const bool bWaitForReturn)
167+
{
168+
if (!isOpen())
169+
return false;
170+
m_bHaveReceived = false;
171+
write((const char*)data, len);
172+
if (!bWaitForReturn)
173+
return true;
174+
sleep_milliseconds(100);
175+
return (m_bHaveReceived == true);
176+
}
177+
178+
void KMTronicSerial::GetRelayStates()
179+
{
180+
unsigned char SendBuf[3];
181+
int ii;
182+
183+
//First check if we are the 4/8 version
184+
SendBuf[0] = 0xFF;
185+
SendBuf[1] = 0x09;
186+
SendBuf[2] = 0x00;
187+
188+
if (WriteInt(SendBuf, 3, true))
189+
{
190+
if (m_bufferpos > Max_KMTronic_Relais)
191+
m_bufferpos = Max_KMTronic_Relais;
192+
for (ii = 0; ii < m_bufferpos; ii++)
193+
{
194+
bool bIsOn = (m_buffer[ii] == 1);
195+
if (m_bRelaisStatus[ii] != bIsOn)
196+
{
197+
m_bRelaisStatus[ii] = bIsOn;
198+
}
199+
std::stringstream sstr;
200+
sstr << "Relay " << (ii + 1);
201+
SendSwitch(ii + 1, 1, 255, bIsOn, (bIsOn) ? 100 : 0, sstr.str());
202+
}
203+
return;
204+
}
205+
SendBuf[0] = 0xFF;
206+
SendBuf[2] = 0x03;
207+
for (ii = 0; ii < Max_KMTronic_Relais; ii++)
208+
{
209+
SendBuf[1] = ii+1;
210+
if (WriteInt(SendBuf, 3,true))
211+
{
212+
if (m_bufferpos == 3)
213+
{
214+
if (m_buffer[1] == (ii + 1))
215+
{
216+
bool bIsOn = (m_buffer[2] == 1);
217+
if (m_bRelaisStatus[ii] != bIsOn)
218+
{
219+
m_bRelaisStatus[ii] = bIsOn;
220+
}
221+
std::stringstream sstr;
222+
sstr << "Relay " << (ii+1);
223+
SendSwitch(ii + 1, 1, 255, bIsOn, (bIsOn) ? 100 : 0, sstr.str());
224+
}
225+
}
226+
else
227+
{
228+
_log.Log(LOG_ERROR, "KMTronic: Invalid data received!");
229+
}
230+
}
231+
else
232+
{
233+
if (m_TotRelais == 0)
234+
{
235+
m_TotRelais = ii;
236+
}
237+
return;
238+
}
239+
}
240+
}

0 commit comments

Comments
 (0)