Skip to content

Commit

Permalink
Testus 2
Browse files Browse the repository at this point in the history
  • Loading branch information
Jean-Marc Collin committed Feb 12, 2023
1 parent 7a917c6 commit 81b4f7e
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 42 deletions.
11 changes: 6 additions & 5 deletions custom_components/versatile_thermostat/prop_algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ def calculate(
def _calculate_internal(self):
"""Finish the calculation to get the on_percent in seconds"""

# calculated on_time duration in seconds
if self._calculated_on_percent > 1:
self._calculated_on_percent = 1
if self._calculated_on_percent < 0:
self._calculated_on_percent = 0

if self._security:
_LOGGER.debug(
"Security is On using the default_on_percent %f",
Expand All @@ -98,11 +104,6 @@ def _calculate_internal(self):
)
self._on_percent = self._calculated_on_percent

# calculated on_time duration in seconds
if self._on_percent > 1:
self._on_percent = 1
if self._on_percent < 0:
self._on_percent = 0
self._on_time_sec = self._on_percent * self._cycle_min * 60

# Do not heat for less than xx sec
Expand Down
67 changes: 66 additions & 1 deletion custom_components/versatile_thermostat/tests/commons.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,58 @@
""" Some common resources """
from unittest.mock import patch

from homeassistant.core import HomeAssistant
from homeassistant.components.climate import ClimateEntity
from homeassistant.const import UnitOfTemperature

from homeassistant.config_entries import ConfigEntryState
from pytest_homeassistant_custom_component.common import MockConfigEntry
from homeassistant.helpers.entity_component import EntityComponent

from ..climate import VersatileThermostat
from ..const import DOMAIN

from homeassistant.components.climate import (
ClimateEntity,
DOMAIN as CLIMATE_DOMAIN,
ATTR_PRESET_MODE,
HVACMode,
HVACAction,
)

from .const import (
MOCK_TH_OVER_SWITCH_USER_CONFIG,
MOCK_TH_OVER_CLIMATE_USER_CONFIG,
MOCK_TH_OVER_SWITCH_TYPE_CONFIG,
MOCK_TH_OVER_CLIMATE_TYPE_CONFIG,
MOCK_TH_OVER_SWITCH_TPI_CONFIG,
MOCK_PRESETS_CONFIG,
MOCK_WINDOW_CONFIG,
MOCK_MOTION_CONFIG,
MOCK_POWER_CONFIG,
MOCK_PRESENCE_CONFIG,
MOCK_ADVANCED_CONFIG,
# MOCK_DEFAULT_FEATURE_CONFIG,
)

FULL_SWITCH_CONFIG = (
MOCK_TH_OVER_SWITCH_USER_CONFIG
| MOCK_TH_OVER_SWITCH_TYPE_CONFIG
| MOCK_TH_OVER_SWITCH_TPI_CONFIG
| MOCK_PRESETS_CONFIG
| MOCK_WINDOW_CONFIG
| MOCK_MOTION_CONFIG
| MOCK_POWER_CONFIG
| MOCK_PRESENCE_CONFIG
| MOCK_ADVANCED_CONFIG
)

PARTIAL_CLIMATE_CONFIG = (
MOCK_TH_OVER_CLIMATE_USER_CONFIG
| MOCK_TH_OVER_CLIMATE_TYPE_CONFIG
| MOCK_PRESETS_CONFIG
| MOCK_ADVANCED_CONFIG
)


class MockClimate(ClimateEntity):
"""A Mock Climate class used for Underlying climate mode"""
Expand All @@ -28,3 +70,26 @@ def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
self._attr_hvac_mode = HVACMode.OFF
self._attr_hvac_modes = [HVACMode.OFF, HVACMode.COOL, HVACMode.HEAT]
self._attr_temperature_unit = UnitOfTemperature.CELSIUS


async def create_thermostat(
hass: HomeAssistant, entry: MockConfigEntry, entity_id: str
) -> VersatileThermostat:
"""Creates and return a TPI Thermostat"""
with patch(
"custom_components.versatile_thermostat.climate.VersatileThermostat.send_event"
):
entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id)
assert entry.state is ConfigEntryState.LOADED

def find_my_entity(entity_id) -> ClimateEntity:
"""Find my new entity"""
component: EntityComponent[ClimateEntity] = hass.data[CLIMATE_DOMAIN]
for entity in component.entities:
if entity.entity_id == entity_id:
return entity

entity = find_my_entity(entity_id)

return entity
39 changes: 3 additions & 36 deletions custom_components/versatile_thermostat/tests/test_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,7 @@

from ..const import DOMAIN, EventType

from .const import (
MOCK_TH_OVER_SWITCH_USER_CONFIG,
MOCK_TH_OVER_CLIMATE_USER_CONFIG,
MOCK_TH_OVER_SWITCH_TYPE_CONFIG,
MOCK_TH_OVER_CLIMATE_TYPE_CONFIG,
MOCK_TH_OVER_SWITCH_TPI_CONFIG,
MOCK_PRESETS_CONFIG,
MOCK_WINDOW_CONFIG,
MOCK_MOTION_CONFIG,
MOCK_POWER_CONFIG,
MOCK_PRESENCE_CONFIG,
MOCK_ADVANCED_CONFIG,
# MOCK_DEFAULT_FEATURE_CONFIG,
)

