Enhanced version of MQTT HVAC (Climate platform) with proper History Chart

Tags: #<Tag:0x00007f3f133e4410>

NOTE

This post has been updated (2019-06-18).

The latest version of my enhanced MQTT HVAC component has been revised for use with Home Assistant 0.93+


I’ve created a version of MQTT HVAC (MQTT climate platform) with the following enhancements:

  • Supports monitoring the HVAC system’s current operating state ( activity_state_topic status_state_topic). This permits the thermostat to report the current state of the HVAC system (its activity: heating/cooling/idle) as opposed to its operating mode (heat/cool/auto/off). This also lets the History Chart correctly show when the HVAC system is actively heating/cooling (green-shaded area in chart).

  • Automatically sets the temperature step-size based on the unit system (metric = 0.5, imperial = 1.0). You can override this behavior by setting a desired step-size using the temp_step parameter. In the current release version (0.81) MQTT HVAC supports temp_step (but does not auto-configure itself based on the unit system).

  • Convert mode with a template for publishing to MQTT (mode_command_template).

  • Convert fan_mode with a template for publishing to MQTT (fan_mode_command_template).

  • Convert hold with a template for publishing to MQTT (hold_command_template).

Here’s an example of how I have it configured for my thermostat.

climate:
  - platform: my_mqtt
    name: "Thermostat"
    qos: 0
    payload_on: 1
    payload_off: 0
    # ENHANCEMENT: Get actual HVAC status. Must map to 'heat'and 'cool'.
    activity_state_topic: "home/thermostat/heatingstatus"
    activity_state_template: >-
      {% set values = { '1':'heat', '2':'cool', '4':'idle'} %}
      {{ values[value] if value in values.keys() else 'idle'}}
    modes:
      - auto
      - heat
      - cool
      - 'off'
    mode_state_topic: "home/thermostat/temperaturemode" 
    mode_state_template: >-
      {% set values = { '0':'auto', '1':'heat',  '2':'cool', '4':'off'} %}
      {{ values[value] if value in values.keys() else 'off' }}
    mode_command_topic: "home/thermostat/temperaturemode/command"
    # ENHANCEMENT: Convert mode for publishing to MQTT
    mode_command_template: >-
      {% set values = { 'auto':'0', 'heat':'1',  'cool':'2', 'off':'4'} %}
      {{ values[value] if value in values.keys() else '4' }}
    fan_modes:
      - auto
      - 'on'
    fan_mode_state_topic: "home/thermostat/fancontrol"
    fan_mode_state_template: >-
      {% set values = { '0':'auto', '1':'on'} %}
      {{ values[value] if value in values.keys() else 'auto' }}
    fan_mode_command_topic: "home/thermostat/fancontrol/command"
    # ENHANCEMENT: Convert fan_mode for publishing to MQTT.
    fan_mode_command_template: >-
      {% set values = { 'auto':'0', 'on':'1'} %}
      {{ values[value] if value in values.keys() else '0' }}
    current_temperature_topic: "home/thermostat/temperature"
    min_temp: 17
    max_temp: 28
    temp_step: 0.5
    temperature_state_topic: "home/thermostat/currentsetpoint"
    temperature_command_topic: "home/thermostat/currentsetpoint/command"
    hold_state_topic: "home/thermostat/mode"
    hold_state_template: "{{ 'hold' if value == '2' else 'auto' }}"
    hold_command_topic: "home/thermostat/mode/command"
    # ENHANCEMENT: Convert hold for publishing to MQTT.
    hold_command_template: "{{ '2' if value == 'hold' else '0' }}"

To have History Chart work correctly, you must convert activity_state_topic's payloads into the key-words heat and cool (see activity_state_template in the example above). They are the only two key-words the chart knows how to represent with a shaded area (the key-words are hard-coded in the Lovelace UI). When the HVAC state is neither heating or cooling, I prefer to represent that state as ‘idle’ but it can also be ‘off’.

Here’s an example of the History Chart showing when my furnace was heating (the green-shaded areas). It just finished a heating cycle, raising the temperature from 21 to 21.5 and is now idle.

Installation Instructions

Create a new directory under custom_components called my_mqtt (or choose something else other than mqtt).

config/custom_components/my_mqtt

Copy the contents of this pastebin link into a new file called climate.py.

config/custom_components/my_mqtt/climate.py

Create a new file in the same directory named manifest.json. Paste the following text into the file and save it.

{
  "domain": "my_mqtt",
  "name": "My MQTT",
  "documentation": "https://www.home-assistant.io/components/climate.mqtt/",
  "dependencies": ["mqtt"],
  "codeowners": [],
  "requirements": []
}

