mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 23:57:06 +00:00
Merge pull request #51595 from home-assistant/rc
This commit is contained in:
commit
e5028d285c
4
.github/workflows/builder.yml
vendored
4
.github/workflows/builder.yml
vendored
@ -115,7 +115,7 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build base image
|
||||
uses: home-assistant/builder@2021.05.0
|
||||
uses: home-assistant/builder@2021.06.2
|
||||
with:
|
||||
args: |
|
||||
$BUILD_ARGS \
|
||||
@ -167,7 +167,7 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build base image
|
||||
uses: home-assistant/builder@2021.05.0
|
||||
uses: home-assistant/builder@2021.06.2
|
||||
with:
|
||||
args: |
|
||||
$BUILD_ARGS \
|
||||
|
@ -228,10 +228,10 @@ class AsusWrtRouter:
|
||||
|
||||
# System
|
||||
model = await _get_nvram_info(self._api, "MODEL")
|
||||
if model:
|
||||
if model and "model" in model:
|
||||
self._model = model["model"]
|
||||
firmware = await _get_nvram_info(self._api, "FIRMWARE")
|
||||
if firmware:
|
||||
if firmware and "firmver" in firmware and "buildno" in firmware:
|
||||
self._sw_v = f"{firmware['firmver']} (build {firmware['buildno']})"
|
||||
|
||||
# Load tracked entities from registry
|
||||
|
@ -44,11 +44,15 @@ class BroadlinkHeartbeat:
|
||||
"""Send packets to feed watchdog timers."""
|
||||
hass = self._hass
|
||||
config_entries = hass.config_entries.async_entries(DOMAIN)
|
||||
hosts = {entry.data[CONF_HOST] for entry in config_entries}
|
||||
await hass.async_add_executor_job(self.heartbeat, hosts)
|
||||
|
||||
for entry in config_entries:
|
||||
host = entry.data[CONF_HOST]
|
||||
@staticmethod
|
||||
def heartbeat(hosts):
|
||||
"""Send packets to feed watchdog timers."""
|
||||
for host in hosts:
|
||||
try:
|
||||
await hass.async_add_executor_job(blk.ping, host)
|
||||
blk.ping(host)
|
||||
except OSError as err:
|
||||
_LOGGER.debug("Failed to send heartbeat to %s: %s", host, err)
|
||||
else:
|
||||
|
@ -3,6 +3,6 @@
|
||||
"name": "Deutscher Wetterdienst (DWD) Weather Warnings",
|
||||
"documentation": "https://www.home-assistant.io/integrations/dwd_weather_warnings",
|
||||
"codeowners": ["@runningman84", "@stephan192", "@Hummel95"],
|
||||
"requirements": ["dwdwfsapi==1.0.3"],
|
||||
"requirements": ["dwdwfsapi==1.0.4"],
|
||||
"iot_class": "cloud_polling"
|
||||
}
|
||||
|
@ -39,14 +39,14 @@ class GarminConnectConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
return await self._show_setup_form()
|
||||
|
||||
websession = async_get_clientsession(self.hass)
|
||||
username = user_input[CONF_USERNAME]
|
||||
password = user_input[CONF_PASSWORD]
|
||||
|
||||
garmin_client = Garmin(
|
||||
websession, user_input[CONF_USERNAME], user_input[CONF_PASSWORD]
|
||||
)
|
||||
garmin_client = Garmin(websession, username, password)
|
||||
|
||||
errors = {}
|
||||
try:
|
||||
username = await garmin_client.login()
|
||||
await garmin_client.login()
|
||||
except GarminConnectConnectionError:
|
||||
errors["base"] = "cannot_connect"
|
||||
return await self._show_setup_form(errors)
|
||||
@ -68,7 +68,7 @@ class GarminConnectConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
title=username,
|
||||
data={
|
||||
CONF_ID: username,
|
||||
CONF_USERNAME: user_input[CONF_USERNAME],
|
||||
CONF_PASSWORD: user_input[CONF_PASSWORD],
|
||||
CONF_USERNAME: username,
|
||||
CONF_PASSWORD: password,
|
||||
},
|
||||
)
|
||||
|
@ -2,7 +2,7 @@
|
||||
"domain": "garmin_connect",
|
||||
"name": "Garmin Connect",
|
||||
"documentation": "https://www.home-assistant.io/integrations/garmin_connect",
|
||||
"requirements": ["garminconnect_aio==0.1.1"],
|
||||
"requirements": ["garminconnect_aio==0.1.4"],
|
||||
"codeowners": ["@cyberjunky"],
|
||||
"config_flow": true,
|
||||
"iot_class": "cloud_polling"
|
||||
|
@ -1,4 +1,6 @@
|
||||
"""Offer geolocation automation rules."""
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.geo_location import DOMAIN
|
||||
@ -10,6 +12,8 @@ from homeassistant.helpers.event import TrackStates, async_track_state_change_fi
|
||||
|
||||
# mypy: allow-untyped-defs, no-check-untyped-defs
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
EVENT_ENTER = "enter"
|
||||
EVENT_LEAVE = "leave"
|
||||
DEFAULT_EVENT = EVENT_ENTER
|
||||
@ -49,6 +53,13 @@ async def async_attach_trigger(hass, config, action, automation_info):
|
||||
return
|
||||
|
||||
zone_state = hass.states.get(zone_entity_id)
|
||||
if zone_state is None:
|
||||
_LOGGER.warning(
|
||||
"Unable to execute automation %s: Zone %s not found",
|
||||
automation_info["name"],
|
||||
zone_entity_id,
|
||||
)
|
||||
return
|
||||
|
||||
from_match = (
|
||||
condition.zone(hass, zone_state, from_state) if from_state else False
|
||||
|
@ -2,7 +2,7 @@
|
||||
"domain": "ialarm",
|
||||
"name": "Antifurto365 iAlarm",
|
||||
"documentation": "https://www.home-assistant.io/integrations/ialarm",
|
||||
"requirements": ["pyialarm==1.7"],
|
||||
"requirements": ["pyialarm==1.8.1"],
|
||||
"codeowners": ["@RyuzakiKK"],
|
||||
"config_flow": true,
|
||||
"iot_class": "local_polling"
|
||||
|
@ -172,14 +172,12 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
try:
|
||||
async with async_timeout.timeout(30):
|
||||
async with async_timeout.timeout(60):
|
||||
await isy.initialize()
|
||||
except asyncio.TimeoutError as err:
|
||||
_LOGGER.error(
|
||||
"Timed out initializing the ISY; device may be busy, trying again later: %s",
|
||||
err,
|
||||
)
|
||||
raise ConfigEntryNotReady from err
|
||||
raise ConfigEntryNotReady(
|
||||
f"Timed out initializing the ISY; device may be busy, trying again later: {err}"
|
||||
) from err
|
||||
except ISYInvalidAuthError as err:
|
||||
_LOGGER.error(
|
||||
"Invalid credentials for the ISY, please adjust settings and try again: %s",
|
||||
@ -187,16 +185,13 @@ async def async_setup_entry(
|
||||
)
|
||||
return False
|
||||
except ISYConnectionError as err:
|
||||
_LOGGER.error(
|
||||
"Failed to connect to the ISY, please adjust settings and try again: %s",
|
||||
err,
|
||||
)
|
||||
raise ConfigEntryNotReady from err
|
||||
raise ConfigEntryNotReady(
|
||||
f"Failed to connect to the ISY, please adjust settings and try again: {err}"
|
||||
) from err
|
||||
except ISYResponseParseError as err:
|
||||
_LOGGER.warning(
|
||||
"Error processing responses from the ISY; device may be busy, trying again later"
|
||||
)
|
||||
raise ConfigEntryNotReady from err
|
||||
raise ConfigEntryNotReady(
|
||||
f"Invalid XML response from ISY; Ensure the ISY is running the latest firmware: {err}"
|
||||
) from err
|
||||
|
||||
_categorize_nodes(hass_isy_data, isy.nodes, ignore_identifier, sensor_identifier)
|
||||
_categorize_programs(hass_isy_data, isy.programs)
|
||||
|
@ -186,9 +186,6 @@ async def async_setup_entity_basic(
|
||||
hass, config, async_add_entities, config_entry, discovery_data=None
|
||||
):
|
||||
"""Set up a MQTT Light."""
|
||||
if CONF_STATE_VALUE_TEMPLATE not in config and CONF_VALUE_TEMPLATE in config:
|
||||
config[CONF_STATE_VALUE_TEMPLATE] = config[CONF_VALUE_TEMPLATE]
|
||||
|
||||
async_add_entities([MqttLight(hass, config, config_entry, discovery_data)])
|
||||
|
||||
|
||||
@ -236,6 +233,9 @@ class MqttLight(MqttEntity, LightEntity, RestoreEntity):
|
||||
|
||||
def _setup_from_config(self, config):
|
||||
"""(Re)Setup the entity."""
|
||||
if CONF_STATE_VALUE_TEMPLATE not in config and CONF_VALUE_TEMPLATE in config:
|
||||
config[CONF_STATE_VALUE_TEMPLATE] = config[CONF_VALUE_TEMPLATE]
|
||||
|
||||
topic = {
|
||||
key: config.get(key)
|
||||
for key in (
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "ReCollect Waste",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/recollect_waste",
|
||||
"requirements": ["aiorecollect==1.0.4"],
|
||||
"requirements": ["aiorecollect==1.0.5"],
|
||||
"codeowners": ["@bachya"],
|
||||
"iot_class": "cloud_polling"
|
||||
}
|
||||
|
@ -280,10 +280,10 @@ def _update_states_table_with_foreign_key_options(connection, engine):
|
||||
for foreign_key in inspector.get_foreign_keys(TABLE_STATES):
|
||||
if foreign_key["name"] and (
|
||||
# MySQL/MariaDB will have empty options
|
||||
not foreign_key["options"]
|
||||
not foreign_key.get("options")
|
||||
or
|
||||
# Postgres will have ondelete set to None
|
||||
foreign_key["options"].get("ondelete") is None
|
||||
foreign_key.get("options", {}).get("ondelete") is None
|
||||
):
|
||||
alters.append(
|
||||
{
|
||||
@ -319,7 +319,7 @@ def _drop_foreign_key_constraints(connection, engine, table, columns):
|
||||
for foreign_key in inspector.get_foreign_keys(table):
|
||||
if (
|
||||
foreign_key["name"]
|
||||
and foreign_key["options"].get("ondelete")
|
||||
and foreign_key.get("options", {}).get("ondelete")
|
||||
and foreign_key["constrained_columns"] == columns
|
||||
):
|
||||
drops.append(ForeignKeyConstraint((), (), name=foreign_key["name"]))
|
||||
|
@ -112,6 +112,7 @@ class SamsungTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
async def _async_set_unique_id_from_udn(self, raise_on_progress=True):
|
||||
"""Set the unique id from the udn."""
|
||||
assert self._host is not None
|
||||
await self.async_set_unique_id(self._udn, raise_on_progress=raise_on_progress)
|
||||
self._async_update_existing_host_entry(self._host)
|
||||
updates = {CONF_HOST: self._host}
|
||||
@ -206,30 +207,28 @@ class SamsungTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
return entry
|
||||
return None
|
||||
|
||||
async def _async_start_discovery_for_host(self, host):
|
||||
"""Start discovery for a host."""
|
||||
if entry := self._async_update_existing_host_entry(host):
|
||||
async def _async_start_discovery(self):
|
||||
"""Start discovery."""
|
||||
assert self._host is not None
|
||||
if entry := self._async_update_existing_host_entry(self._host):
|
||||
if entry.unique_id:
|
||||
# Let the flow continue to fill the missing
|
||||
# unique id as we may be able to obtain it
|
||||
# in the next step
|
||||
raise data_entry_flow.AbortFlow("already_configured")
|
||||
|
||||
self.context[CONF_HOST] = host
|
||||
self.context[CONF_HOST] = self._host
|
||||
for progress in self._async_in_progress():
|
||||
if progress.get("context", {}).get(CONF_HOST) == host:
|
||||
if progress.get("context", {}).get(CONF_HOST) == self._host:
|
||||
raise data_entry_flow.AbortFlow("already_in_progress")
|
||||
|
||||
self._host = host
|
||||
|
||||
async def async_step_ssdp(self, discovery_info: DiscoveryInfoType):
|
||||
"""Handle a flow initialized by ssdp discovery."""
|
||||
LOGGER.debug("Samsung device found via SSDP: %s", discovery_info)
|
||||
self._udn = _strip_uuid(discovery_info[ATTR_UPNP_UDN])
|
||||
self._host = urlparse(discovery_info[ATTR_SSDP_LOCATION]).hostname
|
||||
await self._async_set_unique_id_from_udn()
|
||||
await self._async_start_discovery_for_host(
|
||||
urlparse(discovery_info[ATTR_SSDP_LOCATION]).hostname
|
||||
)
|
||||
await self._async_start_discovery()
|
||||
self._manufacturer = discovery_info[ATTR_UPNP_MANUFACTURER]
|
||||
if not self._manufacturer or not self._manufacturer.lower().startswith(
|
||||
"samsung"
|
||||
@ -245,7 +244,8 @@ class SamsungTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a flow initialized by dhcp discovery."""
|
||||
LOGGER.debug("Samsung device found via DHCP: %s", discovery_info)
|
||||
self._mac = discovery_info[MAC_ADDRESS]
|
||||
await self._async_start_discovery_for_host(discovery_info[IP_ADDRESS])
|
||||
self._host = discovery_info[IP_ADDRESS]
|
||||
await self._async_start_discovery()
|
||||
await self._async_set_device_unique_id()
|
||||
self.context["title_placeholders"] = {"device": self._title}
|
||||
return await self.async_step_confirm()
|
||||
@ -254,7 +254,8 @@ class SamsungTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a flow initialized by zeroconf discovery."""
|
||||
LOGGER.debug("Samsung device found via ZEROCONF: %s", discovery_info)
|
||||
self._mac = format_mac(discovery_info[ATTR_PROPERTIES]["deviceid"])
|
||||
await self._async_start_discovery_for_host(discovery_info[CONF_HOST])
|
||||
self._host = discovery_info[CONF_HOST]
|
||||
await self._async_start_discovery()
|
||||
await self._async_set_device_unique_id()
|
||||
self.context["title_placeholders"] = {"device": self._title}
|
||||
return await self.async_step_confirm()
|
||||
|
@ -764,7 +764,7 @@ class SonosSpeaker:
|
||||
"""Pause all current coordinators and restore groups."""
|
||||
for speaker in (s for s in speakers if s.is_coordinator):
|
||||
if speaker.media.playback_status == SONOS_STATE_PLAYING:
|
||||
hass.async_create_task(speaker.soco.pause())
|
||||
speaker.soco.pause()
|
||||
|
||||
groups = []
|
||||
|
||||
|
@ -45,6 +45,7 @@ SIGNAL_UPDATE_ENTITY = "tibber_rt_update_{}"
|
||||
RT_SENSOR_MAP = {
|
||||
"averagePower": ["average power", DEVICE_CLASS_POWER, POWER_WATT, None],
|
||||
"power": ["power", DEVICE_CLASS_POWER, POWER_WATT, None],
|
||||
"powerProduction": ["power production", DEVICE_CLASS_POWER, POWER_WATT, None],
|
||||
"minPower": ["min power", DEVICE_CLASS_POWER, POWER_WATT, None],
|
||||
"maxPower": ["max power", DEVICE_CLASS_POWER, POWER_WATT, None],
|
||||
"accumulatedConsumption": [
|
||||
|
@ -156,6 +156,26 @@ class TodSensor(BinarySensorEntity):
|
||||
self._time_after += self._after_offset
|
||||
self._time_before += self._before_offset
|
||||
|
||||
def _turn_to_next_day(self):
|
||||
"""Turn to to the next day."""
|
||||
if is_sun_event(self._after):
|
||||
self._time_after = get_astral_event_next(
|
||||
self.hass, self._after, self._time_after - self._after_offset
|
||||
)
|
||||
self._time_after += self._after_offset
|
||||
else:
|
||||
# Offset is already there
|
||||
self._time_after += timedelta(days=1)
|
||||
|
||||
if is_sun_event(self._before):
|
||||
self._time_before = get_astral_event_next(
|
||||
self.hass, self._before, self._time_before - self._before_offset
|
||||
)
|
||||
self._time_before += self._before_offset
|
||||
else:
|
||||
# Offset is already there
|
||||
self._time_before += timedelta(days=1)
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity about to be added to Home Assistant."""
|
||||
self._calculate_boudary_time()
|
||||
@ -182,7 +202,7 @@ class TodSensor(BinarySensorEntity):
|
||||
if now < self._time_before:
|
||||
self._next_update = self._time_before
|
||||
return
|
||||
self._calculate_boudary_time()
|
||||
self._turn_to_next_day()
|
||||
self._next_update = self._time_after
|
||||
|
||||
@callback
|
||||
|
@ -5,7 +5,7 @@ from typing import Final
|
||||
|
||||
MAJOR_VERSION: Final = 2021
|
||||
MINOR_VERSION: Final = 6
|
||||
PATCH_VERSION: Final = "2"
|
||||
PATCH_VERSION: Final = "3"
|
||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 8, 0)
|
||||
|
@ -224,7 +224,7 @@ aiopvpc==2.1.2
|
||||
aiopylgtv==0.4.0
|
||||
|
||||
# homeassistant.components.recollect_waste
|
||||
aiorecollect==1.0.4
|
||||
aiorecollect==1.0.5
|
||||
|
||||
# homeassistant.components.shelly
|
||||
aioshelly==0.6.4
|
||||
@ -515,7 +515,7 @@ dovado==0.4.1
|
||||
dsmr_parser==0.29
|
||||
|
||||
# homeassistant.components.dwd_weather_warnings
|
||||
dwdwfsapi==1.0.3
|
||||
dwdwfsapi==1.0.4
|
||||
|
||||
# homeassistant.components.dweet
|
||||
dweepy==0.3.0
|
||||
@ -635,7 +635,7 @@ gTTS==2.2.2
|
||||
garages-amsterdam==2.1.1
|
||||
|
||||
# homeassistant.components.garmin_connect
|
||||
garminconnect_aio==0.1.1
|
||||
garminconnect_aio==0.1.4
|
||||
|
||||
# homeassistant.components.geniushub
|
||||
geniushub-client==0.6.30
|
||||
@ -1464,7 +1464,7 @@ pyhomematic==0.1.72
|
||||
pyhomeworks==0.0.6
|
||||
|
||||
# homeassistant.components.ialarm
|
||||
pyialarm==1.7
|
||||
pyialarm==1.8.1
|
||||
|
||||
# homeassistant.components.icloud
|
||||
pyicloud==0.10.2
|
||||
|
@ -146,7 +146,7 @@ aiopvpc==2.1.2
|
||||
aiopylgtv==0.4.0
|
||||
|
||||
# homeassistant.components.recollect_waste
|
||||
aiorecollect==1.0.4
|
||||
aiorecollect==1.0.5
|
||||
|
||||
# homeassistant.components.shelly
|
||||
aioshelly==0.6.4
|
||||
@ -341,7 +341,7 @@ gTTS==2.2.2
|
||||
garages-amsterdam==2.1.1
|
||||
|
||||
# homeassistant.components.garmin_connect
|
||||
garminconnect_aio==0.1.1
|
||||
garminconnect_aio==0.1.4
|
||||
|
||||
# homeassistant.components.geo_json_events
|
||||
# homeassistant.components.usgs_earthquakes_feed
|
||||
@ -808,7 +808,7 @@ pyhiveapi==0.4.2
|
||||
pyhomematic==0.1.72
|
||||
|
||||
# homeassistant.components.ialarm
|
||||
pyialarm==1.7
|
||||
pyialarm==1.8.1
|
||||
|
||||
# homeassistant.components.icloud
|
||||
pyicloud==0.10.2
|
||||
|
@ -1,4 +1,6 @@
|
||||
"""The tests for the geolocation trigger."""
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components import automation, zone
|
||||
@ -318,3 +320,46 @@ async def test_if_fires_on_zone_disappear(hass, calls):
|
||||
assert (
|
||||
calls[0].data["some"] == "geo_location - geo_location.entity - hello - - test"
|
||||
)
|
||||
|
||||
|
||||
async def test_zone_undefined(hass, calls, caplog):
|
||||
"""Test for undefined zone."""
|
||||
hass.states.async_set(
|
||||
"geo_location.entity",
|
||||
"hello",
|
||||
{"latitude": 32.880586, "longitude": -117.237564, "source": "test_source"},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
caplog.set_level(logging.WARNING)
|
||||
|
||||
zone_does_not_exist = "zone.does_not_exist"
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
automation.DOMAIN,
|
||||
{
|
||||
automation.DOMAIN: {
|
||||
"trigger": {
|
||||
"platform": "geo_location",
|
||||
"source": "test_source",
|
||||
"zone": zone_does_not_exist,
|
||||
"event": "leave",
|
||||
},
|
||||
"action": {"service": "test.automation"},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
hass.states.async_set(
|
||||
"geo_location.entity",
|
||||
"hello",
|
||||
{"latitude": 32.881011, "longitude": -117.234758, "source": "test_source"},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 0
|
||||
|
||||
assert (
|
||||
f"Unable to execute automation automation 0: Zone {zone_does_not_exist} not found"
|
||||
in caplog.text
|
||||
)
|
||||
|
@ -12,6 +12,8 @@ import homeassistant.util.dt as dt_util
|
||||
|
||||
from tests.common import assert_setup_component
|
||||
|
||||
ORIG_TIMEZONE = dt_util.DEFAULT_TIME_ZONE
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_legacy_time(legacy_patchable_time):
|
||||
@ -26,6 +28,13 @@ def setup_fixture(hass):
|
||||
hass.config.longitude = 18.98583
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def restore_timezone(hass):
|
||||
"""Make sure we change timezone."""
|
||||
yield
|
||||
dt_util.set_default_time_zone(ORIG_TIMEZONE)
|
||||
|
||||
|
||||
async def test_setup(hass):
|
||||
"""Test the setup."""
|
||||
config = {
|
||||
@ -863,6 +872,7 @@ async def test_sun_offset(hass):
|
||||
async def test_dst(hass):
|
||||
"""Test sun event with offset."""
|
||||
hass.config.time_zone = "CET"
|
||||
dt_util.set_default_time_zone(dt_util.get_time_zone("CET"))
|
||||
test_time = datetime(2019, 3, 30, 3, 0, 0, tzinfo=dt_util.UTC)
|
||||
config = {
|
||||
"binary_sensor": [
|
||||
@ -882,7 +892,210 @@ async def test_dst(hass):
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.attributes["after"] == "2019-03-30T03:30:00+01:00"
|
||||
assert state.attributes["before"] == "2019-03-30T03:40:00+01:00"
|
||||
assert state.attributes["next_update"] == "2019-03-30T03:30:00+01:00"
|
||||
assert state.attributes["after"] == "2019-03-31T03:30:00+02:00"
|
||||
assert state.attributes["before"] == "2019-03-31T03:40:00+02:00"
|
||||
assert state.attributes["next_update"] == "2019-03-31T03:30:00+02:00"
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
|
||||
async def test_simple_before_after_does_not_loop_utc_not_in_range(hass):
|
||||
"""Test simple before after."""
|
||||
hass.config.time_zone = "UTC"
|
||||
dt_util.set_default_time_zone(dt_util.UTC)
|
||||
test_time = datetime(2019, 1, 10, 18, 43, 0, tzinfo=dt_util.UTC)
|
||||
config = {
|
||||
"binary_sensor": [
|
||||
{
|
||||
"platform": "tod",
|
||||
"name": "Night",
|
||||
"before": "06:00",
|
||||
"after": "22:00",
|
||||
}
|
||||
]
|
||||
}
|
||||
with patch(
|
||||
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
|
||||
return_value=test_time,
|
||||
):
|
||||
await async_setup_component(hass, "binary_sensor", config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("binary_sensor.night")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes["after"] == "2019-01-10T22:00:00+00:00"
|
||||
assert state.attributes["before"] == "2019-01-11T06:00:00+00:00"
|
||||
assert state.attributes["next_update"] == "2019-01-10T22:00:00+00:00"
|
||||
|
||||
|
||||
async def test_simple_before_after_does_not_loop_utc_in_range(hass):
|
||||
"""Test simple before after."""
|
||||
hass.config.time_zone = "UTC"
|
||||
dt_util.set_default_time_zone(dt_util.UTC)
|
||||
test_time = datetime(2019, 1, 10, 22, 43, 0, tzinfo=dt_util.UTC)
|
||||
config = {
|
||||
"binary_sensor": [
|
||||
{
|
||||
"platform": "tod",
|
||||
"name": "Night",
|
||||
"before": "06:00",
|
||||
"after": "22:00",
|
||||
}
|
||||
]
|
||||
}
|
||||
with patch(
|
||||
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
|
||||
return_value=test_time,
|
||||
):
|
||||
await async_setup_component(hass, "binary_sensor", config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("binary_sensor.night")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["after"] == "2019-01-10T22:00:00+00:00"
|
||||
assert state.attributes["before"] == "2019-01-11T06:00:00+00:00"
|
||||
assert state.attributes["next_update"] == "2019-01-11T06:00:00+00:00"
|
||||
|
||||
|
||||
async def test_simple_before_after_does_not_loop_utc_fire_at_before(hass):
|
||||
"""Test simple before after."""
|
||||
hass.config.time_zone = "UTC"
|
||||
dt_util.set_default_time_zone(dt_util.UTC)
|
||||
test_time = datetime(2019, 1, 11, 6, 0, 0, tzinfo=dt_util.UTC)
|
||||
config = {
|
||||
"binary_sensor": [
|
||||
{
|
||||
"platform": "tod",
|
||||
"name": "Night",
|
||||
"before": "06:00",
|
||||
"after": "22:00",
|
||||
}
|
||||
]
|
||||
}
|
||||
with patch(
|
||||
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
|
||||
return_value=test_time,
|
||||
):
|
||||
await async_setup_component(hass, "binary_sensor", config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("binary_sensor.night")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes["after"] == "2019-01-11T22:00:00+00:00"
|
||||
assert state.attributes["before"] == "2019-01-12T06:00:00+00:00"
|
||||
assert state.attributes["next_update"] == "2019-01-11T22:00:00+00:00"
|
||||
|
||||
|
||||
async def test_simple_before_after_does_not_loop_utc_fire_at_after(hass):
|
||||
"""Test simple before after."""
|
||||
hass.config.time_zone = "UTC"
|
||||
dt_util.set_default_time_zone(dt_util.UTC)
|
||||
test_time = datetime(2019, 1, 10, 22, 0, 0, tzinfo=dt_util.UTC)
|
||||
config = {
|
||||
"binary_sensor": [
|
||||
{
|
||||
"platform": "tod",
|
||||
"name": "Night",
|
||||
"before": "06:00",
|
||||
"after": "22:00",
|
||||
}
|
||||
]
|
||||
}
|
||||
with patch(
|
||||
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
|
||||
return_value=test_time,
|
||||
):
|
||||
await async_setup_component(hass, "binary_sensor", config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("binary_sensor.night")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["after"] == "2019-01-10T22:00:00+00:00"
|
||||
assert state.attributes["before"] == "2019-01-11T06:00:00+00:00"
|
||||
assert state.attributes["next_update"] == "2019-01-11T06:00:00+00:00"
|
||||
|
||||
|
||||
async def test_simple_before_after_does_not_loop_utc_both_before_now(hass):
|
||||
"""Test simple before after."""
|
||||
hass.config.time_zone = "UTC"
|
||||
dt_util.set_default_time_zone(dt_util.UTC)
|
||||
test_time = datetime(2019, 1, 10, 22, 0, 0, tzinfo=dt_util.UTC)
|
||||
config = {
|
||||
"binary_sensor": [
|
||||
{
|
||||
"platform": "tod",
|
||||
"name": "Morning",
|
||||
"before": "08:00",
|
||||
"after": "00:00",
|
||||
}
|
||||
]
|
||||
}
|
||||
with patch(
|
||||
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
|
||||
return_value=test_time,
|
||||
):
|
||||
await async_setup_component(hass, "binary_sensor", config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("binary_sensor.morning")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes["after"] == "2019-01-11T00:00:00+00:00"
|
||||
assert state.attributes["before"] == "2019-01-11T08:00:00+00:00"
|
||||
assert state.attributes["next_update"] == "2019-01-11T00:00:00+00:00"
|
||||
|
||||
|
||||
async def test_simple_before_after_does_not_loop_berlin_not_in_range(hass):
|
||||
"""Test simple before after."""
|
||||
hass.config.time_zone = "Europe/Berlin"
|
||||
dt_util.set_default_time_zone(dt_util.get_time_zone("Europe/Berlin"))
|
||||
test_time = datetime(2019, 1, 10, 18, 43, 0, tzinfo=dt_util.UTC)
|
||||
config = {
|
||||
"binary_sensor": [
|
||||
{
|
||||
"platform": "tod",
|
||||
"name": "Dark",
|
||||
"before": "06:00",
|
||||
"after": "00:00",
|
||||
}
|
||||
]
|
||||
}
|
||||
with patch(
|
||||
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
|
||||
return_value=test_time,
|
||||
):
|
||||
await async_setup_component(hass, "binary_sensor", config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("binary_sensor.dark")
|
||||
assert state.state == STATE_OFF
|
||||
assert state.attributes["after"] == "2019-01-11T00:00:00+01:00"
|
||||
assert state.attributes["before"] == "2019-01-11T06:00:00+01:00"
|
||||
assert state.attributes["next_update"] == "2019-01-11T00:00:00+01:00"
|
||||
|
||||
|
||||
async def test_simple_before_after_does_not_loop_berlin_in_range(hass):
|
||||
"""Test simple before after."""
|
||||
hass.config.time_zone = "Europe/Berlin"
|
||||
dt_util.set_default_time_zone(dt_util.get_time_zone("Europe/Berlin"))
|
||||
test_time = datetime(2019, 1, 10, 23, 43, 0, tzinfo=dt_util.UTC)
|
||||
config = {
|
||||
"binary_sensor": [
|
||||
{
|
||||
"platform": "tod",
|
||||
"name": "Dark",
|
||||
"before": "06:00",
|
||||
"after": "00:00",
|
||||
}
|
||||
]
|
||||
}
|
||||
with patch(
|
||||
"homeassistant.components.tod.binary_sensor.dt_util.utcnow",
|
||||
return_value=test_time,
|
||||
):
|
||||
await async_setup_component(hass, "binary_sensor", config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("binary_sensor.dark")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes["after"] == "2019-01-11T00:00:00+01:00"
|
||||
assert state.attributes["before"] == "2019-01-11T06:00:00+01:00"
|
||||
assert state.attributes["next_update"] == "2019-01-11T06:00:00+01:00"
|
||||
|
Loading…
x
Reference in New Issue
Block a user