Climate: Dual Mode Generic Thermostat

Nice workaround! In addition to setting the mode, you may want to also set the target. If you switch to cool mode but the actual temp is below the target temp, nothing will turn on.

good shout

- id: '1582115889677'
  alias: MJ Thermostat Cool
  description: ''
  trigger:
  - above: '25'
    entity_id: sensor.mj_ave_temp
    platform: numeric_state
  condition: []
  action:
  - data:
      entity_id: climate.mj_thermostat
      hvac_mode: cool
      temperature: 25
    service: climate.set_hvac_mode
- id: '1582116016514'
  alias: MJ Thermostat Heat
  description: ''
  trigger:
  - below: '16'
    entity_id: sensor.mj_ave_temp
    platform: numeric_state
  condition: []
  action:
  - data:
      entity_id: climate.mj_thermostat
      hvac_mode: heat
      temperature: 15
    service: climate.set_hvac_mode

This component is very handy, but without the Auto mode its like missing the key feature :slight_smile:

Hi @zacs Do you mind sharing your entire config for this to work including how you set up the switches?

I have a split AC/Heater and the indoor unit sits in a small hallway, meaning the internal thermometer gets to hot while heating or to cold while cooling so I cant use that for reliable temperatures around the house. So I would need to use another thermometer sitting in another room to control the Daikin unit.

Thanks and best regards

Sure, mine is pretty straightforward:

climate:
  - platform: dualmode_generic
    name: Nursery
    heater: switch.nursery_heater
    cooler: switch.nursery_fan
    target_sensor: sensor.nursery_temperature

In this case the sensor.nursery_temperature is a z-wave sensor sitting in a corner of our nursery. Each of the switches is actually a switch template that calls some Broadlink RF codes to turn my Dyson device onto heat or cool. I can paste more of the templating if that would be helpful as well.

Thanks for sharing and thanks for the dualmode_generic component.
My “heater” and “cooler” is the same unit and it´s not just on/off to have it working nicely.
It sits in a small entry where the temperature gets to hot and to cold so the internal sensor stops it from heating or cooling when the small entry reaches the set target temperature.
I figured if I raise the target temperature with approx. 6°C on a cloudy day (lets say from 22 to 28) I get a nice 22°C around the rest of the house.
This works until the sun decides to show up and in this case the house gets way to hot so I needed a way to use an external sensor with some logic to control the set temperature.
This package is what I ended up doing and it´s still far from perfect since it does not cover all events that can happen but It works for now.
The climate.daikin is my “fake” heater exposed to google and climate.daikinxrh30 is the real heater.
I share for now if anybody else is interested and I will update if I make some changes in the future.

I know there are probably some amateur errors and this can for sure be done in a much cleaner way but here it comes:

input_boolean:
  daikin_varmepump_varme:
    name: Daikin heat boolean for automations
  daikin_varmepump_kyla:
    name: Daikin cool boolean for automations
input_number:
  daikin_temperature_offset:
    name: Daikin temperature offset while heating or cooling
    min: 1
    max: 10
    step: 1

switch:
  - platform: template
    switches:
      daikin_varmepump_varme:
        value_template: "{{ is_state('input_boolean.daikin_varmepump_varme', 'on') }}"
        turn_on:
          service: input_boolean.turn_on
          data:
            entity_id: input_boolean.daikin_varmepump_varme
        turn_off:
          service: input_boolean.turn_off
          data:
            entity_id: input_boolean.daikin_varmepump_varme
  - platform: template
    switches:
      daikin_varmepump_kyla:
        value_template: "{{ is_state('input_boolean.daikin_varmepump_kyla', 'on') }}"
        turn_on:
          service: input_boolean.turn_on
          data:
            entity_id: input_boolean.daikin_varmepump_kyla
        turn_off:
          service: input_boolean.turn_off
          data:
            entity_id: input_boolean.daikin_varmepump_kyla
climate:
  - platform: dualmode_generic
    heater: switch.daikin_varmepump_varme
    cooler: switch.daikin_varmepump_kyla
    reverse_cycle: false
    name: Daikin
    target_sensor: sensor.hall_temp_degc
    min_temp: 18
    max_temp: 31
    target_temp: 22
    cold_tolerance: 0.3
    hot_tolerance: 0.3
    min_cycle_duration:
      minutes: 5
    precision: 0.1

