2020-11-05 17:38:53 +00:00
|
|
|
"""Shelly helpers functions."""
|
2020-11-11 19:13:14 +00:00
|
|
|
|
|
|
|
from datetime import datetime, timedelta
|
2020-11-05 17:38:53 +00:00
|
|
|
import logging
|
2020-11-11 08:05:08 +00:00
|
|
|
from typing import Optional
|
|
|
|
|
|
|
|
import aioshelly
|
2020-11-05 17:38:53 +00:00
|
|
|
|
2020-11-11 19:13:14 +00:00
|
|
|
from homeassistant.components.sensor import DEVICE_CLASS_TIMESTAMP
|
2020-11-11 08:05:08 +00:00
|
|
|
from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT
|
2020-11-05 17:38:53 +00:00
|
|
|
|
2020-11-11 08:05:08 +00:00
|
|
|
from . import ShellyDeviceWrapper
|
2020-11-19 10:42:24 +00:00
|
|
|
from .const import DOMAIN
|
2020-11-11 08:05:08 +00:00
|
|
|
|
2020-11-05 17:38:53 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2020-11-19 10:42:24 +00:00
|
|
|
async def async_remove_shelly_entity(hass, domain, unique_id):
|
|
|
|
"""Remove a Shelly entity."""
|
2020-11-05 17:38:53 +00:00
|
|
|
entity_reg = await hass.helpers.entity_registry.async_get_registry()
|
2020-11-19 10:42:24 +00:00
|
|
|
entity_id = entity_reg.async_get_entity_id(domain, DOMAIN, unique_id)
|
|
|
|
if entity_id:
|
|
|
|
_LOGGER.debug("Removing entity: %s", entity_id)
|
|
|
|
entity_reg.async_remove(entity_id)
|
2020-11-11 08:05:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
def temperature_unit(block_info: dict) -> str:
|
|
|
|
"""Detect temperature unit."""
|
|
|
|
if block_info[aioshelly.BLOCK_VALUE_UNIT] == "F":
|
|
|
|
return TEMP_FAHRENHEIT
|
|
|
|
return TEMP_CELSIUS
|
|
|
|
|
|
|
|
|
|
|
|
def get_entity_name(
|
|
|
|
wrapper: ShellyDeviceWrapper,
|
|
|
|
block: aioshelly.Block,
|
|
|
|
description: Optional[str] = None,
|
|
|
|
):
|
|
|
|
"""Naming for switch and sensors."""
|
|
|
|
entity_name = wrapper.name
|
|
|
|
|
2020-11-12 14:22:51 +00:00
|
|
|
if block:
|
|
|
|
channels = None
|
|
|
|
if block.type == "input":
|
|
|
|
channels = wrapper.device.shelly.get("num_inputs")
|
|
|
|
elif block.type == "emeter":
|
|
|
|
channels = wrapper.device.shelly.get("num_emeters")
|
|
|
|
elif block.type in ["relay", "light"]:
|
|
|
|
channels = wrapper.device.shelly.get("num_outputs")
|
|
|
|
elif block.type in ["roller", "device"]:
|
|
|
|
channels = 1
|
|
|
|
|
|
|
|
channels = channels or 1
|
|
|
|
|
|
|
|
if channels > 1 and block.type != "device":
|
|
|
|
entity_name = None
|
|
|
|
mode = block.type + "s"
|
|
|
|
if mode in wrapper.device.settings:
|
|
|
|
entity_name = wrapper.device.settings[mode][int(block.channel)].get(
|
|
|
|
"name"
|
|
|
|
)
|
|
|
|
|
|
|
|
if not entity_name:
|
|
|
|
if wrapper.model == "SHEM-3":
|
|
|
|
base = ord("A")
|
|
|
|
else:
|
|
|
|
base = ord("1")
|
|
|
|
entity_name = f"{wrapper.name} channel {chr(int(block.channel)+base)}"
|
|
|
|
|
|
|
|
# Shelly Dimmer has two input channels and missing "num_inputs"
|
|
|
|
if wrapper.model in ["SHDM-1", "SHDM-2"] and block.type == "input":
|
|
|
|
entity_name = f"{entity_name} channel {int(block.channel)+1}"
|
2020-11-11 08:05:08 +00:00
|
|
|
|
|
|
|
if description:
|
|
|
|
entity_name = f"{entity_name} {description}"
|
|
|
|
|
|
|
|
return entity_name
|
2020-11-11 19:13:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
def get_rest_value_from_path(status, device_class, path: str):
|
|
|
|
"""Parser for REST path from device status."""
|
|
|
|
|
|
|
|
if "/" not in path:
|
2020-11-19 09:47:23 +00:00
|
|
|
attribute_value = status[path]
|
2020-11-11 19:13:14 +00:00
|
|
|
else:
|
2020-11-19 09:47:23 +00:00
|
|
|
attribute_value = status[path.split("/")[0]][path.split("/")[1]]
|
2020-11-11 19:13:14 +00:00
|
|
|
if device_class == DEVICE_CLASS_TIMESTAMP:
|
2020-11-19 09:47:23 +00:00
|
|
|
last_boot = datetime.utcnow() - timedelta(seconds=attribute_value)
|
|
|
|
attribute_value = last_boot.replace(microsecond=0).isoformat()
|
2020-11-11 19:13:14 +00:00
|
|
|
|
2020-11-19 10:42:24 +00:00
|
|
|
if "new_version" in path:
|
|
|
|
attribute_value = attribute_value.split("/")[1].split("@")[0]
|
|
|
|
|
2020-11-19 09:47:23 +00:00
|
|
|
return attribute_value
|
2020-11-19 10:42:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
def is_momentary_input(settings: dict, block: aioshelly.Block) -> bool:
|
|
|
|
"""Return true if input button settings is set to a momentary type."""
|
|
|
|
button = settings.get("relays") or settings.get("lights") or settings.get("inputs")
|
|
|
|
|
|
|
|
# Shelly 1L has two button settings in the first channel
|
|
|
|
if settings["device"]["type"] == "SHSW-L":
|
|
|
|
channel = int(block.channel or 0) + 1
|
|
|
|
button_type = button[0].get("btn" + str(channel) + "_type")
|
|
|
|
else:
|
|
|
|
# Some devices has only one channel in settings
|
|
|
|
channel = min(int(block.channel or 0), len(button) - 1)
|
|
|
|
button_type = button[channel].get("btn_type")
|
|
|
|
|
|
|
|
return button_type in ["momentary", "momentary_on_release"]
|