Skip to content

Commit

Permalink
[TASK] basic changes and new developer flow
Browse files Browse the repository at this point in the history
  • Loading branch information
KartoffelToby committed Oct 31, 2022
1 parent ff11a3c commit 3cdbbf9
Show file tree
Hide file tree
Showing 16 changed files with 178 additions and 50 deletions.
35 changes: 35 additions & 0 deletions .devcontainer/configuration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
default_config:

logger:
default: error
logs:
custom_components.better_thermostat: debug

climate:
- platform: generic_thermostat
name: Study
heater: input_boolean.heater
target_sensor: input_number.indoor_temperature

input_number:
external_sensor:
name: External Sensor
initial: 18
min: 5
max: 35
step: 1

template:
- sensor:
- name: "External Temperature Sensor"
unique_id: external_temperature_sensor
state_class: measurement
device_class: temperature
unit_of_measurement: "°C"
state: '{{ states.input_number.external_sensor.state | round(1, default=18) }}'


# If you need to debug uncomment the line below (doc: https://www.home-assistant.io/integrations/debugpy/)
#debugpy:


30 changes: 30 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// See https://aka.ms/vscode-remote/devcontainer.json for format details.
{
"image": "ghcr.io/ludeeus/devcontainer/integration:latest",
"name": "BETTER THERMOSTAT development",
"context": "..",
"appPort": [
"9123:8123"
],
"postCreateCommand": "container install",
"extensions": [
"ms-python.python",
"GitHub.copilot",
"ryanluker.vscode-coverage-gutters",
"ms-python.vscode-pylance"
],
"settings": {
"files.eol": "\n",
"editor.tabSize": 4,
"editor.insertSpaces": true,
"python.pythonPath": "/usr/bin/python3",
"python.analysis.autoSearchPaths": false,
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.formatting.provider": "black",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true
}
}
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
.jekyll-cache/
_site/
_site/
__pycache__
pythonenv*
venv
.venv
.coverage
.idea
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"python.linting.enabled": true,
"python.linting.flake8Enabled": true
"python.linting.flake8Enabled": true,
"python.testing.pytestArgs": [
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}
29 changes: 29 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Run Home Assistant on port 9123",
"type": "shell",
"command": "container start",
"problemMatcher": []
},
{
"label": "Run Home Assistant configuration against /config",
"type": "shell",
"command": "container check",
"problemMatcher": []
},
{
"label": "Upgrade Home Assistant to latest dev",
"type": "shell",
"command": "container install",
"problemMatcher": []
},
{
"label": "Install a specific version of Home Assistant",
"type": "shell",
"command": "container set-version",
"problemMatcher": []
}
]
}
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

### Requirements

- Minimum required Home Assistant version: `2022.8.0`
(_Latest tested version: `2022.9.4`_)
- Minimum required Home Assistant version: `2022.8.0`
(_Latest tested version: `2022.10.5`_)

### Companion UI

Expand All @@ -32,7 +32,7 @@ This integration brings some smartness to your connected radiator thermostats se
- Your weather forcast provider will turn your heat on/off
- Or an outside air temperature sensor can do this as well
- Does some valve-maintenance automatically, to avoid that they will get stuck closed over summer

### Which hardware do we support?

**We support all thermostats which are compatible with Home Assistant as long as they are shown up as a climate entity**
Expand Down
1 change: 1 addition & 0 deletions custom_components/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Custom components module."""
2 changes: 1 addition & 1 deletion custom_components/better_thermostat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ async def async_setup(hass: HomeAssistant, config: Config):


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
entry.async_on_unload(entry.add_update_listener(config_entry_update_listener))
return True

Expand Down
4 changes: 2 additions & 2 deletions custom_components/better_thermostat/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ async def startup(self):
# If we have a previously saved temperature
if old_state.attributes.get(ATTR_TEMPERATURE) is None:
self._target_temp = (
trv_state.attributes.get("current_heating_setpoint")
trv_state.attributes.get("temperature")
or trv_state.attributes.get("temperature")
or 5
)
Expand Down Expand Up @@ -569,7 +569,7 @@ async def startup(self):
self.name,
)
self._target_temp = convert_to_float(
str(trv_state.attributes.get("current_heating_setpoint")),
str(trv_state.attributes.get("temperature")),
self.name,
"startup()",
)
Expand Down
4 changes: 1 addition & 3 deletions custom_components/better_thermostat/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
DEFAULT_NAME = "Better Thermostat"
VERSION = "master"
try:
with open(
"/config/custom_components/better_thermostat/manifest.json"
) as manifest_file:
with open("custom_components/better_thermostat/manifest.json") as manifest_file:
manifest = json.load(manifest_file)
VERSION = manifest["version"]
except (FileNotFoundError, KeyError, json.JSONDecodeError) as e:
Expand Down
6 changes: 3 additions & 3 deletions custom_components/better_thermostat/events/trv.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ async def trigger_trv_change(self, event):
return

_new_heating_setpoint = convert_to_float(
str(new_state.attributes.get("current_heating_setpoint", None)),
str(new_state.attributes.get("temperature", None)),
self.name,
"trigger_trv_change()",
)
Expand Down Expand Up @@ -214,7 +214,7 @@ def convert_outbound_states(self, hvac_mode) -> Union[dict, None]:
-------
dict
A dictionary containing the new outbound thermostat state containing the following keys:
current_heating_setpoint: float
temperature: float
local_temperature: float
local_temperature_calibration: float
system_mode: string
Expand Down Expand Up @@ -324,7 +324,7 @@ def convert_outbound_states(self, hvac_mode) -> Union[dict, None]:
hvac_mode = None

return {
"current_heating_setpoint": _new_heating_setpoint,
"temperature": _new_heating_setpoint,
"local_temperature": self._TRV_current_temp,
"system_mode": hvac_mode,
"local_temperature_calibration": _new_local_calibration,
Expand Down
2 changes: 1 addition & 1 deletion custom_components/better_thermostat/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
"@RubenKelevra"
],
"requirements": []
}
}
55 changes: 20 additions & 35 deletions custom_components/better_thermostat/utils/controlling.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ async def control_trv(self, force_mode_change: bool = False):
_trv = self.hass.states.get(self.heater_entity_id)
_current_TRV_mode = _trv.state
_current_set_temperature = convert_to_float(
str(_trv.attributes.get("current_heating_setpoint")),
self.name,
"controlling()",
str(_trv.attributes.get("temperature")), self.name, "controlling()"
)
hvac_mode_send = self._bt_hvac_mode
perfom_change = False
Expand Down Expand Up @@ -96,13 +94,6 @@ async def control_trv(self, force_mode_change: bool = False):
_LOGGER.debug(
f"better_thermostat {self.name}: TO TRV set_hvac_mode: off"
)
await set_trv_values(self, "hvac_mode", HVAC_MODE_OFF)
self._last_states["last_hvac_mode"] = self._bt_hvac_mode
await asyncio.sleep(5)
self.async_write_ha_state()
self.last_change = datetime.now()
self.ignore_states = False
return

elif (
self.call_for_heat is True
Expand Down Expand Up @@ -159,32 +150,38 @@ async def control_trv(self, force_mode_change: bool = False):
self.ignore_states = False
return None
converted_hvac_mode = remapped_states.get("system_mode") or None
current_heating_setpoint = (
remapped_states.get("current_heating_setpoint") or None
)
temperature = remapped_states.get("temperature") or None
calibration = remapped_states.get("local_temperature_calibration") or None

if converted_hvac_mode is not None:
if (_current_TRV_mode != converted_hvac_mode) or perform_calibration:
old = self._last_states.get("last_hvac_mode", "?")
if perform_calibration is False:
_LOGGER.debug(
f"better_thermostat {self.name}: TO TRV set_hvac_mode: from: {old} to: {converted_hvac_mode}"
)
await set_trv_values(self, "hvac_mode", converted_hvac_mode)
self._last_states["last_hvac_mode"] = converted_hvac_mode
perfom_change = True
await asyncio.sleep(3)

if (
current_heating_setpoint is not None
temperature is not None
and self._bt_hvac_mode != HVAC_MODE_OFF
and converted_hvac_mode != HVAC_MODE_OFF
):
if (
_current_set_temperature != current_heating_setpoint
and current_heating_setpoint
!= self._last_states.get("last_target_temp", 0)
_current_set_temperature != temperature
and temperature != self._last_states.get("last_target_temp", 0)
):
old = self._last_states.get("last_target_temp", "?")
_LOGGER.debug(
f"better_thermostat {self.name}: TO TRV set_temperature: from: {old} to: {current_heating_setpoint}"
f"better_thermostat {self.name}: TO TRV set_temperature: from: {old} to: {temperature}"
)
await set_trv_values(
self,
"temperature",
current_heating_setpoint,
hvac_mode=converted_hvac_mode,
self, "temperature", temperature, hvac_mode=converted_hvac_mode
)
self._last_states["last_target_temp"] = current_heating_setpoint
self._last_states["last_target_temp"] = temperature
perfom_change = True
if (
calibration is not None
Expand Down Expand Up @@ -213,18 +210,6 @@ async def control_trv(self, force_mode_change: bool = False):
perform_calibration = True
self._calibration_received = False

if converted_hvac_mode is not None:
if (_current_TRV_mode != converted_hvac_mode) or perform_calibration:
old = self._last_states.get("last_hvac_mode", "?")
if perform_calibration is False:
_LOGGER.debug(
f"better_thermostat {self.name}: TO TRV set_hvac_mode: from: {old} to: {converted_hvac_mode}"
)
await set_trv_values(self, "hvac_mode", converted_hvac_mode)
self._last_states["last_hvac_mode"] = converted_hvac_mode
perfom_change = True
await asyncio.sleep(3)

if perfom_change is True:
self.async_write_ha_state()
self.last_change = datetime.now()
Expand Down
3 changes: 3 additions & 0 deletions requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
homeassistant==2022.10.5
pytest-homeassistant-custom-component
flake8
1 change: 1 addition & 0 deletions requirements_test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest-homeassistant-custom-component==0.12.14
35 changes: 35 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[flake8]
exclude = .venv,.git,.tox,docs,venv,bin,lib,deps,build
doctests = True
# To work with Black
max-line-length = 88
# E501: line too long
# W503: Line break occurred before a binary operator
# E203: Whitespace before ':'
# D202 No blank lines allowed after function docstring
# W504 line break after binary operator
ignore =
E501,
W503,
E203,
D202,
W504

[isort]
# https://github.com/timothycrosley/isort
# https://github.com/timothycrosley/isort/wiki/isort-Settings
# splits long import on multiple lines indented by 4 spaces
multi_line_output = 3
include_trailing_comma=True
force_grid_wrap=0
use_parentheses=True
line_length=88
indent = " "
# by default isort don't check module indexes
not_skip = __init__.py
# will group `import x` and `from x import` of the same module.
force_sort_within_sections = true
sections = FUTURE,STDLIB,INBETWEENS,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
default_section = THIRDPARTY
known_first_party = custom_components.better_thermostat, tests
combine_as_imports = true

0 comments on commit 3cdbbf9

Please sign in to comment.