zacs / ha-dualmodegeneric

Generic thermostat capable of heating and cooling
68 stars 26 forks source link

Help with combined compressor + fan mode #27

Closed mjsambol closed 3 years ago

mjsambol commented 3 years ago

Hi, thanks for your work on this component, it's much appreciated!

I have a central A/C system and am trying to reproduce two separate cooling modes which are offered by some thermostats: one in which the fan runs full-time, with the compressor turning on and off periodically, and the other in which the fan only runs when the compressor is on.

I have a series of relay switches connected to the fan, compressor, and heat pump.

I wanted to use "cool" for the constant fan + occasional compressor mode, and "dry" for the synchronized fan+compressor. I got dry running by using a template switch which turns the fan and compressor on together. For "cool", I made an automation that simply monitors the state of the climate component and turns on the fan when it enters "cool" state.

"Dry" works fine, but in "cool" mode, after the first time the compressor turns off, it never turns on again.

My configuration:

climate:
  - platform: dualmode_generic
    name: Upstairs Thermostat
    heater: switch.upstairs_thermostat_heat_with_fan
    cooler: switch.upstairs_thermostat_compressor
    fan: switch.upstairs_thermostat_fan
    fan_behavior: neutral
    dryer: switch.upstairs_thermostat_cool_with_fan
    dryer_behavior: cooler
    target_sensor: sensor.master_bedoom_temp
    enable_heat_cool: False
    min_temp: 16
    max_temp: 30
    cold_tolerance: 0.5
    hot_tolerance: 0.5
    min_cycle_duration:
        minutes: 8

switch.upstairs_thermostat_fan and switch.upstairs_thermostat_compressor are relays which close the physical circuits powering the system. These work fine.

switch:
  - platform: template
    switches:
      upstairs_thermostat_cool_with_fan:
        value_template: "{{ states.variable.upstairs_thermostat_cool_with_fan.state }}"
        turn_on:
          - service: homeassistant.turn_on
            target:
              entity_id: switch.upstairs_thermostat_fan
          - service: homeassistant.turn_on
            target:
              entity_id: switch.upstairs_thermostat_compressor
          - service: variable.set_variable
            data_template:
              variable: upstairs_thermostat_cool_with_fan
              value: true
        turn_off:
          - service: homeassistant.turn_off
            target:
              entity_id: switch.upstairs_thermostat_compressor
          - service: homeassistant.turn_off
            target:
              entity_id: switch.upstairs_thermostat_fan
          - service: variable.set_variable
            data_template:
              variable: upstairs_thermostat_cool_with_fan
              value: false

Can you help me understand why the compressor is misbehaving in "cool" mode?

Looking in the log file, when I am using the "dryer" mode (which works fine), I see the expected log lines Turning on dehumidifier switch.upstairs_thermostat_cool_with_fan and similar for turning off. But when in "cool" mode there are no log lines.

mjsambol commented 3 years ago

I'm not certain, but this section of code caught my eye:

    async def async_set_hvac_mode(self, hvac_mode):
        """Set hvac mode."""
        if hvac_mode == HVAC_MODE_HEAT:
            self._hvac_mode = HVAC_MODE_HEAT
            if self._is_device_active:
                if REVERSE_CYCLE_IS_COOLER not in self.reverse_cycle:
                    await self._async_cooler_turn_off()
                if REVERSE_CYCLE_IS_FAN not in self.reverse_cycle:
                    await self._async_fan_turn_off()
                if REVERSE_CYCLE_IS_DRYER not in self.reverse_cycle:
                    await self._async_dryer_turn_off()
            await self._async_control_heating(force=True)
        elif hvac_mode == HVAC_MODE_COOL:
            self._hvac_mode = HVAC_MODE_COOL
            if self._is_device_active:
                if REVERSE_CYCLE_IS_HEATER not in self.reverse_cycle:
                    await self._async_heater_turn_off()
                if REVERSE_CYCLE_IS_FAN not in self.reverse_cycle:
                    await self._async_fan_turn_off()

do those last few lines mean that what I'm trying to do - have the fan running during 'cool' mode - is explicitly not supported?

girlpunk commented 3 years ago

Try adding reverse_cycle: fan to your config, you might also need cooler in there too

Edit: Swapped the two around, try fan first

mjsambol commented 3 years ago

Thank you for the suggestion. I tried last night adding

reverse_cycle: cooler, heater, dryer, fan

it doesn't look to me from the code like the order matters or there is a down-side to including too many. As far as I can tell this is just a mechanism to prevent the code from shutting one mode before switching to another.

This change didn't help, I still had the same problem: compressor never turned back on.

I'm happy to try just a subset of this config if you think it can make a difference. I'm also adding a bunch of debug statements to the integration to get a better idea of where things are going wrong.

mjsambol commented 3 years ago

I think I've figured this out. In _async_control_heating there is a block of code:

                    if self._is_device_active:
                        current_state = STATE_ON
                    else:
                        current_state = HVAC_MODE_OFF
                    long_enough = condition.state(
                        self.hass,
                        active_entity,
                        current_state,
                        self.min_cycle_duration,
                    )
                    if not long_enough:
                        return

self._is_device_active is evaluating as True because the fan is on. condition.state is being asked: has the compressor been on for min_cycle_duration? And the answer is no, because it's not really on at all. And this will never change as long as the fan stays on.

I'm not sure that this logic is correct, I think it would be better for the check to be is this specific entity active. Rather than change the integration, I will try to work around it by changing the fan_entity_id to be a new template switch which doesn't reflect the actual state of the underlying fan, but rather the state of the climate component.

mjsambol commented 3 years ago

The work around was successful. This approach works.

For the sake of future users, it may be worth documenting this, or considering changes to the section of code above. (There's also a typo in the README: reverse_cylce)

david-kalbermatten commented 3 years ago

Thanks for your insight. The fan and dryer modes are the same as cooler and heater and only toggle a switch or input_boolean. You can define the behaviour of the two modes by telling what they should act as (heater, cooler, neutral). There is no further logic behind it. If you think this integration is lacking a generalized feature, please open a feature request with a clear and concise description of your proposal.