1 #include "stdafx.h"
2 #include "ICYThermostat.h"
3 #include "../main/Helper.h"
4 #include "../main/Logger.h"
5 #include "hardwaretypes.h"
6 #include "../main/localtime_r.h"
7 #include "../main/RFXtrx.h"
8 #include "../main/SQLHelper.h"
9 #include "../httpclient/HTTPClient.h"
10 #include "../main/mainworker.h"
11 #include "../main/json_helper.h"
12
13 #define round(a) ( int ) ( a + .5 )
14
15 //#define DEBUG_ICYThermostat
16
17 #define ICY_LOGIN_URL "https://portal.icy.nl/login"
18 #define ICY_DATA_URL "https://portal.icy.nl/data"
19
20 #define ENI_LOGIN_URL "https://eniportal.icy.nl/api/login" //https://eniportal.icy.nl/#/user/login"
21 #define ENI_DATA_URL "https://eniportal.icy.nl/api/data" //https://eniportal.icy.nl/#/user/data" // /api/data
22
23 #define SEC_LOGIN_URL "https://secportal.icy.nl/api/login" //https://secportal.icy.nl/#/user/login"
24 #define SEC_DATA_URL "https://secportal.icy.nl/api/data" //https://secportal.icy.nl/#/user/data" // /api/data
25
26
CICYThermostat(const int ID,const std::string & Username,const std::string & Password)27 CICYThermostat::CICYThermostat(const int ID, const std::string &Username, const std::string &Password) :
28 m_UserName(Username),
29 m_Password(Password)
30 {
31 m_HwdID=ID;
32 m_companymode = CMODE_UNKNOWN;
33 Init();
34 }
35
~CICYThermostat(void)36 CICYThermostat::~CICYThermostat(void)
37 {
38 }
39
Init()40 void CICYThermostat::Init()
41 {
42 m_SerialNumber="";
43 m_Token="";
44 }
45
StartHardware()46 bool CICYThermostat::StartHardware()
47 {
48 RequestStart();
49
50 Init();
51 //Start worker thread
52 m_thread = std::make_shared<std::thread>(&CICYThermostat::Do_Work, this);
53 SetThreadNameInt(m_thread->native_handle());
54 m_bIsStarted=true;
55 sOnConnected(this);
56 return (m_thread != nullptr);
57 }
58
StopHardware()59 bool CICYThermostat::StopHardware()
60 {
61 if (m_thread)
62 {
63 RequestStop();
64 m_thread->join();
65 m_thread.reset();
66 }
67 m_bIsStarted=false;
68 return true;
69 }
70
71 #define ICY_POLL_INTERVAL 60
72
Do_Work()73 void CICYThermostat::Do_Work()
74 {
75 int sec_counter = ICY_POLL_INTERVAL-5;
76 _log.Log(LOG_STATUS,"ICYThermostat: Worker started...");
77 while (!IsStopRequested(1000))
78 {
79 sec_counter++;
80 if (sec_counter % 12 == 0)
81 {
82 m_LastHeartbeat = mytime(NULL);
83 }
84 if (sec_counter % ICY_POLL_INTERVAL ==0)
85 {
86 GetMeterDetails();
87 }
88 }
89 _log.Log(LOG_STATUS,"ICYThermostat: Worker stopped...");
90 }
91
WriteToHardware(const char *,const unsigned char)92 bool CICYThermostat::WriteToHardware(const char* /*pdata*/, const unsigned char /*length*/)
93 {
94 return false;
95 }
96
SendSetPointSensor(const unsigned char Idx,const float Temp,const std::string & defaultname)97 void CICYThermostat::SendSetPointSensor(const unsigned char Idx, const float Temp, const std::string &defaultname)
98 {
99 _tThermostat thermos;
100 thermos.subtype=sTypeThermSetpoint;
101 thermos.id1=0;
102 thermos.id2=0;
103 thermos.id3=0;
104 thermos.id4=Idx;
105 thermos.dunit=0;
106
107 thermos.temp=Temp;
108
109 sDecodeRXMessage(this, (const unsigned char *)&thermos, defaultname.c_str(), 255);
110 }
111
GetSerialAndToken()112 bool CICYThermostat::GetSerialAndToken()
113 {
114 std::stringstream sstr;
115 sstr << "username=" << m_UserName << "&password=" << m_Password;
116 std::string szPostdata=sstr.str();
117 std::vector<std::string> ExtraHeaders;
118 std::string sResult;
119 std::string sURL = "";
120
121 if ((m_companymode == CMODE_UNKNOWN) || (m_companymode == CMODE_PORTAL))
122 sURL = ICY_LOGIN_URL;
123 else if (m_companymode == CMODE_ENI)
124 sURL = ENI_LOGIN_URL;
125 else
126 sURL = SEC_LOGIN_URL;
127
128 if (!HTTPClient::POST(sURL, szPostdata, ExtraHeaders, sResult))
129 {
130 _log.Log(LOG_ERROR,"ICYThermostat: Error login!");
131 return false;
132 }
133 if (sResult.find("BadLogin") != std::string::npos)
134 {
135 if (m_companymode == CMODE_UNKNOWN)
136 {
137 //Try ENI mode
138 sURL = ENI_LOGIN_URL;
139 sResult = "";
140 if (!HTTPClient::POST(sURL, szPostdata, ExtraHeaders, sResult))
141 {
142 _log.Log(LOG_ERROR, "ICYThermostat: Error login!");
143 return false;
144 }
145 if (sResult.find("BadLogin") != std::string::npos)
146 {
147 if (m_companymode == CMODE_UNKNOWN)
148 {
149 //Try SEC mode
150 sURL = SEC_LOGIN_URL;
151 sResult = "";
152 if (!HTTPClient::POST(sURL, szPostdata, ExtraHeaders, sResult))
153 {
154 _log.Log(LOG_ERROR, "ICYThermostat: Error login!");
155 return false;
156 }
157 if (sResult.find("BadLogin") != std::string::npos)
158 {
159 _log.Log(LOG_ERROR, "ICYThermostat: Error login! (Check username/password)");
160 return false;
161 }
162 }
163 else
164 {
165 _log.Log(LOG_ERROR, "ICYThermostat: Error login! (Check username/password)");
166 return false;
167 }
168 }
169 }
170 else
171 {
172 _log.Log(LOG_ERROR, "ICYThermostat: Error login! (Check username/password)");
173 return false;
174 }
175 }
176
177 Json::Value root;
178
179 bool ret = ParseJSon(sResult, root);
180 if ((!ret) || (!root.isObject()))
181 {
182 _log.Log(LOG_ERROR, "ICYThermostat: Invalid data received, or invalid username/password!");
183 return false;
184 }
185 if (root["serialthermostat1"].empty() == true)
186 {
187 _log.Log(LOG_ERROR, "ICYThermostat: Invalid data received, or invalid username/password!");
188 return false;
189 }
190 m_SerialNumber = root["serialthermostat1"].asString();
191 if (root["token"].empty() == true)
192 {
193 _log.Log(LOG_ERROR, "ICYThermostat: Invalid data received, or invalid username/password!");
194 return false;
195 }
196 m_Token = root["token"].asString();
197
198 if (m_companymode == CMODE_UNKNOWN)
199 {
200 if (sURL == ICY_LOGIN_URL)
201 m_companymode = CMODE_PORTAL;
202 else if (sURL == ENI_LOGIN_URL)
203 m_companymode = CMODE_ENI;
204 else
205 m_companymode = CMODE_SEC;
206 }
207
208
209 return true;
210 }
211
GetMeterDetails()212 void CICYThermostat::GetMeterDetails()
213 {
214 if (m_UserName.size()==0)
215 return;
216 if (m_Password.size()==0)
217 return;
218 if (!GetSerialAndToken())
219 return;
220
221 std::string sResult;
222
223 //Get Data
224 std::vector<std::string> ExtraHeaders;
225 ExtraHeaders.push_back("Session-token:"+m_Token);
226
227 std::string sURL = "";
228
229 if (m_companymode == CMODE_PORTAL)
230 sURL = ICY_DATA_URL;
231 else if (m_companymode == CMODE_ENI)
232 sURL = ENI_DATA_URL;
233 else
234 sURL = SEC_DATA_URL;
235
236 if (!HTTPClient::GET(sURL, ExtraHeaders, sResult))
237 {
238 _log.Log(LOG_ERROR,"ICYThermostat: Error getting data!");
239 return;
240 }
241
242 Json::Value root;
243
244 bool ret = ParseJSon(sResult, root);
245 if ((!ret) || (!root.isObject()))
246 {
247 _log.Log(LOG_ERROR, "ICYThermostat: Invalid data received!");
248 return;
249 }
250 if (root["temperature1"].empty() == true)
251 {
252 _log.Log(LOG_ERROR, "ICYThermostat: Invalid data received!");
253 return;
254 }
255 SendSetPointSensor(1, root["temperature1"].asFloat(), "Room Setpoint");
256 if (root["temperature2"].empty() == true)
257 {
258 _log.Log(LOG_ERROR, "ICYThermostat: Invalid data received!");
259 return;
260 }
261 SendTempSensor(1, 255, root["temperature2"].asFloat(), "Room Temperature");
262 }
263
SetSetpoint(const int idx,const float temp)264 void CICYThermostat::SetSetpoint(const int idx, const float temp)
265 {
266 if (idx==1)
267 {
268 //Room Set Point
269 if (!GetSerialAndToken())
270 return;
271
272 char szTemp[20];
273 sprintf(szTemp,"%.1f",temp);
274 std::stringstream sstr;
275 sstr << "uid=" << m_SerialNumber << "&temperature1=" << szTemp;
276 std::string szPostdata=sstr.str();
277
278 std::vector<std::string> ExtraHeaders;
279 ExtraHeaders.push_back("Session-token:"+m_Token);
280 std::string sResult;
281
282 std::string sURL = "";
283 if (m_companymode == CMODE_PORTAL)
284 sURL = ICY_DATA_URL;
285 else if (m_companymode == CMODE_ENI)
286 sURL = ENI_DATA_URL;
287 else
288 sURL = SEC_DATA_URL;
289
290 if (!HTTPClient::POST(sURL, szPostdata, ExtraHeaders, sResult)) {
291 _log.Log(LOG_ERROR,"ICYThermostat: Error setting SetPoint temperature!");
292 }
293 else {
294 _log.Debug(DEBUG_HARDWARE, "ICYThermostat: Setting Room SetPoint to: %.1f", temp);
295 }
296 }
297 }
298