mirror of
https://github.com/home-assistant/core.git
synced 2025-07-14 16:57:10 +00:00
Add Guest WiFi QR-Code image entity to AVM Fritz!Tools (#95282)
This commit is contained in:
parent
aaa4ee79b8
commit
4daacf9c4b
@ -393,6 +393,7 @@ omit =
|
||||
homeassistant/components/freebox/switch.py
|
||||
homeassistant/components/fritz/common.py
|
||||
homeassistant/components/fritz/device_tracker.py
|
||||
homeassistant/components/fritz/image.py
|
||||
homeassistant/components/fritz/services.py
|
||||
homeassistant/components/fritz/switch.py
|
||||
homeassistant/components/fritzbox_callmonitor/__init__.py
|
||||
|
@ -31,6 +31,7 @@ PLATFORMS = [
|
||||
Platform.BUTTON,
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.DEVICE_TRACKER,
|
||||
Platform.IMAGE,
|
||||
Platform.SENSOR,
|
||||
Platform.SWITCH,
|
||||
Platform.UPDATE,
|
||||
|
90
homeassistant/components/fritz/image.py
Normal file
90
homeassistant/components/fritz/image.py
Normal file
@ -0,0 +1,90 @@
|
||||
"""FRITZ image integration."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from io import BytesIO
|
||||
import logging
|
||||
|
||||
from homeassistant.components.image import ImageEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import dt as dt_util, slugify
|
||||
|
||||
from .common import AvmWrapper, FritzBoxBaseEntity
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up guest WiFi QR code for device."""
|
||||
avm_wrapper: AvmWrapper = hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
guest_wifi_info = await hass.async_add_executor_job(
|
||||
avm_wrapper.fritz_guest_wifi.get_info
|
||||
)
|
||||
|
||||
if not guest_wifi_info.get("NewEnable"):
|
||||
return
|
||||
|
||||
async_add_entities(
|
||||
[
|
||||
FritzGuestWifiQRImage(
|
||||
avm_wrapper, entry.title, guest_wifi_info["NewSSID"], hass
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class FritzGuestWifiQRImage(FritzBoxBaseEntity, ImageEntity):
|
||||
"""Implementation of the FritzBox guest wifi QR code image entity."""
|
||||
|
||||
_attr_content_type = "image/png"
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
avm_wrapper: AvmWrapper,
|
||||
device_friendly_name: str,
|
||||
ssid: str,
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Initialize the image entity."""
|
||||
self._attr_name = ssid
|
||||
self._attr_unique_id = slugify(f"{avm_wrapper.unique_id}-{ssid}-qr-code")
|
||||
self._current_qr_bytes: bytes | None = None
|
||||
super().__init__(avm_wrapper, device_friendly_name)
|
||||
ImageEntity.__init__(self, hass)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Set the update time."""
|
||||
self._attr_image_last_updated = dt_util.utcnow()
|
||||
|
||||
async def async_image(self) -> bytes:
|
||||
"""Return bytes of image."""
|
||||
qr_stream: BytesIO = await self.hass.async_add_executor_job(
|
||||
self._avm_wrapper.fritz_guest_wifi.get_wifi_qr_code, "png"
|
||||
)
|
||||
qr_bytes = qr_stream.getvalue()
|
||||
|
||||
_LOGGER.debug("fetched %s bytes", len(qr_bytes))
|
||||
|
||||
if self._current_qr_bytes is None:
|
||||
self._current_qr_bytes = qr_bytes
|
||||
return qr_bytes
|
||||
|
||||
if self._current_qr_bytes != qr_bytes:
|
||||
dt_now = dt_util.utcnow()
|
||||
_LOGGER.debug("qr code has changed, reset image last updated property")
|
||||
self._attr_image_last_updated = dt_now
|
||||
self._current_qr_bytes = qr_bytes
|
||||
self.async_write_ha_state()
|
||||
|
||||
return qr_bytes
|
@ -7,7 +7,7 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/fritz",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["fritzconnection"],
|
||||
"requirements": ["fritzconnection==1.12.0", "xmltodict==0.13.0"],
|
||||
"requirements": ["fritzconnection[qr]==1.12.0", "xmltodict==0.13.0"],
|
||||
"ssdp": [
|
||||
{
|
||||
"st": "urn:schemas-upnp-org:device:fritzbox:1"
|
||||
|
@ -7,5 +7,5 @@
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["fritzconnection"],
|
||||
"requirements": ["fritzconnection==1.12.0"]
|
||||
"requirements": ["fritzconnection[qr]==1.12.0"]
|
||||
}
|
||||
|
@ -818,7 +818,7 @@ freesms==0.2.0
|
||||
|
||||
# homeassistant.components.fritz
|
||||
# homeassistant.components.fritzbox_callmonitor
|
||||
fritzconnection==1.12.0
|
||||
fritzconnection[qr]==1.12.0
|
||||
|
||||
# homeassistant.components.google_translate
|
||||
gTTS==2.2.4
|
||||
|
@ -637,7 +637,7 @@ freebox-api==1.1.0
|
||||
|
||||
# homeassistant.components.fritz
|
||||
# homeassistant.components.fritzbox_callmonitor
|
||||
fritzconnection==1.12.0
|
||||
fritzconnection[qr]==1.12.0
|
||||
|
||||
# homeassistant.components.google_translate
|
||||
gTTS==2.2.4
|
||||
|
@ -195,7 +195,6 @@ MOCK_FB_SERVICES: dict[str, dict] = {
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
MOCK_MESH_DATA = {
|
||||
"schema_version": "1.9",
|
||||
"nodes": [
|
||||
|
90
tests/components/fritz/test_image.py
Normal file
90
tests/components/fritz/test_image.py
Normal file
@ -0,0 +1,90 @@
|
||||
"""Tests for Fritz!Tools image platform."""
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.fritz.const import DOMAIN
|
||||
from homeassistant.components.image import DOMAIN as IMAGE_DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_registry import async_get as async_get_entity_registry
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .const import MOCK_FB_SERVICES, MOCK_USER_DATA
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.typing import ClientSessionGenerator
|
||||
|
||||
GUEST_WIFI_ENABLED: dict[str, dict] = {
|
||||
"WLANConfiguration0": {
|
||||
"GetInfo": {
|
||||
"NewEnable": True,
|
||||
"NewSSID": "HomeWifi",
|
||||
}
|
||||
},
|
||||
"WLANConfiguration1": {
|
||||
"GetInfo": {
|
||||
"NewEnable": True,
|
||||
"NewSSID": "GuestWifi",
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
GUEST_WIFI_DISABLED: dict[str, dict] = {
|
||||
"WLANConfiguration0": {
|
||||
"GetInfo": {
|
||||
"NewEnable": True,
|
||||
"NewSSID": "HomeWifi",
|
||||
}
|
||||
},
|
||||
"WLANConfiguration1": {
|
||||
"GetInfo": {
|
||||
"NewEnable": False,
|
||||
"NewSSID": "GuestWifi",
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("fc_data"), [({**MOCK_FB_SERVICES, **GUEST_WIFI_ENABLED})])
|
||||
async def test_image_entities_initialized(
|
||||
hass: HomeAssistant,
|
||||
hass_client: ClientSessionGenerator,
|
||||
fc_class_mock,
|
||||
fh_class_mock,
|
||||
) -> None:
|
||||
"""Test image entities."""
|
||||
|
||||
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_DATA)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
assert entry.state == ConfigEntryState.LOADED
|
||||
|
||||
images = hass.states.async_all(IMAGE_DOMAIN)
|
||||
assert len(images) == 1
|
||||
assert images[0].name == "Mock Title GuestWifi"
|
||||
|
||||
entity_registry = async_get_entity_registry(hass)
|
||||
entity_entry = entity_registry.async_get("image.mock_title_guestwifi")
|
||||
|
||||
assert entity_entry.unique_id == "1c_ed_6f_12_34_11_guestwifi_qr_code"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("fc_data"), [({**MOCK_FB_SERVICES, **GUEST_WIFI_DISABLED})])
|
||||
async def test_image_guest_wifi_disabled(
|
||||
hass: HomeAssistant,
|
||||
hass_client: ClientSessionGenerator,
|
||||
fc_class_mock,
|
||||
fh_class_mock,
|
||||
) -> None:
|
||||
"""Test image entities."""
|
||||
|
||||
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_DATA)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
assert entry.state == ConfigEntryState.LOADED
|
||||
|
||||
images = hass.states.async_all(IMAGE_DOMAIN)
|
||||
assert len(images) == 0
|
Loading…
x
Reference in New Issue
Block a user