Netatmo entity renaming and clean up (#75337)
This commit is contained in:
parent
314778cb50
commit
49854b809c
11 changed files with 128 additions and 144 deletions
|
@ -112,6 +112,8 @@ async def async_setup_entry(
|
||||||
class NetatmoCamera(NetatmoBase, Camera):
|
class NetatmoCamera(NetatmoBase, Camera):
|
||||||
"""Representation of a Netatmo camera."""
|
"""Representation of a Netatmo camera."""
|
||||||
|
|
||||||
|
_attr_brand = MANUFACTURER
|
||||||
|
_attr_has_entity_name = True
|
||||||
_attr_supported_features = CameraEntityFeature.STREAM
|
_attr_supported_features = CameraEntityFeature.STREAM
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -126,14 +128,13 @@ class NetatmoCamera(NetatmoBase, Camera):
|
||||||
Camera.__init__(self)
|
Camera.__init__(self)
|
||||||
super().__init__(data_handler)
|
super().__init__(data_handler)
|
||||||
|
|
||||||
self._data_classes.append(
|
self._publishers.append(
|
||||||
{"name": CAMERA_DATA_CLASS_NAME, SIGNAL_NAME: CAMERA_DATA_CLASS_NAME}
|
{"name": CAMERA_DATA_CLASS_NAME, SIGNAL_NAME: CAMERA_DATA_CLASS_NAME}
|
||||||
)
|
)
|
||||||
|
|
||||||
self._id = camera_id
|
self._id = camera_id
|
||||||
self._home_id = home_id
|
self._home_id = home_id
|
||||||
self._device_name = self._data.get_camera(camera_id=camera_id)["name"]
|
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._model = camera_type
|
||||||
self._netatmo_type = TYPE_SECURITY
|
self._netatmo_type = TYPE_SECURITY
|
||||||
self._attr_unique_id = f"{self._id}-{self._model}"
|
self._attr_unique_id = f"{self._id}-{self._model}"
|
||||||
|
@ -193,7 +194,7 @@ class NetatmoCamera(NetatmoBase, Camera):
|
||||||
"""Return data for this entity."""
|
"""Return data for this entity."""
|
||||||
return cast(
|
return cast(
|
||||||
pyatmo.AsyncCameraData,
|
pyatmo.AsyncCameraData,
|
||||||
self.data_handler.data[self._data_classes[0]["name"]],
|
self.data_handler.data[self._publishers[0]["name"]],
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_camera_image(
|
async def async_camera_image(
|
||||||
|
@ -219,11 +220,6 @@ class NetatmoCamera(NetatmoBase, Camera):
|
||||||
"""Return True if entity is available."""
|
"""Return True if entity is available."""
|
||||||
return bool(self._alim_status == "on" or self._status == "disconnected")
|
return bool(self._alim_status == "on" or self._status == "disconnected")
|
||||||
|
|
||||||
@property
|
|
||||||
def brand(self) -> str:
|
|
||||||
"""Return the camera brand."""
|
|
||||||
return MANUFACTURER
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def motion_detection_enabled(self) -> bool:
|
def motion_detection_enabled(self) -> bool:
|
||||||
"""Return the camera motion detection status."""
|
"""Return the camera motion detection status."""
|
||||||
|
|
|
@ -127,7 +127,7 @@ async def async_setup_entry(
|
||||||
for home_id in climate_topology.home_ids:
|
for home_id in climate_topology.home_ids:
|
||||||
signal_name = f"{CLIMATE_STATE_CLASS_NAME}-{home_id}"
|
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
|
CLIMATE_STATE_CLASS_NAME, signal_name, None, home_id=home_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -185,14 +185,10 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
||||||
self._room = room
|
self._room = room
|
||||||
self._id = self._room.entity_id
|
self._id = self._room.entity_id
|
||||||
|
|
||||||
self._climate_state_class = (
|
self._signal_name = f"{CLIMATE_STATE_CLASS_NAME}-{self._room.home.entity_id}"
|
||||||
f"{CLIMATE_STATE_CLASS_NAME}-{self._room.home.entity_id}"
|
self._climate_state: pyatmo.AsyncClimate = data_handler.data[self._signal_name]
|
||||||
)
|
|
||||||
self._climate_state: pyatmo.AsyncClimate = data_handler.data[
|
|
||||||
self._climate_state_class
|
|
||||||
]
|
|
||||||
|
|
||||||
self._data_classes.extend(
|
self._publishers.extend(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": CLIMATE_TOPOLOGY_CLASS_NAME,
|
"name": CLIMATE_TOPOLOGY_CLASS_NAME,
|
||||||
|
@ -201,7 +197,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
||||||
{
|
{
|
||||||
"name": CLIMATE_STATE_CLASS_NAME,
|
"name": CLIMATE_STATE_CLASS_NAME,
|
||||||
"home_id": self._room.home.entity_id,
|
"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,
|
self.data_handler,
|
||||||
module,
|
module,
|
||||||
self._id,
|
self._id,
|
||||||
self._climate_state_class,
|
self._signal_name,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -278,7 +274,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
||||||
ATTR_SELECTED_SCHEDULE
|
ATTR_SELECTED_SCHEDULE
|
||||||
] = self._selected_schedule
|
] = self._selected_schedule
|
||||||
self.async_write_ha_state()
|
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
|
return
|
||||||
|
|
||||||
home = data["home"]
|
home = data["home"]
|
||||||
|
@ -295,7 +291,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
||||||
self._attr_target_temperature = self._away_temperature
|
self._attr_target_temperature = self._away_temperature
|
||||||
elif self._attr_preset_mode == PRESET_SCHEDULE:
|
elif self._attr_preset_mode == PRESET_SCHEDULE:
|
||||||
self.async_update_callback()
|
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()
|
self.async_write_ha_state()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -73,16 +73,16 @@ DATA_HANDLER = "netatmo_data_handler"
|
||||||
SIGNAL_NAME = "signal_name"
|
SIGNAL_NAME = "signal_name"
|
||||||
NETATMO_CREATE_BATTERY = "netatmo_create_battery"
|
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_AREA_NAME = "area_name"
|
||||||
|
CONF_CLOUDHOOK_URL = "cloudhook_url"
|
||||||
CONF_LAT_NE = "lat_ne"
|
CONF_LAT_NE = "lat_ne"
|
||||||
CONF_LON_NE = "lon_ne"
|
|
||||||
CONF_LAT_SW = "lat_sw"
|
CONF_LAT_SW = "lat_sw"
|
||||||
|
CONF_LON_NE = "lon_ne"
|
||||||
CONF_LON_SW = "lon_sw"
|
CONF_LON_SW = "lon_sw"
|
||||||
|
CONF_NEW_AREA = "new_area"
|
||||||
CONF_PUBLIC_MODE = "mode"
|
CONF_PUBLIC_MODE = "mode"
|
||||||
CONF_UUID = "uuid"
|
CONF_UUID = "uuid"
|
||||||
|
CONF_WEATHER_AREAS = "weather_areas"
|
||||||
|
|
||||||
OAUTH2_AUTHORIZE = "https://api.netatmo.com/oauth2/authorize"
|
OAUTH2_AUTHORIZE = "https://api.netatmo.com/oauth2/authorize"
|
||||||
OAUTH2_TOKEN = "https://api.netatmo.com/oauth2/token"
|
OAUTH2_TOKEN = "https://api.netatmo.com/oauth2/token"
|
||||||
|
@ -94,53 +94,53 @@ DATA_HOMES = "netatmo_homes"
|
||||||
DATA_PERSONS = "netatmo_persons"
|
DATA_PERSONS = "netatmo_persons"
|
||||||
DATA_SCHEDULES = "netatmo_schedules"
|
DATA_SCHEDULES = "netatmo_schedules"
|
||||||
|
|
||||||
NETATMO_WEBHOOK_URL = None
|
|
||||||
NETATMO_EVENT = "netatmo_event"
|
NETATMO_EVENT = "netatmo_event"
|
||||||
|
NETATMO_WEBHOOK_URL = None
|
||||||
|
|
||||||
DEFAULT_PERSON = "unknown"
|
|
||||||
DEFAULT_DISCOVERY = True
|
DEFAULT_DISCOVERY = True
|
||||||
|
DEFAULT_PERSON = "unknown"
|
||||||
DEFAULT_WEBHOOKS = False
|
DEFAULT_WEBHOOKS = False
|
||||||
|
|
||||||
ATTR_PSEUDO = "pseudo"
|
ATTR_CAMERA_LIGHT_MODE = "camera_light_mode"
|
||||||
ATTR_EVENT_TYPE = "event_type"
|
ATTR_EVENT_TYPE = "event_type"
|
||||||
|
ATTR_FACE_URL = "face_url"
|
||||||
ATTR_HEATING_POWER_REQUEST = "heating_power_request"
|
ATTR_HEATING_POWER_REQUEST = "heating_power_request"
|
||||||
ATTR_HOME_ID = "home_id"
|
ATTR_HOME_ID = "home_id"
|
||||||
ATTR_HOME_NAME = "home_name"
|
ATTR_HOME_NAME = "home_name"
|
||||||
|
ATTR_IS_KNOWN = "is_known"
|
||||||
ATTR_PERSON = "person"
|
ATTR_PERSON = "person"
|
||||||
ATTR_PERSONS = "persons"
|
ATTR_PERSONS = "persons"
|
||||||
ATTR_IS_KNOWN = "is_known"
|
ATTR_PSEUDO = "pseudo"
|
||||||
ATTR_FACE_URL = "face_url"
|
|
||||||
ATTR_SCHEDULE_ID = "schedule_id"
|
ATTR_SCHEDULE_ID = "schedule_id"
|
||||||
ATTR_SCHEDULE_NAME = "schedule_name"
|
ATTR_SCHEDULE_NAME = "schedule_name"
|
||||||
ATTR_SELECTED_SCHEDULE = "selected_schedule"
|
ATTR_SELECTED_SCHEDULE = "selected_schedule"
|
||||||
ATTR_CAMERA_LIGHT_MODE = "camera_light_mode"
|
|
||||||
|
|
||||||
SERVICE_SET_CAMERA_LIGHT = "set_camera_light"
|
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_PERSON_AWAY = "set_person_away"
|
||||||
|
SERVICE_SET_PERSONS_HOME = "set_persons_home"
|
||||||
|
SERVICE_SET_SCHEDULE = "set_schedule"
|
||||||
|
|
||||||
# Climate events
|
# Climate events
|
||||||
EVENT_TYPE_SET_POINT = "set_point"
|
|
||||||
EVENT_TYPE_CANCEL_SET_POINT = "cancel_set_point"
|
EVENT_TYPE_CANCEL_SET_POINT = "cancel_set_point"
|
||||||
EVENT_TYPE_THERM_MODE = "therm_mode"
|
|
||||||
EVENT_TYPE_SCHEDULE = "schedule"
|
EVENT_TYPE_SCHEDULE = "schedule"
|
||||||
|
EVENT_TYPE_SET_POINT = "set_point"
|
||||||
|
EVENT_TYPE_THERM_MODE = "therm_mode"
|
||||||
# Camera events
|
# Camera events
|
||||||
EVENT_TYPE_LIGHT_MODE = "light_mode"
|
|
||||||
EVENT_TYPE_CAMERA_OUTDOOR = "outdoor"
|
|
||||||
EVENT_TYPE_CAMERA_ANIMAL = "animal"
|
EVENT_TYPE_CAMERA_ANIMAL = "animal"
|
||||||
EVENT_TYPE_CAMERA_HUMAN = "human"
|
EVENT_TYPE_CAMERA_HUMAN = "human"
|
||||||
EVENT_TYPE_CAMERA_VEHICLE = "vehicle"
|
|
||||||
EVENT_TYPE_CAMERA_MOVEMENT = "movement"
|
EVENT_TYPE_CAMERA_MOVEMENT = "movement"
|
||||||
|
EVENT_TYPE_CAMERA_OUTDOOR = "outdoor"
|
||||||
EVENT_TYPE_CAMERA_PERSON = "person"
|
EVENT_TYPE_CAMERA_PERSON = "person"
|
||||||
EVENT_TYPE_CAMERA_PERSON_AWAY = "person_away"
|
EVENT_TYPE_CAMERA_PERSON_AWAY = "person_away"
|
||||||
|
EVENT_TYPE_CAMERA_VEHICLE = "vehicle"
|
||||||
|
EVENT_TYPE_LIGHT_MODE = "light_mode"
|
||||||
# Door tags
|
# 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_BIG_MOVE = "tag_big_move"
|
||||||
EVENT_TYPE_DOOR_TAG_OPEN = "tag_open"
|
EVENT_TYPE_DOOR_TAG_OPEN = "tag_open"
|
||||||
|
EVENT_TYPE_DOOR_TAG_SMALL_MOVE = "tag_small_move"
|
||||||
EVENT_TYPE_OFF = "off"
|
EVENT_TYPE_OFF = "off"
|
||||||
EVENT_TYPE_ON = "on"
|
EVENT_TYPE_ON = "on"
|
||||||
EVENT_TYPE_ALARM_STARTED = "alarm_started"
|
|
||||||
|
|
||||||
OUTDOOR_CAMERA_TRIGGERS = [
|
OUTDOOR_CAMERA_TRIGGERS = [
|
||||||
EVENT_TYPE_CAMERA_ANIMAL,
|
EVENT_TYPE_CAMERA_ANIMAL,
|
||||||
|
@ -149,46 +149,46 @@ OUTDOOR_CAMERA_TRIGGERS = [
|
||||||
EVENT_TYPE_CAMERA_VEHICLE,
|
EVENT_TYPE_CAMERA_VEHICLE,
|
||||||
]
|
]
|
||||||
INDOOR_CAMERA_TRIGGERS = [
|
INDOOR_CAMERA_TRIGGERS = [
|
||||||
EVENT_TYPE_CAMERA_MOVEMENT,
|
|
||||||
EVENT_TYPE_CAMERA_PERSON,
|
|
||||||
EVENT_TYPE_CAMERA_PERSON_AWAY,
|
|
||||||
EVENT_TYPE_ALARM_STARTED,
|
EVENT_TYPE_ALARM_STARTED,
|
||||||
|
EVENT_TYPE_CAMERA_MOVEMENT,
|
||||||
|
EVENT_TYPE_CAMERA_PERSON_AWAY,
|
||||||
|
EVENT_TYPE_CAMERA_PERSON,
|
||||||
]
|
]
|
||||||
DOOR_TAG_TRIGGERS = [
|
DOOR_TAG_TRIGGERS = [
|
||||||
EVENT_TYPE_DOOR_TAG_SMALL_MOVE,
|
|
||||||
EVENT_TYPE_DOOR_TAG_BIG_MOVE,
|
EVENT_TYPE_DOOR_TAG_BIG_MOVE,
|
||||||
EVENT_TYPE_DOOR_TAG_OPEN,
|
EVENT_TYPE_DOOR_TAG_OPEN,
|
||||||
|
EVENT_TYPE_DOOR_TAG_SMALL_MOVE,
|
||||||
]
|
]
|
||||||
CLIMATE_TRIGGERS = [
|
CLIMATE_TRIGGERS = [
|
||||||
EVENT_TYPE_SET_POINT,
|
|
||||||
EVENT_TYPE_CANCEL_SET_POINT,
|
EVENT_TYPE_CANCEL_SET_POINT,
|
||||||
|
EVENT_TYPE_SET_POINT,
|
||||||
EVENT_TYPE_THERM_MODE,
|
EVENT_TYPE_THERM_MODE,
|
||||||
]
|
]
|
||||||
EVENT_ID_MAP = {
|
EVENT_ID_MAP = {
|
||||||
EVENT_TYPE_CAMERA_MOVEMENT: "device_id",
|
EVENT_TYPE_ALARM_STARTED: "device_id",
|
||||||
EVENT_TYPE_CAMERA_PERSON: "device_id",
|
|
||||||
EVENT_TYPE_CAMERA_PERSON_AWAY: "device_id",
|
|
||||||
EVENT_TYPE_CAMERA_ANIMAL: "device_id",
|
EVENT_TYPE_CAMERA_ANIMAL: "device_id",
|
||||||
EVENT_TYPE_CAMERA_HUMAN: "device_id",
|
EVENT_TYPE_CAMERA_HUMAN: "device_id",
|
||||||
|
EVENT_TYPE_CAMERA_MOVEMENT: "device_id",
|
||||||
EVENT_TYPE_CAMERA_OUTDOOR: "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_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_BIG_MOVE: "device_id",
|
||||||
EVENT_TYPE_DOOR_TAG_OPEN: "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_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_SET_POINT: "room_id",
|
||||||
EVENT_TYPE_THERM_MODE: "home_id",
|
EVENT_TYPE_THERM_MODE: "home_id",
|
||||||
}
|
}
|
||||||
|
|
||||||
MODE_LIGHT_ON = "on"
|
|
||||||
MODE_LIGHT_OFF = "off"
|
|
||||||
MODE_LIGHT_AUTO = "auto"
|
MODE_LIGHT_AUTO = "auto"
|
||||||
|
MODE_LIGHT_OFF = "off"
|
||||||
|
MODE_LIGHT_ON = "on"
|
||||||
CAMERA_LIGHT_MODES = [MODE_LIGHT_ON, MODE_LIGHT_OFF, MODE_LIGHT_AUTO]
|
CAMERA_LIGHT_MODES = [MODE_LIGHT_ON, MODE_LIGHT_OFF, MODE_LIGHT_AUTO]
|
||||||
|
|
||||||
WEBHOOK_ACTIVATION = "webhook_activation"
|
WEBHOOK_ACTIVATION = "webhook_activation"
|
||||||
WEBHOOK_DEACTIVATION = "webhook_deactivation"
|
WEBHOOK_DEACTIVATION = "webhook_deactivation"
|
||||||
|
WEBHOOK_LIGHT_MODE = "NOC-light_mode"
|
||||||
WEBHOOK_NACAMERA_CONNECTION = "NACamera-connection"
|
WEBHOOK_NACAMERA_CONNECTION = "NACamera-connection"
|
||||||
WEBHOOK_PUSH_TYPE = "push_type"
|
WEBHOOK_PUSH_TYPE = "push_type"
|
||||||
WEBHOOK_LIGHT_MODE = "NOC-light_mode"
|
|
||||||
|
|
|
@ -64,11 +64,11 @@ class NetatmoDevice:
|
||||||
data_handler: NetatmoDataHandler
|
data_handler: NetatmoDataHandler
|
||||||
device: pyatmo.climate.NetatmoModule
|
device: pyatmo.climate.NetatmoModule
|
||||||
parent_id: str
|
parent_id: str
|
||||||
state_class_name: str
|
signal_name: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class NetatmoDataClass:
|
class NetatmoPublisher:
|
||||||
"""Class for keeping track of Netatmo data class metadata."""
|
"""Class for keeping track of Netatmo data class metadata."""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
|
@ -85,7 +85,7 @@ class NetatmoDataHandler:
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.config_entry = config_entry
|
self.config_entry = config_entry
|
||||||
self._auth = hass.data[DOMAIN][config_entry.entry_id][AUTH]
|
self._auth = hass.data[DOMAIN][config_entry.entry_id][AUTH]
|
||||||
self.data_classes: dict = {}
|
self.publisher: dict[str, NetatmoPublisher] = {}
|
||||||
self.data: dict = {}
|
self.data: dict = {}
|
||||||
self._queue: deque = deque()
|
self._queue: deque = deque()
|
||||||
self._webhook: bool = False
|
self._webhook: bool = False
|
||||||
|
@ -107,7 +107,7 @@ class NetatmoDataHandler:
|
||||||
|
|
||||||
await asyncio.gather(
|
await asyncio.gather(
|
||||||
*[
|
*[
|
||||||
self.register_data_class(data_class, data_class, None)
|
self.subscribe(data_class, data_class, None)
|
||||||
for data_class in (
|
for data_class in (
|
||||||
CLIMATE_TOPOLOGY_CLASS_NAME,
|
CLIMATE_TOPOLOGY_CLASS_NAME,
|
||||||
CAMERA_DATA_CLASS_NAME,
|
CAMERA_DATA_CLASS_NAME,
|
||||||
|
@ -128,20 +128,18 @@ class NetatmoDataHandler:
|
||||||
if data_class.next_scan > time():
|
if data_class.next_scan > time():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if data_class_name := data_class.name:
|
if publisher := data_class.name:
|
||||||
self.data_classes[data_class_name].next_scan = (
|
self.publisher[publisher].next_scan = time() + data_class.interval
|
||||||
time() + data_class.interval
|
|
||||||
)
|
|
||||||
|
|
||||||
await self.async_fetch_data(data_class_name)
|
await self.async_fetch_data(publisher)
|
||||||
|
|
||||||
self._queue.rotate(BATCH_SIZE)
|
self._queue.rotate(BATCH_SIZE)
|
||||||
|
|
||||||
@callback
|
@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."""
|
"""Prioritize data retrieval for given data class entry."""
|
||||||
self.data_classes[data_class_entry].next_scan = time()
|
self.publisher[signal_name].next_scan = time()
|
||||||
self._queue.rotate(-(self._queue.index(self.data_classes[data_class_entry])))
|
self._queue.rotate(-(self._queue.index(self.publisher[signal_name])))
|
||||||
|
|
||||||
async def handle_event(self, event: dict) -> None:
|
async def handle_event(self, event: dict) -> None:
|
||||||
"""Handle webhook events."""
|
"""Handle webhook events."""
|
||||||
|
@ -157,17 +155,17 @@ class NetatmoDataHandler:
|
||||||
_LOGGER.debug("%s camera reconnected", MANUFACTURER)
|
_LOGGER.debug("%s camera reconnected", MANUFACTURER)
|
||||||
self.async_force_update(CAMERA_DATA_CLASS_NAME)
|
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."""
|
"""Fetch data and notify."""
|
||||||
if self.data[data_class_entry] is None:
|
if self.data[signal_name] is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self.data[data_class_entry].async_update()
|
await self.data[signal_name].async_update()
|
||||||
|
|
||||||
except pyatmo.NoDevice as err:
|
except pyatmo.NoDevice as err:
|
||||||
_LOGGER.debug(err)
|
_LOGGER.debug(err)
|
||||||
self.data[data_class_entry] = None
|
self.data[signal_name] = None
|
||||||
|
|
||||||
except pyatmo.ApiError as err:
|
except pyatmo.ApiError as err:
|
||||||
_LOGGER.debug(err)
|
_LOGGER.debug(err)
|
||||||
|
@ -176,56 +174,52 @@ class NetatmoDataHandler:
|
||||||
_LOGGER.debug(err)
|
_LOGGER.debug(err)
|
||||||
return
|
return
|
||||||
|
|
||||||
for update_callback in self.data_classes[data_class_entry].subscriptions:
|
for update_callback in self.publisher[signal_name].subscriptions:
|
||||||
if update_callback:
|
if update_callback:
|
||||||
update_callback()
|
update_callback()
|
||||||
|
|
||||||
async def register_data_class(
|
async def subscribe(
|
||||||
self,
|
self,
|
||||||
data_class_name: str,
|
publisher: str,
|
||||||
data_class_entry: str,
|
signal_name: str,
|
||||||
update_callback: CALLBACK_TYPE | None,
|
update_callback: CALLBACK_TYPE | None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Register data class."""
|
"""Subscribe to publisher."""
|
||||||
if data_class_entry in self.data_classes:
|
if signal_name in self.publisher:
|
||||||
if update_callback not in self.data_classes[data_class_entry].subscriptions:
|
if update_callback not in self.publisher[signal_name].subscriptions:
|
||||||
self.data_classes[data_class_entry].subscriptions.append(
|
self.publisher[signal_name].subscriptions.append(update_callback)
|
||||||
update_callback
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self.data_classes[data_class_entry] = NetatmoDataClass(
|
self.publisher[signal_name] = NetatmoPublisher(
|
||||||
name=data_class_entry,
|
name=signal_name,
|
||||||
interval=DEFAULT_INTERVALS[data_class_name],
|
interval=DEFAULT_INTERVALS[publisher],
|
||||||
next_scan=time() + DEFAULT_INTERVALS[data_class_name],
|
next_scan=time() + DEFAULT_INTERVALS[publisher],
|
||||||
subscriptions=[update_callback],
|
subscriptions=[update_callback],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.data[data_class_entry] = DATA_CLASSES[data_class_name](
|
self.data[signal_name] = DATA_CLASSES[publisher](self._auth, **kwargs)
|
||||||
self._auth, **kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self.async_fetch_data(data_class_entry)
|
await self.async_fetch_data(signal_name)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.data_classes.pop(data_class_entry)
|
self.publisher.pop(signal_name)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
self._queue.append(self.data_classes[data_class_entry])
|
self._queue.append(self.publisher[signal_name])
|
||||||
_LOGGER.debug("Data class %s added", data_class_entry)
|
_LOGGER.debug("Publisher %s added", signal_name)
|
||||||
|
|
||||||
async def unregister_data_class(
|
async def unsubscribe(
|
||||||
self, data_class_entry: str, update_callback: CALLBACK_TYPE | None
|
self, signal_name: str, update_callback: CALLBACK_TYPE | None
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Unregister data class."""
|
"""Unsubscribe from publisher."""
|
||||||
self.data_classes[data_class_entry].subscriptions.remove(update_callback)
|
self.publisher[signal_name].subscriptions.remove(update_callback)
|
||||||
|
|
||||||
if not self.data_classes[data_class_entry].subscriptions:
|
if not self.publisher[signal_name].subscriptions:
|
||||||
self._queue.remove(self.data_classes[data_class_entry])
|
self._queue.remove(self.publisher[signal_name])
|
||||||
self.data_classes.pop(data_class_entry)
|
self.publisher.pop(signal_name)
|
||||||
self.data.pop(data_class_entry)
|
self.data.pop(signal_name)
|
||||||
_LOGGER.debug("Data class %s removed", data_class_entry)
|
_LOGGER.debug("Publisher %s removed", signal_name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def webhook(self) -> bool:
|
def webhook(self) -> bool:
|
||||||
|
|
|
@ -17,7 +17,6 @@ from .const import (
|
||||||
DATA_HANDLER,
|
DATA_HANDLER,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
EVENT_TYPE_LIGHT_MODE,
|
EVENT_TYPE_LIGHT_MODE,
|
||||||
MANUFACTURER,
|
|
||||||
SIGNAL_NAME,
|
SIGNAL_NAME,
|
||||||
TYPE_SECURITY,
|
TYPE_SECURITY,
|
||||||
WEBHOOK_LIGHT_MODE,
|
WEBHOOK_LIGHT_MODE,
|
||||||
|
@ -63,6 +62,7 @@ class NetatmoLight(NetatmoBase, LightEntity):
|
||||||
"""Representation of a Netatmo Presence camera light."""
|
"""Representation of a Netatmo Presence camera light."""
|
||||||
|
|
||||||
_attr_color_mode = ColorMode.ONOFF
|
_attr_color_mode = ColorMode.ONOFF
|
||||||
|
_attr_has_entity_name = True
|
||||||
_attr_supported_color_modes = {ColorMode.ONOFF}
|
_attr_supported_color_modes = {ColorMode.ONOFF}
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -76,7 +76,7 @@ class NetatmoLight(NetatmoBase, LightEntity):
|
||||||
LightEntity.__init__(self)
|
LightEntity.__init__(self)
|
||||||
super().__init__(data_handler)
|
super().__init__(data_handler)
|
||||||
|
|
||||||
self._data_classes.append(
|
self._publishers.append(
|
||||||
{"name": CAMERA_DATA_CLASS_NAME, SIGNAL_NAME: CAMERA_DATA_CLASS_NAME}
|
{"name": CAMERA_DATA_CLASS_NAME, SIGNAL_NAME: CAMERA_DATA_CLASS_NAME}
|
||||||
)
|
)
|
||||||
self._id = camera_id
|
self._id = camera_id
|
||||||
|
@ -84,7 +84,6 @@ class NetatmoLight(NetatmoBase, LightEntity):
|
||||||
self._model = camera_type
|
self._model = camera_type
|
||||||
self._netatmo_type = TYPE_SECURITY
|
self._netatmo_type = TYPE_SECURITY
|
||||||
self._device_name: str = self._data.get_camera(camera_id)["name"]
|
self._device_name: str = self._data.get_camera(camera_id)["name"]
|
||||||
self._attr_name = f"{MANUFACTURER} {self._device_name}"
|
|
||||||
self._is_on = False
|
self._is_on = False
|
||||||
self._attr_unique_id = f"{self._id}-light"
|
self._attr_unique_id = f"{self._id}-light"
|
||||||
|
|
||||||
|
@ -123,7 +122,7 @@ class NetatmoLight(NetatmoBase, LightEntity):
|
||||||
"""Return data for this entity."""
|
"""Return data for this entity."""
|
||||||
return cast(
|
return cast(
|
||||||
pyatmo.AsyncCameraData,
|
pyatmo.AsyncCameraData,
|
||||||
self.data_handler.data[self._data_classes[0]["name"]],
|
self.data_handler.data[self._publishers[0]["name"]],
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
"""Base class for Netatmo entities."""
|
"""Base class for Netatmo entities."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from homeassistant.const import ATTR_ATTRIBUTION
|
from homeassistant.const import ATTR_ATTRIBUTION
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
@ -23,7 +25,7 @@ class NetatmoBase(Entity):
|
||||||
def __init__(self, data_handler: NetatmoDataHandler) -> None:
|
def __init__(self, data_handler: NetatmoDataHandler) -> None:
|
||||||
"""Set up Netatmo entity base."""
|
"""Set up Netatmo entity base."""
|
||||||
self.data_handler = data_handler
|
self.data_handler = data_handler
|
||||||
self._data_classes: list[dict] = []
|
self._publishers: list[dict[str, Any]] = []
|
||||||
|
|
||||||
self._device_name: str = ""
|
self._device_name: str = ""
|
||||||
self._id: str = ""
|
self._id: str = ""
|
||||||
|
@ -35,11 +37,11 @@ class NetatmoBase(Entity):
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Entity created."""
|
"""Entity created."""
|
||||||
for data_class in self._data_classes:
|
for data_class in self._publishers:
|
||||||
signal_name = data_class[SIGNAL_NAME]
|
signal_name = data_class[SIGNAL_NAME]
|
||||||
|
|
||||||
if "home_id" in data_class:
|
if "home_id" in data_class:
|
||||||
await self.data_handler.register_data_class(
|
await self.data_handler.subscribe(
|
||||||
data_class["name"],
|
data_class["name"],
|
||||||
signal_name,
|
signal_name,
|
||||||
self.async_update_callback,
|
self.async_update_callback,
|
||||||
|
@ -47,7 +49,7 @@ class NetatmoBase(Entity):
|
||||||
)
|
)
|
||||||
|
|
||||||
elif data_class["name"] == PUBLICDATA_DATA_CLASS_NAME:
|
elif data_class["name"] == PUBLICDATA_DATA_CLASS_NAME:
|
||||||
await self.data_handler.register_data_class(
|
await self.data_handler.subscribe(
|
||||||
data_class["name"],
|
data_class["name"],
|
||||||
signal_name,
|
signal_name,
|
||||||
self.async_update_callback,
|
self.async_update_callback,
|
||||||
|
@ -58,13 +60,13 @@ class NetatmoBase(Entity):
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
await self.data_handler.register_data_class(
|
await self.data_handler.subscribe(
|
||||||
data_class["name"], signal_name, self.async_update_callback
|
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:
|
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)
|
registry = dr.async_get(self.hass)
|
||||||
if device := registry.async_get_device({(DOMAIN, self._id)}):
|
if device := registry.async_get_device({(DOMAIN, self._id)}):
|
||||||
|
@ -76,8 +78,8 @@ class NetatmoBase(Entity):
|
||||||
"""Run when entity will be removed from hass."""
|
"""Run when entity will be removed from hass."""
|
||||||
await super().async_will_remove_from_hass()
|
await super().async_will_remove_from_hass()
|
||||||
|
|
||||||
for data_class in self._data_classes:
|
for data_class in self._publishers:
|
||||||
await self.data_handler.unregister_data_class(
|
await self.data_handler.unsubscribe(
|
||||||
data_class[SIGNAL_NAME], self.async_update_callback
|
data_class[SIGNAL_NAME], self.async_update_callback
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ async def async_setup_entry(
|
||||||
for home_id in climate_topology.home_ids:
|
for home_id in climate_topology.home_ids:
|
||||||
signal_name = f"{CLIMATE_STATE_CLASS_NAME}-{home_id}"
|
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
|
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._home = self._climate_state.homes[self._home_id]
|
||||||
|
|
||||||
self._data_classes.extend(
|
self._publishers.extend(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": CLIMATE_TOPOLOGY_CLASS_NAME,
|
"name": CLIMATE_TOPOLOGY_CLASS_NAME,
|
||||||
|
|
|
@ -41,7 +41,6 @@ from .const import (
|
||||||
CONF_WEATHER_AREAS,
|
CONF_WEATHER_AREAS,
|
||||||
DATA_HANDLER,
|
DATA_HANDLER,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
MANUFACTURER,
|
|
||||||
NETATMO_CREATE_BATTERY,
|
NETATMO_CREATE_BATTERY,
|
||||||
SIGNAL_NAME,
|
SIGNAL_NAME,
|
||||||
TYPE_WEATHER,
|
TYPE_WEATHER,
|
||||||
|
@ -422,7 +421,7 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
await data_handler.register_data_class(
|
await data_handler.subscribe(
|
||||||
PUBLICDATA_DATA_CLASS_NAME,
|
PUBLICDATA_DATA_CLASS_NAME,
|
||||||
signal_name,
|
signal_name,
|
||||||
None,
|
None,
|
||||||
|
@ -487,9 +486,7 @@ class NetatmoSensor(NetatmoBase, SensorEntity):
|
||||||
super().__init__(data_handler)
|
super().__init__(data_handler)
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
|
|
||||||
self._data_classes.append(
|
self._publishers.append({"name": data_class_name, SIGNAL_NAME: data_class_name})
|
||||||
{"name": data_class_name, SIGNAL_NAME: data_class_name}
|
|
||||||
)
|
|
||||||
|
|
||||||
self._id = module_info["_id"]
|
self._id = module_info["_id"]
|
||||||
self._station_id = module_info.get("main_device", self._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'])}"
|
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._model = device["type"]
|
||||||
self._netatmo_type = TYPE_WEATHER
|
self._netatmo_type = TYPE_WEATHER
|
||||||
self._attr_unique_id = f"{self._id}-{description.key}"
|
self._attr_unique_id = f"{self._id}-{description.key}"
|
||||||
|
@ -517,7 +514,7 @@ class NetatmoSensor(NetatmoBase, SensorEntity):
|
||||||
"""Return data for this entity."""
|
"""Return data for this entity."""
|
||||||
return cast(
|
return cast(
|
||||||
pyatmo.AsyncWeatherStationData,
|
pyatmo.AsyncWeatherStationData,
|
||||||
self.data_handler.data[self._data_classes[0]["name"]],
|
self.data_handler.data[self._publishers[0]["name"]],
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -598,7 +595,7 @@ class NetatmoClimateBatterySensor(NetatmoBase, SensorEntity):
|
||||||
self._id = netatmo_device.parent_id
|
self._id = netatmo_device.parent_id
|
||||||
self._attr_name = f"{self._module.name} {self.entity_description.name}"
|
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._room_id = self._module.room_id
|
||||||
self._model = getattr(self._module.device_type, "value")
|
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._signal_name = f"{PUBLICDATA_DATA_CLASS_NAME}-{area.uuid}"
|
||||||
|
|
||||||
self._data_classes.append(
|
self._publishers.append(
|
||||||
{
|
{
|
||||||
"name": PUBLICDATA_DATA_CLASS_NAME,
|
"name": PUBLICDATA_DATA_CLASS_NAME,
|
||||||
"lat_ne": area.lat_ne,
|
"lat_ne": area.lat_ne,
|
||||||
|
@ -751,7 +748,7 @@ class NetatmoPublicSensor(NetatmoBase, SensorEntity):
|
||||||
self._area_name = area.area_name
|
self._area_name = area.area_name
|
||||||
self._id = self._area_name
|
self._id = self._area_name
|
||||||
self._device_name = f"{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._show_on_map = area.show_on_map
|
||||||
self._attr_unique_id = (
|
self._attr_unique_id = (
|
||||||
f"{self._device_name.replace(' ', '-')}-{description.key}"
|
f"{self._device_name.replace(' ', '-')}-{description.key}"
|
||||||
|
@ -788,13 +785,13 @@ class NetatmoPublicSensor(NetatmoBase, SensorEntity):
|
||||||
if self.area == area:
|
if self.area == area:
|
||||||
return
|
return
|
||||||
|
|
||||||
await self.data_handler.unregister_data_class(
|
await self.data_handler.unsubscribe(
|
||||||
self._signal_name, self.async_update_callback
|
self._signal_name, self.async_update_callback
|
||||||
)
|
)
|
||||||
|
|
||||||
self.area = area
|
self.area = area
|
||||||
self._signal_name = f"{PUBLICDATA_DATA_CLASS_NAME}-{area.uuid}"
|
self._signal_name = f"{PUBLICDATA_DATA_CLASS_NAME}-{area.uuid}"
|
||||||
self._data_classes = [
|
self._publishers = [
|
||||||
{
|
{
|
||||||
"name": PUBLICDATA_DATA_CLASS_NAME,
|
"name": PUBLICDATA_DATA_CLASS_NAME,
|
||||||
"lat_ne": area.lat_ne,
|
"lat_ne": area.lat_ne,
|
||||||
|
@ -807,7 +804,7 @@ class NetatmoPublicSensor(NetatmoBase, SensorEntity):
|
||||||
]
|
]
|
||||||
self._mode = area.mode
|
self._mode = area.mode
|
||||||
self._show_on_map = area.show_on_map
|
self._show_on_map = area.show_on_map
|
||||||
await self.data_handler.register_data_class(
|
await self.data_handler.subscribe(
|
||||||
PUBLICDATA_DATA_CLASS_NAME,
|
PUBLICDATA_DATA_CLASS_NAME,
|
||||||
self._signal_name,
|
self._signal_name,
|
||||||
self.async_update_callback,
|
self.async_update_callback,
|
||||||
|
|
|
@ -32,8 +32,8 @@ async def test_setup_component_with_webhook(hass, config_entry, netatmo_auth):
|
||||||
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
webhook_id = config_entry.data[CONF_WEBHOOK_ID]
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
camera_entity_indoor = "camera.netatmo_hall"
|
camera_entity_indoor = "camera.hall"
|
||||||
camera_entity_outdoor = "camera.netatmo_garden"
|
camera_entity_outdoor = "camera.garden"
|
||||||
assert hass.states.get(camera_entity_indoor).state == "streaming"
|
assert hass.states.get(camera_entity_indoor).state == "streaming"
|
||||||
response = {
|
response = {
|
||||||
"event_type": "off",
|
"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:
|
with patch("pyatmo.camera.AsyncCameraData.async_set_state") as mock_set_state:
|
||||||
await hass.services.async_call(
|
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()
|
await hass.async_block_till_done()
|
||||||
mock_set_state.assert_called_once_with(
|
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:
|
with patch("pyatmo.camera.AsyncCameraData.async_set_state") as mock_set_state:
|
||||||
await hass.services.async_call(
|
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()
|
await hass.async_block_till_done()
|
||||||
mock_set_state.assert_called_once_with(
|
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"
|
uri = "http://192.168.0.123/678460a0d47e5618699fb31169e2b47d"
|
||||||
stream_uri = uri + "/live/files/high/index.m3u8"
|
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)
|
cam = hass.states.get(camera_entity_indoor)
|
||||||
|
|
||||||
assert cam is not None
|
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,,"
|
"6d278460699e56180d47ab47169efb31/MpEylTU2MDYzNjRVD-LJxUnIndumKzLboeAwMDqTTw,,"
|
||||||
)
|
)
|
||||||
stream_uri = uri + "/live/files/high/index.m3u8"
|
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)
|
cam = hass.states.get(camera_entity_indoor)
|
||||||
|
|
||||||
assert cam is not None
|
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()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"entity_id": "camera.netatmo_hall",
|
"entity_id": "camera.hall",
|
||||||
"person": "Richard Doe",
|
"person": "Richard Doe",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ async def test_service_set_person_away(hass, config_entry, netatmo_auth):
|
||||||
)
|
)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"entity_id": "camera.netatmo_hall",
|
"entity_id": "camera.hall",
|
||||||
}
|
}
|
||||||
|
|
||||||
with patch(
|
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()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"entity_id": "camera.netatmo_hall",
|
"entity_id": "camera.hall",
|
||||||
"person": "Batman",
|
"person": "Batman",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,7 +259,7 @@ async def test_service_set_persons_home_invalid_person(
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"entity_id": "camera.netatmo_hall",
|
"entity_id": "camera.hall",
|
||||||
"persons": "Batman",
|
"persons": "Batman",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +285,7 @@ async def test_service_set_persons_home(hass, config_entry, netatmo_auth):
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"entity_id": "camera.netatmo_hall",
|
"entity_id": "camera.hall",
|
||||||
"persons": "John Doe",
|
"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()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"entity_id": "camera.netatmo_garden",
|
"entity_id": "camera.garden",
|
||||||
"camera_light_mode": "on",
|
"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.config_entries.async_setup(config_entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
camera_entity_indoor = "camera.netatmo_hall"
|
camera_entity_indoor = "camera.hall"
|
||||||
|
|
||||||
with pytest.raises(Exception) as excinfo:
|
with pytest.raises(Exception) as excinfo:
|
||||||
await camera.async_get_image(hass, camera_entity_indoor)
|
await camera.async_get_image(hass, camera_entity_indoor)
|
||||||
|
|
|
@ -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 simulate_webhook(hass, webhook_id, FAKE_WEBHOOK_ACTIVATION)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
light_entity = "light.netatmo_garden"
|
light_entity = "light.garden"
|
||||||
assert hass.states.get(light_entity).state == "unavailable"
|
assert hass.states.get(light_entity).state == "unavailable"
|
||||||
|
|
||||||
# Trigger light mode change
|
# Trigger light mode change
|
||||||
|
|
|
@ -17,7 +17,7 @@ async def test_weather_sensor(hass, config_entry, netatmo_auth):
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
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}temperature").state == "24.6"
|
||||||
assert hass.states.get(f"{prefix}humidity").state == "36"
|
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
|
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}temperature").state == "27.4"
|
||||||
assert hass.states.get(f"{prefix}humidity").state == "76"
|
assert hass.states.get(f"{prefix}humidity").state == "76"
|
||||||
assert hass.states.get(f"{prefix}pressure").state == "1014.4"
|
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}temperature").state == "22.7"
|
||||||
assert hass.states.get(f"{prefix}humidity").state == "63.2"
|
assert hass.states.get(f"{prefix}humidity").state == "63.2"
|
||||||
|
|
Loading…
Add table
Reference in a new issue