mirror of
https://github.com/home-assistant/core.git
synced 2025-06-25 01:21:51 +02:00
Replace fiblary3 with pyfibaro library (#83500)
* Replace fiblary3 with pyfibaro library * Fix some missing replacements for pyfibaro library * Remove debug code which was committed accidentially * Use fibaro_parent_id in another place * Fix some bugs * Move more code to the library * Move has_unit check to correct place
This commit is contained in:
@ -6,12 +6,10 @@ from collections.abc import Mapping
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from fiblary3.client.v4.client import (
|
||||
Client as FibaroClientV4,
|
||||
StateHandler as StateHandlerV4,
|
||||
)
|
||||
from fiblary3.client.v5.client import StateHandler as StateHandlerV5
|
||||
from fiblary3.common.exceptions import HTTPException
|
||||
from pyfibaro.fibaro_client import FibaroClient
|
||||
from pyfibaro.fibaro_device import DeviceModel
|
||||
from pyfibaro.fibaro_scene import SceneModel
|
||||
from requests.exceptions import HTTPError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
@ -134,24 +132,11 @@ class FibaroController:
|
||||
def __init__(
|
||||
self, config: Mapping[str, Any], serial_number: str | None = None
|
||||
) -> None:
|
||||
"""Initialize the Fibaro controller.
|
||||
"""Initialize the Fibaro controller."""
|
||||
|
||||
Version 4 is used for home center 2 (SN starts with HC2) and
|
||||
home center lite (SN starts with HCL).
|
||||
|
||||
Version 5 is used for home center 3 (SN starts with HC3),
|
||||
home center 3 lite (SN starts with HC3L) and yubii home (SN starts with YH).
|
||||
|
||||
Here the serial number is optional and we choose then the V4 client. You
|
||||
should do that only when you use the FibaroController for login test as only
|
||||
the login and info API's are equal throughout the different versions.
|
||||
"""
|
||||
|
||||
# Only use V4 API as it works better even for HC3, after the library is fixed, we should
|
||||
# add here support for the newer library version V5 again.
|
||||
self._client = FibaroClientV4(
|
||||
config[CONF_URL], config[CONF_USERNAME], config[CONF_PASSWORD]
|
||||
)
|
||||
# The FibaroClient uses the correct API version automatically
|
||||
self._client = FibaroClient(config[CONF_URL])
|
||||
self._client.set_authentication(config[CONF_USERNAME], config[CONF_PASSWORD])
|
||||
|
||||
self._scene_map = None
|
||||
# Whether to import devices from plugins
|
||||
@ -162,7 +147,6 @@ class FibaroController:
|
||||
list
|
||||
) # List of devices by entity platform
|
||||
self._callbacks: dict[Any, Any] = {} # Update value callbacks by deviceId
|
||||
self._state_handler = None # Fiblary's StateHandler object
|
||||
self.hub_serial: str # Unique serial number of the hub
|
||||
self.hub_name: str # The friendly name of the hub
|
||||
self.hub_software_version: str
|
||||
@ -173,21 +157,21 @@ class FibaroController:
|
||||
def connect(self):
|
||||
"""Start the communication with the Fibaro controller."""
|
||||
try:
|
||||
login = self._client.login.get()
|
||||
info = self._client.info.get()
|
||||
self.hub_serial = info.serialNumber
|
||||
self.hub_name = info.hcName
|
||||
self.hub_software_version = info.softVersion
|
||||
connected = self._client.connect()
|
||||
info = self._client.read_info()
|
||||
self.hub_serial = info.serial_number
|
||||
self.hub_name = info.hc_name
|
||||
self.hub_software_version = info.current_version
|
||||
except AssertionError:
|
||||
_LOGGER.error("Can't connect to Fibaro HC. Please check URL")
|
||||
return False
|
||||
if login is None or login.status is False:
|
||||
if connected is False:
|
||||
_LOGGER.error(
|
||||
"Invalid login for Fibaro HC. Please check username and password"
|
||||
)
|
||||
return False
|
||||
|
||||
self._room_map = {room.id: room for room in self._client.rooms.list()}
|
||||
self._room_map = {room.fibaro_id: room for room in self._client.read_rooms()}
|
||||
self._read_devices()
|
||||
self._read_scenes()
|
||||
return True
|
||||
@ -201,8 +185,8 @@ class FibaroController:
|
||||
connected = self.connect()
|
||||
if not connected:
|
||||
raise FibaroConnectFailed("Connect status is false")
|
||||
except HTTPException as http_ex:
|
||||
if http_ex.details == "Forbidden":
|
||||
except HTTPError as http_ex:
|
||||
if http_ex.response.status_code == 403:
|
||||
raise FibaroAuthFailed from http_ex
|
||||
|
||||
raise FibaroConnectFailed from http_ex
|
||||
@ -211,15 +195,11 @@ class FibaroController:
|
||||
|
||||
def enable_state_handler(self):
|
||||
"""Start StateHandler thread for monitoring updates."""
|
||||
if isinstance(self._client, FibaroClientV4):
|
||||
self._state_handler = StateHandlerV4(self._client, self._on_state_change)
|
||||
else:
|
||||
self._state_handler = StateHandlerV5(self._client, self._on_state_change)
|
||||
self._client.register_update_handler(self._on_state_change)
|
||||
|
||||
def disable_state_handler(self):
|
||||
"""Stop StateHandler thread used for monitoring updates."""
|
||||
self._state_handler.stop()
|
||||
self._state_handler = None
|
||||
self._client.unregister_update_handler()
|
||||
|
||||
def _on_state_change(self, state):
|
||||
"""Handle change report received from the HomeCenter."""
|
||||
@ -262,7 +242,7 @@ class FibaroController:
|
||||
return [
|
||||
device
|
||||
for device in self._device_map.values()
|
||||
if device.parentId == device_id
|
||||
if device.parent_fibaro_id == device_id
|
||||
]
|
||||
|
||||
def get_children2(self, device_id, endpoint_id):
|
||||
@ -270,31 +250,28 @@ class FibaroController:
|
||||
return [
|
||||
device
|
||||
for device in self._device_map.values()
|
||||
if device.parentId == device_id
|
||||
and (
|
||||
"endPointId" not in device.properties
|
||||
or device.properties.endPointId == endpoint_id
|
||||
)
|
||||
if device.parent_fibaro_id == device_id
|
||||
and (not device.has_endpoint_id or device.endpoint_id == endpoint_id)
|
||||
]
|
||||
|
||||
def get_siblings(self, device):
|
||||
"""Get the siblings of a device."""
|
||||
if "endPointId" in device.properties:
|
||||
if device.has_endpoint_id:
|
||||
return self.get_children2(
|
||||
self._device_map[device.id].parentId,
|
||||
self._device_map[device.id].properties.endPointId,
|
||||
self._device_map[device.fibaro_id].parent_fibaro_id,
|
||||
self._device_map[device.fibaro_id].endpoint_id,
|
||||
)
|
||||
return self.get_children(self._device_map[device.id].parentId)
|
||||
return self.get_children(self._device_map[device.fibaro_id].parent_fibaro_id)
|
||||
|
||||
@staticmethod
|
||||
def _map_device_to_platform(device: Any) -> Platform | None:
|
||||
"""Map device to HA device type."""
|
||||
# Use our lookup table to identify device type
|
||||
platform: Platform | None = None
|
||||
if "type" in device:
|
||||
if device.type:
|
||||
platform = FIBARO_TYPEMAP.get(device.type)
|
||||
if platform is None and "baseType" in device:
|
||||
platform = FIBARO_TYPEMAP.get(device.baseType)
|
||||
if platform is None and device.base_type:
|
||||
platform = FIBARO_TYPEMAP.get(device.base_type)
|
||||
|
||||
# We can also identify device type by its capabilities
|
||||
if platform is None:
|
||||
@ -306,8 +283,8 @@ class FibaroController:
|
||||
platform = Platform.COVER
|
||||
elif "secure" in device.actions:
|
||||
platform = Platform.LOCK
|
||||
elif "value" in device.properties:
|
||||
if device.properties.value in ("true", "false"):
|
||||
elif device.value.has_value:
|
||||
if device.value.is_bool_value:
|
||||
platform = Platform.BINARY_SENSOR
|
||||
else:
|
||||
platform = Platform.SENSOR
|
||||
@ -317,31 +294,33 @@ class FibaroController:
|
||||
platform = Platform.LIGHT
|
||||
return platform
|
||||
|
||||
def _create_device_info(self, device: Any, devices: list) -> None:
|
||||
def _create_device_info(
|
||||
self, device: DeviceModel, devices: list[DeviceModel]
|
||||
) -> None:
|
||||
"""Create the device info. Unrooted entities are directly shown below the home center."""
|
||||
|
||||
# The home center is always id 1 (z-wave primary controller)
|
||||
if "parentId" not in device or device.parentId <= 1:
|
||||
if device.parent_fibaro_id <= 1:
|
||||
return
|
||||
|
||||
master_entity: Any | None = None
|
||||
if device.parentId == 1:
|
||||
if device.parent_fibaro_id == 1:
|
||||
master_entity = device
|
||||
else:
|
||||
for parent in devices:
|
||||
if "id" in parent and parent.id == device.parentId:
|
||||
if parent.fibaro_id == device.parent_fibaro_id:
|
||||
master_entity = parent
|
||||
if master_entity is None:
|
||||
_LOGGER.error("Parent with id %s not found", device.parentId)
|
||||
_LOGGER.error("Parent with id %s not found", device.parent_fibaro_id)
|
||||
return
|
||||
|
||||
if "zwaveCompany" in master_entity.properties:
|
||||
manufacturer = master_entity.properties.zwaveCompany
|
||||
manufacturer = master_entity.properties.get("zwaveCompany")
|
||||
else:
|
||||
manufacturer = "Unknown"
|
||||
|
||||
self._device_infos[master_entity.id] = DeviceInfo(
|
||||
identifiers={(DOMAIN, master_entity.id)},
|
||||
self._device_infos[master_entity.fibaro_id] = DeviceInfo(
|
||||
identifiers={(DOMAIN, master_entity.fibaro_id)},
|
||||
manufacturer=manufacturer,
|
||||
name=master_entity.name,
|
||||
via_device=(DOMAIN, self.hub_serial),
|
||||
@ -349,70 +328,65 @@ class FibaroController:
|
||||
|
||||
def get_device_info(self, device: Any) -> DeviceInfo:
|
||||
"""Get the device info by fibaro device id."""
|
||||
if device.id in self._device_infos:
|
||||
return self._device_infos[device.id]
|
||||
if "parentId" in device and device.parentId in self._device_infos:
|
||||
return self._device_infos[device.parentId]
|
||||
if device.fibaro_id in self._device_infos:
|
||||
return self._device_infos[device.fibaro_id]
|
||||
if device.parent_fibaro_id in self._device_infos:
|
||||
return self._device_infos[device.parent_fibaro_id]
|
||||
return DeviceInfo(identifiers={(DOMAIN, self.hub_serial)})
|
||||
|
||||
def _read_scenes(self):
|
||||
scenes = self._client.scenes.list()
|
||||
scenes = self._client.read_scenes()
|
||||
self._scene_map = {}
|
||||
for device in scenes:
|
||||
if "name" not in device or "id" not in device:
|
||||
continue
|
||||
device.fibaro_controller = self
|
||||
if "roomID" not in device or device.roomID == 0:
|
||||
if device.room_id == 0:
|
||||
room_name = "Unknown"
|
||||
else:
|
||||
room_name = self._room_map[device.roomID].name
|
||||
room_name = self._room_map[device.room_id].name
|
||||
device.room_name = room_name
|
||||
device.friendly_name = f"{room_name} {device.name}"
|
||||
device.ha_id = (
|
||||
f"scene_{slugify(room_name)}_{slugify(device.name)}_{device.id}"
|
||||
f"scene_{slugify(room_name)}_{slugify(device.name)}_{device.fibaro_id}"
|
||||
)
|
||||
device.unique_id_str = f"{slugify(self.hub_serial)}.scene.{device.id}"
|
||||
self._scene_map[device.id] = device
|
||||
device.unique_id_str = (
|
||||
f"{slugify(self.hub_serial)}.scene.{device.fibaro_id}"
|
||||
)
|
||||
self._scene_map[device.fibaro_id] = device
|
||||
self.fibaro_devices[Platform.SCENE].append(device)
|
||||
_LOGGER.debug("%s scene -> %s", device.ha_id, device)
|
||||
|
||||
def _read_devices(self):
|
||||
"""Read and process the device list."""
|
||||
devices = list(self._client.devices.list())
|
||||
devices = self._client.read_devices()
|
||||
self._device_map = {}
|
||||
last_climate_parent = None
|
||||
last_endpoint = None
|
||||
for device in devices:
|
||||
try:
|
||||
if "name" not in device or "id" not in device:
|
||||
continue
|
||||
device.fibaro_controller = self
|
||||
if "roomID" not in device or device.roomID == 0:
|
||||
if device.room_id == 0:
|
||||
room_name = "Unknown"
|
||||
else:
|
||||
room_name = self._room_map[device.roomID].name
|
||||
room_name = self._room_map[device.room_id].name
|
||||
device.room_name = room_name
|
||||
device.friendly_name = f"{room_name} {device.name}"
|
||||
device.ha_id = (
|
||||
f"{slugify(room_name)}_{slugify(device.name)}_{device.id}"
|
||||
f"{slugify(room_name)}_{slugify(device.name)}_{device.fibaro_id}"
|
||||
)
|
||||
if device.enabled and (
|
||||
"isPlugin" not in device
|
||||
or (not device.isPlugin or self._import_plugins)
|
||||
):
|
||||
if device.enabled and (not device.is_plugin or self._import_plugins):
|
||||
device.mapped_platform = self._map_device_to_platform(device)
|
||||
else:
|
||||
device.mapped_platform = None
|
||||
if (platform := device.mapped_platform) is None:
|
||||
continue
|
||||
device.unique_id_str = f"{slugify(self.hub_serial)}.{device.id}"
|
||||
device.unique_id_str = f"{slugify(self.hub_serial)}.{device.fibaro_id}"
|
||||
self._create_device_info(device, devices)
|
||||
self._device_map[device.id] = device
|
||||
self._device_map[device.fibaro_id] = device
|
||||
_LOGGER.debug(
|
||||
"%s (%s, %s) -> %s %s",
|
||||
device.ha_id,
|
||||
device.type,
|
||||
device.baseType,
|
||||
device.base_type,
|
||||
platform,
|
||||
str(device),
|
||||
)
|
||||
@ -421,11 +395,11 @@ class FibaroController:
|
||||
continue
|
||||
# We group climate devices into groups with the same
|
||||
# endPointID belonging to the same parent device.
|
||||
if "endPointId" in device.properties:
|
||||
if device.has_endpoint_id:
|
||||
_LOGGER.debug(
|
||||
"climate device: %s, endPointId: %s",
|
||||
device.ha_id,
|
||||
device.properties.endPointId,
|
||||
device.endpoint_id,
|
||||
)
|
||||
else:
|
||||
_LOGGER.debug("climate device: %s, no endPointId", device.ha_id)
|
||||
@ -433,17 +407,13 @@ class FibaroController:
|
||||
# otherwise add the first visible device in the group
|
||||
# which is a hack, but solves a problem with FGT having
|
||||
# hidden compatibility devices before the real device
|
||||
if last_climate_parent != device.parentId or (
|
||||
"endPointId" in device.properties
|
||||
and last_endpoint != device.properties.endPointId
|
||||
if last_climate_parent != device.parent_fibaro_id or (
|
||||
device.has_endpoint_id and last_endpoint != device.endpoint_id
|
||||
):
|
||||
_LOGGER.debug("Handle separately")
|
||||
self.fibaro_devices[platform].append(device)
|
||||
last_climate_parent = device.parentId
|
||||
if "endPointId" in device.properties:
|
||||
last_endpoint = device.properties.endPointId
|
||||
else:
|
||||
last_endpoint = 0
|
||||
last_climate_parent = device.parent_fibaro_id
|
||||
last_endpoint = device.endpoint_id
|
||||
else:
|
||||
_LOGGER.debug("not handling separately")
|
||||
except (KeyError, ValueError):
|
||||
@ -548,21 +518,23 @@ class FibaroDevice(Entity):
|
||||
|
||||
_attr_should_poll = False
|
||||
|
||||
def __init__(self, fibaro_device):
|
||||
def __init__(self, fibaro_device: DeviceModel | SceneModel) -> None:
|
||||
"""Initialize the device."""
|
||||
self.fibaro_device = fibaro_device
|
||||
self.controller = fibaro_device.fibaro_controller
|
||||
self.ha_id = fibaro_device.ha_id
|
||||
self._attr_name = fibaro_device.friendly_name
|
||||
self._attr_unique_id = fibaro_device.unique_id_str
|
||||
self._attr_device_info = self.controller.get_device_info(fibaro_device)
|
||||
|
||||
if isinstance(fibaro_device, DeviceModel):
|
||||
self._attr_device_info = self.controller.get_device_info(fibaro_device)
|
||||
# propagate hidden attribute set in fibaro home center to HA
|
||||
if "visible" in fibaro_device and fibaro_device.visible is False:
|
||||
if not fibaro_device.visible:
|
||||
self._attr_entity_registry_visible_default = False
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self.controller.register(self.fibaro_device.id, self._update_callback)
|
||||
self.controller.register(self.fibaro_device.fibaro_id, self._update_callback)
|
||||
|
||||
def _update_callback(self):
|
||||
"""Update the state."""
|
||||
@ -571,15 +543,15 @@ class FibaroDevice(Entity):
|
||||
@property
|
||||
def level(self):
|
||||
"""Get the level of Fibaro device."""
|
||||
if "value" in self.fibaro_device.properties:
|
||||
return self.fibaro_device.properties.value
|
||||
if self.fibaro_device.value.has_value:
|
||||
return self.fibaro_device.value.int_value()
|
||||
return None
|
||||
|
||||
@property
|
||||
def level2(self):
|
||||
"""Get the tilt level of Fibaro device."""
|
||||
if "value2" in self.fibaro_device.properties:
|
||||
return self.fibaro_device.properties.value2
|
||||
if self.fibaro_device.value_2.has_value:
|
||||
return self.fibaro_device.value_2.int_value()
|
||||
return None
|
||||
|
||||
def dont_know_message(self, action):
|
||||
@ -593,16 +565,16 @@ class FibaroDevice(Entity):
|
||||
def set_level(self, level):
|
||||
"""Set the level of Fibaro device."""
|
||||
self.action("setValue", level)
|
||||
if "value" in self.fibaro_device.properties:
|
||||
self.fibaro_device.properties.value = level
|
||||
if "brightness" in self.fibaro_device.properties:
|
||||
self.fibaro_device.properties.brightness = level
|
||||
if self.fibaro_device.value.has_value:
|
||||
self.fibaro_device.properties["value"] = level
|
||||
if self.fibaro_device.has_brightness:
|
||||
self.fibaro_device.properties["brightness"] = level
|
||||
|
||||
def set_level2(self, level):
|
||||
"""Set the level2 of Fibaro device."""
|
||||
self.action("setValue2", level)
|
||||
if "value2" in self.fibaro_device.properties:
|
||||
self.fibaro_device.properties.value2 = level
|
||||
if self.fibaro_device.value_2.has_value:
|
||||
self.fibaro_device.properties["value2"] = level
|
||||
|
||||
def call_turn_on(self):
|
||||
"""Turn on the Fibaro device."""
|
||||
@ -619,13 +591,13 @@ class FibaroDevice(Entity):
|
||||
blue = int(max(0, min(255, blue)))
|
||||
white = int(max(0, min(255, white)))
|
||||
color_str = f"{red},{green},{blue},{white}"
|
||||
self.fibaro_device.properties.color = color_str
|
||||
self.fibaro_device.properties["color"] = color_str
|
||||
self.action("setColor", str(red), str(green), str(blue), str(white))
|
||||
|
||||
def action(self, cmd, *args):
|
||||
"""Perform an action on the Fibaro HC."""
|
||||
if cmd in self.fibaro_device.actions:
|
||||
getattr(self.fibaro_device, cmd)(*args)
|
||||
self.fibaro_device.execute_action(cmd, args)
|
||||
_LOGGER.debug("-> %s.%s%s called", str(self.ha_id), str(cmd), str(args))
|
||||
else:
|
||||
self.dont_know_message(cmd)
|
||||
@ -633,35 +605,18 @@ class FibaroDevice(Entity):
|
||||
@property
|
||||
def current_binary_state(self):
|
||||
"""Return the current binary state."""
|
||||
if self.fibaro_device.properties.value == "false":
|
||||
return False
|
||||
if (
|
||||
self.fibaro_device.properties.value == "true"
|
||||
or int(self.fibaro_device.properties.value) > 0
|
||||
):
|
||||
return True
|
||||
return False
|
||||
return self.fibaro_device.value.bool_value(False)
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the state attributes of the device."""
|
||||
attr = {"fibaro_id": self.fibaro_device.id}
|
||||
attr = {"fibaro_id": self.fibaro_device.fibaro_id}
|
||||
|
||||
try:
|
||||
if "battery" in self.fibaro_device.interfaces:
|
||||
attr[ATTR_BATTERY_LEVEL] = int(
|
||||
self.fibaro_device.properties.batteryLevel
|
||||
)
|
||||
if "armed" in self.fibaro_device.properties:
|
||||
armed = self.fibaro_device.properties.armed
|
||||
if isinstance(armed, bool):
|
||||
attr[ATTR_ARMED] = armed
|
||||
elif isinstance(armed, str) and armed.lower() in ("true", "false"):
|
||||
attr[ATTR_ARMED] = armed.lower() == "true"
|
||||
else:
|
||||
attr[ATTR_ARMED] = None
|
||||
except (ValueError, KeyError):
|
||||
pass
|
||||
if isinstance(self.fibaro_device, DeviceModel):
|
||||
if self.fibaro_device.has_battery_level:
|
||||
attr[ATTR_BATTERY_LEVEL] = self.fibaro_device.battery_level
|
||||
if self.fibaro_device.has_armed:
|
||||
attr[ATTR_ARMED] = self.fibaro_device.armed
|
||||
|
||||
return attr
|
||||
|
||||
|
@ -2,9 +2,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
import json
|
||||
from typing import Any, cast
|
||||
|
||||
from pyfibaro.fibaro_device import DeviceModel
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
ENTITY_ID_FORMAT,
|
||||
BinarySensorDeviceClass,
|
||||
@ -58,7 +59,7 @@ async def async_setup_entry(
|
||||
class FibaroBinarySensor(FibaroDevice, BinarySensorEntity):
|
||||
"""Representation of a Fibaro Binary Sensor."""
|
||||
|
||||
def __init__(self, fibaro_device: Any) -> None:
|
||||
def __init__(self, fibaro_device: DeviceModel) -> None:
|
||||
"""Initialize the binary_sensor."""
|
||||
super().__init__(fibaro_device)
|
||||
self.entity_id = ENTITY_ID_FORMAT.format(self.ha_id)
|
||||
@ -66,8 +67,8 @@ class FibaroBinarySensor(FibaroDevice, BinarySensorEntity):
|
||||
self._fibaro_sensor_type = None
|
||||
if fibaro_device.type in SENSOR_TYPES:
|
||||
self._fibaro_sensor_type = fibaro_device.type
|
||||
elif fibaro_device.baseType in SENSOR_TYPES:
|
||||
self._fibaro_sensor_type = fibaro_device.baseType
|
||||
elif fibaro_device.base_type in SENSOR_TYPES:
|
||||
self._fibaro_sensor_type = fibaro_device.base_type
|
||||
if self._fibaro_sensor_type:
|
||||
self._attr_device_class = cast(
|
||||
BinarySensorDeviceClass, SENSOR_TYPES[self._fibaro_sensor_type][2]
|
||||
@ -105,9 +106,4 @@ class FibaroBinarySensor(FibaroDevice, BinarySensorEntity):
|
||||
|
||||
def _get_moving_values(self) -> Mapping[str, Any]:
|
||||
"""Get the moving values of the accelerator sensor in a dict."""
|
||||
value = self.fibaro_device.properties.value
|
||||
if isinstance(value, str):
|
||||
# HC2 returns dict as str
|
||||
return json.loads(value)
|
||||
# HC3 returns a real dict
|
||||
return value
|
||||
return self.fibaro_device.value.dict_value()
|
||||
|
@ -5,6 +5,8 @@ from contextlib import suppress
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from pyfibaro.fibaro_device import DeviceModel
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
ENTITY_ID_FORMAT,
|
||||
PRESET_AWAY,
|
||||
@ -124,7 +126,7 @@ async def async_setup_entry(
|
||||
class FibaroThermostat(FibaroDevice, ClimateEntity):
|
||||
"""Representation of a Fibaro Thermostat."""
|
||||
|
||||
def __init__(self, fibaro_device):
|
||||
def __init__(self, fibaro_device: DeviceModel) -> None:
|
||||
"""Initialize the Fibaro device."""
|
||||
super().__init__(fibaro_device)
|
||||
self._temp_sensor_device: FibaroDevice | None = None
|
||||
@ -141,26 +143,23 @@ class FibaroThermostat(FibaroDevice, ClimateEntity):
|
||||
# doing so, so we prefer the hard evidence, if there is such.
|
||||
if device.type == "com.fibaro.temperatureSensor":
|
||||
self._temp_sensor_device = FibaroDevice(device)
|
||||
tempunit = device.properties.unit
|
||||
tempunit = device.unit
|
||||
elif (
|
||||
self._temp_sensor_device is None
|
||||
and "unit" in device.properties
|
||||
and (
|
||||
"value" in device.properties
|
||||
or "heatingThermostatSetpoint" in device.properties
|
||||
)
|
||||
and device.properties.unit in ("C", "F")
|
||||
and device.has_unit
|
||||
and (device.value.has_value or device.has_heating_thermostat_setpoint)
|
||||
and device.unit in ("C", "F")
|
||||
):
|
||||
self._temp_sensor_device = FibaroDevice(device)
|
||||
tempunit = device.properties.unit
|
||||
tempunit = device.unit
|
||||
|
||||
if any(
|
||||
action for action in TARGET_TEMP_ACTIONS if action in device.actions
|
||||
):
|
||||
self._target_temp_device = FibaroDevice(device)
|
||||
self._attr_supported_features |= ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
if "unit" in device.properties:
|
||||
tempunit = device.properties.unit
|
||||
if device.has_unit:
|
||||
tempunit = device.unit
|
||||
|
||||
if any(action for action in OP_MODE_ACTIONS if action in device.actions):
|
||||
self._op_mode_device = FibaroDevice(device)
|
||||
@ -176,12 +175,9 @@ class FibaroThermostat(FibaroDevice, ClimateEntity):
|
||||
self._attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
|
||||
if self._fan_mode_device:
|
||||
fan_modes = (
|
||||
self._fan_mode_device.fibaro_device.properties.supportedModes.split(",")
|
||||
)
|
||||
fan_modes = self._fan_mode_device.fibaro_device.supported_modes
|
||||
self._attr_fan_modes = []
|
||||
for mode in fan_modes:
|
||||
mode = int(mode)
|
||||
if mode not in FANMODES:
|
||||
_LOGGER.warning("%d unknown fan mode", mode)
|
||||
continue
|
||||
@ -190,21 +186,20 @@ class FibaroThermostat(FibaroDevice, ClimateEntity):
|
||||
self._attr_hvac_modes = [HVACMode.AUTO] # default
|
||||
if self._op_mode_device:
|
||||
self._attr_preset_modes = []
|
||||
self._attr_hvac_modes = []
|
||||
prop = self._op_mode_device.fibaro_device.properties
|
||||
if "supportedThermostatModes" in prop:
|
||||
for mode in prop.supportedThermostatModes:
|
||||
self._attr_hvac_modes: list[HVACMode] = []
|
||||
device = self._op_mode_device.fibaro_device
|
||||
if device.has_supported_thermostat_modes:
|
||||
for mode in device.supported_thermostat_modes:
|
||||
try:
|
||||
self._attr_hvac_modes.append(HVACMode(mode.lower()))
|
||||
except ValueError:
|
||||
self._attr_preset_modes.append(mode)
|
||||
else:
|
||||
if "supportedOperatingModes" in prop:
|
||||
op_modes = prop.supportedOperatingModes.split(",")
|
||||
if device.has_supported_operating_modes:
|
||||
op_modes = device.supported_operating_modes
|
||||
else:
|
||||
op_modes = prop.supportedModes.split(",")
|
||||
op_modes = device.supported_modes
|
||||
for mode in op_modes:
|
||||
mode = int(mode)
|
||||
if (
|
||||
mode in OPMODES_HVAC
|
||||
and (mode_ha := OPMODES_HVAC.get(mode))
|
||||
@ -236,14 +231,14 @@ class FibaroThermostat(FibaroDevice, ClimateEntity):
|
||||
siblings = self.fibaro_device.fibaro_controller.get_siblings(self.fibaro_device)
|
||||
for device in siblings:
|
||||
if device != self.fibaro_device:
|
||||
self.controller.register(device.id, self._update_callback)
|
||||
self.controller.register(device.fibaro_id, self._update_callback)
|
||||
|
||||
@property
|
||||
def fan_mode(self) -> str | None:
|
||||
"""Return the fan setting."""
|
||||
if not self._fan_mode_device:
|
||||
return None
|
||||
mode = int(self._fan_mode_device.fibaro_device.properties.mode)
|
||||
mode = self._fan_mode_device.fibaro_device.mode
|
||||
return FANMODES[mode]
|
||||
|
||||
def set_fan_mode(self, fan_mode: str) -> None:
|
||||
@ -258,14 +253,13 @@ class FibaroThermostat(FibaroDevice, ClimateEntity):
|
||||
if not self._op_mode_device:
|
||||
return HA_OPMODES_HVAC[HVACMode.AUTO]
|
||||
|
||||
prop = self._op_mode_device.fibaro_device.properties
|
||||
device = self._op_mode_device.fibaro_device
|
||||
|
||||
if "operatingMode" in prop:
|
||||
return int(prop.operatingMode)
|
||||
if "thermostatMode" in prop:
|
||||
return prop.thermostatMode
|
||||
|
||||
return int(prop.mode)
|
||||
if device.has_operating_mode:
|
||||
return device.operating_mode
|
||||
if device.has_thermostat_mode:
|
||||
return device.thermostat_mode
|
||||
return device.mode
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> HVACMode | str | None:
|
||||
@ -288,9 +282,9 @@ class FibaroThermostat(FibaroDevice, ClimateEntity):
|
||||
if "setOperatingMode" in self._op_mode_device.fibaro_device.actions:
|
||||
self._op_mode_device.action("setOperatingMode", HA_OPMODES_HVAC[hvac_mode])
|
||||
elif "setThermostatMode" in self._op_mode_device.fibaro_device.actions:
|
||||
prop = self._op_mode_device.fibaro_device.properties
|
||||
if "supportedThermostatModes" in prop:
|
||||
for mode in prop.supportedThermostatModes:
|
||||
device = self._op_mode_device.fibaro_device
|
||||
if device.has_supported_thermostat_modes:
|
||||
for mode in device.supported_thermostat_modes:
|
||||
if mode.lower() == hvac_mode:
|
||||
self._op_mode_device.action("setThermostatMode", mode)
|
||||
break
|
||||
@ -303,10 +297,10 @@ class FibaroThermostat(FibaroDevice, ClimateEntity):
|
||||
if not self._op_mode_device:
|
||||
return None
|
||||
|
||||
prop = self._op_mode_device.fibaro_device.properties
|
||||
if "thermostatOperatingState" in prop:
|
||||
device = self._op_mode_device.fibaro_device
|
||||
if device.has_thermostat_operating_state:
|
||||
with suppress(ValueError):
|
||||
return HVACAction(prop.thermostatOperatingState.lower())
|
||||
return HVACAction(device.thermostat_operating_state.lower())
|
||||
|
||||
return None
|
||||
|
||||
@ -319,15 +313,15 @@ class FibaroThermostat(FibaroDevice, ClimateEntity):
|
||||
if not self._op_mode_device:
|
||||
return None
|
||||
|
||||
if "thermostatMode" in self._op_mode_device.fibaro_device.properties:
|
||||
mode = self._op_mode_device.fibaro_device.properties.thermostatMode
|
||||
if self._op_mode_device.fibaro_device.has_thermostat_mode:
|
||||
mode = self._op_mode_device.fibaro_device.thermostat_mode
|
||||
if self.preset_modes is not None and mode in self.preset_modes:
|
||||
return mode
|
||||
return None
|
||||
if "operatingMode" in self._op_mode_device.fibaro_device.properties:
|
||||
mode = int(self._op_mode_device.fibaro_device.properties.operatingMode)
|
||||
if self._op_mode_device.fibaro_device.has_operating_mode:
|
||||
mode = self._op_mode_device.fibaro_device.operating_mode
|
||||
else:
|
||||
mode = int(self._op_mode_device.fibaro_device.properties.mode)
|
||||
mode = self._op_mode_device.fibaro_device.mode
|
||||
|
||||
if mode not in OPMODES_PRESET:
|
||||
return None
|
||||
@ -352,9 +346,9 @@ class FibaroThermostat(FibaroDevice, ClimateEntity):
|
||||
"""Return the current temperature."""
|
||||
if self._temp_sensor_device:
|
||||
device = self._temp_sensor_device.fibaro_device
|
||||
if "heatingThermostatSetpoint" in device.properties:
|
||||
return float(device.properties.heatingThermostatSetpoint)
|
||||
return float(device.properties.value)
|
||||
if device.has_heating_thermostat_setpoint:
|
||||
return device.heating_thermostat_setpoint
|
||||
return device.value.float_value()
|
||||
return None
|
||||
|
||||
@property
|
||||
@ -362,9 +356,9 @@ class FibaroThermostat(FibaroDevice, ClimateEntity):
|
||||
"""Return the temperature we try to reach."""
|
||||
if self._target_temp_device:
|
||||
device = self._target_temp_device.fibaro_device
|
||||
if "heatingThermostatSetpointFuture" in device.properties:
|
||||
return float(device.properties.heatingThermostatSetpointFuture)
|
||||
return float(device.properties.targetLevel)
|
||||
if device.has_heating_thermostat_setpoint_future:
|
||||
return device.heating_thermostat_setpoint_future
|
||||
return device.target_level
|
||||
return None
|
||||
|
||||
def set_temperature(self, **kwargs: Any) -> None:
|
||||
|
@ -3,6 +3,8 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from pyfibaro.fibaro_device import DeviceModel
|
||||
|
||||
from homeassistant.components.cover import (
|
||||
ATTR_POSITION,
|
||||
ATTR_TILT_POSITION,
|
||||
@ -39,7 +41,7 @@ async def async_setup_entry(
|
||||
class FibaroCover(FibaroDevice, CoverEntity):
|
||||
"""Representation a Fibaro Cover."""
|
||||
|
||||
def __init__(self, fibaro_device):
|
||||
def __init__(self, fibaro_device: DeviceModel) -> None:
|
||||
"""Initialize the Vera device."""
|
||||
super().__init__(fibaro_device)
|
||||
self.entity_id = ENTITY_ID_FORMAT.format(self.ha_id)
|
||||
@ -67,9 +69,7 @@ class FibaroCover(FibaroDevice, CoverEntity):
|
||||
"""Return if only open / close is supported."""
|
||||
# Normally positionable devices report the position over value,
|
||||
# so if it is missing we have a device which supports open / close only
|
||||
if "value" not in self.fibaro_device.properties:
|
||||
return True
|
||||
return False
|
||||
return not self.fibaro_device.value.has_value
|
||||
|
||||
@property
|
||||
def current_cover_position(self) -> int | None:
|
||||
@ -93,12 +93,10 @@ class FibaroCover(FibaroDevice, CoverEntity):
|
||||
def is_closed(self) -> bool | None:
|
||||
"""Return if the cover is closed."""
|
||||
if self._is_open_close_only():
|
||||
if (
|
||||
"state" not in self.fibaro_device.properties
|
||||
or self.fibaro_device.properties.state.lower() == "unknown"
|
||||
):
|
||||
state = self.fibaro_device.state
|
||||
if not state.has_value or state.str_value.lower() == "unknown":
|
||||
return None
|
||||
return self.fibaro_device.properties.state.lower() == "closed"
|
||||
return state.str_value.lower() == "closed"
|
||||
|
||||
if self.current_cover_position is None:
|
||||
return None
|
||||
|
@ -6,6 +6,8 @@ from contextlib import suppress
|
||||
from functools import partial
|
||||
from typing import Any
|
||||
|
||||
from pyfibaro.fibaro_device import DeviceModel
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_RGB_COLOR,
|
||||
@ -68,7 +70,7 @@ async def async_setup_entry(
|
||||
class FibaroLight(FibaroDevice, LightEntity):
|
||||
"""Representation of a Fibaro Light, including dimmable."""
|
||||
|
||||
def __init__(self, fibaro_device):
|
||||
def __init__(self, fibaro_device: DeviceModel) -> None:
|
||||
"""Initialize the light."""
|
||||
self._update_lock = asyncio.Lock()
|
||||
|
||||
@ -77,7 +79,7 @@ class FibaroLight(FibaroDevice, LightEntity):
|
||||
or "colorComponents" in fibaro_device.properties
|
||||
or "RGB" in fibaro_device.type
|
||||
or "rgb" in fibaro_device.type
|
||||
or "color" in fibaro_device.baseType
|
||||
or "color" in fibaro_device.base_type
|
||||
) and (
|
||||
"setColor" in fibaro_device.actions
|
||||
or "setColorComponents" in fibaro_device.actions
|
||||
@ -88,7 +90,7 @@ class FibaroLight(FibaroDevice, LightEntity):
|
||||
or "rgbw" in fibaro_device.type
|
||||
)
|
||||
supports_dimming = (
|
||||
"levelChange" in fibaro_device.interfaces
|
||||
fibaro_device.has_interface("levelChange")
|
||||
and "setValue" in fibaro_device.actions
|
||||
)
|
||||
|
||||
@ -153,17 +155,16 @@ class FibaroLight(FibaroDevice, LightEntity):
|
||||
|
||||
JSON for HC2 uses always string, HC3 uses int for integers.
|
||||
"""
|
||||
props = self.fibaro_device.properties
|
||||
if self.current_binary_state:
|
||||
return True
|
||||
with suppress(ValueError, TypeError):
|
||||
if "brightness" in props and int(props.brightness) != 0:
|
||||
with suppress(TypeError):
|
||||
if self.fibaro_device.brightness != 0:
|
||||
return True
|
||||
with suppress(ValueError, TypeError):
|
||||
if "currentProgram" in props and int(props.currentProgram) != 0:
|
||||
with suppress(TypeError):
|
||||
if self.fibaro_device.current_program != 0:
|
||||
return True
|
||||
with suppress(ValueError, TypeError):
|
||||
if "currentProgramID" in props and int(props.currentProgramID) != 0:
|
||||
with suppress(TypeError):
|
||||
if self.fibaro_device.current_program_id != 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
@ -177,21 +178,19 @@ class FibaroLight(FibaroDevice, LightEntity):
|
||||
"""Really update the state."""
|
||||
# Brightness handling
|
||||
if brightness_supported(self.supported_color_modes):
|
||||
self._attr_brightness = scaleto255(int(self.fibaro_device.properties.value))
|
||||
self._attr_brightness = scaleto255(self.fibaro_device.value.int_value())
|
||||
|
||||
# Color handling
|
||||
if (
|
||||
color_supported(self.supported_color_modes)
|
||||
and "color" in self.fibaro_device.properties
|
||||
and "," in self.fibaro_device.properties.color
|
||||
and self.fibaro_device.color.has_color
|
||||
):
|
||||
# Fibaro communicates the color as an 'R, G, B, W' string
|
||||
rgbw_s = self.fibaro_device.properties.color
|
||||
if rgbw_s == "0,0,0,0" and "lastColorSet" in self.fibaro_device.properties:
|
||||
rgbw_s = self.fibaro_device.properties.lastColorSet
|
||||
rgbw_list = [int(i) for i in rgbw_s.split(",")][:4]
|
||||
rgbw = self.fibaro_device.color.rgbw_color
|
||||
if rgbw == (0, 0, 0, 0) and self.fibaro_device.last_color_set.has_color:
|
||||
rgbw = self.fibaro_device.last_color_set.rgbw_color
|
||||
|
||||
if self._attr_color_mode == ColorMode.RGB:
|
||||
self._attr_rgb_color = tuple(rgbw_list[:3])
|
||||
self._attr_rgb_color = rgbw[:3]
|
||||
else:
|
||||
self._attr_rgbw_color = tuple(rgbw_list)
|
||||
self._attr_rgbw_color = rgbw
|
||||
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from fiblary3.client.v4.models import DeviceModel, SceneModel
|
||||
from pyfibaro.fibaro_device import DeviceModel
|
||||
|
||||
from homeassistant.components.lock import ENTITY_ID_FORMAT, LockEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
@ -35,7 +35,7 @@ async def async_setup_entry(
|
||||
class FibaroLock(FibaroDevice, LockEntity):
|
||||
"""Representation of a Fibaro Lock."""
|
||||
|
||||
def __init__(self, fibaro_device: DeviceModel | SceneModel) -> None:
|
||||
def __init__(self, fibaro_device: DeviceModel) -> None:
|
||||
"""Initialize the Fibaro device."""
|
||||
super().__init__(fibaro_device)
|
||||
self.entity_id = ENTITY_ID_FORMAT.format(self.ha_id)
|
||||
|
@ -6,6 +6,6 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/fibaro",
|
||||
"integration_type": "hub",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["fiblary3"],
|
||||
"requirements": ["fiblary3==0.1.8"]
|
||||
"loggers": ["pyfibaro"],
|
||||
"requirements": ["pyfibaro==0.6.6"]
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from pyfibaro.fibaro_scene import SceneModel
|
||||
|
||||
from homeassistant.components.scene import Scene
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
@ -34,7 +36,7 @@ async def async_setup_entry(
|
||||
class FibaroScene(FibaroDevice, Scene):
|
||||
"""Representation of a Fibaro scene entity."""
|
||||
|
||||
def __init__(self, fibaro_device: Any) -> None:
|
||||
def __init__(self, fibaro_device: SceneModel) -> None:
|
||||
"""Initialize the Fibaro scene."""
|
||||
super().__init__(fibaro_device)
|
||||
|
||||
|
@ -2,7 +2,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import suppress
|
||||
from typing import Any
|
||||
|
||||
from pyfibaro.fibaro_device import DeviceModel
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
ENTITY_ID_FORMAT,
|
||||
@ -125,7 +126,9 @@ class FibaroSensor(FibaroDevice, SensorEntity):
|
||||
"""Representation of a Fibaro Sensor."""
|
||||
|
||||
def __init__(
|
||||
self, fibaro_device: Any, entity_description: SensorEntityDescription | None
|
||||
self,
|
||||
fibaro_device: DeviceModel,
|
||||
entity_description: SensorEntityDescription | None,
|
||||
) -> None:
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(fibaro_device)
|
||||
@ -138,20 +141,20 @@ class FibaroSensor(FibaroDevice, SensorEntity):
|
||||
with suppress(KeyError, ValueError):
|
||||
if not self.native_unit_of_measurement:
|
||||
self._attr_native_unit_of_measurement = FIBARO_TO_HASS_UNIT.get(
|
||||
fibaro_device.properties.unit, fibaro_device.properties.unit
|
||||
fibaro_device.unit, fibaro_device.unit
|
||||
)
|
||||
|
||||
def update(self) -> None:
|
||||
"""Update the state."""
|
||||
with suppress(KeyError, ValueError):
|
||||
self._attr_native_value = float(self.fibaro_device.properties.value)
|
||||
with suppress(TypeError):
|
||||
self._attr_native_value = self.fibaro_device.value.float_value()
|
||||
|
||||
|
||||
class FibaroAdditionalSensor(FibaroDevice, SensorEntity):
|
||||
"""Representation of a Fibaro Additional Sensor."""
|
||||
|
||||
def __init__(
|
||||
self, fibaro_device: Any, entity_description: SensorEntityDescription
|
||||
self, fibaro_device: DeviceModel, entity_description: SensorEntityDescription
|
||||
) -> None:
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(fibaro_device)
|
||||
|
@ -3,6 +3,8 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from pyfibaro.fibaro_device import DeviceModel
|
||||
|
||||
from homeassistant.components.switch import ENTITY_ID_FORMAT, SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
@ -33,7 +35,7 @@ async def async_setup_entry(
|
||||
class FibaroSwitch(FibaroDevice, SwitchEntity):
|
||||
"""Representation of a Fibaro Switch."""
|
||||
|
||||
def __init__(self, fibaro_device: Any) -> None:
|
||||
def __init__(self, fibaro_device: DeviceModel) -> None:
|
||||
"""Initialize the Fibaro device."""
|
||||
super().__init__(fibaro_device)
|
||||
self.entity_id = ENTITY_ID_FORMAT.format(self.ha_id)
|
||||
|
@ -703,9 +703,6 @@ fastdotcom==0.0.3
|
||||
# homeassistant.components.feedreader
|
||||
feedparser==6.0.10
|
||||
|
||||
# homeassistant.components.fibaro
|
||||
fiblary3==0.1.8
|
||||
|
||||
# homeassistant.components.file
|
||||
file-read-backwards==2.0.0
|
||||
|
||||
@ -1620,6 +1617,9 @@ pyevilgenius==2.0.0
|
||||
# homeassistant.components.ezviz
|
||||
pyezviz==0.2.0.9
|
||||
|
||||
# homeassistant.components.fibaro
|
||||
pyfibaro==0.6.6
|
||||
|
||||
# homeassistant.components.fido
|
||||
pyfido==2.1.1
|
||||
|
||||
|
@ -537,9 +537,6 @@ faadelays==0.0.7
|
||||
# homeassistant.components.feedreader
|
||||
feedparser==6.0.10
|
||||
|
||||
# homeassistant.components.fibaro
|
||||
fiblary3==0.1.8
|
||||
|
||||
# homeassistant.components.file
|
||||
file-read-backwards==2.0.0
|
||||
|
||||
@ -1160,6 +1157,9 @@ pyevilgenius==2.0.0
|
||||
# homeassistant.components.ezviz
|
||||
pyezviz==0.2.0.9
|
||||
|
||||
# homeassistant.components.fibaro
|
||||
pyfibaro==0.6.6
|
||||
|
||||
# homeassistant.components.fido
|
||||
pyfido==2.1.1
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
"""Test the Fibaro config flow."""
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from fiblary3.common.exceptions import HTTPException
|
||||
import pytest
|
||||
from requests.exceptions import HTTPError
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.fibaro import DOMAIN
|
||||
@ -25,37 +25,31 @@ TEST_VERSION = "4.360"
|
||||
def fibaro_client_fixture():
|
||||
"""Mock common methods and attributes of fibaro client."""
|
||||
info_mock = Mock()
|
||||
info_mock.get.return_value = Mock(
|
||||
serialNumber=TEST_SERIALNUMBER, hcName=TEST_NAME, softVersion=TEST_VERSION
|
||||
)
|
||||
|
||||
array_mock = Mock()
|
||||
array_mock.list.return_value = []
|
||||
info_mock.return_value.serial_number = TEST_SERIALNUMBER
|
||||
info_mock.return_value.hc_name = TEST_NAME
|
||||
info_mock.return_value.current_version = TEST_VERSION
|
||||
|
||||
client_mock = Mock()
|
||||
client_mock.base_url.return_value = TEST_URL
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.__init__",
|
||||
"homeassistant.components.fibaro.FibaroClient.__init__",
|
||||
return_value=None,
|
||||
), patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.info",
|
||||
"homeassistant.components.fibaro.FibaroClient.read_info",
|
||||
info_mock,
|
||||
create=True,
|
||||
), patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.rooms",
|
||||
array_mock,
|
||||
create=True,
|
||||
"homeassistant.components.fibaro.FibaroClient.read_rooms",
|
||||
return_value=[],
|
||||
), patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.devices",
|
||||
array_mock,
|
||||
create=True,
|
||||
"homeassistant.components.fibaro.FibaroClient.read_devices",
|
||||
return_value=[],
|
||||
), patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.scenes",
|
||||
array_mock,
|
||||
create=True,
|
||||
"homeassistant.components.fibaro.FibaroClient.read_scenes",
|
||||
return_value=[],
|
||||
), patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.client",
|
||||
"homeassistant.components.fibaro.FibaroClient._rest_client",
|
||||
client_mock,
|
||||
create=True,
|
||||
):
|
||||
@ -72,10 +66,9 @@ async def test_config_flow_user_initiated_success(hass: HomeAssistant) -> None:
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {}
|
||||
|
||||
login_mock = Mock()
|
||||
login_mock.get.return_value = Mock(status=True)
|
||||
with patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.login", login_mock, create=True
|
||||
"homeassistant.components.fibaro.FibaroClient.connect",
|
||||
return_value=True,
|
||||
), patch(
|
||||
"homeassistant.components.fibaro.async_setup_entry",
|
||||
return_value=True,
|
||||
@ -109,10 +102,9 @@ async def test_config_flow_user_initiated_connect_failure(hass: HomeAssistant) -
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {}
|
||||
|
||||
login_mock = Mock()
|
||||
login_mock.get.return_value = Mock(status=False)
|
||||
with patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.login", login_mock, create=True
|
||||
"homeassistant.components.fibaro.FibaroClient.connect",
|
||||
return_value=False,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
@ -139,9 +131,9 @@ async def test_config_flow_user_initiated_auth_failure(hass: HomeAssistant) -> N
|
||||
assert result["errors"] == {}
|
||||
|
||||
login_mock = Mock()
|
||||
login_mock.get.side_effect = HTTPException(details="Forbidden")
|
||||
login_mock.side_effect = HTTPError(response=Mock(status_code=403))
|
||||
with patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.login", login_mock, create=True
|
||||
"homeassistant.components.fibaro.FibaroClient.connect", login_mock, create=True
|
||||
):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
@ -170,9 +162,9 @@ async def test_config_flow_user_initiated_unknown_failure_1(
|
||||
assert result["errors"] == {}
|
||||
|
||||
login_mock = Mock()
|
||||
login_mock.get.side_effect = HTTPException(details="Any")
|
||||
login_mock.side_effect = HTTPError(response=Mock(status_code=500))
|
||||
with patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.login", login_mock, create=True
|
||||
"homeassistant.components.fibaro.FibaroClient.connect", login_mock, create=True
|
||||
):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
@ -200,26 +192,29 @@ async def test_config_flow_user_initiated_unknown_failure_2(
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {}
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
CONF_URL: TEST_URL,
|
||||
CONF_USERNAME: TEST_USERNAME,
|
||||
CONF_PASSWORD: TEST_PASSWORD,
|
||||
},
|
||||
)
|
||||
login_mock = Mock()
|
||||
login_mock.side_effect = Exception()
|
||||
with patch(
|
||||
"homeassistant.components.fibaro.FibaroClient.connect", login_mock, create=True
|
||||
):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
CONF_URL: TEST_URL,
|
||||
CONF_USERNAME: TEST_USERNAME,
|
||||
CONF_PASSWORD: TEST_PASSWORD,
|
||||
},
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {"base": "cannot_connect"}
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
|
||||
async def test_config_flow_import(hass: HomeAssistant) -> None:
|
||||
"""Test for importing config from configuration.yaml."""
|
||||
login_mock = Mock()
|
||||
login_mock.get.return_value = Mock(status=True)
|
||||
with patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.login", login_mock, create=True
|
||||
"homeassistant.components.fibaro.FibaroClient.connect", return_value=True
|
||||
), patch(
|
||||
"homeassistant.components.fibaro.async_setup_entry",
|
||||
return_value=True,
|
||||
@ -271,10 +266,8 @@ async def test_reauth_success(hass: HomeAssistant) -> None:
|
||||
assert result["step_id"] == "reauth_confirm"
|
||||
assert result["errors"] == {}
|
||||
|
||||
login_mock = Mock()
|
||||
login_mock.get.return_value = Mock(status=True)
|
||||
with patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.login", login_mock, create=True
|
||||
"homeassistant.components.fibaro.FibaroClient.connect", return_value=True
|
||||
), patch(
|
||||
"homeassistant.components.fibaro.async_setup_entry",
|
||||
return_value=True,
|
||||
@ -315,9 +308,9 @@ async def test_reauth_connect_failure(hass: HomeAssistant) -> None:
|
||||
assert result["errors"] == {}
|
||||
|
||||
login_mock = Mock()
|
||||
login_mock.get.return_value = Mock(status=False)
|
||||
login_mock.side_effect = Exception()
|
||||
with patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.login", login_mock, create=True
|
||||
"homeassistant.components.fibaro.FibaroClient.connect", login_mock, create=True
|
||||
):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
@ -356,9 +349,9 @@ async def test_reauth_auth_failure(hass: HomeAssistant) -> None:
|
||||
assert result["errors"] == {}
|
||||
|
||||
login_mock = Mock()
|
||||
login_mock.get.side_effect = HTTPException(details="Forbidden")
|
||||
login_mock.side_effect = HTTPError(response=Mock(status_code=403))
|
||||
with patch(
|
||||
"homeassistant.components.fibaro.FibaroClientV4.login", login_mock, create=True
|
||||
"homeassistant.components.fibaro.FibaroClient.connect", login_mock, create=True
|
||||
):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
|
Reference in New Issue
Block a user