Add more base entities to netatmo (#107862)
* Rename netatmo base entity file * Add more Netatmo base entities * Add more Netatmo base entities * Add more Netatmo base entities * Add more Netatmo base entities * Apply suggestions from code review * Add more Netatmo base entities * Add snapshot tests to Netatmo platforms * Add snapshot tests to Netatmo platforms * Fix snapshots * Fix tests * Update snapshots * Add fans * Add fans * Update homeassistant/components/netatmo/select.py Co-authored-by: Tobias Sauerwein <cgtobi@users.noreply.github.com> * Add snapshot tests to Netatmo platforms * Update snapshots * minor clean up * Fix tests * Fix * Fix * Fix * Move dot split to weather station sensors --------- Co-authored-by: Tobias Sauerwein <cgtobi@users.noreply.github.com> Co-authored-by: Tobias Sauerwein <cgtobi@gmail.com>
This commit is contained in:
parent
9f2fa7ec19
commit
021eed66f3
18 changed files with 497 additions and 525 deletions
|
@ -40,7 +40,7 @@ from .const import (
|
|||
WEBHOOK_PUSH_TYPE,
|
||||
)
|
||||
from .data_handler import EVENT, HOME, SIGNAL_NAME, NetatmoDevice
|
||||
from .entity import NetatmoBaseEntity
|
||||
from .entity import NetatmoModuleEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -80,12 +80,16 @@ async def async_setup_entry(
|
|||
)
|
||||
|
||||
|
||||
class NetatmoCamera(NetatmoBaseEntity, Camera):
|
||||
class NetatmoCamera(NetatmoModuleEntity, Camera):
|
||||
"""Representation of a Netatmo camera."""
|
||||
|
||||
_attr_brand = MANUFACTURER
|
||||
_attr_has_entity_name = True
|
||||
_attr_supported_features = CameraEntityFeature.STREAM
|
||||
_attr_configuration_url = CONF_URL_SECURITY
|
||||
device: NaModules.Camera
|
||||
_quality = DEFAULT_QUALITY
|
||||
_monitoring: bool | None = None
|
||||
_attr_name = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -93,30 +97,22 @@ class NetatmoCamera(NetatmoBaseEntity, Camera):
|
|||
) -> None:
|
||||
"""Set up for access to the Netatmo camera images."""
|
||||
Camera.__init__(self)
|
||||
super().__init__(netatmo_device.data_handler)
|
||||
super().__init__(netatmo_device)
|
||||
|
||||
self._camera = cast(NaModules.Camera, netatmo_device.device)
|
||||
self._id = self._camera.entity_id
|
||||
self._home_id = self._camera.home.entity_id
|
||||
self._device_name = self._camera.name
|
||||
self._model = self._camera.device_type
|
||||
self._config_url = CONF_URL_SECURITY
|
||||
self._attr_unique_id = f"{self._id}-{self._model}"
|
||||
self._quality = DEFAULT_QUALITY
|
||||
self._monitoring: bool | None = None
|
||||
self._attr_unique_id = f"{netatmo_device.device.entity_id}-{self.device_type}"
|
||||
self._light_state = None
|
||||
|
||||
self._publishers.extend(
|
||||
[
|
||||
{
|
||||
"name": HOME,
|
||||
"home_id": self._home_id,
|
||||
SIGNAL_NAME: f"{HOME}-{self._home_id}",
|
||||
"home_id": self.home.entity_id,
|
||||
SIGNAL_NAME: f"{HOME}-{self.home.entity_id}",
|
||||
},
|
||||
{
|
||||
"name": EVENT,
|
||||
"home_id": self._home_id,
|
||||
SIGNAL_NAME: f"{EVENT}-{self._home_id}",
|
||||
"home_id": self.home.entity_id,
|
||||
SIGNAL_NAME: f"{EVENT}-{self.home.entity_id}",
|
||||
},
|
||||
]
|
||||
)
|
||||
|
@ -134,7 +130,7 @@ class NetatmoCamera(NetatmoBaseEntity, Camera):
|
|||
)
|
||||
)
|
||||
|
||||
self.hass.data[DOMAIN][DATA_CAMERAS][self._id] = self._device_name
|
||||
self.hass.data[DOMAIN][DATA_CAMERAS][self.device.entity_id] = self.device.name
|
||||
|
||||
@callback
|
||||
def handle_event(self, event: dict) -> None:
|
||||
|
@ -144,7 +140,10 @@ class NetatmoCamera(NetatmoBaseEntity, Camera):
|
|||
if not data.get("camera_id"):
|
||||
return
|
||||
|
||||
if data["home_id"] == self._home_id and data["camera_id"] == self._id:
|
||||
if (
|
||||
data["home_id"] == self.home.entity_id
|
||||
and data["camera_id"] == self.device.entity_id
|
||||
):
|
||||
if data[WEBHOOK_PUSH_TYPE] in ("NACamera-off", "NACamera-disconnection"):
|
||||
self._attr_is_streaming = False
|
||||
self._monitoring = False
|
||||
|
@ -168,7 +167,7 @@ class NetatmoCamera(NetatmoBaseEntity, Camera):
|
|||
) -> bytes | None:
|
||||
"""Return a still image response from the camera."""
|
||||
try:
|
||||
return cast(bytes, await self._camera.async_get_live_snapshot())
|
||||
return cast(bytes, await self.device.async_get_live_snapshot())
|
||||
except (
|
||||
aiohttp.ClientPayloadError,
|
||||
aiohttp.ContentTypeError,
|
||||
|
@ -183,50 +182,50 @@ class NetatmoCamera(NetatmoBaseEntity, Camera):
|
|||
def supported_features(self) -> CameraEntityFeature:
|
||||
"""Return supported features."""
|
||||
supported_features = CameraEntityFeature.ON_OFF
|
||||
if self._model != "NDB":
|
||||
if self.device_type != "NDB":
|
||||
supported_features |= CameraEntityFeature.STREAM
|
||||
return supported_features
|
||||
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn off camera."""
|
||||
await self._camera.async_monitoring_off()
|
||||
await self.device.async_monitoring_off()
|
||||
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn on camera."""
|
||||
await self._camera.async_monitoring_on()
|
||||
await self.device.async_monitoring_on()
|
||||
|
||||
async def stream_source(self) -> str:
|
||||
"""Return the stream source."""
|
||||
if self._camera.is_local:
|
||||
await self._camera.async_update_camera_urls()
|
||||
if self.device.is_local:
|
||||
await self.device.async_update_camera_urls()
|
||||
|
||||
if self._camera.local_url:
|
||||
return f"{self._camera.local_url}/live/files/{self._quality}/index.m3u8"
|
||||
return f"{self._camera.vpn_url}/live/files/{self._quality}/index.m3u8"
|
||||
if self.device.local_url:
|
||||
return f"{self.device.local_url}/live/files/{self._quality}/index.m3u8"
|
||||
return f"{self.device.vpn_url}/live/files/{self._quality}/index.m3u8"
|
||||
|
||||
@callback
|
||||
def async_update_callback(self) -> None:
|
||||
"""Update the entity's state."""
|
||||
self._attr_is_on = self._camera.alim_status is not None
|
||||
self._attr_available = self._camera.alim_status is not None
|
||||
self._attr_is_on = self.device.alim_status is not None
|
||||
self._attr_available = self.device.alim_status is not None
|
||||
|
||||
if self._camera.monitoring is not None:
|
||||
self._attr_is_streaming = self._camera.monitoring
|
||||
self._attr_motion_detection_enabled = self._camera.monitoring
|
||||
if self.device.monitoring is not None:
|
||||
self._attr_is_streaming = self.device.monitoring
|
||||
self._attr_motion_detection_enabled = self.device.monitoring
|
||||
|
||||
self.hass.data[DOMAIN][DATA_EVENTS][self._id] = self.process_events(
|
||||
self._camera.events
|
||||
self.hass.data[DOMAIN][DATA_EVENTS][self.device.entity_id] = (
|
||||
self.process_events(self.device.events)
|
||||
)
|
||||
|
||||
self._attr_extra_state_attributes.update(
|
||||
{
|
||||
"id": self._id,
|
||||
"id": self.device.entity_id,
|
||||
"monitoring": self._monitoring,
|
||||
"sd_status": self._camera.sd_status,
|
||||
"alim_status": self._camera.alim_status,
|
||||
"is_local": self._camera.is_local,
|
||||
"vpn_url": self._camera.vpn_url,
|
||||
"local_url": self._camera.local_url,
|
||||
"sd_status": self.device.sd_status,
|
||||
"alim_status": self.device.alim_status,
|
||||
"is_local": self.device.is_local,
|
||||
"vpn_url": self.device.vpn_url,
|
||||
"local_url": self.device.local_url,
|
||||
"light_state": self._light_state,
|
||||
}
|
||||
)
|
||||
|
@ -249,9 +248,9 @@ class NetatmoCamera(NetatmoBaseEntity, Camera):
|
|||
|
||||
def get_video_url(self, video_id: str) -> str:
|
||||
"""Get video url."""
|
||||
if self._camera.is_local:
|
||||
return f"{self._camera.local_url}/vod/{video_id}/files/{self._quality}/index.m3u8"
|
||||
return f"{self._camera.vpn_url}/vod/{video_id}/files/{self._quality}/index.m3u8"
|
||||
if self.device.is_local:
|
||||
return f"{self.device.local_url}/vod/{video_id}/files/{self._quality}/index.m3u8"
|
||||
return f"{self.device.vpn_url}/vod/{video_id}/files/{self._quality}/index.m3u8"
|
||||
|
||||
def fetch_person_ids(self, persons: list[str | None]) -> list[str]:
|
||||
"""Fetch matching person ids for given list of persons."""
|
||||
|
@ -260,7 +259,7 @@ class NetatmoCamera(NetatmoBaseEntity, Camera):
|
|||
|
||||
for person in persons:
|
||||
person_id = None
|
||||
for pid, data in self._camera.home.persons.items():
|
||||
for pid, data in self.home.persons.items():
|
||||
if data.pseudo == person:
|
||||
person_ids.append(pid)
|
||||
person_id = pid
|
||||
|
@ -279,7 +278,7 @@ class NetatmoCamera(NetatmoBaseEntity, Camera):
|
|||
persons = kwargs.get(ATTR_PERSONS, [])
|
||||
person_ids = self.fetch_person_ids(persons)
|
||||
|
||||
await self._camera.home.async_set_persons_home(person_ids=person_ids)
|
||||
await self.home.async_set_persons_home(person_ids=person_ids)
|
||||
_LOGGER.debug("Set %s as at home", persons)
|
||||
|
||||
async def _service_set_person_away(self, **kwargs: Any) -> None:
|
||||
|
@ -288,7 +287,7 @@ class NetatmoCamera(NetatmoBaseEntity, Camera):
|
|||
person_ids = self.fetch_person_ids([person] if person else [])
|
||||
person_id = next(iter(person_ids), None)
|
||||
|
||||
await self._camera.home.async_set_persons_away(
|
||||
await self.home.async_set_persons_away(
|
||||
person_id=person_id,
|
||||
)
|
||||
|
||||
|
@ -299,11 +298,11 @@ class NetatmoCamera(NetatmoBaseEntity, Camera):
|
|||
|
||||
async def _service_set_camera_light(self, **kwargs: Any) -> None:
|
||||
"""Service to set light mode."""
|
||||
if not isinstance(self._camera, NaModules.netatmo.NOC):
|
||||
if not isinstance(self.device, NaModules.netatmo.NOC):
|
||||
raise HomeAssistantError(
|
||||
f"{self._model} <{self._device_name}> does not have a floodlight"
|
||||
f"{self.device_type} <{self.device.name}> does not have a floodlight"
|
||||
)
|
||||
|
||||
mode = str(kwargs.get(ATTR_CAMERA_LIGHT_MODE))
|
||||
_LOGGER.debug("Turn %s camera light for '%s'", mode, self._attr_name)
|
||||
await self._camera.async_set_floodlight_state(mode)
|
||||
await self.device.async_set_floodlight_state(mode)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue