diff --git a/homeassistant/components/zha/__init__.py b/homeassistant/components/zha/__init__.py index 5905f86d1bd..b0d1ec42ec7 100644 --- a/homeassistant/components/zha/__init__.py +++ b/homeassistant/components/zha/__init__.py @@ -26,7 +26,7 @@ from .core.const import ( DEFAULT_BAUDRATE, DEFAULT_RADIO_TYPE, DOMAIN, - ENABLE_QUIRKS, + CONF_ENABLE_QUIRKS, RadioType, ) from .core.registries import establish_device_mappings @@ -46,7 +46,7 @@ CONFIG_SCHEMA = vol.Schema( vol.Optional(CONF_DEVICE_CONFIG, default={}): vol.Schema( {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] = [] 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 # before zhaquirks is imported # pylint: disable=W0611, W0612 diff --git a/homeassistant/components/zha/api.py b/homeassistant/components/zha/api.py index 0e26bfab592..9b482dfb4f5 100644 --- a/homeassistant/components/zha/api.py +++ b/homeassistant/components/zha/api.py @@ -21,16 +21,16 @@ from .core.const import ( ATTR_ENDPOINT_ID, ATTR_MANUFACTURER, ATTR_VALUE, - CLIENT_COMMANDS, + CLUSTER_COMMANDS_CLIENT, DATA_ZHA, DATA_ZHA_GATEWAY, DOMAIN, - IN, + CLUSTER_TYPE_IN, MFG_CLUSTER_ID_START, - NAME, - OUT, - SERVER, - SERVER_COMMANDS, + ATTR_NAME, + CLUSTER_TYPE_OUT, + CLUSTER_COMMAND_SERVER, + CLUSTER_COMMANDS_SERVER, ) 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_ENDPOINT_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_VALUE): cv.string, vol.Optional(ATTR_MANUFACTURER): cv.positive_int, @@ -85,7 +85,7 @@ SERVICE_SCHEMAS = { vol.Required(ATTR_IEEE): convert_ieee, vol.Required(ATTR_ENDPOINT_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_TYPE): 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.update(device.device_info) 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] ] @@ -201,21 +204,21 @@ async def websocket_device_clusters(hass, connection, msg): if zha_device is not None: clusters_by_endpoint = zha_device.async_get_clusters() 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( { - TYPE: IN, + TYPE: CLUSTER_TYPE_IN, ID: c_id, - NAME: cluster.__class__.__name__, + ATTR_NAME: cluster.__class__.__name__, "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( { - TYPE: OUT, + TYPE: CLUSTER_TYPE_OUT, ID: c_id, - NAME: cluster.__class__.__name__, + ATTR_NAME: cluster.__class__.__name__, "endpoint_id": ep_id, } ) @@ -250,7 +253,9 @@ async def websocket_device_cluster_attributes(hass, connection, msg): ) if attributes is not None: 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( "Requested attributes for: %s %s %s %s", "{}: [{}]".format(ATTR_CLUSTER_ID, cluster_id), @@ -289,20 +294,20 @@ async def websocket_device_cluster_commands(hass, connection, msg): ) if commands is not None: - for cmd_id in commands[CLIENT_COMMANDS]: + for cmd_id in commands[CLUSTER_COMMANDS_CLIENT]: cluster_commands.append( { TYPE: CLIENT, 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( { - TYPE: SERVER, + TYPE: CLUSTER_COMMAND_SERVER, ID: cmd_id, - NAME: commands[SERVER_COMMANDS][cmd_id][0], + ATTR_NAME: commands[CLUSTER_COMMANDS_SERVER][cmd_id][0], } ) _LOGGER.debug( diff --git a/homeassistant/components/zha/binary_sensor.py b/homeassistant/components/zha/binary_sensor.py index 7ca7dbf9db3..082cd4542e7 100644 --- a/homeassistant/components/zha/binary_sensor.py +++ b/homeassistant/components/zha/binary_sensor.py @@ -2,34 +2,35 @@ import logging 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, 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.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect + from .core.const import ( + SENSOR_ACCELERATION, + CHANNEL_ATTRIBUTE, DATA_ZHA, DATA_ZHA_DISPATCHERS, - ZHA_DISCOVERY_NEW, - ON_OFF_CHANNEL, - ZONE_CHANNEL, - SIGNAL_ATTR_UPDATED, - ATTRIBUTE_CHANNEL, - UNKNOWN, - OPENING, - ZONE, - OCCUPANCY, + SENSOR_OCCUPANCY, + CHANNEL_ON_OFF, + SENSOR_OPENING, SENSOR_TYPE, - ACCELERATION, + SIGNAL_ATTR_UPDATED, + UNKNOWN, + ZHA_DISCOVERY_NEW, + ZONE, + CHANNEL_ZONE, ) from .entity import ZhaEntity @@ -54,10 +55,10 @@ async def get_ias_device_class(channel): DEVICE_CLASS_REGISTRY = { UNKNOWN: None, - OPENING: DEVICE_CLASS_OPENING, + SENSOR_OPENING: DEVICE_CLASS_OPENING, ZONE: get_ias_device_class, - OCCUPANCY: DEVICE_CLASS_OCCUPANCY, - ACCELERATION: DEVICE_CLASS_MOVING, + SENSOR_OCCUPANCY: DEVICE_CLASS_OCCUPANCY, + SENSOR_ACCELERATION: DEVICE_CLASS_MOVING, } @@ -108,9 +109,9 @@ class BinarySensor(ZhaEntity, BinarySensorDevice): """Initialize the ZHA binary sensor.""" super().__init__(**kwargs) self._device_state_attributes = {} - self._zone_channel = self.cluster_channels.get(ZONE_CHANNEL) - self._on_off_channel = self.cluster_channels.get(ON_OFF_CHANNEL) - self._attr_channel = self.cluster_channels.get(ATTRIBUTE_CHANNEL) + self._zone_channel = self.cluster_channels.get(CHANNEL_ZONE) + self._on_off_channel = self.cluster_channels.get(CHANNEL_ON_OFF) + self._attr_channel = self.cluster_channels.get(CHANNEL_ATTRIBUTE) self._zha_sensor_type = kwargs[SENSOR_TYPE] async def _determine_device_class(self): diff --git a/homeassistant/components/zha/core/channels/__init__.py b/homeassistant/components/zha/core/channels/__init__.py index 6183d36427c..98919e46555 100644 --- a/homeassistant/components/zha/core/channels/__init__.py +++ b/homeassistant/components/zha/core/channels/__init__.py @@ -13,20 +13,21 @@ from random import uniform from homeassistant.core import callback 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 ( + CHANNEL_ATTRIBUTE, + CHANNEL_EVENT_RELAY, REPORT_CONFIG_DEFAULT, SIGNAL_ATTR_UPDATED, - ATTRIBUTE_CHANNEL, - EVENT_RELAY_CHANNEL, - ZDO_CHANNEL, + CHANNEL_ZDO, +) +from ..helpers import ( + LogMixin, + bind_cluster, + configure_reporting, + construct_unique_id, + get_attr_id_by_name, + safe_read, ) from ..registries import CLUSTER_REPORT_CONFIGS @@ -232,7 +233,7 @@ class ZigbeeChannel(LogMixin): class AttributeListeningChannel(ZigbeeChannel): """Channel for attribute reports from the cluster.""" - CHANNEL_NAME = ATTRIBUTE_CHANNEL + CHANNEL_NAME = CHANNEL_ATTRIBUTE def __init__(self, cluster, device): """Initialize AttributeListeningChannel.""" @@ -266,7 +267,7 @@ class ZDOChannel(LogMixin): def __init__(self, cluster, device): """Initialize ZDOChannel.""" - self.name = ZDO_CHANNEL + self.name = CHANNEL_ZDO self._cluster = cluster self._zha_device = device self._status = ChannelStatus.CREATED @@ -320,7 +321,7 @@ class ZDOChannel(LogMixin): class EventRelayChannel(ZigbeeChannel): """Event relay that can be attached to zigbee clusters.""" - CHANNEL_NAME = EVENT_RELAY_CHANNEL + CHANNEL_NAME = CHANNEL_EVENT_RELAY @callback def attribute_updated(self, attrid, value): diff --git a/homeassistant/components/zha/core/channels/closures.py b/homeassistant/components/zha/core/channels/closures.py index 5c3a3d46f0d..23d174c08b1 100644 --- a/homeassistant/components/zha/core/channels/closures.py +++ b/homeassistant/components/zha/core/channels/closures.py @@ -5,8 +5,10 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/zha/ """ import logging + from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_send + from . import ZigbeeChannel from ..const import SIGNAL_ATTR_UPDATED diff --git a/homeassistant/components/zha/core/channels/general.py b/homeassistant/components/zha/core/channels/general.py index 5d624c832dd..388524b62e4 100644 --- a/homeassistant/components/zha/core/channels/general.py +++ b/homeassistant/components/zha/core/channels/general.py @@ -5,12 +5,14 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/zha/ """ import logging + from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.event import async_call_later + 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 ..helpers import get_attr_id_by_name _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/zha/core/channels/homeautomation.py b/homeassistant/components/zha/core/channels/homeautomation.py index dee6e43f475..05b9b591cac 100644 --- a/homeassistant/components/zha/core/channels/homeautomation.py +++ b/homeassistant/components/zha/core/channels/homeautomation.py @@ -5,9 +5,11 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/zha/ """ import logging + from homeassistant.helpers.dispatcher import async_dispatcher_send + 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__) @@ -15,7 +17,7 @@ _LOGGER = logging.getLogger(__name__) class ElectricalMeasurementChannel(AttributeListeningChannel): """Channel that polls active power level.""" - CHANNEL_NAME = ELECTRICAL_MEASUREMENT_CHANNEL + CHANNEL_NAME = CHANNEL_ELECTRICAL_MEASUREMENT async def async_update(self): """Retrieve latest state.""" diff --git a/homeassistant/components/zha/core/channels/hvac.py b/homeassistant/components/zha/core/channels/hvac.py index 164497abd35..7e38af4a0d7 100644 --- a/homeassistant/components/zha/core/channels/hvac.py +++ b/homeassistant/components/zha/core/channels/hvac.py @@ -5,8 +5,10 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/zha/ """ import logging + from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_send + from . import ZigbeeChannel from ..const import SIGNAL_ATTR_UPDATED diff --git a/homeassistant/components/zha/core/channels/lighting.py b/homeassistant/components/zha/core/channels/lighting.py index e36da629ace..05d88d82288 100644 --- a/homeassistant/components/zha/core/channels/lighting.py +++ b/homeassistant/components/zha/core/channels/lighting.py @@ -5,6 +5,7 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/zha/ """ import logging + from . import ZigbeeChannel _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/zha/core/channels/registry.py b/homeassistant/components/zha/core/channels/registry.py index 9a590600f70..86527e0ac4a 100644 --- a/homeassistant/components/zha/core/channels/registry.py +++ b/homeassistant/components/zha/core/channels/registry.py @@ -5,13 +5,12 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/zha/ """ from . import ZigbeeChannel - from .closures import DoorLockChannel from .general import ( - OnOffChannel, - LevelControlChannel, - PowerConfigurationChannel, BasicChannel, + LevelControlChannel, + OnOffChannel, + PowerConfigurationChannel, ) from .homeautomation import ElectricalMeasurementChannel from .hvac import FanChannel @@ -27,27 +26,27 @@ def populate_channel_registry(): 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.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, } ) diff --git a/homeassistant/components/zha/core/channels/security.py b/homeassistant/components/zha/core/channels/security.py index 6b2a8af837f..20b5ce7ba8f 100644 --- a/homeassistant/components/zha/core/channels/security.py +++ b/homeassistant/components/zha/core/channels/security.py @@ -5,11 +5,13 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/zha/ """ import logging + from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_send + from . import ZigbeeChannel -from ..helpers import bind_cluster from ..const import SIGNAL_ATTR_UPDATED +from ..helpers import bind_cluster _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index 8f58f0c9af0..7a4f5f94897 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -10,132 +10,98 @@ from homeassistant.components.lock import DOMAIN as LOCK from homeassistant.components.sensor import DOMAIN as SENSOR 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] -DATA_ZHA = "zha" -DATA_ZHA_CONFIG = "config" -DATA_ZHA_BRIDGE_ID = "zha_bridge_id" -DATA_ZHA_DISPATCHERS = "zha_dispatchers" -DATA_ZHA_CORE_EVENTS = "zha_core_events" -DATA_ZHA_GATEWAY = "zha_gateway" -ZHA_DISCOVERY_NEW = "zha_discovery_new_{}" +CHANNEL_ATTRIBUTE = "attribute" +CHANNEL_BASIC = "basic" +CHANNEL_COLOR = "light_color" +CHANNEL_DOORLOCK = "door_lock" +CHANNEL_ELECTRICAL_MEASUREMENT = "electrical_measurement" +CHANNEL_EVENT_RELAY = "event_relay" +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) CONF_BAUDRATE = "baudrate" CONF_DATABASE = "database_path" CONF_DEVICE_CONFIG = "device_config" +CONF_ENABLE_QUIRKS = "enable_quirks" CONF_RADIO_TYPE = "radio_type" CONF_USB_PATH = "usb_path" -DATA_DEVICE_CONFIG = "zha_device_config" -ENABLE_QUIRKS = "enable_quirks" - -RADIO = "radio" -RADIO_DESCRIPTION = "radio_description" 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_BAUDRATE = 57600 DEFAULT_DATABASE_NAME = "zigbee.db" +DISCOVERY_KEY = "zha_discovery_info" -ATTR_CLUSTER_ID = "cluster_id" -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" +DOMAIN = "zha" -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 +POWER_MAINS_POWERED = "Mains" +POWER_BATTERY_OR_UNKNOWN = "Battery or Unknown" + class RadioType(enum.Enum): """Possible options for radio type.""" @@ -150,8 +116,6 @@ class RadioType(enum.Enum): return [e.value for e in RadioType] -DISCOVERY_KEY = "zha_discovery_info" - REPORT_CONFIG_MAX_INT = 900 REPORT_CONFIG_MAX_INT_BATTERY_SAVE = 10800 REPORT_CONFIG_MIN_INT = 30 @@ -185,3 +149,39 @@ REPORT_CONFIG_OP = ( REPORT_CONFIG_MAX_INT, 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" diff --git a/homeassistant/components/zha/core/device.py b/homeassistant/components/zha/core/device.py index a76c580a3f1..748a9839bb2 100644 --- a/homeassistant/components/zha/core/device.py +++ b/homeassistant/components/zha/core/device.py @@ -21,36 +21,36 @@ from .channels import EventRelayChannel from .const import ( ATTR_ARGS, ATTR_ATTRIBUTE, + ATTR_AVAILABLE, ATTR_CLUSTER_ID, ATTR_COMMAND, ATTR_COMMAND_TYPE, ATTR_ENDPOINT_ID, ATTR_MANUFACTURER, ATTR_VALUE, - BATTERY_OR_UNKNOWN, - CLIENT_COMMANDS, - IEEE, - IN, - MAINS_POWERED, - MANUFACTURER_CODE, - MODEL, - NAME, - NWK, - OUT, - POWER_CONFIGURATION_CHANNEL, - POWER_SOURCE, - QUIRK_APPLIED, - QUIRK_CLASS, - SERVER, - SERVER_COMMANDS, + POWER_BATTERY_OR_UNKNOWN, + CLUSTER_COMMANDS_CLIENT, + ATTR_IEEE, + CLUSTER_TYPE_IN, + ATTR_LAST_SEEN, + ATTR_LQI, + POWER_MAINS_POWERED, + ATTR_MANUFACTURER_CODE, + ATTR_MODEL, + ATTR_NAME, + ATTR_NWK, + CLUSTER_TYPE_OUT, + CHANNEL_POWER_CONFIGURATION, + ATTR_POWER_SOURCE, + ATTR_QUIRK_APPLIED, + ATTR_QUIRK_CLASS, + ATTR_RSSI, + CLUSTER_COMMAND_SERVER, + CLUSTER_COMMANDS_SERVER, SIGNAL_AVAILABLE, UNKNOWN_MANUFACTURER, UNKNOWN_MODEL, - ZDO_CHANNEL, - LQI, - RSSI, - LAST_SEEN, - ATTR_AVAILABLE, + CHANNEL_ZDO, ) from .helpers import LogMixin @@ -155,7 +155,9 @@ class ZHADevice(LogMixin): @property def power_source(self): """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 def is_router(self): @@ -223,18 +225,18 @@ class ZHADevice(LogMixin): time_struct = time.localtime(self.last_seen) update_time = time.strftime("%Y-%m-%dT%H:%M:%S", time_struct) return { - IEEE: ieee, - NWK: self.nwk, + ATTR_IEEE: ieee, + ATTR_NWK: self.nwk, ATTR_MANUFACTURER: self.manufacturer, - MODEL: self.model, - NAME: self.name or ieee, - QUIRK_APPLIED: self.quirk_applied, - QUIRK_CLASS: self.quirk_class, - MANUFACTURER_CODE: self.manufacturer_code, - POWER_SOURCE: self.power_source, - LQI: self.lqi, - RSSI: self.rssi, - LAST_SEEN: update_time, + ATTR_MODEL: self.model, + ATTR_NAME: self.name or ieee, + ATTR_QUIRK_APPLIED: self.quirk_applied, + ATTR_QUIRK_CLASS: self.quirk_class, + ATTR_MANUFACTURER_CODE: self.manufacturer_code, + ATTR_POWER_SOURCE: self.power_source, + ATTR_LQI: self.lqi, + ATTR_RSSI: self.rssi, + ATTR_LAST_SEEN: update_time, ATTR_AVAILABLE: self.available, } @@ -242,8 +244,8 @@ class ZHADevice(LogMixin): """Add cluster channel to device.""" # only keep 1 power configuration channel if ( - cluster_channel.name is POWER_CONFIGURATION_CHANNEL - and POWER_CONFIGURATION_CHANNEL in self.cluster_channels + cluster_channel.name is CHANNEL_POWER_CONFIGURATION + and CHANNEL_POWER_CONFIGURATION in self.cluster_channels ): return @@ -318,7 +320,7 @@ class ZHADevice(LogMixin): semaphore = asyncio.Semaphore(3) zdo_task = None for channel in channels: - if channel.name == ZDO_CHANNEL: + if channel.name == CHANNEL_ZDO: # pylint: disable=E1111 if zdo_task is None: # We only want to do this once zdo_task = self._async_create_task( @@ -356,7 +358,10 @@ class ZHADevice(LogMixin): def async_get_clusters(self): """Get all clusters for this device.""" 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() if ep_id != 0 } @@ -367,19 +372,24 @@ class ZHADevice(LogMixin): from zigpy.profiles import zha, zll 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() if ep_id != 0 and endpoint.profile_id in (zha.PROFILE_ID, zll.PROFILE_ID) } @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.""" clusters = self.async_get_clusters() return clusters[endpoint_id][cluster_type][cluster_id] @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.""" cluster = self.async_get_cluster(endpoint_id, cluster_id, cluster_type) if cluster is None: @@ -387,14 +397,16 @@ class ZHADevice(LogMixin): return cluster.attributes @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.""" cluster = self.async_get_cluster(endpoint_id, cluster_id, cluster_type) if cluster is None: return None return { - CLIENT_COMMANDS: cluster.client_commands, - SERVER_COMMANDS: cluster.server_commands, + CLUSTER_COMMANDS_CLIENT: cluster.client_commands, + CLUSTER_COMMANDS_SERVER: cluster.server_commands, } async def write_zigbee_attribute( @@ -403,7 +415,7 @@ class ZHADevice(LogMixin): cluster_id, attribute, value, - cluster_type=IN, + cluster_type=CLUSTER_TYPE_IN, manufacturer=None, ): """Write a value to a zigbee attribute for a cluster in this entity.""" @@ -444,7 +456,7 @@ class ZHADevice(LogMixin): command, command_type, args, - cluster_type=IN, + cluster_type=CLUSTER_TYPE_IN, manufacturer=None, ): """Issue a command against specified zigbee cluster on this entity.""" @@ -452,7 +464,7 @@ class ZHADevice(LogMixin): if cluster is None: return None response = None - if command_type == SERVER: + if command_type == CLUSTER_COMMAND_SERVER: response = await cluster.command( command, *args, manufacturer=manufacturer, expect_reply=True ) diff --git a/homeassistant/components/zha/core/discovery.py b/homeassistant/components/zha/core/discovery.py index 97506494387..687728b5e26 100644 --- a/homeassistant/components/zha/core/discovery.py +++ b/homeassistant/components/zha/core/discovery.py @@ -12,28 +12,29 @@ from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR from homeassistant.components.sensor import DOMAIN as SENSOR from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_send + from .channels import AttributeListeningChannel, EventRelayChannel, ZDOChannel from .channels.registry import ZIGBEE_CHANNEL_REGISTRY from .const import ( - CONF_DEVICE_CONFIG, COMPONENTS, - ZHA_DISCOVERY_NEW, + CONF_DEVICE_CONFIG, DATA_ZHA, + SENSOR_GENERIC, SENSOR_TYPE, UNKNOWN, - GENERIC, + ZHA_DISCOVERY_NEW, ) from .registries import ( BINARY_SENSOR_TYPES, CHANNEL_ONLY_CLUSTERS, - EVENT_RELAY_CLUSTERS, - SENSOR_TYPES, - DEVICE_CLASS, COMPONENT_CLUSTERS, - SINGLE_INPUT_CLUSTER_DEVICE_CLASS, - SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS, + DEVICE_CLASS, + EVENT_RELAY_CLUSTERS, OUTPUT_CHANNEL_ONLY_CLUSTERS, REMOTE_DEVICE_TYPES, + SENSOR_TYPES, + SINGLE_INPUT_CLUSTER_DEVICE_CLASS, + SINGLE_OUTPUT_CLUSTER_DEVICE_CLASS, ) _LOGGER = logging.getLogger(__name__) @@ -291,7 +292,7 @@ def _async_handle_single_cluster_match( if component == SENSOR: 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: discovery_info.update( diff --git a/homeassistant/components/zha/core/gateway.py b/homeassistant/components/zha/core/gateway.py index 9994c445dbc..1e6367898d5 100644 --- a/homeassistant/components/zha/core/gateway.py +++ b/homeassistant/components/zha/core/gateway.py @@ -22,45 +22,45 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send from ..api import async_get_device_info from .const import ( - ADD_DEVICE_RELAY_LOGGERS, + DEBUG_RELAY_LOGGERS, ATTR_MANUFACTURER, - BELLOWS, + DEBUG_COMP_BELLOWS, CONF_BAUDRATE, CONF_DATABASE, CONF_RADIO_TYPE, CONF_USB_PATH, CONTROLLER, - CURRENT, + DEBUG_LEVEL_CURRENT, DATA_ZHA, DATA_ZHA_BRIDGE_ID, DATA_ZHA_GATEWAY, DEBUG_LEVELS, DEFAULT_BAUDRATE, DEFAULT_DATABASE_NAME, - DEVICE_FULL_INIT, - DEVICE_INFO, - DEVICE_JOINED, - DEVICE_REMOVED, + ZHA_GW_MSG_DEVICE_FULL_INIT, + ZHA_GW_MSG_DEVICE_INFO, + ZHA_GW_MSG_DEVICE_JOINED, + ZHA_GW_MSG_DEVICE_REMOVED, DOMAIN, - IEEE, - LOG_ENTRY, - LOG_OUTPUT, - MODEL, - NWK, - ORIGINAL, - RADIO, - RADIO_DESCRIPTION, - RAW_INIT, + ATTR_IEEE, + ZHA_GW_MSG_LOG_ENTRY, + ZHA_GW_MSG_LOG_OUTPUT, + ATTR_MODEL, + ATTR_NWK, + DEBUG_LEVEL_ORIGINAL, + ZHA_GW_RADIO, + ZHA_GW_RADIO_DESCRIPTION, + ZHA_GW_MSG_RAW_INIT, SIGNAL_REMOVE, - SIGNATURE, - TYPE, + ATTR_SIGNATURE, + ATTR_TYPE, UNKNOWN_MANUFACTURER, UNKNOWN_MODEL, - ZHA, + DEBUG_COMP_ZHA, ZHA_GW_MSG, - ZIGPY, - ZIGPY_DECONZ, - ZIGPY_XBEE, + DEBUG_COMP_ZIGPY, + DEBUG_COMP_ZIGPY_DECONZ, + DEBUG_COMP_ZIGPY_XBEE, ) from .device import DeviceStatus, ZHADevice from .discovery import async_dispatch_discovery_info, async_process_endpoint @@ -91,8 +91,8 @@ class ZHAGateway: self.radio_description = None hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] = self self._log_levels = { - ORIGINAL: async_capture_log_levels(), - CURRENT: async_capture_log_levels(), + DEBUG_LEVEL_ORIGINAL: async_capture_log_levels(), + DEBUG_LEVEL_CURRENT: async_capture_log_levels(), } self.debug_enabled = False self._log_relay_handler = LogRelayHandler(hass, self) @@ -107,9 +107,9 @@ class ZHAGateway: baudrate = self._config.get(CONF_BAUDRATE, DEFAULT_BAUDRATE) radio_type = self._config_entry.data.get(CONF_RADIO_TYPE) - radio_details = RADIO_TYPES[radio_type][RADIO]() - radio = radio_details[RADIO] - self.radio_description = RADIO_TYPES[radio_type][RADIO_DESCRIPTION] + radio_details = RADIO_TYPES[radio_type][ZHA_GW_RADIO]() + radio = radio_details[ZHA_GW_RADIO] + self.radio_description = RADIO_TYPES[radio_type][ZHA_GW_RADIO_DESCRIPTION] await radio.connect(usb_path, baudrate) if CONF_DATABASE in self._config: @@ -141,7 +141,11 @@ class ZHAGateway: async_dispatcher_send( self._hass, 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): @@ -154,12 +158,12 @@ class ZHAGateway: self._hass, ZHA_GW_MSG, { - TYPE: RAW_INIT, - NWK: device.nwk, - IEEE: str(device.ieee), - MODEL: device.model if device.model else UNKNOWN_MODEL, + ATTR_TYPE: ZHA_GW_MSG_RAW_INIT, + ATTR_NWK: device.nwk, + ATTR_IEEE: str(device.ieee), + ATTR_MODEL: device.model if device.model else UNKNOWN_MODEL, 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( self._hass, 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): @@ -254,11 +261,11 @@ class ZHAGateway: @callback def async_enable_debug_mode(self): """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) - 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) self.debug_enabled = True @@ -266,9 +273,9 @@ class ZHAGateway: @callback def async_disable_debug_mode(self): """Disable debug mode for ZHA.""" - async_set_logger_levels(self._log_levels[ORIGINAL]) - self._log_levels[CURRENT] = async_capture_log_levels() - for logger_name in ADD_DEVICE_RELAY_LOGGERS: + async_set_logger_levels(self._log_levels[DEBUG_LEVEL_ORIGINAL]) + self._log_levels[DEBUG_LEVEL_CURRENT] = async_capture_log_levels() + for logger_name in DEBUG_RELAY_LOGGERS: logging.getLogger(logger_name).removeHandler(self._log_relay_handler) self.debug_enabled = False @@ -377,7 +384,10 @@ class ZHAGateway: async_dispatcher_send( self._hass, 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): @@ -390,22 +400,26 @@ class ZHAGateway: def async_capture_log_levels(): """Capture current logger levels for ZHA.""" return { - BELLOWS: logging.getLogger(BELLOWS).getEffectiveLevel(), - ZHA: logging.getLogger(ZHA).getEffectiveLevel(), - ZIGPY: logging.getLogger(ZIGPY).getEffectiveLevel(), - ZIGPY_XBEE: logging.getLogger(ZIGPY_XBEE).getEffectiveLevel(), - ZIGPY_DECONZ: logging.getLogger(ZIGPY_DECONZ).getEffectiveLevel(), + DEBUG_COMP_BELLOWS: logging.getLogger(DEBUG_COMP_BELLOWS).getEffectiveLevel(), + DEBUG_COMP_ZHA: logging.getLogger(DEBUG_COMP_ZHA).getEffectiveLevel(), + DEBUG_COMP_ZIGPY: logging.getLogger(DEBUG_COMP_ZIGPY).getEffectiveLevel(), + DEBUG_COMP_ZIGPY_XBEE: logging.getLogger( + DEBUG_COMP_ZIGPY_XBEE + ).getEffectiveLevel(), + DEBUG_COMP_ZIGPY_DECONZ: logging.getLogger( + DEBUG_COMP_ZIGPY_DECONZ + ).getEffectiveLevel(), } @callback def async_set_logger_levels(levels): """Set logger levels for ZHA.""" - logging.getLogger(BELLOWS).setLevel(levels[BELLOWS]) - logging.getLogger(ZHA).setLevel(levels[ZHA]) - logging.getLogger(ZIGPY).setLevel(levels[ZIGPY]) - logging.getLogger(ZIGPY_XBEE).setLevel(levels[ZIGPY_XBEE]) - logging.getLogger(ZIGPY_DECONZ).setLevel(levels[ZIGPY_DECONZ]) + logging.getLogger(DEBUG_COMP_BELLOWS).setLevel(levels[DEBUG_COMP_BELLOWS]) + logging.getLogger(DEBUG_COMP_ZHA).setLevel(levels[DEBUG_COMP_ZHA]) + logging.getLogger(DEBUG_COMP_ZIGPY).setLevel(levels[DEBUG_COMP_ZIGPY]) + logging.getLogger(DEBUG_COMP_ZIGPY_XBEE).setLevel(levels[DEBUG_COMP_ZIGPY_XBEE]) + logging.getLogger(DEBUG_COMP_ZIGPY_DECONZ).setLevel(levels[DEBUG_COMP_ZIGPY_DECONZ]) class LogRelayHandler(logging.Handler): @@ -426,5 +440,7 @@ class LogRelayHandler(logging.Handler): entry = LogEntry(record, stack, _figure_out_source(record, stack, self.hass)) 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()}, ) diff --git a/homeassistant/components/zha/core/helpers.py b/homeassistant/components/zha/core/helpers.py index 3a053d7be01..23ebd9381bb 100644 --- a/homeassistant/components/zha/core/helpers.py +++ b/homeassistant/components/zha/core/helpers.py @@ -6,17 +6,19 @@ https://home-assistant.io/components/zha/ """ import asyncio import collections -import logging from concurrent.futures import TimeoutError as Timeout +import logging + from homeassistant.core import callback + from .const import ( DEFAULT_BAUDRATE, + CLUSTER_TYPE_IN, + CLUSTER_TYPE_OUT, REPORT_CONFIG_MAX_INT, REPORT_CONFIG_MIN_INT, REPORT_CONFIG_RPT_CHANGE, RadioType, - IN, - OUT, ) from .registries import BINDABLE_CLUSTERS @@ -206,14 +208,18 @@ async def get_matched_clusters(source_zha_device, target_zha_device): clusters_to_bind = [] 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: continue 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( - source_cluster=source_clusters[endpoint_id][OUT][cluster_id], - target_cluster=target_clusters[t_endpoint_id][IN][cluster_id], + source_cluster=source_clusters[endpoint_id][CLUSTER_TYPE_OUT][ + cluster_id + ], + target_cluster=target_clusters[t_endpoint_id][CLUSTER_TYPE_IN][ + cluster_id + ], ) clusters_to_bind.append(cluster_pair) return clusters_to_bind @@ -228,9 +234,9 @@ def async_is_bindable_target(source_zha_device, target_zha_device): bindables = set(BINDABLE_CLUSTERS) for endpoint_id in source_clusters: for t_endpoint_id in target_clusters: - matches = set(source_clusters[endpoint_id][OUT].keys()).intersection( - target_clusters[t_endpoint_id][IN].keys() - ) + matches = set( + 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): return True return False diff --git a/homeassistant/components/zha/core/registries.py b/homeassistant/components/zha/core/registries.py index e0cfbeeee7b..27e79749838 100644 --- a/homeassistant/components/zha/core/registries.py +++ b/homeassistant/components/zha/core/registries.py @@ -14,56 +14,56 @@ from homeassistant.components.sensor import DOMAIN as SENSOR from homeassistant.components.switch import DOMAIN as SWITCH from .const import ( - HUMIDITY, - TEMPERATURE, - ILLUMINANCE, - PRESSURE, - METERING, - ELECTRICAL_MEASUREMENT, - OCCUPANCY, - REPORT_CONFIG_IMMEDIATE, - OPENING, - ZONE, - RADIO_DESCRIPTION, + SENSOR_ACCELERATION, + SENSOR_BATTERY, + CONTROLLER, + SENSOR_ELECTRICAL_MEASUREMENT, + SENSOR_HUMIDITY, + SENSOR_ILLUMINANCE, + SENSOR_METERING, + SENSOR_OCCUPANCY, + SENSOR_OPENING, + SENSOR_PRESSURE, + ZHA_GW_RADIO, + ZHA_GW_RADIO_DESCRIPTION, REPORT_CONFIG_ASAP, REPORT_CONFIG_DEFAULT, - REPORT_CONFIG_MIN_INT, + REPORT_CONFIG_IMMEDIATE, REPORT_CONFIG_MAX_INT, + REPORT_CONFIG_MIN_INT, REPORT_CONFIG_OP, - ACCELERATION, + SENSOR_TEMPERATURE, + ZONE, RadioType, - RADIO, - CONTROLLER, - BATTERY, ) -SMARTTHINGS_HUMIDITY_CLUSTER = 0xFC45 -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_CLUSTERS = set() BINARY_SENSOR_TYPES = {} -REMOTE_DEVICE_TYPES = {} +BINDABLE_CLUSTERS = [] +CHANNEL_ONLY_CLUSTERS = [] CLUSTER_REPORT_CONFIGS = {} CUSTOM_CLUSTER_MAPPINGS = {} -EVENT_RELAY_CLUSTERS = [] -CHANNEL_ONLY_CLUSTERS = [] -OUTPUT_CHANNEL_ONLY_CLUSTERS = [] -BINDABLE_CLUSTERS = [] -INPUT_BIND_ONLY_CLUSTERS = [] -BINARY_SENSOR_CLUSTERS = set() +DEVICE_CLASS = {} DEVICE_TRACKER_CLUSTERS = set() +EVENT_RELAY_CLUSTERS = [] +INPUT_BIND_ONLY_CLUSTERS = [] 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() +SMARTTHINGS_ACCELERATION_CLUSTER = 0xFC02 +SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE = 0x8000 +SMARTTHINGS_HUMIDITY_CLUSTER = 0xFC45 + COMPONENT_CLUSTERS = { BINARY_SENSOR: BINARY_SENSOR_CLUSTERS, + DEVICE_TRACKER: DEVICE_TRACKER_CLUSTERS, LIGHT: LIGHT_CLUSTERS, SWITCH: SWITCH_CLUSTERS, - DEVICE_TRACKER: DEVICE_TRACKER_CLUSTERS, } @@ -90,144 +90,58 @@ def establish_device_mappings(): import bellows.ezsp 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: get_ezsp_radio, - RADIO_DESCRIPTION: "EZSP", + ZHA_GW_RADIO: get_ezsp_radio, + ZHA_GW_RADIO_DESCRIPTION: "EZSP", } def get_xbee_radio(): import zigpy_xbee.api 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: get_xbee_radio, - RADIO_DESCRIPTION: "XBee", + ZHA_GW_RADIO: get_xbee_radio, + ZHA_GW_RADIO_DESCRIPTION: "XBee", } def get_deconz_radio(): import zigpy_deconz.api 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: get_deconz_radio, - RADIO_DESCRIPTION: "Deconz", + ZHA_GW_RADIO: get_deconz_radio, + ZHA_GW_RADIO_DESCRIPTION: "Deconz", } - EVENT_RELAY_CLUSTERS.append(zcl.clusters.general.LevelControl.cluster_id) - EVENT_RELAY_CLUSTERS.append(zcl.clusters.general.OnOff.cluster_id) + BINARY_SENSOR_CLUSTERS.add(SMARTTHINGS_ACCELERATION_CLUSTER) + 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) - CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.lightlink.LightLink.cluster_id) - - OUTPUT_CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.general.Scenes.cluster_id) + BINARY_SENSOR_TYPES.update( + { + SMARTTHINGS_ACCELERATION_CLUSTER: SENSOR_ACCELERATION, + 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.OnOff.cluster_id) BINDABLE_CLUSTERS.append(zcl.clusters.lighting.Color.cluster_id) - INPUT_BIND_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) + CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.general.Basic.cluster_id) + CHANNEL_ONLY_CLUSTERS.append(zcl.clusters.lightlink.LightLink.cluster_id) CLUSTER_REPORT_CONFIGS.update( { @@ -311,15 +225,104 @@ def establish_device_mappings(): } ) - BINARY_SENSOR_CLUSTERS.add(zcl.clusters.general.OnOff.cluster_id) - BINARY_SENSOR_CLUSTERS.add(zcl.clusters.security.IasZone.cluster_id) - BINARY_SENSOR_CLUSTERS.add(zcl.clusters.measurement.OccupancySensing.cluster_id) - BINARY_SENSOR_CLUSTERS.add(SMARTTHINGS_ACCELERATION_CLUSTER) + DEVICE_CLASS[zha.PROFILE_ID].update( + { + SMARTTHINGS_ARRIVAL_SENSOR_DEVICE_TYPE: DEVICE_TRACKER, + 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) - 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.OnOff.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) + + 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) diff --git a/homeassistant/components/zha/core/store.py b/homeassistant/components/zha/core/store.py index 312cfc7e545..85b4261e4ec 100644 --- a/homeassistant/components/zha/core/store.py +++ b/homeassistant/components/zha/core/store.py @@ -1,16 +1,15 @@ """Data storage helper for ZHA.""" -import logging -from collections import OrderedDict - # pylint: disable=W0611 +from collections import OrderedDict +import logging from typing import MutableMapping # noqa: F401 from typing import cast import attr from homeassistant.core import callback -from homeassistant.loader import bind_hass from homeassistant.helpers.typing import HomeAssistantType +from homeassistant.loader import bind_hass _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/zha/device_tracker.py b/homeassistant/components/zha/device_tracker.py index 6b881ff7a7d..5d05e980dab 100644 --- a/homeassistant/components/zha/device_tracker.py +++ b/homeassistant/components/zha/device_tracker.py @@ -1,16 +1,18 @@ """Support for the ZHA platform.""" import logging 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.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect + from .core.const import ( DATA_ZHA, DATA_ZHA_DISPATCHERS, - ZHA_DISCOVERY_NEW, - POWER_CONFIGURATION_CHANNEL, + CHANNEL_POWER_CONFIGURATION, SIGNAL_ATTR_UPDATED, + ZHA_DISCOVERY_NEW, ) from .entity import ZhaEntity from .sensor import battery_percentage_remaining_formatter @@ -56,7 +58,7 @@ class ZHADeviceScannerEntity(ScannerEntity, ZhaEntity): def __init__(self, **kwargs): """Initialize the ZHA device tracker.""" 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._keepalive_interval = 60 self._should_poll = True diff --git a/homeassistant/components/zha/entity.py b/homeassistant/components/zha/entity.py index 46cb7583ef3..dd5364b09e0 100644 --- a/homeassistant/components/zha/entity.py +++ b/homeassistant/components/zha/entity.py @@ -16,8 +16,8 @@ from .core.const import ( DATA_ZHA, DATA_ZHA_BRIDGE_ID, DOMAIN, - MODEL, - NAME, + ATTR_MODEL, + ATTR_NAME, SIGNAL_REMOVE, ) from .core.helpers import LogMixin @@ -99,8 +99,8 @@ class ZhaEntity(RestoreEntity, LogMixin, entity.Entity): "connections": {(CONNECTION_ZIGBEE, ieee)}, "identifiers": {(DOMAIN, ieee)}, ATTR_MANUFACTURER: zha_device_info[ATTR_MANUFACTURER], - MODEL: zha_device_info[MODEL], - NAME: zha_device_info[NAME], + ATTR_MODEL: zha_device_info[ATTR_MODEL], + ATTR_NAME: zha_device_info[ATTR_NAME], "via_device": (DOMAIN, self.hass.data[DATA_ZHA][DATA_ZHA_BRIDGE_ID]), } diff --git a/homeassistant/components/zha/fan.py b/homeassistant/components/zha/fan.py index 318e2962e54..e20d147006a 100644 --- a/homeassistant/components/zha/fan.py +++ b/homeassistant/components/zha/fan.py @@ -1,7 +1,6 @@ """Fans on Zigbee Home Automation networks.""" import logging -from homeassistant.core import callback from homeassistant.components.fan import ( DOMAIN, SPEED_HIGH, @@ -11,13 +10,15 @@ from homeassistant.components.fan import ( SUPPORT_SET_SPEED, FanEntity, ) +from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect + from .core.const import ( DATA_ZHA, DATA_ZHA_DISPATCHERS, - ZHA_DISCOVERY_NEW, - FAN_CHANNEL, + CHANNEL_FAN, SIGNAL_ATTR_UPDATED, + ZHA_DISCOVERY_NEW, ) from .entity import ZhaEntity @@ -91,7 +92,7 @@ class ZhaFan(ZhaEntity, FanEntity): def __init__(self, unique_id, zha_device, channels, **kwargs): """Init this sensor.""" 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): """Run when about to be added to hass.""" diff --git a/homeassistant/components/zha/light.py b/homeassistant/components/zha/light.py index 64b1897bb3a..80d6af81605 100644 --- a/homeassistant/components/zha/light.py +++ b/homeassistant/components/zha/light.py @@ -3,21 +3,23 @@ from datetime import timedelta import logging from zigpy.zcl.foundation import Status + from homeassistant.components import light from homeassistant.const import STATE_ON from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.event import async_track_time_interval import homeassistant.util.color as color_util + from .core.const import ( + CHANNEL_COLOR, DATA_ZHA, DATA_ZHA_DISPATCHERS, - ZHA_DISCOVERY_NEW, - COLOR_CHANNEL, - ON_OFF_CHANNEL, - LEVEL_CHANNEL, + CHANNEL_LEVEL, + CHANNEL_ON_OFF, SIGNAL_ATTR_UPDATED, SIGNAL_SET_LEVEL, + ZHA_DISCOVERY_NEW, ) from .entity import ZhaEntity @@ -83,9 +85,9 @@ class Light(ZhaEntity, light.Light): self._color_temp = None self._hs_color = None self._brightness = None - self._on_off_channel = self.cluster_channels.get(ON_OFF_CHANNEL) - self._level_channel = self.cluster_channels.get(LEVEL_CHANNEL) - self._color_channel = self.cluster_channels.get(COLOR_CHANNEL) + self._on_off_channel = self.cluster_channels.get(CHANNEL_ON_OFF) + self._level_channel = self.cluster_channels.get(CHANNEL_LEVEL) + self._color_channel = self.cluster_channels.get(CHANNEL_COLOR) if self._level_channel: self._supported_features |= light.SUPPORT_BRIGHTNESS diff --git a/homeassistant/components/zha/lock.py b/homeassistant/components/zha/lock.py index f3c6326d32d..a7b2d393012 100644 --- a/homeassistant/components/zha/lock.py +++ b/homeassistant/components/zha/lock.py @@ -2,20 +2,22 @@ import logging from zigpy.zcl.foundation import Status -from homeassistant.core import callback + from homeassistant.components.lock import ( DOMAIN, - STATE_UNLOCKED, STATE_LOCKED, + STATE_UNLOCKED, LockDevice, ) +from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect + from .core.const import ( DATA_ZHA, DATA_ZHA_DISPATCHERS, - ZHA_DISCOVERY_NEW, - DOORLOCK_CHANNEL, + CHANNEL_DOORLOCK, SIGNAL_ATTR_UPDATED, + ZHA_DISCOVERY_NEW, ) from .entity import ZhaEntity @@ -73,7 +75,7 @@ class ZhaDoorLock(ZhaEntity, LockDevice): def __init__(self, unique_id, zha_device, channels, **kwargs): """Init this sensor.""" 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): """Run when about to be added to hass.""" diff --git a/homeassistant/components/zha/sensor.py b/homeassistant/components/zha/sensor.py index fe0096dd150..df8e2add7dd 100644 --- a/homeassistant/components/zha/sensor.py +++ b/homeassistant/components/zha/sensor.py @@ -2,37 +2,38 @@ import logging import numbers -from homeassistant.core import callback from homeassistant.components.sensor import ( - DOMAIN, + DEVICE_CLASS_BATTERY, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, - DEVICE_CLASS_TEMPERATURE, - DEVICE_CLASS_PRESSURE, 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 .core.const import ( + CHANNEL_ATTRIBUTE, + SENSOR_BATTERY, DATA_ZHA, DATA_ZHA_DISPATCHERS, - ZHA_DISCOVERY_NEW, - HUMIDITY, - TEMPERATURE, - ILLUMINANCE, - PRESSURE, - METERING, - ELECTRICAL_MEASUREMENT, - GENERIC, + SENSOR_ELECTRICAL_MEASUREMENT, + CHANNEL_ELECTRICAL_MEASUREMENT, + SENSOR_GENERIC, + SENSOR_HUMIDITY, + SENSOR_ILLUMINANCE, + SENSOR_METERING, + CHANNEL_POWER_CONFIGURATION, + SENSOR_PRESSURE, SENSOR_TYPE, - ATTRIBUTE_CHANNEL, - ELECTRICAL_MEASUREMENT_CHANNEL, SIGNAL_ATTR_UPDATED, SIGNAL_STATE_ATTR, + SENSOR_TEMPERATURE, UNKNOWN, - BATTERY, - POWER_CONFIGURATION_CHANNEL, + ZHA_DISCOVERY_NEW, ) from .entity import ZhaEntity @@ -121,49 +122,49 @@ async def async_battery_device_state_attr_provider(channel): FORMATTER_FUNC_REGISTRY = { - HUMIDITY: humidity_formatter, - TEMPERATURE: temperature_formatter, - PRESSURE: pressure_formatter, - ELECTRICAL_MEASUREMENT: active_power_formatter, - ILLUMINANCE: illuminance_formatter, - GENERIC: pass_through_formatter, - BATTERY: battery_percentage_remaining_formatter, + SENSOR_HUMIDITY: humidity_formatter, + SENSOR_TEMPERATURE: temperature_formatter, + SENSOR_PRESSURE: pressure_formatter, + SENSOR_ELECTRICAL_MEASUREMENT: active_power_formatter, + SENSOR_ILLUMINANCE: illuminance_formatter, + SENSOR_GENERIC: pass_through_formatter, + SENSOR_BATTERY: battery_percentage_remaining_formatter, } UNIT_REGISTRY = { - HUMIDITY: "%", - TEMPERATURE: TEMP_CELSIUS, - PRESSURE: "hPa", - ILLUMINANCE: "lx", - METERING: POWER_WATT, - ELECTRICAL_MEASUREMENT: POWER_WATT, - GENERIC: None, - BATTERY: "%", + SENSOR_HUMIDITY: "%", + SENSOR_TEMPERATURE: TEMP_CELSIUS, + SENSOR_PRESSURE: "hPa", + SENSOR_ILLUMINANCE: "lx", + SENSOR_METERING: POWER_WATT, + SENSOR_ELECTRICAL_MEASUREMENT: POWER_WATT, + SENSOR_GENERIC: None, + SENSOR_BATTERY: "%", } CHANNEL_REGISTRY = { - ELECTRICAL_MEASUREMENT: ELECTRICAL_MEASUREMENT_CHANNEL, - BATTERY: POWER_CONFIGURATION_CHANNEL, + SENSOR_ELECTRICAL_MEASUREMENT: CHANNEL_ELECTRICAL_MEASUREMENT, + 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 = { UNKNOWN: None, - HUMIDITY: DEVICE_CLASS_HUMIDITY, - TEMPERATURE: DEVICE_CLASS_TEMPERATURE, - PRESSURE: DEVICE_CLASS_PRESSURE, - ILLUMINANCE: DEVICE_CLASS_ILLUMINANCE, - METERING: DEVICE_CLASS_POWER, - ELECTRICAL_MEASUREMENT: DEVICE_CLASS_POWER, - BATTERY: DEVICE_CLASS_BATTERY, + SENSOR_HUMIDITY: DEVICE_CLASS_HUMIDITY, + SENSOR_TEMPERATURE: DEVICE_CLASS_TEMPERATURE, + SENSOR_PRESSURE: DEVICE_CLASS_PRESSURE, + SENSOR_ILLUMINANCE: DEVICE_CLASS_ILLUMINANCE, + SENSOR_METERING: DEVICE_CLASS_POWER, + SENSOR_ELECTRICAL_MEASUREMENT: DEVICE_CLASS_POWER, + SENSOR_BATTERY: DEVICE_CLASS_BATTERY, } 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): """Init this sensor.""" 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._formatter_function = FORMATTER_FUNC_REGISTRY.get( 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._should_poll = POLLING_REGISTRY.get(self._sensor_type, False) 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.state_attr_provider = DEVICE_STATE_ATTR_PROVIDER_REGISTRY.get( diff --git a/homeassistant/components/zha/switch.py b/homeassistant/components/zha/switch.py index 853a50993ab..f2c00809d59 100644 --- a/homeassistant/components/zha/switch.py +++ b/homeassistant/components/zha/switch.py @@ -2,16 +2,18 @@ import logging from zigpy.zcl.foundation import Status + from homeassistant.components.switch import DOMAIN, SwitchDevice from homeassistant.const import STATE_ON from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect + from .core.const import ( DATA_ZHA, DATA_ZHA_DISPATCHERS, - ZHA_DISCOVERY_NEW, - ON_OFF_CHANNEL, + CHANNEL_ON_OFF, SIGNAL_ATTR_UPDATED, + ZHA_DISCOVERY_NEW, ) from .entity import ZhaEntity @@ -63,7 +65,7 @@ class Switch(ZhaEntity, SwitchDevice): def __init__(self, **kwargs): """Initialize the ZHA switch.""" 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 def is_on(self) -> bool: diff --git a/tests/components/zha/test_api.py b/tests/components/zha/test_api.py index 0eb5bb4f230..5bf891b132e 100644 --- a/tests/components/zha/test_api.py +++ b/tests/components/zha/test_api.py @@ -1,15 +1,15 @@ """Test ZHA API.""" import pytest 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 ( ATTR_CLUSTER_ID, ATTR_CLUSTER_TYPE, - IN, - IEEE, - MODEL, - NAME, - QUIRK_APPLIED, + CLUSTER_TYPE_IN, + ATTR_IEEE, + ATTR_MODEL, + ATTR_NAME, + ATTR_QUIRK_APPLIED, ATTR_MANUFACTURER, 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_info = cluster_infos[0] - assert cluster_info[TYPE] == IN + assert cluster_info[TYPE] == CLUSTER_TYPE_IN assert cluster_info[ID] == 0 - assert cluster_info[NAME] == "Basic" + assert cluster_info[ATTR_NAME] == "Basic" 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[NAME] == "OnOff" + assert cluster_info[ATTR_NAME] == "OnOff" 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_IEEE: "00:0d:6f:00:0a:90:69:e7", 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: 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): @@ -91,7 +91,7 @@ async def test_device_cluster_commands(hass, config_entry, zha_gateway, zha_clie ATTR_ENDPOINT_ID: 1, ATTR_IEEE: "00:0d:6f:00:0a:90:69:e7", 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: 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 @@ -116,13 +116,13 @@ async def test_list_devices(hass, config_entry, zha_gateway, zha_client): assert len(devices) == 1 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[MODEL] is not None - assert device[NAME] is not None - assert device[QUIRK_APPLIED] is not None + assert device[ATTR_MODEL] is not None + assert device[ATTR_NAME] is not None + assert device[ATTR_QUIRK_APPLIED] is not None assert device["entities"] is not None 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