ZHA code cleanup. (#25644)

* isort ZHA imports.

* Sort zha channel registry.

* Sort ZHA core registry.

* Sort ZHA core consts.
This commit is contained in:
Alexei Chetroi 2019-08-02 06:05:23 -04:00 committed by David F. Mulcahey
parent 39257164a9
commit 77e4ff94fd
26 changed files with 627 additions and 563 deletions

View File

@ -26,7 +26,7 @@ from .core.const import (
DEFAULT_BAUDRATE, DEFAULT_BAUDRATE,
DEFAULT_RADIO_TYPE, DEFAULT_RADIO_TYPE,
DOMAIN, DOMAIN,
ENABLE_QUIRKS, CONF_ENABLE_QUIRKS,
RadioType, RadioType,
) )
from .core.registries import establish_device_mappings from .core.registries import establish_device_mappings
@ -46,7 +46,7 @@ CONFIG_SCHEMA = vol.Schema(
vol.Optional(CONF_DEVICE_CONFIG, default={}): vol.Schema( vol.Optional(CONF_DEVICE_CONFIG, default={}): vol.Schema(
{cv.string: DEVICE_CONFIG_SCHEMA_ENTRY} {cv.string: DEVICE_CONFIG_SCHEMA_ENTRY}
), ),
vol.Optional(ENABLE_QUIRKS, default=True): cv.boolean, vol.Optional(CONF_ENABLE_QUIRKS, default=True): cv.boolean,
} }
) )
}, },
@ -99,7 +99,7 @@ async def async_setup_entry(hass, config_entry):
hass.data[DATA_ZHA][DATA_ZHA_DISPATCHERS] = [] hass.data[DATA_ZHA][DATA_ZHA_DISPATCHERS] = []
config = hass.data[DATA_ZHA].get(DATA_ZHA_CONFIG, {}) config = hass.data[DATA_ZHA].get(DATA_ZHA_CONFIG, {})
if config.get(ENABLE_QUIRKS, True): if config.get(CONF_ENABLE_QUIRKS, True):
# needs to be done here so that the ZHA module is finished loading # needs to be done here so that the ZHA module is finished loading
# before zhaquirks is imported # before zhaquirks is imported
# pylint: disable=W0611, W0612 # pylint: disable=W0611, W0612

View File

@ -21,16 +21,16 @@ from .core.const import (
ATTR_ENDPOINT_ID, ATTR_ENDPOINT_ID,
ATTR_MANUFACTURER, ATTR_MANUFACTURER,
ATTR_VALUE, ATTR_VALUE,
CLIENT_COMMANDS, CLUSTER_COMMANDS_CLIENT,
DATA_ZHA, DATA_ZHA,
DATA_ZHA_GATEWAY, DATA_ZHA_GATEWAY,
DOMAIN, DOMAIN,
IN, CLUSTER_TYPE_IN,
MFG_CLUSTER_ID_START, MFG_CLUSTER_ID_START,
NAME, ATTR_NAME,
OUT, CLUSTER_TYPE_OUT,
SERVER, CLUSTER_COMMAND_SERVER,
SERVER_COMMANDS, CLUSTER_COMMANDS_SERVER,
) )
from .core.helpers import async_is_bindable_target, convert_ieee, get_matched_clusters from .core.helpers import async_is_bindable_target, convert_ieee, get_matched_clusters
@ -74,7 +74,7 @@ SERVICE_SCHEMAS = {
vol.Required(ATTR_IEEE): convert_ieee, vol.Required(ATTR_IEEE): convert_ieee,
vol.Required(ATTR_ENDPOINT_ID): cv.positive_int, vol.Required(ATTR_ENDPOINT_ID): cv.positive_int,
vol.Required(ATTR_CLUSTER_ID): cv.positive_int, vol.Required(ATTR_CLUSTER_ID): cv.positive_int,
vol.Optional(ATTR_CLUSTER_TYPE, default=IN): cv.string, vol.Optional(ATTR_CLUSTER_TYPE, default=CLUSTER_TYPE_IN): cv.string,
vol.Required(ATTR_ATTRIBUTE): cv.positive_int, vol.Required(ATTR_ATTRIBUTE): cv.positive_int,
vol.Required(ATTR_VALUE): cv.string, vol.Required(ATTR_VALUE): cv.string,
vol.Optional(ATTR_MANUFACTURER): cv.positive_int, vol.Optional(ATTR_MANUFACTURER): cv.positive_int,
@ -85,7 +85,7 @@ SERVICE_SCHEMAS = {
vol.Required(ATTR_IEEE): convert_ieee, vol.Required(ATTR_IEEE): convert_ieee,
vol.Required(ATTR_ENDPOINT_ID): cv.positive_int, vol.Required(ATTR_ENDPOINT_ID): cv.positive_int,
vol.Required(ATTR_CLUSTER_ID): cv.positive_int, vol.Required(ATTR_CLUSTER_ID): cv.positive_int,
vol.Optional(ATTR_CLUSTER_TYPE, default=IN): cv.string, vol.Optional(ATTR_CLUSTER_TYPE, default=CLUSTER_TYPE_IN): cv.string,
vol.Required(ATTR_COMMAND): cv.positive_int, vol.Required(ATTR_COMMAND): cv.positive_int,
vol.Required(ATTR_COMMAND_TYPE): cv.string, vol.Required(ATTR_COMMAND_TYPE): cv.string,
vol.Optional(ATTR_ARGS, default=""): cv.string, vol.Optional(ATTR_ARGS, default=""): cv.string,
@ -155,7 +155,10 @@ def async_get_device_info(hass, device, ha_device_registry=None):
ret_device = {} ret_device = {}
ret_device.update(device.device_info) ret_device.update(device.device_info)
ret_device["entities"] = [ ret_device["entities"] = [
{"entity_id": entity_ref.reference_id, NAME: entity_ref.device_info[NAME]} {
"entity_id": entity_ref.reference_id,
ATTR_NAME: entity_ref.device_info[ATTR_NAME],
}
for entity_ref in zha_gateway.device_registry[device.ieee] for entity_ref in zha_gateway.device_registry[device.ieee]
] ]
@ -201,21 +204,21 @@ async def websocket_device_clusters(hass, connection, msg):
if zha_device is not None: if zha_device is not None:
clusters_by_endpoint = zha_device.async_get_clusters() clusters_by_endpoint = zha_device.async_get_clusters()
for ep_id, clusters in clusters_by_endpoint.items(): for ep_id, clusters in clusters_by_endpoint.items():
for c_id, cluster in clusters[IN].items(): for c_id, cluster in clusters[CLUSTER_TYPE_IN].items():
response_clusters.append( response_clusters.append(
{ {
TYPE: IN, TYPE: CLUSTER_TYPE_IN,
ID: c_id, ID: c_id,
NAME: cluster.__class__.__name__, ATTR_NAME: cluster.__class__.__name__,
"endpoint_id": ep_id, "endpoint_id": ep_id,
} }
) )
for c_id, cluster in clusters[OUT].items(): for c_id, cluster in clusters[CLUSTER_TYPE_OUT].items():
response_clusters.append( response_clusters.append(
{ {
TYPE: OUT, TYPE: CLUSTER_TYPE_OUT,
ID: c_id, ID: c_id,
NAME: cluster.__class__.__name__, ATTR_NAME: cluster.__class__.__name__,
"endpoint_id": ep_id, "endpoint_id": ep_id,
} }
) )
@ -250,7 +253,9 @@ async def websocket_device_cluster_attributes(hass, connection, msg):
) )
if attributes is not None: if attributes is not None:
for attr_id in attributes: for attr_id in attributes:
cluster_attributes.append({ID: attr_id, NAME: attributes[attr_id][0]}) cluster_attributes.append(
{ID: attr_id, ATTR_NAME: attributes[attr_id][0]}
)
_LOGGER.debug( _LOGGER.debug(
"Requested attributes for: %s %s %s %s", "Requested attributes for: %s %s %s %s",
"{}: [{}]".format(ATTR_CLUSTER_ID, cluster_id), "{}: [{}]".format(ATTR_CLUSTER_ID, cluster_id),
@ -289,20 +294,20 @@ async def websocket_device_cluster_commands(hass, connection, msg):
) )
if commands is not None: if commands is not None:
for cmd_id in commands[CLIENT_COMMANDS]: for cmd_id in commands[CLUSTER_COMMANDS_CLIENT]:
cluster_commands.append( cluster_commands.append(
{ {
TYPE: CLIENT, TYPE: CLIENT,
ID: cmd_id, ID: cmd_id,
NAME: commands[CLIENT_COMMANDS][cmd_id][0], ATTR_NAME: commands[CLUSTER_COMMANDS_CLIENT][cmd_id][0],
} }
) )
for cmd_id in commands[SERVER_COMMANDS]: for cmd_id in commands[CLUSTER_COMMANDS_SERVER]:
cluster_commands.append( cluster_commands.append(
{ {
TYPE: SERVER, TYPE: CLUSTER_COMMAND_SERVER,
ID: cmd_id, ID: cmd_id,
NAME: commands[SERVER_COMMANDS][cmd_id][0], ATTR_NAME: commands[CLUSTER_COMMANDS_SERVER][cmd_id][0],
} }
) )
_LOGGER.debug( _LOGGER.debug(

View File

@ -2,34 +2,35 @@
import logging import logging
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
DEVICE_CLASS_GAS,
DEVICE_CLASS_MOISTURE,
DEVICE_CLASS_MOTION,
DEVICE_CLASS_MOVING,
DEVICE_CLASS_OCCUPANCY,
DEVICE_CLASS_OPENING,
DEVICE_CLASS_SMOKE,
DEVICE_CLASS_VIBRATION,
DOMAIN, DOMAIN,
BinarySensorDevice, BinarySensorDevice,
DEVICE_CLASS_MOVING,
DEVICE_CLASS_MOTION,
DEVICE_CLASS_OPENING,
DEVICE_CLASS_MOISTURE,
DEVICE_CLASS_SMOKE,
DEVICE_CLASS_GAS,
DEVICE_CLASS_VIBRATION,
DEVICE_CLASS_OCCUPANCY,
) )
from homeassistant.const import STATE_ON from homeassistant.const import STATE_ON
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .core.const import ( from .core.const import (
SENSOR_ACCELERATION,
CHANNEL_ATTRIBUTE,
DATA_ZHA, DATA_ZHA,
DATA_ZHA_DISPATCHERS, DATA_ZHA_DISPATCHERS,
ZHA_DISCOVERY_NEW, SENSOR_OCCUPANCY,
ON_OFF_CHANNEL, CHANNEL_ON_OFF,
ZONE_CHANNEL, SENSOR_OPENING,
SIGNAL_ATTR_UPDATED,
ATTRIBUTE_CHANNEL,
UNKNOWN,
OPENING,
ZONE,
OCCUPANCY,
SENSOR_TYPE, SENSOR_TYPE,
ACCELERATION, SIGNAL_ATTR_UPDATED,
UNKNOWN,
ZHA_DISCOVERY_NEW,
ZONE,
CHANNEL_ZONE,
) )
from .entity import ZhaEntity from .entity import ZhaEntity
@ -54,10 +55,10 @@ async def get_ias_device_class(channel):
DEVICE_CLASS_REGISTRY = { DEVICE_CLASS_REGISTRY = {
UNKNOWN: None, UNKNOWN: None,
OPENING: DEVICE_CLASS_OPENING, SENSOR_OPENING: DEVICE_CLASS_OPENING,
ZONE: get_ias_device_class, ZONE: get_ias_device_class,
OCCUPANCY: DEVICE_CLASS_OCCUPANCY, SENSOR_OCCUPANCY: DEVICE_CLASS_OCCUPANCY,
ACCELERATION: DEVICE_CLASS_MOVING, SENSOR_ACCELERATION: DEVICE_CLASS_MOVING,
} }
@ -108,9 +109,9 @@ class BinarySensor(ZhaEntity, BinarySensorDevice):
"""Initialize the ZHA binary sensor.""" """Initialize the ZHA binary sensor."""
super().__init__(**kwargs) super().__init__(**kwargs)
self._device_state_attributes = {} self._device_state_attributes = {}
self._zone_channel = self.cluster_channels.get(ZONE_CHANNEL) self._zone_channel = self.cluster_channels.get(CHANNEL_ZONE)
self._on_off_channel = self.cluster_channels.get(ON_OFF_CHANNEL) self._on_off_channel = self.cluster_channels.get(CHANNEL_ON_OFF)
self._attr_channel = self.cluster_channels.get(ATTRIBUTE_CHANNEL) self._attr_channel = self.cluster_channels.get(CHANNEL_ATTRIBUTE)
self._zha_sensor_type = kwargs[SENSOR_TYPE] self._zha_sensor_type = kwargs[SENSOR_TYPE]
async def _determine_device_class(self): async def _determine_device_class(self):

View File

