Skip to content

Commit 4dc7681

Browse files
authored
Merge pull request #4231 from deligoz/patch-1
Update Honeywell.cpp
2 parents 885ede4 + 46df5c5 commit 4dc7681

File tree

2 files changed

+178
-40
lines changed

2 files changed

+178
-40
lines changed

hardware/Honeywell.cpp

Lines changed: 177 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@ const std::string HONEYWELL_LOCATIONS_PATH = "https://api.honeywell.com/v2/locat
2020
const std::string HONEYWELL_UPDATE_THERMOSTAT = "https://api.honeywell.com/v2/devices/thermostats/[deviceid]?apikey=[apikey]&locationId=[locationid]";
2121
const std::string HONEYWELL_TOKEN_PATH = "https://api.honeywell.com/oauth2/token";
2222

23-
const std::string kHeatSetPointDesc = "Target temperature ([devicename])";
24-
const std::string kHeatingDesc = "Heating ([devicename])";
25-
const std::string kOperationStatusDesc = "Heating state ([devicename])";
23+
const std::string kSetPointDesc = "Target temperature ([devicename])";
24+
const std::string kHeatingDesc = "Heating Mode([devicename])";
25+
const std::string kCoolingDesc = "Cooling Mome([devicename])";
26+
const std::string kHeatingStatusDesc = "Heating State ([devicename])";
27+
const std::string kCoolingStatusDesc = "Cooling State ([devicename])";
2628
const std::string kOutdoorTempDesc = "Outdoor temperature ([devicename])";
2729
const std::string kRoomTempDesc = "Room temperature ([devicename])";
2830
const std::string kAwayDesc = "Away ([name])";
31+
const std::string kfanRequest = "Fan Request ([devicename])";
32+
const std::string kcirculationFanRequest = "Circulation Fan Request ([devicename])";
2933

3034
extern http::server::CWebServerHelper m_webservers;
3135