automation:
  - alias: Turn off daikin
    description: ''
    trigger:
      platform: state
      entity_id: climate.daikin
      to: 'off'
    action:
      - service: climate.turn_off
        data:
          entity_id: climate.daikinxrh30
  - alias: Change daikin to heat
    description: ''
    trigger:
      platform: state
      entity_id: climate.daikin
      to: 'heat'
    action:
     - service: climate.set_hvac_mode
       data:
         entity_id: climate.daikinxrh30
         hvac_mode: heat
  - alias: Change daikin to cool
    description: ''
    trigger:
      platform: state
      entity_id: climate.daikin
      to: 'cool'
    action:
     - service: climate.set_hvac_mode
       data:
         entity_id: climate.daikinxrh30
         hvac_mode: cool
  - alias: Turn on daikin heat
    description: ''
    trigger:
      platform: state
      entity_id: input_boolean.daikin_varmepump_varme
      to: 'on'
      for:
        seconds: 2
    action:
    - data_template:
        temperature: "{{ state_attr('climate.daikin', 'temperature') + states('input_number.daikin_temperature_offset') | float }}"
      entity_id: climate.daikinxrh30
      service: climate.set_temperature
    - service: climate.set_hvac_mode
      data:
        entity_id: climate.daikinxrh30
        hvac_mode: heat
  - alias: Turn off daikin heat
    description: ''
    trigger:
      platform: state
      entity_id: input_boolean.daikin_varmepump_varme
      to: 'off'
    condition:
    - condition: state
      entity_id: climate.daikin
      state: heat
    action:
    - data_template:
        temperature: "{{ state_attr('climate.daikin', 'temperature') | float }}"
      entity_id: climate.daikinxrh30
      service: climate.set_temperature
  - alias: Turn on daikin cool
    description: ''
    trigger:
      platform: state
      entity_id: input_boolean.daikin_varmepump_kyla
      to: 'on'
      for:
        seconds: 2
    action:
    - data_template:
        temperature: "{{ state_attr('climate.daikin', 'temperature') - states('input_number.daikin_temperature_offset') | float }}"
      entity_id: climate.daikinxrh30
      service: climate.set_temperature
    - service: climate.set_hvac_mode
      data:
        entity_id: climate.daikinxrh30
        hvac_mode: cool
  - alias: Turn off daikin cool
    description: ''
    trigger:
      platform: state
      entity_id: input_boolean.daikin_varmepump_kyla
      to: 'off'
    condition:
    - condition: state
      entity_id: climate.daikin
      state: cool
    action:
    - data_template:
        temperature: "{{ state_attr('climate.daikin', 'temperature') | float }}"
      entity_id: climate.daikinxrh30
      service: climate.set_temperature

Nice, changing set point based on the sun is a fun optimization!

Hello @zacs, thanks for the good work, I really like this auto option, it should be part of the generic thermostat I think…
I looked at your code to check if the Away Mode was an option, and I found that:
Removed PRESET_AWAY as I don't need it, may reimplement it later
Still a chance to get this option back one day? That’s the only option I’m missing.
Thanks!

Sorry for not seeing this earlier, but away_temp is definitely supported in the component. If you want to try it out, let me know if you run into issues!

To use it just add away_temp as one of the config variables when you ad the component.

Hello @zacs,

Awesome work, thanks. I already set up to control my server room temperature via a Broadlink RM4 mini and a portable AC/Heater.

This thing has a remote control with temperature settings, and I grabbed all the IR codes for all temperature levels and all fan speeds for heating and cooling.

Would it be somehow possible to map the different temperature codes within the thermostat, and getting more fine grained temperature control? I mapped some temperature values to switches like this:

