Skip to content

Commit 128406b

Browse files
committed
Fibaro Push, now with option to send value only on change
Fibaro Push, implemented background worker
1 parent 20f1121 commit 128406b

36 files changed

+166
-62
lines changed

push/InfluxPush.cpp

Lines changed: 117 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,59 @@
1111
#include "../webserver/Base64.h"
1212
#include "../main/WebServer.h"
1313
#include "../webserver/cWebem.h"
14+
#include "../main/localtime_r.h"
1415
#define __STDC_FORMAT_MACROS
1516
#include <inttypes.h>
1617

17-
CInfluxPush::CInfluxPush()
18+
CInfluxPush::CInfluxPush():
19+
m_InfluxPort(8086),
20+
m_bInfluxDebugActive(false),
21+
m_stoprequested(false)
1822
{
1923
m_bLinkActive = false;
2024
}
2125

2226
void CInfluxPush::Start()
2327
{
24-
UpdateActive();
28+
UpdateSettings();
2529
m_sConnection = m_mainworker.sOnDeviceReceived.connect(boost::bind(&CInfluxPush::OnDeviceReceived, this, _1, _2, _3, _4));
30+
StartThread();
2631
}
2732

2833
void CInfluxPush::Stop()
2934
{
3035
if (m_sConnection.connected())
3136
m_sConnection.disconnect();
37+
StopThread();
3238
}
3339

34-
void CInfluxPush::UpdateActive()
40+
void CInfluxPush::UpdateSettings()
3541
{
3642
int fActive;
3743
m_sql.GetPreferencesVar("InfluxActive", fActive);
3844
m_bLinkActive = (fActive == 1);
45+
m_InfluxPort = 8086;
46+
m_sql.GetPreferencesVar("InfluxIP", m_InfluxIP);
47+
m_sql.GetPreferencesVar("InfluxPort", m_InfluxPort);
48+
m_sql.GetPreferencesVar("InfluxDatabase", m_InfluxDatabase);
49+
int InfluxDebugActiveInt;
50+
m_bInfluxDebugActive = false;
51+
m_sql.GetPreferencesVar("InfluxDebug", InfluxDebugActiveInt);
52+
if (InfluxDebugActiveInt == 1) {
53+
m_bInfluxDebugActive = true;
54+
}
55+
m_szURL = "";
56+
if (
57+
(m_InfluxIP == "") ||
58+
(m_InfluxPort == 0) ||
59+
(m_InfluxDatabase == "")
60+
)
61+
return;
62+
std::stringstream sURL;
63+
if (m_InfluxIP.find("://") == std::string::npos)
64+
sURL << "http://";
65+
sURL << m_InfluxIP << ":" << m_InfluxPort << "/write?db=" << m_InfluxDatabase;
66+
m_szURL = sURL.str();
3967
}
4068