@ -13,20 +13,21 @@ from random import uniform
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from ..helpers import (
configure_reporting,
construct_unique_id,
safe_read,
get_attr_id_by_name,
bind_cluster,
LogMixin,
)
from ..const import ( from ..const import (
CHANNEL_ATTRIBUTE,
CHANNEL_EVENT_RELAY,
REPORT_CONFIG_DEFAULT, REPORT_CONFIG_DEFAULT,
SIGNAL_ATTR_UPDATED, SIGNAL_ATTR_UPDATED,
ATTRIBUTE_CHANNEL, CHANNEL_ZDO,
EVENT_RELAY_CHANNEL, )
ZDO_CHANNEL, from ..helpers import (
LogMixin,
bind_cluster,
configure_reporting,
construct_unique_id,
get_attr_id_by_name,
safe_read,
) )
from ..registries import CLUSTER_REPORT_CONFIGS from ..registries import CLUSTER_REPORT_CONFIGS
@ -232,7 +233,7 @@ class ZigbeeChannel(LogMixin):
class AttributeListeningChannel(ZigbeeChannel): class AttributeListeningChannel(ZigbeeChannel):
"""Channel for attribute reports from the cluster.""" """Channel for attribute reports from the cluster."""
CHANNEL_NAME = ATTRIBUTE_CHANNEL CHANNEL_NAME = CHANNEL_ATTRIBUTE
def __init__(self, cluster, device): def __init__(self, cluster, device):
"""Initialize AttributeListeningChannel.""" """Initialize AttributeListeningChannel."""
@ -266,7 +267,7 @@ class ZDOChannel(LogMixin):
def __init__(self, cluster, device): def __init__(self, cluster, device):
"""Initialize ZDOChannel.""" """Initialize ZDOChannel."""
self.name = ZDO_CHANNEL self.name = CHANNEL_ZDO
self._cluster = cluster self._cluster = cluster
self._zha_device = device self._zha_device = device
self._status = ChannelStatus.CREATED self._status = ChannelStatus.CREATED
@ -320,7 +321,7 @@ class ZDOChannel(LogMixin):
class EventRelayChannel(ZigbeeChannel): class EventRelayChannel(ZigbeeChannel):
"""Event relay that can be attached to zigbee clusters.""" """Event relay that can be attached to zigbee clusters."""
CHANNEL_NAME = EVENT_RELAY_CHANNEL CHANNEL_NAME = CHANNEL_EVENT_RELAY
@callback @callback
def attribute_updated(self, attrid, value): def attribute_updated(self, attrid, value):

View File

@ -5,8 +5,10 @@ For more details about this component, please refer to the documentation at
https://home-assistant.io/components/zha/ https://home-assistant.io/components/zha/
""" """
import logging import logging
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from . import ZigbeeChannel from . import ZigbeeChannel
from ..const import SIGNAL_ATTR_UPDATED from ..const import SIGNAL_ATTR_UPDATED

View File

@ -5,12 +5,14 @@ For more details about this component, please refer to the documentation at
https://home-assistant.io/components/zha/ https://home-assistant.io/components/zha/
""" """
import logging import logging
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_call_later from homeassistant.helpers.event import async_call_later
from . import ZigbeeChannel, parse_and_log_command from . import ZigbeeChannel, parse_and_log_command
from ..helpers import get_attr_id_by_name
from ..const import SIGNAL_ATTR_UPDATED, SIGNAL_MOVE_LEVEL, SIGNAL_SET_LEVEL from ..const import SIGNAL_ATTR_UPDATED, SIGNAL_MOVE_LEVEL, SIGNAL_SET_LEVEL
from ..helpers import get_attr_id_by_name
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -5,9 +5,11 @@ For more details about this component, please refer to the documentation at
https://home-assistant.io/components/zha/ https://home-assistant.io/components/zha/
""" """
import logging import logging
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from . import AttributeListeningChannel from . import AttributeListeningChannel
from ..const import SIGNAL_ATTR_UPDATED, ELECTRICAL_MEASUREMENT_CHANNEL from ..const import CHANNEL_ELECTRICAL_MEASUREMENT, SIGNAL_ATTR_UPDATED
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -15,7 +17,7 @@ _LOGGER = logging.getLogger(__name__)
class ElectricalMeasurementChannel(AttributeListeningChannel): class ElectricalMeasurementChannel(AttributeListeningChannel):
"""Channel that polls active power level.""" """Channel that polls active power level."""
CHANNEL_NAME = ELECTRICAL_MEASUREMENT_CHANNEL CHANNEL_NAME = CHANNEL_ELECTRICAL_MEASUREMENT
async def async_update(self): async def async_update(self):
"""Retrieve latest state.""" """Retrieve latest state."""

View File

@ -5,8 +5,10 @@ For more details about this component, please refer to the documentation at
https://home-assistant.io/components/zha/ https://home-assistant.io/components/zha/
""" """
import logging import logging
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from . import ZigbeeChannel from . import ZigbeeChannel
from ..const import SIGNAL_ATTR_UPDATED from ..const import SIGNAL_ATTR_UPDATED

View File

@ -5,6 +5,7 @@ For more details about this component, please refer to the documentation at
https://home-assistant.io/components/zha/ https://home-assistant.io/components/zha/
""" """
import logging import logging
from . import ZigbeeChannel from . import ZigbeeChannel
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -5,13 +5,12 @@ For more details about this component, please refer to the documentation at
https://home-assistant.io/components/zha/ https://home-assistant.io/components/zha/
""" """
from . import ZigbeeChannel from . import ZigbeeChannel
from .closures import DoorLockChannel from .closures import DoorLockChannel
from .general import ( from .general import (
OnOffChannel,
LevelControlChannel,
PowerConfigurationChannel,
BasicChannel, BasicChannel,
LevelControlChannel,
OnOffChannel,
PowerConfigurationChannel,
) )
from .homeautomation import ElectricalMeasurementChannel from .homeautomation import ElectricalMeasurementChannel
from .hvac import FanChannel from .hvac import FanChannel
@ -27,27 +26,27 @@ def populate_channel_registry():
ZIGBEE_CHANNEL_REGISTRY.update( ZIGBEE_CHANNEL_REGISTRY.update(
{ {
zcl.clusters.general.Alarms.cluster_id: ZigbeeChannel,
zcl.clusters.general.Commissioning.cluster_id: ZigbeeChannel,
zcl.clusters.general.Identify.cluster_id: ZigbeeChannel,
zcl.clusters.general.Groups.cluster_id: ZigbeeChannel,
zcl.clusters.general.Scenes.cluster_id: ZigbeeChannel,
zcl.clusters.general.Partition.cluster_id: ZigbeeChannel,
zcl.clusters.general.Ota.cluster_id: ZigbeeChannel,
zcl.clusters.general.PowerProfile.cluster_id: ZigbeeChannel,
zcl.clusters.general.ApplianceControl.cluster_id: ZigbeeChannel,
zcl.clusters.general.PollControl.cluster_id: ZigbeeChannel,
zcl.clusters.general.GreenPowerProxy.cluster_id: ZigbeeChannel,
zcl.clusters.general.OnOffConfiguration.cluster_id: ZigbeeChannel,
zcl.clusters.general.OnOff.cluster_id: OnOffChannel,
zcl.clusters.general.LevelControl.cluster_id: LevelControlChannel,
zcl.clusters.lighting.Color.cluster_id: ColorChannel,
zcl.clusters.homeautomation.ElectricalMeasurement.cluster_id: ElectricalMeasurementChannel,
zcl.clusters.general.PowerConfiguration.cluster_id: PowerConfigurationChannel,
zcl.clusters.general.Basic.cluster_id: BasicChannel,
zcl.clusters.security.IasZone.cluster_id: IASZoneChannel,
zcl.clusters.hvac.Fan.cluster_id: FanChannel,
zcl.clusters.lightlink.LightLink.cluster_id: ZigbeeChannel,
zcl.clusters.closures.DoorLock.cluster_id: DoorLockChannel, zcl.clusters.closures.DoorLock.cluster_id: DoorLockChannel,
zcl.clusters.general.Alarms.cluster_id: ZigbeeChannel,
zcl.clusters.general.ApplianceControl.cluster_id: ZigbeeChannel,
zcl.clusters.general.Basic.cluster_id: BasicChannel,
zcl.clusters.general.Commissioning.cluster_id: ZigbeeChannel,
zcl.clusters.general.GreenPowerProxy.cluster_id: ZigbeeChannel,
zcl.clusters.general.Groups.cluster_id: ZigbeeChannel,
zcl.clusters.general.Identify.cluster_id: ZigbeeChannel,
zcl.clusters.general.LevelControl.cluster_id: LevelControlChannel,
zcl.clusters.general.OnOff.cluster_id: OnOffChannel,
zcl.clusters.general.OnOffConfiguration.cluster_id: ZigbeeChannel,
zcl.clusters.general.Ota.cluster_id: ZigbeeChannel,
zcl.clusters.general.Partition.cluster_id: ZigbeeChannel,
zcl.clusters.general.PollControl.cluster_id: ZigbeeChannel,
zcl.clusters.general.PowerConfiguration.cluster_id: PowerConfigurationChannel,
zcl.clusters.general.PowerProfile.cluster_id: ZigbeeChannel,
zcl.clusters.general.Scenes.cluster_id: ZigbeeChannel,
zcl.clusters.homeautomation.ElectricalMeasurement.cluster_id: ElectricalMeasurementChannel,
zcl.clusters.hvac.Fan.cluster_id: FanChannel,
zcl.clusters.lighting.Color.cluster_id: ColorChannel,
zcl.clusters.lightlink.LightLink.cluster_id: ZigbeeChannel,
zcl.clusters.security.IasZone.cluster_id: IASZoneChannel,
} }
) )

View File

