mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Manual IP & port configuration for Konnected devices (#17120)
* add capability for manually specifying IP and port of Konnected device(s) * add config options for blink and discovery settings * import konnected only in functions where needed * updates from code review feedback * convert manual_discovery to async * code review updates; use correct sync vs async
This commit is contained in:
parent
83db673bd0
commit
11004bcf34
@ -4,9 +4,11 @@ Support for Konnected devices.
|
|||||||
For more details about this component, please refer to the documentation at
|
For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/konnected/
|
https://home-assistant.io/components/konnected/
|
||||||
"""
|
"""
|
||||||
import logging
|
import asyncio
|
||||||
import hmac
|
import hmac
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from aiohttp.hdrs import AUTHORIZATION
|
from aiohttp.hdrs import AUTHORIZATION
|
||||||
@ -16,17 +18,18 @@ from homeassistant.components.binary_sensor import DEVICE_CLASSES_SCHEMA
|
|||||||
from homeassistant.components.discovery import SERVICE_KONNECTED
|
from homeassistant.components.discovery import SERVICE_KONNECTED
|
||||||
from homeassistant.components.http import HomeAssistantView
|
from homeassistant.components.http import HomeAssistantView
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_UNAUTHORIZED,
|
EVENT_HOMEASSISTANT_START, HTTP_BAD_REQUEST, HTTP_NOT_FOUND,
|
||||||
CONF_DEVICES, CONF_BINARY_SENSORS, CONF_SWITCHES, CONF_HOST, CONF_PORT,
|
HTTP_UNAUTHORIZED, CONF_DEVICES, CONF_BINARY_SENSORS, CONF_SWITCHES,
|
||||||
CONF_ID, CONF_NAME, CONF_TYPE, CONF_PIN, CONF_ZONE, CONF_ACCESS_TOKEN,
|
CONF_HOST, CONF_PORT, CONF_ID, CONF_NAME, CONF_TYPE, CONF_PIN, CONF_ZONE,
|
||||||
ATTR_ENTITY_ID, ATTR_STATE, STATE_ON)
|
CONF_ACCESS_TOKEN, ATTR_ENTITY_ID, ATTR_STATE, STATE_ON)
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import (
|
||||||
|
async_dispatcher_send, dispatcher_send)
|
||||||
from homeassistant.helpers import discovery
|
from homeassistant.helpers import discovery
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
REQUIREMENTS = ['konnected==0.1.2']
|
REQUIREMENTS = ['konnected==0.1.4']
|
||||||
|
|
||||||
DOMAIN = 'konnected'
|
DOMAIN = 'konnected'
|
||||||
|
|
||||||
@ -36,6 +39,8 @@ CONF_MOMENTARY = 'momentary'
|
|||||||
CONF_PAUSE = 'pause'
|
CONF_PAUSE = 'pause'
|
||||||
CONF_REPEAT = 'repeat'
|
CONF_REPEAT = 'repeat'
|
||||||
CONF_INVERSE = 'inverse'
|
CONF_INVERSE = 'inverse'
|
||||||
|
CONF_BLINK = 'blink'
|
||||||
|
CONF_DISCOVERY = 'discovery'
|
||||||
|
|
||||||
STATE_LOW = 'low'
|
STATE_LOW = 'low'
|
||||||
STATE_HIGH = 'high'
|
STATE_HIGH = 'high'
|
||||||
@ -49,7 +54,7 @@ _BINARY_SENSOR_SCHEMA = vol.All(
|
|||||||
vol.Exclusive(CONF_ZONE, 's_pin'): vol.Any(*ZONE_TO_PIN),
|
vol.Exclusive(CONF_ZONE, 's_pin'): vol.Any(*ZONE_TO_PIN),
|
||||||
vol.Required(CONF_TYPE): DEVICE_CLASSES_SCHEMA,
|
vol.Required(CONF_TYPE): DEVICE_CLASSES_SCHEMA,
|
||||||
vol.Optional(CONF_NAME): cv.string,
|
vol.Optional(CONF_NAME): cv.string,
|
||||||
vol.Optional(CONF_INVERSE): cv.boolean,
|
vol.Optional(CONF_INVERSE, default=False): cv.boolean,
|
||||||
}), cv.has_at_least_one_key(CONF_PIN, CONF_ZONE)
|
}), cv.has_at_least_one_key(CONF_PIN, CONF_ZONE)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -81,6 +86,10 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
cv.ensure_list, [_BINARY_SENSOR_SCHEMA]),
|
cv.ensure_list, [_BINARY_SENSOR_SCHEMA]),
|
||||||
vol.Optional(CONF_SWITCHES): vol.All(
|
vol.Optional(CONF_SWITCHES): vol.All(
|
||||||
cv.ensure_list, [_SWITCH_SCHEMA]),
|
cv.ensure_list, [_SWITCH_SCHEMA]),
|
||||||
|
vol.Optional(CONF_HOST): cv.string,
|
||||||
|
vol.Optional(CONF_PORT): cv.port,
|
||||||
|
vol.Optional(CONF_BLINK, default=True): cv.boolean,
|
||||||
|
vol.Optional(CONF_DISCOVERY, default=True): cv.boolean,
|
||||||
}],
|
}],
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@ -96,6 +105,8 @@ SIGNAL_SENSOR_UPDATE = 'konnected.{}.update'
|
|||||||
|
|
||||||
async def async_setup(hass, config):
|
async def async_setup(hass, config):
|
||||||
"""Set up the Konnected platform."""
|
"""Set up the Konnected platform."""
|
||||||
|
import konnected
|
||||||
|
|
||||||
cfg = config.get(DOMAIN)
|
cfg = config.get(DOMAIN)
|
||||||
if cfg is None:
|
if cfg is None:
|
||||||
cfg = {}
|
cfg = {}
|
||||||
@ -107,10 +118,8 @@ async def async_setup(hass, config):
|
|||||||
CONF_API_HOST: cfg.get(CONF_API_HOST)
|
CONF_API_HOST: cfg.get(CONF_API_HOST)
|
||||||
}
|
}
|
||||||
|
|
||||||
def device_discovered(service, info):
|
def setup_device(host, port):
|
||||||
"""Call when a Konnected device has been discovered."""
|
"""Set up a Konnected device at `host` listening on `port`."""
|
||||||
host = info.get(CONF_HOST)
|
|
||||||
port = info.get(CONF_PORT)
|
|
||||||
discovered = DiscoveredDevice(hass, host, port)
|
discovered = DiscoveredDevice(hass, host, port)
|
||||||
if discovered.is_configured:
|
if discovered.is_configured:
|
||||||
discovered.setup()
|
discovered.setup()
|
||||||
@ -119,6 +128,33 @@ async def async_setup(hass, config):
|
|||||||
" but not specified in configuration.yaml",
|
" but not specified in configuration.yaml",
|
||||||
discovered.device_id)
|
discovered.device_id)
|
||||||
|
|
||||||
|
def device_discovered(service, info):
|
||||||
|
"""Call when a Konnected device has been discovered."""
|
||||||
|
host = info.get(CONF_HOST)
|
||||||
|
port = info.get(CONF_PORT)
|
||||||
|
setup_device(host, port)
|
||||||
|
|
||||||
|
async def manual_discovery(event):
|
||||||
|
"""Init devices on the network with manually assigned addresses."""
|
||||||
|
specified = [dev for dev in cfg.get(CONF_DEVICES) if
|
||||||
|
dev.get(CONF_HOST) and dev.get(CONF_PORT)]
|
||||||
|
|
||||||
|
while specified:
|
||||||
|
for dev in specified:
|
||||||
|
_LOGGER.debug("Discovering Konnected device %s at %s:%s",
|
||||||
|
dev.get(CONF_ID),
|
||||||
|
dev.get(CONF_HOST),
|
||||||
|
dev.get(CONF_PORT))
|
||||||
|
try:
|
||||||
|
await hass.async_add_executor_job(setup_device,
|
||||||
|
dev.get(CONF_HOST),
|
||||||
|
dev.get(CONF_PORT))
|
||||||
|
specified.remove(dev)
|
||||||
|
except konnected.Client.ClientError as err:
|
||||||
|
_LOGGER.error(err)
|
||||||
|
await asyncio.sleep(10) # try again in 10 seconds
|
||||||
|
|
||||||
|
# Initialize devices specified in the configuration on boot
|
||||||
for device in cfg.get(CONF_DEVICES):
|
for device in cfg.get(CONF_DEVICES):
|
||||||
ConfiguredDevice(hass, device).save_data()
|
ConfiguredDevice(hass, device).save_data()
|
||||||
|
|
||||||
@ -128,6 +164,7 @@ async def async_setup(hass, config):
|
|||||||
device_discovered)
|
device_discovered)
|
||||||
|
|
||||||
hass.http.register_view(KonnectedView(access_token))
|
hass.http.register_view(KonnectedView(access_token))
|
||||||
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, manual_discovery)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -188,6 +225,8 @@ class ConfiguredDevice:
|
|||||||
device_data = {
|
device_data = {
|
||||||
CONF_BINARY_SENSORS: sensors,
|
CONF_BINARY_SENSORS: sensors,
|
||||||
CONF_SWITCHES: actuators,
|
CONF_SWITCHES: actuators,
|
||||||
|
CONF_BLINK: self.config.get(CONF_BLINK),
|
||||||
|
CONF_DISCOVERY: self.config.get(CONF_DISCOVERY)
|
||||||
}
|
}
|
||||||
|
|
||||||
if CONF_DEVICES not in self.hass.data[DOMAIN]:
|
if CONF_DEVICES not in self.hass.data[DOMAIN]:
|
||||||
@ -271,7 +310,7 @@ class DiscoveredDevice:
|
|||||||
if sensor_config.get(CONF_INVERSE):
|
if sensor_config.get(CONF_INVERSE):
|
||||||
state = not state
|
state = not state
|
||||||
|
|
||||||
async_dispatcher_send(
|
dispatcher_send(
|
||||||
self.hass,
|
self.hass,
|
||||||
SIGNAL_SENSOR_UPDATE.format(entity_id),
|
SIGNAL_SENSOR_UPDATE.format(entity_id),
|
||||||
state)
|
state)
|
||||||
@ -306,13 +345,19 @@ class DiscoveredDevice:
|
|||||||
|
|
||||||
if (desired_sensor_configuration != current_sensor_configuration) or \
|
if (desired_sensor_configuration != current_sensor_configuration) or \
|
||||||
(current_actuator_config != desired_actuator_config) or \
|
(current_actuator_config != desired_actuator_config) or \
|
||||||
(current_api_endpoint != desired_api_endpoint):
|
(current_api_endpoint != desired_api_endpoint) or \
|
||||||
|
(self.status.get(CONF_BLINK) !=
|
||||||
|
self.stored_configuration.get(CONF_BLINK)) or \
|
||||||
|
(self.status.get(CONF_DISCOVERY) !=
|
||||||
|
self.stored_configuration.get(CONF_DISCOVERY)):
|
||||||
_LOGGER.info('pushing settings to device %s', self.device_id)
|
_LOGGER.info('pushing settings to device %s', self.device_id)
|
||||||
self.client.put_settings(
|
self.client.put_settings(
|
||||||
desired_sensor_configuration,
|
desired_sensor_configuration,
|
||||||
desired_actuator_config,
|
desired_actuator_config,
|
||||||
self.hass.data[DOMAIN].get(CONF_ACCESS_TOKEN),
|
self.hass.data[DOMAIN].get(CONF_ACCESS_TOKEN),
|
||||||
desired_api_endpoint
|
desired_api_endpoint,
|
||||||
|
blink=self.stored_configuration.get(CONF_BLINK),
|
||||||
|
discovery=self.stored_configuration.get(CONF_DISCOVERY)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -531,7 +531,7 @@ keyrings.alt==3.1
|
|||||||
kiwiki-client==0.1.1
|
kiwiki-client==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.konnected
|
# homeassistant.components.konnected
|
||||||
konnected==0.1.2
|
konnected==0.1.4
|
||||||
|
|
||||||
# homeassistant.components.eufy
|
# homeassistant.components.eufy
|
||||||
lakeside==0.10
|
lakeside==0.10
|
||||||
|
Loading…
x
Reference in New Issue
Block a user