Skip to content

Commit abcaf9c

Browse files
committed
Merge pull request #658 from larber/master
Add support for Rainforest RAVEn USB ZigBee Smart Meter Adapter
2 parents 30f5523 + f8e2e1e commit abcaf9c

File tree

6 files changed

+12662
-12479
lines changed

6 files changed

+12662
-12479
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ hardware/Tellstick.cpp
307307
hardware/Thermosmart.cpp
308308
hardware/ToonThermostat.cpp
309309
hardware/VolcraftCO20.cpp
310+
hardware/RAVEn.cpp
310311
hardware/Winddelen.cpp
311312
hardware/WOL.cpp
312313
hardware/Wunderground.cpp

hardware/RAVEn.cpp

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
2+
#include "stdafx.h"
3+
#ifndef WIN32
4+
#include "RAVEn.h"
5+
#include "../main/Helper.h"
6+
#include "../main/Logger.h"
7+
#include "hardwaretypes.h"
8+
#include "../main/RFXtrx.h"
9+
#include "../main/localtime_r.h"
10+
#include "../main/mainworker.h"
11+
#include "../tinyxpath/tinyxml.h"
12+
#include <usb.h>
13+
#include <stdint.h>
14+
15+
RAVEn::RAVEn(const int ID, const std::string& devname)
16+
: device_(devname), wptr_(buffer_), currUsage_(0), totalUsage_(0)
17+
{
18+
m_HwdID = ID;
19+
}
20+
21+
RAVEn::~RAVEn(void)
22+
{
23+
}
24+
25+
bool RAVEn::StartHardware()
26+
{
27+
StartHeartbeatThread();
28+
//Try to open the Serial Port
29+
try
30+
{
31+
_log.Log(LOG_STATUS, "RAVEn: Using serial port: %s", device_.c_str());
32+
open(device_.c_str(), 115200);
33+
}
34+
catch (boost::exception & e)
35+
{
36+
_log.Log(LOG_ERROR, "RAVEn: Error opening serial port!");
37+
#ifdef _DEBUG
38+
_log.Log(LOG_ERROR, "-----------------\n%s\n-----------------", boost::diagnostic_information(e).c_str());
39+
#else
40+
(void)e;
41+
#endif
42+
return false;
43+
}
44+
catch (...)
45+
{
46+
_log.Log(LOG_ERROR, "RAVEn: Error opening serial port!!!");
47+
return false;
48+
}
49+
setReadCallback(boost::bind(&RAVEn::readCallback, this, _1, _2));
50+
m_bIsStarted = true;
51+
sOnConnected(this);
52+
53+
return true;
54+
}
55+
56+
bool RAVEn::StopHardware()
57+
{
58+
terminate();
59+
StopHeartbeatThread();
60+
m_bIsStarted = false;
61+
return true;
62+
}
63+
64+
void RAVEn::readCallback(const char *indata, size_t inlen)
65+
{
66+
boost::lock_guard<boost::mutex> l(readQueueMutex);
67+
if (!m_bEnableReceive)
68+
return; //receiving not enabled
69+
70+
const char* data;
71+
for(data = indata; data < indata+inlen; data++)
72+
{
73+
if(*data != '\0')
74+
break;
75+
}
76+
if(data == (indata+inlen))
77+
{
78+
_log.Log(LOG_ERROR, "RAVEn::readCallback only got NULLs (%d of them)", inlen);
79+
return;
80+
}
81+
size_t len = (indata+inlen) - data;
82+
#ifdef _DEBUG
83+
_log.Log(LOG_NORM, "RAVEn::readCallback got %d, have %d. Incoming: %s, Current: %s", len, wptr_-buffer_, data, buffer_);
84+
#endif
85+
if(wptr_+len > buffer_+MAX_BUFFER_LEN)
86+
{
87+
_log.Log(LOG_ERROR, "Exceeded buffer space...resetting buffer");
88+
wptr_ = buffer_;
89+
}
90+
91+
memcpy(wptr_, data, len);
92+
wptr_ += len;
93+
*wptr_ = '\0';
94+
95+
TiXmlDocument doc;
96+
const char* endPtr = doc.Parse(buffer_);
97+
if (!endPtr)
98+
{
99+
#ifdef _DEBUG
100+
_log.Log(LOG_ERROR, "RAVEn: Not enough data received (%d): %s", len, buffer_);
101+
#endif
102+
return;
103+
}
104+
else
105+
{
106+
#ifdef _DEBUG
107+
_log.Log(LOG_NORM, "RAVEn::shifting buffer after parsing %d with %d bytes remaining: %s", endPtr - buffer_, wptr_ - endPtr, endPtr);
108+
#endif
109+
memmove(buffer_, endPtr, wptr_ - endPtr);
110+
wptr_ = buffer_ + (wptr_ - endPtr);
111+
}
112+
113+
TiXmlElement *pRoot;
114+
115+
pRoot = doc.FirstChildElement("InstantaneousDemand");
116+
bool updated=false;
117+
if (pRoot)
118+
{
119+
currUsage_ = 1000*double(strtoul(pRoot->FirstChildElement("Demand")->GetText(), NULL, 16))/strtoul(pRoot->FirstChildElement("Divisor")->GetText(), NULL, 16);
120+
updated = true;
121+
}
122+
pRoot = doc.FirstChildElement("CurrentSummationDelivered");
123+
if(pRoot)
124+
{
125+
totalUsage_ = double(strtoul(pRoot->FirstChildElement("SummationDelivered")->GetText(), NULL, 16))/strtoul(pRoot->FirstChildElement("Divisor")->GetText(), NULL, 16);
126+
updated = true;
127+
}
128+
129+
if(updated)
130+
SendKwhMeter(CDomoticzHardwareBase::m_HwdID, 1, 255, currUsage_, totalUsage_, "Power Meter");
131+
else
132+
_log.Log(LOG_ERROR, "RAVEn: Unknown node");
133+
}
134+
135+
bool RAVEn::WriteToHardware(const char *pdata, const unsigned char length)
136+
{
137+
return false;
138+
}
139+
140+
141+
#endif //WIN32