@ -5,11 +5,13 @@ For more details about this component, please refer to the documentation at
https://home-assistant.io/components/zha/ https://home-assistant.io/components/zha/
""" """
import logging import logging
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from . import ZigbeeChannel from . import ZigbeeChannel
from ..helpers import bind_cluster
from ..const import SIGNAL_ATTR_UPDATED from ..const import SIGNAL_ATTR_UPDATED
from ..helpers import bind_cluster
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -10,132 +10,98 @@ from homeassistant.components.lock import DOMAIN as LOCK
from homeassistant.components.sensor import DOMAIN as SENSOR from homeassistant.components.sensor import DOMAIN as SENSOR
from homeassistant.components.switch import DOMAIN as SWITCH from homeassistant.components.switch import DOMAIN as SWITCH
DOMAIN = "zha" ATTR_ARGS = "args"
ATTR_ATTRIBUTE = "attribute"
ATTR_AVAILABLE = "available"
ATTR_CLUSTER_ID = "cluster_id"
ATTR_CLUSTER_TYPE = "cluster_type"
ATTR_COMMAND = "command"
ATTR_COMMAND_TYPE = "command_type"
ATTR_ENDPOINT_ID = "endpoint_id"
ATTR_IEEE = "ieee"
ATTR_LAST_SEEN = "last_seen"
ATTR_LEVEL = "level"
ATTR_LQI = "lqi"
ATTR_MANUFACTURER = "manufacturer"
ATTR_MANUFACTURER_CODE = "manufacturer_code"
ATTR_MODEL = "model"
ATTR_NAME = "name"
ATTR_NWK = "nwk"
ATTR_POWER_SOURCE = "power_source"
ATTR_QUIRK_APPLIED = "quirk_applied"
ATTR_QUIRK_CLASS = "quirk_class"
ATTR_RSSI = "rssi"
ATTR_SIGNATURE = "signature"
ATTR_TYPE = "type"
ATTR_VALUE = "value"
BAUD_RATES = [2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200, 128000, 256000] BAUD_RATES = [2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200, 128000, 256000]
DATA_ZHA = "zha" CHANNEL_ATTRIBUTE = "attribute"
DATA_ZHA_CONFIG = "config" CHANNEL_BASIC = "basic"
DATA_ZHA_BRIDGE_ID = "zha_bridge_id" CHANNEL_COLOR = "light_color"
DATA_ZHA_DISPATCHERS = "zha_dispatchers" CHANNEL_DOORLOCK = "door_lock"
DATA_ZHA_CORE_EVENTS = "zha_core_events" CHANNEL_ELECTRICAL_MEASUREMENT = "electrical_measurement"
DATA_ZHA_GATEWAY = "zha_gateway" CHANNEL_EVENT_RELAY = "event_relay"
ZHA_DISCOVERY_NEW = "zha_discovery_new_{}" CHANNEL_FAN = "fan"
CHANNEL_LEVEL = ATTR_LEVEL
CHANNEL_ON_OFF = "on_off"
CHANNEL_POWER_CONFIGURATION = "power"
CHANNEL_ZDO = "zdo"
CHANNEL_ZONE = ZONE = "ias_zone"
CLUSTER_COMMAND_SERVER = "server"
CLUSTER_COMMANDS_CLIENT = "client_commands"
CLUSTER_COMMANDS_SERVER = "server_commands"
CLUSTER_TYPE_IN = "in"
CLUSTER_TYPE_OUT = "out"
COMPONENTS = (BINARY_SENSOR, DEVICE_TRACKER, FAN, LIGHT, LOCK, SENSOR, SWITCH) COMPONENTS = (BINARY_SENSOR, DEVICE_TRACKER, FAN, LIGHT, LOCK, SENSOR, SWITCH)
CONF_BAUDRATE = "baudrate" CONF_BAUDRATE = "baudrate"
CONF_DATABASE = "database_path" CONF_DATABASE = "database_path"
CONF_DEVICE_CONFIG = "device_config" CONF_DEVICE_CONFIG = "device_config"
CONF_ENABLE_QUIRKS = "enable_quirks"
CONF_RADIO_TYPE = "radio_type" CONF_RADIO_TYPE = "radio_type"
CONF_USB_PATH = "usb_path" CONF_USB_PATH = "usb_path"
DATA_DEVICE_CONFIG = "zha_device_config"
ENABLE_QUIRKS = "enable_quirks"
RADIO = "radio"
RADIO_DESCRIPTION = "radio_description"
CONTROLLER = "controller" CONTROLLER = "controller"
DATA_DEVICE_CONFIG = "zha_device_config"
DATA_ZHA = "zha"
DATA_ZHA_CONFIG = "config"
DATA_ZHA_BRIDGE_ID = "zha_bridge_id"
DATA_ZHA_CORE_EVENTS = "zha_core_events"
DATA_ZHA_DISPATCHERS = "zha_dispatchers"
DATA_ZHA_GATEWAY = "zha_gateway"
DEBUG_COMP_BELLOWS = "bellows"
DEBUG_COMP_ZHA = "homeassistant.components.zha"
DEBUG_COMP_ZIGPY = "zigpy"
DEBUG_COMP_ZIGPY_DECONZ = "zigpy_deconz"
DEBUG_COMP_ZIGPY_XBEE = "zigpy_xbee"
DEBUG_LEVEL_CURRENT = "current"
DEBUG_LEVEL_ORIGINAL = "original"
DEBUG_LEVELS = {
DEBUG_COMP_BELLOWS: logging.DEBUG,
DEBUG_COMP_ZHA: logging.DEBUG,
DEBUG_COMP_ZIGPY: logging.DEBUG,
DEBUG_COMP_ZIGPY_XBEE: logging.DEBUG,
DEBUG_COMP_ZIGPY_DECONZ: logging.DEBUG,
}
DEBUG_RELAY_LOGGERS = [DEBUG_COMP_ZHA, DEBUG_COMP_ZIGPY]
DEFAULT_RADIO_TYPE = "ezsp" DEFAULT_RADIO_TYPE = "ezsp"
DEFAULT_BAUDRATE = 57600 DEFAULT_BAUDRATE = 57600
DEFAULT_DATABASE_NAME = "zigbee.db" DEFAULT_DATABASE_NAME = "zigbee.db"
DISCOVERY_KEY = "zha_discovery_info"
ATTR_CLUSTER_ID = "cluster_id" DOMAIN = "zha"
ATTR_CLUSTER_TYPE = "cluster_type"
ATTR_ATTRIBUTE = "attribute"
ATTR_VALUE = "value"
ATTR_MANUFACTURER = "manufacturer"
ATTR_COMMAND = "command"
ATTR_COMMAND_TYPE = "command_type"
ATTR_ARGS = "args"
ATTR_ENDPOINT_ID = "endpoint_id"
ATTR_AVAILABLE = "available"
IN = "in"
OUT = "out"
CLIENT_COMMANDS = "client_commands"
SERVER_COMMANDS = "server_commands"
SERVER = "server"
IEEE = "ieee"
MODEL = "model"
NAME = "name"
LQI = "lqi"
RSSI = "rssi"
LAST_SEEN = "last_seen"
SENSOR_TYPE = "sensor_type"
HUMIDITY = "humidity"
TEMPERATURE = "temperature"
ILLUMINANCE = "illuminance"
PRESSURE = "pressure"
METERING = "metering"
ELECTRICAL_MEASUREMENT = "electrical_measurement"
GENERIC = "generic"
BATTERY = "battery"
UNKNOWN = "unknown"
UNKNOWN_MANUFACTURER = "unk_manufacturer"
UNKNOWN_MODEL = "unk_model"
OPENING = "opening"
OCCUPANCY = "occupancy"
ACCELERATION = "acceleration"
ATTR_LEVEL = "level"
ZDO_CHANNEL = "zdo"
ON_OFF_CHANNEL = "on_off"
ATTRIBUTE_CHANNEL = "attribute"
BASIC_CHANNEL = "basic"
COLOR_CHANNEL = "light_color"
FAN_CHANNEL = "fan"
LEVEL_CHANNEL = ATTR_LEVEL
ZONE_CHANNEL = ZONE = "ias_zone"
ELECTRICAL_MEASUREMENT_CHANNEL = "electrical_measurement"
POWER_CONFIGURATION_CHANNEL = "power"
EVENT_RELAY_CHANNEL = "event_relay"
DOORLOCK_CHANNEL = "door_lock"
SIGNAL_ATTR_UPDATED = "attribute_updated"
SIGNAL_MOVE_LEVEL = "move_level"
SIGNAL_SET_LEVEL = "set_level"
SIGNAL_STATE_ATTR = "update_state_attribute"
SIGNAL_AVAILABLE = "available"
SIGNAL_REMOVE = "remove"
QUIRK_APPLIED = "quirk_applied"
QUIRK_CLASS = "quirk_class"
MANUFACTURER_CODE = "manufacturer_code"
POWER_SOURCE = "power_source"
MAINS_POWERED = "Mains"
BATTERY_OR_UNKNOWN = "Battery or Unknown"
BELLOWS = "bellows"
ZHA = "homeassistant.components.zha"
ZIGPY = "zigpy"
ZIGPY_XBEE = "zigpy_xbee"
ZIGPY_DECONZ = "zigpy_deconz"
ORIGINAL = "original"
CURRENT = "current"
DEBUG_LEVELS = {
BELLOWS: logging.DEBUG,
ZHA: logging.DEBUG,
ZIGPY: logging.DEBUG,
ZIGPY_XBEE: logging.DEBUG,
ZIGPY_DECONZ: logging.DEBUG,
}
ADD_DEVICE_RELAY_LOGGERS = [ZHA, ZIGPY]
TYPE = "type"
NWK = "nwk"
SIGNATURE = "signature"
RAW_INIT = "raw_device_initialized"
ZHA_GW_MSG = "zha_gateway_message"
DEVICE_REMOVED = "device_removed"
DEVICE_INFO = "device_info"
DEVICE_FULL_INIT = "device_fully_initialized"
DEVICE_JOINED = "device_joined"
LOG_OUTPUT = "log_output"
LOG_ENTRY = "log_entry"
MFG_CLUSTER_ID_START = 0xFC00 MFG_CLUSTER_ID_START = 0xFC00
POWER_MAINS_POWERED = "Mains"
POWER_BATTERY_OR_UNKNOWN = "Battery or Unknown"
class RadioType(enum.Enum): class RadioType(enum.Enum):
"""Possible options for radio type.""" """Possible options for radio type."""
@ -150,8 +116,6 @@ class RadioType(enum.Enum):
return [e.value for e in RadioType] return [e.value for e in RadioType]
DISCOVERY_KEY = "zha_discovery_info"
REPORT_CONFIG_MAX_INT = 900 REPORT_CONFIG_MAX_INT = 900
REPORT_CONFIG_MAX_INT_BATTERY_SAVE = 10800 REPORT_CONFIG_MAX_INT_BATTERY_SAVE = 10800
REPORT_CONFIG_MIN_INT = 30 REPORT_CONFIG_MIN_INT = 30
@ -185,3 +149,39 @@ REPORT_CONFIG_OP = (
REPORT_CONFIG_MAX_INT, REPORT_CONFIG_MAX_INT,
REPORT_CONFIG_RPT_CHANGE, REPORT_CONFIG_RPT_CHANGE,
) )
SENSOR_ACCELERATION = "acceleration"
SENSOR_BATTERY = "battery"
SENSOR_ELECTRICAL_MEASUREMENT = "electrical_measurement"
SENSOR_GENERIC = "generic"
SENSOR_HUMIDITY = "humidity"
SENSOR_ILLUMINANCE = "illuminance"
SENSOR_METERING = "metering"
SENSOR_OCCUPANCY = "occupancy"
SENSOR_OPENING = "opening"
SENSOR_PRESSURE = "pressure"
SENSOR_TEMPERATURE = "temperature"
SENSOR_TYPE = "sensor_type"
SIGNAL_ATTR_UPDATED = "attribute_updated"
SIGNAL_AVAILABLE = "available"
SIGNAL_MOVE_LEVEL = "move_level"
SIGNAL_REMOVE = "remove"
SIGNAL_SET_LEVEL = "set_level"
SIGNAL_STATE_ATTR = "update_state_attribute"
UNKNOWN = "unknown"
UNKNOWN_MANUFACTURER = "unk_manufacturer"
UNKNOWN_MODEL = "unk_model"
ZHA_DISCOVERY_NEW = "zha_discovery_new_{}"
ZHA_GW_MSG_RAW_INIT = "raw_device_initialized"
ZHA_GW_MSG = "zha_gateway_message"
ZHA_GW_MSG_DEVICE_REMOVED = "device_removed"
ZHA_GW_MSG_DEVICE_INFO = "device_info"
ZHA_GW_MSG_DEVICE_FULL_INIT = "device_fully_initialized"
ZHA_GW_MSG_DEVICE_JOINED = "device_joined"
ZHA_GW_MSG_LOG_OUTPUT = "log_output"
ZHA_GW_MSG_LOG_ENTRY = "log_entry"
ZHA_GW_RADIO = "radio"
ZHA_GW_RADIO_DESCRIPTION = "radio_description"

View File