switch:
  - platform: broadlink
    mac: '24:DF:A7:50:07:20'
    switches:
      - name: Fisher Cooling 20C High
        command_on: JgBwAA9sDxAPEA8QDxAPEA8QDy8PLw8QDxAPEA8QDxAPDw8QDxEPEA8QDxAPEA4QDxAQDw8SDxAPEA4QEA8PEA8QDy8PEA8QEA8PEA8QDxAPEA8QDxEPLw8QDxAOEA8RDi8PEA8yDy4PLw8PDy8PbA8ADQU=
        command_off: JgBwAA9zEBEQERAQEBEQERAREBAQEg8REBEQERAQEBEQERAREBEQEBAREBEQERAQEBEQERASEBEQEBAREBEQEQ8REDIPEhAREBAQERAREBEQEQ8yDxIQERAREDEQEQ8REDIQMRAUDxEQEQ8yDzIPcxAADQU=
      - name: Fisher Cooling 24C High
        command_on: JgBwABBzDxEQERAREBEPERARETAQMhAREBAQERAREBEQEBAREBEQERARDxEQERAREBEPERASEBEQERAREBAQERAREDEQERAREBEQERAQEBEQERAREBEQMRAREBEQERAxEBEPERA0EDIPERAREDEQchAADQU=
        command_off: JgBwAA9zEBEQERAQEBEQERAREBAQEg8REBEQERAQEBEQERAREBEQEBAREBEQERAQEBEQERASEBEQEBAREBEQEQ8REDIPEhAREBAQERAREBEQEQ8yDxIQERAREDEQEQ8REDIQMRAUDxEQEQ8yDzIPcxAADQU= 
      - name: Fisher Heating 25C High
        command_on: JgBwABByEBEQERAREBEPERAREDIQMRAREBEQERAQEBEQERARDxIQEBAREBEQERAQEBEQERASEBEQEBAREBEQEQ8REDIQERAREBAQERAREBEQEBAREBIQERAQEDIQMRAxEBEQMRAUEDEQMRAQEDEQcxAADQU=
        command_off: JgBwAA9zEBEQERAQEBEQERAREBAQEg8REBEQERAQEBEQERAREBEQEBAREBEQERAQEBEQERASEBEQEBAREBEQEQ8REDIPEhAREBAQERAREBEQEQ8yDxIQERAREDEQEQ8REDIQMRAUDxEQEQ8yDzIPcxAADQU=
      - name: Fisher Heating 22C High

But obviously I am able to map only one switch to the “cool” and “heat” functions so if the temperature set on the unit is too high, under certain circumstances the result will not be the expected. Am I missing something, or is that not possible?

Thanks,
Daniel

The notion of multiple heaters/coolers is not supported. However, the logic of the entity should lend itself to just using the most powerful switch. It’s going to run until it hits the setpoint either way, the only difference in using the 20C vs 24C is probably efficiency, I would think. If you’re never making the setpoint lower than 24C though, you can of course use that switch.

To give you an example, when I used this with a Dyson heater and a Broadlink, I sent IR codes that made the heater go to 80 or 90 degrees when the heater “turned on,” because I honestly didn’t care. I knew that the component would turn the heater off as soon as it got the set point (which was obviously below 80 degrees).

Thanks, now I found something else. If I change the configuration of the thermostat and hit reload on Dualmode_generic (under YAML configuration reload) it breaks, and comes back only after a HA restart. I’m trying to find out why the AC is not switched off when the target temperature is below the threshold value (with more than 0.5 C). If I set the thermostat to Off, the AC shuts down, but seems to stay on forever with just being in AC mode.

2021-07-29 10:26:42 INFO (MainThread) [homeassistant.components.climate] Setting up climate.dualmode_generic
2021-07-29 10:26:42 ERROR (MainThread) [homeassistant.components.climate] Error adding entities for domain climate with platform dualmode_generic
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 383, in async_add_entities
    await asyncio.gather(*tasks)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 588, in _async_add_entity
    await entity.add_to_platform_finish()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 665, in add_to_platform_finish
    await self.async_added_to_hass()
  File "/config/custom_components/dualmode_generic/climate.py", line 390, in async_added_to_hass
    _async_startup()
TypeError: _async_startup() missing 1 required positional argument: 'event'
2021-07-29 10:26:42 ERROR (MainThread) [homeassistant.components.climate] Error while setting up dualmode_generic platform for climate
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 258, in _async_setup_platform
    await asyncio.gather(*pending)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 383, in async_add_entities
    await asyncio.gather(*tasks)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 588, in _async_add_entity
    await entity.add_to_platform_finish()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 665, in add_to_platform_finish
    await self.async_added_to_hass()
  File "/config/custom_components/dualmode_generic/climate.py", line 390, in async_added_to_hass
    _async_startup()