In configuration.yaml, find your existing MQTT climate entity and replace:

platform: mqtt

with:

platform: my_mqtt

The next step is needed ONLY if your climate entity uses the unique_id option. If it doesn’t then simply run Config Check and restart Home Assistant. If it does then perform the following additional steps:

  1. Stop Home Assistant.
  2. Save a copy of config/.storage/core.entity_registry to serve as a backup.
  3. Use a text editor to modify the following file: config/.storage/core.entity_registry
  4. Find your climate entity and replace: “platform”: “mqtt” with “platform”: “my_mqtt”
  5. Save the file and restart Home Assistant.
1 Like

@flyboy
Replying to your post here because this thread is specifically about enhancing MQTT HVAC.

Thanks for making the enhancements!

My “update” is based on the discussion I started here:

In a nutshell, I want the thermostat’s history chart to show when the furnace is actively heating (or A/C is cooling) and not simply when it is in “heat mode” (which is what almost all of Home Assistant climate platforms currently do). To achieve this, the climate platform has to acquire the operating state which means, for MQTT HVAC, yet another MQTT topic (and template) dedicated to this purpose.

In this post I mentioned that I discovered someone is already working on a PR to add an “activity topic”. It wasn’t precisely what I had in mind but, after contacting the author, convinced him/her to employ a template to allow for greater flexibility (and also address a potential charting error if in auto mode).

The PR is still in the pipe but I just helped myself to the code and incorporated it into my custom_components/climate/mqtt_climate.py.

The only modification I made was to the name of the new topic. The PR’s version uses:

  • state_topic
  • state_template

IMHO, that’s inconsistent with how all other topic/templates are named. All others are in the form:

  • something_state_topic
  • something_state_template

The PR’s version lacks the something part. My version uses:

  • status_state_topic
  • status_state_template

Ideally it should be state instead of status but state_state_topic is damned confusing!

So my version contains the enhancement in the aforementioned PR by @definitio plus the following two lines (near line 46):

CONF_STATE_TOPIC = 'status_state_topic'
CONF_STATE_TEMPLATE = 'status_state_template'

It all ends up looking like this in configuration.yaml:

climate:
  - platform: mqtt_climate
    name: "Thermostat"
    optimistic: false
    retain: false
    qos: 0
    payload_on: 1
    payload_off: 0
    # Acquire HVAC operating status
    status_state_topic: "premise/home/thermostat/heatingstatus"
    status_state_template: >-
      {% set values = { '1':'heat', '2':'cool', '4':'idle'} %}
      {{ values[value] if value in values.keys() else 'idle' }}
    modes:
      - auto
      - heat
      - cool
      - 'off'
    # Acquire HVAC operating mode
    mode_state_topic: "premise/home/thermostat/temperaturemode" 
    mode_state_template: >-
      {% set values = { '0':'auto', '1':'heat',  '2':'cool', '4':'off'} %}
      {{ values[value] if value in values.keys() else 'off' }}
    mode_command_topic: "premise/command/home/thermostat/temperaturemode"
    mode_command_template: >-
      {% set values = { 'auto':'0', 'heat':'1',  'cool':'2', 'off':'4'} %}
      {{ values[value] if value in values.keys() else '4' }}
    --- etc ---

Finally, here’s my version which is running well and producing no errors (in the log): mqtt_climate.py

I’m new to HA development, so I don’t know the best way to get these incorporated into a released version.

I’m a novice as well so I may be omitting a few steps but the general idea is you get a GitHub account, install git on your PC, use it to fork the MQTT HVAC platform to your repository, make all desired enhancements to this local copy (modifications are tracked by git), then submit a pull request to have your version incorporated into Home Assistant’s repo. There’s a vetting process to get your changes into the main repo and this podcast episode does a good job of explaining it.

Actually other mqtt components use state_topic for receiving state (look at homeassistant.components.mqtt).

No argument from me; other MQTT components definitely use state_topic.

It typically refers to some fundamental characteristic of the device (true/false, amplitude, mode, etc). Interestingly MQTT HVAC is unique among MQTT components in that it (currently) has no state_topic!

When your PR is merged, it will finally get state_topic and be in line with other MQTT components.

Personally, I like status_state_topic only because it makes it consistent with the nomenclature used by the many other topics within MQTT HVAC. Having said that, it’s a semantic hill I won’t defend and will gladly cede ground to state_topic! :slight_smile:

Thanks for the response. I have integrated the changes in my current working version, but have a few questions.

