Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: tetele/hvac_group
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0.2.0-beta.4
Choose a base ref
...
head repository: tetele/hvac_group
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 0.2.0-beta.5
Choose a head ref
Loading
22 changes: 22 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -33,3 +33,25 @@ jobs:
uses: "hacs/action@main"
with:
category: "integration"

pytest:
name: "Run tests"
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12"]

steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements_test.txt
- name: Test with pytest
run: |
pytest tests/ --asyncio-mode auto
16 changes: 3 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -26,18 +26,8 @@ _Create a custom thermostat to control multiple other climate components. Useful

[![Open your Home Assistant instance and open HVAC Group inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=tetele&repository=hvac_group&category=Integration)

1. If you're using HACS, go to "HACS" > "Integrations" and add `https://github.com/tetele/hvac_group` as a [custom repository](https://hacs.xyz/docs/faq/custom_repositories/) under the "Integration" category
1. In the HA UI go to "Settings" -> "Devices & services" -> "Helpers" click "+" and search for "HVAC group"

### Standalone

1. Using the tool of choice open the directory (folder) for your HA configuration (where you find `configuration.yaml`).
1. If you do not have a `custom_components` directory (folder) there, you need to create it.
1. In the `custom_components` directory (folder) create a new folder called `hvac_group`.
1. Download _all_ the files from the `custom_components/hvac_group/` directory (folder) in this repository.
1. Place the files you downloaded in the new directory (folder) you created.
1. Restart Home Assistant
1. In the HA UI go to "Settings" -> "Devices & services" -> "Helpers" click "+" and search for "HVAC group"
1. If you're using HACS, go to "HACS" > "Integrations" and search for the `HVAC Group` integration, then download it
1. In the HA UI go to "Settings" -> "Devices & services" -> "Helpers" click "+" and search for "HVAC Group"

## Configuration is done in the UI

@@ -64,7 +54,7 @@ If you want to contribute to this please read the [Contribution guidelines](CONT
[commits-shield]: https://img.shields.io/github/commit-activity/y/tetele/hvac_group.svg?style=for-the-badge
[commits]: https://github.com/tetele/hvac_group/commits/main
[hacs]: https://github.com/hacs/integration
[hacsbadge]: https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge
[hacsbadge]: https://img.shields.io/badge/HACS-Default-orange.svg?style=for-the-badge

<!-- [discord]: https://discord.gg/Qa5fW2R -->
<!-- [discord-shield]: https://img.shields.io/discord/330944238910963714.svg?style=for-the-badge -->
29 changes: 13 additions & 16 deletions custom_components/hvac_group/climate.py
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@
ATTR_TEMPERATURE,
CONF_NAME,
PRECISION_HALVES,
PRECISION_TENTHS,
PRECISION_WHOLE,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
UnitOfTemperature,
@@ -74,13 +74,18 @@ async def async_setup_entry(

sensor_entity_id = config_entry.options.get(CONF_CURRENT_TEMPERATURE_ENTITY_ID)

precision = config_entry.options.get(CONF_PRECISION, PRECISION_TENTHS)
temperature_unit = hass.config.units.temperature_unit

precision = config_entry.options.get(CONF_PRECISION)
target_temperature_step = config_entry.options.get(
CONF_TARGET_TEMP_STEP, PRECISION_HALVES
CONF_TARGET_TEMP_STEP,
(
PRECISION_HALVES
if temperature_unit == UnitOfTemperature.CELSIUS
else PRECISION_WHOLE
),
)

temperature_unit = hass.config.units.temperature_unit

min_temp = config_entry.options.get(
CONF_MIN_TEMP,
TemperatureConverter.convert(
@@ -181,7 +186,7 @@ def __init__(
self._attr_unique_id = unique_id

self._temperature_sensor_entity_id = temperature_sensor_entity_id
self._temp_precision = precision or PRECISION_TENTHS
self._temp_precision = precision
self._temp_target_temperature_step = target_temperature_step
self._attr_temperature_unit = temperature_unit

@@ -861,22 +866,14 @@ def _update_hvac_modes(self, actuator_type: HvacActuatorType) -> bool:
required_mode in self._attr_hvac_modes
or HVACMode.HEAT_COOL in self._attr_hvac_modes
):
self._attr_hvac_modes.append(required_mode)
modes_have_changed = True
if opposite_mode in self._attr_hvac_modes:
self._attr_hvac_modes.remove(opposite_mode)
self._attr_hvac_modes.append(HVACMode.HEAT_COOL)
modes_have_changed = not bool(
self._attr_supported_features
& ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
)
self._attr_supported_features = (
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
)
else:
self._attr_hvac_modes.append(required_mode)
modes_have_changed = not bool(
self._attr_supported_features
& ClimateEntityFeature.TARGET_TEMPERATURE
)
self._attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE

if modes_have_changed:
34 changes: 34 additions & 0 deletions custom_components/hvac_group/translations/ro.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"config": {
"step": {
"user": {
"title": "Adaugă grup de climatizare (HVAC)",
"description": "Grupurile de climatizare (HVAC) îți permit să creezi un termostat nou care controlează alte termostate dintr-o interfață unificată.",
"data": {
"name": "Nume",
"heaters": "Elemente de încălzire",
"toggle_heaters": "Pornește sau oprește elementele de încălzire în funcție de temperatura ambientală",
"coolers": "Elemente de răcire",
"toggle_coolers": "Pornește sau oprește elementele de răcire în funcție de temperatura ambientală",
"hide_members": "Ascunde membrii",
"temperature_entity_id": "Senzor de temperatură"
}
}
}
},
"options": {
"step": {
"init": {
"title": "Modifică grup de climatizare (HVAC)",
"data": {
"heaters": "Elemente de încălzire",
"toggle_heaters": "Pornește sau oprește elementele de încălzire în funcție de temperatura ambientală",
"coolers": "Elemente de răcire",
"toggle_coolers": "Pornește sau oprește elementele de răcire în funcție de temperatura ambientală",
"hide_members": "Ascunde membrii",
"temperature_entity_id": "Senzor de temperatură"
}
}
}
}
}
34 changes: 34 additions & 0 deletions custom_components/hvac_group/translations/sk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"config": {
"step": {
"user": {
"title": "Pridať skupinu HVAC",
"description": "HVAC Groups vám umožňujú vytvoriť nový termostat, ktorý ovláda ostatné termostaty pomocou jediného rozhrania.",
"data": {
"name": "Názov",
"heaters": "Termostaty vykurovania",
"toggle_heaters": "Zapnite alebo vypnite ohrievače v závislosti od teploty okolia",
"coolers": "Termostaty chladenia",
"toggle_coolers": "Zapnite alebo vypnite chladiče v závislosti od okolitej teploty",
"hide_members": "Skryť členov",
"temperature_entity_id": "Teplotný senzor"
}
}
}
},
"options": {
"step": {
"init": {
"title": "Upraviť skupinu HVAC",
"data": {
"heaters": "Termostaty vykurovania",
"toggle_heaters": "Zapnite alebo vypnite ohrievače v závislosti od teploty okolia",
"coolers": "Termostaty chladenia",
"toggle_coolers": "Zapnite alebo vypnite chladiče v závislosti od okolitej teploty",
"hide_members": "Skryť členov",
"temperature_entity_id": "Teplotný senzor"
}
}
}
}
}
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
colorlog==6.8.0
colorlog==6.8.2
homeassistant==2024.1.2
pip>=21.0,<23.4
ruff==0.1.14
pip>=21.0,<24.1
ruff==0.2.1
2 changes: 2 additions & 0 deletions requirements_test.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
pytest>=7.4.0,<7.5
pytest-asyncio>=0.21.0,<0.23.5
pytest-homeassistant-custom-component==0.13.88
pre-commit
65 changes: 65 additions & 0 deletions tests/test_climate.py
Original file line number Diff line number Diff line change
@@ -11,8 +11,10 @@
ATTR_MAX_TEMP,
ATTR_TARGET_TEMP_LOW,
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_STEP,
ATTR_TEMPERATURE,
DOMAIN as CLIMATE_DOMAIN,
PRECISION_WHOLE,
SERVICE_SET_TEMPERATURE,
ClimateEntityFeature,
HVACMode,
@@ -25,6 +27,7 @@
CONF_ENTITY_ID,
CONF_NAME,
CONF_PLATFORM,
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
@@ -171,6 +174,8 @@ async def hvac_group_entry(
async def test_bare_setup(hass: HomeAssistant) -> None:
"""Test an empty config entry setup."""

hass.config.units.temperature_unit = UnitOfTemperature.FAHRENHEIT

entry = MockConfigEntry(
title="HVAC group 1",
domain=DOMAIN,
@@ -213,6 +218,12 @@ async def test_bare_setup(hass: HomeAssistant) -> None:
)

assert entity_id == "climate.test_hvac"
assert (
hass.states.get(entity_id).attributes.get(ATTR_TARGET_TEMP_STEP)
== PRECISION_WHOLE
)

hass.config.units.temperature_unit = UnitOfTemperature.CELSIUS


@pytest.mark.parametrize(("setup_extras", "group_extras"), [({}, {})])
@@ -362,6 +373,60 @@ async def test_setup(
},
},
),
# Test 4 - check setting COOL mode
(
{DEMO_TEMP_SENSOR: (27, {})},
{"options": {CONF_TOGGLE_COOLERS: True, CONF_TOGGLE_HEATERS: True}},
{
ATTR_TARGET_TEMP_LOW: 21,
ATTR_TARGET_TEMP_HIGH: 23,
ATTR_HVAC_MODE: HVACMode.COOL,
},
{
DEMO_COOLER_SINGLE_TEMP: {
ATTR_HVAC_MODE: HVACMode.COOL,
},
DEMO_COOLER_TEMP_RANGE: {
ATTR_HVAC_MODE: HVACMode.COOL,
},
DEMO_HEATER_SINGLE_TEMP: {
ATTR_HVAC_MODE: HVACMode.OFF,
},
DEMO_HEATER_TEMP_RANGE: {
ATTR_HVAC_MODE: HVACMode.OFF,
},
DEMO_COOLER_HEATER: {
ATTR_HVAC_MODE: HVACMode.COOL,
},
},
),
# Test 5 - check setting HEAT mode
(
{DEMO_TEMP_SENSOR: (20, {})},
{"options": {CONF_TOGGLE_COOLERS: True, CONF_TOGGLE_HEATERS: True}},
{
ATTR_TARGET_TEMP_LOW: 21,
ATTR_TARGET_TEMP_HIGH: 23,
ATTR_HVAC_MODE: HVACMode.HEAT,
},
{
DEMO_COOLER_SINGLE_TEMP: {
ATTR_HVAC_MODE: HVACMode.OFF,
},
DEMO_COOLER_TEMP_RANGE: {
ATTR_HVAC_MODE: HVACMode.OFF,
},
DEMO_HEATER_SINGLE_TEMP: {
ATTR_HVAC_MODE: HVACMode.HEAT,
},
DEMO_HEATER_TEMP_RANGE: {
ATTR_HVAC_MODE: HVACMode.HEAT,
},
DEMO_COOLER_HEATER: {
ATTR_HVAC_MODE: HVACMode.HEAT,
},
},
),
],
)
@pytest.mark.asyncio