MizterB / homeassistant-infinitude

Home Assistant custom component for controlling Carrier Infinity Touch thermostats through an Infinitude proxy server.
53 stars 20 forks source link

Alternate Temperature Sensor for Thermostat? #38

Closed willclev closed 6 months ago

willclev commented 2 years ago

Hello, I'm looking to set the thermostat temperature (ie. Current Temperature) from a remote Z-wave temperature sensor which I have added to Home Assistant. My thermostat is not in an ideal location to appropriately obtain an accurate temperature for the heat zone, therefore I'd like to use the remote sensor to set the 'current' temperature for the zone. Is there any way to accomplish this?

brettonw commented 2 years ago

I have this same problem, where my bedroom environment is controlled by a thermostat in the hallway, and the hallway does not reflect the bedroom temperature at all.

I solved this in home assistant (HA), but I'm a bit cautious about sharing the details because there's a lot of complexity in order to get a robust solution and I'd like a better way. That said, if you're a technical type and would like to dive in...

Temperature Sensors

All the temperature sensors I looked are battery powered and conserve battery life by reporting only if there is a 2 degree or more change, or on a long period like 30 minutes. They are also ugly as sin.

At minimum, I needed a 1 degree change resolution, and I needed it to be timely because my infinity HVAC can change the temperature by nearly 10 degrees in a 30 minute time period. My solution was a custom temperature sensor using a raspberry pi zero W. It is plugged in, so I don't care about conserving power, and it reports once per minute. Integration is in python using Adafruit's libraries for the hardware sensors, and I calibrated loosely off another sensor. I made the enclosure out of some nice oak and it sits on my dresser looking for all the world like our decor, instead of like a red eye of sauron. My wife hasn't commented on it at all, though she keep asking about the ugly motion sensors...

It's a custom integration I made for myself, but I'm sure you can figure out how to integrate a temperature sensor in HA. In my configuration.yaml file it looks like this (the important part being that the entity will end up being named sensor.bedroom_rpi_temperature):

sensor:
  - platform: rpi_sensor
    name: "Bedroom RPi"
    host: "rpi-sensor-bedroom.local"
    scan_interval: 60

Custom thermostat integration

In HA, I use a custom thermostat integration called "smart thermostat". I don't use the fancy features of it, but it just gives me a generic thermostat that has both heating and cooling. I link the sensor to my RPi temperature sensor, and I created two input_boolean helpers representing "heating_requested" and "cooling_requested" which the thermostat triggers.

  - platform: smart_thermostat
    name: Bedroom
    heater: input_boolean.bedroom_env_heat
    cooler: input_boolean.bedroom_env_cool
    target_sensor: sensor.bedroom_rpi_temperature
    min_temp: 60
    max_temp: 80
    precision: 0.1

Infinitude

I run the infinitude proxy server in a container with a 512MB limit. For reasons I will sort-of explain later, I set the state on the infinitude integration once per minute. However, infinitude has a memory leak that will crash the host server eventually. This limit forces the server to reboot on a roughly 17-hour cycle. I was previously running this container on the same raspberry pi running HA without this limit, which obviously had disastrous results. The relevant portion of my docker-compose.yaml file is:

version: "3.9"
services:
  inf2:
    container_name: "inf2"
    image: "nebulous/infinitude:latest"
    ports:
      - "3002:3000"
    volumes:
      - /usr/local/containers/inf2:/infinitude/state
    restart: always
    deploy:
      resources:
        limits:
          memory: 512M

The relevant portion of the configuration.yaml for the infinitude integration is:

  - platform: infinitude-2
    host: homesvcs.local
    port: 3002
    zone_names:
      - Upstairs Hall

Heating and Cooling

I treat the infinitude HVAC system as a big heater or chiller. I built an automation in HA that checks the heating_requested and cooling_requested helpers once per minute, and sets the thermostat state accordingly. I needed to check it this frequently because all of this home automation stuff is ridiculously unreliable, and missing a signal to turn off the heat at the right moment meant waking up at 4am with it being 95 degrees in the bedroom. My wife was not amused when this happened.

I built a big state table covering all the possible infinitude conditions encapsulated in a state vector (heat requested, cooling requested, current mode, running). I actually created HA scripts for every state in this table, with the action to perform to move to the next state based on the requests. I thought I was clever because I execute these scripts using the jinja template language (which I absolutely despise) to build the script name from the given state vector. From my automations.yaml file:

- id: '1636933592878'
  alias: Bedroom Temperature
  description: ''
  trigger:
  - platform: time_pattern
    minutes: /1
  condition: []
  action:
  - service: script.99bedroomaction_{{ states ('climate.upstairs_hall')[-1] + state_attr('climate.upstairs_hall',
      'hvac_action')[-1] + states ('input_boolean.bedroom_env_heat')[-1] + states
      ('input_boolean.bedroom_env_cool')[-1] }}
  - service: input_text.set_value
    target:
      entity_id: input_text.last_bedroom_state
    data:
      value: '{{ states (''climate.upstairs_hall'')[-1] + state_attr(''climate.upstairs_hall'',
        ''hvac_action'')[-1] + states (''input_boolean.bedroom_env_heat'')[-1] + states
        (''input_boolean.bedroom_env_cool'')[-1] }}'
  mode: single