My first test is with my heated floors. I am using both mode_state_topic to determine if the floor heat is off or on and I’m using status_state_topic to determine if the element is currently actively heating. The element cycles on and off based on the temperature that’s set.

The status correctly switches between “heating” and “idle” when the element is providing heat, but when I turn the floor heat off (mode_state_topic = “Off”), the status still shows up at “idle” instead of off, like it did without the integration the status capability. Perhaps the components needs to display both the mode and the status. As is, there is no way to know that the unit is turned off.

Perhaps I need to look deeper at climate and not mqtt?

I may be able to write an automation that gets triggered on the change of the mode_state_topic and override the status_topic value to show the unit is actually turn off, but that seems like a kludge. Thoughts?

I also don’t see the history graph showing when the unit is actually running. Was this a separate modification and if so, can you share it? Thanks.

That’s kind of unavoidable since the UI is now showing operating state, not mode. Remember, the frontend UI assumes it is showing the operating mode (even the new Lovelace Thermostat assumes it is rendering the mode, not the state).

Whoever designed the climate component’s architecture chose to focus on the operating mode and not the state. As a consequence, the UI shows mode and nothing about state. This results in the curious history chart that graphs mode (when furnace is enabled) and not state (when furnace is actively heating).

By reversing the two, the UI now shows what the HVAC system is currently doing (as opposed to what mode its in) and the chart shows when the HVAC system is working. However, now this switcheroo prevents the UI from telling you anything about the HVAC’s operating mode (unless you click on it to display additional information).

One way to fix it is to replace the word idle with off in the state_template. That’s a bit of a kluge because off now represents two possible conditions:

  • Off => HVAC is enabled but neither heating or cooling (state = idle).
  • Off => HVAC is disabled (mode = off).

Ideally, the underlying architecture, and the thermostat UI, should be tweaked. The UI should show the mode and the state. The state is what should be rendered by the history chart.

Nothing I’ve said is new. I’m using Premise Home Control and it came to market circa 2000 (and Motorola discontinued it in 2006). It has an extensive schema of common devices (from lights, to fridges, to A/V gear to security systems) and implements something very similar to Home Assistant’s component/platform model (but it’s more sophisticated). Anyway, the upshot is that it has a decent thermostat model with an auto-generated UI widget. The widget (though terribly dated in appearance) uses icons to represent the HVAC system’s state. It shows flames when heating and a snowflake when cooling. Operating mode is displayed by text. In addition, it shows a fan icon when the fan is active (currently the climate component doesn’t support fan status). It also shows the hold mode and lets you control it (currently the climate UI doesn’t allow for any of this).

Home Assistant’s UI is a lot more attractive, especially the Lovelace version, but is less informative and less functional. All the tweaks I’ve done are just to get it to about 80% of what I’ve always had.

This is a screenscrape of Premise Builder showing the hierarchical layout of my home and the Properties of a Thermostat in the Foyer. Think of it as a graphical version of configuration.yaml. There are many similarities and I’ve indicated the equivalent properties.

This is the highly informative, but arguably fugly by 2018 standards, thermostat widget. Be kind, this was incredible web-technology for the early 2000’s.
Premise%20-%20Thermostat%20-%20Sample

I also don’t see the history graph showing when the unit is actually running. Was this a separate modification and if so, can you share it?

It’s all in the link I posted and is achieved by the new state_topic. The trick is that you must use the keywords heat and cool in the state_template. Why? Because heat and cool are hard-coded in the UI’s code and used to create the history chart. If you use something like heating or cooling it won’t be understood and will fail to be rendered in the chart.

I found a workaround for the problem. Currently there are two topics that track the status/mode. One (mode) tracks whether the device is set to off or heat and the other (status) lets me know when the device is actively heating.

Instead of having the climate.mqtt component monitor these MQTT topics, I have an automation that monitors them. The automation is triggered whenever either topic changes. The action checks the value of each topic and generates a new internally used topic that has values of “Off”, “Heat”, or “Heating”. The climate component then monitors this new topic for status.

I still need to review the history chart. I assume that since I’m using “Heat” and “Heating”, the chart isn’t being generated quite right.

My plan would be to develop similar automation for the heat pump units with values of “Off”, “Cool”, “Cooling”, “Heat”, and “Heating”.

do you have a yaml code of the history graph?

I don’t understand your request. Are you looking for the custom component I created? The link to the code is in this thread’s second message. Here it is again: mqtt_climate.py

I’ll follow this thread.
I have 4 indoor Mitsubishi units.
I’m pretty new to Home Assistant but I had a hard time to understand I was missing template for outgoing messages.
I’ll post more once back home.