@ -21,36 +21,36 @@ from .channels import EventRelayChannel
from .const import ( from .const import (
ATTR_ARGS, ATTR_ARGS,
ATTR_ATTRIBUTE, ATTR_ATTRIBUTE,
ATTR_AVAILABLE,
ATTR_CLUSTER_ID, ATTR_CLUSTER_ID,
ATTR_COMMAND, ATTR_COMMAND,
ATTR_COMMAND_TYPE, ATTR_COMMAND_TYPE,
ATTR_ENDPOINT_ID, ATTR_ENDPOINT_ID,
ATTR_MANUFACTURER, ATTR_MANUFACTURER,
ATTR_VALUE, ATTR_VALUE,
BATTERY_OR_UNKNOWN, POWER_BATTERY_OR_UNKNOWN,
CLIENT_COMMANDS, CLUSTER_COMMANDS_CLIENT,
IEEE, ATTR_IEEE,
IN, CLUSTER_TYPE_IN,
MAINS_POWERED, ATTR_LAST_SEEN,
MANUFACTURER_CODE, ATTR_LQI,
MODEL, POWER_MAINS_POWERED,
NAME, ATTR_MANUFACTURER_CODE,
NWK, ATTR_MODEL,
OUT, ATTR_NAME,
POWER_CONFIGURATION_CHANNEL, ATTR_NWK,
POWER_SOURCE, CLUSTER_TYPE_OUT,
QUIRK_APPLIED, CHANNEL_POWER_CONFIGURATION,
QUIRK_CLASS, ATTR_POWER_SOURCE,
SERVER, ATTR_QUIRK_APPLIED,
SERVER_COMMANDS, ATTR_QUIRK_CLASS,
ATTR_RSSI,
CLUSTER_COMMAND_SERVER,
CLUSTER_COMMANDS_SERVER,
SIGNAL_AVAILABLE, SIGNAL_AVAILABLE,
UNKNOWN_MANUFACTURER, UNKNOWN_MANUFACTURER,
UNKNOWN_MODEL, UNKNOWN_MODEL,
ZDO_CHANNEL, CHANNEL_ZDO,
LQI,
RSSI,
LAST_SEEN,
ATTR_AVAILABLE,
) )
from .helpers import LogMixin from .helpers import LogMixin
@ -155,7 +155,9 @@ class ZHADevice(LogMixin):
@property @property
def power_source(self): def power_source(self):
"""Return the power source for the device.""" """Return the power source for the device."""
return MAINS_POWERED if self.is_mains_powered else BATTERY_OR_UNKNOWN return (
POWER_MAINS_POWERED if self.is_mains_powered else POWER_BATTERY_OR_UNKNOWN
)
@property @property
def is_router(self): def is_router(self):
@ -223,18 +225,18 @@ class ZHADevice(LogMixin):
time_struct = time.localtime(self.last_seen) time_struct = time.localtime(self.last_seen)
update_time = time.strftime("%Y-%m-%dT%H:%M:%S", time_struct) update_time = time.strftime("%Y-%m-%dT%H:%M:%S", time_struct)
return { return {
IEEE: ieee, ATTR_IEEE: ieee,
NWK: self.nwk, ATTR_NWK: self.nwk,
ATTR_MANUFACTURER: self.manufacturer, ATTR_MANUFACTURER: self.manufacturer,
MODEL: self.model, ATTR_MODEL: self.model,
NAME: self.name or ieee, ATTR_NAME: self.name or ieee,
QUIRK_APPLIED: self.quirk_applied, ATTR_QUIRK_APPLIED: self.quirk_applied,
QUIRK_CLASS: self.quirk_class, ATTR_QUIRK_CLASS: self.quirk_class,
MANUFACTURER_CODE: self.manufacturer_code, ATTR_MANUFACTURER_CODE: self.manufacturer_code,
POWER_SOURCE: self.power_source, ATTR_POWER_SOURCE: self.power_source,
LQI: self.lqi, ATTR_LQI: self.lqi,
RSSI: self.rssi, ATTR_RSSI: self.rssi,
LAST_SEEN: update_time, ATTR_LAST_SEEN: update_time,
ATTR_AVAILABLE: self.available, ATTR_AVAILABLE: self.available,
} }
@ -242,8 +244,8 @@ class ZHADevice(LogMixin):
"""Add cluster channel to device.""" """Add cluster channel to device."""
# only keep 1 power configuration channel # only keep 1 power configuration channel
if ( if (
cluster_channel.name is POWER_CONFIGURATION_CHANNEL cluster_channel.name is CHANNEL_POWER_CONFIGURATION
and POWER_CONFIGURATION_CHANNEL in self.cluster_channels and CHANNEL_POWER_CONFIGURATION in self.cluster_channels
): ):
return return
@ -318,7 +320,7 @@ class ZHADevice(LogMixin):
semaphore = asyncio.Semaphore(3) semaphore = asyncio.Semaphore(3)
zdo_task = None zdo_task = None
for channel in channels: for channel in channels:
if channel.name == ZDO_CHANNEL: if channel.name == CHANNEL_ZDO:
# pylint: disable=E1111 # pylint: disable=E1111
if zdo_task is None: # We only want to do this once if zdo_task is None: # We only want to do this once
zdo_task = self._async_create_task( zdo_task = self._async_create_task(
@ -356,7 +358,10 @@ class ZHADevice(LogMixin):
def async_get_clusters(self): def async_get_clusters(self):
"""Get all clusters for this device.""" """Get all clusters for this device."""
return { return {
ep_id: {IN: endpoint.in_clusters, OUT: endpoint.out_clusters} ep_id: {
CLUSTER_TYPE_IN: endpoint.in_clusters,
CLUSTER_TYPE_OUT: endpoint.out_clusters,
}
for (ep_id, endpoint) in self._zigpy_device.endpoints.items() for (ep_id, endpoint) in self._zigpy_device.endpoints.items()
if ep_id != 0 if ep_id != 0
} }
@ -367,19 +372,24 @@ class ZHADevice(LogMixin):
from zigpy.profiles import zha, zll from zigpy.profiles import zha, zll
return { return {
ep_id: {IN: endpoint.in_clusters, OUT: endpoint.out_clusters} ep_id: {
CLUSTER_TYPE_IN: endpoint.in_clusters,
CLUSTER_TYPE_OUT: endpoint.out_clusters,
}
for (ep_id, endpoint) in self._zigpy_device.endpoints.items() for (ep_id, endpoint) in self._zigpy_device.endpoints.items()
if ep_id != 0 and endpoint.profile_id in (zha.PROFILE_ID, zll.PROFILE_ID) if ep_id != 0 and endpoint.profile_id in (zha.PROFILE_ID, zll.PROFILE_ID)
} }
@callback @callback
def async_get_cluster(self, endpoint_id, cluster_id, cluster_type=IN): def async_get_cluster(self, endpoint_id, cluster_id, cluster_type=CLUSTER_TYPE_IN):
"""Get zigbee cluster from this entity.""" """Get zigbee cluster from this entity."""
clusters = self.async_get_clusters() clusters = self.async_get_clusters()
return clusters[endpoint_id][cluster_type][cluster_id] return clusters[endpoint_id][cluster_type][cluster_id]
@callback @callback
def async_get_cluster_attributes(self, endpoint_id, cluster_id, cluster_type=IN): def async_get_cluster_attributes(
self, endpoint_id, cluster_id, cluster_type=CLUSTER_TYPE_IN
):
"""Get zigbee attributes for specified cluster.""" """Get zigbee attributes for specified cluster."""
cluster = self.async_get_cluster(endpoint_id, cluster_id, cluster_type) cluster = self.async_get_cluster(endpoint_id, cluster_id, cluster_type)
if cluster is None: if cluster is None:
@ -387,14 +397,16 @@ class ZHADevice(LogMixin):
return cluster.attributes return cluster.attributes
@callback @callback
def async_get_cluster_commands(self, endpoint_id, cluster_id, cluster_type=IN): def async_get_cluster_commands(
self, endpoint_id, cluster_id, cluster_type=CLUSTER_TYPE_IN
):
"""Get zigbee commands for specified cluster.""" """Get zigbee commands for specified cluster."""
cluster = self.async_get_cluster(endpoint_id, cluster_id, cluster_type) cluster = self.async_get_cluster(endpoint_id, cluster_id, cluster_type)
if cluster is None: if cluster is None:
return None return None
return { return {
CLIENT_COMMANDS: cluster.client_commands, CLUSTER_COMMANDS_CLIENT: cluster.client_commands,
SERVER_COMMANDS: cluster.server_commands, CLUSTER_COMMANDS_SERVER: cluster.server_commands,
} }
async def write_zigbee_attribute( async def write_zigbee_attribute(
@ -403,7 +415,7 @@ class ZHADevice(LogMixin):
cluster_id, cluster_id,
attribute, attribute,
value, value,
cluster_type=IN, cluster_type=CLUSTER_TYPE_IN,
manufacturer=None, manufacturer=None,
): ):
"""Write a value to a zigbee attribute for a cluster in this entity.""" """Write a value to a zigbee attribute for a cluster in this entity."""
@ -444,7 +456,7 @@ class ZHADevice(LogMixin):
command, command,
command_type, command_type,
args, args,
cluster_type=IN, cluster_type=CLUSTER_TYPE_IN,
manufacturer=None, manufacturer=None,
): ):
"""Issue a command against specified zigbee cluster on this entity.""" """Issue a command against specified zigbee cluster on this entity."""
@ -452,7 +464,7 @@ class ZHADevice(LogMixin):
if cluster is None: if cluster is None:
return None return None
response = None response = None
if command_type == SERVER: if command_type == CLUSTER_COMMAND_SERVER:
response = await cluster.command( response = await cluster.command(
command, *args, manufacturer=manufacturer, expect_reply=True command, *args, manufacturer=manufacturer, expect_reply=True
) )

View File

@ -12,28 +12,29 @@ from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR
from homeassistant.components.sensor import DOMAIN as SENSOR from homeassistant.components.sensor import DOMAIN as SENSOR
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from .channels import AttributeListeningChannel, EventRelayChannel, ZDOChannel from .channels import AttributeListeningChannel, EventRelayChannel, ZDOChannel
from .channels.registry import ZIGBEE_CHANNEL_REGISTRY from .channels.registry import ZIGBEE_CHANNEL_REGISTRY
from .const import ( from .const import (
CONF_DEVICE_CONFIG,
COMPONENTS, COMPONENTS,
ZHA_DISCOVERY_NEW, CONF_DEVICE_CONFIG,
DATA_ZHA, DATA_ZHA,
SENSOR_GENERIC,
SENSOR_TYPE, SENSOR_TYPE,
UNKNOWN, UNKNOWN,
GENERIC, ZHA_DISCOVERY_NEW,
) )
from .registries import ( from .registries import (
BINARY_SENSOR_TYPES, BINARY_SENSOR_TYPES,
CHANNEL_ONLY_CLUSTERS, CHANNEL_ONLY_CLUSTERS,
EVENT_RELAY_CLUSTERS,
SENSOR_TYPES,
DEVICE_CLASS,
COMPONENT_CLUSTERS, COMPONENT_CLUSTERS,
SINGLE_INPUT_CLUSTER_DEVICE_CLASS, DEVICE_CLASS,
SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS, EVENT_RELAY_CLUSTERS,
OUTPUT_CHANNEL_ONLY_CLUSTERS, OUTPUT_CHANNEL_ONLY_CLUSTERS,
REMOTE_DEVICE_TYPES, REMOTE_DEVICE_TYPES,
SENSOR_TYPES,
SINGLE_INPUT_CLUSTER_DEVICE_CLASS,
SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS,
) )
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -291,7 +292,7 @@ def _async_handle_single_cluster_match(
if component == SENSOR: if component == SENSOR:
discovery_info.update( discovery_info.update(
{SENSOR_TYPE: SENSOR_TYPES.get(cluster.cluster_id, GENERIC)} {SENSOR_TYPE: SENSOR_TYPES.get(cluster.cluster_id, SENSOR_GENERIC)}
) )
if component == BINARY_SENSOR: if component == BINARY_SENSOR:
discovery_info.update( discovery_info.update(

View File

@ -22,45 +22,45 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send
from ..api import async_get_device_info from ..api import async_get_device_info
from .const import ( from .const import (
ADD_DEVICE_RELAY_LOGGERS, DEBUG_RELAY_LOGGERS,
ATTR_MANUFACTURER, ATTR_MANUFACTURER,
BELLOWS, DEBUG_COMP_BELLOWS,
CONF_BAUDRATE, CONF_BAUDRATE,
CONF_DATABASE, CONF_DATABASE,
CONF_RADIO_TYPE, CONF_RADIO_TYPE,
CONF_USB_PATH, CONF_USB_PATH,
CONTROLLER, CONTROLLER,
CURRENT, DEBUG_LEVEL_CURRENT,
DATA_ZHA, DATA_ZHA,
DATA_ZHA_BRIDGE_ID, DATA_ZHA_BRIDGE_ID,
DATA_ZHA_GATEWAY, DATA_ZHA_GATEWAY,
DEBUG_LEVELS, DEBUG_LEVELS,
DEFAULT_BAUDRATE, DEFAULT_BAUDRATE,
DEFAULT_DATABASE_NAME, DEFAULT_DATABASE_NAME,
DEVICE_FULL_INIT, ZHA_GW_MSG_DEVICE_FULL_INIT,
DEVICE_INFO, ZHA_GW_MSG_DEVICE_INFO,
DEVICE_JOINED, ZHA_GW_MSG_DEVICE_JOINED,
DEVICE_REMOVED, ZHA_GW_MSG_DEVICE_REMOVED,
DOMAIN, DOMAIN,
IEEE, ATTR_IEEE,
LOG_ENTRY, ZHA_GW_MSG_LOG_ENTRY,
LOG_OUTPUT, ZHA_GW_MSG_LOG_OUTPUT,
MODEL, ATTR_MODEL,
NWK, ATTR_NWK,
ORIGINAL, DEBUG_LEVEL_ORIGINAL,
RADIO, ZHA_GW_RADIO,
RADIO_DESCRIPTION, ZHA_GW_RADIO_DESCRIPTION,
RAW_INIT, ZHA_GW_MSG_RAW_INIT,
SIGNAL_REMOVE, SIGNAL_REMOVE,
SIGNATURE, ATTR_SIGNATURE,
TYPE, ATTR_TYPE,
UNKNOWN_MANUFACTURER, UNKNOWN_MANUFACTURER,
UNKNOWN_MODEL, UNKNOWN_MODEL,
ZHA, DEBUG_COMP_ZHA,
ZHA_GW_MSG, ZHA_GW_MSG,
ZIGPY, DEBUG_COMP_ZIGPY,
ZIGPY_DECONZ, DEBUG_COMP_ZIGPY_DECONZ,
ZIGPY_XBEE, DEBUG_COMP_ZIGPY_XBEE,
) )
from .device import DeviceStatus, ZHADevice from .device import DeviceStatus, ZHADevice
from .discovery import async_dispatch_discovery_info, async_process_endpoint from .discovery import async_dispatch_discovery_info, async_process_endpoint
@ -91,8 +91,8 @@ class ZHAGateway:
self.radio_description = None self.radio_description = None
hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] = self hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] = self
self._log_levels = { self._log_levels = {
ORIGINAL: async_capture_log_levels(), DEBUG_LEVEL_ORIGINAL: async_capture_log_levels(),
CURRENT: async_capture_log_levels(), DEBUG_LEVEL_CURRENT: async_capture_log_levels(),
} }
self.debug_enabled = False self.debug_enabled = False
self._log_relay_handler = LogRelayHandler(hass, self) self._log_relay_handler = LogRelayHandler(hass, self)
@ -107,9 +107,9 @@ class ZHAGateway:
baudrate = self._config.get(CONF_BAUDRATE, DEFAULT_BAUDRATE) baudrate = self._config.get(CONF_BAUDRATE, DEFAULT_BAUDRATE)
radio_type = self._config_entry.data.get(CONF_RADIO_TYPE) radio_type = self._config_entry.data.get(CONF_RADIO_TYPE)
radio_details = RADIO_TYPES[radio_type][RADIO]() radio_details = RADIO_TYPES[radio_type][ZHA_GW_RADIO]()
radio = radio_details[RADIO] radio = radio_details[ZHA_GW_RADIO]
self.radio_description = RADIO_TYPES[radio_type][RADIO_DESCRIPTION] self.radio_description = RADIO_TYPES[radio_type][ZHA_GW_RADIO_DESCRIPTION]
await radio.connect(usb_path, baudrate) await radio.connect(usb_path, baudrate)
if CONF_DATABASE in self._config: if CONF_DATABASE in self._config:
@ -141,7 +141,11 @@ class ZHAGateway:
async_dispatcher_send( async_dispatcher_send(
self._hass, self._hass,
ZHA_GW_MSG, ZHA_GW_MSG,
{TYPE: DEVICE_JOINED, NWK: device.nwk, IEEE: str(device.ieee)}, {
ATTR_TYPE: ZHA_GW_MSG_DEVICE_JOINED,
ATTR_NWK: device.nwk,
ATTR_IEEE: str(device.ieee),
},
) )
def raw_device_initialized(self, device): def raw_device_initialized(self, device):
@ -154,12 +158,12 @@ class ZHAGateway:
self._hass, self._hass,
ZHA_GW_MSG, ZHA_GW_MSG,
{ {
TYPE: RAW_INIT, ATTR_TYPE: ZHA_GW_MSG_RAW_INIT,
NWK: device.nwk, ATTR_NWK: device.nwk,
IEEE: str(device.ieee), ATTR_IEEE: str(device.ieee),
MODEL: device.model if device.model else UNKNOWN_MODEL, ATTR_MODEL: device.model if device.model else UNKNOWN_MODEL,
ATTR_MANUFACTURER: manuf if manuf else UNKNOWN_MANUFACTURER, ATTR_MANUFACTURER: manuf if manuf else UNKNOWN_MANUFACTURER,
SIGNATURE: device.get_signature(), ATTR_SIGNATURE: device.get_signature(),
}, },
) )
@ -198,7 +202,10 @@ class ZHAGateway:
async_dispatcher_send( async_dispatcher_send(
self._hass, self._hass,
ZHA_GW_MSG, ZHA_GW_MSG,
{TYPE: DEVICE_REMOVED, DEVICE_INFO: device_info}, {
ATTR_TYPE: ZHA_GW_MSG_DEVICE_REMOVED,
ZHA_GW_MSG_DEVICE_INFO: device_info,
},
) )
def get_device(self, ieee): def get_device(self, ieee):
@ -254,11 +261,11 @@ class ZHAGateway:
@callback @callback
def async_enable_debug_mode(self): def async_enable_debug_mode(self):
"""Enable debug mode for ZHA.""" """Enable debug mode for ZHA."""
self._log_levels[ORIGINAL] = async_capture_log_levels() self._log_levels[DEBUG_LEVEL_ORIGINAL] = async_capture_log_levels()
async_set_logger_levels(DEBUG_LEVELS) async_set_logger_levels(DEBUG_LEVELS)
self._log_levels[CURRENT] = async_capture_log_levels() self._log_levels[DEBUG_LEVEL_CURRENT] = async_capture_log_levels()
for logger_name in ADD_DEVICE_RELAY_LOGGERS: for logger_name in DEBUG_RELAY_LOGGERS:
logging.getLogger(logger_name).addHandler(self._log_relay_handler) logging.getLogger(logger_name).addHandler(self._log_relay_handler)
self.debug_enabled = True self.debug_enabled = True
@ -266,9 +273,9 @@ class ZHAGateway:
@callback @callback
def async_disable_debug_mode(self): def async_disable_debug_mode(self):
"""Disable debug mode for ZHA.""" """Disable debug mode for ZHA."""
async_set_logger_levels(self._log_levels[ORIGINAL]) async_set_logger_levels(self._log_levels[DEBUG_LEVEL_ORIGINAL])
self._log_levels[CURRENT] = async_capture_log_levels() self._log_levels[DEBUG_LEVEL_CURRENT] = async_capture_log_levels()
for logger_name in ADD_DEVICE_RELAY_LOGGERS: for logger_name in DEBUG_RELAY_LOGGERS:
logging.getLogger(logger_name).removeHandler(self._log_relay_handler) logging.getLogger(logger_name).removeHandler(self._log_relay_handler)
self.debug_enabled = False self.debug_enabled = False
@ -377,7 +384,10 @@ class ZHAGateway:
async_dispatcher_send( async_dispatcher_send(
self._hass, self._hass,
ZHA_GW_MSG, ZHA_GW_MSG,
{TYPE: DEVICE_FULL_INIT, DEVICE_INFO: device_info}, {
ATTR_TYPE: ZHA_GW_MSG_DEVICE_FULL_INIT,
ZHA_GW_MSG_DEVICE_INFO: device_info,
},
) )
async def shutdown(self): async def shutdown(self):
@ -390,22 +400,26 @@ class ZHAGateway:
def async_capture_log_levels(): def async_capture_log_levels():
"""Capture current logger levels for ZHA.""" """Capture current logger levels for ZHA."""
return { return {
BELLOWS: logging.getLogger(BELLOWS).getEffectiveLevel(), DEBUG_COMP_BELLOWS: logging.getLogger(DEBUG_COMP_BELLOWS).getEffectiveLevel(),
ZHA: logging.getLogger(ZHA).getEffectiveLevel(), DEBUG_COMP_ZHA: logging.getLogger(DEBUG_COMP_ZHA).getEffectiveLevel(),
ZIGPY: logging.getLogger(ZIGPY).getEffectiveLevel(), DEBUG_COMP_ZIGPY: logging.getLogger(DEBUG_COMP_ZIGPY).getEffectiveLevel(),
ZIGPY_XBEE: logging.getLogger(ZIGPY_XBEE).getEffectiveLevel(), DEBUG_COMP_ZIGPY_XBEE: logging.getLogger(
ZIGPY_DECONZ: logging.getLogger(ZIGPY_DECONZ).getEffectiveLevel(), DEBUG_COMP_ZIGPY_XBEE
).getEffectiveLevel(),
DEBUG_COMP_ZIGPY_DECONZ: logging.getLogger(
DEBUG_COMP_ZIGPY_DECONZ
).getEffectiveLevel(),
} }
@callback @callback
def async_set_logger_levels(levels): def async_set_logger_levels(levels):
"""Set logger levels for ZHA.""" """Set logger levels for ZHA."""
logging.getLogger(BELLOWS).setLevel(levels[BELLOWS]) logging.getLogger(DEBUG_COMP_BELLOWS).setLevel(levels[DEBUG_COMP_BELLOWS])
logging.getLogger(ZHA).setLevel(levels[ZHA]) logging.getLogger(DEBUG_COMP_ZHA).setLevel(levels[DEBUG_COMP_ZHA])
logging.getLogger(ZIGPY).setLevel(levels[ZIGPY]) logging.getLogger(DEBUG_COMP_ZIGPY).setLevel(levels[DEBUG_COMP_ZIGPY])
logging.getLogger(ZIGPY_XBEE).setLevel(levels[ZIGPY_XBEE]) logging.getLogger(DEBUG_COMP_ZIGPY_XBEE).setLevel(levels[DEBUG_COMP_ZIGPY_XBEE])
logging.getLogger(ZIGPY_DECONZ).setLevel(levels[ZIGPY_DECONZ]) logging.getLogger(DEBUG_COMP_ZIGPY_DECONZ).setLevel(levels[DEBUG_COMP_ZIGPY_DECONZ])
class LogRelayHandler(logging.Handler): class LogRelayHandler(logging.Handler):
@ -426,5 +440,7 @@ class LogRelayHandler(logging.Handler):
entry = LogEntry(record, stack, _figure_out_source(record, stack, self.hass)) entry = LogEntry(record, stack, _figure_out_source(record, stack, self.hass))
async_dispatcher_send( async_dispatcher_send(
self.hass, ZHA_GW_MSG, {TYPE: LOG_OUTPUT, LOG_ENTRY: entry.to_dict()} self.hass,
ZHA_GW_MSG,
{ATTR_TYPE: ZHA_GW_MSG_LOG_OUTPUT, ZHA_GW_MSG_LOG_ENTRY: entry.to_dict()},
) )