4169
void CInfluxPush::OnDeviceReceived(const int m_HwdID, const uint64_t DeviceRowIdx, const std::string &DeviceName, const unsigned char *pRXCommand)
@@ -49,34 +77,14 @@ void CInfluxPush::OnDeviceReceived(const int m_HwdID, const uint64_t DeviceRowId
4977

5078
void CInfluxPush::DoInfluxPush()
5179
{
52-
std::string InfluxIP = "";
53-
int InfluxPort = 8086;
54-
std::string InfluxDatabase = "";
55-
m_sql.GetPreferencesVar("InfluxIP", InfluxIP);
56-
m_sql.GetPreferencesVar("InfluxPort", InfluxPort);
57-
m_sql.GetPreferencesVar("InfluxDatabase", InfluxDatabase);
58-
59-
60-
int InfluxDebugActiveInt;
61-
bool InfluxDebugActive = false;
62-
m_sql.GetPreferencesVar("InfluxDebug", InfluxDebugActiveInt);
63-
if (InfluxDebugActiveInt == 1) {
64-
InfluxDebugActive = true;
65-
}
66-
67-
if (
68-
(InfluxIP == "") ||
69-
(InfluxPort == 0) ||
70-
(InfluxDatabase == "")
71-
)
72-
return;
7380
std::vector<std::vector<std::string> > result;
7481
result = m_sql.safe_query(
7582
"SELECT A.DeviceID, A.DelimitedValue, B.ID, B.Type, B.SubType, B.nValue, B.sValue, A.TargetType, A.TargetVariable, A.TargetDeviceID, A.TargetProperty, A.IncludeUnit, B.Name, B.SwitchType FROM PushLink as A, DeviceStatus as B "
7683
"WHERE (A.PushType==1 AND A.DeviceID == '%" PRIu64 "' AND A.Enabled==1 AND A.DeviceID==B.ID)",
7784
m_DeviceRowIdx);
7885
if (result.size()>0)
7986
{
87+
time_t atime = mytime(NULL);
8088
std::string sendValue;
8189
std::vector<std::vector<std::string> >::const_iterator itt;
8290
for (itt=result.begin(); itt!=result.end(); ++itt)
@@ -106,36 +114,98 @@ void CInfluxPush::DoInfluxPush()
106114
}
107115
}
108116
if (sendValue !="") {
109-
std::stringstream szKey;
117+
std::string szKey;
110118
std::string vType = DropdownOptionsValue(m_DeviceRowIdx, delpos);
111119
stdreplace(vType, " ", "-");
112120
stdreplace(name, " ", "-");
113-
szKey << vType << ",idx=" << sd[0] << ",name=" << name << " value=" << sendValue;
121+
szKey = vType + ",idx=" + sd[0] + ",name=" + name;
114122

115-
std::string szPostdata = szKey.str();
116-
std::vector<std::string> ExtraHeaders;
123+
_tPushItem pItem;
124+
pItem.skey = szKey;
125+
pItem.stimestamp = atime;
126+
pItem.svalue = sendValue;
117127

118-
std::stringstream sURL;
119-
if (InfluxIP.find("://") == std::string::npos)
120-
sURL << "http://";
121-
sURL << InfluxIP << ":" << InfluxPort << "/write?db=" << InfluxDatabase;
128+
if (targetType == 0)
129+
{
130+
//Only send on change
131+
std::map<std::string, _tPushItem>::iterator itt = m_PushedItems.find(szKey);
132+
if (itt != m_PushedItems.end())
133+
{
134+
if (sendValue == itt->second.svalue)
135+
continue;
136+
}
137+
m_PushedItems[szKey] = pItem;
138+
}
122139

140+
boost::lock_guard<boost::mutex> l(m_background_task_mutex);
141+
if (m_background_task_queue.size() < 50)
142+
m_background_task_queue.push_back(pItem);
143+
}
144+
}
145+
}
146+
}
123147

124-
if (InfluxDebugActive) {
125-
_log.Log(LOG_NORM, "InfluxLink: value %s", szPostdata.c_str());
126-
}
148+
bool CInfluxPush::StartThread()
149+
{
150+
StopThread();
151+
m_stoprequested = false;
152+
m_background_task_thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&CInfluxPush::Do_Work, this)));
153+
return (m_background_task_thread != NULL);
154+
}
127155

128-
std::string sResult;
129-
if (!HTTPClient::POST(sURL.str(), szPostdata, ExtraHeaders, sResult))
130-
{
131-
_log.Log(LOG_ERROR, "InfluxLink: Error sending data to InfluxDB server! (check address/port/database)");
132-
return;
133-
}
156+
void CInfluxPush::StopThread()
157+
{
158+
if (m_background_task_thread)
159+
{
160+
m_stoprequested = true;
161+
m_background_task_thread->join();
162+
}
163+
}
164+
165+
166+
void CInfluxPush::Do_Work()
167+
{
168+
std::vector<_tPushItem> _items2do;
169+
170+
while (!m_stoprequested)
171+
{
172+
sleep_milliseconds(500);
173+
174+
{ // additional scope for lock (accessing size should be within lock too)
175+
boost::lock_guard<boost::mutex> l(m_background_task_mutex);
176+
if (m_background_task_queue.empty())
177+
continue;
178+
_items2do = m_background_task_queue;
179+
m_background_task_queue.clear();
180+
}
181+
182+
if (_items2do.size() < 1) {
183+
continue;
184+
}
185+
if (m_szURL.empty())
186+
continue;
187+
188+
std::vector<_tPushItem>::iterator itt = _items2do.begin();
189+
while (itt != _items2do.end())
190+
{
191+
std::string szPostdata = itt->skey + " value=" + itt->svalue;
192+
std::vector<std::string> ExtraHeaders;
193+
194+
if (m_bInfluxDebugActive) {
195+
_log.Log(LOG_NORM, "InfluxLink: value %s", szPostdata.c_str());
196+
}
197+
198+
std::string sResult;
199+
if (!HTTPClient::POST(m_szURL, szPostdata, ExtraHeaders, sResult))
200+
{
201+
_log.Log(LOG_ERROR, "InfluxLink: Error sending data to InfluxDB server! (check address/port/database)");
134202
}
203+
++itt;
135204
}
136205
}
137206
}
138207

208+
139209
//Webserver helpers
140210
namespace http {
141211
namespace server {
@@ -167,7 +237,7 @@ namespace http {
167237
m_sql.UpdatePreferencesVar("InfluxPort", atoi(port.c_str()));
168238
m_sql.UpdatePreferencesVar("InfluxDatabase", database.c_str());
169239
m_sql.UpdatePreferencesVar("InfluxDebug", idebugenabled);
170-
m_mainworker.m_influxpush.UpdateActive();
240+
m_mainworker.m_influxpush.UpdateSettings();
171241
root["status"] = "OK";
172242
root["title"] = "SaveInfluxLinkConfig";
173243
}
@@ -253,14 +323,16 @@ namespace http {
253323
std::string deviceid = request::findValue(&req, "deviceid");
254324
int deviceidi = atoi(deviceid.c_str());
255325
std::string valuetosend = request::findValue(&req, "valuetosend");
326+
std::string targettype = request::findValue(&req, "targettype");
327+
int targettypei = atoi(targettype.c_str());
256328
std::string linkactive = request::findValue(&req, "linkactive");
257329
if (idx == "0") {
258330
m_sql.safe_query(
259331
"INSERT INTO PushLink (PushType,DeviceID,DelimitedValue,TargetType,TargetVariable,TargetDeviceID,TargetProperty,IncludeUnit,Enabled) VALUES (%d,'%d',%d,%d,'%q',%d,'%q',%d,%d)",
260332
1,
261333
deviceidi,
262334
atoi(valuetosend.c_str()),
263-
0,
335+
targettypei,
264336
"-",
265337
0,
266338
"-",
@@ -270,9 +342,10 @@ namespace http {
270342
}
271343
else {
272344
m_sql.safe_query(
273-
"UPDATE PushLink SET DeviceID='%d', DelimitedValue=%d, Enabled='%d' WHERE (ID == '%q')",
345+
"UPDATE PushLink SET DeviceID=%d, DelimitedValue=%d, TargetType=%d, Enabled=%d WHERE (ID == '%q')",
274346
deviceidi,
275347
atoi(valuetosend.c_str()),
348+
targettypei,
276349
atoi(linkactive.c_str()),
277350
idx.c_str()
278351
);

push/InfluxPush.h

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,38 @@
33
#include <boost/signals2.hpp>
44

55
#include "Push.h"
6+
#include <map>
7+
#include <string>
68

79
class CInfluxPush : public CPush
810
{
11+
struct _tPushItem
12+
{
13+
std::string skey;
14+
time_t stimestamp;
15+
std::string svalue;
16+
};
917
public:
1018
CInfluxPush();
1119
void Start();
1220
void Stop();
13-
void UpdateActive();
14-
21+
void UpdateSettings();
1522
private:
16-
1723
void OnDeviceReceived(const int m_HwdID, const uint64_t DeviceRowIdx, const std::string &DeviceName, const unsigned char *pRXCommand);
1824
void DoInfluxPush();
25+
26+
boost::shared_ptr<boost::thread> m_background_task_thread;
27+
boost::mutex m_background_task_mutex;
28+
bool m_stoprequested;
29+
bool StartThread();
30+
void StopThread();
31+
void Do_Work();
32+
33+
std::map<std::string,_tPushItem> m_PushedItems;
34+
std::vector<_tPushItem> m_background_task_queue;
35+
std::string m_szURL;
36+
std::string m_InfluxIP;
37+
int m_InfluxPort;
38+
std::string m_InfluxDatabase;
39+
bool m_bInfluxDebugActive;
1940
};

push/Push.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ const char *RFX_Type_SubType_Values(const unsigned char dType, const unsigned ch
243243
{ pTypeGeneral, sTypeKwh, "Instant,Usage" },
244244
{ pTypeGeneral, sTypeWaterflow, "Percentage" },
245245
{ pTypeGeneral, sTypeCustom, "Percentage" },
246+
{ pTypeGeneral, sTypeZWaveAlarm, "Status" },
246247

247248
{ pTypeThermostat, sTypeThermSetpoint, "Temperature" },
248249
{ pTypeThermostat, sTypeThermTemperature, "Temperature" },

www/app/DPInfluxController.js

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ define(['app'], function (app) {
9393
var valuetosend = $('#linkparamstable #combosendvalue option:selected').val();
9494
var scenevaluetosend = $('#linkparamstable #sendvaluescene option:selected').val();
9595
var rebootvaluetosend = $('#linkparamstable #sendvaluereboot option:selected').val();
96+
var targettype = $("#linkparamstable #combotargettype option:selected").val();
9697
var targetvariable = $('#linkparamstable #targetvariable').val();
9798
var targetdeviceid = $('#linkparamstable #targetdeviceid').val();
9899
var targetproperty = $('#linkparamstable #targetproperty').val();
@@ -112,6 +113,7 @@ define(['app'], function (app) {
112113
"&idx=" + idx +
113114
"&deviceid=" + deviceid +
114115
"&valuetosend=" + valuetosend +
116+
"&targettype=" + targettype +
115117
"&linkactive=" + linkactive;
116118
$.ajax({
117119
url: url,
@@ -175,15 +177,21 @@ define(['app'], function (app) {
175177
else {
176178
DelimitedValue = $.t(GetDeviceValueOptionWording(item.DeviceID,item.Delimitedvalue));
177179
}
180+
var TargetType = $.t('On Value Change');
181+
if (item.TargetType==1)
182+
TargetType = $.t('Direct');
183+
178184
var addId = oTable.fnAddData( {
179185
"DT_RowId": item.idx,
180186
"DeviceID": item.DeviceID,
187+
"TargetType": item.TargetType,
181188
"Enabled": item.Enabled,
182189
"Delimitedvalue": item.Delimitedvalue,
183190
"0": item.DeviceID,
184191
"1": item.Name,
185192
"2": DelimitedValue,
186-
"3": enabled
193+
"3": TargetType,
194+
"4": enabled
187195
} );
188196
});
189197
}
@@ -231,19 +239,10 @@ define(['app'], function (app) {
231239
$.linkIdx=idx;
232240
$("#linkparamstable #linkupdate").attr("href", "javascript:AddLink('u')");
233241
$("#linkparamstable #linkdelete").attr("href", "javascript:DeleteLink(" + idx + ")");
234-
if (data["TargetType"]==2) {
235-
$("#linkparamstable #sendvaluescene").val(data["Delimitedvalue"]);
236-
$("#linkparamstable #onoffdevicename").val(data["DeviceID"]);
237-
}
238-
if (data["TargetType"]==3) {
239-
$("#linkparamstable #sendvaluereboot").val(data["Delimitedvalue"]);
240-
$("#linkparamstable #onoffdevicename").val(data["DeviceID"]);
241-
}
242-
else {
243-
$("#linkparamstable #devicename").val(data["DeviceID"]);
244-
ValueSelectorUpdate();
245-
$("#linkparamstable #combosendvalue").val(data["Delimitedvalue"]);
246-
}
242+
$("#linkparamstable #combotargettype").val(data["TargetType"]);
243+
$("#linkparamstable #devicename").val(data["DeviceID"]);
244+
ValueSelectorUpdate();
245+
$("#linkparamstable #combosendvalue").val(data["Delimitedvalue"]);
247246
if (data["Enabled"] == 1) {
248247
$('#linkparamstable #linkenabled').prop('checked', true);
249248
}

www/html5.appcache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
CACHE MANIFEST
2-
# ref 1352
2+
# ref 1353
33

44
CACHE:
55
# CSS

www/i18n/domoticz-ar.json.gz

11 Bytes
Binary file not shown.

www/i18n/domoticz-bg.json.gz

11 Bytes
Binary file not shown.

www/i18n/domoticz-ca.json.gz

11 Bytes
Binary file not shown.

www/i18n/domoticz-cs.json.gz

11 Bytes
Binary file not shown.

www/i18n/domoticz-da.json.gz

11 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)