hardware/RAVEn.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#pragma once
2+
3+
#ifndef WIN32
4+
#include "DomoticzHardware.h"
5+
#include "ASyncSerial.h"
6+
#include <iostream>
7+
8+
#define MAX_BUFFER_LEN 10000
9+
10+
class RAVEn : public CDomoticzHardwareBase,
11+
public AsyncSerial
12+
{
13+
public:
14+
explicit RAVEn(const int ID, const std::string& devname);
15+
~RAVEn(void);
16+
17+
bool WriteToHardware(const char *pdata, const unsigned char length);
18+
private:
19+
const std::string device_;
20+
boost::shared_ptr<boost::thread> m_thread;
21+
22+
bool StartHardware();
23+
bool StopHardware();
24+
void readCallback(const char *indata, size_t inlen);
25+
26+
char buffer_[MAX_BUFFER_LEN];
27+
char* wptr_;
28+
29+
double currUsage_;
30+
double totalUsage_;
31+
};
32+
33+
#endif //WIN32

main/RFXNames.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ const char *Hardware_Type_Desc(int hType)
223223
{ HTYPE_Sterbox, "Sterbox v2-3 PLC with LAN interface" },
224224
{ HTYPE_HTTPPOLLER, "HTTP/HTTPS poller" },
225225
{ HTYPE_FITBIT, "Fitbit" },
226+
{ HTYPE_RAVEn, "Rainforest RAVEn USB" },
226227
{ 0, NULL, NULL }
227228
};
228229
return findTableIDSingle1 (Table, hType);
@@ -3324,7 +3325,8 @@ bool IsSerialDevice(const _eHardwareTypes htype)
33243325
(htype == HTYPE_RFXtrx315) || (htype == HTYPE_RFXtrx433) || (htype == HTYPE_RFXtrx868) ||
33253326
(htype == HTYPE_P1SmartMeter) || (htype == HTYPE_Rego6XX) || (htype == HTYPE_DavisVantage) || (htype == HTYPE_S0SmartMeter) || (htype == HTYPE_OpenThermGateway) ||
33263327
(htype == HTYPE_TeleinfoMeter) || (htype == HTYPE_OpenZWave) || (htype == HTYPE_EnOceanESP2) || (htype == HTYPE_EnOceanESP3) || (htype == HTYPE_Meteostick) ||
3327-
(htype == HTYPE_MySensorsUSB) || (htype == HTYPE_RFLINKUSB) || (htype == HTYPE_KMTronicUSB) || (htype == HTYPE_KMTronic433) || (htype == HTYPE_CurrentCostMeter)
3328+
(htype == HTYPE_MySensorsUSB) || (htype == HTYPE_RFLINKUSB) || (htype == HTYPE_KMTronicUSB) || (htype == HTYPE_KMTronic433) || (htype == HTYPE_CurrentCostMeter) ||
3329+
(htype == HTYPE_RAVEn)
33283330
);
33293331
}
33303332

0 commit comments

Comments
 (0)