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