The state vector I built this way is essentially the last character of each of the states (HVAC mode [heat/cool/off], HVAC status [running/idle], heat requested [on/off], cool requested [on/off]). This substitution creates a script name that is called by the automation action, something like 99bedroomaction_lenf or 99bedroomaction_tgff.

The individual scripts, from my scripts.yaml file:

99bedroomaction_tgnf:
  alias: BedroomAction_tgnf
  sequence:
  - service: climate.set_temperature
    target:
      entity_id: climate.upstairs_hall
    data:
      temperature: '{{state_attr (''climate.upstairs_hall'', ''current_temperature'')
        + 2}}'
  mode: single
99bedroomaction_teff:
  alias: BedroomAction_teff
  sequence:
  - service: climate.set_temperature
    target:
      entity_id: climate.upstairs_hall
    data:
      temperature: '{{state_attr (''climate.upstairs_hall'', ''current_temperature'')
        - 2}}'
  mode: single
99bedroomaction_lgfn:
  alias: BedroomAction_lgfn
  sequence:
  - service: climate.set_temperature
    target:
      entity_id: climate.upstairs_hall
    data:
      temperature: '{{state_attr (''climate.upstairs_hall'', ''current_temperature'')
        - 2}}'
  mode: single
99bedroomaction_leff:
  alias: BedroomAction_leff
  sequence:
  - service: climate.set_temperature
    target:
      entity_id: climate.upstairs_hall
    data:
      temperature: '{{state_attr (''climate.upstairs_hall'', ''current_temperature'')
        + 2}}'
  mode: single
99bedroomaction_ffff:
  alias: BedroomAction_ffff
  sequence:
  - delay:
      hours: 0
      minutes: 0
      seconds: 1
      milliseconds: 0
  mode: single
99bedroomaction_tgff:
  alias: BedroomAction_tgff
  sequence:
  - service: climate.set_temperature
    target:
      entity_id: climate.upstairs_hall
    data:
      temperature: '{{state_attr (''climate.upstairs_hall'', ''current_temperature'')
        - 2}}'
  mode: single
99bedroomaction_tgfn:
  alias: BedroomAction_tgfn
  sequence:
  - service: climate.set_temperature
    target:
      entity_id: climate.upstairs_hall
    data:
      temperature: '{{state_attr (''climate.upstairs_hall'', ''current_temperature'')
        - 2}}'
  mode: single
99bedroomaction_tenf:
  alias: BedroomAction_tenf
  sequence:
  - service: climate.set_temperature
    target:
      entity_id: climate.upstairs_hall
    data:
      temperature: '{{state_attr (''climate.upstairs_hall'', ''current_temperature'')
        + 2}}'
  mode: single
99bedroomaction_lgnf:
  alias: BedroomAction_lgnf
  sequence:
  - service: climate.set_temperature
    target:
      entity_id: climate.upstairs_hall
    data:
      temperature: '{{state_attr (''climate.upstairs_hall'', ''current_temperature'')
        + 2}}'
  mode: single
99bedroomaction_lgff:
  alias: BedroomAction_lgff
  sequence:
  - service: climate.set_temperature
    target:
      entity_id: climate.upstairs_hall
    data:
      temperature: '{{state_attr (''climate.upstairs_hall'', ''current_temperature'')
        + 2}}'
  mode: single
99bedroomaction_lefn:
  alias: BedroomAction_lefn
  sequence:
  - service: climate.set_temperature
    target:
      entity_id: climate.upstairs_hall
    data:
      temperature: '{{state_attr (''climate.upstairs_hall'', ''current_temperature'')
        - 2}}'
  mode: single
99bedroomaction_ffnf:
  alias: BedroomAction_ffnf
  sequence:
  - service: climate.set_hvac_mode
    data:
      hvac_mode: heat
    target:
      entity_id: climate.upstairs_hall
  mode: single
99bedroomaction_fffn:
  alias: BedroomAction_fffn
  sequence:
  - service: climate.set_hvac_mode
    data:
      hvac_mode: cool
    target:
      entity_id: climate.upstairs_hall
  mode: single
99bedroomaction_tefn:
  alias: BedroomAction_tefn
  sequence:
  - service: climate.set_temperature
    data:
      temperature: 55
    target:
      entity_id: climate.upstairs_hall
  - delay:
      hours: 0
      minutes: 0
      seconds: 3
      milliseconds: 0
  - service: climate.set_hvac_mode
    target:
      entity_id: climate.upstairs_hall
    data:
      hvac_mode: cool
  mode: single
99bedroomaction_lenf:
  alias: BedroomAction_lenf
  sequence:
  - service: climate.set_temperature
    data:
      temperature: 85
    target:
      entity_id: climate.upstairs_hall
  - delay:
      hours: 0
      minutes: 0
      seconds: 3
      milliseconds: 0
  - service: climate.set_hvac_mode
    target:
      entity_id: climate.upstairs_hall
    data:
      hvac_mode: heat
  mode: single

The result of all this has been pretty reliable, and the bedroom temperature hovers within a 1 degree window of the target. It will switch between heating and cooling automatically if you want to use the heat/cool option in the thermostat, but I find that's not really the behavior we want.

(I hope to transition this to a pyscript module when I can find some time, or even better to fork MizterB's code here and crate a custom integration that does all this.)

MizterB commented 6 months ago

This is best addressed in a Home Assistant automation, not via this integration