View File

@ -6,17 +6,19 @@ https://home-assistant.io/components/zha/
""" """
import asyncio import asyncio
import collections import collections
import logging
from concurrent.futures import TimeoutError as Timeout from concurrent.futures import TimeoutError as Timeout
import logging
from homeassistant.core import callback from homeassistant.core import callback
from .const import ( from .const import (
DEFAULT_BAUDRATE, DEFAULT_BAUDRATE,
CLUSTER_TYPE_IN,
CLUSTER_TYPE_OUT,
REPORT_CONFIG_MAX_INT, REPORT_CONFIG_MAX_INT,
REPORT_CONFIG_MIN_INT, REPORT_CONFIG_MIN_INT,
REPORT_CONFIG_RPT_CHANGE, REPORT_CONFIG_RPT_CHANGE,
RadioType, RadioType,
IN,
OUT,
) )
from .registries import BINDABLE_CLUSTERS from .registries import BINDABLE_CLUSTERS
@ -206,14 +208,18 @@ async def get_matched_clusters(source_zha_device, target_zha_device):
clusters_to_bind = [] clusters_to_bind = []
for endpoint_id in source_clusters: for endpoint_id in source_clusters:
for cluster_id in source_clusters[endpoint_id][OUT]: for cluster_id in source_clusters[endpoint_id][CLUSTER_TYPE_OUT]:
if cluster_id not in BINDABLE_CLUSTERS: if cluster_id not in BINDABLE_CLUSTERS:
continue continue
for t_endpoint_id in target_clusters: for t_endpoint_id in target_clusters:
if cluster_id in target_clusters[t_endpoint_id][IN]: if cluster_id in target_clusters[t_endpoint_id][CLUSTER_TYPE_IN]:
cluster_pair = ClusterPair( cluster_pair = ClusterPair(
source_cluster=source_clusters[endpoint_id][OUT][cluster_id], source_cluster=source_clusters[endpoint_id][CLUSTER_TYPE_OUT][
target_cluster=target_clusters[t_endpoint_id][IN][cluster_id], cluster_id
],
target_cluster=target_clusters[t_endpoint_id][CLUSTER_TYPE_IN][
cluster_id
],
) )
clusters_to_bind.append(cluster_pair) clusters_to_bind.append(cluster_pair)
return clusters_to_bind return clusters_to_bind
@ -228,9 +234,9 @@ def async_is_bindable_target(source_zha_device, target_zha_device):
bindables = set(BINDABLE_CLUSTERS) bindables = set(BINDABLE_CLUSTERS)
for endpoint_id in source_clusters: for endpoint_id in source_clusters:
for t_endpoint_id in target_clusters: for t_endpoint_id in target_clusters:
matches = set(source_clusters[endpoint_id][OUT].keys()).intersection( matches = set(
target_clusters[t_endpoint_id][IN].keys() source_clusters[endpoint_id][CLUSTER_TYPE_OUT].keys()
) ).intersection(target_clusters[t_endpoint_id][CLUSTER_TYPE_IN].keys())
if any(bindable in bindables for bindable in matches): if any(bindable in bindables for bindable in matches):
return True return True
return False return False

View File

@ -14,56 +14,56 @@ from homeassistant.components.sensor import DOMAIN as SENSOR
from homeassistant.components.switch import DOMAIN as SWITCH from homeassistant.components.switch import DOMAIN as SWITCH
from .const import ( from .const import (
HUMIDITY, SENSOR_ACCELERATION,
TEMPERATURE, SENSOR_BATTERY,
ILLUMINANCE, CONTROLLER,
PRESSURE, SENSOR_ELECTRICAL_MEASUREMENT,
METERING, SENSOR_HUMIDITY,
ELECTRICAL_MEASUREMENT, SENSOR_ILLUMINANCE,
OCCUPANCY, SENSOR_METERING,
REPORT_CONFIG_IMMEDIATE, SENSOR_OCCUPANCY,
OPENING, SENSOR_OPENING,
ZONE, SENSOR_PRESSURE,
RADIO_DESCRIPTION, ZHA_GW_RADIO,
ZHA_GW_RADIO_DESCRIPTION,
REPORT_CONFIG_ASAP, REPORT_CONFIG_ASAP,
REPORT_CONFIG_DEFAULT, REPORT_CONFIG_DEFAULT,
REPORT_CONFIG_MIN_INT, REPORT_CONFIG_IMMEDIATE,
REPORT_CONFIG_MAX_INT, REPORT_CONFIG_MAX_INT,
REPORT_CONFIG_MIN_INT,
REPORT_CONFIG_OP, REPORT_CONFIG_OP,
ACCELERATION, SENSOR_TEMPERATURE,
ZONE,
RadioType, RadioType,
RADIO,
CONTROLLER,
BATTERY,
) )
SMARTTHINGS_HUMIDITY_CLUSTER = 0xFC45 BINARY_SENSOR_CLUSTERS = set()
SMARTTHINGS_ACCELERATION_CLUSTER = 0xFC02
SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE = 0x8000
DEVICE_CLASS = {}
SINGLE_INPUT_CLUSTER_DEVICE_CLASS = {}
SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS = {}
SENSOR_TYPES = {}
RADIO_TYPES = {}
BINARY_SENSOR_TYPES = {} BINARY_SENSOR_TYPES = {}
REMOTE_DEVICE_TYPES = {} BINDABLE_CLUSTERS = []
CHANNEL_ONLY_CLUSTERS = []
CLUSTER_REPORT_CONFIGS = {} CLUSTER_REPORT_CONFIGS = {}
CUSTOM_CLUSTER_MAPPINGS = {} CUSTOM_CLUSTER_MAPPINGS = {}
EVENT_RELAY_CLUSTERS = [] DEVICE_CLASS = {}
CHANNEL_ONLY_CLUSTERS = []
OUTPUT_CHANNEL_ONLY_CLUSTERS = []
BINDABLE_CLUSTERS = []
INPUT_BIND_ONLY_CLUSTERS = []
BINARY_SENSOR_CLUSTERS = set()
DEVICE_TRACKER_CLUSTERS = set() DEVICE_TRACKER_CLUSTERS = set()
EVENT_RELAY_CLUSTERS = []
INPUT_BIND_ONLY_CLUSTERS = []
LIGHT_CLUSTERS = set() LIGHT_CLUSTERS = set()
OUTPUT_CHANNEL_ONLY_CLUSTERS = []
RADIO_TYPES = {}
REMOTE_DEVICE_TYPES = {}
SENSOR_TYPES = {}
SINGLE_INPUT_CLUSTER_DEVICE_CLASS = {}
SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS = {}
SWITCH_CLUSTERS = set() SWITCH_CLUSTERS = set()
SMARTTHINGS_ACCELERATION_CLUSTER = 0xFC02
SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE = 0x8000
SMARTTHINGS_HUMIDITY_CLUSTER = 0xFC45
COMPONENT_CLUSTERS = { COMPONENT_CLUSTERS = {
BINARY_SENSOR: BINARY_SENSOR_CLUSTERS, BINARY_SENSOR: BINARY_SENSOR_CLUSTERS,
DEVICE_TRACKER: DEVICE_TRACKER_CLUSTERS,
LIGHT: LIGHT_CLUSTERS, LIGHT: LIGHT_CLUSTERS,
SWITCH: SWITCH_CLUSTERS, SWITCH: SWITCH_CLUSTERS,
DEVICE_TRACKER: DEVICE_TRACKER_CLUSTERS,
} }
@ -90,144 +90,58 @@ def establish_device_mappings():
import bellows.ezsp import bellows.ezsp
from bellows.zigbee.application import ControllerApplication from bellows.zigbee.application import ControllerApplication
return {RADIO: bellows.ezsp.EZSP(), CONTROLLER: ControllerApplication} return {ZHA_GW_RADIO: bellows.ezsp.EZSP(), CONTROLLER: ControllerApplication}
RADIO_TYPES[RadioType.ezsp.name] = { RADIO_TYPES[RadioType.ezsp.name] = {
RADIO: get_ezsp_radio, ZHA_GW_RADIO: get_ezsp_radio,
RADIO_DESCRIPTION: "EZSP", ZHA_GW_RADIO_DESCRIPTION: "EZSP",
} }
def get_xbee_radio(): def get_xbee_radio():
import zigpy_xbee.api import zigpy_xbee.api
from zigpy_xbee.zigbee.application import ControllerApplication from zigpy_xbee.zigbee.application import ControllerApplication
return {RADIO: zigpy_xbee.api.XBee(), CONTROLLER: ControllerApplication} return {ZHA_GW_RADIO: zigpy_xbee.api.XBee(), CONTROLLER: ControllerApplication}
RADIO_TYPES[RadioType.xbee.name] = { RADIO_TYPES[RadioType.xbee.name] = {
RADIO: get_xbee_radio, ZHA_GW_RADIO: get_xbee_radio,
RADIO_DESCRIPTION: "XBee", ZHA_GW_RADIO_DESCRIPTION: "XBee",
} }
def get_deconz_radio(): def get_deconz_radio():
import zigpy_deconz.api import zigpy_deconz.api
from zigpy_deconz.zigbee.application import ControllerApplication from zigpy_deconz.zigbee.application import ControllerApplication
return {RADIO: zigpy_deconz.api.Deconz(), CONTROLLER: ControllerApplication} return {
ZHA_GW_RADIO: zigpy_deconz.api.Deconz(),
CONTROLLER: ControllerApplication,
}
RADIO_TYPES[RadioType.deconz.name] = { RADIO_TYPES[RadioType.deconz.name] = {
RADIO: get_deconz_radio, ZHA_GW_RADIO: get_deconz_radio,
RADIO_DESCRIPTION: "Deconz", ZHA_GW_RADIO_DESCRIPTION: "Deconz",
} }
EVENT_RELAY_CLUSTERS.append(zcl.clusters.general.LevelControl.cluster_id) BINARY_SENSOR_CLUSTERS.add(SMARTTHINGS_ACCELERATION_CLUSTER)
EVENT_RELAY_CLUSTERS.append(zcl.clusters.general.OnOff.cluster_id) BINARY_SENSOR_CLUSTERS.add(zcl.clusters.general.OnOff.cluster_id)
BINARY_SENSOR_CLUSTERS.add(zcl.clusters.measurement.OccupancySensing.cluster_id)
BINARY_SENSOR_CLUSTERS.add(zcl.clusters.security.IasZone.cluster_id)
CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.general.Basic.cluster_id) BINARY_SENSOR_TYPES.update(
CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.lightlink.LightLink.cluster_id) {
SMARTTHINGS_ACCELERATION_CLUSTER: SENSOR_ACCELERATION,
OUTPUT_CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.general.Scenes.cluster_id) zcl.clusters.general.OnOff.cluster_id: SENSOR_OPENING,
zcl.clusters.measurement.OccupancySensing.cluster_id: SENSOR_OCCUPANCY,
zcl.clusters.security.IasZone.cluster_id: ZONE,
}
)
BINDABLE_CLUSTERS.append(zcl.clusters.general.LevelControl.cluster_id) BINDABLE_CLUSTERS.append(zcl.clusters.general.LevelControl.cluster_id)
BINDABLE_CLUSTERS.append(zcl.clusters.general.OnOff.cluster_id) BINDABLE_CLUSTERS.append(zcl.clusters.general.OnOff.cluster_id)
BINDABLE_CLUSTERS.append(zcl.clusters.lighting.Color.cluster_id) BINDABLE_CLUSTERS.append(zcl.clusters.lighting.Color.cluster_id)
INPUT_BIND_ONLY_CLUSTERS.append(zcl.clusters.lightlink.LightLink.cluster_id) CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.general.Basic.cluster_id)
CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.lightlink.LightLink.cluster_id)
DEVICE_CLASS[zha.PROFILE_ID].update(
{
zha.DeviceType.SMART_PLUG: SWITCH,
zha.DeviceType.LEVEL_CONTROLLABLE_OUTPUT: LIGHT,
zha.DeviceType.ON_OFF_LIGHT: LIGHT,
zha.DeviceType.DIMMABLE_LIGHT: LIGHT,
zha.DeviceType.COLOR_DIMMABLE_LIGHT: LIGHT,
zha.DeviceType.ON_OFF_LIGHT_SWITCH: SWITCH,
zha.DeviceType.ON_OFF_BALLAST: SWITCH,
zha.DeviceType.DIMMABLE_BALLAST: LIGHT,
zha.DeviceType.ON_OFF_PLUG_IN_UNIT: SWITCH,
zha.DeviceType.DIMMABLE_PLUG_IN_UNIT: LIGHT,
zha.DeviceType.COLOR_TEMPERATURE_LIGHT: LIGHT,
zha.DeviceType.EXTENDED_COLOR_LIGHT: LIGHT,
SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE: DEVICE_TRACKER,
}
)
DEVICE_CLASS[zll.PROFILE_ID].update(
{
zll.DeviceType.ON_OFF_LIGHT: LIGHT,
zll.DeviceType.ON_OFF_PLUGIN_UNIT: SWITCH,
zll.DeviceType.DIMMABLE_LIGHT: LIGHT,
zll.DeviceType.DIMMABLE_PLUGIN_UNIT: LIGHT,
zll.DeviceType.COLOR_LIGHT: LIGHT,
zll.DeviceType.EXTENDED_COLOR_LIGHT: LIGHT,
zll.DeviceType.COLOR_TEMPERATURE_LIGHT: LIGHT,
}
)
SINGLE_INPUT_CLUSTER_DEVICE_CLASS.update(
{
zcl.clusters.general.OnOff: SWITCH,
zcl.clusters.measurement.RelativeHumidity: SENSOR,
# this works for now but if we hit conflicts we can break it out to
# a different dict that is keyed by manufacturer
SMARTTHINGS_HUMIDITY_CLUSTER: SENSOR,
zcl.clusters.measurement.TemperatureMeasurement: SENSOR,
zcl.clusters.measurement.PressureMeasurement: SENSOR,
zcl.clusters.measurement.IlluminanceMeasurement: SENSOR,
zcl.clusters.smartenergy.Metering: SENSOR,
zcl.clusters.homeautomation.ElectricalMeasurement: SENSOR,
zcl.clusters.security.IasZone: BINARY_SENSOR,
zcl.clusters.measurement.OccupancySensing: BINARY_SENSOR,
zcl.clusters.hvac.Fan: FAN,
SMARTTHINGS_ACCELERATION_CLUSTER: BINARY_SENSOR,
zcl.clusters.general.MultistateInput.cluster_id: SENSOR,
zcl.clusters.general.AnalogInput.cluster_id: SENSOR,
zcl.clusters.closures.DoorLock: LOCK,
zcl.clusters.general.PowerConfiguration: SENSOR,
}
)
SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS.update(
{zcl.clusters.general.OnOff: BINARY_SENSOR}
)
SENSOR_TYPES.update(
{
zcl.clusters.measurement.RelativeHumidity.cluster_id: HUMIDITY,
SMARTTHINGS_HUMIDITY_CLUSTER: HUMIDITY,
zcl.clusters.measurement.TemperatureMeasurement.cluster_id: TEMPERATURE,
zcl.clusters.measurement.PressureMeasurement.cluster_id: PRESSURE,
zcl.clusters.measurement.IlluminanceMeasurement.cluster_id: ILLUMINANCE,
zcl.clusters.smartenergy.Metering.cluster_id: METERING,
zcl.clusters.homeautomation.ElectricalMeasurement.cluster_id: ELECTRICAL_MEASUREMENT,
zcl.clusters.general.PowerConfiguration.cluster_id: BATTERY,
}
)
BINARY_SENSOR_TYPES.update(
{
zcl.clusters.measurement.OccupancySensing.cluster_id: OCCUPANCY,
zcl.clusters.security.IasZone.cluster_id: ZONE,
zcl.clusters.general.OnOff.cluster_id: OPENING,
SMARTTHINGS_ACCELERATION_CLUSTER: ACCELERATION,
}
)
zhap = zha.PROFILE_ID
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.NON_COLOR_SCENE_CONTROLLER)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.NON_COLOR_CONTROLLER)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.COLOR_SCENE_CONTROLLER)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.COLOR_CONTROLLER)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.REMOTE_CONTROL)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.SCENE_SELECTOR)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.DIMMER_SWITCH)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.COLOR_DIMMER_SWITCH)
zllp = zll.PROFILE_ID
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.COLOR_CONTROLLER)
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.COLOR_SCENE_CONTROLLER)
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.CONTROLLER)
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.SCENE_CONTROLLER)
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.CONTROL_BRIDGE)
CLUSTER_REPORT_CONFIGS.update( CLUSTER_REPORT_CONFIGS.update(
{ {
@ -311,15 +225,104 @@ def establish_device_mappings():
} }
) )
BINARY_SENSOR_CLUSTERS.add(zcl.clusters.general.OnOff.cluster_id) DEVICE_CLASS[zha.PROFILE_ID].update(
BINARY_SENSOR_CLUSTERS.add(zcl.clusters.security.IasZone.cluster_id) {
BINARY_SENSOR_CLUSTERS.add(zcl.clusters.measurement.OccupancySensing.cluster_id) SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE: DEVICE_TRACKER,
BINARY_SENSOR_CLUSTERS.add(SMARTTHINGS_ACCELERATION_CLUSTER) zha.DeviceType.COLOR_DIMMABLE_LIGHT: LIGHT,
zha.DeviceType.COLOR_TEMPERATURE_LIGHT: LIGHT,
zha.DeviceType.DIMMABLE_BALLAST: LIGHT,
zha.DeviceType.DIMMABLE_LIGHT: LIGHT,
zha.DeviceType.DIMMABLE_PLUG_IN_UNIT: LIGHT,
zha.DeviceType.EXTENDED_COLOR_LIGHT: LIGHT,
zha.DeviceType.LEVEL_CONTROLLABLE_OUTPUT: LIGHT,
zha.DeviceType.ON_OFF_BALLAST: SWITCH,
zha.DeviceType.ON_OFF_LIGHT: LIGHT,
zha.DeviceType.ON_OFF_LIGHT_SWITCH: SWITCH,
zha.DeviceType.ON_OFF_PLUG_IN_UNIT: SWITCH,
zha.DeviceType.SMART_PLUG: SWITCH,
}
)
DEVICE_CLASS[zll.PROFILE_ID].update(
{
zll.DeviceType.COLOR_LIGHT: LIGHT,
zll.DeviceType.COLOR_TEMPERATURE_LIGHT: LIGHT,
zll.DeviceType.DIMMABLE_LIGHT: LIGHT,
zll.DeviceType.DIMMABLE_PLUGIN_UNIT: LIGHT,
zll.DeviceType.EXTENDED_COLOR_LIGHT: LIGHT,
zll.DeviceType.ON_OFF_LIGHT: LIGHT,
zll.DeviceType.ON_OFF_PLUGIN_UNIT: SWITCH,
}
)
DEVICE_TRACKER_CLUSTERS.add(zcl.clusters.general.PowerConfiguration.cluster_id) DEVICE_TRACKER_CLUSTERS.add(zcl.clusters.general.PowerConfiguration.cluster_id)
LIGHT_CLUSTERS.add(zcl.clusters.general.OnOff.cluster_id) EVENT_RELAY_CLUSTERS.append(zcl.clusters.general.LevelControl.cluster_id)
EVENT_RELAY_CLUSTERS.append(zcl.clusters.general.OnOff.cluster_id)
INPUT_BIND_ONLY_CLUSTERS.append(zcl.clusters.lightlink.LightLink.cluster_id)
OUTPUT_CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.general.Scenes.cluster_id)
LIGHT_CLUSTERS.add(zcl.clusters.general.LevelControl.cluster_id) LIGHT_CLUSTERS.add(zcl.clusters.general.LevelControl.cluster_id)
LIGHT_CLUSTERS.add(zcl.clusters.general.OnOff.cluster_id)
LIGHT_CLUSTERS.add(zcl.clusters.lighting.Color.cluster_id) LIGHT_CLUSTERS.add(zcl.clusters.lighting.Color.cluster_id)
SINGLE_INPUT_CLUSTER_DEVICE_CLASS.update(
{
# this works for now but if we hit conflicts we can break it out to
# a different dict that is keyed by manufacturer
SMARTTHINGS_ACCELERATION_CLUSTER: BINARY_SENSOR,
SMARTTHINGS_HUMIDITY_CLUSTER: SENSOR,
zcl.clusters.closures.DoorLock: LOCK,
zcl.clusters.general.AnalogInput.cluster_id: SENSOR,
zcl.clusters.general.MultistateInput.cluster_id: SENSOR,
zcl.clusters.general.OnOff: SWITCH,
zcl.clusters.general.PowerConfiguration: SENSOR,
zcl.clusters.homeautomation.ElectricalMeasurement: SENSOR,
zcl.clusters.hvac.Fan: FAN,
zcl.clusters.measurement.IlluminanceMeasurement: SENSOR,
zcl.clusters.measurement.OccupancySensing: BINARY_SENSOR,
zcl.clusters.measurement.PressureMeasurement: SENSOR,
zcl.clusters.measurement.RelativeHumidity: SENSOR,
zcl.clusters.measurement.TemperatureMeasurement: SENSOR,
zcl.clusters.security.IasZone: BINARY_SENSOR,
zcl.clusters.smartenergy.Metering: SENSOR,
}
)
SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS.update(
{zcl.clusters.general.OnOff: BINARY_SENSOR}
)
SENSOR_TYPES.update(
{
SMARTTHINGS_HUMIDITY_CLUSTER: SENSOR_HUMIDITY,
zcl.clusters.general.PowerConfiguration.cluster_id: SENSOR_BATTERY,
zcl.clusters.homeautomation.ElectricalMeasurement.cluster_id: SENSOR_ELECTRICAL_MEASUREMENT,
zcl.clusters.measurement.IlluminanceMeasurement.cluster_id: SENSOR_ILLUMINANCE,
zcl.clusters.measurement.PressureMeasurement.cluster_id: SENSOR_PRESSURE,
zcl.clusters.measurement.RelativeHumidity.cluster_id: SENSOR_HUMIDITY,
zcl.clusters.measurement.TemperatureMeasurement.cluster_id: SENSOR_TEMPERATURE,
zcl.clusters.smartenergy.Metering.cluster_id: SENSOR_METERING,
}
)
SWITCH_CLUSTERS.add(zcl.clusters.general.OnOff.cluster_id) SWITCH_CLUSTERS.add(zcl.clusters.general.OnOff.cluster_id)
zhap = zha.PROFILE_ID
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.COLOR_CONTROLLER)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.COLOR_DIMMER_SWITCH)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.COLOR_SCENE_CONTROLLER)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.DIMMER_SWITCH)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.NON_COLOR_CONTROLLER)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.NON_COLOR_SCENE_CONTROLLER)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.REMOTE_CONTROL)
REMOTE_DEVICE_TYPES[zhap].append(zha.DeviceType.SCENE_SELECTOR)
zllp = zll.PROFILE_ID
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.COLOR_CONTROLLER)
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.COLOR_SCENE_CONTROLLER)
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.CONTROL_BRIDGE)
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.CONTROLLER)
REMOTE_DEVICE_TYPES[zllp].append(zll.DeviceType.SCENE_CONTROLLER)

View File

@ -1,16 +1,15 @@
"""Data storage helper for ZHA.""" """Data storage helper for ZHA."""
import logging
from collections import OrderedDict
# pylint: disable=W0611 # pylint: disable=W0611
from collections import OrderedDict
import logging
from typing import MutableMapping # noqa: F401 from typing import MutableMapping # noqa: F401
from typing import cast from typing import cast
import attr import attr
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.loader import bind_hass
from homeassistant.helpers.typing import HomeAssistantType from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.loader import bind_hass
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -1,16 +1,18 @@
"""Support for the ZHA platform.""" """Support for the ZHA platform."""
import logging import logging
import time import time
from homeassistant.components.device_tracker import SOURCE_TYPE_ROUTER, DOMAIN
from homeassistant.components.device_tracker import DOMAIN, SOURCE_TYPE_ROUTER
from homeassistant.components.device_tracker.config_entry import ScannerEntity from homeassistant.components.device_tracker.config_entry import ScannerEntity
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .core.const import ( from .core.const import (
DATA_ZHA, DATA_ZHA,
DATA_ZHA_DISPATCHERS, DATA_ZHA_DISPATCHERS,
ZHA_DISCOVERY_NEW, CHANNEL_POWER_CONFIGURATION,
POWER_CONFIGURATION_CHANNEL,
SIGNAL_ATTR_UPDATED, SIGNAL_ATTR_UPDATED,
ZHA_DISCOVERY_NEW,
) )
from .entity import ZhaEntity from .entity import ZhaEntity
from .sensor import battery_percentage_remaining_formatter from .sensor import battery_percentage_remaining_formatter
@ -56,7 +58,7 @@ class ZHADeviceScannerEntity(ScannerEntity, ZhaEntity):
def __init__(self, **kwargs): def __init__(self, **kwargs):
"""Initialize the ZHA device tracker.""" """Initialize the ZHA device tracker."""
super().__init__(**kwargs) super().__init__(**kwargs)
self._battery_channel = self.cluster_channels.get(POWER_CONFIGURATION_CHANNEL) self._battery_channel = self.cluster_channels.get(CHANNEL_POWER_CONFIGURATION)
self._connected = False self._connected = False
self._keepalive_interval = 60 self._keepalive_interval = 60
self._should_poll = True self._should_poll = True

View File

@ -16,8 +16,8 @@ from .core.const import (
DATA_ZHA, DATA_ZHA,
DATA_ZHA_BRIDGE_ID, DATA_ZHA_BRIDGE_ID,
DOMAIN, DOMAIN,
MODEL, ATTR_MODEL,
NAME, ATTR_NAME,
SIGNAL_REMOVE, SIGNAL_REMOVE,
) )
from .core.helpers import LogMixin from .core.helpers import LogMixin
@ -99,8 +99,8 @@ class ZhaEntity(RestoreEntity, LogMixin, entity.Entity):
"connections": {(CONNECTION_ZIGBEE, ieee)}, "connections": {(CONNECTION_ZIGBEE, ieee)},
"identifiers": {(DOMAIN, ieee)}, "identifiers": {(DOMAIN, ieee)},
ATTR_MANUFACTURER: zha_device_info[ATTR_MANUFACTURER], ATTR_MANUFACTURER: zha_device_info[ATTR_MANUFACTURER],
MODEL: zha_device_info[MODEL], ATTR_MODEL: zha_device_info[ATTR_MODEL],
NAME: zha_device_info[NAME], ATTR_NAME: zha_device_info[ATTR_NAME],
"via_device": (DOMAIN, self.hass.data[DATA_ZHA][DATA_ZHA_BRIDGE_ID]), "via_device": (DOMAIN, self.hass.data[DATA_ZHA][DATA_ZHA_BRIDGE_ID]),
} }

View File