Bonus 1 : I’ll have to dig a bit more to know how to completely power off a unit.
Bonus 2 : I’m suspecting an issue about swing mode, to be developed further once back home.

Hi!

The pastebin link is no longer working. I really want to try this out.

Which version of Home Assistant are you using?

0.94.3

I’m using the mqtt climate platform right now successfully. I can’t believe it doesn’t track when the system is actively heating/cooling.

OK. I just revised the first post in this thread. It contains a revised description and new installation instructions for use with version 0.93+. There’s also a new pastebin link (expires in 6 months) containing the updated source code. I’m currently using it successfully with version 0.94.2.

Hi all,
For those interested, there is an ongoing discussion about Mitsubishi heatpumps and HA auto config.
Head to :

However I’m still using a variant of the first post here but with an old HA (0.8xx something).

Thanks, got it working! Great work on this.

I can almost get rid of my separate “status message” entities, I’m wondering if there is a way to get my “Status” messages to be displayed / logged in the thermostat entity. I have a few additional messages such as compressor delay, anti-freeze active and system error. My thermostats are built in Node-Red.

Are you aware of any problems in 0.96.+? I had this working in 0.95.4 but in 0.96.3 the entity doesn’t come up anymore.

I haven’t been able to find any error messages related to it other than "Platform not found: climate.my_mqtt" . The log does show the component being loaded, but I can’t find the entity listed.

Edit: I just found your post in the update blog from 4 days ago. I see that you are already on top of this issue. I’ll be checking back here to see if you have been able to sort out a solution.

I can confirm that the latest version of my custom component, designed for use with 0.93+, does not work with 0.96. Underlying changes introduced by ‘Climate 1.0’ have rendered it incompatible.

The enhancements I created can be summarized as follows:

  1. Provide a topic for receiving the HVAC system’s current operating state (activity_state_topic).
  2. Fix its History Chart by distinguishing between the HVAC system’s operating state and operation mode.
  3. Provide command_templates for converting mode, fan_mode, and hold.

‘Climate 1.0’ supports the first two features. However, they are not yet fully implemented in MQTT HVAC 0.96.0 (nor in 0.96.3).

I raised the issue that the History Chart still graphs operation mode , not operating state, plus there’s no topic for receiving the operating state.

  • The graphing error was already known and corrected by balloob in PR 3380 and implemented in 0.96.1.
  • The addition of action_topic and action_template was done by @definitio via PR 25260. I don’t know when it will be implemented. It’s not in 0.96.3. Maybe it will be released in 0.96.4 or possibly 0.97.0.

Whenever a release version containing definitio’s changes becomes available, two out of the three features offered by my custom component will be available in the release version. What won’t be available are the three command_templates. However, this functionality can be gained by using automations.

My plan going forward is to wait until definitio’s changes become available and then test that version. If all is well, I will no longer use nor maintain my custom component and switch to using the stock MQTT HVAC component.

Ideally, it should also support command_templates. However, until that’s implemented (if ever) I will use automations to transform the mode, fan_mode, and hold commands. It’s not as neat as native command_templates, but it’s a lot less work for me than maintaining a custom component.

I’ll post my test results after the new version becomes available.

It’s the command template that I needed most of all, too.

I did give it a whack with the 0.97.0-dev and as of last night’s build, no love.

Fortunately the heater I’m working with is only “on” and “off” and instead of trying to transform “heat” to “on” I am using the power on/off topic (since that gives you custom payload options). The alternative was to rewrite my controller’s firmware to accept “heat” instead of “on”.

I don’t know why a state template was implemented in the stock climate control but not a command template.

Here’s my workaround for the lack of a command_template. This example is for mode_command_topic but it is the same principle for fan_mode_command_topic and hold_command_topic.

Set mode_command_topic to a ‘middleman’ topic like this:

    mode_command_topic: 'temp/climate/hvac_mode'

Create an automation that subscribes to the ‘middleman’ topic, converts the received payload for use with your thermostat, and publishes it to your thermostat’s command topic.

- alias: 'hvac_mode controller'
  trigger:
    platform: mqtt
    topic: temp/climate/hvac_mode
  action:
    service: mqtt.publish
    data_template:
      topic: 'premise/command/thermostat/temperaturemode'
      payload: >
        {% set values = { 'auto':'0', 'heat':'1',  'cool':'2', 'off':'4'} %}
        {{ values[trigger.payload] if trigger.payload in values.keys() else '4' }}

However, I agree with you, it would be preferable if the stock MQTT HVAC included support for the three command_templates. The needed code-changes are trivial (just a bit tedious). However, the submission process is a step beyond my current skills so it’s not likely I’ll be doing it any time soon.