Updated changes for aioshelly 1.0.0 (#56083)
This commit is contained in:
parent
ac1251c52b
commit
8c3c2ad8e3
14 changed files with 108 additions and 86 deletions
|
@ -7,6 +7,7 @@ import logging
|
|||
from typing import Any, Final, cast
|
||||
|
||||
import aioshelly
|
||||
from aioshelly.block_device import BlockDevice
|
||||
import async_timeout
|
||||
import voluptuous as vol
|
||||
|
||||
|
@ -89,7 +90,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
|
||||
temperature_unit = "C" if hass.config.units.is_metric else "F"
|
||||
|
||||
options = aioshelly.ConnectionOptions(
|
||||
options = aioshelly.common.ConnectionOptions(
|
||||
entry.data[CONF_HOST],
|
||||
entry.data.get(CONF_USERNAME),
|
||||
entry.data.get(CONF_PASSWORD),
|
||||
|
@ -98,7 +99,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
|
||||
coap_context = await get_coap_context(hass)
|
||||
|
||||
device = await aioshelly.Device.create(
|
||||
device = await BlockDevice.create(
|
||||
aiohttp_client.async_get_clientsession(hass),
|
||||
coap_context,
|
||||
options,
|
||||
|
@ -134,7 +135,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
_LOGGER.debug("Setting up online device %s", entry.title)
|
||||
try:
|
||||
async with async_timeout.timeout(AIOSHELLY_DEVICE_TIMEOUT_SEC):
|
||||
await device.initialize(True)
|
||||
await device.initialize()
|
||||
except (asyncio.TimeoutError, OSError) as err:
|
||||
raise ConfigEntryNotReady from err
|
||||
|
||||
|
@ -146,7 +147,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
"Setup for device %s will resume when device is online", entry.title
|
||||
)
|
||||
device.subscribe_updates(_async_device_online)
|
||||
await device.coap_request("s")
|
||||
else:
|
||||
# Restore sensors for sleeping device
|
||||
_LOGGER.debug("Setting up offline device %s", entry.title)
|
||||
|
@ -156,7 +156,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
|
||||
|
||||
async def async_device_setup(
|
||||
hass: HomeAssistant, entry: ConfigEntry, device: aioshelly.Device
|
||||
hass: HomeAssistant, entry: ConfigEntry, device: BlockDevice
|
||||
) -> None:
|
||||
"""Set up a device that is online."""
|
||||
device_wrapper = hass.data[DOMAIN][DATA_CONFIG_ENTRY][entry.entry_id][
|
||||
|
@ -179,7 +179,7 @@ class ShellyDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
"""Wrapper for a Shelly device with Home Assistant specific functions."""
|
||||
|
||||
def __init__(
|
||||
self, hass: HomeAssistant, entry: ConfigEntry, device: aioshelly.Device
|
||||
self, hass: HomeAssistant, entry: ConfigEntry, device: BlockDevice
|
||||
) -> None:
|
||||
"""Initialize the Shelly device wrapper."""
|
||||
self.device_id: str | None = None
|
||||
|
@ -208,7 +208,9 @@ class ShellyDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
)
|
||||
self._last_input_events_count: dict = {}
|
||||
|
||||
entry.async_on_unload(
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self._handle_ha_stop)
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_device_updates_handler(self) -> None:
|
||||
|
@ -216,6 +218,8 @@ class ShellyDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
if not self.device.initialized:
|
||||
return
|
||||
|
||||
assert self.device.blocks
|
||||
|
||||
# For buttons which are battery powered - set initial value for last_event_count
|
||||
if self.model in SHBTN_MODELS and self._last_input_events_count.get(1) is None:
|
||||
for block in self.device.blocks:
|
||||
|
@ -298,7 +302,7 @@ class ShellyDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
# This is duplicate but otherwise via_device can't work
|
||||
identifiers={(DOMAIN, self.mac)},
|
||||
manufacturer="Shelly",
|
||||
model=aioshelly.MODEL_NAMES.get(self.model, self.model),
|
||||
model=aioshelly.const.MODEL_NAMES.get(self.model, self.model),
|
||||
sw_version=sw_version,
|
||||
)
|
||||
self.device_id = entry.id
|
||||
|
@ -306,10 +310,8 @@ class ShellyDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
|
||||
def shutdown(self) -> None:
|
||||
"""Shutdown the wrapper."""
|
||||
if self.device:
|
||||
self.device.shutdown()
|
||||
self._async_remove_device_updates_handler()
|
||||
self.device = None
|
||||
|
||||
@callback
|
||||
def _handle_ha_stop(self, _event: Event) -> None:
|
||||
|
@ -321,7 +323,7 @@ class ShellyDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
class ShellyDeviceRestWrapper(update_coordinator.DataUpdateCoordinator):
|
||||
"""Rest Wrapper for a Shelly device with Home Assistant specific functions."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, device: aioshelly.Device) -> None:
|
||||
def __init__(self, hass: HomeAssistant, device: BlockDevice) -> None:
|
||||
"""Initialize the Shelly device wrapper."""
|
||||
if (
|
||||
device.settings["device"]["type"]
|
||||
|
|
|
@ -48,7 +48,7 @@ SENSORS: Final = {
|
|||
("sensor", "dwIsOpened"): BlockAttributeDescription(
|
||||
name="Door",
|
||||
device_class=DEVICE_CLASS_OPENING,
|
||||
available=lambda block: cast(bool, block.dwIsOpened != -1),
|
||||
available=lambda block: cast(int, block.dwIsOpened) != -1,
|
||||
),
|
||||
("sensor", "flood"): BlockAttributeDescription(
|
||||
name="Flood", device_class=DEVICE_CLASS_MOISTURE
|
||||
|
|
|
@ -7,6 +7,7 @@ from typing import Any, Dict, Final, cast
|
|||
|
||||
import aiohttp
|
||||
import aioshelly
|
||||
from aioshelly.block_device import BlockDevice
|
||||
import async_timeout
|
||||
import voluptuous as vol
|
||||
|
||||
|
@ -39,13 +40,13 @@ async def validate_input(
|
|||
Data has the keys from DATA_SCHEMA with values provided by the user.
|
||||
"""
|
||||
|
||||
options = aioshelly.ConnectionOptions(
|
||||
options = aioshelly.common.ConnectionOptions(
|
||||
host, data.get(CONF_USERNAME), data.get(CONF_PASSWORD)
|
||||
)
|
||||
coap_context = await get_coap_context(hass)
|
||||
|
||||
async with async_timeout.timeout(AIOSHELLY_DEVICE_TIMEOUT_SEC):
|
||||
device = await aioshelly.Device.create(
|
||||
device = await BlockDevice.create(
|
||||
aiohttp_client.async_get_clientsession(hass),
|
||||
coap_context,
|
||||
options,
|
||||
|
@ -82,7 +83,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
info = await self._async_get_info(host)
|
||||
except HTTP_CONNECT_ERRORS:
|
||||
errors["base"] = "cannot_connect"
|
||||
except aioshelly.FirmwareUnsupported:
|
||||
except aioshelly.exceptions.FirmwareUnsupported:
|
||||
return self.async_abort(reason="unsupported_firmware")
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Unexpected exception")
|
||||
|
@ -165,7 +166,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
self.info = info = await self._async_get_info(discovery_info["host"])
|
||||
except HTTP_CONNECT_ERRORS:
|
||||
return self.async_abort(reason="cannot_connect")
|
||||
except aioshelly.FirmwareUnsupported:
|
||||
except aioshelly.exceptions.FirmwareUnsupported:
|
||||
return self.async_abort(reason="unsupported_firmware")
|
||||
|
||||
await self.async_set_unique_id(info["mac"])
|
||||
|
@ -206,7 +207,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
return self.async_show_form(
|
||||
step_id="confirm_discovery",
|
||||
description_placeholders={
|
||||
"model": aioshelly.MODEL_NAMES.get(
|
||||
"model": aioshelly.const.MODEL_NAMES.get(
|
||||
self.info["type"], self.info["type"]
|
||||
),
|
||||
"host": self.host,
|
||||
|
@ -219,7 +220,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
async with async_timeout.timeout(AIOSHELLY_DEVICE_TIMEOUT_SEC):
|
||||
return cast(
|
||||
Dict[str, Any],
|
||||
await aioshelly.get_info(
|
||||
await aioshelly.common.get_info(
|
||||
aiohttp_client.async_get_clientsession(self.hass),
|
||||
host,
|
||||
),
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
|
||||
from typing import Any, cast
|
||||
|
||||
from aioshelly import Block
|
||||
from aioshelly.block_device import Block
|
||||
|
||||
from homeassistant.components.cover import (
|
||||
ATTR_POSITION,
|
||||
|
@ -57,7 +57,7 @@ class ShellyCover(ShellyBlockEntity, CoverEntity):
|
|||
if self.control_result:
|
||||
return cast(bool, self.control_result["current_pos"] == 0)
|
||||
|
||||
return cast(bool, self.block.rollerPos == 0)
|
||||
return cast(int, self.block.rollerPos) == 0
|
||||
|
||||
@property
|
||||
def current_cover_position(self) -> int:
|
||||
|
@ -73,7 +73,7 @@ class ShellyCover(ShellyBlockEntity, CoverEntity):
|
|||
if self.control_result:
|
||||
return cast(bool, self.control_result["state"] == "close")
|
||||
|
||||
return cast(bool, self.block.roller == "close")
|
||||
return self.block.roller == "close"
|
||||
|
||||
@property
|
||||
def is_opening(self) -> bool:
|
||||
|
@ -81,7 +81,7 @@ class ShellyCover(ShellyBlockEntity, CoverEntity):
|
|||
if self.control_result:
|
||||
return cast(bool, self.control_result["state"] == "open")
|
||||
|
||||
return cast(bool, self.block.roller == "open")
|
||||
return self.block.roller == "open"
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int:
|
||||
|
|
|
@ -60,6 +60,8 @@ async def async_validate_trigger_config(
|
|||
|
||||
trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])
|
||||
|
||||
assert wrapper.device.blocks
|
||||
|
||||
for block in wrapper.device.blocks:
|
||||
input_triggers = get_input_triggers(wrapper.device, block)
|
||||
if trigger in input_triggers:
|
||||
|
@ -93,6 +95,8 @@ async def async_get_triggers(
|
|||
)
|
||||
return triggers
|
||||
|
||||
assert wrapper.device.blocks
|
||||
|
||||
for block in wrapper.device.blocks:
|
||||
input_triggers = get_input_triggers(wrapper.device, block)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from dataclasses import dataclass
|
|||
import logging
|
||||
from typing import Any, Callable, Final, cast
|
||||
|
||||
import aioshelly
|
||||
from aioshelly.block_device import Block
|
||||
import async_timeout
|
||||
|
||||
from homeassistant.components.sensor import ATTR_STATE_CLASS
|
||||
|
@ -62,6 +62,8 @@ async def async_setup_block_attribute_entities(
|
|||
"""Set up entities for block attributes."""
|
||||
blocks = []
|
||||
|
||||
assert wrapper.device.blocks
|
||||
|
||||
for block in wrapper.device.blocks:
|
||||
for sensor_id in block.sensor_ids:
|
||||
description = sensors.get((block.type, sensor_id))
|
||||
|
@ -175,10 +177,10 @@ class BlockAttributeDescription:
|
|||
device_class: str | None = None
|
||||
state_class: str | None = None
|
||||
default_enabled: bool = True
|
||||
available: Callable[[aioshelly.Block], bool] | None = None
|
||||
available: Callable[[Block], bool] | None = None
|
||||
# Callable (settings, block), return true if entity should be removed
|
||||
removal_condition: Callable[[dict, aioshelly.Block], bool] | None = None
|
||||
extra_state_attributes: Callable[[aioshelly.Block], dict | None] | None = None
|
||||
removal_condition: Callable[[dict, Block], bool] | None = None
|
||||
extra_state_attributes: Callable[[Block], dict | None] | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -198,7 +200,7 @@ class RestAttributeDescription:
|
|||
class ShellyBlockEntity(entity.Entity):
|
||||
"""Helper class to represent a block."""
|
||||
|
||||
def __init__(self, wrapper: ShellyDeviceWrapper, block: aioshelly.Block) -> None:
|
||||
def __init__(self, wrapper: ShellyDeviceWrapper, block: Block) -> None:
|
||||
"""Initialize Shelly entity."""
|
||||
self.wrapper = wrapper
|
||||
self.block = block
|
||||
|
@ -267,7 +269,7 @@ class ShellyBlockAttributeEntity(ShellyBlockEntity, entity.Entity):
|
|||
def __init__(
|
||||
self,
|
||||
wrapper: ShellyDeviceWrapper,
|
||||
block: aioshelly.Block,
|
||||
block: Block,
|
||||
attribute: str,
|
||||
description: BlockAttributeDescription,
|
||||
) -> None:
|
||||
|
@ -418,7 +420,7 @@ class ShellySleepingBlockAttributeEntity(ShellyBlockAttributeEntity, RestoreEnti
|
|||
def __init__(
|
||||
self,
|
||||
wrapper: ShellyDeviceWrapper,
|
||||
block: aioshelly.Block,
|
||||
block: Block | None,
|
||||
attribute: str,
|
||||
description: BlockAttributeDescription,
|
||||
entry: entity_registry.RegistryEntry | None = None,
|
||||
|
@ -429,7 +431,7 @@ class ShellySleepingBlockAttributeEntity(ShellyBlockAttributeEntity, RestoreEnti
|
|||
self.last_state: StateType = None
|
||||
self.wrapper = wrapper
|
||||
self.attribute = attribute
|
||||
self.block = block
|
||||
self.block: Block | None = block # type: ignore[assignment]
|
||||
self.description = description
|
||||
self._unit = self.description.unit
|
||||
|
||||
|
@ -468,6 +470,8 @@ class ShellySleepingBlockAttributeEntity(ShellyBlockAttributeEntity, RestoreEnti
|
|||
|
||||
_, entity_block, entity_sensor = self.unique_id.split("-")
|
||||
|
||||
assert self.wrapper.device.blocks
|
||||
|
||||
for block in self.wrapper.device.blocks:
|
||||
if block.description != entity_block:
|
||||
continue
|
||||
|
|
|
@ -5,7 +5,7 @@ import asyncio
|
|||
import logging
|
||||
from typing import Any, Final, cast
|
||||
|
||||
from aioshelly import Block
|
||||
from aioshelly.block_device import Block
|
||||
import async_timeout
|
||||
|
||||
from homeassistant.components.light import (
|
||||
|
@ -117,7 +117,7 @@ class ShellyLight(ShellyBlockEntity, LightEntity):
|
|||
self._supported_features |= SUPPORT_EFFECT
|
||||
|
||||
if wrapper.model in MODELS_SUPPORTING_LIGHT_TRANSITION:
|
||||
match = FIRMWARE_PATTERN.search(wrapper.device.settings.get("fw"))
|
||||
match = FIRMWARE_PATTERN.search(wrapper.device.settings.get("fw", ""))
|
||||
if (
|
||||
match is not None
|
||||
and int(match[0]) >= LIGHT_TRANSITION_MIN_FIRMWARE_DATE
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Shelly",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/shelly",
|
||||
"requirements": ["aioshelly==0.6.4"],
|
||||
"requirements": ["aioshelly==1.0.0"],
|
||||
"zeroconf": [
|
||||
{
|
||||
"type": "_http._tcp.local.",
|
||||
|
|
|
@ -40,7 +40,7 @@ SENSORS: Final = {
|
|||
device_class=sensor.DEVICE_CLASS_BATTERY,
|
||||
state_class=sensor.STATE_CLASS_MEASUREMENT,
|
||||
removal_condition=lambda settings, _: settings.get("external_power") == 1,
|
||||
available=lambda block: cast(bool, block.battery != -1),
|
||||
available=lambda block: cast(int, block.battery) != -1,
|
||||
),
|
||||
("device", "deviceTemp"): BlockAttributeDescription(
|
||||
name="Device Temperature",
|
||||
|
@ -162,7 +162,7 @@ SENSORS: Final = {
|
|||
value=lambda value: round(value, 1),
|
||||
device_class=sensor.DEVICE_CLASS_TEMPERATURE,
|
||||
state_class=sensor.STATE_CLASS_MEASUREMENT,
|
||||
available=lambda block: cast(bool, block.extTemp != 999),
|
||||
available=lambda block: cast(int, block.extTemp) != 999,
|
||||
),
|
||||
("sensor", "humidity"): BlockAttributeDescription(
|
||||
name="Humidity",
|
||||
|
@ -170,14 +170,14 @@ SENSORS: Final = {
|
|||
value=lambda value: round(value, 1),
|
||||
device_class=sensor.DEVICE_CLASS_HUMIDITY,
|
||||
state_class=sensor.STATE_CLASS_MEASUREMENT,
|
||||
available=lambda block: cast(bool, block.extTemp != 999),
|
||||
available=lambda block: cast(int, block.extTemp) != 999,
|
||||
),
|
||||
("sensor", "luminosity"): BlockAttributeDescription(
|
||||
name="Luminosity",
|
||||
unit=LIGHT_LUX,
|
||||
device_class=sensor.DEVICE_CLASS_ILLUMINANCE,
|
||||
state_class=sensor.STATE_CLASS_MEASUREMENT,
|
||||
available=lambda block: cast(bool, block.luminosity != -1),
|
||||
available=lambda block: cast(int, block.luminosity) != -1,
|
||||
),
|
||||
("sensor", "tilt"): BlockAttributeDescription(
|
||||
name="Tilt",
|
||||
|
@ -191,7 +191,7 @@ SENSORS: Final = {
|
|||
icon="mdi:progress-wrench",
|
||||
value=lambda value: round(100 - (value / 3600 / SHAIR_MAX_WORK_HOURS), 1),
|
||||
extra_state_attributes=lambda block: {
|
||||
"Operational hours": round(block.totalWorkTime / 3600, 1)
|
||||
"Operational hours": round(cast(int, block.totalWorkTime) / 3600, 1)
|
||||
},
|
||||
),
|
||||
("adc", "adc"): BlockAttributeDescription(
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
|
||||
from typing import Any, cast
|
||||
|
||||
from aioshelly import Block
|
||||
from aioshelly.block_device import Block
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
|
|
@ -5,7 +5,7 @@ from datetime import datetime, timedelta
|
|||
import logging
|
||||
from typing import Any, Final, cast
|
||||
|
||||
import aioshelly
|
||||
from aioshelly.block_device import BLOCK_VALUE_UNIT, COAP, Block, BlockDevice
|
||||
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, TEMP_CELSIUS, TEMP_FAHRENHEIT
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
|
@ -40,18 +40,20 @@ async def async_remove_shelly_entity(
|
|||
|
||||
def temperature_unit(block_info: dict[str, Any]) -> str:
|
||||
"""Detect temperature unit."""
|
||||
if block_info[aioshelly.BLOCK_VALUE_UNIT] == "F":
|
||||
if block_info[BLOCK_VALUE_UNIT] == "F":
|
||||
return TEMP_FAHRENHEIT
|
||||
return TEMP_CELSIUS
|
||||
|
||||
|
||||
def get_device_name(device: aioshelly.Device) -> str:
|
||||
def get_device_name(device: BlockDevice) -> str:
|
||||
"""Naming for device."""
|
||||
return cast(str, device.settings["name"] or device.settings["device"]["hostname"])
|
||||
|
||||
|
||||
def get_number_of_channels(device: aioshelly.Device, block: aioshelly.Block) -> int:
|
||||
def get_number_of_channels(device: BlockDevice, block: Block) -> int:
|
||||
"""Get number of channels for block type."""
|
||||
assert isinstance(device.shelly, dict)
|
||||
|
||||
channels = None
|
||||
|
||||
if block.type == "input":
|
||||
|
@ -71,8 +73,8 @@ def get_number_of_channels(device: aioshelly.Device, block: aioshelly.Block) ->
|
|||
|
||||
|
||||
def get_entity_name(
|
||||
device: aioshelly.Device,
|
||||
block: aioshelly.Block,
|
||||
device: BlockDevice,
|
||||
block: Block | None,
|
||||
description: str | None = None,
|
||||
) -> str:
|
||||
"""Naming for switch and sensors."""
|
||||
|
@ -84,10 +86,7 @@ def get_entity_name(
|
|||
return channel_name
|
||||
|
||||
|
||||
def get_device_channel_name(
|
||||
device: aioshelly.Device,
|
||||
block: aioshelly.Block,
|
||||
) -> str:
|
||||
def get_device_channel_name(device: BlockDevice, block: Block | None) -> str:
|
||||
"""Get name based on device and channel name."""
|
||||
entity_name = get_device_name(device)
|
||||
|
||||
|
@ -98,8 +97,10 @@ def get_device_channel_name(
|
|||
):
|
||||
return entity_name
|
||||
|
||||
assert block.channel
|
||||
|
||||
channel_name: str | None = None
|
||||
mode = block.type + "s"
|
||||
mode = cast(str, block.type) + "s"
|
||||
if mode in device.settings:
|
||||
channel_name = device.settings[mode][int(block.channel)].get("name")
|
||||
|
||||
|
@ -114,7 +115,7 @@ def get_device_channel_name(
|
|||
return f"{entity_name} channel {chr(int(block.channel)+base)}"
|
||||
|
||||
|
||||
def is_momentary_input(settings: dict[str, Any], block: aioshelly.Block) -> bool:
|
||||
def is_momentary_input(settings: dict[str, Any], block: Block) -> bool:
|
||||
"""Return true if input button settings is set to a momentary type."""
|
||||
# Shelly Button type is fixed to momentary and no btn_type
|
||||
if settings["device"]["type"] in SHBTN_MODELS:
|
||||
|
@ -150,9 +151,7 @@ def get_device_uptime(status: dict[str, Any], last_uptime: str | None) -> str:
|
|||
return last_uptime
|
||||
|
||||
|
||||
def get_input_triggers(
|
||||
device: aioshelly.Device, block: aioshelly.Block
|
||||
) -> list[tuple[str, str]]:
|
||||
def get_input_triggers(device: BlockDevice, block: Block) -> list[tuple[str, str]]:
|
||||
"""Return list of input triggers for block."""
|
||||
if "inputEvent" not in block.sensor_ids or "inputEventCnt" not in block.sensor_ids:
|
||||
return []
|
||||
|
@ -165,6 +164,7 @@ def get_input_triggers(
|
|||
if block.type == "device" or get_number_of_channels(device, block) == 1:
|
||||
subtype = "button"
|
||||
else:
|
||||
assert block.channel
|
||||
subtype = f"button{int(block.channel)+1}"
|
||||
|
||||
if device.settings["device"]["type"] in SHBTN_MODELS:
|
||||
|
@ -181,9 +181,9 @@ def get_input_triggers(
|
|||
|
||||
|
||||
@singleton.singleton("shelly_coap")
|
||||
async def get_coap_context(hass: HomeAssistant) -> aioshelly.COAP:
|
||||
async def get_coap_context(hass: HomeAssistant) -> COAP:
|
||||
"""Get CoAP context to be used in all Shelly devices."""
|
||||
context = aioshelly.COAP()
|
||||
context = COAP()
|
||||
if DOMAIN in hass.data:
|
||||
port = hass.data[DOMAIN].get(CONF_COAP_PORT, DEFAULT_COAP_PORT)
|
||||
else:
|
||||
|
|
|
@ -240,7 +240,7 @@ aiopylgtv==0.4.0
|
|||
aiorecollect==1.0.8
|
||||
|
||||
# homeassistant.components.shelly
|
||||
aioshelly==0.6.4
|
||||
aioshelly==1.0.0
|
||||
|
||||
# homeassistant.components.switcher_kis
|
||||
aioswitcher==2.0.5
|
||||
|
|
|
@ -161,7 +161,7 @@ aiopylgtv==0.4.0
|
|||
aiorecollect==1.0.8
|
||||
|
||||
# homeassistant.components.shelly
|
||||
aioshelly==0.6.4
|
||||
aioshelly==1.0.0
|
||||
|
||||
# homeassistant.components.switcher_kis
|
||||
aioswitcher==2.0.5
|
||||
|
|
|
@ -32,10 +32,10 @@ async def test_form(hass):
|
|||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"aioshelly.get_info",
|
||||
"aioshelly.common.get_info",
|
||||
return_value={"mac": "test-mac", "type": "SHSW-1", "auth": False},
|
||||
), patch(
|
||||
"aioshelly.Device.create",
|
||||
"aioshelly.block_device.BlockDevice.create",
|
||||
new=AsyncMock(
|
||||
return_value=Mock(
|
||||
settings=MOCK_SETTINGS,
|
||||
|
@ -78,10 +78,10 @@ async def test_title_without_name(hass):
|
|||
settings["device"] = settings["device"].copy()
|
||||
settings["device"]["hostname"] = "shelly1pm-12345"
|
||||
with patch(
|
||||
"aioshelly.get_info",
|
||||
"aioshelly.common.get_info",
|
||||
return_value={"mac": "test-mac", "type": "SHSW-1", "auth": False},
|
||||
), patch(
|
||||
"aioshelly.Device.create",
|
||||
"aioshelly.block_device.BlockDevice.create",
|
||||
new=AsyncMock(
|
||||
return_value=Mock(
|
||||
settings=settings,
|
||||
|
@ -119,7 +119,7 @@ async def test_form_auth(hass):
|
|||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"aioshelly.get_info",
|
||||
"aioshelly.common.get_info",
|
||||
return_value={"mac": "test-mac", "type": "SHSW-1", "auth": True},
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
|
@ -131,7 +131,7 @@ async def test_form_auth(hass):
|
|||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"aioshelly.Device.create",
|
||||
"aioshelly.block_device.BlockDevice.create",
|
||||
new=AsyncMock(
|
||||
return_value=Mock(
|
||||
settings=MOCK_SETTINGS,
|
||||
|
@ -172,7 +172,7 @@ async def test_form_errors_get_info(hass, error):
|
|||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
with patch("aioshelly.get_info", side_effect=exc):
|
||||
with patch("aioshelly.common.get_info", side_effect=exc):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{"host": "1.1.1.1"},
|
||||
|
@ -193,8 +193,10 @@ async def test_form_errors_test_connection(hass, error):
|
|||
)
|
||||
|
||||
with patch(
|
||||
"aioshelly.get_info", return_value={"mac": "test-mac", "auth": False}
|
||||
), patch("aioshelly.Device.create", new=AsyncMock(side_effect=exc)):
|
||||
"aioshelly.common.get_info", return_value={"mac": "test-mac", "auth": False}
|
||||
), patch(
|
||||
"aioshelly.block_device.BlockDevice.create", new=AsyncMock(side_effect=exc)
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{"host": "1.1.1.1"},
|
||||
|
@ -217,7 +219,7 @@ async def test_form_already_configured(hass):
|
|||
)
|
||||
|
||||
with patch(
|
||||
"aioshelly.get_info",
|
||||
"aioshelly.common.get_info",
|
||||
return_value={"mac": "test-mac", "type": "SHSW-1", "auth": False},
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
|
@ -252,10 +254,10 @@ async def test_user_setup_ignored_device(hass):
|
|||
settings["fw"] = "20201124-092534/v1.9.0@57ac4ad8"
|
||||
|
||||
with patch(
|
||||
"aioshelly.get_info",
|
||||
"aioshelly.common.get_info",
|
||||
return_value={"mac": "test-mac", "type": "SHSW-1", "auth": False},
|
||||
), patch(
|
||||
"aioshelly.Device.create",
|
||||
"aioshelly.block_device.BlockDevice.create",
|
||||
new=AsyncMock(
|
||||
return_value=Mock(
|
||||
settings=settings,
|
||||
|
@ -287,7 +289,10 @@ async def test_form_firmware_unsupported(hass):
|
|||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
with patch("aioshelly.get_info", side_effect=aioshelly.FirmwareUnsupported):
|
||||
with patch(
|
||||
"aioshelly.common.get_info",
|
||||
side_effect=aioshelly.exceptions.FirmwareUnsupported,
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{"host": "1.1.1.1"},
|
||||
|
@ -313,14 +318,17 @@ async def test_form_auth_errors_test_connection(hass, error):
|
|||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
with patch("aioshelly.get_info", return_value={"mac": "test-mac", "auth": True}):
|
||||
with patch(
|
||||
"aioshelly.common.get_info",
|
||||
return_value={"mac": "test-mac", "auth": True},
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{"host": "1.1.1.1"},
|
||||
)
|
||||
|
||||
with patch(
|
||||
"aioshelly.Device.create",
|
||||
"aioshelly.block_device.BlockDevice.create",
|
||||
new=AsyncMock(side_effect=exc),
|
||||
):
|
||||
result3 = await hass.config_entries.flow.async_configure(
|
||||
|
@ -336,10 +344,10 @@ async def test_zeroconf(hass):
|
|||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
|
||||
with patch(
|
||||
"aioshelly.get_info",
|
||||
"aioshelly.common.get_info",
|
||||
return_value={"mac": "test-mac", "type": "SHSW-1", "auth": False},
|
||||
), patch(
|
||||
"aioshelly.Device.create",
|
||||
"aioshelly.block_device.BlockDevice.create",
|
||||
new=AsyncMock(
|
||||
return_value=Mock(
|
||||
settings=MOCK_SETTINGS,
|
||||
|
@ -388,7 +396,7 @@ async def test_zeroconf_sleeping_device(hass):
|
|||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
|
||||
with patch(
|
||||
"aioshelly.get_info",
|
||||
"aioshelly.common.get_info",
|
||||
return_value={
|
||||
"mac": "test-mac",
|
||||
"type": "SHSW-1",
|
||||
|
@ -396,7 +404,7 @@ async def test_zeroconf_sleeping_device(hass):
|
|||
"sleep_mode": True,
|
||||
},
|
||||
), patch(
|
||||
"aioshelly.Device.create",
|
||||
"aioshelly.block_device.BlockDevice.create",
|
||||
new=AsyncMock(
|
||||
return_value=Mock(
|
||||
settings={
|
||||
|
@ -460,7 +468,7 @@ async def test_zeroconf_sleeping_device_error(hass, error):
|
|||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
|
||||
with patch(
|
||||
"aioshelly.get_info",
|
||||
"aioshelly.common.get_info",
|
||||
return_value={
|
||||
"mac": "test-mac",
|
||||
"type": "SHSW-1",
|
||||
|
@ -468,7 +476,7 @@ async def test_zeroconf_sleeping_device_error(hass, error):
|
|||
"sleep_mode": True,
|
||||
},
|
||||
), patch(
|
||||
"aioshelly.Device.create",
|
||||
"aioshelly.block_device.BlockDevice.create",
|
||||
new=AsyncMock(side_effect=exc),
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
@ -489,7 +497,7 @@ async def test_zeroconf_already_configured(hass):
|
|||
entry.add_to_hass(hass)
|
||||
|
||||
with patch(
|
||||
"aioshelly.get_info",
|
||||
"aioshelly.common.get_info",
|
||||
return_value={"mac": "test-mac", "type": "SHSW-1", "auth": False},
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
@ -506,7 +514,10 @@ async def test_zeroconf_already_configured(hass):
|
|||
|
||||
async def test_zeroconf_firmware_unsupported(hass):
|
||||
"""Test we abort if device firmware is unsupported."""
|
||||
with patch("aioshelly.get_info", side_effect=aioshelly.FirmwareUnsupported):
|
||||
with patch(
|
||||
"aioshelly.common.get_info",
|
||||
side_effect=aioshelly.exceptions.FirmwareUnsupported,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
data=DISCOVERY_INFO,
|
||||
|
@ -519,7 +530,7 @@ async def test_zeroconf_firmware_unsupported(hass):
|
|||
|
||||
async def test_zeroconf_cannot_connect(hass):
|
||||
"""Test we get the form."""
|
||||
with patch("aioshelly.get_info", side_effect=asyncio.TimeoutError):
|
||||
with patch("aioshelly.common.get_info", side_effect=asyncio.TimeoutError):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
data=DISCOVERY_INFO,
|
||||
|
@ -534,7 +545,7 @@ async def test_zeroconf_require_auth(hass):
|
|||
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||
|
||||
with patch(
|
||||
"aioshelly.get_info",
|
||||
"aioshelly.common.get_info",
|
||||
return_value={"mac": "test-mac", "type": "SHSW-1", "auth": True},
|
||||
):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
@ -546,7 +557,7 @@ async def test_zeroconf_require_auth(hass):
|
|||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"aioshelly.Device.create",
|
||||
"aioshelly.block_device.BlockDevice.create",
|
||||
new=AsyncMock(
|
||||
return_value=Mock(
|
||||
settings=MOCK_SETTINGS,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue