Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .strict-typing
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ homeassistant.components.simplisafe.*
homeassistant.components.siren.*
homeassistant.components.skybell.*
homeassistant.components.slack.*
homeassistant.components.sleep_as_android.*
homeassistant.components.sleepiq.*
homeassistant.components.smhi.*
homeassistant.components.smlight.*
Expand Down
2 changes: 2 additions & 0 deletions CODEOWNERS

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions homeassistant/components/foscam/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: FoscamConfigEntry) -> bo
verbose=False,
)
coordinator = FoscamCoordinator(hass, entry, session)

await coordinator.async_config_entry_first_refresh()

entry.runtime_data = coordinator
Expand Down Expand Up @@ -89,7 +88,7 @@ def update_unique_id(entry):


async def async_migrate_entities(hass: HomeAssistant, entry: FoscamConfigEntry) -> None:
"""Migrate old entry."""
"""Migrate old entries to support config_entry_id-based unique IDs."""

@callback
def _update_unique_id(
Expand Down
13 changes: 13 additions & 0 deletions homeassistant/components/foscam/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,16 @@

SERVICE_PTZ = "ptz"
SERVICE_PTZ_PRESET = "ptz_preset"

SUPPORTED_SWITCHES = [
"flip_switch",
"mirror_switch",
"ir_switch",
"sleep_switch",
"white_light_switch",
"siren_alarm_switch",
"turn_off_volume_switch",
"light_status_switch",
"hdr_switch",
"wdr_switch",
]
128 changes: 106 additions & 22 deletions homeassistant/components/foscam/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""The foscam coordinator object."""

import asyncio
from dataclasses import dataclass
from datetime import timedelta
from typing import Any

from libpyfoscamcgi import FoscamCamera

Expand All @@ -15,9 +15,35 @@
type FoscamConfigEntry = ConfigEntry[FoscamCoordinator]


class FoscamCoordinator(DataUpdateCoordinator[dict[str, Any]]):
@dataclass
class FoscamDeviceInfo:
"""A data class representing the current state and configuration of a Foscam camera device."""

dev_info: dict
product_info: dict

is_open_ir: bool
is_flip: bool
is_mirror: bool

is_asleep: dict
is_open_white_light: bool
is_siren_alarm: bool

volume: int
speak_volume: int
is_turn_off_volume: bool
is_turn_off_light: bool

is_open_wdr: bool | None = None
is_open_hdr: bool | None = None


class FoscamCoordinator(DataUpdateCoordinator[FoscamDeviceInfo]):
"""Foscam coordinator."""

config_entry: FoscamConfigEntry

def __init__(
self,
hass: HomeAssistant,
Expand All @@ -34,24 +60,82 @@ def __init__(
)
self.session = session

async def _async_update_data(self) -> dict[str, Any]:
"""Fetch data from API endpoint."""
def gather_all_configs(self) -> FoscamDeviceInfo:
"""Get all Foscam configurations."""
ret_dev_info, dev_info = self.session.get_dev_info()
dev_info = dev_info if ret_dev_info == 0 else {}

ret_product_info, product_info = self.session.get_product_all_info()
product_info = product_info if ret_product_info == 0 else {}

ret_ir, infra_led_config = self.session.get_infra_led_config()
is_open_ir = infra_led_config["mode"] == "1" if ret_ir == 0 else False

ret_mf, mirror_flip_setting = self.session.get_mirror_and_flip_setting()
is_flip = mirror_flip_setting["isFlip"] == "1" if ret_mf == 0 else False
is_mirror = mirror_flip_setting["isMirror"] == "1" if ret_mf == 0 else False

ret_sleep, sleep_setting = self.session.is_asleep()
is_asleep = {"supported": ret_sleep == 0, "status": bool(int(sleep_setting))}

ret_wl, is_open_white_light = self.session.getWhiteLightBrightness()
is_open_white_light_val = (
is_open_white_light["enable"] == "1" if ret_wl == 0 else False
)

ret_sc, is_siren_alarm = self.session.getSirenConfig()
is_siren_alarm_val = (
is_siren_alarm["sirenEnable"] == "1" if ret_sc == 0 else False
)

ret_vol, volume = self.session.getAudioVolume()
volume_val = int(volume["volume"]) if ret_vol == 0 else 0

ret_sv, speak_volume = self.session.getSpeakVolume()
speak_volume_val = int(speak_volume["SpeakVolume"]) if ret_sv == 0 else 0

ret_ves, is_turn_off_volume = self.session.getVoiceEnableState()
is_turn_off_volume_val = not (
ret_ves == 0 and is_turn_off_volume["isEnable"] == "1"
)

async with asyncio.timeout(30):
data = {}
ret, dev_info = await self.hass.async_add_executor_job(
self.session.get_dev_info
)
if ret == 0:
data["dev_info"] = dev_info

all_info = await self.hass.async_add_executor_job(
self.session.get_product_all_info
)
data["product_info"] = all_info[1]

ret, is_asleep = await self.hass.async_add_executor_job(
self.session.is_asleep
)
data["is_asleep"] = {"supported": ret == 0, "status": is_asleep}
return data
ret_les, is_turn_off_light = self.session.getLedEnableState()
is_turn_off_light_val = not (
ret_les == 0 and is_turn_off_light["isEnable"] == "0"
)

is_open_wdr = None
is_open_hdr = None
reserve3 = product_info.get("reserve3")
reserve3_int = int(reserve3) if reserve3 is not None else 0

if (reserve3_int & (1 << 8)) != 0:
ret_wdr, is_open_wdr_data = self.session.getWdrMode()
mode = is_open_wdr_data["mode"] if ret_wdr == 0 and is_open_wdr_data else 0
is_open_wdr = bool(int(mode))
else:
ret_hdr, is_open_hdr_data = self.session.getHdrMode()
mode = is_open_hdr_data["mode"] if ret_hdr == 0 and is_open_hdr_data else 0
is_open_hdr = bool(int(mode))

return FoscamDeviceInfo(
dev_info=dev_info,
product_info=product_info,
is_open_ir=is_open_ir,
is_flip=is_flip,
is_mirror=is_mirror,
is_asleep=is_asleep,
is_open_white_light=is_open_white_light_val,
is_siren_alarm=is_siren_alarm_val,
volume=volume_val,
speak_volume=speak_volume_val,
is_turn_off_volume=is_turn_off_volume_val,
is_turn_off_light=is_turn_off_light_val,
is_open_wdr=is_open_wdr,
is_open_hdr=is_open_hdr,
)

async def _async_update_data(self) -> FoscamDeviceInfo:
"""Fetch data from API endpoint."""
async with asyncio.timeout(10):
return await self.hass.async_add_executor_job(self.gather_all_configs)
10 changes: 3 additions & 7 deletions homeassistant/components/foscam/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,15 @@
class FoscamEntity(CoordinatorEntity[FoscamCoordinator]):
"""Base entity for Foscam camera."""

def __init__(
self,
coordinator: FoscamCoordinator,
entry_id: str,
) -> None:
def __init__(self, coordinator: FoscamCoordinator, config_entry_id: str) -> None:
"""Initialize the base Foscam entity."""
super().__init__(coordinator)

self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, entry_id)},
identifiers={(DOMAIN, config_entry_id)},
manufacturer="Foscam",
)
if dev_info := coordinator.data.get("dev_info"):
if dev_info := coordinator.data.dev_info:
self._attr_device_info[ATTR_MODEL] = dev_info["productName"]
self._attr_device_info[ATTR_SW_VERSION] = dev_info["firmwareVer"]
self._attr_device_info[ATTR_HW_VERSION] = dev_info["hardwareVer"]
34 changes: 34 additions & 0 deletions homeassistant/components/foscam/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,39 @@
"ptz_preset": {
"service": "mdi:target-variant"
}
},
"entity": {
"switch": {
"flip_switch": {
"default": "mdi:flip-vertical"
},
"mirror_switch": {
"default": "mdi:mirror"
},
"ir_switch": {
"default": "mdi:theme-light-dark"
},
"sleep_switch": {
"default": "mdi:sleep"
},
"white_light_switch": {
"default": "mdi:light-flood-down"
},
"siren_alarm_switch": {
"default": "mdi:alarm-note"
},
"turn_off_volume_switch": {
"default": "mdi:volume-off"
},
"turn_off_light_switch": {
"default": "mdi:lightbulb-fluorescent-tube"
},
"hdr_switch": {
"default": "mdi:hdr"
},
"wdr_switch": {
"default": "mdi:alpha-w-box"
}
}
}
}
29 changes: 28 additions & 1 deletion homeassistant/components/foscam/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,35 @@
},
"entity": {
"switch": {
"flip_switch": {
"name": "Flip"
},
"mirror_switch": {
"name": "Mirror"
},
"ir_switch": {
"name": "Infrared mode"
},
"sleep_switch": {
"name": "Sleep"
"name": "Sleep mode"
},
"white_light_switch": {
"name": "White light"
},
"siren_alarm_switch": {
"name": "Siren alarm"
},
"turn_off_volume_switch": {
"name": "Volume muted"
},
"turn_off_light_switch": {
"name": "Light"
},
"hdr_switch": {
"name": "HDR"
},
"wdr_switch": {
"name": "WDR"
}
}
},
Expand Down
Loading
Loading