mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
commit
a0403a8864
@ -8,8 +8,8 @@ import async_timeout
|
|||||||
import coronavirus
|
import coronavirus
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers import aiohttp_client, update_coordinator
|
from homeassistant.helpers import aiohttp_client, entity_registry, update_coordinator
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
|
|
||||||
@ -25,6 +25,26 @@ async def async_setup(hass: HomeAssistant, config: dict):
|
|||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||||
"""Set up Coronavirus from a config entry."""
|
"""Set up Coronavirus from a config entry."""
|
||||||
|
if isinstance(entry.data["country"], int):
|
||||||
|
hass.config_entries.async_update_entry(
|
||||||
|
entry, data={**entry.data, "country": entry.title}
|
||||||
|
)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _async_migrator(entity_entry: entity_registry.RegistryEntry):
|
||||||
|
"""Migrate away from unstable ID."""
|
||||||
|
country, info_type = entity_entry.unique_id.rsplit("-", 1)
|
||||||
|
if not country.isnumeric():
|
||||||
|
return None
|
||||||
|
return {"new_unique_id": f"{entry.title}-{info_type}"}
|
||||||
|
|
||||||
|
await entity_registry.async_migrate_entries(
|
||||||
|
hass, entry.entry_id, _async_migrator
|
||||||
|
)
|
||||||
|
|
||||||
|
if not entry.unique_id:
|
||||||
|
hass.config_entries.async_update_entry(entry, unique_id=entry.data["country"])
|
||||||
|
|
||||||
for component in PLATFORMS:
|
for component in PLATFORMS:
|
||||||
hass.async_create_task(
|
hass.async_create_task(
|
||||||
hass.config_entries.async_forward_entry_setup(entry, component)
|
hass.config_entries.async_forward_entry_setup(entry, component)
|
||||||
@ -56,7 +76,7 @@ async def get_coordinator(hass):
|
|||||||
try:
|
try:
|
||||||
with async_timeout.timeout(10):
|
with async_timeout.timeout(10):
|
||||||
return {
|
return {
|
||||||
case.id: case
|
case.country: case
|
||||||
for case in await coronavirus.get_cases(
|
for case in await coronavirus.get_cases(
|
||||||
aiohttp_client.async_get_clientsession(hass)
|
aiohttp_client.async_get_clientsession(hass)
|
||||||
)
|
)
|
||||||
|
@ -26,10 +26,14 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
if self._options is None:
|
if self._options is None:
|
||||||
self._options = {OPTION_WORLDWIDE: "Worldwide"}
|
self._options = {OPTION_WORLDWIDE: "Worldwide"}
|
||||||
coordinator = await get_coordinator(self.hass)
|
coordinator = await get_coordinator(self.hass)
|
||||||
for case_id in sorted(coordinator.data):
|
for case in sorted(
|
||||||
self._options[case_id] = coordinator.data[case_id].country
|
coordinator.data.values(), key=lambda case: case.country
|
||||||
|
):
|
||||||
|
self._options[case.country] = case.country
|
||||||
|
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
|
await self.async_set_unique_id(user_input["country"])
|
||||||
|
self._abort_if_unique_id_configured()
|
||||||
return self.async_create_entry(
|
return self.async_create_entry(
|
||||||
title=self._options[user_input["country"]], data=user_input
|
title=self._options[user_input["country"]], data=user_input
|
||||||
)
|
)
|
||||||
|
@ -25,9 +25,9 @@ class CoronavirusSensor(Entity):
|
|||||||
def __init__(self, coordinator, country, info_type):
|
def __init__(self, coordinator, country, info_type):
|
||||||
"""Initialize coronavirus sensor."""
|
"""Initialize coronavirus sensor."""
|
||||||
if country == OPTION_WORLDWIDE:
|
if country == OPTION_WORLDWIDE:
|
||||||
self.name = f"Worldwide {info_type}"
|
self.name = f"Worldwide Coronavirus {info_type}"
|
||||||
else:
|
else:
|
||||||
self.name = f"{coordinator.data[country].country} {info_type}"
|
self.name = f"{coordinator.data[country].country} Coronavirus {info_type}"
|
||||||
self.unique_id = f"{country}-{info_type}"
|
self.unique_id = f"{country}-{info_type}"
|
||||||
self.coordinator = coordinator
|
self.coordinator = coordinator
|
||||||
self.country = country
|
self.country = country
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
"country": "Country"
|
"country": "Country"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "This country is already configured."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"domain": "eight_sleep",
|
"domain": "eight_sleep",
|
||||||
"name": "Eight Sleep",
|
"name": "Eight Sleep",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/eight_sleep",
|
"documentation": "https://www.home-assistant.io/integrations/eight_sleep",
|
||||||
"requirements": ["pyeight==0.1.3"],
|
"requirements": ["pyeight==0.1.4"],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"codeowners": ["@mezz64"]
|
"codeowners": ["@mezz64"]
|
||||||
}
|
}
|
||||||
|
@ -261,14 +261,26 @@ class EightUserSensor(EightSleepUserEntity):
|
|||||||
bed_temp = None
|
bed_temp = None
|
||||||
|
|
||||||
if "current" in self._sensor_root:
|
if "current" in self._sensor_root:
|
||||||
state_attr[ATTR_RESP_RATE] = round(self._attr["resp_rate"], 2)
|
try:
|
||||||
state_attr[ATTR_HEART_RATE] = round(self._attr["heart_rate"], 2)
|
state_attr[ATTR_RESP_RATE] = round(self._attr["resp_rate"], 2)
|
||||||
|
except TypeError:
|
||||||
|
state_attr[ATTR_RESP_RATE] = None
|
||||||
|
try:
|
||||||
|
state_attr[ATTR_HEART_RATE] = round(self._attr["heart_rate"], 2)
|
||||||
|
except TypeError:
|
||||||
|
state_attr[ATTR_HEART_RATE] = None
|
||||||
state_attr[ATTR_SLEEP_STAGE] = self._attr["stage"]
|
state_attr[ATTR_SLEEP_STAGE] = self._attr["stage"]
|
||||||
state_attr[ATTR_ROOM_TEMP] = room_temp
|
state_attr[ATTR_ROOM_TEMP] = room_temp
|
||||||
state_attr[ATTR_BED_TEMP] = bed_temp
|
state_attr[ATTR_BED_TEMP] = bed_temp
|
||||||
elif "last" in self._sensor_root:
|
elif "last" in self._sensor_root:
|
||||||
state_attr[ATTR_AVG_RESP_RATE] = round(self._attr["resp_rate"], 2)
|
try:
|
||||||
state_attr[ATTR_AVG_HEART_RATE] = round(self._attr["heart_rate"], 2)
|
state_attr[ATTR_AVG_RESP_RATE] = round(self._attr["resp_rate"], 2)
|
||||||
|
except TypeError:
|
||||||
|
state_attr[ATTR_AVG_RESP_RATE] = None
|
||||||
|
try:
|
||||||
|
state_attr[ATTR_AVG_HEART_RATE] = round(self._attr["heart_rate"], 2)
|
||||||
|
except TypeError:
|
||||||
|
state_attr[ATTR_AVG_HEART_RATE] = None
|
||||||
state_attr[ATTR_AVG_ROOM_TEMP] = room_temp
|
state_attr[ATTR_AVG_ROOM_TEMP] = room_temp
|
||||||
state_attr[ATTR_AVG_BED_TEMP] = bed_temp
|
state_attr[ATTR_AVG_BED_TEMP] = bed_temp
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry)
|
|||||||
await server.async_update()
|
await server.async_update()
|
||||||
server.start_periodic_update()
|
server.start_periodic_update()
|
||||||
|
|
||||||
# Set up platform(s).
|
# Set up platforms.
|
||||||
for platform in PLATFORMS:
|
for platform in PLATFORMS:
|
||||||
hass.async_create_task(
|
hass.async_create_task(
|
||||||
hass.config_entries.async_forward_entry_setup(config_entry, platform)
|
hass.config_entries.async_forward_entry_setup(config_entry, platform)
|
||||||
@ -103,7 +103,6 @@ class MinecraftServer:
|
|||||||
self._mc_status = MCStatus(self.host, self.port)
|
self._mc_status = MCStatus(self.host, self.port)
|
||||||
|
|
||||||
# Data provided by 3rd party library
|
# Data provided by 3rd party library
|
||||||
self.description = None
|
|
||||||
self.version = None
|
self.version = None
|
||||||
self.protocol_version = None
|
self.protocol_version = None
|
||||||
self.latency_time = None
|
self.latency_time = None
|
||||||
@ -168,7 +167,6 @@ class MinecraftServer:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Got answer to request, update properties.
|
# Got answer to request, update properties.
|
||||||
self.description = status_response.description["text"]
|
|
||||||
self.version = status_response.version.name
|
self.version = status_response.version.name
|
||||||
self.protocol_version = status_response.version.protocol
|
self.protocol_version = status_response.version.protocol
|
||||||
self.players_online = status_response.players.online
|
self.players_online = status_response.players.online
|
||||||
@ -185,7 +183,6 @@ class MinecraftServer:
|
|||||||
self._last_status_request_failed = False
|
self._last_status_request_failed = False
|
||||||
except OSError as error:
|
except OSError as error:
|
||||||
# No answer to request, set all properties to unknown.
|
# No answer to request, set all properties to unknown.
|
||||||
self.description = None
|
|
||||||
self.version = None
|
self.version = None
|
||||||
self.protocol_version = None
|
self.protocol_version = None
|
||||||
self.players_online = None
|
self.players_online = None
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Constants used by Home Assistant components."""
|
"""Constants used by Home Assistant components."""
|
||||||
MAJOR_VERSION = 0
|
MAJOR_VERSION = 0
|
||||||
MINOR_VERSION = 106
|
MINOR_VERSION = 106
|
||||||
PATCH_VERSION = "3"
|
PATCH_VERSION = "4"
|
||||||
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||||
__version__ = f"{__short_version__}.{PATCH_VERSION}"
|
__version__ = f"{__short_version__}.{PATCH_VERSION}"
|
||||||
REQUIRED_PYTHON_VER = (3, 7, 0)
|
REQUIRED_PYTHON_VER = (3, 7, 0)
|
||||||
|
@ -11,7 +11,7 @@ import asyncio
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, cast
|
from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional, cast
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
|
|
||||||
@ -560,3 +560,21 @@ def async_setup_entity_restore(
|
|||||||
states.async_set(entry.entity_id, STATE_UNAVAILABLE, attrs)
|
states.async_set(entry.entity_id, STATE_UNAVAILABLE, attrs)
|
||||||
|
|
||||||
hass.bus.async_listen(EVENT_HOMEASSISTANT_START, _write_unavailable_states)
|
hass.bus.async_listen(EVENT_HOMEASSISTANT_START, _write_unavailable_states)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_migrate_entries(
|
||||||
|
hass: HomeAssistantType,
|
||||||
|
config_entry_id: str,
|
||||||
|
entry_callback: Callable[[RegistryEntry], Optional[dict]],
|
||||||
|
) -> None:
|
||||||
|
"""Migrator of unique IDs."""
|
||||||
|
ent_reg = await async_get_registry(hass)
|
||||||
|
|
||||||
|
for entry in ent_reg.entities.values():
|
||||||
|
if entry.config_entry_id != config_entry_id:
|
||||||
|
continue
|
||||||
|
|
||||||
|
updates = entry_callback(entry)
|
||||||
|
|
||||||
|
if updates is not None:
|
||||||
|
ent_reg.async_update_entity(entry.entity_id, **updates) # type: ignore
|
||||||
|
@ -1226,7 +1226,7 @@ pyeconet==0.0.11
|
|||||||
pyedimax==0.2.1
|
pyedimax==0.2.1
|
||||||
|
|
||||||
# homeassistant.components.eight_sleep
|
# homeassistant.components.eight_sleep
|
||||||
pyeight==0.1.3
|
pyeight==0.1.4
|
||||||
|
|
||||||
# homeassistant.components.emby
|
# homeassistant.components.emby
|
||||||
pyemby==1.6
|
pyemby==1.6
|
||||||
|
@ -22,9 +22,9 @@ async def test_form(hass):
|
|||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], {"country": OPTION_WORLDWIDE},
|
result["flow_id"], {"country": OPTION_WORLDWIDE},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result2["type"] == "create_entry"
|
assert result2["type"] == "create_entry"
|
||||||
assert result2["title"] == "Worldwide"
|
assert result2["title"] == "Worldwide"
|
||||||
|
assert result2["result"].unique_id == OPTION_WORLDWIDE
|
||||||
assert result2["data"] == {
|
assert result2["data"] == {
|
||||||
"country": OPTION_WORLDWIDE,
|
"country": OPTION_WORLDWIDE,
|
||||||
}
|
}
|
||||||
|
58
tests/components/coronavirus/test_init.py
Normal file
58
tests/components/coronavirus/test_init.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
"""Test init of Coronavirus integration."""
|
||||||
|
from asynctest import Mock, patch
|
||||||
|
|
||||||
|
from homeassistant.components.coronavirus.const import DOMAIN, OPTION_WORLDWIDE
|
||||||
|
from homeassistant.helpers import entity_registry
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry, mock_registry
|
||||||
|
|
||||||
|
|
||||||
|
async def test_migration(hass):
|
||||||
|
"""Test that we can migrate coronavirus to stable unique ID."""
|
||||||
|
nl_entry = MockConfigEntry(domain=DOMAIN, title="Netherlands", data={"country": 34})
|
||||||
|
nl_entry.add_to_hass(hass)
|
||||||
|
worldwide_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN, title="Worldwide", data={"country": OPTION_WORLDWIDE}
|
||||||
|
)
|
||||||
|
worldwide_entry.add_to_hass(hass)
|
||||||
|
mock_registry(
|
||||||
|
hass,
|
||||||
|
{
|
||||||
|
"sensor.netherlands_confirmed": entity_registry.RegistryEntry(
|
||||||
|
entity_id="sensor.netherlands_confirmed",
|
||||||
|
unique_id="34-confirmed",
|
||||||
|
platform="coronavirus",
|
||||||
|
config_entry_id=nl_entry.entry_id,
|
||||||
|
),
|
||||||
|
"sensor.worldwide_confirmed": entity_registry.RegistryEntry(
|
||||||
|
entity_id="sensor.worldwide_confirmed",
|
||||||
|
unique_id="__worldwide-confirmed",
|
||||||
|
platform="coronavirus",
|
||||||
|
config_entry_id=worldwide_entry.entry_id,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
with patch(
|
||||||
|
"coronavirus.get_cases",
|
||||||
|
return_value=[
|
||||||
|
Mock(country="Netherlands", confirmed=10, recovered=8, deaths=1, current=1),
|
||||||
|
Mock(country="Germany", confirmed=1, recovered=0, deaths=0, current=0),
|
||||||
|
],
|
||||||
|
):
|
||||||
|
assert await async_setup_component(hass, DOMAIN, {})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
ent_reg = await entity_registry.async_get_registry(hass)
|
||||||
|
|
||||||
|
sensor_nl = ent_reg.async_get("sensor.netherlands_confirmed")
|
||||||
|
assert sensor_nl.unique_id == "Netherlands-confirmed"
|
||||||
|
|
||||||
|
sensor_worldwide = ent_reg.async_get("sensor.worldwide_confirmed")
|
||||||
|
assert sensor_worldwide.unique_id == "__worldwide-confirmed"
|
||||||
|
|
||||||
|
assert hass.states.get("sensor.netherlands_confirmed").state == "10"
|
||||||
|
assert hass.states.get("sensor.worldwide_confirmed").state == "11"
|
||||||
|
|
||||||
|
assert nl_entry.unique_id == "Netherlands"
|
||||||
|
assert worldwide_entry.unique_id == OPTION_WORLDWIDE
|
Loading…
x
Reference in New Issue
Block a user