mirror of https://github.com/home-assistant/core
1094 lines
36 KiB
Python
1094 lines
36 KiB
Python
"""The tests for the Netatmo climate platform."""
|
|
|
|
from datetime import timedelta
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
import pytest
|
|
from syrupy import SnapshotAssertion
|
|
from voluptuous.error import MultipleInvalid
|
|
|
|
from homeassistant.components.climate import (
|
|
ATTR_HVAC_MODE,
|
|
ATTR_PRESET_MODE,
|
|
DOMAIN as CLIMATE_DOMAIN,
|
|
PRESET_AWAY,
|
|
PRESET_BOOST,
|
|
SERVICE_SET_HVAC_MODE,
|
|
SERVICE_SET_PRESET_MODE,
|
|
SERVICE_SET_TEMPERATURE,
|
|
SERVICE_TURN_OFF,
|
|
SERVICE_TURN_ON,
|
|
HVACMode,
|
|
)
|
|
from homeassistant.components.netatmo.climate import PRESET_FROST_GUARD, PRESET_SCHEDULE
|
|
from homeassistant.components.netatmo.const import (
|
|
ATTR_END_DATETIME,
|
|
ATTR_SCHEDULE_NAME,
|
|
ATTR_TARGET_TEMPERATURE,
|
|
ATTR_TIME_PERIOD,
|
|
DOMAIN as NETATMO_DOMAIN,
|
|
SERVICE_CLEAR_TEMPERATURE_SETTING,
|
|
SERVICE_SET_PRESET_MODE_WITH_END_DATETIME,
|
|
SERVICE_SET_SCHEDULE,
|
|
SERVICE_SET_TEMPERATURE_WITH_END_DATETIME,
|
|
SERVICE_SET_TEMPERATURE_WITH_TIME_PERIOD,
|
|
)
|
|
from homeassistant.const import (
|
|
ATTR_ENTITY_ID,
|
|
ATTR_TEMPERATURE,
|
|
CONF_WEBHOOK_ID,
|
|
Platform,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import ServiceValidationError
|
|
import homeassistant.helpers.entity_registry as er
|
|
from homeassistant.util import dt as dt_util
|
|
|
|
from .common import selected_platforms, simulate_webhook, snapshot_platform_entities
|
|
|
|
from tests.common import MockConfigEntry
|
|
|
|
|
|
async def test_entity(
|
|
hass: HomeAssistant,
|
|
config_entry: MockConfigEntry,
|
|
netatmo_auth: AsyncMock,
|
|
snapshot: SnapshotAssertion,
|
|
entity_registry: er.EntityRegistry,
|
|
) -> None:
|
|
"""Test entities."""
|
|
await snapshot_platform_entities(
|
|
hass,
|
|
config_entry,
|
|
Platform.CLIMATE,
|
|
entity_registry,
|
|
snapshot,
|
|
)
|
|
|
|
|
|
async def test_webhook_event_handling_thermostats(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service and webhook event handling with thermostats."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_livingroom = "climate.livingroom"
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "auto"
|
|
assert (
|
|
hass.states.get(climate_entity_livingroom).attributes["preset_mode"] == "away"
|
|
)
|
|
assert hass.states.get(climate_entity_livingroom).attributes["temperature"] == 12
|
|
|
|
# Test service setting the temperature
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_TEMPERATURE,
|
|
{ATTR_ENTITY_ID: climate_entity_livingroom, ATTR_TEMPERATURE: 21},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Fake webhook thermostat manual set point
|
|
response = {
|
|
"room_id": "2746182631",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2746182631",
|
|
"name": "Livingroom",
|
|
"type": "livingroom",
|
|
"therm_setpoint_mode": "manual",
|
|
"therm_setpoint_temperature": 21,
|
|
"therm_setpoint_end_time": 1612734552,
|
|
}
|
|
],
|
|
"modules": [
|
|
{"id": "12:34:56:00:01:ae", "name": "Livingroom", "type": "NATherm1"}
|
|
],
|
|
},
|
|
"mode": "manual",
|
|
"event_type": "set_point",
|
|
"temperature": 21,
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "heat"
|
|
assert (
|
|
hass.states.get(climate_entity_livingroom).attributes["preset_mode"] == "away"
|
|
)
|
|
assert hass.states.get(climate_entity_livingroom).attributes["temperature"] == 21
|
|
|
|
# Test service setting the HVAC mode to "heat"
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_HVAC_MODE,
|
|
{ATTR_ENTITY_ID: climate_entity_livingroom, ATTR_HVAC_MODE: HVACMode.HEAT},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Fake webhook thermostat mode change to "Max"
|
|
response = {
|
|
"room_id": "2746182631",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2746182631",
|
|
"name": "Livingroom",
|
|
"type": "livingroom",
|
|
"therm_setpoint_mode": "max",
|
|
"therm_setpoint_end_time": 1612749189,
|
|
}
|
|
],
|
|
"modules": [
|
|
{"id": "12:34:56:00:01:ae", "name": "Livingroom", "type": "NATherm1"}
|
|
],
|
|
},
|
|
"mode": "max",
|
|
"event_type": "set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "heat"
|
|
assert hass.states.get(climate_entity_livingroom).attributes["temperature"] == 30
|
|
|
|
# Test service setting the HVAC mode to "off"
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_HVAC_MODE,
|
|
{ATTR_ENTITY_ID: climate_entity_livingroom, ATTR_HVAC_MODE: HVACMode.OFF},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Fake webhook turn thermostat off
|
|
response = {
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2746182631",
|
|
"name": "Livingroom",
|
|
"type": "livingroom",
|
|
"therm_setpoint_mode": "off",
|
|
}
|
|
],
|
|
"modules": [
|
|
{"id": "12:34:56:00:01:ae", "name": "Livingroom", "type": "NATherm1"}
|
|
],
|
|
},
|
|
"mode": "off",
|
|
"event_type": "set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "off"
|
|
|
|
# Test service setting the HVAC mode to "auto"
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_HVAC_MODE,
|
|
{ATTR_ENTITY_ID: climate_entity_livingroom, ATTR_HVAC_MODE: HVACMode.AUTO},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Fake webhook thermostat mode cancel set point
|
|
response = {
|
|
"room_id": "2746182631",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2746182631",
|
|
"name": "Livingroom",
|
|
"type": "livingroom",
|
|
"therm_setpoint_mode": "home",
|
|
}
|
|
],
|
|
"modules": [
|
|
{"id": "12:34:56:00:01:ae", "name": "Livingroom", "type": "NATherm1"}
|
|
],
|
|
},
|
|
"mode": "home",
|
|
"event_type": "cancel_set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "auto"
|
|
assert (
|
|
hass.states.get(climate_entity_livingroom).attributes["preset_mode"] == "away"
|
|
)
|
|
|
|
|
|
async def test_service_preset_mode_frost_guard_thermostat(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service with frost guard preset for thermostats."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_livingroom = "climate.livingroom"
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "auto"
|
|
assert (
|
|
hass.states.get(climate_entity_livingroom).attributes["preset_mode"] == "away"
|
|
)
|
|
|
|
# Test service setting the preset mode to "frost guard"
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_PRESET_MODE,
|
|
{
|
|
ATTR_ENTITY_ID: climate_entity_livingroom,
|
|
ATTR_PRESET_MODE: PRESET_FROST_GUARD,
|
|
},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Fake webhook thermostat mode change to "Frost Guard"
|
|
response = {
|
|
"event_type": "therm_mode",
|
|
"home": {"id": "91763b24c43d3e344f424e8b", "therm_mode": "hg"},
|
|
"mode": "hg",
|
|
"previous_mode": "schedule",
|
|
"push_type": "home_event_changed",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "auto"
|
|
assert (
|
|
hass.states.get(climate_entity_livingroom).attributes["preset_mode"]
|
|
== "frost_guard"
|
|
)
|
|
|
|
# Test service setting the preset mode to "frost guard"
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_PRESET_MODE,
|
|
{
|
|
ATTR_ENTITY_ID: climate_entity_livingroom,
|
|
ATTR_PRESET_MODE: PRESET_SCHEDULE,
|
|
},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Test webhook thermostat mode change to "Schedule"
|
|
response = {
|
|
"event_type": "therm_mode",
|
|
"home": {"id": "91763b24c43d3e344f424e8b", "therm_mode": "schedule"},
|
|
"mode": "schedule",
|
|
"previous_mode": "hg",
|
|
"push_type": "home_event_changed",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "auto"
|
|
assert (
|
|
hass.states.get(climate_entity_livingroom).attributes["preset_mode"] == "away"
|
|
)
|
|
|
|
|
|
async def test_service_preset_modes_thermostat(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service with preset modes for thermostats."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_livingroom = "climate.livingroom"
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "auto"
|
|
assert (
|
|
hass.states.get(climate_entity_livingroom).attributes["preset_mode"] == "away"
|
|
)
|
|
|
|
# Test service setting the preset mode to "away"
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_PRESET_MODE,
|
|
{ATTR_ENTITY_ID: climate_entity_livingroom, ATTR_PRESET_MODE: PRESET_AWAY},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Fake webhook thermostat mode change to "Away"
|
|
response = {
|
|
"event_type": "therm_mode",
|
|
"home": {"id": "91763b24c43d3e344f424e8b", "therm_mode": "away"},
|
|
"mode": "away",
|
|
"previous_mode": "schedule",
|
|
"push_type": "home_event_changed",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "auto"
|
|
assert (
|
|
hass.states.get(climate_entity_livingroom).attributes["preset_mode"] == "away"
|
|
)
|
|
|
|
# Test service setting the preset mode to "boost"
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_PRESET_MODE,
|
|
{ATTR_ENTITY_ID: climate_entity_livingroom, ATTR_PRESET_MODE: PRESET_BOOST},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Test webhook thermostat mode change to "Max"
|
|
response = {
|
|
"room_id": "2746182631",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2746182631",
|
|
"name": "Livingroom",
|
|
"type": "livingroom",
|
|
"therm_setpoint_mode": "max",
|
|
"therm_setpoint_end_time": 1612749189,
|
|
}
|
|
],
|
|
"modules": [
|
|
{"id": "12:34:56:00:01:ae", "name": "Livingroom", "type": "NATherm1"}
|
|
],
|
|
},
|
|
"mode": "max",
|
|
"event_type": "set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "heat"
|
|
assert hass.states.get(climate_entity_livingroom).attributes["temperature"] == 30
|
|
|
|
|
|
async def test_service_set_temperature_with_end_datetime(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service setting temperature with an end datetime."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_livingroom = "climate.livingroom"
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "auto"
|
|
|
|
# Test service setting the temperature without an end datetime
|
|
await hass.services.async_call(
|
|
NETATMO_DOMAIN,
|
|
SERVICE_SET_TEMPERATURE_WITH_END_DATETIME,
|
|
{
|
|
ATTR_ENTITY_ID: climate_entity_livingroom,
|
|
ATTR_TARGET_TEMPERATURE: 25,
|
|
ATTR_END_DATETIME: "2023-11-17 12:23:00",
|
|
},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Test webhook room mode change to "manual"
|
|
response = {
|
|
"room_id": "2746182631",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2746182631",
|
|
"name": "Livingroom",
|
|
"type": "livingroom",
|
|
"therm_setpoint_mode": "manual",
|
|
"therm_setpoint_temperature": 25,
|
|
"therm_setpoint_end_time": 1612749189,
|
|
}
|
|
],
|
|
"modules": [
|
|
{"id": "12:34:56:00:01:ae", "name": "Livingroom", "type": "NATherm1"}
|
|
],
|
|
},
|
|
"mode": "manual",
|
|
"event_type": "set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "heat"
|
|
assert hass.states.get(climate_entity_livingroom).attributes["temperature"] == 25
|
|
|
|
|
|
async def test_service_set_temperature_with_time_period(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service setting temperature with an end datetime."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_livingroom = "climate.livingroom"
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "auto"
|
|
|
|
# Test service setting the temperature without an end datetime
|
|
await hass.services.async_call(
|
|
NETATMO_DOMAIN,
|
|
SERVICE_SET_TEMPERATURE_WITH_TIME_PERIOD,
|
|
{
|
|
ATTR_ENTITY_ID: climate_entity_livingroom,
|
|
ATTR_TARGET_TEMPERATURE: 25,
|
|
ATTR_TIME_PERIOD: "02:24:00",
|
|
},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Test webhook room mode change to "manual"
|
|
response = {
|
|
"room_id": "2746182631",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2746182631",
|
|
"name": "Livingroom",
|
|
"type": "livingroom",
|
|
"therm_setpoint_mode": "manual",
|
|
"therm_setpoint_temperature": 25,
|
|
"therm_setpoint_end_time": 1612749189,
|
|
}
|
|
],
|
|
"modules": [
|
|
{"id": "12:34:56:00:01:ae", "name": "Livingroom", "type": "NATherm1"}
|
|
],
|
|
},
|
|
"mode": "manual",
|
|
"event_type": "set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "heat"
|
|
assert hass.states.get(climate_entity_livingroom).attributes["temperature"] == 25
|
|
|
|
|
|
async def test_service_clear_temperature_setting(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service clearing temperature setting."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_livingroom = "climate.livingroom"
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "auto"
|
|
|
|
# Simulate a room thermostat change to manual boost
|
|
response = {
|
|
"room_id": "2746182631",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2746182631",
|
|
"name": "Livingroom",
|
|
"type": "livingroom",
|
|
"therm_setpoint_mode": "manual",
|
|
"therm_setpoint_temperature": 25,
|
|
"therm_setpoint_end_time": 1612749189,
|
|
}
|
|
],
|
|
"modules": [
|
|
{"id": "12:34:56:00:01:ae", "name": "Livingroom", "type": "NATherm1"}
|
|
],
|
|
},
|
|
"mode": "manual",
|
|
"event_type": "set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "heat"
|
|
assert hass.states.get(climate_entity_livingroom).attributes["temperature"] == 25
|
|
|
|
# Test service setting the temperature without an end datetime
|
|
await hass.services.async_call(
|
|
NETATMO_DOMAIN,
|
|
SERVICE_CLEAR_TEMPERATURE_SETTING,
|
|
{ATTR_ENTITY_ID: climate_entity_livingroom},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Test webhook room mode change to "home"
|
|
response = {
|
|
"room_id": "2746182631",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2746182631",
|
|
"name": "Livingroom",
|
|
"type": "livingroom",
|
|
"therm_setpoint_mode": "home",
|
|
}
|
|
],
|
|
"modules": [
|
|
{"id": "12:34:56:00:01:ae", "name": "Livingroom", "type": "NATherm1"}
|
|
],
|
|
},
|
|
"mode": "home",
|
|
"event_type": "cancel_set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "auto"
|
|
|
|
|
|
async def test_webhook_event_handling_no_data(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service and webhook event handling with erroneous data."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
# Test webhook without home entry
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
|
|
response = {
|
|
"push_type": "home_event_changed",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
# Test webhook with different home id
|
|
response = {
|
|
"home_id": "3d3e344f491763b24c424e8b",
|
|
"room_id": "2746182631",
|
|
"home": {
|
|
"id": "3d3e344f491763b24c424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [],
|
|
"modules": [],
|
|
},
|
|
"mode": "home",
|
|
"event_type": "cancel_set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
# Test webhook without room entries
|
|
response = {
|
|
"room_id": "2746182631",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [],
|
|
"modules": [],
|
|
},
|
|
"mode": "home",
|
|
"event_type": "cancel_set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
|
|
async def test_service_schedule_thermostats(
|
|
hass: HomeAssistant, config_entry, caplog: pytest.LogCaptureFixture, netatmo_auth
|
|
) -> None:
|
|
"""Test service for selecting Netatmo schedule with thermostats."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_livingroom = "climate.livingroom"
|
|
|
|
# Test setting a valid schedule
|
|
with patch("pyatmo.home.Home.async_switch_schedule") as mock_switch_schedule:
|
|
await hass.services.async_call(
|
|
"netatmo",
|
|
SERVICE_SET_SCHEDULE,
|
|
{ATTR_ENTITY_ID: climate_entity_livingroom, ATTR_SCHEDULE_NAME: "Winter"},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
mock_switch_schedule.assert_called_once_with(
|
|
schedule_id="b1b54a2f45795764f59d50d8"
|
|
)
|
|
|
|
# Fake backend response for valve being turned on
|
|
response = {
|
|
"event_type": "schedule",
|
|
"schedule_id": "b1b54a2f45795764f59d50d8",
|
|
"previous_schedule_id": "59d32176d183948b05ab4dce",
|
|
"push_type": "home_event_changed",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert (
|
|
hass.states.get(climate_entity_livingroom).attributes["selected_schedule"]
|
|
== "Winter"
|
|
)
|
|
|
|
# Test setting an invalid schedule
|
|
with patch("pyatmo.home.Home.async_switch_schedule") as mock_switch_home_schedule:
|
|
await hass.services.async_call(
|
|
"netatmo",
|
|
SERVICE_SET_SCHEDULE,
|
|
{ATTR_ENTITY_ID: climate_entity_livingroom, ATTR_SCHEDULE_NAME: "summer"},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
mock_switch_home_schedule.assert_not_called()
|
|
|
|
assert "summer is not a valid schedule" in caplog.text
|
|
|
|
|
|
async def test_service_preset_mode_with_end_time_thermostats(
|
|
hass: HomeAssistant, config_entry, caplog: pytest.LogCaptureFixture, netatmo_auth
|
|
) -> None:
|
|
"""Test service for set preset mode with end datetime for Netatmo thermostats."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_livingroom = "climate.livingroom"
|
|
|
|
# Test setting a valid preset mode (that allow an end datetime in Netatmo == THERM_MODES) and a valid end datetime
|
|
await hass.services.async_call(
|
|
"netatmo",
|
|
SERVICE_SET_PRESET_MODE_WITH_END_DATETIME,
|
|
{
|
|
ATTR_ENTITY_ID: climate_entity_livingroom,
|
|
ATTR_PRESET_MODE: PRESET_AWAY,
|
|
ATTR_END_DATETIME: (dt_util.now() + timedelta(days=10)).strftime(
|
|
"%Y-%m-%d %H:%M:%S"
|
|
),
|
|
},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Fake webhook thermostat mode change to "Away"
|
|
response = {
|
|
"event_type": "therm_mode",
|
|
"home": {"id": "91763b24c43d3e344f424e8b", "therm_mode": "away"},
|
|
"mode": "away",
|
|
"previous_mode": "schedule",
|
|
"push_type": "home_event_changed",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_livingroom).state == "auto"
|
|
assert (
|
|
hass.states.get(climate_entity_livingroom).attributes["preset_mode"] == "away"
|
|
)
|
|
|
|
# Test setting an invalid preset mode (not in THERM_MODES) and a valid end datetime
|
|
with pytest.raises(MultipleInvalid):
|
|
await hass.services.async_call(
|
|
"netatmo",
|
|
SERVICE_SET_PRESET_MODE_WITH_END_DATETIME,
|
|
{
|
|
ATTR_ENTITY_ID: climate_entity_livingroom,
|
|
ATTR_PRESET_MODE: PRESET_BOOST,
|
|
ATTR_END_DATETIME: (dt_util.now() + timedelta(days=10)).strftime(
|
|
"%Y-%m-%d %H:%M:%S"
|
|
),
|
|
},
|
|
blocking=True,
|
|
)
|
|
|
|
# Test setting a valid preset mode (that allow an end datetime in Netatmo == THERM_MODES) without an end datetime
|
|
with pytest.raises(MultipleInvalid):
|
|
await hass.services.async_call(
|
|
"netatmo",
|
|
SERVICE_SET_PRESET_MODE_WITH_END_DATETIME,
|
|
{
|
|
ATTR_ENTITY_ID: climate_entity_livingroom,
|
|
ATTR_PRESET_MODE: PRESET_AWAY,
|
|
},
|
|
blocking=True,
|
|
)
|
|
|
|
|
|
async def test_service_preset_mode_already_boost_valves(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service with boost preset for valves when already in boost mode."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_entrada = "climate.entrada"
|
|
|
|
assert hass.states.get(climate_entity_entrada).state == "auto"
|
|
assert (
|
|
hass.states.get(climate_entity_entrada).attributes["preset_mode"]
|
|
== "frost_guard"
|
|
)
|
|
assert hass.states.get(climate_entity_entrada).attributes["temperature"] == 7
|
|
|
|
# Test webhook valve mode change to "Max"
|
|
response = {
|
|
"room_id": "2833524037",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2833524037",
|
|
"name": "Entrada",
|
|
"type": "lobby",
|
|
"therm_setpoint_mode": "max",
|
|
"therm_setpoint_end_time": 1612749189,
|
|
}
|
|
],
|
|
"modules": [{"id": "12:34:56:00:01:ae", "name": "Entrada", "type": "NRV"}],
|
|
},
|
|
"mode": "max",
|
|
"event_type": "set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
# Test service setting the preset mode to "boost"
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_PRESET_MODE,
|
|
{ATTR_ENTITY_ID: climate_entity_entrada, ATTR_PRESET_MODE: PRESET_BOOST},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Test webhook valve mode change to "Max"
|
|
response = {
|
|
"room_id": "2833524037",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2833524037",
|
|
"name": "Entrada",
|
|
"type": "lobby",
|
|
"therm_setpoint_mode": "max",
|
|
"therm_setpoint_end_time": 1612749189,
|
|
}
|
|
],
|
|
"modules": [{"id": "12:34:56:00:01:ae", "name": "Entrada", "type": "NRV"}],
|
|
},
|
|
"mode": "max",
|
|
"event_type": "set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_entrada).state == "heat"
|
|
assert hass.states.get(climate_entity_entrada).attributes["temperature"] == 30
|
|
|
|
|
|
async def test_service_preset_mode_boost_valves(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service with boost preset for valves."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_entrada = "climate.entrada"
|
|
|
|
# Test service setting the preset mode to "boost"
|
|
assert hass.states.get(climate_entity_entrada).state == "auto"
|
|
assert hass.states.get(climate_entity_entrada).attributes["temperature"] == 7
|
|
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_PRESET_MODE,
|
|
{ATTR_ENTITY_ID: climate_entity_entrada, ATTR_PRESET_MODE: PRESET_BOOST},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Fake backend response
|
|
response = {
|
|
"room_id": "2833524037",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2833524037",
|
|
"name": "Entrada",
|
|
"type": "lobby",
|
|
"therm_setpoint_mode": "max",
|
|
"therm_setpoint_end_time": 1612749189,
|
|
}
|
|
],
|
|
"modules": [{"id": "12:34:56:00:01:ae", "name": "Entrada", "type": "NRV"}],
|
|
},
|
|
"mode": "max",
|
|
"event_type": "set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_entrada).state == "heat"
|
|
assert hass.states.get(climate_entity_entrada).attributes["temperature"] == 30
|
|
|
|
|
|
async def test_service_preset_mode_invalid(
|
|
hass: HomeAssistant, config_entry, caplog: pytest.LogCaptureFixture, netatmo_auth
|
|
) -> None:
|
|
"""Test service with invalid preset."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
with pytest.raises(ServiceValidationError):
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_SET_PRESET_MODE,
|
|
{ATTR_ENTITY_ID: "climate.cocina", ATTR_PRESET_MODE: "invalid"},
|
|
blocking=True,
|
|
)
|
|
|
|
|
|
async def test_valves_service_turn_off(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service turn off for valves."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_entrada = "climate.entrada"
|
|
|
|
assert hass.states.get(climate_entity_entrada).attributes["hvac_modes"] == [
|
|
"auto",
|
|
"heat",
|
|
]
|
|
|
|
# Test turning valve off
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_TURN_OFF,
|
|
{ATTR_ENTITY_ID: climate_entity_entrada},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Fake backend response for valve being turned off
|
|
response = {
|
|
"room_id": "2833524037",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2833524037",
|
|
"name": "Entrada",
|
|
"type": "lobby",
|
|
"therm_setpoint_mode": "off",
|
|
}
|
|
],
|
|
"modules": [{"id": "12:34:56:00:01:ae", "name": "Entrada", "type": "NRV"}],
|
|
},
|
|
"mode": "off",
|
|
"event_type": "set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_entrada).state == "off"
|
|
|
|
|
|
async def test_valves_service_turn_on(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service turn on for valves."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_entrada = "climate.entrada"
|
|
|
|
# Test turning valve on
|
|
await hass.services.async_call(
|
|
CLIMATE_DOMAIN,
|
|
SERVICE_TURN_ON,
|
|
{ATTR_ENTITY_ID: climate_entity_entrada},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# Fake backend response for valve being turned on
|
|
response = {
|
|
"room_id": "2833524037",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2833524037",
|
|
"name": "Entrada",
|
|
"type": "lobby",
|
|
"therm_setpoint_mode": "home",
|
|
}
|
|
],
|
|
"modules": [{"id": "12:34:56:00:01:ae", "name": "Entrada", "type": "NRV"}],
|
|
},
|
|
"mode": "home",
|
|
"event_type": "cancel_set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_entrada).state == "auto"
|
|
|
|
|
|
async def test_webhook_home_id_mismatch(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service turn on for valves."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_entrada = "climate.entrada"
|
|
|
|
assert hass.states.get(climate_entity_entrada).state == "auto"
|
|
|
|
# Fake backend response for valve being turned on
|
|
response = {
|
|
"room_id": "2833524037",
|
|
"home": {
|
|
"id": "123",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2833524037",
|
|
"name": "Entrada",
|
|
"type": "lobby",
|
|
"therm_setpoint_mode": "home",
|
|
}
|
|
],
|
|
"modules": [{"id": "12:34:56:00:01:ae", "name": "Entrada", "type": "NRV"}],
|
|
},
|
|
"mode": "home",
|
|
"event_type": "cancel_set_point",
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_entrada).state == "auto"
|
|
|
|
|
|
async def test_webhook_set_point(
|
|
hass: HomeAssistant, config_entry: MockConfigEntry, netatmo_auth: AsyncMock
|
|
) -> None:
|
|
"""Test service turn on for valves."""
|
|
with selected_platforms([Platform.CLIMATE]):
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
|
climate_entity_entrada = "climate.entrada"
|
|
|
|
# Fake backend response for valve being turned on
|
|
response = {
|
|
"room_id": "2746182631",
|
|
"home": {
|
|
"id": "91763b24c43d3e344f424e8b",
|
|
"name": "MYHOME",
|
|
"country": "DE",
|
|
"rooms": [
|
|
{
|
|
"id": "2833524037",
|
|
"name": "Entrada",
|
|
"type": "lobby",
|
|
"therm_setpoint_mode": "home",
|
|
"therm_setpoint_temperature": 30,
|
|
}
|
|
],
|
|
"modules": [{"id": "12:34:56:00:01:ae", "name": "Entrada", "type": "NRV"}],
|
|
},
|
|
"mode": "home",
|
|
"event_type": "set_point",
|
|
"temperature": 21,
|
|
"push_type": "display_change",
|
|
}
|
|
await simulate_webhook(hass, webhook_id, response)
|
|
|
|
assert hass.states.get(climate_entity_entrada).state == "heat"
|