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_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

View file

@ -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(

View file

@ -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):

View file

@ -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):

View file

@ -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

View file

@ -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__)

View file

@ -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."""

View file

@ -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

View file

@ -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__)

View file

@ -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,
}
)

View file

@ -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__)

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.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"

View file

@ -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
)

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.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(

View file

@ -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()},
)

View file

@ -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

View file

@ -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)

View file

@ -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__)

View file

@ -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

View file

@ -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]),
}

View file

@ -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."""

View file

@ -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

View file

@ -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."""

View file

@ -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(

View file

@ -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:

View file

@ -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