TypeError: _async_startup() missing 1 required positional argument: 'event'`

Should the thermostat survive a YAML reload, or is this expected?

thanks again
Daniel

I have similar problem. Auto works well, except minimum on and off. But if I switch to heat or cool. It will never shut off as well.

Hi all,

I also had an issue on startup. Can someone help me?

Error doing job: Exception in callback DualModeGenericThermostat.async_added_to_hass.<locals>._async_startup(<Event homeassistant_start[L]>) at /config/custom_components/dualmode_generic/climate.py:382
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/asyncio/events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/src/homeassistant/homeassistant/core.py", line 835, in _onetime_listener
    self._hass.async_run_job(listener, event)
  File "/usr/src/homeassistant/homeassistant/core.py", line 452, in async_run_job
    return self.async_run_hass_job(HassJob(target), *args)
  File "/usr/src/homeassistant/homeassistant/core.py", line 433, in async_run_hass_job
    hassjob.target(*args)
TypeError: _async_startup() takes 0 positional arguments but 1 was given

Looks like a related (but opposite) error to the one reported above. What version of HA are you running? I’m guessing the old code needs to be updated so that _async_startup behaves in a more modern way, but I haven’t looked at the docs. I have a test HA instance I can use to debug sometime in the next week or so.

Hi Zacs,

Thats my setup:

core-2021.11.5
supervisor-2021.10.8
dual_generic: last files on github

#THERMOSTAAT DTH1-LIVING INSTELLEN
  - platform: dualmode_generic
    name: DTH1_LIVING
    unique_id: climate.DTH1
    heater: input_boolean.contact_dth1_heat
    cooler: input_boolean.contact_dth1_cool
#    fan: switch.fan
#    fan_behavior: neutral
#    dryer: switch.dryer
#    dryer_behavior: cooler
    target_sensor: sensor.shelly_h_t_956332_temperature
#    reverse_cycle: cooler, heater
#    enable_heat_cool: false
    min_temp: 16
    max_temp: 30
    cold_tolerance: 0.1
    hot_tolerance: 0.2
    min_cycle_duration:
        minutes: 15
#    initial_hvac_mode: "off"
#    away_temp: 16
#    precision: 0.1

@zacs I’ve been using your component for a little while, and I’m very happy with it. Thank you.

I’m having a problem I wonder if you can advise me on. For context, I’m dealing with a separate integration that crashes a lot, so I have to reboot Home Assistant on a fairly regular basis. Hopefully this will settle down soon, but…

When HASS reboots and loads the dualmode generic thermostat, I notice that it does not set the heater and cooler switches based on the current temperature state. I use input binary helpers as my on-off switches, which remember their state across reboots.

So for instance, if the heat was on when HASS crashed, but a few minutes pass before the reboot with the heat running, then the temperature might be above the heat set point at reboot. The heat switch doesn’t get set to off during restart and the heat keeps running, getting warmer and warmer. I wake up at 3 am with my bedroom at 90 degrees F.

I’ve considered some sort of automation to try to bump the thermostat up and down after restart to make sure it sets the heater switch to off, but I wonder if there is an initialize step in the thermostat that could set the switch to the correct state based on the current temperature.

Yah you definitely shouldn’t have to write an automation to deal with that. Does the switch ever correct itself (like a minute or five after reboot)?

I am considering taking a fresh fork of generic_thermostat and re-applying all the patches here. I originally forked it over two years ago, so I expect your issue may also be related to the async_startup item mentioned above.

I will of course post here if I am able to make the time to update it. Time is hard to come by these days :slight_smile:.

@zacs I made similar project with better functionality: https://community.home-assistant.io/t/climate-smart-thermostat-with-auto-heat-cool-mode-pid-control-and-pwm

Take a look on it. May be don’t need to spend time on dualmode_generic:wink:

2 Likes

Hello zacs and thank you for your great work !

Since the hot season i’m struggling with one parameter.

In the winter the away_temp is set to 18°C and the target temp to 22 In the summer the target temp is still ok with 22, but an higher away temp is expected, as in this configuration :
Before leaving the house the AC is off with a 21°C temp, and then leaving the AC is on as the away temp is 18°C !

Is there any misconfiguration ?