Honeywell thermostat Demand Response events

I am signed up for the demand response program which will change the thermostat settings in periods of high loads on the electric grid.

I saved the json payload during an active demand response event, and latestData.drData element exists only when an event is active. (full payload below).

There are a number of smart thermostats that can work with demand response, so my assumption is that demand response should be added to the climate platform. Thoughts?

{
  "success": true,
  "deviceLive": true,
  "communicationLost": false,
  "latestData": {
    "uiData": {
      "DispTemperature": 76,
      "HeatSetpoint": 68,
      "CoolSetpoint": 78,
      "DisplayUnits": "F",
      "StatusHeat": 2,
      "StatusCool": 2,
      "HoldUntilCapable": true,
      "ScheduleCapable": true,
      "VacationHold": 0,
      "DualSetpointStatus": false,
      "HeatNextPeriod": 86,
      "CoolNextPeriod": 86,
      "HeatLowerSetptLimit": 40,
      "HeatUpperSetptLimit": 80,
      "CoolLowerSetptLimit": 62,
      "CoolUpperSetptLimit": 99,
      "ScheduleHeatSp": 69,
      "ScheduleCoolSp": 75,
      "SwitchAutoAllowed": false,
      "SwitchCoolAllowed": true,
      "SwitchOffAllowed": true,
      "SwitchHeatAllowed": true,
      "SwitchEmergencyHeatAllowed": false,
      "SystemSwitchPosition": 3,
      "Deadband": 0,
      "IndoorHumidity": 38,
      "DeviceID": xxxxxxxxx,
      "Commercial": false,
      "DispTemperatureAvailable": true,
      "IndoorHumiditySensorAvailable": true,
      "IndoorHumiditySensorNotFault": true,
      "VacationHoldUntilTime": 0,
      "TemporaryHoldUntilTime": 0,
      "IsInVacationHoldMode": false,
      "VacationHoldCancelable": true,
      "SetpointChangeAllowed": true,
      "OutdoorTemperature": 128,
      "OutdoorHumidity": 128,
      "OutdoorHumidityAvailable": false,
      "OutdoorTemperatureAvailable": false,
      "DispTemperatureStatus": 0,
      "IndoorHumidStatus": 0,
      "OutdoorTempStatus": 128,
      "OutdoorHumidStatus": 128,
      "OutdoorTemperatureSensorNotFault": true,
      "OutdoorHumiditySensorNotFault": true,
      "CurrentSetpointStatus": 2,
      "EquipmentOutputStatus": 0
    },
    "fanData": {
      "fanMode": 2,
      "fanModeAutoAllowed": true,
      "fanModeOnAllowed": true,
      "fanModeCirculateAllowed": true,
      "fanModeFollowScheduleAllowed": false,
      "fanIsRunning": false
    },
    "hasFan": true,
    "canControlHumidification": false,
    "drData": {
      "CoolSetpLimit": 25.56,
      "HeatSetpLimit": 20,
      "Phase": 1,
      "OptOutable": true,
      "DeltaCoolSP": 2,
      "DeltaHeatSP": -2,
      "Load": null
    }
  },
  "alerts": "\r\n\r\n    <div id=\"PageAlerts\">\r\n        <div class=\"topmiddle-border\">\r\n        </div>\r\n        <div class=\"alert-content\">\r\n            <div class=\"information-image\">\r\n                <img src=\"/portal/Images/Alerts/alert_red_icon.png?v=2.8.22\" alt=\"Alert Information\" />\r\n            </div>\r\n            <div class=\"alert-messages\">\r\n                <ul>\r\n                        <li>\r\n                            <div class=\"alertActions\">\r\n                                    <div class=\"gray-31-button viewDR\">\r\n                                                <a href=\"javascript:void(0);\" onclick=\" openDrOptOutPopup('1'); \">View</a>\r\n                                    </div>\r\n                            </div>\r\n\r\n                                <span>Your Thermostat is in an Energy Saving Event. This event is scheduled to finish at 8:04 PM Mountain Time (US, Canada, Mexico).</span>\r\n\r\n                            <div class=\"clear\"></div>\r\n\r\n                        </li>\r\n                                    </ul>\r\n            </div>\r\n            <div class=\"dealerinfobutton gray-31-button\">\r\n            </div>\r\n            <div class=\"clear\"></div>\r\n        </div>\r\n        <div class=\"bottommiddle-border\">\r\n        </div>\r\n    </div>\r\n\r\n           \r\n<div id=\"drPopupView1\" class=\"drPopupWindow\" title=\"Energy Saving Event\">\r\n    <p>\r\n        Your Thermostat is in an Energy Savings Event until 8:04 PM Mountain Time (US, Canada, Mexico). To Opt-Out of this event click &quot;Opt-Out&quot; below.\r\n    </p>\r\n    <div class=\"buttons\">\r\n        <div>\r\n            <a onclick=\"openDrConfirmOptOutPopup();\" href=\"javascript:void(0)\" class=\"red\">Opt-Out</a>\r\n        </div>\r\n        <div>\r\n            <a onclick=\"closeDrPopup();\" href=\"javascript:void(0)\" class=\"green\">OK</a>\r\n        </div>\r\n    </div>\r\n</div>\r\n<div id=\"drPopupView2\" class=\"drPopupWindow\" title=\"Energy Saving Event\">\r\n    <p>\r\n        Your Thermostat is in an Energy Savings Event until 8:04 PM Mountain Time (US, Canada, Mexico).\r\n    </p>\r\n    <div class=\"buttons\">\r\n        <div>\r\n            <a onclick=\"closeDrPopup();\" href=\"javascript:void(0)\" class=\"green\">OK</a>\r\n        </div>\r\n    </div>\r\n</div>\r\n<div id=\"drPopupView3\" class=\"drPopupWindow\" title=\"Energy Saving Event\">\r\n    <p>\r\n        Your Thermostat is in an Energy Savings Event until 8:04 PM Mountain Time (US, Canada, Mexico). In order to make a change to your temperature setting you must first opt-out of this event. To Opt-Out of this event click &quot;Opt-Out&quot; below.&quot;\r\n    </p>\r\n    <div class=\"buttons\">\r\n        <div>\r\n            <a onclick=\"openDrConfirmOptOutPopup();\" href=\"javascript:void(0)\" class=\"red\">Opt-Out</a>\r\n        </div>\r\n        <div>\r\n            <a onclick=\"closeDrPopup();\" href=\"javascript:void(0)\" class=\"green\">OK</a>\r\n        </div>\r\n    </div>\r\n</div>\r\n<div id=\"drPopupView4\" class=\"drPopupWindow\" title=\"Opt-Out Confirmation\">\r\n    <p>\r\n        Are you sure you want to Opt-Out of this energy saving event? After you Opt-Out of an event you cannot Opt-In to it again.\r\n    </p>\r\n    <div class=\"buttons\">\r\n        <div>\r\n            <a class=\"red\" data-ajax=\"true\" data-ajax-complete=\"onDoOptOutCompleted\" data-ajax-method=\"POST\" href=\"/portal/Device/DemandResponseOptOut/1625920\">Yes</a>\r\n        </div>\r\n        <div>\r\n            <a onclick=\"closeDrPopup();\" href=\"javascript:void(0)\" class=\"green\">No</a>\r\n        </div>\r\n    </div>\r\n</div>\r\n"
}

