1
mirror of https://github.com/home-assistant/core synced 2024-09-03 08:14:07 +02:00
ha-core/homeassistant/components/supla/__init__.py
Rocik d996a4a9a9
Add Supla gate (#31643)
* Add support for Supla gate with sensor

* Fix Supla switch module description and state access

* Add docs to methods of Supla gate

* Add missing comma

* Remove unused import

* Sort imports of Supla cover

* Add returning availability for every Supla device

* Use direct access to dict

* Remove deprecated property "hidden"

* Remove unused constant

* Revert using get function on dict
2020-02-24 15:34:53 +01:00

173 lines
5.0 KiB
Python

"""Support for Supla devices."""
import logging
from typing import Optional
from pysupla import SuplaAPI
import voluptuous as vol
from homeassistant.const import CONF_ACCESS_TOKEN
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.discovery import load_platform
from homeassistant.helpers.entity import Entity
_LOGGER = logging.getLogger(__name__)
DOMAIN = "supla"
CONF_SERVER = "server"
CONF_SERVERS = "servers"
SUPLA_FUNCTION_HA_CMP_MAP = {
"CONTROLLINGTHEROLLERSHUTTER": "cover",
"CONTROLLINGTHEGATE": "cover",
"LIGHTSWITCH": "switch",
}
SUPLA_FUNCTION_NONE = "NONE"
SUPLA_CHANNELS = "supla_channels"
SUPLA_SERVERS = "supla_servers"
SERVER_CONFIG = vol.Schema(
{vol.Required(CONF_SERVER): cv.string, vol.Required(CONF_ACCESS_TOKEN): cv.string}
)
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
{vol.Required(CONF_SERVERS): vol.All(cv.ensure_list, [SERVER_CONFIG])}
)
},
extra=vol.ALLOW_EXTRA,
)
def setup(hass, base_config):
"""Set up the Supla component."""
server_confs = base_config[DOMAIN][CONF_SERVERS]
hass.data[SUPLA_SERVERS] = {}
hass.data[SUPLA_CHANNELS] = {}
for server_conf in server_confs:
server_address = server_conf[CONF_SERVER]
server = SuplaAPI(server_address, server_conf[CONF_ACCESS_TOKEN])
# Test connection
try:
srv_info = server.get_server_info()
if srv_info.get("authenticated"):
hass.data[SUPLA_SERVERS][server_conf[CONF_SERVER]] = server
else:
_LOGGER.error(
"Server: %s not configured. API call returned: %s",
server_address,
srv_info,
)
return False
except OSError:
_LOGGER.exception(
"Server: %s not configured. Error on Supla API access: ", server_address
)
return False
discover_devices(hass, base_config)
return True
def discover_devices(hass, hass_config):
"""
Run periodically to discover new devices.
Currently it's only run at startup.
"""
component_configs = {}
for server_name, server in hass.data[SUPLA_SERVERS].items():
for channel in server.get_channels(include=["iodevice"]):
channel_function = channel["function"]["name"]
if channel_function == SUPLA_FUNCTION_NONE:
_LOGGER.debug(
"Ignored function: %s, channel id: %s",
channel_function,
channel["id"],
)
continue
component_name = SUPLA_FUNCTION_HA_CMP_MAP.get(channel_function)
if component_name is None:
_LOGGER.warning(
"Unsupported function: %s, channel id: %s",
channel_function,
channel["id"],
)
continue
channel["server_name"] = server_name
component_configs.setdefault(component_name, []).append(channel)
# Load discovered devices
for component_name, channel in component_configs.items():
load_platform(hass, component_name, "supla", channel, hass_config)
class SuplaChannel(Entity):
"""Base class of a Supla Channel (an equivalent of HA's Entity)."""
def __init__(self, channel_data):
"""Channel data -- raw channel information from PySupla."""
self.server_name = channel_data["server_name"]
self.channel_data = channel_data
@property
def server(self):
"""Return PySupla's server component associated with entity."""
return self.hass.data[SUPLA_SERVERS][self.server_name]
@property
def unique_id(self) -> str:
"""Return a unique ID."""
return "supla-{}-{}".format(
self.channel_data["iodevice"]["gUIDString"].lower(),
self.channel_data["channelNumber"],
)
@property
def name(self) -> Optional[str]:
"""Return the name of the device."""
return self.channel_data["caption"]
@property
def available(self) -> bool:
"""Return True if entity is available."""
if self.channel_data is None:
return False
state = self.channel_data.get("state")
if state is None:
return False
return state.get("connected")
def action(self, action, **add_pars):
"""
Run server action.
Actions are currently hardcoded in components.
Supla's API enables autodiscovery
"""
_LOGGER.debug(
"Executing action %s on channel %d, params: %s",
action,
self.channel_data["id"],
add_pars,
)
self.server.execute_action(self.channel_data["id"], action, **add_pars)
def update(self):
"""Call to update state."""
self.channel_data = self.server.get_channel(
self.channel_data["id"], include=["connected", "state"]
)