Netatmo entity renaming and clean up (#75337)

This commit is contained in:
Tobias Sauerwein 2022-07-27 14:17:38 +02:00 committed by GitHub
parent 314778cb50
commit 49854b809c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 128 additions and 144 deletions

View file

@ -112,6 +112,8 @@ async def async_setup_entry(
class NetatmoCamera(NetatmoBase, Camera):
"""Representation of a Netatmo camera."""
_attr_brand = MANUFACTURER
_attr_has_entity_name = True
_attr_supported_features = CameraEntityFeature.STREAM
def __init__(
@ -126,14 +128,13 @@ class NetatmoCamera(NetatmoBase, Camera):
Camera.__init__(self)
super().__init__(data_handler)
self._data_classes.append(
self._publishers.append(
{"name": CAMERA_DATA_CLASS_NAME, SIGNAL_NAME: CAMERA_DATA_CLASS_NAME}
)
self._id = camera_id
self._home_id = home_id
self._device_name = self._data.get_camera(camera_id=camera_id)["name"]
self._attr_name = f"{MANUFACTURER} {self._device_name}"
self._model = camera_type
self._netatmo_type = TYPE_SECURITY
self._attr_unique_id = f"{self._id}-{self._model}"
@ -193,7 +194,7 @@ class NetatmoCamera(NetatmoBase, Camera):
"""Return data for this entity."""
return cast(
pyatmo.AsyncCameraData,
self.data_handler.data[self._data_classes[0]["name"]],
self.data_handler.data[self._publishers[0]["name"]],
)
async def async_camera_image(
@ -219,11 +220,6 @@ class NetatmoCamera(NetatmoBase, Camera):
"""Return True if entity is available."""
return bool(self._alim_status == "on" or self._status == "disconnected")
@property
def brand(self) -> str:
"""Return the camera brand."""
return MANUFACTURER
@property
def motion_detection_enabled(self) -> bool:
"""Return the camera motion detection status."""

View file

@ -127,7 +127,7 @@ async def async_setup_entry(
for home_id in climate_topology.home_ids:
signal_name = f"{CLIMATE_STATE_CLASS_NAME}-{home_id}"
await data_handler.register_data_class(
await data_handler.subscribe(
CLIMATE_STATE_CLASS_NAME, signal_name, None, home_id=home_id
)
@ -185,14 +185,10 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
self._room = room
self._id = self._room.entity_id
self._climate_state_class = (
f"{CLIMATE_STATE_CLASS_NAME}-{self._room.home.entity_id}"
)
self._climate_state: pyatmo.AsyncClimate = data_handler.data[
self._climate_state_class
]
self._signal_name = f"{CLIMATE_STATE_CLASS_NAME}-{self._room.home.entity_id}"
self._climate_state: pyatmo.AsyncClimate = data_handler.data[self._signal_name]
self._data_classes.extend(
self._publishers.extend(
[
{
"name": CLIMATE_TOPOLOGY_CLASS_NAME,
@ -201,7 +197,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
{
"name": CLIMATE_STATE_CLASS_NAME,
"home_id": self._room.home.entity_id,
SIGNAL_NAME: self._climate_state_class,
SIGNAL_NAME: self._signal_name,
},
]
)
@ -254,7 +250,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
self.data_handler,
module,
self._id,
self._climate_state_class,
self._signal_name,
),
)
@ -278,7 +274,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
ATTR_SELECTED_SCHEDULE
] = self._selected_schedule
self.async_write_ha_state()
self.data_handler.async_force_update(self._climate_state_class)
self.data_handler.async_force_update(self._signal_name)
return
home = data["home"]
@ -295,7 +291,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
self._attr_target_temperature = self._away_temperature
elif self._attr_preset_mode == PRESET_SCHEDULE:
self.async_update_callback()
self.data_handler.async_force_update(self._climate_state_class)
self.data_handler.async_force_update(self._signal_name)
self.async_write_ha_state()
return

View file

@ -73,16 +73,16 @@ DATA_HANDLER = "netatmo_data_handler"
SIGNAL_NAME = "signal_name"
NETATMO_CREATE_BATTERY = "netatmo_create_battery"
CONF_CLOUDHOOK_URL = "cloudhook_url"
CONF_WEATHER_AREAS = "weather_areas"
CONF_NEW_AREA = "new_area"
CONF_AREA_NAME = "area_name"
CONF_CLOUDHOOK_URL = "cloudhook_url"
CONF_LAT_NE = "lat_ne"
CONF_LON_NE = "lon_ne"
CONF_LAT_SW = "lat_sw"
CONF_LON_NE = "lon_ne"
CONF_LON_SW = "lon_sw"
CONF_NEW_AREA = "new_area"
CONF_PUBLIC_MODE = "mode"
CONF_UUID = "uuid"
CONF_WEATHER_AREAS = "weather_areas"
OAUTH2_AUTHORIZE = "https://api.netatmo.com/oauth2/authorize"
OAUTH2_TOKEN = "https://api.netatmo.com/oauth2/token"
@ -94,53 +94,53 @@ DATA_HOMES = "netatmo_homes"
DATA_PERSONS = "netatmo_persons"
DATA_SCHEDULES = "netatmo_schedules"
NETATMO_WEBHOOK_URL = None
NETATMO_EVENT = "netatmo_event"
NETATMO_WEBHOOK_URL = None
DEFAULT_PERSON = "unknown"
DEFAULT_DISCOVERY = True
DEFAULT_PERSON = "unknown"
DEFAULT_WEBHOOKS = False
ATTR_PSEUDO = "pseudo"
ATTR_CAMERA_LIGHT_MODE = "camera_light_mode"
ATTR_EVENT_TYPE = "event_type"
ATTR_FACE_URL = "face_url"
ATTR_HEATING_POWER_REQUEST = "heating_power_request"
ATTR_HOME_ID = "home_id"
ATTR_HOME_NAME = "home_name"
ATTR_IS_KNOWN = "is_known"
ATTR_PERSON = "person"
ATTR_PERSONS = "persons"
ATTR_IS_KNOWN = "is_known"
ATTR_FACE_URL = "face_url"
ATTR_PSEUDO = "pseudo"
ATTR_SCHEDULE_ID = "schedule_id"
ATTR_SCHEDULE_NAME = "schedule_name"
ATTR_SELECTED_SCHEDULE = "selected_schedule"
ATTR_CAMERA_LIGHT_MODE = "camera_light_mode"
SERVICE_SET_CAMERA_LIGHT = "set_camera_light"
SERVICE_SET_SCHEDULE = "set_schedule"
SERVICE_SET_PERSONS_HOME = "set_persons_home"
SERVICE_SET_PERSON_AWAY = "set_person_away"
SERVICE_SET_PERSONS_HOME = "set_persons_home"
SERVICE_SET_SCHEDULE = "set_schedule"
# Climate events
EVENT_TYPE_SET_POINT = "set_point"
EVENT_TYPE_CANCEL_SET_POINT = "cancel_set_point"
EVENT_TYPE_THERM_MODE = "therm_mode"
EVENT_TYPE_SCHEDULE = "schedule"
EVENT_TYPE_SET_POINT = "set_point"
EVENT_TYPE_THERM_MODE = "therm_mode"
# Camera events
EVENT_TYPE_LIGHT_MODE = "light_mode"
EVENT_TYPE_CAMERA_OUTDOOR = "outdoor"
EVENT_TYPE_CAMERA_ANIMAL = "animal"
EVENT_TYPE_CAMERA_HUMAN = "human"
EVENT_TYPE_CAMERA_VEHICLE = "vehicle"
EVENT_TYPE_CAMERA_MOVEMENT = "movement"
EVENT_TYPE_CAMERA_OUTDOOR = "outdoor"
EVENT_TYPE_CAMERA_PERSON = "person"
EVENT_TYPE_CAMERA_PERSON_AWAY = "person_away"
EVENT_TYPE_CAMERA_VEHICLE = "vehicle"
EVENT_TYPE_LIGHT_MODE = "light_mode"
# Door tags
EVENT_TYPE_DOOR_TAG_SMALL_MOVE = "tag_small_move"
EVENT_TYPE_ALARM_STARTED = "alarm_started"
EVENT_TYPE_DOOR_TAG_BIG_MOVE = "tag_big_move"
EVENT_TYPE_DOOR_TAG_OPEN = "tag_open"
EVENT_TYPE_DOOR_TAG_SMALL_MOVE = "tag_small_move"
EVENT_TYPE_OFF = "off"
EVENT_TYPE_ON = "on"
EVENT_TYPE_ALARM_STARTED = "alarm_started"
OUTDOOR_CAMERA_TRIGGERS = [
EVENT_TYPE_CAMERA_ANIMAL,
@ -149,46 +149,46 @@ OUTDOOR_CAMERA_TRIGGERS = [
EVENT_TYPE_CAMERA_VEHICLE,
]
INDOOR_CAMERA_TRIGGERS = [
EVENT_TYPE_CAMERA_MOVEMENT,
EVENT_TYPE_CAMERA_PERSON,
EVENT_TYPE_CAMERA_PERSON_AWAY,
EVENT_TYPE_ALARM_STARTED,
EVENT_TYPE_CAMERA_MOVEMENT,
EVENT_TYPE_CAMERA_PERSON_AWAY,
EVENT_TYPE_CAMERA_PERSON,
]
DOOR_TAG_TRIGGERS = [
EVENT_TYPE_DOOR_TAG_SMALL_MOVE,
EVENT_TYPE_DOOR_TAG_BIG_MOVE,
EVENT_TYPE_DOOR_TAG_OPEN,
EVENT_TYPE_DOOR_TAG_SMALL_MOVE,
]
CLIMATE_TRIGGERS = [
EVENT_TYPE_SET_POINT,
EVENT_TYPE_CANCEL_SET_POINT,
EVENT_TYPE_SET_POINT,
EVENT_TYPE_THERM_MODE,
]
EVENT_ID_MAP = {
EVENT_TYPE_CAMERA_MOVEMENT: "device_id",
EVENT_TYPE_CAMERA_PERSON: "device_id",
EVENT_TYPE_CAMERA_PERSON_AWAY: "device_id",
EVENT_TYPE_ALARM_STARTED: "device_id",
EVENT_TYPE_CAMERA_ANIMAL: "device_id",
EVENT_TYPE_CAMERA_HUMAN: "device_id",
EVENT_TYPE_CAMERA_MOVEMENT: "device_id",
EVENT_TYPE_CAMERA_OUTDOOR: "device_id",
EVENT_TYPE_CAMERA_PERSON_AWAY: "device_id",
EVENT_TYPE_CAMERA_PERSON: "device_id",
EVENT_TYPE_CAMERA_VEHICLE: "device_id",
EVENT_TYPE_DOOR_TAG_SMALL_MOVE: "device_id",
EVENT_TYPE_CANCEL_SET_POINT: "room_id",
EVENT_TYPE_DOOR_TAG_BIG_MOVE: "device_id",
EVENT_TYPE_DOOR_TAG_OPEN: "device_id",
EVENT_TYPE_DOOR_TAG_SMALL_MOVE: "device_id",
EVENT_TYPE_LIGHT_MODE: "device_id",
EVENT_TYPE_ALARM_STARTED: "device_id",
EVENT_TYPE_CANCEL_SET_POINT: "room_id",
EVENT_TYPE_SET_POINT: "room_id",
EVENT_TYPE_THERM_MODE: "home_id",
}
MODE_LIGHT_ON = "on"
MODE_LIGHT_OFF = "off"
MODE_LIGHT_AUTO = "auto"
MODE_LIGHT_OFF = "off"
MODE_LIGHT_ON = "on"
CAMERA_LIGHT_MODES = [MODE_LIGHT_ON, MODE_LIGHT_OFF, MODE_LIGHT_AUTO]
WEBHOOK_ACTIVATION = "webhook_activation"
WEBHOOK_DEACTIVATION = "webhook_deactivation"
WEBHOOK_LIGHT_MODE = "NOC-light_mode"
WEBHOOK_NACAMERA_CONNECTION = "NACamera-connection"
WEBHOOK_PUSH_TYPE = "push_type"
WEBHOOK_LIGHT_MODE = "NOC-light_mode"

View file

@ -64,11 +64,11 @@ class NetatmoDevice:
data_handler: NetatmoDataHandler
device: pyatmo.climate.NetatmoModule
parent_id: str
state_class_name: str
signal_name: str
@dataclass
class NetatmoDataClass:
class NetatmoPublisher:
"""Class for keeping track of Netatmo data class metadata."""
name: str
@ -85,7 +85,7 @@ class NetatmoDataHandler:
self.hass = hass
self.config_entry = config_entry
self._auth = hass.data[DOMAIN][config_entry.entry_id][AUTH]
self.data_classes: dict = {}
self.publisher: dict[str, NetatmoPublisher] = {}
self.data: dict = {}
self._queue: deque = deque()
self._webhook: bool = False
@ -107,7 +107,7 @@ class NetatmoDataHandler:
await asyncio.gather(
*[
self.register_data_class(data_class, data_class, None)
self.subscribe(data_class, data_class, None)
for data_class in (
CLIMATE_TOPOLOGY_CLASS_NAME,
CAMERA_DATA_CLASS_NAME,
@ -128,20 +128,18 @@ class NetatmoDataHandler:
if data_class.next_scan > time():
continue
if data_class_name := data_class.name:
self.data_classes[data_class_name].next_scan = (
time() + data_class.interval
)
if publisher := data_class.name:
self.publisher[publisher].next_scan = time() + data_class.interval
await self.async_fetch_data(data_class_name)
await self.async_fetch_data(publisher)
self._queue.rotate(BATCH_SIZE)
@callback
def async_force_update(self, data_class_entry: str) -> None:
def async_force_update(self, signal_name: str) -> None:
"""Prioritize data retrieval for given data class entry."""
self.data_classes[data_class_entry].next_scan = time()
self._queue.rotate(-(self._queue.index(self.data_classes[data_class_entry])))
self.publisher[signal_name].next_scan = time()
self._queue.rotate(-(self._queue.index(self.publisher[signal_name])))
async def handle_event(self, event: dict) -> None:
"""Handle webhook events."""
@ -157,17 +155,17 @@ class NetatmoDataHandler:
_LOGGER.debug("%s camera reconnected", MANUFACTURER)
self.async_force_update(CAMERA_DATA_CLASS_NAME)
async def async_fetch_data(self, data_class_entry: str) -> None:
async def async_fetch_data(self, signal_name: str) -> None:
"""Fetch data and notify."""
if self.data[data_class_entry] is None:
if self.data[signal_name] is None:
return
try:
await self.data[data_class_entry].async_update()
await self.data[signal_name].async_update()
except pyatmo.NoDevice as err:
_LOGGER.debug(err)
self.data[data_class_entry] = None
self.data[signal_name] = None
except pyatmo.ApiError as err:
_LOGGER.debug(err)
@ -176,56 +174,52 @@ class NetatmoDataHandler:
_LOGGER.debug(err)
return
for update_callback in self.data_classes[data_class_entry].subscriptions:
for update_callback in self.publisher[signal_name].subscriptions:
if update_callback:
update_callback()
async def register_data_class(
async def subscribe(
self,
data_class_name: str,
data_class_entry: str,
publisher: str,
signal_name: str,
update_callback: CALLBACK_TYPE | None,
**kwargs: Any,
) -> None:
"""Register data class."""
if data_class_entry in self.data_classes:
if update_callback not in self.data_classes[data_class_entry].subscriptions:
self.data_classes[data_class_entry].subscriptions.append(
update_callback
)
"""Subscribe to publisher."""
if signal_name in self.publisher:
if update_callback not in self.publisher[signal_name].subscriptions:
self.publisher[signal_name].subscriptions.append(update_callback)
return
self.data_classes[data_class_entry] = NetatmoDataClass(
name=data_class_entry,
interval=DEFAULT_INTERVALS[data_class_name],
next_scan=time() + DEFAULT_INTERVALS[data_class_name],
self.publisher[signal_name] = NetatmoPublisher(
name=signal_name,
interval=DEFAULT_INTERVALS[publisher],
next_scan=time() + DEFAULT_INTERVALS[publisher],
subscriptions=[update_callback],
)
self.data[data_class_entry] = DATA_CLASSES[data_class_name](
self._auth, **kwargs
)
self.data[signal_name] = DATA_CLASSES[publisher](self._auth, **kwargs)
try:
await self.async_fetch_data(data_class_entry)
await self.async_fetch_data(signal_name)
except KeyError:
self.data_classes.pop(data_class_entry)
self.publisher.pop(signal_name)
raise
self._queue.append(self.data_classes[data_class_entry])
_LOGGER.debug("Data class %s added", data_class_entry)
self._queue.append(self.publisher[signal_name])
_LOGGER.debug("Publisher %s added", signal_name)
async def unregister_data_class(
self, data_class_entry: str, update_callback: CALLBACK_TYPE | None
async def unsubscribe(
self, signal_name: str, update_callback: CALLBACK_TYPE | None
) -> None:
"""Unregister data class."""
self.data_classes[data_class_entry].subscriptions.remove(update_callback)
"""Unsubscribe from publisher."""
self.publisher[signal_name].subscriptions.remove(update_callback)
if not self.data_classes[data_class_entry].subscriptions:
self._queue.remove(self.data_classes[data_class_entry])
self.data_classes.pop(data_class_entry)
self.data.pop(data_class_entry)
_LOGGER.debug("Data class %s removed", data_class_entry)
if not self.publisher[signal_name].subscriptions:
self._queue.remove(self.publisher[signal_name])
self.publisher.pop(signal_name)
self.data.pop(signal_name)
_LOGGER.debug("Publisher %s removed", signal_name)
@property
def webhook(self) -> bool:

View file

@ -17,7 +17,6 @@ from .const import (
DATA_HANDLER,
DOMAIN,
EVENT_TYPE_LIGHT_MODE,
MANUFACTURER,
SIGNAL_NAME,
TYPE_SECURITY,
WEBHOOK_LIGHT_MODE,
@ -63,6 +62,7 @@ class NetatmoLight(NetatmoBase, LightEntity):
"""Representation of a Netatmo Presence camera light."""
_attr_color_mode = ColorMode.ONOFF
_attr_has_entity_name = True
_attr_supported_color_modes = {ColorMode.ONOFF}
def __init__(
@ -76,7 +76,7 @@ class NetatmoLight(NetatmoBase, LightEntity):
LightEntity.__init__(self)
super().__init__(data_handler)
self._data_classes.append(
self._publishers.append(
{"name": CAMERA_DATA_CLASS_NAME, SIGNAL_NAME: CAMERA_DATA_CLASS_NAME}
)
self._id = camera_id
@ -84,7 +84,6 @@ class NetatmoLight(NetatmoBase, LightEntity):
self._model = camera_type
self._netatmo_type = TYPE_SECURITY
self._device_name: str = self._data.get_camera(camera_id)["name"]
self._attr_name = f"{MANUFACTURER} {self._device_name}"
self._is_on = False
self._attr_unique_id = f"{self._id}-light"
@ -123,7 +122,7 @@ class NetatmoLight(NetatmoBase, LightEntity):
"""Return data for this entity."""
return cast(
pyatmo.AsyncCameraData,
self.data_handler.data[self._data_classes[0]["name"]],
self.data_handler.data[self._publishers[0]["name"]],
)
@property

View file

@ -1,6 +1,8 @@
"""Base class for Netatmo entities."""
from __future__ import annotations
from typing import Any
from homeassistant.const import ATTR_ATTRIBUTION
from homeassistant.core import callback
from homeassistant.helpers import device_registry as dr
@ -23,7 +25,7 @@ class NetatmoBase(Entity):
def __init__(self, data_handler: NetatmoDataHandler) -> None:
"""Set up Netatmo entity base."""
self.data_handler = data_handler
self._data_classes: list[dict] = []
self._publishers: list[dict[str, Any]] = []
self._device_name: str = ""
self._id: str = ""
@ -35,11 +37,11 @@ class NetatmoBase(Entity):
async def async_added_to_hass(self) -> None:
"""Entity created."""
for data_class in self._data_classes:
for data_class in self._publishers:
signal_name = data_class[SIGNAL_NAME]
if "home_id" in data_class:
await self.data_handler.register_data_class(
await self.data_handler.subscribe(
data_class["name"],
signal_name,
self.async_update_callback,
@ -47,7 +49,7 @@ class NetatmoBase(Entity):
)
elif data_class["name"] == PUBLICDATA_DATA_CLASS_NAME:
await self.data_handler.register_data_class(
await self.data_handler.subscribe(
data_class["name"],
signal_name,
self.async_update_callback,
@ -58,13 +60,13 @@ class NetatmoBase(Entity):
)
else:
await self.data_handler.register_data_class(
await self.data_handler.subscribe(
data_class["name"], signal_name, self.async_update_callback
)
for sub in self.data_handler.data_classes[signal_name].subscriptions:
for sub in self.data_handler.publisher[signal_name].subscriptions:
if sub is None:
await self.data_handler.unregister_data_class(signal_name, None)
await self.data_handler.unsubscribe(signal_name, None)
registry = dr.async_get(self.hass)
if device := registry.async_get_device({(DOMAIN, self._id)}):
@ -76,8 +78,8 @@ class NetatmoBase(Entity):
"""Run when entity will be removed from hass."""
await super().async_will_remove_from_hass()
for data_class in self._data_classes:
await self.data_handler.unregister_data_class(
for data_class in self._publishers:
await self.data_handler.unsubscribe(
data_class[SIGNAL_NAME], self.async_update_callback
)

View file

@ -46,7 +46,7 @@ async def async_setup_entry(
for home_id in climate_topology.home_ids:
signal_name = f"{CLIMATE_STATE_CLASS_NAME}-{home_id}"
await data_handler.register_data_class(
await data_handler.subscribe(
CLIMATE_STATE_CLASS_NAME, signal_name, None, home_id=home_id
)
@ -92,7 +92,7 @@ class NetatmoScheduleSelect(NetatmoBase, SelectEntity):
self._home = self._climate_state.homes[self._home_id]
self._data_classes.extend(
self._publishers.extend(
[
{
"name": CLIMATE_TOPOLOGY_CLASS_NAME,

View file

@ -41,7 +41,6 @@ from .const import (
CONF_WEATHER_AREAS,
DATA_HANDLER,
DOMAIN,
MANUFACTURER,
NETATMO_CREATE_BATTERY,
SIGNAL_NAME,
TYPE_WEATHER,
@ -422,7 +421,7 @@ async def async_setup_entry(
)
continue
await data_handler.register_data_class(
await data_handler.subscribe(
PUBLICDATA_DATA_CLASS_NAME,
signal_name,
None,
@ -487,9 +486,7 @@ class NetatmoSensor(NetatmoBase, SensorEntity):
super().__init__(data_handler)
self.entity_description = description
self._data_classes.append(
{"name": data_class_name, SIGNAL_NAME: data_class_name}
)
self._publishers.append({"name": data_class_name, SIGNAL_NAME: data_class_name})
self._id = module_info["_id"]
self._station_id = module_info.get("main_device", self._id)
@ -507,7 +504,7 @@ class NetatmoSensor(NetatmoBase, SensorEntity):
f"{module_info.get('module_name', device['type'])}"
)
self._attr_name = f"{MANUFACTURER} {self._device_name} {description.name}"
self._attr_name = f"{self._device_name} {description.name}"
self._model = device["type"]
self._netatmo_type = TYPE_WEATHER
self._attr_unique_id = f"{self._id}-{description.key}"
@ -517,7 +514,7 @@ class NetatmoSensor(NetatmoBase, SensorEntity):
"""Return data for this entity."""
return cast(
pyatmo.AsyncWeatherStationData,
self.data_handler.data[self._data_classes[0]["name"]],
self.data_handler.data[self._publishers[0]["name"]],
)
@property
@ -598,7 +595,7 @@ class NetatmoClimateBatterySensor(NetatmoBase, SensorEntity):
self._id = netatmo_device.parent_id
self._attr_name = f"{self._module.name} {self.entity_description.name}"
self._state_class_name = netatmo_device.state_class_name
self._signal_name = netatmo_device.signal_name
self._room_id = self._module.room_id
self._model = getattr(self._module.device_type, "value")
@ -734,7 +731,7 @@ class NetatmoPublicSensor(NetatmoBase, SensorEntity):
self._signal_name = f"{PUBLICDATA_DATA_CLASS_NAME}-{area.uuid}"
self._data_classes.append(
self._publishers.append(
{
"name": PUBLICDATA_DATA_CLASS_NAME,
"lat_ne": area.lat_ne,
@ -751,7 +748,7 @@ class NetatmoPublicSensor(NetatmoBase, SensorEntity):
self._area_name = area.area_name
self._id = self._area_name
self._device_name = f"{self._area_name}"
self._attr_name = f"{MANUFACTURER} {self._device_name} {description.name}"
self._attr_name = f"{self._device_name} {description.name}"
self._show_on_map = area.show_on_map
self._attr_unique_id = (
f"{self._device_name.replace(' ', '-')}-{description.key}"
@ -788,13 +785,13 @@ class NetatmoPublicSensor(NetatmoBase, SensorEntity):
if self.area == area:
return
await self.data_handler.unregister_data_class(
await self.data_handler.unsubscribe(
self._signal_name, self.async_update_callback
)
self.area = area
self._signal_name = f"{PUBLICDATA_DATA_CLASS_NAME}-{area.uuid}"
self._data_classes = [
self._publishers = [
{
"name": PUBLICDATA_DATA_CLASS_NAME,
"lat_ne": area.lat_ne,
@ -807,7 +804,7 @@ class NetatmoPublicSensor(NetatmoBase, SensorEntity):
]
self._mode = area.mode
self._show_on_map = area.show_on_map
await self.data_handler.register_data_class(
await self.data_handler.subscribe(
PUBLICDATA_DATA_CLASS_NAME,
self._signal_name,
self.async_update_callback,

View file

@ -32,8 +32,8 @@ async def test_setup_component_with_webhook(hass, config_entry, netatmo_auth):
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
await hass.async_block_till_done()
camera_entity_indoor = "camera.netatmo_hall"
camera_entity_outdoor = "camera.netatmo_garden"
camera_entity_indoor = "camera.hall"
camera_entity_outdoor = "camera.garden"
assert hass.states.get(camera_entity_indoor).state == "streaming"
response = {
"event_type": "off",
@ -95,7 +95,7 @@ async def test_setup_component_with_webhook(hass, config_entry, netatmo_auth):
with patch("pyatmo.camera.AsyncCameraData.async_set_state") as mock_set_state:
await hass.services.async_call(
"camera", "turn_off", service_data={"entity_id": "camera.netatmo_hall"}
"camera", "turn_off", service_data={"entity_id": "camera.hall"}
)
await hass.async_block_till_done()
mock_set_state.assert_called_once_with(
@ -106,7 +106,7 @@ async def test_setup_component_with_webhook(hass, config_entry, netatmo_auth):
with patch("pyatmo.camera.AsyncCameraData.async_set_state") as mock_set_state:
await hass.services.async_call(
"camera", "turn_on", service_data={"entity_id": "camera.netatmo_hall"}
"camera", "turn_on", service_data={"entity_id": "camera.hall"}
)
await hass.async_block_till_done()
mock_set_state.assert_called_once_with(
@ -130,7 +130,7 @@ async def test_camera_image_local(hass, config_entry, requests_mock, netatmo_aut
uri = "http://192.168.0.123/678460a0d47e5618699fb31169e2b47d"
stream_uri = uri + "/live/files/high/index.m3u8"
camera_entity_indoor = "camera.netatmo_hall"
camera_entity_indoor = "camera.hall"
cam = hass.states.get(camera_entity_indoor)
assert cam is not None
@ -161,7 +161,7 @@ async def test_camera_image_vpn(hass, config_entry, requests_mock, netatmo_auth)
"6d278460699e56180d47ab47169efb31/MpEylTU2MDYzNjRVD-LJxUnIndumKzLboeAwMDqTTw,,"
)
stream_uri = uri + "/live/files/high/index.m3u8"
camera_entity_indoor = "camera.netatmo_garden"
camera_entity_indoor = "camera.garden"
cam = hass.states.get(camera_entity_indoor)
assert cam is not None
@ -188,7 +188,7 @@ async def test_service_set_person_away(hass, config_entry, netatmo_auth):
await hass.async_block_till_done()
data = {
"entity_id": "camera.netatmo_hall",
"entity_id": "camera.hall",
"person": "Richard Doe",
}
@ -205,7 +205,7 @@ async def test_service_set_person_away(hass, config_entry, netatmo_auth):
)
data = {
"entity_id": "camera.netatmo_hall",
"entity_id": "camera.hall",
}
with patch(
@ -231,7 +231,7 @@ async def test_service_set_person_away_invalid_person(hass, config_entry, netatm
await hass.async_block_till_done()
data = {
"entity_id": "camera.netatmo_hall",
"entity_id": "camera.hall",
"person": "Batman",
}
@ -259,7 +259,7 @@ async def test_service_set_persons_home_invalid_person(
await hass.async_block_till_done()
data = {
"entity_id": "camera.netatmo_hall",
"entity_id": "camera.hall",
"persons": "Batman",
}
@ -285,7 +285,7 @@ async def test_service_set_persons_home(hass, config_entry, netatmo_auth):
await hass.async_block_till_done()
data = {
"entity_id": "camera.netatmo_hall",
"entity_id": "camera.hall",
"persons": "John Doe",
}
@ -312,7 +312,7 @@ async def test_service_set_camera_light(hass, config_entry, netatmo_auth):
await hass.async_block_till_done()
data = {
"entity_id": "camera.netatmo_garden",
"entity_id": "camera.garden",
"camera_light_mode": "on",
}
@ -485,7 +485,7 @@ async def test_camera_image_raises_exception(hass, config_entry, requests_mock):
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
camera_entity_indoor = "camera.netatmo_hall"
camera_entity_indoor = "camera.hall"
with pytest.raises(Exception) as excinfo:
await camera.async_get_image(hass, camera_entity_indoor)

View file

@ -27,7 +27,7 @@ async def test_light_setup_and_services(hass, config_entry, netatmo_auth):
await simulate_webhook(hass, webhook_id, FAKE_WEBHOOK_ACTIVATION)
await hass.async_block_till_done()
light_entity = "light.netatmo_garden"
light_entity = "light.garden"
assert hass.states.get(light_entity).state == "unavailable"
# Trigger light mode change

View file

@ -17,7 +17,7 @@ async def test_weather_sensor(hass, config_entry, netatmo_auth):
await hass.async_block_till_done()
prefix = "sensor.netatmo_mystation_"
prefix = "sensor.mystation_"
assert hass.states.get(f"{prefix}temperature").state == "24.6"
assert hass.states.get(f"{prefix}humidity").state == "36"
@ -34,13 +34,13 @@ async def test_public_weather_sensor(hass, config_entry, netatmo_auth):
assert len(hass.states.async_all()) > 0
prefix = "sensor.netatmo_home_max_"
prefix = "sensor.home_max_"
assert hass.states.get(f"{prefix}temperature").state == "27.4"
assert hass.states.get(f"{prefix}humidity").state == "76"
assert hass.states.get(f"{prefix}pressure").state == "1014.4"
prefix = "sensor.netatmo_home_avg_"
prefix = "sensor.home_avg_"
assert hass.states.get(f"{prefix}temperature").state == "22.7"
assert hass.states.get(f"{prefix}humidity").state == "63.2"