from .commons import MockClimate

FULL_SWITCH_CONFIG = (
MOCK_TH_OVER_SWITCH_USER_CONFIG
| MOCK_TH_OVER_SWITCH_TYPE_CONFIG
| MOCK_TH_OVER_SWITCH_TPI_CONFIG
| MOCK_PRESETS_CONFIG
| MOCK_WINDOW_CONFIG
| MOCK_MOTION_CONFIG
| MOCK_POWER_CONFIG
| MOCK_PRESENCE_CONFIG
| MOCK_ADVANCED_CONFIG
)

PARTIAL_CLIMATE_CONFIG = (
MOCK_TH_OVER_CLIMATE_USER_CONFIG
| MOCK_TH_OVER_CLIMATE_TYPE_CONFIG
| MOCK_PRESETS_CONFIG
| MOCK_ADVANCED_CONFIG
)
from .commons import MockClimate, FULL_SWITCH_CONFIG, PARTIAL_CLIMATE_CONFIG


async def test_over_switch_full_start(hass: HomeAssistant, skip_hass_states_is_state):
Expand All @@ -76,7 +42,7 @@ def find_my_entity(entity_id) -> ClimateEntity:
if entity.entity_id == entity_id:
return entity

entity = find_my_entity("climate.theoverswitchmockname")
entity: VersatileThermostat = find_my_entity("climate.theoverswitchmockname")

assert entity

Expand All @@ -90,6 +56,7 @@ def find_my_entity(entity_id) -> ClimateEntity:
assert entity._window_state is None
assert entity._motion_state is None
assert entity._presence_state is None
assert entity._prop_algorithm is not None

# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
assert mock_send_event.call_count == 2
Expand Down
81 changes: 81 additions & 0 deletions custom_components/versatile_thermostat/tests/test_tpi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
""" Test the TPI algorithm """

from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import


async def test_tpi_calculation(hass: HomeAssistant, skip_hass_states_is_state):
"""Test the TPI calculation"""

entry = MockConfigEntry(
domain=DOMAIN,
title="TheOverSwitchMockName",
unique_id="uniqueId",
data={
"name": "TheOverSwitchMockName",
"thermostat_type": "thermostat_over_switch",
"temperature_sensor_entity_id": "sensor.mock_temp_sensor",
"external_temperature_sensor_entity_id": "sensor.mock_ext_temp_sensor",
"cycle_min": 5,
"temp_min": 15,
"temp_max": 30,
"use_window_feature": False,
"use_motion_feature": False,
"use_power_feature": False,
"use_presence_feature": False,
"heater_entity_id": "switch.mock_switch",
"proportional_function": "tpi",
"tpi_coef_int": 0.3,
"tpi_coef_ext": 0.01,
"minimal_activation_delay": 30,
"security_delay_min": 5,
"security_default_on_percent": 0.3,
},
)

entity: VersatileThermostat = await create_thermostat(
hass, entry, "climate.theoverswitchmockname"
)
assert entity

tpi_algo = entity._prop_algorithm
assert tpi_algo

tpi_algo.calculate(15, 10, 7)
assert tpi_algo.on_percent == 1
assert tpi_algo.calculated_on_percent == 1
assert tpi_algo.on_time_sec == 300
assert tpi_algo.off_time_sec == 0

tpi_algo.calculate(15, 14, 5)
assert tpi_algo.on_percent == 0.4
assert tpi_algo.calculated_on_percent == 0.4
assert tpi_algo.on_time_sec == 120
assert tpi_algo.off_time_sec == 180

tpi_algo.set_security(0.1)
tpi_algo.calculate(15, 14, 5)
assert tpi_algo.on_percent == 0.1
assert tpi_algo.calculated_on_percent == 0.4
assert tpi_algo.on_time_sec == 30 # >= minimal_activation_delay (=30)
assert tpi_algo.off_time_sec == 270

tpi_algo.unset_security()
tpi_algo.calculate(15, 14, 5)
assert tpi_algo.on_percent == 0.4
assert tpi_algo.calculated_on_percent == 0.4
assert tpi_algo.on_time_sec == 120
assert tpi_algo.off_time_sec == 180

# Test minimal activation delay
tpi_algo.calculate(15, 14.7, 15)
assert tpi_algo.on_percent == 0.09
assert tpi_algo.calculated_on_percent == 0.09
assert tpi_algo.on_time_sec == 0
assert tpi_algo.off_time_sec == 300

tpi_algo.set_security(0.09)
tpi_algo.calculate(15, 14.7, 15)
assert tpi_algo.on_percent == 0.09
assert tpi_algo.calculated_on_percent == 0.09
assert tpi_algo.on_time_sec == 0
assert tpi_algo.off_time_sec == 300

0 comments on commit 81b4f7e

Please sign in to comment.