mirror of
https://github.com/home-assistant/core.git
synced 2026-05-08 09:38:58 +01:00
51acdeb563
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Erik Montnemery <erik@montnemery.com> Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
196 lines
6.2 KiB
Python
196 lines
6.2 KiB
Python
"""Switch platform for the Orvibo integration."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from orvibo.s20 import S20, S20Exception
|
|
import voluptuous as vol
|
|
|
|
from homeassistant import config_entries
|
|
from homeassistant.components.switch import (
|
|
PLATFORM_SCHEMA as SWITCH_PLATFORM_SCHEMA,
|
|
SwitchEntity,
|
|
)
|
|
from homeassistant.const import (
|
|
CONF_DISCOVERY,
|
|
CONF_HOST,
|
|
CONF_MAC,
|
|
CONF_NAME,
|
|
CONF_SWITCHES,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.data_entry_flow import FlowResultType
|
|
from homeassistant.exceptions import HomeAssistantError
|
|
from homeassistant.helpers import config_validation as cv, issue_registry as ir
|
|
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
|
|
from homeassistant.helpers.entity_platform import (
|
|
AddConfigEntryEntitiesCallback,
|
|
AddEntitiesCallback,
|
|
)
|
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|
|
|
from .const import DEFAULT_NAME, DOMAIN
|
|
from .models import S20ConfigEntry
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
DEFAULT_DISCOVERY = False
|
|
|
|
# Library is not thread safe and uses global variables, so we limit to 1 update at a time
|
|
PARALLEL_UPDATES = 1
|
|
|
|
PLATFORM_SCHEMA = SWITCH_PLATFORM_SCHEMA.extend(
|
|
{
|
|
vol.Required(CONF_SWITCHES, default=[]): vol.All(
|
|
cv.ensure_list,
|
|
[
|
|
{
|
|
vol.Required(CONF_HOST): cv.string,
|
|
vol.Optional(CONF_MAC): cv.string,
|
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
}
|
|
],
|
|
),
|
|
vol.Optional(CONF_DISCOVERY, default=DEFAULT_DISCOVERY): cv.boolean,
|
|
}
|
|
)
|
|
|
|
|
|
async def async_setup_platform(
|
|
hass: HomeAssistant,
|
|
config: ConfigType,
|
|
add_entities_callback: AddEntitiesCallback,
|
|
discovery_info: DiscoveryInfoType | None = None,
|
|
) -> None:
|
|
"""Set up the integration from configuration.yaml."""
|
|
for switch in config.get(CONF_SWITCHES, []):
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN,
|
|
context={"source": config_entries.SOURCE_IMPORT},
|
|
data=switch,
|
|
)
|
|
|
|
if (
|
|
result.get("type") is FlowResultType.ABORT
|
|
and result.get("reason") != "already_configured"
|
|
):
|
|
ir.async_create_issue(
|
|
hass,
|
|
DOMAIN,
|
|
f"yaml_deprecation_import_issue_{switch.get('host')}_{(switch.get('mac') or 'unknown_mac').replace(':', '').lower()}",
|
|
breaks_in_ha_version="2026.9.0",
|
|
is_fixable=False,
|
|
is_persistent=False,
|
|
issue_domain=DOMAIN,
|
|
severity=ir.IssueSeverity.WARNING,
|
|
translation_key="yaml_deprecation_import_issue",
|
|
translation_placeholders={
|
|
"reason": str(result.get("reason")),
|
|
"host": switch.get("host"),
|
|
"mac": switch.get("mac", ""),
|
|
},
|
|
)
|
|
continue
|
|
|
|
ir.async_create_issue(
|
|
hass,
|
|
DOMAIN,
|
|
f"yaml_deprecation_{switch.get('host')}_{(switch.get('mac') or 'unknown_mac').replace(':', '').lower()}",
|
|
breaks_in_ha_version="2026.9.0",
|
|
is_fixable=False,
|
|
is_persistent=False,
|
|
severity=ir.IssueSeverity.WARNING,
|
|
translation_key="yaml_deprecation",
|
|
translation_placeholders={
|
|
"host": switch.get("host"),
|
|
"mac": switch.get("mac") or "Unknown MAC",
|
|
},
|
|
)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
entry: S20ConfigEntry,
|
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
) -> None:
|
|
"""Set up orvibo from a config entry."""
|
|
async_add_entities(
|
|
[
|
|
S20Switch(
|
|
entry.title,
|
|
entry.data[CONF_HOST],
|
|
entry.data[CONF_MAC],
|
|
entry.runtime_data,
|
|
)
|
|
]
|
|
)
|
|
|
|
|
|
class S20Switch(SwitchEntity):
|
|
"""Representation of an S20 switch."""
|
|
|
|
_attr_has_entity_name = True
|
|
|
|
def __init__(self, name: str, host: str, mac: str, s20: S20) -> None:
|
|
"""Initialize the S20 device."""
|
|
|
|
self._attr_is_on = False
|
|
self._host = host
|
|
self._mac = mac
|
|
self._s20 = s20
|
|
self._attr_unique_id = self._mac
|
|
self._name = name
|
|
self._attr_name = None
|
|
self._attr_device_info = DeviceInfo(
|
|
identifiers={
|
|
# MAC addresses are used as unique identifiers within this domain
|
|
(DOMAIN, self._attr_unique_id)
|
|
},
|
|
name=name,
|
|
manufacturer="Orvibo",
|
|
model="S20",
|
|
connections={(CONNECTION_NETWORK_MAC, self._mac)},
|
|
)
|
|
|
|
def turn_on(self, **kwargs: Any) -> None:
|
|
"""Turn the device on."""
|
|
try:
|
|
self._s20.on = True
|
|
except S20Exception as err:
|
|
raise HomeAssistantError(
|
|
translation_domain=DOMAIN,
|
|
translation_key="turn_on_error",
|
|
translation_placeholders={"name": self._name},
|
|
) from err
|
|
|
|
def turn_off(self, **kwargs: Any) -> None:
|
|
"""Turn the device off."""
|
|
try:
|
|
self._s20.on = False
|
|
except S20Exception as err:
|
|
raise HomeAssistantError(
|
|
translation_domain=DOMAIN,
|
|
translation_key="turn_off_error",
|
|
translation_placeholders={"name": self._name},
|
|
) from err
|
|
|
|
def update(self) -> None:
|
|
"""Update device state."""
|
|
try:
|
|
self._attr_is_on = self._s20.on
|
|
|
|
# If the device was previously offline, let the user know it's back!
|
|
if not self._attr_available:
|
|
_LOGGER.info("Orvibo switch %s reconnected", self._name)
|
|
self._attr_available = True
|
|
|
|
except S20Exception as err:
|
|
# Only log the error if this is the FIRST time it failed
|
|
if self._attr_available:
|
|
_LOGGER.info(
|
|
"Error communicating with Orvibo switch %s: %s", self._name, err
|
|
)
|
|
self._attr_available = False
|