1 """Support for Konnected devices."""
48 from .errors
import CannotConnect
50 _LOGGER = logging.getLogger(__name__)
52 KONN_MODEL =
"Konnected"
53 KONN_MODEL_PRO =
"Konnected Pro"
58 KONN_MODEL_PRO: CONF_ZONE,
63 """A representation of a Konnected alarm panel."""
66 """Initialize the Konnected device."""
69 self.
configconfig = config_entry.data
70 self.
optionsoptions = config_entry.options
or config_entry.data.get(
71 CONF_DEFAULT_OPTIONS, {}
84 """Device id is the chipId (pro) or MAC address as string with punctuation removed."""
89 """Return the configuration stored in `hass.data` for this device."""
94 """Return whether the device is available."""
98 """Get zone or pin based dict based on the client type."""
102 else ZONE_TO_PIN[zone]
104 payload.update(other_items
or {})
108 """Connect to and setup a Konnected device."""
117 self.
clientclient = konnected.Client(
120 websession=aiohttp_client.async_get_clientsession(self.
hasshass),
123 self.
api_versionapi_version = KONN_API_VERSIONS.get(
124 self.
statusstatus.
get(
"model", KONN_MODEL), KONN_API_VERSIONS[KONN_MODEL]
127 "Connected to new %s device", self.
statusstatus.
get(
"model",
"Konnected")
129 _LOGGER.debug(self.
statusstatus)
133 await asyncio.sleep(0.1)
136 except self.
clientclient.ClientError
as err:
137 _LOGGER.warning(
"Exception trying to connect to panel: %s", err)
150 "Set up Konnected device %s. Open http://%s:%s in a "
151 "web browser to view device status"
158 device_registry = dr.async_get(self.
hasshass)
159 device_registry.async_get_or_create(
161 connections={(dr.CONNECTION_NETWORK_MAC, self.
statusstatus.
get(
"mac"))},
162 identifiers={(DOMAIN, self.
device_iddevice_id)},
163 manufacturer=
"Konnected.io",
166 sw_version=self.
statusstatus.
get(
"swVersion"),
169 async
def update_switch(self, zone, state, momentary=None, times=None, pause=None):
170 """Update the state of a switchable output."""
174 return await self.
clientclient.put_zone(
183 return await self.
clientclient.put_device(
191 except self.
clientclient.ClientError
as err:
192 _LOGGER.warning(
"Exception trying to update panel: %s", err)
197 """Save the device configuration to `hass.data`."""
199 for entity
in self.
optionsoptions.
get(CONF_BINARY_SENSORS)
or []:
200 zone = entity[CONF_ZONE]
202 binary_sensors[zone] = {
203 CONF_TYPE: entity[CONF_TYPE],
204 CONF_NAME: entity.get(
205 CONF_NAME, f
"Konnected {self.device_id[6:]} Zone {zone}"
207 CONF_INVERSE: entity.get(CONF_INVERSE),
211 "Set up binary_sensor %s (initial state: %s)",
212 binary_sensors[zone].
get(
"name"),
213 binary_sensors[zone].
get(ATTR_STATE),
217 for entity
in self.
optionsoptions.
get(CONF_SWITCHES)
or []:
218 zone = entity[CONF_ZONE]
222 CONF_NAME: entity.get(
224 f
"Konnected {self.device_id[6:]} Actuator {zone}",
227 CONF_ACTIVATION: entity[CONF_ACTIVATION],
228 CONF_MOMENTARY: entity.get(CONF_MOMENTARY),
229 CONF_PAUSE: entity.get(CONF_PAUSE),
230 CONF_REPEAT: entity.get(CONF_REPEAT),
232 actuators.append(act)
233 _LOGGER.debug(
"Set up switch %s", act)
236 for entity
in self.
optionsoptions.
get(CONF_SENSORS)
or []:
237 zone = entity[CONF_ZONE]
241 CONF_NAME: entity.get(
242 CONF_NAME, f
"Konnected {self.device_id[6:]} Sensor {zone}"
244 CONF_TYPE: entity[CONF_TYPE],
245 CONF_POLL_INTERVAL: entity.get(CONF_POLL_INTERVAL),
247 sensors.append(sensor)
249 "Set up %s sensor %s (initial state: %s)",
250 sensor.get(CONF_TYPE),
251 sensor.get(CONF_NAME),
252 sensor.get(ATTR_STATE),
256 CONF_BINARY_SENSORS: binary_sensors,
257 CONF_SENSORS: sensors,
258 CONF_SWITCHES: actuators,
259 CONF_BLINK: self.
optionsoptions.
get(CONF_BLINK),
260 CONF_DISCOVERY: self.
optionsoptions.
get(CONF_DISCOVERY),
261 CONF_HOST: self.
hosthost,
262 CONF_PORT: self.
portport,
266 if CONF_DEVICES
not in self.
hasshass.data[DOMAIN]:
267 self.
hasshass.data[DOMAIN][CONF_DEVICES] = {}
270 "Storing data in hass.data[%s][%s][%s]: %s",
276 self.
hasshass.data[DOMAIN][CONF_DEVICES][self.
device_iddevice_id] = device_data
280 """Return the configuration map for syncing binary sensors."""
287 """Return the configuration map for syncing actuators."""
291 {
"trigger": (0
if data.get(CONF_ACTIVATION)
in [0, STATE_LOW]
else 1)},
298 """Return the configuration map for syncing DHT sensors."""
301 sensor[CONF_ZONE], {CONF_POLL_INTERVAL: sensor[CONF_POLL_INTERVAL]}
304 if sensor[CONF_TYPE] ==
"dht"
309 """Return the configuration map for syncing DS18B20 sensors."""
312 sensor[CONF_ZONE], {CONF_POLL_INTERVAL: sensor[CONF_POLL_INTERVAL]}
315 if sensor[CONF_TYPE] ==
"ds18b20"
319 """Update the initial state of each sensor from status poll."""
320 for sensor_data
in self.
statusstatus.
get(
"sensors"):
322 sensor_data.get(CONF_ZONE, sensor_data.get(CONF_PIN)), {}
324 entity_id = sensor_config.get(ATTR_ENTITY_ID)
326 state = bool(sensor_data.get(ATTR_STATE))
327 if sensor_config.get(CONF_INVERSE):
334 """Return a dict representing the desired device configuration."""
337 desired_api_host = self.
optionsoptions.
get(CONF_API_HOST)
or (
340 desired_api_endpoint = desired_api_host + ENDPOINT_ROOT
347 "auth_token": self.
configconfig.
get(CONF_ACCESS_TOKEN),
348 "endpoint": desired_api_endpoint,
349 "blink": self.
optionsoptions.
get(CONF_BLINK,
True),
350 "discovery": self.
optionsoptions.
get(CONF_DISCOVERY,
True),
355 """Return a dict of configuration currently stored on the device."""
356 settings = self.
statusstatus[
"settings"]
or {}
361 for s
in self.
statusstatus.
get(
"sensors")
363 "actuators": self.
statusstatus.
get(
"actuators"),
364 "dht_sensors": self.
statusstatus.
get(CONF_DHT_SENSORS),
365 "ds18b20_sensors": self.
statusstatus.
get(CONF_DS18B20_SENSORS),
366 "auth_token": settings.get(
"token"),
367 "endpoint": settings.get(
"endpoint"),
368 "blink": settings.get(CONF_BLINK),
369 "discovery": settings.get(CONF_DISCOVERY),
373 """Sync the new zone configuration to the Konnected device if needed."""
375 "Device %s settings payload: %s",
383 _LOGGER.debug(
"Pushing settings to device %s", self.
device_iddevice_id)
388 """Get the status of a Konnected Panel."""
389 client = konnected.Client(
390 host,
str(port), aiohttp_client.async_get_clientsession(hass)
393 return await client.get_status()
395 except client.ClientError
as err:
396 _LOGGER.error(
"Exception trying to get panel status: %s", err)
397 raise CannotConnect
from err
def async_ds18b20_sensor_configuration(self)
def async_connect(self, now=None)
def async_desired_settings_payload(self)
def async_sync_device_config(self)
def async_update_initial_states(self)
def async_binary_sensor_configuration(self)
def async_current_settings_payload(self)
def stored_configuration(self)
def __init__(self, hass, config_entry)
def async_actuator_configuration(self)
def format_zone(self, zone, other_items=None)
def async_save_data(self)
def async_dht_sensor_configuration(self)
def update_switch(self, zone, state, momentary=None, times=None, pause=None)
web.Response get(self, web.Request request, str config_key)
def get_status(hass, host, port)
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)
CALLBACK_TYPE async_call_later(HomeAssistant hass, float|timedelta delay, HassJob[[datetime], Coroutine[Any, Any, None]|None]|Callable[[datetime], Coroutine[Any, Any, None]|None] action)
str get_url(HomeAssistant hass, *bool require_current_request=False, bool require_ssl=False, bool require_standard_port=False, bool require_cloud=False, bool allow_internal=True, bool allow_external=True, bool allow_cloud=True, bool|None allow_ip=None, bool|None prefer_external=None, bool prefer_cloud=False)