Skip to content

Commit

Permalink
Disable climate based on open/close sensors
Browse files Browse the repository at this point in the history
  • Loading branch information
kprestel committed Feb 21, 2022
1 parent 26400c8 commit 51e4876
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 14 deletions.
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@

_AppDaemon app for [HACS](https://github.com/custom-components/hacs)._

## What is this?
## What is this?

This is an appdaemon app that controls your theromstat via Homeassisant. This appp has the ability to target specific areas of your house and prioritize them depending on the time of day.

## Installation

Download the `hacs` directory from inside the `apps` directory here to your local `apps` directory, then add the configuration to enable the `hacs` module.

## Features

* Switch between A/C and Heat based on the current indoor temperature vs the current outdoor temperature.
* Prioritize different areas of your house based on time of day

* Prioritize different areas of your house based on time of day

* Allow for adjustments to "actual" temperature to achieve desired temperature

## App configuration

The configuration is broken into 4 parts.
The configuration is broken into 4 parts.

1. AD Configuration
1. Single required application parameters
Expand All @@ -25,16 +29,15 @@ The configuration is broken into 4 parts.

Any "key" in the `inside_temperature_sensors` configuration must map to a target area in `preferences`.


```yaml
climate:
module: climatge
class: Climate
thermostat: climate.kitchen
weather_sensor: sensor.dark_sky_temperature
mode_switching_enabled: true
max_temperature: 80
min_temperature: 60
mode_switching_enabled: input_boolean.enable_climate_mode_switching
max_temperature: input_number.max_temperature
min_temperature: input_number.min_temperature
inside_temperature_sensors:
basement:
sensors:
Expand All @@ -48,6 +51,10 @@ climate:
sensors:
- sensor.masterbed_room_temperature
- sensor.kids_room_temperature
open_close_sensors:
- binary_sensor.front_door
- binary_sensor.living_room_window
climate_off_timeout: "00:30:00"
preferences:
morning:
time: input_datetime.morning
Expand Down Expand Up @@ -78,4 +85,3 @@ climate:
| `weather_sensor` | False | string | | A sensor that provides the current outdoor temperature. |
| `inside_temperature_sensors` | False | string | | Sensors that provide temperature data about different areas. |
| `preferences` | False | string | | Target area configuration |

53 changes: 47 additions & 6 deletions apps/climate/climate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import datetime
from dataclasses import dataclass
from typing import Dict, List, Tuple
from typing import Dict

import appdaemon.plugins.hass.hassapi as hass

Expand Down Expand Up @@ -28,7 +28,6 @@ def initialize(self):
except KeyError:
self.log("missing required argument: thermostat")
raise
self.mode_switching_enabled = self.args.get("mode_switching_enabled", False)

try:
self.prefs = Preferences.from_args(self.args["preferences"])
Expand All @@ -46,25 +45,67 @@ def initialize(self):
raise

self.run_minutely(self.temperature_check, datetime.time(0, 0, 0))
self.open_close_sensors = self.args.get("open_close_sensors", {})
self.log(f"open_close_sensors: {self.open_close_sensors}")
for sensor in self.open_close_sensors:
self.listen_state(callback=self.open_close_callback, entity_id=sensor)
self.climate_off_timeout = self.parse_time(self.args.get("climate_off_timeout", "00:30:00"))

@property
def outside_temperature(self) -> float:
return float(self.get_state(self._outside_temperature_sensor))

@property
def max_temperature(self) -> int:
return int(self.args.get("max_temperature", 80))
try:
return int(self.get_state(self.args.get("max_temperature")))
except Exception as e:
self.log("Error getting max temp, using default of 80", e)
return 80

@property
def min_temperature(self) -> int:
return int(self.args.get("min_temperature", 60))
try:
return int(self.get_state(self.args.get("min_temperature")))
except Exception:
self.log("Error getting min temp. Using default of 55")
return 55

@property
def thermostat_temperature(self) -> int:
return int(self.get_state(
self.thermostat, attribute="current_temperature"
self.thermostat, attribute="current_temperature"
))

@property
def mode_switching_enabled(self) -> bool:
try:
return bool(self.get_state(self.args.get("mode_switching_enabled")))
except Exception as e:
self.log("Error getting mode switching option, defaulting to false.", e)
return False

def open_close_callback(self, entity, attribute, old, new, kwargs):
self.log(f"Running open_close_callback, new: {new}, old: {old}, entity: {entity}")
if old == new:
return

if new == "open":
self.turn_off_climate()
elif new == "closed":
self.turn_on_climate()
else:
self.log(f"Unknown state: {new}")

def turn_off_climate(self, kwargs=None):
self.log("Turning climate off")
self.call_service("climate/turn_off")
self.run_in(self.turn_on_climate, self.open_close_callback)

def turn_on_climate(self, kwargs=None):
self.log("Turning climate on")
self.call_service("climate/turn_on")

def temperature_check(self, kwargs):
self.log("Checking temperature")
pref = self.nearest(self.time_pref.keys(), self.get_now())
Expand Down Expand Up @@ -174,4 +215,4 @@ def create_pref_time_dict(self) -> Dict[datetime.time, Preferences]:
except TypeError:
self.log(f"Error parsing: {state}")

return ret
return ret

0 comments on commit 51e4876

Please sign in to comment.