|
16 | 16 | const std::string THERMOSMART_LOGIN_PATH = "https://api.thermosmart.com/login";
|
17 | 17 | const std::string THERMOSMART_AUTHORISE_PATH = "https://api.thermosmart.com/oauth2/authorize?response_type=code&client_id=client123&redirect_uri=http://clientapp.com/done";
|
18 | 18 | const std::string THERMOSMART_DECISION_PATH = "https://api.thermosmart.com/oauth2/authorize/decision";
|
19 |
| -const std::string THERMOSMART_TOKEN_PATH = "https://api.thermosmart.com/oauth2/token"; |
20 |
| -const std::string THERMOSMART_ACCESS_PATH = "https://api.thermosmart.com/thermostat"; |
| 19 | +const std::string THERMOSMART_TOKEN_PATH = "https://username:password@api.thermosmart.com/oauth2/token"; |
| 20 | +const std::string THERMOSMART_ACCESS_PATH = "https://api.thermosmart.com/thermostat/[TID]?access_token=[access_token]"; |
| 21 | +const std::string THERMOSMART_SETPOINT_PATH = "https://api.thermosmart.com/thermostat/[TID]?access_token=[access_token]"; |
21 | 22 |
|
22 | 23 | #ifdef _DEBUG
|
23 | 24 | //#define DEBUG_ThermosmartThermostat
|
@@ -51,10 +52,21 @@ std::string ReadFile(std::string filename)
|
51 | 52 | }
|
52 | 53 | #endif
|
53 | 54 |
|
54 |
| -CThermosmart::CThermosmart(const int ID, const std::string &Username, const std::string &Password) : |
55 |
| -m_UserName(Username), |
56 |
| -m_Password(Password) |
| 55 | +CThermosmart::CThermosmart(const int ID, const std::string &Username, const std::string &Password) |
57 | 56 | {
|
| 57 | + std::vector<std::string> results; |
| 58 | + StringSplit(Username, "*;", results); |
| 59 | + if (results.size()<4) |
| 60 | + { |
| 61 | + _log.Log(LOG_ERROR, "Thermosmart: Invalid login credentials provided"); |
| 62 | + return; |
| 63 | + } |
| 64 | + |
| 65 | + m_UserName = results[0]; |
| 66 | + m_Password = results[1]; |
| 67 | + m_ClientID = results[2]; |
| 68 | + m_ClientSecret = results[3]; |
| 69 | + |
58 | 70 | m_HwdID=ID;
|
59 | 71 | Init();
|
60 | 72 | }
|
@@ -160,33 +172,113 @@ bool CThermosmart::Login()
|
160 | 172 | m_AccessToken = "";
|
161 | 173 | m_ThermostatID = "";
|
162 | 174 |
|
| 175 | + std::string sURL; |
163 | 176 | std::stringstream sstr;
|
164 | 177 | sstr << "username=" << m_UserName << "&password=" << m_Password;
|
165 | 178 | std::string szPostdata=sstr.str();
|
166 | 179 | std::vector<std::string> ExtraHeaders;
|
167 | 180 | std::string sResult;
|
168 | 181 |
|
169 |
| - std::string sURL = THERMOSMART_LOGIN_PATH; |
| 182 | + //# 1. Login |
| 183 | + |
| 184 | + sURL = THERMOSMART_LOGIN_PATH; |
170 | 185 | if (!HTTPClient::POST(sURL, szPostdata, ExtraHeaders, sResult))
|
171 |
| - { |
172 |
| - _log.Log(LOG_ERROR,"Thermosmart: Error login!"); |
173 |
| - return false; |
174 |
| - } |
| 186 | + { |
| 187 | + _log.Log(LOG_ERROR,"Thermosmart: Error login!"); |
| 188 | + return false; |
| 189 | + } |
| 190 | +/* |
175 | 191 | #ifdef DEBUG_ThermosmartThermostat
|
176 | 192 | SaveString2Disk(sResult, "E:\\thermosmart1.txt");
|
177 | 193 | #endif
|
178 |
| - |
| 194 | +*/ |
| 195 | + //# 2. Get Authorize Dialog |
179 | 196 | sURL = THERMOSMART_AUTHORISE_PATH;
|
180 |
| - stdreplace(sURL, "client123", "3de470ce1db15f92"); |
| 197 | + stdreplace(sURL, "client123", m_ClientID); |
181 | 198 | ExtraHeaders.clear();
|
182 | 199 | if (!HTTPClient::GET(sURL, sResult))
|
183 | 200 | {
|
184 | 201 | _log.Log(LOG_ERROR, "Thermosmart: Error login!");
|
185 | 202 | return false;
|
186 | 203 | }
|
| 204 | +/* |
187 | 205 | #ifdef DEBUG_ThermosmartThermostat
|
188 | 206 | SaveString2Disk(sResult, "E:\\thermosmart2.txt");
|
189 | 207 | #endif
|
| 208 | +*/ |
| 209 | + size_t tpos = sResult.find("value="); |
| 210 | + if (tpos == std::string::npos) |
| 211 | + { |
| 212 | + _log.Log(LOG_ERROR, "Thermosmart: Error login!, check username/password"); |
| 213 | + return false; |
| 214 | + } |
| 215 | + sResult = sResult.substr(tpos + 7); |
| 216 | + tpos = sResult.find("\">"); |
| 217 | + if (tpos == std::string::npos) |
| 218 | + { |
| 219 | + _log.Log(LOG_ERROR, "Thermosmart: Error login!, check username/password"); |
| 220 | + return false; |
| 221 | + } |
| 222 | + std::string TID = sResult.substr(0, tpos); |
| 223 | + |
| 224 | + //# 3. Authorize (read out transaction_id from the HTML form received in the previous step). transaction_id prevents from XSRF attacks. |
| 225 | + szPostdata = "transaction_id=" + TID; |
| 226 | + ExtraHeaders.clear(); |
| 227 | + sURL = THERMOSMART_DECISION_PATH; |
| 228 | + if (!HTTPClient::POST(sURL, szPostdata, ExtraHeaders, sResult, false)) |
| 229 | + { |
| 230 | + _log.Log(LOG_ERROR, "Thermosmart: Error login!, check username/password"); |
| 231 | + return false; |
| 232 | + } |
| 233 | +/* |
| 234 | +#ifdef DEBUG_ThermosmartThermostat |
| 235 | + SaveString2Disk(sResult, "E:\\thermosmart3.txt"); |
| 236 | +#endif |
| 237 | +*/ |
| 238 | + tpos = sResult.find("code="); |
| 239 | + if (tpos == std::string::npos) |
| 240 | + { |
| 241 | + _log.Log(LOG_ERROR, "Thermosmart: Error login!, check username/password"); |
| 242 | + return false; |
| 243 | + } |
| 244 | + std::string CODE = sResult.substr(tpos + 5); |
| 245 | + |
| 246 | + //# 4. Exchange authorization code for Access token (read out the code from the previous response) |
| 247 | + szPostdata = "grant_type=authorization_code&code=" + CODE + "&redirect_uri=http://clientapp.com/done"; |
| 248 | + sURL = THERMOSMART_TOKEN_PATH; |
| 249 | + |
| 250 | + stdreplace(sURL, "username", m_ClientID); |
| 251 | + stdreplace(sURL, "password", m_ClientSecret); |
| 252 | + |
| 253 | + if (!HTTPClient::POST(sURL, szPostdata, ExtraHeaders, sResult, false)) |
| 254 | + { |
| 255 | + _log.Log(LOG_ERROR, "Thermosmart: Error login!, check username/password"); |
| 256 | + return false; |
| 257 | + } |
| 258 | +/* |
| 259 | +#ifdef DEBUG_ThermosmartThermostat |
| 260 | + SaveString2Disk(sResult, "E:\\thermosmart4.txt"); |
| 261 | +#endif |
| 262 | +*/ |
| 263 | + Json::Value root; |
| 264 | + Json::Reader jReader; |
| 265 | + bool ret = jReader.parse(sResult, root); |
| 266 | + if (!ret) |
| 267 | + { |
| 268 | + _log.Log(LOG_ERROR, "Thermosmart: Invalid/no data received..."); |
| 269 | + return false; |
| 270 | + } |
| 271 | + |
| 272 | + if (root["access_token"].empty()||root["thermostat"].empty()) |
| 273 | + { |
| 274 | + _log.Log(LOG_ERROR, "Thermosmart: No access granted, check username/password..."); |
| 275 | + return false; |
| 276 | + } |
| 277 | + |
| 278 | + m_AccessToken = root["access_token"].asString(); |
| 279 | + m_ThermostatID = root["thermostat"].asString(); |
| 280 | + |
| 281 | + _log.Log(LOG_STATUS, "Thermosmart: Login successfull!..."); |
190 | 282 |
|
191 | 283 | m_bDoLogin = false;
|
192 | 284 | return true;
|
@@ -227,13 +319,83 @@ void CThermosmart::GetMeterDetails()
|
227 | 319 | if (m_Password.size()==0)
|
228 | 320 | return;
|
229 | 321 | std::string sResult;
|
| 322 | +/* |
| 323 | + sResult = ReadFile("E:\\thermosmart_getdata.txt"); |
| 324 | +*/ |
230 | 325 | if (m_bDoLogin)
|
231 | 326 | {
|
232 | 327 | if (!Login())
|
| 328 | + return; |
| 329 | + } |
| 330 | + std::string sURL = THERMOSMART_ACCESS_PATH; |
| 331 | + stdreplace(sURL, "[TID]", m_ThermostatID); |
| 332 | + stdreplace(sURL, "[access_token]", m_AccessToken); |
| 333 | + if (!HTTPClient::GET(sURL, sResult)) |
| 334 | + { |
| 335 | + _log.Log(LOG_ERROR, "Thermosmart: Error getting thermostat data!"); |
| 336 | + m_bDoLogin = true; |
| 337 | + return; |
| 338 | + } |
| 339 | + |
| 340 | +#ifdef DEBUG_ThermosmartThermostat |
| 341 | + SaveString2Disk(sResult, "E:\\thermosmart_getdata.txt"); |
| 342 | +#endif |
| 343 | + |
| 344 | + Json::Value root; |
| 345 | + Json::Reader jReader; |
| 346 | + bool ret = jReader.parse(sResult, root); |
| 347 | + if (!ret) |
| 348 | + { |
| 349 | + _log.Log(LOG_ERROR, "Thermosmart: Invalid/no data received..."); |
| 350 | + m_bDoLogin = true; |
| 351 | + return; |
| 352 | + } |
| 353 | + |
| 354 | + if (root["target_temperature"].empty() || root["room_temperature"].empty()) |
| 355 | + { |
| 356 | + _log.Log(LOG_ERROR, "Thermosmart: Invalid/no data received..."); |
| 357 | + m_bDoLogin = true; |
233 | 358 | return;
|
234 | 359 | }
|
| 360 | + |
| 361 | + float temperature; |
| 362 | + temperature = (float)root["target_temperature"].asFloat(); |
| 363 | + SendSetPointSensor(1, temperature, "target temperature"); |
| 364 | + |
| 365 | + temperature = (float)root["room_temperature"].asFloat(); |
| 366 | + SendTempSensor(2, 255, temperature, "room temperature"); |
| 367 | + |
| 368 | + if (!root["outside_temperature"].empty()) |
| 369 | + { |
| 370 | + temperature = (float)root["outside_temperature"].asFloat(); |
| 371 | + SendTempSensor(3, 255, temperature, "outside temperature"); |
| 372 | + } |
235 | 373 | }
|
236 | 374 |
|
237 | 375 | void CThermosmart::SetSetpoint(const int idx, const float temp)
|
238 | 376 | {
|
| 377 | + if (m_bDoLogin) |
| 378 | + { |
| 379 | + if (!Login()) |
| 380 | + return; |
| 381 | + } |
| 382 | + |
| 383 | + char szTemp[20]; |
| 384 | + sprintf(szTemp, "%.1f", temp); |
| 385 | + std::string sTemp = szTemp; |
| 386 | + |
| 387 | + std::string szPostdata = "target_temperature=" + sTemp; |
| 388 | + std::vector<std::string> ExtraHeaders; |
| 389 | + std::string sResult; |
| 390 | + |
| 391 | + std::string sURL = THERMOSMART_SETPOINT_PATH; |
| 392 | + stdreplace(sURL, "[TID]", m_ThermostatID); |
| 393 | + stdreplace(sURL, "[access_token]", m_AccessToken); |
| 394 | + if (!HTTPClient::PUT(sURL, szPostdata, ExtraHeaders, sResult)) |
| 395 | + { |
| 396 | + _log.Log(LOG_ERROR, "Thermosmart: Error setting thermostat data!"); |
| 397 | + m_bDoLogin = true; |
| 398 | + return; |
| 399 | + } |
| 400 | + SendSetPointSensor(1, temp, "target temperature"); |
239 | 401 | }
|
0 commit comments