Hi @ericgla, Thanks for your post.

This seems doable…

I am the CODEOWNER for honeywell, but I don’t have regular access to one (if we proceed, I may need access to your system, or you can test for me?).

The client library exposes the drData, so no problem there…

Can you give more information? I have to write the code, you see…

Are you saying the working setpoint is the scheduled setpoint less the deltas? Say:

  • CoolSetpoint (78) = ScheduleCoolSp - DeltaCoolSP = 75 +2 = 77 !
  • HeatSetpoint (68) = ScheduleHeatSp - DeltaHeatSP = 69 -2 = 67 !

As you can see, the numbers don’t match!

In any case, the HA UI shows the CoolSetpoint and HeatSetpoint, so it should be all good?

David,

It’s 100+ in Denver today, so I have another demand response event to look at. I’ll be happy to share my TCC login with you for testing, but we would need to do it when there is an upcoming or active event.

Upcoming demand response event: drData !== undefined && drData.Phase === 0

Active demand response event: drData !== undefined && drData.Phase > 0 && drData.Phase <= 3

No or Expired demand response event: drData === undefined

Not sure what Phase 1-3 specify, but the TCC js code just checks for Phase equal to a range of 1-3. There isn’t any specific behavior for a single Phase value.

If you look at the other properties of the drData element, everything is in Celsius. A delta of 2C is 2.6F, so the setpoint math works (with rounding).