@@ -123,19 +127,19 @@ void CHoneywell::Do_Work()
123127
//
124128
bool CHoneywell::WriteToHardware(const char *pdata, const unsigned char /*length*/)
125129
{
130+
126131
const tRBUF *pCmd = reinterpret_cast<const tRBUF *>(pdata);
132+
127133
if (pCmd->LIGHTING2.packettype == pTypeLighting2)
128134
{
129135
//Light command
130-
131-
int nodeID = pCmd->LIGHTING2.id3;
136+
137+
int nodeID = pCmd->LIGHTING2.id4;
132138
int devID = nodeID / 10;
133139
std::string deviceName = mDeviceList[devID]["name"].asString();
134-
135-
136140
bool bIsOn = (pCmd->LIGHTING2.cmnd == light2_sOn);
137-
if ((nodeID % 10) == 3) {
138-
// heating on or off
141+
if ((nodeID % 10) == 3 | (nodeID % 10) == 7) {
142+
// heating cooling on or off
139143
SetPauseStatus(devID, bIsOn, nodeID);
140144
return true;
141145
}
@@ -248,40 +252,83 @@ void CHoneywell::GetThermostatData()
248252
Json::Value devices = location["devices"];
249253
for (int devCnt = 0; devCnt < (int)devices.size(); devCnt++)
250254
{
255+
251256
Json::Value device = devices[devCnt];
252257
std::string deviceName = device["name"].asString();
253258
mDeviceList[devNr] = device;
254259
mLocationList[devNr] = location["locationID"].asString();
255260

261+
std::string units = device["units"].asString(); //:"Fahrenheit"
262+
256263
float temperature;
257264
temperature = (float)device["indoorTemperature"].asFloat();
258265
std::string desc = kRoomTempDesc;
259266
stdreplace(desc, "[devicename]", deviceName);
260-
SendTempSensor(10 * devNr + 1, 255, temperature, desc);
267+
if(units == "Fahrenheit") {
268+
SendTempSensor(10 * devNr + 1, 255, (float)ConvertToCelsius(temperature), desc);
269+
}else{
270+
SendTempSensor(10 * devNr + 1, 255, temperature, desc);
271+
}
261272

262273
temperature = (float)device["outdoorTemperature"].asFloat();
263274
desc = kOutdoorTempDesc;
264275
stdreplace(desc, "[devicename]", deviceName);
265-
SendTempSensor(10 * devNr + 2, 255, temperature, desc);
276+
if(units == "Fahrenheit") {
277+
SendTempSensor(10 * devNr + 2, 255, (float)ConvertToCelsius(temperature), desc);
278+
}else{
279+
SendTempSensor(10 * devNr + 2, 255, temperature, desc);
280+
}
266281

267282
std::string mode = device["changeableValues"]["mode"].asString();
268283
bool bHeating = (mode == "Heat");
269284
desc = kHeatingDesc;
270285
stdreplace(desc, "[devicename]", deviceName);
271286
SendSwitch(10 * devNr + 3, 1, 255, bHeating, 0, desc);
272287

273-
temperature = (float)device["changeableValues"]["heatSetpoint"].asFloat();
274-
desc = kHeatSetPointDesc;
288+
if(bHeating){
289+
temperature = (float)device["changeableValues"]["heatSetpoint"].asFloat();
290+
}else{
291+
temperature = (float)device["changeableValues"]["coolSetpoint"].asFloat();
292+
}
293+
desc = kSetPointDesc;
275294
stdreplace(desc, "[devicename]", deviceName);
276-
SendSetPointSensor((uint8_t)(10 * devNr + 4), temperature, desc);
277-
devNr++;
295+
if(units == "Fahrenheit") {
296+
SendSetPointSensor((uint8_t)(10 * devNr + 4), (float)ConvertToCelsius(temperature), desc);
297+
}else{
298+
SendSetPointSensor((uint8_t)(10 * devNr + 4), temperature, desc);
299+
}
278300

279301
std::string operationstatus = device["operationStatus"]["mode"].asString();
280-
bool bStatus = (operationstatus != "EquipmentOff");
281-
desc = kOperationStatusDesc;
302+
bool bStatus = (operationstatus == "Heat");
303+
desc = kHeatingStatusDesc;
282304
stdreplace(desc, "[devicename]", deviceName);
283305
SendSwitch(10 * devNr + 5, 1, 255, bStatus, 0, desc);
284-
}
306+
307+
//std::string operationstatus = device["operationStatus"]["mode"].asString();
308+
bool bCStatus = (operationstatus == "Cool");
309+
desc = kCoolingStatusDesc;
310+
stdreplace(desc, "[devicename]", deviceName);
311+
SendSwitch(10 * devNr + 6, 1, 255, bCStatus, 0, desc);
312+
313+
//std::string mode = device["changeableValues"]["mode"].asString();
314+
bool bCooling = (mode == "Cool");
315+
desc = kCoolingDesc;
316+
stdreplace(desc, "[devicename]", deviceName);
317+
SendSwitch(10 * devNr + 7, 1, 255, bCooling, 0, desc);
318+
319+
bool fanRequest = device["operationStatus"]["fanRequest"].asBool();
320+
desc = kfanRequest;
321+
stdreplace(desc, "[devicename]", deviceName);
322+
SendSwitch(10 * devNr + 8, 1, 255, fanRequest, 0, desc);
323+
324+
bool circulationFanRequest = device["operationStatus"]["circulationFanRequest"].asBool();
325+
desc = kcirculationFanRequest;
326+
stdreplace(desc, "[devicename]", deviceName);
327+
SendSwitch(10 * devNr + 9, 1, 255, circulationFanRequest, 0, desc);
328+
329+
devNr++;
330+
331+
}
285332

286333
bool geoFenceEnabled = location["geoFenceEnabled"].asBool();
287334
if (geoFenceEnabled) {
@@ -324,13 +371,35 @@ void CHoneywell::SendSetPointSensor(const unsigned char Idx, const float Temp, c
324371
//
325372
// transfer pause status to Honeywell api
326373
//
327-
void CHoneywell::SetPauseStatus(const int idx, bool bHeating, const int /*nodeid*/)
374+
void CHoneywell::SetPauseStatus(const int idx, bool bCommand, const int nodeID)
328375
{
329376
if (!refreshToken()) {
330377
_log.Log(LOG_ERROR,"Honeywell: No token available. Failed setting thermostat data");
331378
return;
332379
}
333380

381+
std::string currentMode = mDeviceList[idx]["changeableValues"]["mode"].asString();
382+
383+
bool bHeating = currentMode == "Heat";
384+
bool nHeat = currentMode == "Heat";
385+
bool nCool = currentMode == "Cool";
386+
387+
if ((nodeID % 10) == 3){
388+
nHeat = bCommand;
389+
bHeating = true;
390+
if(bCommand){
391+
nCool = false;
392+
}
393+
}
394+
if ((nodeID % 10) == 7){
395+
nCool = bCommand;
396+
bHeating = false;
397+
if(bCommand){
398+
nHeat = false;
399+
}
400+
}
401+
402+
334403
std::string url = HONEYWELL_UPDATE_THERMOSTAT;
335404
std::string deviceID = mDeviceList[idx]["deviceID"].asString();
336405

@@ -339,8 +408,9 @@ void CHoneywell::SetPauseStatus(const int idx, bool bHeating, const int /*nodeid
339408
stdreplace(url, "[locationid]", mLocationList[idx]);
340409

341410
Json::Value reqRoot;
342-
reqRoot["mode"] = bHeating ? "Heat" : "Off";
343-
reqRoot["heatSetpoint"] = mDeviceList[idx]["changeableValues"]["coolHeatpoint"].asInt();
411+
reqRoot["mode"] = nHeat ? "Heat" : (nCool ? "Cool" : "Off");
412+
reqRoot["autoChangeoverActive"] = "true";
413+
reqRoot["heatSetpoint"] = mDeviceList[idx]["changeableValues"]["heatSetpoint"].asInt();
344414
reqRoot["coolSetpoint"] = mDeviceList[idx]["changeableValues"]["coolSetpoint"].asInt();
345415
reqRoot["thermostatSetpointStatus"] = "TemporaryHold";
346416

@@ -351,16 +421,38 @@ void CHoneywell::SetPauseStatus(const int idx, bool bHeating, const int /*nodeid
351421
_log.Log(LOG_ERROR, "Honeywell: Error setting thermostat data!");
352422
return;
353423
}
354-
355424
std::string desc = kHeatingDesc;
356425
stdreplace(desc, "[devicename]", mDeviceList[idx]["name"].asString());
357-
SendSwitch(10 * idx + 3, 1, 255, bHeating, 0, desc);
426+
SendSwitch(10 * idx + 3, 1, 255, nHeat, 0, desc);
427+
428+
desc = kCoolingDesc;
429+
stdreplace(desc, "[devicename]", mDeviceList[idx]["name"].asString());
430+
SendSwitch(10 * idx + 7, 1, 255, nCool, 0, desc);
431+
432+
if(bCommand){
433+
std::string units = mDeviceList[idx]["units"].asString();
434+
float temperature;
435+
if(nHeat){
436+
temperature = (float)mDeviceList[idx]["changeableValues"]["heatSetpoint"].asFloat();
437+
}else{
438+
temperature = (float)mDeviceList[idx]["changeableValues"]["coolSetpoint"].asFloat();
439+
}
440+
desc = kSetPointDesc;
441+
stdreplace(desc, "[devicename]", mDeviceList[idx]["name"].asString());
442+
if(units == "Fahrenheit") {
443+
SendSetPointSensor((uint8_t)(10 * idx + 4), (float)ConvertToCelsius(temperature), desc);
444+
}else{
445+
SendSetPointSensor((uint8_t)(10 * idx + 4), temperature, desc);
446+
}
447+
}
448+
449+
358450
}
359451

360452
//
361453
// transfer the updated temperature to Honeywell API
362454
//
363-
void CHoneywell::SetSetpoint(const int idx, const float temp, const int /*nodeid*/)
455+
void CHoneywell::SetSetpoint(const int idx, const float temp, const int nodeid)
364456
{
365457
if (!refreshToken()) {
366458
_log.Log(LOG_ERROR, "Honeywell: No token available. Error setting thermostat data!");
@@ -375,24 +467,69 @@ void CHoneywell::SetSetpoint(const int idx, const float temp, const int /*nodeid
375467
stdreplace(url, "[locationid]", mLocationList[idx]);
376468

377469
Json::Value reqRoot;
378-
reqRoot["mode"] = "Heat";
379-
reqRoot["heatSetpoint"] = temp;
380-
reqRoot["coolSetpoint"] = mDeviceList[idx]["changeableValues"]["coolSetpoint"].asInt();
470+
std::string units = mDeviceList[idx]["units"].asString();
471+
472+
if(GetSwitchValue((uint8_t)(10 * idx + 7)) /* mode set for cooling*/){
473+
reqRoot["mode"] = "Cool";
474+
reqRoot["autoChangeoverActive"] = "true";
475+
reqRoot["heatSetpoint"] = mDeviceList[idx]["changeableValues"]["heatSetpoint"].asInt();
476+
477+
if(units == "Fahrenheit") {
478+
reqRoot["coolSetpoint"] = (float)ConvertToFahrenheit(temp);
479+
}else{
480+
reqRoot["coolSetpoint"] = temp;
481+
}
482+
}else{
483+
reqRoot["mode"] = "Heat";
484+
reqRoot["autoChangeoverActive"] = "true";
485+
if(units == "Fahrenheit") {
486+
reqRoot["heatSetpoint"] = (float)ConvertToFahrenheit(temp);
487+
}else{
488+
reqRoot["heatSetpoint"] = temp;
489+
}
490+
reqRoot["coolSetpoint"] = mDeviceList[idx]["changeableValues"]["coolSetpoint"].asInt();
491+
}
492+
493+
//reqRoot["thermostatSetpointStatus"] = "PermanentHold";
381494
reqRoot["thermostatSetpointStatus"] = "TemporaryHold";
382-
383495
std::string sResult;
384-
HTTPClient::SetConnectionTimeout(HWAPITIMEOUT);
385-
HTTPClient::SetTimeout(HWAPITIMEOUT);
386-
if (!HTTPClient::POST(url, JSonToRawString(reqRoot), mSessionHeaders, sResult, true, true)) {
387-
_log.Log(LOG_ERROR, "Honeywell: Error setting thermostat data!");
388-
return;
389-
}
496+
if(GetSwitchValue((uint8_t)(10 * idx + 7)) | GetSwitchValue((uint8_t)(10 * idx + 3))){
497+
HTTPClient::SetConnectionTimeout(HWAPITIMEOUT);
498+
HTTPClient::SetTimeout(HWAPITIMEOUT);
499+
if (!HTTPClient::POST(url, JSonToRawString(reqRoot), mSessionHeaders, sResult, true, true)) {
500+
_log.Log(LOG_ERROR, "Honeywell: Error setting thermostat data!");
501+
return;
502+
}
390503

391-
std::string desc = kHeatSetPointDesc;
392-
stdreplace(desc, "[devicename]", mDeviceList[idx]["name"].asString());
393-
SendSetPointSensor((uint8_t)(10 * idx + 4), temp, desc);
504+
std::string desc = kSetPointDesc;
505+
stdreplace(desc, "[devicename]", mDeviceList[idx]["name"].asString());
506+
SendSetPointSensor((uint8_t)(10 * idx + 4), temp, desc);
507+
}
508+
//desc = kHeatingDesc;
509+
//stdreplace(desc, "[devicename]", mDeviceList[idx]["name"].asString());
510+
//SendSwitch(10 * idx + 3, 1, 255, true, 0, desc);
511+
}
394512

395-
desc = kHeatingDesc;
396-
stdreplace(desc, "[devicename]", mDeviceList[idx]["name"].asString());
397-
SendSwitch(10 * idx + 3, 1, 255, true, 0, desc);
513+
bool CHoneywell::GetSwitchValue(const int NodeID)
514+
{
515+
uint8_t ChildID = 1;
516+
//make device ID
517+
unsigned char ID1 = (unsigned char)((NodeID & 0xFF000000) >> 24);
518+
unsigned char ID2 = (unsigned char)((NodeID & 0xFF0000) >> 16);
519+
unsigned char ID3 = (unsigned char)((NodeID & 0xFF00) >> 8);
520+
unsigned char ID4 = (unsigned char)NodeID & 0xFF;
521+
522+
char szIdx[10];
523+
sprintf(szIdx, "%X%02X%02X%02X", ID1, ID2, ID3, ID4);
524+
std::vector<std::vector<std::string> > result;
525+
result = m_sql.safe_query("SELECT Name,nValue,sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Unit == %d) AND (Type==%d) AND (Subtype==%d)",
526+
m_HwdID, szIdx, ChildID, int(pTypeLighting2), int(sTypeAC));
527+
if (!result.empty())
528+
{
529+
int nvalue = atoi(result[0][1].c_str());
530+
return (nvalue != light2_sOff);
531+
}else{
532+
return false;
533+
_log.Log(LOG_ERROR, "Honeywell: Error reading switch data!");
534+
}
398535
}

hardware/Honeywell.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class CHoneywell : public CDomoticzHardwareBase
2424
bool StopHardware() override;
2525
void Do_Work();
2626
void GetThermostatData();
27+
bool GetSwitchValue(const int NodeID);
2728
private:
2829
std::string mApiKey;
2930
std::string mApiSecret;

0 commit comments

Comments
 (0)