Generic thermostat - Toggling multiple switches and conditions

New here, Trying to get home assistant to control my ac unit which is connected to my RPI via relays and then GPIO. The switches themselves work fine - eg I can manually control it via Switch.Turn_on and all automatons work nicely.

The ac unit has the following switches associated with it:

Fan_High
Fan_Med
Fan_Low
Compressor

And sensors:

Room_1
Room_2
Room_3
Input_air

Conditions:

  • The compressor should never be run without a fan, only be run when Input_Air is above 50f, and needs a 5 second delay before starting and a 5 minute cooldown after stopping to prevent motor burnout.
  • The fan switches should never be triggered simultaneously. Eg when switching from fan high to fan low fan high is switched off first and then fan low is switched on.
  • After reaching target temp the fan should stay on for 5 minutes.
  • The thermostat should take an average of all three room sensor values as its input.
  • I would like to be able to configure minimum cycle time and overcool as well.

Thanks to anyone who looks at this. I am well versed in Java and can dogpaddle my way around most other code, Python just doesn’t make sense to me :stuck_out_tongue:

Hey David and welcome to the community :partying_face:

Respect for wiring this stuff for yourself! Bear in mind that Home Assistant can’t give you the stability a dedicated A/C controller might, but I guess you already know that :slight_smile:
That’s quite a request, let’s see. You probably won’t need any python for this though, just YAML and jinja templates.

Okay, so from looking at your post title I’m guessing you’ve already set up a generic thermostat.
To make sure that the compressor doesn’t just switch on when HA sends a call for cooling without the fan running, I’d set up a Template Switch like this:

  - platform: template
    switches:
      ac_compressor:
        friendly_name: "A/C Compressor Switch"
        value_template: "{{ is_state('switch.gpio_compressor', 'on') }}" 
# switch.gpiocompressor should be the switch you use to switch the relay
        turn_on:
          service: script.compressor_on
        turn_off:
          service: script.compressor_off

This will be the switch that Home-Assistant will use to control the A/C. Of course we now need to add the scripts we linked:

  compressor_on:
    mode: single # Only allow one instance of this script to run
    sequence:
      - condition: state
        entity_id: switch.gpio_compressor
        state: off
# To make sure we don't screw up the state with the delay
      - wait_delay: "{{ is_state('binary_sensor.compressor_cooldown', 'on') }}"
# Wait until the compressor has cooled down (If it already has it will continue immediately)
      - service: switch.turn_on
        data:
          entity_id: fan.ac_fan
      - delay:
          seconds: 5
# 5 second delay you've asked for
      - service: switch.turn_on
        data:
          entity_id: switch.gpio_compressor # Again, your GPIO switch for the compressor

  compressor_off:
    mode: single
    sequence:
      - wait_delay: "{{ is_state('script.compressor_on', 'off') }}"
# To make sure both scripts won't run at the same time
      - service: switch.turn_off
        data:
          entity_id: switch.gpio_compressor
      - delay:
          minutes: 5
      - service: switch.turn_off
        data:
          entity_id: fan.ac_fan
# To control the A/C fan, we set up this script that will be called from the fan integration.
  ac_fan_on:
    sequence:
      - service: switch.turn_on
        data_template: >-
          {% if speed == "low" %}
            switch.gpio1
          {% elif speed == "med" %}
            switch.gpio2
          {% elif speed == "high" %}
            switch.gpio3
          {% endif %}

You will also need to add the template binary sensor, you can also add this one to the UI to see if the compressor is currently in cooldown:

binary_sensor:
  - platform: template
    sensors:
      compressor_cooldown:
        friendly_name: "Compressor in Cooldown"
        value_template: "{% if as_timestamp(now()) - as_timestamp(state_attr('script.compressor_off', 'last_triggered')) > 300 and is_state('script.compressor_off', 'off') %} true {% endif %}"
# We both check the time the script has last executed as well as the current state
# to make sure we won't miss anything in case of a restart

I would also suggesst adding the fan as a Template fan. Have a read through it, I guess you won’t have a need for oscillation / direction.

fan:
  - platform: template
    fans:
      ac_fan:
        friendly_name: "A/C fan"
        value_template: "{% if is_state('switch.gpiofan1', 'on') or is_state('switch.gpiofan2', 'on') or is_state('switch.gpiofan3', 'on') %} true {% endif %}"
        speed_template: "{{ states('input_select.ac_fan_speed') }}"
        turn_on:
          service: script.ac_fan_on
          data_template:
            speed: "{{ states('input_select.ac_fan_speed') }}"
        turn_off:
          service: switch.turn_off
          data:
            entity_id: 'switch.gpio1, switch.gpio2, switch.gpio3'
        set_speed:
          service: script.ac_fan_on
          data_template:
            speed: "{{ speed }}"
        speeds:
          - 'low'
          - 'med'
          - 'high'

You also need the input_select for the fan speed:

input_select:
  ac_fan_speed:
    name: 'A/C Fan Speed'
    options:
      - low
      - med
      - high

As for the minimum cycle duration, have a look at the docs: Specify the parameter in your generic thermostat config.
To get the average of your temperature sensors, use the min/max sensor and set the type to mean:

sensor:
  - platform: min_max
    type: mean
    name: "A/C temp sensor"
    entity_ids:
      - sensor.Room_1
      - sensor.Room_2
      - sensor.Room_3
      - sensor.Input_air

Your generic thermostat could look like this. Please read the documentation for this integration and check every parameter.

climate:
  - platform: generic_thermostat
    name: 'My A/C'
    heater: switch.ac_compressor
    target_sensor: sensor.ac_temp_sensor
    min_temp: 16
    max_temp: 26
    ac_mode: true
    target_temp: 22
    cold_tolerance: 0.3
    hot_tolerance: 0
    min_cycle_duration:
      minutes: 5
    initial_hvac_mode: "cool"
    away_temp: 24

Those are just some ideas, check them out and report any issues with them, since I can’t test this config for myself :slight_smile:

Dude, @fedot you didn’t get the credit you deserve!

Thanks for your code. I’m using your ideas in my current underfloor hydronic heating system for a van conversion.

1 Like

Oh wow, that sounds cool, that’s a dream of mine as well :smiley:
Let me know how it goes!