One more update. It looks like the DeltaCoolSp isn’t used at all, and the current setpoint is determined by CoolSetpLimit alone.

Currently my CoolSetpoint is still at 75, DeltaCoolSp is 2, and CoolSetpLimit is 26.11C (79F). uiData. CoolSetpoint is also 79.

@ericgla Can you clarify what you’re expecting? The HA UI to show the correct temp (you haven’t explicity said it isn’t), or for the dr mode to be indicated in the UI, or as a state attribute?

The most useful data to expose would be the dr mode as a state attribute. When the dr event is over, the thermostat is left at the higher setpoint, so by exposing the dr mode, I would be able to have automation to restore the original setpoint.

FWIW, the HA UI shows current setpoints as:

  • self._data['uiData']['CoolSetpoint'], and
  • self._data['uiData']['HeatSetpoint']

The system that I do have access to says:

'drData': {
	'CoolSetpLimit': None,
	'HeatSetpLimit': None,
	'Phase': -1,
	'OptOutable': False,
	'DeltaCoolSP': None,
	'DeltaHeatSP': None,
	'Load': None
}

I get the sense that maybe it’s not as simple as you say?

  • manual setpoints limited by CoolSetpLimit and HeatSetpLimit?
  • scheduled setpoints adjusted by: DeltaCoolSP and DeltaHeatSP?

Or the above changes according to Phase?

And when the dr event has finished - do CoolSetpoint and HeatSetpoint just return to ‘normal’?

What I can easily do is just add dr_phase as a state attribute: Optional[int] (i.e. could be and integer, or Null/None)?

That should be enough, and it won’t run the risk of affecting those who don’t use dr, and are happy with the status quo?

This works OK:

    @property
    def device_state_attributes(self) -> Dict[str, Any]:
        """Return the device specific state attributes."""
        # pylint: disable=protected-access
        data = {}
        if self._device._data['hasFan']:
            data[ATTR_FAN_ACTION] = \
                'running' if self._device.fan_running else 'idle'
        if self._device._data['drData']:
            data['dr_phase'] = self._device._data['drData'].get('Phase')
        return data

It looks like the someComfort lib sets the drData element to default values (shown above) when there is no dr event, and the drData element is undefined in the response payload from TCC. My guess is that they use a non nullable int for Phase, which is why it defaults to -1.

What I do know is that the in manual mode, the CoolSetpoint and HeatSetpoint do not return to their original values at the end of the dr event. I would assume that if I had a schedule set, the setpoints would update on the schedule change.

I’ve only been able to capture 2 events, so I don’t think I have enough information to fully understand how all of the values in drData are used. Simply adding dr_phase would be good enough for now!

I had a look at somecomfort and I think it just passes ‘drData’ through unmolested.

In any case, I’ll just add dr_data as above.

Thanks for the quick turnaround on this change! I’ll start running it as a custom component and let you know if I run into any issues.

The honeywell integration has changes a lot in the latest PR & could really do with some testing / feedback (I don’t have one to test), but please feedback via https://github.com/home-assistant/home-assistant/issues

I don’t know if it helps, but I’ll share my data from a DR event:

{
   "drData" : {
      "OptOutable" : true,
      "DeltaCoolSP" : -1.11,
      "DeltaHeatSP" : null,
      "Phase" : 1,
      "Load" : null,
      "CoolSetpLimit" : 22.22,
      "HeatSetpLimit" : null
   }
}

Thermostat displays setpoint of 72 F (my scheduled value is 74 F).

In a previous event, instead of using CoolSetpLimit, they set Load to 0.25. In practice, it seemed to regulate the duty cycle. In that event, my scheduled setpoint was displayed, but the A/C was only triggered about 25% of the time (about 15 minutes every hour) even though the current temp was above the setpoint. I think Phase was 2, but I’m not sure.

…and as I posted that, it changed the setpoint to 77 F with the following:

{
   "drData" : {
      "Load" : null,
      "CoolSetpLimit" : 25,
      "DeltaCoolSP" : 1.66,
      "DeltaHeatSP" : null,
      "OptOutable" : true,
      "Phase" : 2,
      "HeatSetpLimit" : null
   }
}

Phase changed from 1 to 2, so maybe that’s a trigger that the values should be reapplied.

Given that, and that my scheduled setpoint was 74 F, I’m guessing that DeltaCoolSP = CoolSetpLimit - Scheduled (in C)

It looks like the intent here was to first run the system cooler to pre-chill the house starting at 4 PM, then bump the setpoint 5 degF warmer at 5 PM to reduce the overall load from that point. Event is scheduled to end at 6 PM. This is the first year I’ve seen the events actually occur, so I suspect my utility is trying out different algorithms to see what works best.

I am happy to ad some intelligence to the honeywell component for these demand response events, but I would need a very clear specification of the effects of the various drData parameters.

Does anyone have access to developer docs?

It’s not a developer interface, it’s using the website’s internal AJAX interface, so there’s probably no documentation available.

We don’t have a spec, but here’s my capture from all phases of a summer DR event:

{"drData":{"CoolSetpLimit":null,"HeatSetpLimit":null,"Phase":0,"OptOutable":true,"DeltaCoolSP":null,"DeltaHeatSP":null,"Load":null}}
{"drData":{"CoolSetpLimit":21.11,"HeatSetpLimit":null,"Phase":1,"OptOutable":true,"DeltaCoolSP":-1.11,"DeltaHeatSP":null,"Load":null}}
{"drData":{"CoolSetpLimit":23.89,"HeatSetpLimit":null,"Phase":2,"OptOutable":true,"DeltaCoolSP":1.66,"DeltaHeatSP":null,"Load":null}}
{"drData":{"CoolSetpLimit":null,"HeatSetpLimit":null,"Phase":-1,"OptOutable":false,"DeltaCoolSP":null,"DeltaHeatSP":null,"Load":null}}

I think this is enough we can infer the behavior for a Delta event.

My cooling set point is 72 °F. Normally, Phase is -1.

  • A few hours before this DR event started, Phase changed to 0, and OptOutable changed to true.
  • At the start of the DR event, Phase changed to 1, my set point was dropped 2 °F to 70 °F (1.11 °C to 21.11 °C), apparently as a pre-cooling cycle.
  • One hour into the DR event, Phase changed to 2, and my set point was raised 3 °F above my original to 75 °F (1.66 °C to 23.89 °C). Swinging from 70 °F to 75 °F should obviously reduce the demand significantly.
  • At the end of the DR event, Phase changed back to -1, my original set point was restored, and OptOutable returned to false.

A few potential attributes to add to the climate entity:

  • DR phase
    • none (if Phase < 0)
    • upcoming (if Phase == 0 && !DeltaCoolSp && !DeltaHeatSp)
    • pre-cooling (if DeltaCoolSp < 0)
    • pre-heating (if DeltaHeatSp > 0)
    • limiting cooling (if DeltaCoolSp > 0)
    • limiting heating (if DeltaHeatSp < 0)
  • OptOutable

I’ll have to think through what to do if there’s a Load limit.

Got our first DR event of the season last week. It only lasted 30 minutes, so I think they were just testing:

drData': {'CoolSetpLimit': None, 'HeatSetpLimit': None, 'Phase': -1, 'OptOutable': False, 'DeltaCoolSP': None, 'DeltaHeatSP': None, 'Load': None}
drData': {'CoolSetpLimit': 22.78, 'HeatSetpLimit': None, 'Phase': 1, 'OptOutable': True, 'DeltaCoolSP': 0.55, 'DeltaHeatSP': None, 'Load': None}
drData': {'CoolSetpLimit': 22.78, 'HeatSetpLimit': None, 'Phase': 1, 'OptOutable': True, 'DeltaCoolSP': 0.55, 'DeltaHeatSP': None, 'Load': None}
drData': {'CoolSetpLimit': None, 'HeatSetpLimit': None, 'Phase': -1, 'OptOutable': False, 'DeltaCoolSP': None, 'DeltaHeatSP': None, 'Load': None}

In which the setpoint was raised by 1 °F (0.55 °C) from 72 °F to 73 °F for 30 minutes, then restored.