@ -1,7 +1,6 @@
"""Fans on Zigbee Home Automation networks.""" """Fans on Zigbee Home Automation networks."""
import logging import logging
from homeassistant.core import callback
from homeassistant.components.fan import ( from homeassistant.components.fan import (
DOMAIN, DOMAIN,
SPEED_HIGH, SPEED_HIGH,
@ -11,13 +10,15 @@ from homeassistant.components.fan import (
SUPPORT_SET_SPEED, SUPPORT_SET_SPEED,
FanEntity, FanEntity,
) )
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .core.const import ( from .core.const import (
DATA_ZHA, DATA_ZHA,
DATA_ZHA_DISPATCHERS, DATA_ZHA_DISPATCHERS,
ZHA_DISCOVERY_NEW, CHANNEL_FAN,
FAN_CHANNEL,
SIGNAL_ATTR_UPDATED, SIGNAL_ATTR_UPDATED,
ZHA_DISCOVERY_NEW,
) )
from .entity import ZhaEntity from .entity import ZhaEntity
@ -91,7 +92,7 @@ class ZhaFan(ZhaEntity, FanEntity):
def __init__(self, unique_id, zha_device, channels, **kwargs): def __init__(self, unique_id, zha_device, channels, **kwargs):
"""Init this sensor.""" """Init this sensor."""
super().__init__(unique_id, zha_device, channels, **kwargs) super().__init__(unique_id, zha_device, channels, **kwargs)
self._fan_channel = self.cluster_channels.get(FAN_CHANNEL) self._fan_channel = self.cluster_channels.get(CHANNEL_FAN)
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Run when about to be added to hass.""" """Run when about to be added to hass."""

View File

@ -3,21 +3,23 @@ from datetime import timedelta
import logging import logging
from zigpy.zcl.foundation import Status from zigpy.zcl.foundation import Status
from homeassistant.components import light from homeassistant.components import light
from homeassistant.const import STATE_ON from homeassistant.const import STATE_ON
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.event import async_track_time_interval
import homeassistant.util.color as color_util import homeassistant.util.color as color_util
from .core.const import ( from .core.const import (
CHANNEL_COLOR,
DATA_ZHA, DATA_ZHA,
DATA_ZHA_DISPATCHERS, DATA_ZHA_DISPATCHERS,
ZHA_DISCOVERY_NEW, CHANNEL_LEVEL,
COLOR_CHANNEL, CHANNEL_ON_OFF,
ON_OFF_CHANNEL,
LEVEL_CHANNEL,
SIGNAL_ATTR_UPDATED, SIGNAL_ATTR_UPDATED,
SIGNAL_SET_LEVEL, SIGNAL_SET_LEVEL,
ZHA_DISCOVERY_NEW,
) )
from .entity import ZhaEntity from .entity import ZhaEntity
@ -83,9 +85,9 @@ class Light(ZhaEntity, light.Light):
self._color_temp = None self._color_temp = None
self._hs_color = None self._hs_color = None
self._brightness = None self._brightness = None
self._on_off_channel = self.cluster_channels.get(ON_OFF_CHANNEL) self._on_off_channel = self.cluster_channels.get(CHANNEL_ON_OFF)
self._level_channel = self.cluster_channels.get(LEVEL_CHANNEL) self._level_channel = self.cluster_channels.get(CHANNEL_LEVEL)
self._color_channel = self.cluster_channels.get(COLOR_CHANNEL) self._color_channel = self.cluster_channels.get(CHANNEL_COLOR)
if self._level_channel: if self._level_channel:
self._supported_features |= light.SUPPORT_BRIGHTNESS self._supported_features |= light.SUPPORT_BRIGHTNESS

View File

@ -2,20 +2,22 @@
import logging import logging
from zigpy.zcl.foundation import Status from zigpy.zcl.foundation import Status
from homeassistant.core import callback
from homeassistant.components.lock import ( from homeassistant.components.lock import (
DOMAIN, DOMAIN,
STATE_UNLOCKED,
STATE_LOCKED, STATE_LOCKED,
STATE_UNLOCKED,
LockDevice, LockDevice,
) )
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .core.const import ( from .core.const import (
DATA_ZHA, DATA_ZHA,
DATA_ZHA_DISPATCHERS, DATA_ZHA_DISPATCHERS,
ZHA_DISCOVERY_NEW, CHANNEL_DOORLOCK,
DOORLOCK_CHANNEL,
SIGNAL_ATTR_UPDATED, SIGNAL_ATTR_UPDATED,
ZHA_DISCOVERY_NEW,
) )
from .entity import ZhaEntity from .entity import ZhaEntity
@ -73,7 +75,7 @@ class ZhaDoorLock(ZhaEntity, LockDevice):
def __init__(self, unique_id, zha_device, channels, **kwargs): def __init__(self, unique_id, zha_device, channels, **kwargs):
"""Init this sensor.""" """Init this sensor."""
super().__init__(unique_id, zha_device, channels, **kwargs) super().__init__(unique_id, zha_device, channels, **kwargs)
self._doorlock_channel = self.cluster_channels.get(DOORLOCK_CHANNEL) self._doorlock_channel = self.cluster_channels.get(CHANNEL_DOORLOCK)
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Run when about to be added to hass.""" """Run when about to be added to hass."""

View File

@ -2,37 +2,38 @@
import logging import logging
import numbers import numbers
from homeassistant.core import callback
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
DOMAIN, DEVICE_CLASS_BATTERY,
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_ILLUMINANCE,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_POWER, DEVICE_CLASS_POWER,
DEVICE_CLASS_BATTERY, DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_TEMPERATURE,
DOMAIN,
) )
from homeassistant.const import TEMP_CELSIUS, POWER_WATT, ATTR_UNIT_OF_MEASUREMENT from homeassistant.const import ATTR_UNIT_OF_MEASUREMENT, POWER_WATT, TEMP_CELSIUS
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .core.const import ( from .core.const import (
CHANNEL_ATTRIBUTE,
SENSOR_BATTERY,
DATA_ZHA, DATA_ZHA,
DATA_ZHA_DISPATCHERS, DATA_ZHA_DISPATCHERS,
ZHA_DISCOVERY_NEW, SENSOR_ELECTRICAL_MEASUREMENT,
HUMIDITY, CHANNEL_ELECTRICAL_MEASUREMENT,
TEMPERATURE, SENSOR_GENERIC,
ILLUMINANCE, SENSOR_HUMIDITY,
PRESSURE, SENSOR_ILLUMINANCE,
METERING, SENSOR_METERING,
ELECTRICAL_MEASUREMENT, CHANNEL_POWER_CONFIGURATION,
GENERIC, SENSOR_PRESSURE,
SENSOR_TYPE, SENSOR_TYPE,
ATTRIBUTE_CHANNEL,
ELECTRICAL_MEASUREMENT_CHANNEL,
SIGNAL_ATTR_UPDATED, SIGNAL_ATTR_UPDATED,
SIGNAL_STATE_ATTR, SIGNAL_STATE_ATTR,
SENSOR_TEMPERATURE,
UNKNOWN, UNKNOWN,
BATTERY, ZHA_DISCOVERY_NEW,
POWER_CONFIGURATION_CHANNEL,
) )
from .entity import ZhaEntity from .entity import ZhaEntity
@ -121,49 +122,49 @@ async def async_battery_device_state_attr_provider(channel):
FORMATTER_FUNC_REGISTRY = { FORMATTER_FUNC_REGISTRY = {
HUMIDITY: humidity_formatter, SENSOR_HUMIDITY: humidity_formatter,
TEMPERATURE: temperature_formatter, SENSOR_TEMPERATURE: temperature_formatter,
PRESSURE: pressure_formatter, SENSOR_PRESSURE: pressure_formatter,
ELECTRICAL_MEASUREMENT: active_power_formatter, SENSOR_ELECTRICAL_MEASUREMENT: active_power_formatter,
ILLUMINANCE: illuminance_formatter, SENSOR_ILLUMINANCE: illuminance_formatter,
GENERIC: pass_through_formatter, SENSOR_GENERIC: pass_through_formatter,
BATTERY: battery_percentage_remaining_formatter, SENSOR_BATTERY: battery_percentage_remaining_formatter,
} }
UNIT_REGISTRY = { UNIT_REGISTRY = {
HUMIDITY: "%", SENSOR_HUMIDITY: "%",
TEMPERATURE: TEMP_CELSIUS, SENSOR_TEMPERATURE: TEMP_CELSIUS,
PRESSURE: "hPa", SENSOR_PRESSURE: "hPa",
ILLUMINANCE: "lx", SENSOR_ILLUMINANCE: "lx",
METERING: POWER_WATT, SENSOR_METERING: POWER_WATT,
ELECTRICAL_MEASUREMENT: POWER_WATT, SENSOR_ELECTRICAL_MEASUREMENT: POWER_WATT,
GENERIC: None, SENSOR_GENERIC: None,
BATTERY: "%", SENSOR_BATTERY: "%",
} }
CHANNEL_REGISTRY = { CHANNEL_REGISTRY = {
ELECTRICAL_MEASUREMENT: ELECTRICAL_MEASUREMENT_CHANNEL, SENSOR_ELECTRICAL_MEASUREMENT: CHANNEL_ELECTRICAL_MEASUREMENT,
BATTERY: POWER_CONFIGURATION_CHANNEL, SENSOR_BATTERY: CHANNEL_POWER_CONFIGURATION,
} }
POLLING_REGISTRY = {ELECTRICAL_MEASUREMENT: True} POLLING_REGISTRY = {SENSOR_ELECTRICAL_MEASUREMENT: True}
FORCE_UPDATE_REGISTRY = {ELECTRICAL_MEASUREMENT: False} FORCE_UPDATE_REGISTRY = {SENSOR_ELECTRICAL_MEASUREMENT: False}
DEVICE_CLASS_REGISTRY = { DEVICE_CLASS_REGISTRY = {
UNKNOWN: None, UNKNOWN: None,
HUMIDITY: DEVICE_CLASS_HUMIDITY, SENSOR_HUMIDITY: DEVICE_CLASS_HUMIDITY,
TEMPERATURE: DEVICE_CLASS_TEMPERATURE, SENSOR_TEMPERATURE: DEVICE_CLASS_TEMPERATURE,
PRESSURE: DEVICE_CLASS_PRESSURE, SENSOR_PRESSURE: DEVICE_CLASS_PRESSURE,
ILLUMINANCE: DEVICE_CLASS_ILLUMINANCE, SENSOR_ILLUMINANCE: DEVICE_CLASS_ILLUMINANCE,
METERING: DEVICE_CLASS_POWER, SENSOR_METERING: DEVICE_CLASS_POWER,
ELECTRICAL_MEASUREMENT: DEVICE_CLASS_POWER, SENSOR_ELECTRICAL_MEASUREMENT: DEVICE_CLASS_POWER,
BATTERY: DEVICE_CLASS_BATTERY, SENSOR_BATTERY: DEVICE_CLASS_BATTERY,
} }
DEVICE_STATE_ATTR_PROVIDER_REGISTRY = { DEVICE_STATE_ATTR_PROVIDER_REGISTRY = {
BATTERY: async_battery_device_state_attr_provider SENSOR_BATTERY: async_battery_device_state_attr_provider
} }
@ -217,7 +218,7 @@ class Sensor(ZhaEntity):
def __init__(self, unique_id, zha_device, channels, **kwargs): def __init__(self, unique_id, zha_device, channels, **kwargs):
"""Init this sensor.""" """Init this sensor."""
super().__init__(unique_id, zha_device, channels, **kwargs) super().__init__(unique_id, zha_device, channels, **kwargs)
self._sensor_type = kwargs.get(SENSOR_TYPE, GENERIC) self._sensor_type = kwargs.get(SENSOR_TYPE, SENSOR_GENERIC)
self._unit = UNIT_REGISTRY.get(self._sensor_type) self._unit = UNIT_REGISTRY.get(self._sensor_type)
self._formatter_function = FORMATTER_FUNC_REGISTRY.get( self._formatter_function = FORMATTER_FUNC_REGISTRY.get(
self._sensor_type, pass_through_formatter self._sensor_type, pass_through_formatter
@ -225,7 +226,7 @@ class Sensor(ZhaEntity):
self._force_update = FORCE_UPDATE_REGISTRY.get(self._sensor_type, False) self._force_update = FORCE_UPDATE_REGISTRY.get(self._sensor_type, False)
self._should_poll = POLLING_REGISTRY.get(self._sensor_type, False) self._should_poll = POLLING_REGISTRY.get(self._sensor_type, False)
self._channel = self.cluster_channels.get( self._channel = self.cluster_channels.get(
CHANNEL_REGISTRY.get(self._sensor_type, ATTRIBUTE_CHANNEL) CHANNEL_REGISTRY.get(self._sensor_type, CHANNEL_ATTRIBUTE)
) )
self._device_class = DEVICE_CLASS_REGISTRY.get(self._sensor_type, None) self._device_class = DEVICE_CLASS_REGISTRY.get(self._sensor_type, None)
self.state_attr_provider = DEVICE_STATE_ATTR_PROVIDER_REGISTRY.get( self.state_attr_provider = DEVICE_STATE_ATTR_PROVIDER_REGISTRY.get(

View File

@ -2,16 +2,18 @@
import logging import logging
from zigpy.zcl.foundation import Status from zigpy.zcl.foundation import Status
from homeassistant.components.switch import DOMAIN, SwitchDevice from homeassistant.components.switch import DOMAIN, SwitchDevice
from homeassistant.const import STATE_ON from homeassistant.const import STATE_ON
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .core.const import ( from .core.const import (
DATA_ZHA, DATA_ZHA,
DATA_ZHA_DISPATCHERS, DATA_ZHA_DISPATCHERS,
ZHA_DISCOVERY_NEW, CHANNEL_ON_OFF,
ON_OFF_CHANNEL,
SIGNAL_ATTR_UPDATED, SIGNAL_ATTR_UPDATED,
ZHA_DISCOVERY_NEW,
) )
from .entity import ZhaEntity from .entity import ZhaEntity
@ -63,7 +65,7 @@ class Switch(ZhaEntity, SwitchDevice):
def __init__(self, **kwargs): def __init__(self, **kwargs):
"""Initialize the ZHA switch.""" """Initialize the ZHA switch."""
super().__init__(**kwargs) super().__init__(**kwargs)
self._on_off_channel = self.cluster_channels.get(ON_OFF_CHANNEL) self._on_off_channel = self.cluster_channels.get(CHANNEL_ON_OFF)
@property @property
def is_on(self) -> bool: def is_on(self) -> bool:

View File

@ -1,15 +1,15 @@
"""Test ZHA API.""" """Test ZHA API."""
import pytest import pytest
from homeassistant.components.switch import DOMAIN from homeassistant.components.switch import DOMAIN
from homeassistant.components.zha.api import async_load_api, ATTR_IEEE, TYPE, ID from homeassistant.components.zha.api import async_load_api, TYPE, ID
from homeassistant.components.zha.core.const import ( from homeassistant.components.zha.core.const import (
ATTR_CLUSTER_ID, ATTR_CLUSTER_ID,
ATTR_CLUSTER_TYPE, ATTR_CLUSTER_TYPE,
IN, CLUSTER_TYPE_IN,
IEEE, ATTR_IEEE,
MODEL, ATTR_MODEL,
NAME, ATTR_NAME,
QUIRK_APPLIED, ATTR_QUIRK_APPLIED,
ATTR_MANUFACTURER, ATTR_MANUFACTURER,
ATTR_ENDPOINT_ID, ATTR_ENDPOINT_ID,
) )
@ -49,14 +49,14 @@ async def test_device_clusters(hass, config_entry, zha_gateway, zha_client):
cluster_infos = sorted(msg["result"], key=lambda k: k[ID]) cluster_infos = sorted(msg["result"], key=lambda k: k[ID])
cluster_info = cluster_infos[0] cluster_info = cluster_infos[0]
assert cluster_info[TYPE] == IN assert cluster_info[TYPE] == CLUSTER_TYPE_IN
assert cluster_info[ID] == 0 assert cluster_info[ID] == 0
assert cluster_info[NAME] == "Basic" assert cluster_info[ATTR_NAME] == "Basic"
cluster_info = cluster_infos[1] cluster_info = cluster_infos[1]
assert cluster_info[TYPE] == IN assert cluster_info[TYPE] == CLUSTER_TYPE_IN
assert cluster_info[ID] == 6 assert cluster_info[ID] == 6
assert cluster_info[NAME] == "OnOff" assert cluster_info[ATTR_NAME] == "OnOff"
async def test_device_cluster_attributes(hass, config_entry, zha_gateway, zha_client): async def test_device_cluster_attributes(hass, config_entry, zha_gateway, zha_client):
@ -68,7 +68,7 @@ async def test_device_cluster_attributes(hass, config_entry, zha_gateway, zha_cl
ATTR_ENDPOINT_ID: 1, ATTR_ENDPOINT_ID: 1,
ATTR_IEEE: "00:0d:6f:00:0a:90:69:e7", ATTR_IEEE: "00:0d:6f:00:0a:90:69:e7",
ATTR_CLUSTER_ID: 6, ATTR_CLUSTER_ID: 6,
ATTR_CLUSTER_TYPE: IN, ATTR_CLUSTER_TYPE: CLUSTER_TYPE_IN,
} }
) )
@ -79,7 +79,7 @@ async def test_device_cluster_attributes(hass, config_entry, zha_gateway, zha_cl
for attribute in attributes: for attribute in attributes:
assert attribute[ID] is not None assert attribute[ID] is not None
assert attribute[NAME] is not None assert attribute[ATTR_NAME] is not None
async def test_device_cluster_commands(hass, config_entry, zha_gateway, zha_client): async def test_device_cluster_commands(hass, config_entry, zha_gateway, zha_client):
@ -91,7 +91,7 @@ async def test_device_cluster_commands(hass, config_entry, zha_gateway, zha_clie
ATTR_ENDPOINT_ID: 1, ATTR_ENDPOINT_ID: 1,
ATTR_IEEE: "00:0d:6f:00:0a:90:69:e7", ATTR_IEEE: "00:0d:6f:00:0a:90:69:e7",
ATTR_CLUSTER_ID: 6, ATTR_CLUSTER_ID: 6,
ATTR_CLUSTER_TYPE: IN, ATTR_CLUSTER_TYPE: CLUSTER_TYPE_IN,
} }
) )
@ -102,7 +102,7 @@ async def test_device_cluster_commands(hass, config_entry, zha_gateway, zha_clie
for command in commands: for command in commands:
assert command[ID] is not None assert command[ID] is not None
assert command[NAME] is not None assert command[ATTR_NAME] is not None
assert command[TYPE] is not None assert command[TYPE] is not None
@ -116,13 +116,13 @@ async def test_list_devices(hass, config_entry, zha_gateway, zha_client):
assert len(devices) == 1 assert len(devices) == 1
for device in devices: for device in devices:
assert device[IEEE] is not None assert device[ATTR_IEEE] is not None
assert device[ATTR_MANUFACTURER] is not None assert device[ATTR_MANUFACTURER] is not None
assert device[MODEL] is not None assert device[ATTR_MODEL] is not None
assert device[NAME] is not None assert device[ATTR_NAME] is not None
assert device[QUIRK_APPLIED] is not None assert device[ATTR_QUIRK_APPLIED] is not None
assert device["entities"] is not None assert device["entities"] is not None
for entity_reference in device["entities"]: for entity_reference in device["entities"]:
assert entity_reference[NAME] is not None assert entity_reference[ATTR_NAME] is not None
assert entity_reference["entity_id"] is not None assert entity_reference["entity_id"] is not None