Change Insteon backend module to pyinsteon from insteonplm (#35198)
* Migrate to pyinsteon from insteonplm * Rename devices entities * Print ALDB even if not loaded * Add relay to name map * Change insteonplm to pyinsteon * Update requirements_all correctly * Code review updates * async_set_speed receive std speed value * default speed to std medium value * Call async methods for fan on/off * Comment await required in loop * Remove emtpy and add codeowner * Make services async and remove async_add_job call * Remove extra logging * New device as async task and aldb load in loop * Place lock in context bloxk * Limiting lock to min * Remove .env filepull/35739/head
parent
47801e7350
commit
dbd821a564
|
@ -194,6 +194,7 @@ homeassistant/components/input_datetime/* @home-assistant/core
|
|||
homeassistant/components/input_number/* @home-assistant/core
|
||||
homeassistant/components/input_select/* @home-assistant/core
|
||||
homeassistant/components/input_text/* @home-assistant/core
|
||||
homeassistant/components/insteon/* @teharris1
|
||||
homeassistant/components/integration/* @dgomes
|
||||
homeassistant/components/intent/* @home-assistant/core
|
||||
homeassistant/components/intesishome/* @jnimmo
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
"""Support for INSTEON Modems (PLM and Hub)."""
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
import insteonplm
|
||||
from pyinsteon import async_close, async_connect, devices
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
|
@ -24,21 +25,75 @@ from .const import (
|
|||
CONF_SUBCAT,
|
||||
CONF_UNITCODE,
|
||||
CONF_X10,
|
||||
CONF_X10_ALL_LIGHTS_OFF,
|
||||
CONF_X10_ALL_LIGHTS_ON,
|
||||
CONF_X10_ALL_UNITS_OFF,
|
||||
DOMAIN,
|
||||
INSTEON_ENTITIES,
|
||||
INSTEON_COMPONENTS,
|
||||
ON_OFF_EVENTS,
|
||||
)
|
||||
from .schemas import CONFIG_SCHEMA # noqa F440
|
||||
from .utils import async_register_services, register_new_device_callback
|
||||
from .utils import (
|
||||
add_on_off_event_device,
|
||||
async_register_services,
|
||||
get_device_platforms,
|
||||
register_new_device_callback,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_id_unknown_devices(config_dir):
|
||||
"""Send device ID commands to all unidentified devices."""
|
||||
await devices.async_load(id_devices=1)
|
||||
for addr in devices:
|
||||
device = devices[addr]
|
||||
flags = True
|
||||
for name in device.operating_flags:
|
||||
if not device.operating_flags[name].is_loaded:
|
||||
flags = False
|
||||
break
|
||||
if flags:
|
||||
for name in device.properties:
|
||||
if not device.properties[name].is_loaded:
|
||||
flags = False
|
||||
break
|
||||
|
||||
# Cannot be done concurrently due to issues with the underlying protocol.
|
||||
if not device.aldb.is_loaded or not flags:
|
||||
await device.async_read_config()
|
||||
|
||||
await devices.async_save(workdir=config_dir)
|
||||
|
||||
|
||||
async def async_setup_platforms(hass, config):
|
||||
"""Initiate the connection and services."""
|
||||
tasks = [
|
||||
hass.helpers.discovery.async_load_platform(component, DOMAIN, {}, config)
|
||||
for component in INSTEON_COMPONENTS
|
||||
]
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
for address in devices:
|
||||
device = devices[address]
|
||||
platforms = get_device_platforms(device)
|
||||
if ON_OFF_EVENTS in platforms:
|
||||
add_on_off_event_device(hass, device)
|
||||
|
||||
_LOGGER.debug("Insteon device count: %s", len(devices))
|
||||
register_new_device_callback(hass, config)
|
||||
async_register_services(hass)
|
||||
|
||||
# Cannot be done concurrently due to issues with the underlying protocol.
|
||||
for address in devices:
|
||||
await devices[address].async_status()
|
||||
await async_id_unknown_devices(hass.config.config_dir)
|
||||
|
||||
|
||||
async def close_insteon_connection(*args):
|
||||
"""Close the Insteon connection."""
|
||||
await async_close()
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
"""Set up the connection to the modem."""
|
||||
insteon_modem = None
|
||||
|
||||
conf = config[DOMAIN]
|
||||
port = conf.get(CONF_PORT)
|
||||
|
@ -47,68 +102,50 @@ async def async_setup(hass, config):
|
|||
username = conf.get(CONF_HUB_USERNAME)
|
||||
password = conf.get(CONF_HUB_PASSWORD)
|
||||
hub_version = conf.get(CONF_HUB_VERSION)
|
||||
overrides = conf.get(CONF_OVERRIDE, [])
|
||||
x10_devices = conf.get(CONF_X10, [])
|
||||
x10_all_units_off_housecode = conf.get(CONF_X10_ALL_UNITS_OFF)
|
||||
x10_all_lights_on_housecode = conf.get(CONF_X10_ALL_LIGHTS_ON)
|
||||
x10_all_lights_off_housecode = conf.get(CONF_X10_ALL_LIGHTS_OFF)
|
||||
|
||||
if host:
|
||||
_LOGGER.info("Connecting to Insteon Hub on %s", host)
|
||||
conn = await insteonplm.Connection.create(
|
||||
_LOGGER.info("Connecting to Insteon Hub on %s:%d", host, ip_port)
|
||||
else:
|
||||
_LOGGER.info("Connecting to Insteon PLM on %s", port)
|
||||
|
||||
try:
|
||||
await async_connect(
|
||||
device=port,
|
||||
host=host,
|
||||
port=ip_port,
|
||||
username=username,
|
||||
password=password,
|
||||
hub_version=hub_version,
|
||||
loop=hass.loop,
|
||||
workdir=hass.config.config_dir,
|
||||
)
|
||||
else:
|
||||
_LOGGER.info("Looking for Insteon PLM on %s", port)
|
||||
conn = await insteonplm.Connection.create(
|
||||
device=port, loop=hass.loop, workdir=hass.config.config_dir
|
||||
)
|
||||
except ConnectionError:
|
||||
_LOGGER.error("Could not connect to Insteon modem")
|
||||
return False
|
||||
_LOGGER.info("Connection to Insteon modem successful")
|
||||
|
||||
insteon_modem = conn.protocol
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, close_insteon_connection)
|
||||
conf = config[DOMAIN]
|
||||
overrides = conf.get(CONF_OVERRIDE, [])
|
||||
x10_devices = conf.get(CONF_X10, [])
|
||||
|
||||
hass.data[DOMAIN] = {}
|
||||
hass.data[DOMAIN]["modem"] = insteon_modem
|
||||
hass.data[DOMAIN][INSTEON_ENTITIES] = set()
|
||||
|
||||
register_new_device_callback(hass, config, insteon_modem)
|
||||
async_register_services(hass, config, insteon_modem)
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, conn.close)
|
||||
await devices.async_load(
|
||||
workdir=hass.config.config_dir, id_devices=0, load_modem_aldb=0
|
||||
)
|
||||
|
||||
for device_override in overrides:
|
||||
#
|
||||
# Override the device default capabilities for a specific address
|
||||
#
|
||||
address = device_override.get("address")
|
||||
for prop in device_override:
|
||||
if prop in [CONF_CAT, CONF_SUBCAT]:
|
||||
insteon_modem.devices.add_override(address, prop, device_override[prop])
|
||||
elif prop in [CONF_FIRMWARE, CONF_PRODUCT_KEY]:
|
||||
insteon_modem.devices.add_override(
|
||||
address, CONF_PRODUCT_KEY, device_override[prop]
|
||||
)
|
||||
if not devices.get(address):
|
||||
cat = device_override[CONF_CAT]
|
||||
subcat = device_override[CONF_SUBCAT]
|
||||
firmware = device_override.get(CONF_FIRMWARE)
|
||||
if firmware is None:
|
||||
firmware = device_override.get(CONF_PRODUCT_KEY, 0)
|
||||
devices.set_id(address, cat, subcat, firmware)
|
||||
|
||||
if x10_all_units_off_housecode:
|
||||
device = insteon_modem.add_x10_device(
|
||||
x10_all_units_off_housecode, 20, "allunitsoff"
|
||||
)
|
||||
if x10_all_lights_on_housecode:
|
||||
device = insteon_modem.add_x10_device(
|
||||
x10_all_lights_on_housecode, 21, "alllightson"
|
||||
)
|
||||
if x10_all_lights_off_housecode:
|
||||
device = insteon_modem.add_x10_device(
|
||||
x10_all_lights_off_housecode, 22, "alllightsoff"
|
||||
)
|
||||
for device in x10_devices:
|
||||
housecode = device.get(CONF_HOUSECODE)
|
||||
unitcode = device.get(CONF_UNITCODE)
|
||||
x10_type = "onoff"
|
||||
x10_type = "on_off"
|
||||
steps = device.get(CONF_DIM_STEPS, 22)
|
||||
if device.get(CONF_PLATFORM) == "light":
|
||||
x10_type = "dimmable"
|
||||
|
@ -117,8 +154,7 @@ async def async_setup(hass, config):
|
|||
_LOGGER.debug(
|
||||
"Adding X10 device to Insteon: %s %d %s", housecode, unitcode, x10_type
|
||||
)
|
||||
device = insteon_modem.add_x10_device(housecode, unitcode, x10_type)
|
||||
if device and hasattr(device.states[0x01], "steps"):
|
||||
device.states[0x01].steps = steps
|
||||
device = devices.add_x10_device(housecode, unitcode, x10_type, steps)
|
||||
|
||||
asyncio.create_task(async_setup_platforms(hass, config))
|
||||
return True
|
||||
|
|
|
@ -1,50 +1,69 @@
|
|||
"""Support for INSTEON dimmers via PowerLinc Modem."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorEntity
|
||||
from pyinsteon.groups import (
|
||||
CO_SENSOR,
|
||||
DOOR_SENSOR,
|
||||
HEARTBEAT,
|
||||
LEAK_SENSOR_WET,
|
||||
LIGHT_SENSOR,
|
||||
LOW_BATTERY,
|
||||
MOTION_SENSOR,
|
||||
OPEN_CLOSE_SENSOR,
|
||||
SENSOR_MALFUNCTION,
|
||||
SMOKE_SENSOR,
|
||||
TEST_SENSOR,
|
||||
)
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
DEVICE_CLASS_BATTERY,
|
||||
DEVICE_CLASS_DOOR,
|
||||
DEVICE_CLASS_GAS,
|
||||
DEVICE_CLASS_LIGHT,
|
||||
DEVICE_CLASS_MOISTURE,
|
||||
DEVICE_CLASS_MOTION,
|
||||
DEVICE_CLASS_OPENING,
|
||||
DEVICE_CLASS_PROBLEM,
|
||||
DEVICE_CLASS_SAFETY,
|
||||
DEVICE_CLASS_SMOKE,
|
||||
DOMAIN,
|
||||
BinarySensorEntity,
|
||||
)
|
||||
|
||||
from .insteon_entity import InsteonEntity
|
||||
from .utils import async_add_insteon_entities
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SENSOR_TYPES = {
|
||||
"openClosedSensor": "opening",
|
||||
"ioLincSensor": "opening",
|
||||
"motionSensor": "motion",
|
||||
"doorSensor": "door",
|
||||
"wetLeakSensor": "moisture",
|
||||
"lightSensor": "light",
|
||||
"batterySensor": "battery",
|
||||
OPEN_CLOSE_SENSOR: DEVICE_CLASS_OPENING,
|
||||
MOTION_SENSOR: DEVICE_CLASS_MOTION,
|
||||
DOOR_SENSOR: DEVICE_CLASS_DOOR,
|
||||
LEAK_SENSOR_WET: DEVICE_CLASS_MOISTURE,
|
||||
LIGHT_SENSOR: DEVICE_CLASS_LIGHT,
|
||||
LOW_BATTERY: DEVICE_CLASS_BATTERY,
|
||||
CO_SENSOR: DEVICE_CLASS_GAS,
|
||||
SMOKE_SENSOR: DEVICE_CLASS_SMOKE,
|
||||
TEST_SENSOR: DEVICE_CLASS_SAFETY,
|
||||
SENSOR_MALFUNCTION: DEVICE_CLASS_PROBLEM,
|
||||
HEARTBEAT: DEVICE_CLASS_PROBLEM,
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the INSTEON device class for the hass platform."""
|
||||
insteon_modem = hass.data["insteon"].get("modem")
|
||||
|
||||
address = discovery_info["address"]
|
||||
device = insteon_modem.devices[address]
|
||||
state_key = discovery_info["state_key"]
|
||||
name = device.states[state_key].name
|
||||
if name != "dryLeakSensor":
|
||||
_LOGGER.debug(
|
||||
"Adding device %s entity %s to Binary Sensor platform",
|
||||
device.address.hex,
|
||||
name,
|
||||
)
|
||||
|
||||
new_entity = InsteonBinarySensor(device, state_key)
|
||||
|
||||
async_add_entities([new_entity])
|
||||
"""Set up the INSTEON entity class for the hass platform."""
|
||||
async_add_insteon_entities(
|
||||
hass, DOMAIN, InsteonBinarySensorEntity, async_add_entities, discovery_info
|
||||
)
|
||||
|
||||
|
||||
class InsteonBinarySensor(InsteonEntity, BinarySensorEntity):
|
||||
"""A Class for an Insteon device entity."""
|
||||
class InsteonBinarySensorEntity(InsteonEntity, BinarySensorEntity):
|
||||
"""A Class for an Insteon binary sensor entity."""
|
||||
|
||||
def __init__(self, device, state_key):
|
||||
def __init__(self, device, group):
|
||||
"""Initialize the INSTEON binary sensor."""
|
||||
super().__init__(device, state_key)
|
||||
self._sensor_type = SENSOR_TYPES.get(self._insteon_device_state.name)
|
||||
super().__init__(device, group)
|
||||
self._sensor_type = SENSOR_TYPES.get(self._insteon_device_group.name)
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
|
@ -54,9 +73,4 @@ class InsteonBinarySensor(InsteonEntity, BinarySensorEntity):
|
|||
@property
|
||||
def is_on(self):
|
||||
"""Return the boolean response if the node is on."""
|
||||
on_val = bool(self._insteon_device_state.value)
|
||||
|
||||
if self._insteon_device_state.name in ["lightSensor", "ioLincSensor"]:
|
||||
return not on_val
|
||||
|
||||
return on_val
|
||||
return bool(self._insteon_device_group.value)
|
||||
|
|
|
@ -1,7 +1,46 @@
|
|||
"""Constants used by insteon component."""
|
||||
from pyinsteon.groups import (
|
||||
CO_SENSOR,
|
||||
COVER,
|
||||
DIMMABLE_FAN,
|
||||
DIMMABLE_LIGHT,
|
||||
DIMMABLE_LIGHT_MAIN,
|
||||
DIMMABLE_OUTLET,
|
||||
DOOR_SENSOR,
|
||||
HEARTBEAT,
|
||||
LEAK_SENSOR_WET,
|
||||
LIGHT_SENSOR,
|
||||
LOW_BATTERY,
|
||||
MOTION_SENSOR,
|
||||
NEW_SENSOR,
|
||||
ON_OFF_OUTLET_BOTTOM,
|
||||
ON_OFF_OUTLET_TOP,
|
||||
ON_OFF_SWITCH,
|
||||
ON_OFF_SWITCH_A,
|
||||
ON_OFF_SWITCH_B,
|
||||
ON_OFF_SWITCH_C,
|
||||
ON_OFF_SWITCH_D,
|
||||
ON_OFF_SWITCH_E,
|
||||
ON_OFF_SWITCH_F,
|
||||
ON_OFF_SWITCH_G,
|
||||
ON_OFF_SWITCH_H,
|
||||
ON_OFF_SWITCH_MAIN,
|
||||
OPEN_CLOSE_SENSOR,
|
||||
RELAY,
|
||||
SENSOR_MALFUNCTION,
|
||||
SMOKE_SENSOR,
|
||||
TEST_SENSOR,
|
||||
)
|
||||
|
||||
DOMAIN = "insteon"
|
||||
INSTEON_ENTITIES = "entities"
|
||||
|
||||
INSTEON_COMPONENTS = [
|
||||
"binary_sensor",
|
||||
"cover",
|
||||
"fan",
|
||||
"light",
|
||||
"switch",
|
||||
]
|
||||
|
||||
CONF_IP_PORT = "ip_port"
|
||||
CONF_HUB_USERNAME = "username"
|
||||
|
@ -40,6 +79,7 @@ SRV_SCENE_OFF = "scene_off"
|
|||
|
||||
SIGNAL_LOAD_ALDB = "load_aldb"
|
||||
SIGNAL_PRINT_ALDB = "print_aldb"
|
||||
SIGNAL_SAVE_DEVICES = "save_devices"
|
||||
|
||||
HOUSECODES = [
|
||||
"a",
|
||||
|
@ -60,47 +100,42 @@ HOUSECODES = [
|
|||
"p",
|
||||
]
|
||||
|
||||
BUTTON_PRESSED_STATE_NAME = "onLevelButton"
|
||||
EVENT_BUTTON_ON = "insteon.button_on"
|
||||
EVENT_BUTTON_OFF = "insteon.button_off"
|
||||
EVENT_GROUP_ON = "insteon.button_on"
|
||||
EVENT_GROUP_OFF = "insteon.button_off"
|
||||
EVENT_GROUP_ON_FAST = "insteon.button_on_fast"
|
||||
EVENT_GROUP_OFF_FAST = "insteon.button_off_fast"
|
||||
EVENT_CONF_BUTTON = "button"
|
||||
|
||||
ON_OFF_EVENTS = "on_off_events"
|
||||
|
||||
STATE_NAME_LABEL_MAP = {
|
||||
"keypadButtonA": "Button A",
|
||||
"keypadButtonB": "Button B",
|
||||
"keypadButtonC": "Button C",
|
||||
"keypadButtonD": "Button D",
|
||||
"keypadButtonE": "Button E",
|
||||
"keypadButtonF": "Button F",
|
||||
"keypadButtonG": "Button G",
|
||||
"keypadButtonH": "Button H",
|
||||
"keypadButtonMain": "Main",
|
||||
"onOffButtonA": "Button A",
|
||||
"onOffButtonB": "Button B",
|
||||
"onOffButtonC": "Button C",
|
||||
"onOffButtonD": "Button D",
|
||||
"onOffButtonE": "Button E",
|
||||
"onOffButtonF": "Button F",
|
||||
"onOffButtonG": "Button G",
|
||||
"onOffButtonH": "Button H",
|
||||
"onOffButtonMain": "Main",
|
||||
"fanOnLevel": "Fan",
|
||||
"lightOnLevel": "Light",
|
||||
"coolSetPoint": "Cool Set",
|
||||
"heatSetPoint": "HeatSet",
|
||||
"statusReport": "Status",
|
||||
"generalSensor": "Sensor",
|
||||
"motionSensor": "Motion",
|
||||
"lightSensor": "Light",
|
||||
"batterySensor": "Battery",
|
||||
"dryLeakSensor": "Dry",
|
||||
"wetLeakSensor": "Wet",
|
||||
"heartbeatLeakSensor": "Heartbeat",
|
||||
"openClosedRelay": "Relay",
|
||||
"openClosedSensor": "Sensor",
|
||||
"lightOnOff": "Light",
|
||||
"outletTopOnOff": "Top",
|
||||
"outletBottomOnOff": "Bottom",
|
||||
"coverOpenLevel": "Cover",
|
||||
DIMMABLE_LIGHT_MAIN: "Main",
|
||||
ON_OFF_SWITCH_A: "Button A",
|
||||
ON_OFF_SWITCH_B: "Button B",
|
||||
ON_OFF_SWITCH_C: "Button C",
|
||||
ON_OFF_SWITCH_D: "Button D",
|
||||
ON_OFF_SWITCH_E: "Button E",
|
||||
ON_OFF_SWITCH_F: "Button F",
|
||||
ON_OFF_SWITCH_G: "Button G",
|
||||
ON_OFF_SWITCH_H: "Button H",
|
||||
ON_OFF_SWITCH_MAIN: "Main",
|
||||
DIMMABLE_FAN: "Fan",
|
||||
DIMMABLE_LIGHT: "Light",
|
||||
DIMMABLE_OUTLET: "Outlet",
|
||||
MOTION_SENSOR: "Motion",
|
||||
LIGHT_SENSOR: "Light",
|
||||
LOW_BATTERY: "Battery",
|
||||
LEAK_SENSOR_WET: "Wet",
|
||||
DOOR_SENSOR: "Door",
|
||||
SMOKE_SENSOR: "Smoke",
|
||||
CO_SENSOR: "Carbon Monoxide",
|
||||
TEST_SENSOR: "Test",
|
||||
NEW_SENSOR: "New",
|
||||
SENSOR_MALFUNCTION: "Malfunction",
|
||||
HEARTBEAT: "Heartbeat",
|
||||
OPEN_CLOSE_SENSOR: "Sensor",
|
||||
ON_OFF_SWITCH: "Light",
|
||||
ON_OFF_OUTLET_TOP: "Top",
|
||||
ON_OFF_OUTLET_BOTTOM: "Bottom",
|
||||
COVER: "Cover",
|
||||
RELAY: "Relay",
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import math
|
|||
|
||||
from homeassistant.components.cover import (
|
||||
ATTR_POSITION,
|
||||
DOMAIN,
|
||||
SUPPORT_CLOSE,
|
||||
SUPPORT_OPEN,
|
||||
SUPPORT_SET_POSITION,
|
||||
|
@ -11,6 +12,7 @@ from homeassistant.components.cover import (
|
|||
)
|
||||
|
||||
from .insteon_entity import InsteonEntity
|
||||
from .utils import async_add_insteon_entities
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -19,33 +21,18 @@ SUPPORTED_FEATURES = SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_SET_POSITION
|
|||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the Insteon platform."""
|
||||
if not discovery_info:
|
||||
return
|
||||
|
||||
insteon_modem = hass.data["insteon"].get("modem")
|
||||
|
||||
address = discovery_info["address"]
|
||||
device = insteon_modem.devices[address]
|
||||
state_key = discovery_info["state_key"]
|
||||
|
||||
_LOGGER.debug(
|
||||
"Adding device %s entity %s to Cover platform",
|
||||
device.address.hex,
|
||||
device.states[state_key].name,
|
||||
async_add_insteon_entities(
|
||||
hass, DOMAIN, InsteonCoverEntity, async_add_entities, discovery_info
|
||||
)
|
||||
|
||||
new_entity = InsteonCoverEntity(device, state_key)
|
||||
|
||||
async_add_entities([new_entity])
|
||||
|
||||
|
||||
class InsteonCoverEntity(InsteonEntity, CoverEntity):
|
||||
"""A Class for an Insteon device."""
|
||||
"""A Class for an Insteon cover entity."""
|
||||
|
||||
@property
|
||||
def current_cover_position(self):
|
||||
"""Return the current cover position."""
|
||||
return int(math.ceil(self._insteon_device_state.value * 100 / 255))
|
||||
return int(math.ceil(self._insteon_device_group.value * 100 / 255))
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
|
@ -58,17 +45,19 @@ class InsteonCoverEntity(InsteonEntity, CoverEntity):
|
|||
return bool(self.current_cover_position)
|
||||
|
||||
async def async_open_cover(self, **kwargs):
|
||||
"""Open device."""
|
||||
self._insteon_device_state.open()
|
||||
"""Open cover."""
|
||||
await self._insteon_device.async_open()
|
||||
|
||||
async def async_close_cover(self, **kwargs):
|
||||
"""Close device."""
|
||||
self._insteon_device_state.close()
|
||||
"""Close cover."""
|
||||
await self._insteon_device.async_close()
|
||||
|
||||
async def async_set_cover_position(self, **kwargs):
|
||||
"""Set the cover position."""
|
||||
position = int(kwargs[ATTR_POSITION] * 255 / 100)
|
||||
if position == 0:
|
||||
self._insteon_device_state.close()
|
||||
await self._insteon_device.async_close()
|
||||
else:
|
||||
self._insteon_device_state.set_position(position)
|
||||
await self._insteon_device.async_open(
|
||||
position=position, group=self._insteon_device_group.group
|
||||
)
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
"""Support for INSTEON fans via PowerLinc Modem."""
|
||||
import logging
|
||||
|
||||
from pyinsteon.constants import FanSpeed
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
DOMAIN,
|
||||
SPEED_HIGH,
|
||||
SPEED_LOW,
|
||||
SPEED_MEDIUM,
|
||||
|
@ -9,43 +12,40 @@ from homeassistant.components.fan import (
|
|||
SUPPORT_SET_SPEED,
|
||||
FanEntity,
|
||||
)
|
||||
from homeassistant.const import STATE_OFF
|
||||
|
||||
from .insteon_entity import InsteonEntity
|
||||
from .utils import async_add_insteon_entities
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SPEED_TO_HEX = {SPEED_OFF: 0x00, SPEED_LOW: 0x3F, SPEED_MEDIUM: 0xBE, SPEED_HIGH: 0xFF}
|
||||
|
||||
FAN_SPEEDS = [STATE_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]
|
||||
FAN_SPEEDS = [SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]
|
||||
SPEED_TO_VALUE = {
|
||||
SPEED_OFF: FanSpeed.OFF,
|
||||
SPEED_LOW: FanSpeed.LOW,
|
||||
SPEED_MEDIUM: FanSpeed.MEDIUM,
|
||||
SPEED_HIGH: FanSpeed.HIGH,
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the INSTEON device class for the hass platform."""
|
||||
insteon_modem = hass.data["insteon"].get("modem")
|
||||
|
||||
address = discovery_info["address"]
|
||||
device = insteon_modem.devices[address]
|
||||
state_key = discovery_info["state_key"]
|
||||
|
||||
_LOGGER.debug(
|
||||
"Adding device %s entity %s to Fan platform",
|
||||
device.address.hex,
|
||||
device.states[state_key].name,
|
||||
"""Set up the INSTEON entity class for the hass platform."""
|
||||
async_add_insteon_entities(
|
||||
hass, DOMAIN, InsteonFanEntity, async_add_entities, discovery_info
|
||||
)
|
||||
|
||||
new_entity = InsteonFan(device, state_key)
|
||||
|
||||
async_add_entities([new_entity])
|
||||
|
||||
|
||||
class InsteonFan(InsteonEntity, FanEntity):
|
||||
"""An INSTEON fan component."""
|
||||
class InsteonFanEntity(InsteonEntity, FanEntity):
|
||||
"""An INSTEON fan entity."""
|
||||
|
||||
@property
|
||||
def speed(self) -> str:
|
||||
"""Return the current speed."""
|
||||
return self._hex_to_speed(self._insteon_device_state.value)
|
||||
if self._insteon_device_group.value == FanSpeed.HIGH:
|
||||
return SPEED_HIGH
|
||||
if self._insteon_device_group.value == FanSpeed.MEDIUM:
|
||||
return SPEED_MEDIUM
|
||||
if self._insteon_device_group.value == FanSpeed.LOW:
|
||||
return SPEED_LOW
|
||||
return SPEED_OFF
|
||||
|
||||
@property
|
||||
def speed_list(self) -> list:
|
||||
|
@ -58,30 +58,19 @@ class InsteonFan(InsteonEntity, FanEntity):
|
|||
return SUPPORT_SET_SPEED
|
||||
|
||||
async def async_turn_on(self, speed: str = None, **kwargs) -> None:
|
||||
"""Turn on the entity."""
|
||||
"""Turn on the fan."""
|
||||
if speed is None:
|
||||
speed = SPEED_MEDIUM
|
||||
await self.async_set_speed(speed)
|
||||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
"""Turn off the entity."""
|
||||
await self.async_set_speed(SPEED_OFF)
|
||||
"""Turn off the fan."""
|
||||
await self._insteon_device.async_fan_off()
|
||||
|
||||
async def async_set_speed(self, speed: str) -> None:
|
||||
"""Set the speed of the fan."""
|
||||
fan_speed = SPEED_TO_HEX[speed]
|
||||
if fan_speed == 0x00:
|
||||
self._insteon_device_state.off()
|
||||
fan_speed = SPEED_TO_VALUE[speed]
|
||||
if fan_speed == FanSpeed.OFF:
|
||||
await self._insteon_device.async_fan_off()
|
||||
else:
|
||||
self._insteon_device_state.set_level(fan_speed)
|
||||
|
||||
@staticmethod
|
||||
def _hex_to_speed(speed: int):
|
||||
hex_speed = SPEED_OFF
|
||||
if speed > 0xFE:
|
||||
hex_speed = SPEED_HIGH
|
||||
elif speed > 0x7F:
|
||||
hex_speed = SPEED_MEDIUM
|
||||
elif speed > 0:
|
||||
hex_speed = SPEED_LOW
|
||||
return hex_speed
|
||||
await self._insteon_device.async_fan_on(on_level=fan_speed)
|
||||
|
|
|
@ -2,14 +2,16 @@
|
|||
import logging
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_connect,
|
||||
async_dispatcher_send,
|
||||
)
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
INSTEON_ENTITIES,
|
||||
SIGNAL_LOAD_ALDB,
|
||||
SIGNAL_PRINT_ALDB,
|
||||
SIGNAL_SAVE_DEVICES,
|
||||
STATE_NAME_LABEL_MAP,
|
||||
)
|
||||
from .utils import print_aldb_to_log
|
||||
|
@ -20,11 +22,14 @@ _LOGGER = logging.getLogger(__name__)
|
|||
class InsteonEntity(Entity):
|
||||
"""INSTEON abstract base entity."""
|
||||
|
||||
def __init__(self, device, state_key):
|
||||
def __init__(self, device, group):
|
||||
"""Initialize the INSTEON binary sensor."""
|
||||
self._insteon_device_state = device.states[state_key]
|
||||
self._insteon_device_group = device.groups[group]
|
||||
self._insteon_device = device
|
||||
self._insteon_device.aldb.add_loaded_callback(self._aldb_loaded)
|
||||
|
||||
def __hash__(self):
|
||||
"""Return the hash of the Insteon Entity."""
|
||||
return hash(self._insteon_device)
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
|
@ -34,20 +39,20 @@ class InsteonEntity(Entity):
|
|||
@property
|
||||
def address(self):
|
||||
"""Return the address of the node."""
|
||||
return self._insteon_device.address.human
|
||||
return str(self._insteon_device.address)
|
||||
|
||||
@property
|
||||
def group(self):
|
||||
"""Return the INSTEON group that the entity responds to."""
|
||||
return self._insteon_device_state.group
|
||||
return self._insteon_device_group.group
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return a unique ID."""
|
||||
if self._insteon_device_state.group == 0x01:
|
||||
if self._insteon_device_group.group == 0x01:
|
||||
uid = self._insteon_device.id
|
||||
else:
|
||||
uid = f"{self._insteon_device.id}_{self._insteon_device_state.group}"
|
||||
uid = f"{self._insteon_device.id}_{self._insteon_device_group.group}"
|
||||
return uid
|
||||
|
||||
@property
|
||||
|
@ -61,7 +66,7 @@ class InsteonEntity(Entity):
|
|||
extension = self._get_label()
|
||||
if extension:
|
||||
extension = f" {extension}"
|
||||
return f"{description} {self._insteon_device.address.human}{extension}"
|
||||
return f"{description} {self._insteon_device.address}{extension}"
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
|
@ -69,56 +74,45 @@ class InsteonEntity(Entity):
|
|||
return {"insteon_address": self.address, "insteon_group": self.group}
|
||||
|
||||
@callback
|
||||
def async_entity_update(self, deviceid, group, val):
|
||||
def async_entity_update(self, name, address, value, group):
|
||||
"""Receive notification from transport that new data exists."""
|
||||
_LOGGER.debug(
|
||||
"Received update for device %s group %d value %s",
|
||||
deviceid.human,
|
||||
group,
|
||||
val,
|
||||
"Received update for device %s group %d value %s", address, group, value,
|
||||
)
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register INSTEON update events."""
|
||||
_LOGGER.debug(
|
||||
"Tracking updates for device %s group %d statename %s",
|
||||
"Tracking updates for device %s group %d name %s",
|
||||
self.address,
|
||||
self.group,
|
||||
self._insteon_device_state.name,
|
||||
self._insteon_device_group.name,
|
||||
)
|
||||
self._insteon_device_state.register_updates(self.async_entity_update)
|
||||
self.hass.data[DOMAIN][INSTEON_ENTITIES].add(self.entity_id)
|
||||
self._insteon_device_group.subscribe(self.async_entity_update)
|
||||
load_signal = f"{self.entity_id}_{SIGNAL_LOAD_ALDB}"
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(self.hass, load_signal, self._load_aldb)
|
||||
async_dispatcher_connect(self.hass, load_signal, self._async_read_aldb)
|
||||
)
|
||||
print_signal = f"{self.entity_id}_{SIGNAL_PRINT_ALDB}"
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(self.hass, print_signal, self._print_aldb)
|
||||
)
|
||||
async_dispatcher_connect(self.hass, print_signal, self._print_aldb)
|
||||
|
||||
def _load_aldb(self, reload=False):
|
||||
"""Load the device All-Link Database."""
|
||||
if reload:
|
||||
self._insteon_device.aldb.clear()
|
||||
self._insteon_device.read_aldb()
|
||||
async def _async_read_aldb(self, reload):
|
||||
"""Call device load process and print to log."""
|
||||
await self._insteon_device.aldb.async_load(refresh=reload)
|
||||
self._print_aldb()
|
||||
async_dispatcher_send(self.hass, SIGNAL_SAVE_DEVICES)
|
||||
|
||||
def _print_aldb(self):
|
||||
"""Print the device ALDB to the log file."""
|
||||
print_aldb_to_log(self._insteon_device.aldb)
|
||||
|
||||
@callback
|
||||
def _aldb_loaded(self):
|
||||
"""All-Link Database loaded for the device."""
|
||||
self._print_aldb()
|
||||
|
||||
def _get_label(self):
|
||||
"""Get the device label for grouped devices."""
|
||||
label = ""
|
||||
if len(self._insteon_device.states) > 1:
|
||||
if self._insteon_device_state.name in STATE_NAME_LABEL_MAP:
|
||||
label = STATE_NAME_LABEL_MAP[self._insteon_device_state.name]
|
||||
if len(self._insteon_device.groups) > 1:
|
||||
if self._insteon_device_group.name in STATE_NAME_LABEL_MAP:
|
||||
label = STATE_NAME_LABEL_MAP[self._insteon_device_group.name]
|
||||
else:
|
||||
label = f"Group {self.group:d}"
|
||||
return label
|
||||
|
|
|
@ -1,81 +1,112 @@
|
|||
"""Insteon product database."""
|
||||
import collections
|
||||
"""Utility methods for the Insteon platform."""
|
||||
import logging
|
||||
|
||||
from insteonplm.states.cover import Cover
|
||||
from insteonplm.states.dimmable import (
|
||||
DimmableKeypadA,
|
||||
DimmableRemote,
|
||||
DimmableSwitch,
|
||||
DimmableSwitch_Fan,
|
||||
)
|
||||
from insteonplm.states.onOff import (
|
||||
OnOffKeypad,
|
||||
OnOffKeypadA,
|
||||
OnOffSwitch,
|
||||
OnOffSwitch_OutletBottom,
|
||||
OnOffSwitch_OutletTop,
|
||||
OpenClosedRelay,
|
||||
)
|
||||
from insteonplm.states.sensor import (
|
||||
IoLincSensor,
|
||||
LeakSensorDryWet,
|
||||
OnOffSensor,
|
||||
SmokeCO2Sensor,
|
||||
VariableSensor,
|
||||
)
|
||||
from insteonplm.states.x10 import (
|
||||
X10AllLightsOffSensor,
|
||||
X10AllLightsOnSensor,
|
||||
X10AllUnitsOffSensor,
|
||||
X10DimmableSwitch,
|
||||
from pyinsteon.device_types import (
|
||||
DimmableLightingControl,
|
||||
DimmableLightingControl_DinRail,
|
||||
DimmableLightingControl_FanLinc,
|
||||
DimmableLightingControl_InLineLinc,
|
||||
DimmableLightingControl_KeypadLinc_6,
|
||||
DimmableLightingControl_KeypadLinc_8,
|
||||
DimmableLightingControl_LampLinc,
|
||||
DimmableLightingControl_OutletLinc,
|
||||
DimmableLightingControl_SwitchLinc,
|
||||
DimmableLightingControl_ToggleLinc,
|
||||
GeneralController_ControlLinc,
|
||||
GeneralController_MiniRemote_4,
|
||||
GeneralController_MiniRemote_8,
|
||||
GeneralController_MiniRemote_Switch,
|
||||
GeneralController_RemoteLinc,
|
||||
SecurityHealthSafety_DoorSensor,
|
||||
SecurityHealthSafety_LeakSensor,
|
||||
SecurityHealthSafety_MotionSensor,
|
||||
SecurityHealthSafety_OpenCloseSensor,
|
||||
SecurityHealthSafety_Smokebridge,
|
||||
SensorsActuators_IOLink,
|
||||
SwitchedLightingControl,
|
||||
SwitchedLightingControl_ApplianceLinc,
|
||||
SwitchedLightingControl_DinRail,
|
||||
SwitchedLightingControl_InLineLinc,
|
||||
SwitchedLightingControl_KeypadLinc_6,
|
||||
SwitchedLightingControl_KeypadLinc_8,
|
||||
SwitchedLightingControl_OnOffOutlet,
|
||||
SwitchedLightingControl_OutletLinc,
|
||||
SwitchedLightingControl_SwitchLinc,
|
||||
SwitchedLightingControl_ToggleLinc,
|
||||
WindowCovering,
|
||||
X10Dimmable,
|
||||
X10OnOff,
|
||||
X10OnOffSensor,
|
||||
X10OnOffSwitch,
|
||||
)
|
||||
|
||||
State = collections.namedtuple("Product", "stateType platform")
|
||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR
|
||||
from homeassistant.components.cover import DOMAIN as COVER
|
||||
from homeassistant.components.fan import DOMAIN as FAN
|
||||
from homeassistant.components.light import DOMAIN as LIGHT
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH
|
||||
|
||||
from .const import ON_OFF_EVENTS
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEVICE_PLATFORM = {
|
||||
DimmableLightingControl: {LIGHT: [1], ON_OFF_EVENTS: [1]},
|
||||
DimmableLightingControl_DinRail: {LIGHT: [1], ON_OFF_EVENTS: [1]},
|
||||
DimmableLightingControl_FanLinc: {LIGHT: [1], FAN: [2], ON_OFF_EVENTS: [1, 2]},
|
||||
DimmableLightingControl_InLineLinc: {LIGHT: [1], ON_OFF_EVENTS: [1]},
|
||||
DimmableLightingControl_KeypadLinc_6: {
|
||||
LIGHT: [1],
|
||||
SWITCH: [3, 4, 5, 6],
|
||||
ON_OFF_EVENTS: [1, 3, 4, 5, 6],
|
||||
},
|
||||
DimmableLightingControl_KeypadLinc_8: {
|
||||
LIGHT: [1],
|
||||
SWITCH: range(2, 9),
|
||||
ON_OFF_EVENTS: range(1, 9),
|
||||
},
|
||||
DimmableLightingControl_LampLinc: {LIGHT: [1], ON_OFF_EVENTS: [1]},
|
||||
DimmableLightingControl_OutletLinc: {LIGHT: [1], ON_OFF_EVENTS: [1]},
|
||||
DimmableLightingControl_SwitchLinc: {LIGHT: [1], ON_OFF_EVENTS: [1]},
|
||||
DimmableLightingControl_ToggleLinc: {LIGHT: [1], ON_OFF_EVENTS: [1]},
|
||||
GeneralController_ControlLinc: {ON_OFF_EVENTS: [1]},
|
||||
GeneralController_MiniRemote_4: {ON_OFF_EVENTS: range(1, 5)},
|
||||
GeneralController_MiniRemote_8: {ON_OFF_EVENTS: range(1, 9)},
|
||||
GeneralController_MiniRemote_Switch: {ON_OFF_EVENTS: [1, 2]},
|
||||
GeneralController_RemoteLinc: {ON_OFF_EVENTS: [1]},
|
||||
SecurityHealthSafety_DoorSensor: {BINARY_SENSOR: [1, 3, 4], ON_OFF_EVENTS: [1]},
|
||||
SecurityHealthSafety_LeakSensor: {BINARY_SENSOR: [2, 4]},
|
||||
SecurityHealthSafety_MotionSensor: {BINARY_SENSOR: [1, 2, 3], ON_OFF_EVENTS: [1]},
|
||||
SecurityHealthSafety_OpenCloseSensor: {BINARY_SENSOR: [1]},
|
||||
SecurityHealthSafety_Smokebridge: {BINARY_SENSOR: [1]},
|
||||
SensorsActuators_IOLink: {SWITCH: [1], BINARY_SENSOR: [2], ON_OFF_EVENTS: [1, 2]},
|
||||
SwitchedLightingControl: {SWITCH: [1], ON_OFF_EVENTS: [1]},
|
||||
SwitchedLightingControl_ApplianceLinc: {SWITCH: [1], ON_OFF_EVENTS: [1]},
|
||||
SwitchedLightingControl_DinRail: {SWITCH: [1], ON_OFF_EVENTS: [1]},
|
||||
SwitchedLightingControl_InLineLinc: {SWITCH: [1], ON_OFF_EVENTS: [1]},
|
||||
SwitchedLightingControl_KeypadLinc_6: {
|
||||
SWITCH: [1, 3, 4, 5, 6],
|
||||
ON_OFF_EVENTS: [1, 3, 4, 5, 6],
|
||||
},
|
||||
SwitchedLightingControl_KeypadLinc_8: {
|
||||
SWITCH: range(1, 9),
|
||||
ON_OFF_EVENTS: range(1, 9),
|
||||
},
|
||||
SwitchedLightingControl_OnOffOutlet: {SWITCH: [1, 2], ON_OFF_EVENTS: [1, 2]},
|
||||
SwitchedLightingControl_OutletLinc: {SWITCH: [1], ON_OFF_EVENTS: [1]},
|
||||
SwitchedLightingControl_SwitchLinc: {SWITCH: [1], ON_OFF_EVENTS: [1]},
|
||||
SwitchedLightingControl_ToggleLinc: {SWITCH: [1], ON_OFF_EVENTS: [1]},
|
||||
WindowCovering: {COVER: [1]},
|
||||
X10Dimmable: {LIGHT: [1]},
|
||||
X10OnOff: {SWITCH: [1]},
|
||||
X10OnOffSensor: {BINARY_SENSOR: [1]},
|
||||
}
|
||||
|
||||
|
||||
class IPDB:
|
||||
"""Embodies the INSTEON Product Database static data and access methods."""
|
||||
def get_device_platforms(device):
|
||||
"""Return the HA platforms for a device type."""
|
||||
return DEVICE_PLATFORM.get(type(device), {}).keys()
|
||||
|
||||
def __init__(self):
|
||||
"""Create the INSTEON Product Database (IPDB)."""
|
||||
self.states = [
|
||||
State(Cover, "cover"),
|
||||
State(OnOffSwitch_OutletTop, "switch"),
|
||||
State(OnOffSwitch_OutletBottom, "switch"),
|
||||
State(OpenClosedRelay, "switch"),
|
||||
State(OnOffSwitch, "switch"),
|
||||
State(OnOffKeypadA, "switch"),
|
||||
State(OnOffKeypad, "switch"),
|
||||
State(LeakSensorDryWet, "binary_sensor"),
|
||||
State(IoLincSensor, "binary_sensor"),
|
||||
State(SmokeCO2Sensor, "sensor"),
|
||||
State(OnOffSensor, "binary_sensor"),
|
||||
State(VariableSensor, "sensor"),
|
||||
State(DimmableSwitch_Fan, "fan"),
|
||||
State(DimmableSwitch, "light"),
|
||||
State(DimmableRemote, "on_off_events"),
|
||||
State(DimmableKeypadA, "light"),
|
||||
State(X10DimmableSwitch, "light"),
|
||||
State(X10OnOffSwitch, "switch"),
|
||||
State(X10OnOffSensor, "binary_sensor"),
|
||||
State(X10AllUnitsOffSensor, "binary_sensor"),
|
||||
State(X10AllLightsOnSensor, "binary_sensor"),
|
||||
State(X10AllLightsOffSensor, "binary_sensor"),
|
||||
]
|
||||
|
||||
def __len__(self):
|
||||
"""Return the number of INSTEON state types mapped to HA platforms."""
|
||||
return len(self.states)
|
||||
|
||||
def __iter__(self):
|
||||
"""Itterate through the INSTEON state types to HA platforms."""
|
||||
yield from self.states
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""Return a Home Assistant platform from an INSTEON state type."""
|
||||
for state in self.states:
|
||||
if isinstance(key, state.stateType):
|
||||
return state
|
||||
return None
|
||||
def get_platform_groups(device, domain) -> dict:
|
||||
"""Return the platforms that a device belongs in."""
|
||||
return DEVICE_PLATFORM.get(type(device), {}).get(domain, {})
|
||||
|
|
|
@ -3,11 +3,13 @@ import logging
|
|||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
DOMAIN,
|
||||
SUPPORT_BRIGHTNESS,
|
||||
LightEntity,
|
||||
)
|
||||
|
||||
from .insteon_entity import InsteonEntity
|
||||
from .utils import async_add_insteon_entities
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -16,31 +18,18 @@ MAX_BRIGHTNESS = 255
|
|||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the Insteon component."""
|
||||
insteon_modem = hass.data["insteon"].get("modem")
|
||||
|
||||
address = discovery_info["address"]
|
||||
device = insteon_modem.devices[address]
|
||||
state_key = discovery_info["state_key"]
|
||||
|
||||
_LOGGER.debug(
|
||||
"Adding device %s entity %s to Light platform",
|
||||
device.address.hex,
|
||||
device.states[state_key].name,
|
||||
async_add_insteon_entities(
|
||||
hass, DOMAIN, InsteonDimmerEntity, async_add_entities, discovery_info
|
||||
)
|
||||
|
||||
new_entity = InsteonDimmerDevice(device, state_key)
|
||||
|
||||
async_add_entities([new_entity])
|
||||
|
||||
|
||||
class InsteonDimmerDevice(InsteonEntity, LightEntity):
|
||||
"""A Class for an Insteon device."""
|
||||
class InsteonDimmerEntity(InsteonEntity, LightEntity):
|
||||
"""A Class for an Insteon light entity."""
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""Return the brightness of this light between 0..255."""
|
||||
onlevel = self._insteon_device_state.value
|
||||
return int(onlevel)
|
||||
return self._insteon_device_group.value
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
|
@ -53,13 +42,15 @@ class InsteonDimmerDevice(InsteonEntity, LightEntity):
|
|||
return SUPPORT_BRIGHTNESS
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Turn device on."""
|
||||
"""Turn light on."""
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
brightness = int(kwargs[ATTR_BRIGHTNESS])
|
||||
self._insteon_device_state.set_level(brightness)
|
||||
await self._insteon_device.async_on(
|
||||
on_level=brightness, group=self._insteon_device_group.group
|
||||
)
|
||||
else:
|
||||
self._insteon_device_state.on()
|
||||
await self._insteon_device.async_on(group=self._insteon_device_group.group)
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Turn device off."""
|
||||
self._insteon_device_state.off()
|
||||
"""Turn light off."""
|
||||
await self._insteon_device.async_off(self._insteon_device_group.group)
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
"domain": "insteon",
|
||||
"name": "Insteon",
|
||||
"documentation": "https://www.home-assistant.io/integrations/insteon",
|
||||
"requirements": ["insteonplm==0.16.8"],
|
||||
"codeowners": []
|
||||
}
|
||||
"requirements": ["pyinsteon==1.0.0"],
|
||||
"codeowners": ["@teharris1"]
|
||||
}
|
|
@ -11,7 +11,6 @@ from homeassistant.const import (
|
|||
CONF_PLATFORM,
|
||||
CONF_PORT,
|
||||
ENTITY_MATCH_ALL,
|
||||
ENTITY_MATCH_NONE,
|
||||
)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
|
@ -57,7 +56,6 @@ def set_default_port(schema: Dict) -> Dict:
|
|||
|
||||
|
||||
CONF_DEVICE_OVERRIDE_SCHEMA = vol.All(
|
||||
cv.deprecated(CONF_PLATFORM),
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_ADDRESS): cv.string,
|
||||
|
@ -86,6 +84,9 @@ CONF_X10_SCHEMA = vol.All(
|
|||
CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
DOMAIN: vol.All(
|
||||
cv.deprecated(CONF_X10_ALL_UNITS_OFF),
|
||||
cv.deprecated(CONF_X10_ALL_LIGHTS_ON),
|
||||
cv.deprecated(CONF_X10_ALL_LIGHTS_OFF),
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Exclusive(
|
||||
|
@ -101,9 +102,6 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
vol.Optional(CONF_OVERRIDE): vol.All(
|
||||
cv.ensure_list_csv, [CONF_DEVICE_OVERRIDE_SCHEMA]
|
||||
),
|
||||
vol.Optional(CONF_X10_ALL_UNITS_OFF): vol.In(HOUSECODES),
|
||||
vol.Optional(CONF_X10_ALL_LIGHTS_ON): vol.In(HOUSECODES),
|
||||
vol.Optional(CONF_X10_ALL_LIGHTS_OFF): vol.In(HOUSECODES),
|
||||
vol.Optional(CONF_X10): vol.All(
|
||||
cv.ensure_list_csv, [CONF_X10_SCHEMA]
|
||||
),
|
||||
|
@ -134,9 +132,7 @@ DEL_ALL_LINK_SCHEMA = vol.Schema(
|
|||
|
||||
LOAD_ALDB_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_ENTITY_ID): vol.Any(
|
||||
cv.entity_id, ENTITY_MATCH_ALL, ENTITY_MATCH_NONE
|
||||
),
|
||||
vol.Required(CONF_ENTITY_ID): vol.Any(cv.entity_id, ENTITY_MATCH_ALL),
|
||||
vol.Optional(SRV_LOAD_DB_RELOAD, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
"""Support for INSTEON dimmers via PowerLinc Modem."""
|
||||
import logging
|
||||
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .insteon_entity import InsteonEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the INSTEON device class for the hass platform."""
|
||||
insteon_modem = hass.data["insteon"].get("modem")
|
||||
|
||||
address = discovery_info["address"]
|
||||
device = insteon_modem.devices[address]
|
||||
state_key = discovery_info["state_key"]
|
||||
|
||||
_LOGGER.debug(
|
||||
"Adding device %s entity %s to Sensor platform",
|
||||
device.address.hex,
|
||||
device.states[state_key].name,
|
||||
)
|
||||
|
||||
new_entity = InsteonSensorDevice(device, state_key)
|
||||
|
||||
async_add_entities([new_entity])
|
||||
|
||||
|
||||
class InsteonSensorDevice(InsteonEntity, Entity):
|
||||
"""A Class for an Insteon device."""
|
|
@ -1,66 +1,33 @@
|
|||
"""Support for INSTEON dimmers via PowerLinc Modem."""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.components.switch import DOMAIN, SwitchEntity
|
||||
|
||||
from .insteon_entity import InsteonEntity
|
||||
from .utils import async_add_insteon_entities
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the INSTEON device class for the hass platform."""
|
||||
insteon_modem = hass.data["insteon"].get("modem")
|
||||
|
||||
address = discovery_info["address"]
|
||||
device = insteon_modem.devices[address]
|
||||
state_key = discovery_info["state_key"]
|
||||
|
||||
state_name = device.states[state_key].name
|
||||
|
||||
_LOGGER.debug(
|
||||
"Adding device %s entity %s to Switch platform", device.address.hex, state_name,
|
||||
"""Set up the INSTEON entity class for the hass platform."""
|
||||
async_add_insteon_entities(
|
||||
hass, DOMAIN, InsteonSwitchEntity, async_add_entities, discovery_info
|
||||
)
|
||||
|
||||
new_entity = None
|
||||
if state_name == "openClosedRelay":
|
||||
new_entity = InsteonOpenClosedDevice(device, state_key)
|
||||
else:
|
||||
new_entity = InsteonSwitchDevice(device, state_key)
|
||||
|
||||
if new_entity is not None:
|
||||
async_add_entities([new_entity])
|
||||
|
||||
|
||||
class InsteonSwitchDevice(InsteonEntity, SwitchEntity):
|
||||
"""A Class for an Insteon device."""
|
||||
class InsteonSwitchEntity(InsteonEntity, SwitchEntity):
|
||||
"""A Class for an Insteon switch entity."""
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return the boolean response if the node is on."""
|
||||
return bool(self._insteon_device_state.value)
|
||||
return bool(self._insteon_device_group.value)
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Turn device on."""
|
||||
self._insteon_device_state.on()
|
||||
"""Turn switch on."""
|
||||
await self._insteon_device.async_on(group=self._insteon_device_group.group)
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Turn device off."""
|
||||
self._insteon_device_state.off()
|
||||
|
||||
|
||||
class InsteonOpenClosedDevice(InsteonEntity, SwitchEntity):
|
||||
"""A Class for an Insteon device."""
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return the boolean response if the node is on."""
|
||||
return bool(self._insteon_device_state.value)
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Turn device on."""
|
||||
self._insteon_device_state.open()
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Turn device off."""
|
||||
self._insteon_device_state.close()
|
||||
"""Turn switch off."""
|
||||
await self._insteon_device.async_off(group=self._insteon_device_group.group)
|
||||
|
|
|
@ -1,23 +1,44 @@
|
|||
"""Utilities used by insteon component."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from insteonplm.devices import ALDBStatus
|
||||
from pyinsteon import devices
|
||||
from pyinsteon.constants import ALDBStatus
|
||||
from pyinsteon.events import OFF_EVENT, OFF_FAST_EVENT, ON_EVENT, ON_FAST_EVENT
|
||||
from pyinsteon.managers.link_manager import (
|
||||
async_enter_linking_mode,
|
||||
async_enter_unlinking_mode,
|
||||
)
|
||||
from pyinsteon.managers.scene_manager import (
|
||||
async_trigger_scene_off,
|
||||
async_trigger_scene_on,
|
||||
)
|
||||
from pyinsteon.managers.x10_manager import (
|
||||
async_x10_all_lights_off,
|
||||
async_x10_all_lights_on,
|
||||
async_x10_all_units_off,
|
||||
)
|
||||
|
||||
from homeassistant.const import CONF_ADDRESS, CONF_ENTITY_ID, ENTITY_MATCH_ALL
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers import discovery
|
||||
from homeassistant.helpers.dispatcher import dispatcher_send
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_connect,
|
||||
async_dispatcher_send,
|
||||
dispatcher_send,
|
||||
)
|
||||
|
||||
from .const import (
|
||||
BUTTON_PRESSED_STATE_NAME,
|
||||
DOMAIN,
|
||||
EVENT_BUTTON_OFF,
|
||||
EVENT_BUTTON_ON,
|
||||
EVENT_CONF_BUTTON,
|
||||
INSTEON_ENTITIES,
|
||||
EVENT_GROUP_OFF,
|
||||
EVENT_GROUP_OFF_FAST,
|
||||
EVENT_GROUP_ON,
|
||||
EVENT_GROUP_ON_FAST,
|
||||
ON_OFF_EVENTS,
|
||||
SIGNAL_LOAD_ALDB,
|
||||
SIGNAL_PRINT_ALDB,
|
||||
SIGNAL_SAVE_DEVICES,
|
||||
SRV_ADD_ALL_LINK,
|
||||
SRV_ALL_LINK_GROUP,
|
||||
SRV_ALL_LINK_MODE,
|
||||
|
@ -34,7 +55,7 @@ from .const import (
|
|||
SRV_X10_ALL_LIGHTS_ON,
|
||||
SRV_X10_ALL_UNITS_OFF,
|
||||
)
|
||||
from .ipdb import IPDB
|
||||
from .ipdb import get_device_platforms, get_platform_groups
|
||||
from .schemas import (
|
||||
ADD_ALL_LINK_SCHEMA,
|
||||
DEL_ALL_LINK_SCHEMA,
|
||||
|
@ -47,91 +68,129 @@ from .schemas import (
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def register_new_device_callback(hass, config, insteon_modem):
|
||||
"""Register callback for new Insteon device."""
|
||||
|
||||
def _fire_button_on_off_event(address, group, val):
|
||||
# Firing an event when a button is pressed.
|
||||
device = insteon_modem.devices[address.hex]
|
||||
state_name = device.states[group].name
|
||||
button = (
|
||||
"" if state_name == BUTTON_PRESSED_STATE_NAME else state_name[-1].lower()
|
||||
)
|
||||
schema = {CONF_ADDRESS: address.hex}
|
||||
if button:
|
||||
schema[EVENT_CONF_BUTTON] = button
|
||||
event = EVENT_BUTTON_ON if val else EVENT_BUTTON_OFF
|
||||
_LOGGER.debug(
|
||||
"Firing event %s with address %s and button %s", event, address.hex, button
|
||||
)
|
||||
hass.bus.fire(event, schema)
|
||||
def add_on_off_event_device(hass, device):
|
||||
"""Register an Insteon device as an on/off event device."""
|
||||
|
||||
@callback
|
||||
def async_new_insteon_device(device):
|
||||
def async_fire_group_on_off_event(name, address, group, button):
|
||||
# Firing an event when a button is pressed.
|
||||
if button and button[-2] == "_":
|
||||
button_id = button[-1].lower()
|
||||
else:
|
||||
button_id = None
|
||||
|
||||
schema = {CONF_ADDRESS: address}
|
||||
if button_id:
|
||||
schema[EVENT_CONF_BUTTON] = button_id
|
||||
if name == ON_EVENT:
|
||||
event = EVENT_GROUP_ON
|
||||
if name == OFF_EVENT:
|
||||
event = EVENT_GROUP_OFF
|
||||
if name == ON_FAST_EVENT:
|
||||
event = EVENT_GROUP_ON_FAST
|
||||
if name == OFF_FAST_EVENT:
|
||||
event = EVENT_GROUP_OFF_FAST
|
||||
_LOGGER.debug("Firing event %s with %s", event, schema)
|
||||
hass.bus.async_fire(event, schema)
|
||||
|
||||
for group in device.events:
|
||||
if isinstance(group, int):
|
||||
for event in device.events[group]:
|
||||
if event in [
|
||||
OFF_EVENT,
|
||||
ON_EVENT,
|
||||
OFF_FAST_EVENT,
|
||||
ON_FAST_EVENT,
|
||||
]:
|
||||
_LOGGER.debug(
|
||||
"Registering on/off event for %s %d %s",
|
||||
str(device.address),
|
||||
group,
|
||||
event,
|
||||
)
|
||||
device.events[group][event].subscribe(
|
||||
async_fire_group_on_off_event, force_strong_ref=True
|
||||
)
|
||||
|
||||
|
||||
def register_new_device_callback(hass, config):
|
||||
"""Register callback for new Insteon device."""
|
||||
new_device_lock = asyncio.Lock()
|
||||
|
||||
@callback
|
||||
def async_new_insteon_device(address=None):
|
||||
"""Detect device from transport to be delegated to platform."""
|
||||
ipdb = IPDB()
|
||||
for state_key in device.states:
|
||||
platform_info = ipdb[device.states[state_key]]
|
||||
if platform_info and platform_info.platform:
|
||||
platform = platform_info.platform
|
||||
hass.async_create_task(async_create_new_entities(address))
|
||||
|
||||
if platform == "on_off_events":
|
||||
device.states[state_key].register_updates(_fire_button_on_off_event)
|
||||
async def async_create_new_entities(address):
|
||||
_LOGGER.debug(
|
||||
"Adding new INSTEON device to Home Assistant with address %s", address
|
||||
)
|
||||
async with new_device_lock:
|
||||
await devices.async_save(workdir=hass.config.config_dir)
|
||||
device = devices[address]
|
||||
await device.async_status()
|
||||
platforms = get_device_platforms(device)
|
||||
tasks = []
|
||||
for platform in platforms:
|
||||
if platform == ON_OFF_EVENTS:
|
||||
add_on_off_event_device(hass, device)
|
||||
|
||||
else:
|
||||
_LOGGER.info(
|
||||
"New INSTEON device: %s (%s) %s",
|
||||
device.address,
|
||||
device.states[state_key].name,
|
||||
else:
|
||||
tasks.append(
|
||||
discovery.async_load_platform(
|
||||
hass,
|
||||
platform,
|
||||
DOMAIN,
|
||||
discovered={"address": device.address.id},
|
||||
hass_config=config,
|
||||
)
|
||||
)
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
hass.async_create_task(
|
||||
discovery.async_load_platform(
|
||||
hass,
|
||||
platform,
|
||||
DOMAIN,
|
||||
discovered={
|
||||
"address": device.address.id,
|
||||
"state_key": state_key,
|
||||
},
|
||||
hass_config=config,
|
||||
)
|
||||
)
|
||||
|
||||
insteon_modem.devices.add_device_callback(async_new_insteon_device)
|
||||
devices.subscribe(async_new_insteon_device, force_strong_ref=True)
|
||||
|
||||
|
||||
@callback
|
||||
def async_register_services(hass, config, insteon_modem):
|
||||
def async_register_services(hass):
|
||||
"""Register services used by insteon component."""
|
||||
|
||||
def add_all_link(service):
|
||||
async def async_srv_add_all_link(service):
|
||||
"""Add an INSTEON All-Link between two devices."""
|
||||
group = service.data.get(SRV_ALL_LINK_GROUP)
|
||||
mode = service.data.get(SRV_ALL_LINK_MODE)
|
||||
link_mode = 1 if mode.lower() == SRV_CONTROLLER else 0
|
||||
insteon_modem.start_all_linking(link_mode, group)
|
||||
link_mode = mode.lower() == SRV_CONTROLLER
|
||||
await async_enter_linking_mode(link_mode, group)
|
||||
|
||||
def del_all_link(service):
|
||||
async def async_srv_del_all_link(service):
|
||||
"""Delete an INSTEON All-Link between two devices."""
|
||||
group = service.data.get(SRV_ALL_LINK_GROUP)
|
||||
insteon_modem.start_all_linking(255, group)
|
||||
await async_enter_unlinking_mode(group)
|
||||
|
||||
def load_aldb(service):
|
||||
async def async_srv_load_aldb(service):
|
||||
"""Load the device All-Link database."""
|
||||
entity_id = service.data[CONF_ENTITY_ID]
|
||||
reload = service.data[SRV_LOAD_DB_RELOAD]
|
||||
if entity_id.lower() == ENTITY_MATCH_ALL:
|
||||
for entity_id in hass.data[DOMAIN][INSTEON_ENTITIES]:
|
||||
_send_load_aldb_signal(entity_id, reload)
|
||||
await async_srv_load_aldb_all(reload)
|
||||
else:
|
||||
_send_load_aldb_signal(entity_id, reload)
|
||||
signal = f"{entity_id}_{SIGNAL_LOAD_ALDB}"
|
||||
async_dispatcher_send(hass, signal, reload)
|
||||
|
||||
def _send_load_aldb_signal(entity_id, reload):
|
||||
"""Send the load All-Link database signal to INSTEON entity."""
|
||||
signal = f"{entity_id}_{SIGNAL_LOAD_ALDB}"
|
||||
dispatcher_send(hass, signal, reload)
|
||||
async def async_srv_load_aldb_all(reload):
|
||||
"""Load the All-Link database for all devices."""
|
||||
# Cannot be done concurrently due to issues with the underlying protocol.
|
||||
for address in devices:
|
||||
device = devices[address]
|
||||
if device != devices.modem and device.cat != 0x03:
|
||||
await device.aldb.async_load(
|
||||
refresh=reload, callback=async_srv_save_devices
|
||||
)
|
||||
|
||||
async def async_srv_save_devices():
|
||||
"""Write the Insteon device configuration to file."""
|
||||
_LOGGER.debug("Saving Insteon devices")
|
||||
await devices.async_save(hass.config.config_dir)
|
||||
|
||||
def print_aldb(service):
|
||||
"""Print the All-Link Database for a device."""
|
||||
|
@ -145,71 +204,85 @@ def async_register_services(hass, config, insteon_modem):
|
|||
"""Print the All-Link Database for a device."""
|
||||
# For now this sends logs to the log file.
|
||||
# Future direction is to create an INSTEON control panel.
|
||||
print_aldb_to_log(insteon_modem.aldb)
|
||||
print_aldb_to_log(devices.modem.aldb)
|
||||
|
||||
def x10_all_units_off(service):
|
||||
async def async_srv_x10_all_units_off(service):
|
||||
"""Send the X10 All Units Off command."""
|
||||
housecode = service.data.get(SRV_HOUSECODE)
|
||||
insteon_modem.x10_all_units_off(housecode)
|
||||
await async_x10_all_units_off(housecode)
|
||||
|
||||
def x10_all_lights_off(service):
|
||||
async def async_srv_x10_all_lights_off(service):
|
||||
"""Send the X10 All Lights Off command."""
|
||||
housecode = service.data.get(SRV_HOUSECODE)
|
||||
insteon_modem.x10_all_lights_off(housecode)
|
||||
await async_x10_all_lights_off(housecode)
|
||||
|
||||
def x10_all_lights_on(service):
|
||||
async def async_srv_x10_all_lights_on(service):
|
||||
"""Send the X10 All Lights On command."""
|
||||
housecode = service.data.get(SRV_HOUSECODE)
|
||||
insteon_modem.x10_all_lights_on(housecode)
|
||||
await async_x10_all_lights_on(housecode)
|
||||
|
||||
def scene_on(service):
|
||||
async def async_srv_scene_on(service):
|
||||
"""Trigger an INSTEON scene ON."""
|
||||
group = service.data.get(SRV_ALL_LINK_GROUP)
|
||||
insteon_modem.trigger_group_on(group)
|
||||
await async_trigger_scene_on(group)
|
||||
|
||||
def scene_off(service):
|
||||
async def async_srv_scene_off(service):
|
||||
"""Trigger an INSTEON scene ON."""
|
||||
group = service.data.get(SRV_ALL_LINK_GROUP)
|
||||
insteon_modem.trigger_group_off(group)
|
||||
await async_trigger_scene_off(group)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN, SRV_ADD_ALL_LINK, add_all_link, schema=ADD_ALL_LINK_SCHEMA
|
||||
DOMAIN, SRV_ADD_ALL_LINK, async_srv_add_all_link, schema=ADD_ALL_LINK_SCHEMA
|
||||
)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SRV_DEL_ALL_LINK, del_all_link, schema=DEL_ALL_LINK_SCHEMA
|
||||
DOMAIN, SRV_DEL_ALL_LINK, async_srv_del_all_link, schema=DEL_ALL_LINK_SCHEMA
|
||||
)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SRV_LOAD_ALDB, load_aldb, schema=LOAD_ALDB_SCHEMA
|
||||
DOMAIN, SRV_LOAD_ALDB, async_srv_load_aldb, schema=LOAD_ALDB_SCHEMA
|
||||
)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SRV_PRINT_ALDB, print_aldb, schema=PRINT_ALDB_SCHEMA
|
||||
)
|
||||
hass.services.async_register(DOMAIN, SRV_PRINT_IM_ALDB, print_im_aldb, schema=None)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SRV_X10_ALL_UNITS_OFF, x10_all_units_off, schema=X10_HOUSECODE_SCHEMA
|
||||
DOMAIN,
|
||||
SRV_X10_ALL_UNITS_OFF,
|
||||
async_srv_x10_all_units_off,
|
||||
schema=X10_HOUSECODE_SCHEMA,
|
||||
)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SRV_X10_ALL_LIGHTS_OFF, x10_all_lights_off, schema=X10_HOUSECODE_SCHEMA
|
||||
DOMAIN,
|
||||
SRV_X10_ALL_LIGHTS_OFF,
|
||||
async_srv_x10_all_lights_off,
|
||||
schema=X10_HOUSECODE_SCHEMA,
|
||||
)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SRV_X10_ALL_LIGHTS_ON, x10_all_lights_on, schema=X10_HOUSECODE_SCHEMA
|
||||
DOMAIN,
|
||||
SRV_X10_ALL_LIGHTS_ON,
|
||||
async_srv_x10_all_lights_on,
|
||||
schema=X10_HOUSECODE_SCHEMA,
|
||||
)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SRV_SCENE_ON, scene_on, schema=TRIGGER_SCENE_SCHEMA
|
||||
DOMAIN, SRV_SCENE_ON, async_srv_scene_on, schema=TRIGGER_SCENE_SCHEMA
|
||||
)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SRV_SCENE_OFF, scene_off, schema=TRIGGER_SCENE_SCHEMA
|
||||
DOMAIN, SRV_SCENE_OFF, async_srv_scene_off, schema=TRIGGER_SCENE_SCHEMA
|
||||
)
|
||||
async_dispatcher_connect(hass, SIGNAL_SAVE_DEVICES, async_srv_save_devices)
|
||||
_LOGGER.debug("Insteon Services registered")
|
||||
|
||||
|
||||
def print_aldb_to_log(aldb):
|
||||
"""Print the All-Link Database to the log file."""
|
||||
_LOGGER.info("ALDB load status is %s", aldb.status.name)
|
||||
# This service is useless if the log level is not INFO for the
|
||||
# insteon component. Setting the log level to INFO and resetting it
|
||||
# back when we are done
|
||||
orig_log_level = _LOGGER.level
|
||||
if orig_log_level > logging.INFO:
|
||||
_LOGGER.setLevel(logging.INFO)
|
||||
_LOGGER.info("%s ALDB load status is %s", aldb.address, aldb.status.name)
|
||||
if aldb.status not in [ALDBStatus.LOADED, ALDBStatus.PARTIAL]:
|
||||
_LOGGER.warning("Device All-Link database not loaded")
|
||||
_LOGGER.warning("Use service insteon.load_aldb first")
|
||||
return
|
||||
_LOGGER.warning("All-Link database not loaded")
|
||||
|
||||
_LOGGER.info("RecID In Use Mode HWM Group Address Data 1 Data 2 Data 3")
|
||||
_LOGGER.info("----- ------ ---- --- ----- -------- ------ ------ ------")
|
||||
|
@ -217,12 +290,30 @@ def print_aldb_to_log(aldb):
|
|||
rec = aldb[mem_addr]
|
||||
# For now we write this to the log
|
||||
# Roadmap is to create a configuration panel
|
||||
in_use = "Y" if rec.control_flags.is_in_use else "N"
|
||||
mode = "C" if rec.control_flags.is_controller else "R"
|
||||
hwm = "Y" if rec.control_flags.is_high_water_mark else "N"
|
||||
in_use = "Y" if rec.is_in_use else "N"
|
||||
mode = "C" if rec.is_controller else "R"
|
||||
hwm = "Y" if rec.is_high_water_mark else "N"
|
||||
log_msg = (
|
||||
f" {rec.mem_addr:04x} {in_use:s} {mode:s} {hwm:s} "
|
||||
f"{rec.group:3d} {rec.address.human:s} {rec.data1:3d} "
|
||||
f"{rec.group:3d} {str(rec.target):s} {rec.data1:3d} "
|
||||
f"{rec.data2:3d} {rec.data3:3d}"
|
||||
)
|
||||
_LOGGER.info(log_msg)
|
||||
_LOGGER.setLevel(orig_log_level)
|
||||
|
||||
|
||||
@callback
|
||||
def async_add_insteon_entities(
|
||||
hass, platform, entity_type, async_add_entities, discovery_info
|
||||
):
|
||||
"""Add Insteon devices to a platform."""
|
||||
new_entities = []
|
||||
device_list = [discovery_info.get("address")] if discovery_info else devices
|
||||
|
||||
for address in device_list:
|
||||
device = devices[address]
|
||||
groups = get_platform_groups(device, platform)
|
||||
for group in groups:
|
||||
new_entities.append(entity_type(device, group))
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
|
|
@ -787,9 +787,6 @@ incomfort-client==0.4.0
|
|||
# homeassistant.components.influxdb
|
||||
influxdb==5.2.3
|
||||
|
||||
# homeassistant.components.insteon
|
||||
insteonplm==0.16.8
|
||||
|
||||
# homeassistant.components.iperf3
|
||||
iperf3==0.1.11
|
||||
|
||||
|
@ -1377,6 +1374,9 @@ pyialarm==0.3
|
|||
# homeassistant.components.icloud
|
||||
pyicloud==0.9.7
|
||||
|
||||
# homeassistant.components.insteon
|
||||
pyinsteon==1.0.0
|
||||
|
||||
# homeassistant.components.intesishome
|
||||
pyintesishome==1.7.4
|
||||
|
||||
|
|
Loading…
Reference in New Issue