Add dynamic subscription for ZHA add device page (#22164)
* add ws subscription for zha gateway messages * add debug mode * only relay certain logs * add missing require admin * add devices command * add area_id * fix manufacturer code
This commit is contained in:
parent
05db444832
commit
46ece3603f
3 changed files with 233 additions and 19 deletions
|
@ -10,13 +10,15 @@ import logging
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import websocket_api
|
from homeassistant.components import websocket_api
|
||||||
|
from homeassistant.core import callback
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.device_registry import async_get_registry
|
from homeassistant.helpers.device_registry import async_get_registry
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from .core.const import (
|
from .core.const import (
|
||||||
DOMAIN, ATTR_CLUSTER_ID, ATTR_CLUSTER_TYPE, ATTR_ATTRIBUTE, ATTR_VALUE,
|
DOMAIN, ATTR_CLUSTER_ID, ATTR_CLUSTER_TYPE, ATTR_ATTRIBUTE, ATTR_VALUE,
|
||||||
ATTR_MANUFACTURER, ATTR_COMMAND, ATTR_COMMAND_TYPE, ATTR_ARGS, IN, OUT,
|
ATTR_MANUFACTURER, ATTR_COMMAND, ATTR_COMMAND_TYPE, ATTR_ARGS, IN, OUT,
|
||||||
CLIENT_COMMANDS, SERVER_COMMANDS, SERVER, NAME, ATTR_ENDPOINT_ID,
|
CLIENT_COMMANDS, SERVER_COMMANDS, SERVER, NAME, ATTR_ENDPOINT_ID,
|
||||||
DATA_ZHA_GATEWAY, DATA_ZHA)
|
DATA_ZHA_GATEWAY, DATA_ZHA, MFG_CLUSTER_ID_START)
|
||||||
from .core.helpers import get_matched_clusters, async_is_bindable_target
|
from .core.helpers import get_matched_clusters, async_is_bindable_target
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -74,6 +76,38 @@ SERVICE_SCHEMAS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@websocket_api.require_admin
|
||||||
|
@websocket_api.async_response
|
||||||
|
@websocket_api.websocket_command({
|
||||||
|
vol.Required('type'): 'zha/devices/permit'
|
||||||
|
})
|
||||||
|
async def websocket_permit_devices(hass, connection, msg):
|
||||||
|
"""Permit ZHA zigbee devices."""
|
||||||
|
zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY]
|
||||||
|
|
||||||
|
async def forward_messages(data):
|
||||||
|
"""Forward events to websocket."""
|
||||||
|
connection.send_message(websocket_api.event_message(msg['id'], data))
|
||||||
|
|
||||||
|
remove_dispatcher_function = async_dispatcher_connect(
|
||||||
|
hass,
|
||||||
|
"zha_gateway_message",
|
||||||
|
forward_messages
|
||||||
|
)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_cleanup() -> None:
|
||||||
|
"""Remove signal listener and turn off debug mode."""
|
||||||
|
zha_gateway.async_disable_debug_mode()
|
||||||
|
remove_dispatcher_function()
|
||||||
|
|
||||||
|
connection.subscriptions[msg['id']] = async_cleanup
|
||||||
|
zha_gateway.async_enable_debug_mode()
|
||||||
|
await zha_gateway.application_controller.permit(60)
|
||||||
|
|
||||||
|
connection.send_result(msg['id'])
|
||||||
|
|
||||||
|
|
||||||
@websocket_api.require_admin
|
@websocket_api.require_admin
|
||||||
@websocket_api.async_response
|
@websocket_api.async_response
|
||||||
@websocket_api.websocket_command({
|
@websocket_api.websocket_command({
|
||||||
|
@ -86,22 +120,33 @@ async def websocket_get_devices(hass, connection, msg):
|
||||||
|
|
||||||
devices = []
|
devices = []
|
||||||
for device in zha_gateway.devices.values():
|
for device in zha_gateway.devices.values():
|
||||||
ret_device = {}
|
devices.append(
|
||||||
ret_device.update(device.device_info)
|
async_get_device_info(
|
||||||
ret_device['entities'] = [{
|
hass, device, ha_device_registry=ha_device_registry
|
||||||
'entity_id': entity_ref.reference_id,
|
)
|
||||||
NAME: entity_ref.device_info[NAME]
|
)
|
||||||
} for entity_ref in zha_gateway.device_registry[device.ieee]]
|
connection.send_result(msg[ID], devices)
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_get_device_info(hass, device, ha_device_registry=None):
|
||||||
|
"""Get ZHA device."""
|
||||||
|
zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY]
|
||||||
|
ret_device = {}
|
||||||
|
ret_device.update(device.device_info)
|
||||||
|
ret_device['entities'] = [{
|
||||||
|
'entity_id': entity_ref.reference_id,
|
||||||
|
NAME: entity_ref.device_info[NAME]
|
||||||
|
} for entity_ref in zha_gateway.device_registry[device.ieee]]
|
||||||
|
|
||||||
|
if ha_device_registry is not None:
|
||||||
reg_device = ha_device_registry.async_get_device(
|
reg_device = ha_device_registry.async_get_device(
|
||||||
{(DOMAIN, str(device.ieee))}, set())
|
{(DOMAIN, str(device.ieee))}, set())
|
||||||
if reg_device is not None:
|
if reg_device is not None:
|
||||||
ret_device['user_given_name'] = reg_device.name_by_user
|
ret_device['user_given_name'] = reg_device.name_by_user
|
||||||
ret_device['device_reg_id'] = reg_device.id
|
ret_device['device_reg_id'] = reg_device.id
|
||||||
|
ret_device['area_id'] = reg_device.area_id
|
||||||
devices.append(ret_device)
|
return ret_device
|
||||||
|
|
||||||
connection.send_result(msg[ID], devices)
|
|
||||||
|
|
||||||
|
|
||||||
@websocket_api.require_admin
|
@websocket_api.require_admin
|
||||||
|
@ -265,7 +310,10 @@ async def websocket_read_zigbee_cluster_attributes(hass, connection, msg):
|
||||||
cluster_id = msg[ATTR_CLUSTER_ID]
|
cluster_id = msg[ATTR_CLUSTER_ID]
|
||||||
cluster_type = msg[ATTR_CLUSTER_TYPE]
|
cluster_type = msg[ATTR_CLUSTER_TYPE]
|
||||||
attribute = msg[ATTR_ATTRIBUTE]
|
attribute = msg[ATTR_ATTRIBUTE]
|
||||||
manufacturer = msg.get(ATTR_MANUFACTURER) or None
|
manufacturer = None
|
||||||
|
# only use manufacturer code for manufacturer clusters
|
||||||
|
if cluster_id >= MFG_CLUSTER_ID_START:
|
||||||
|
manufacturer = msg.get(ATTR_MANUFACTURER) or None
|
||||||
zha_device = zha_gateway.get_device(ieee)
|
zha_device = zha_gateway.get_device(ieee)
|
||||||
success = failure = None
|
success = failure = None
|
||||||
if zha_device is not None:
|
if zha_device is not None:
|
||||||
|
@ -428,7 +476,10 @@ def async_load_api(hass):
|
||||||
cluster_type = service.data.get(ATTR_CLUSTER_TYPE)
|
cluster_type = service.data.get(ATTR_CLUSTER_TYPE)
|
||||||
attribute = service.data.get(ATTR_ATTRIBUTE)
|
attribute = service.data.get(ATTR_ATTRIBUTE)
|
||||||
value = service.data.get(ATTR_VALUE)
|
value = service.data.get(ATTR_VALUE)
|
||||||
manufacturer = service.data.get(ATTR_MANUFACTURER) or None
|
manufacturer = None
|
||||||
|
# only use manufacturer code for manufacturer clusters
|
||||||
|
if cluster_id >= MFG_CLUSTER_ID_START:
|
||||||
|
manufacturer = service.data.get(ATTR_MANUFACTURER) or None
|
||||||
zha_device = zha_gateway.get_device(ieee)
|
zha_device = zha_gateway.get_device(ieee)
|
||||||
response = None
|
response = None
|
||||||
if zha_device is not None:
|
if zha_device is not None:
|
||||||
|
@ -466,7 +517,10 @@ def async_load_api(hass):
|
||||||
command = service.data.get(ATTR_COMMAND)
|
command = service.data.get(ATTR_COMMAND)
|
||||||
command_type = service.data.get(ATTR_COMMAND_TYPE)
|
command_type = service.data.get(ATTR_COMMAND_TYPE)
|
||||||
args = service.data.get(ATTR_ARGS)
|
args = service.data.get(ATTR_ARGS)
|
||||||
manufacturer = service.data.get(ATTR_MANUFACTURER) or None
|
manufacturer = None
|
||||||
|
# only use manufacturer code for manufacturer clusters
|
||||||
|
if cluster_id >= MFG_CLUSTER_ID_START:
|
||||||
|
manufacturer = service.data.get(ATTR_MANUFACTURER) or None
|
||||||
zha_device = zha_gateway.get_device(ieee)
|
zha_device = zha_gateway.get_device(ieee)
|
||||||
response = None
|
response = None
|
||||||
if zha_device is not None:
|
if zha_device is not None:
|
||||||
|
@ -497,6 +551,7 @@ def async_load_api(hass):
|
||||||
SERVICE_ISSUE_ZIGBEE_CLUSTER_COMMAND
|
SERVICE_ISSUE_ZIGBEE_CLUSTER_COMMAND
|
||||||
])
|
])
|
||||||
|
|
||||||
|
websocket_api.async_register_command(hass, websocket_permit_devices)
|
||||||
websocket_api.async_register_command(hass, websocket_get_devices)
|
websocket_api.async_register_command(hass, websocket_get_devices)
|
||||||
websocket_api.async_register_command(hass, websocket_reconfigure_node)
|
websocket_api.async_register_command(hass, websocket_reconfigure_node)
|
||||||
websocket_api.async_register_command(hass, websocket_device_clusters)
|
websocket_api.async_register_command(hass, websocket_device_clusters)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""All constants related to the ZHA component."""
|
"""All constants related to the ZHA component."""
|
||||||
import enum
|
import enum
|
||||||
|
import logging
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR
|
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR
|
||||||
from homeassistant.components.fan import DOMAIN as FAN
|
from homeassistant.components.fan import DOMAIN as FAN
|
||||||
|
@ -106,6 +107,34 @@ QUIRK_CLASS = 'quirk_class'
|
||||||
MANUFACTURER_CODE = 'manufacturer_code'
|
MANUFACTURER_CODE = 'manufacturer_code'
|
||||||
POWER_SOURCE = 'power_source'
|
POWER_SOURCE = 'power_source'
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
class RadioType(enum.Enum):
|
class RadioType(enum.Enum):
|
||||||
"""Possible options for radio type."""
|
"""Possible options for radio type."""
|
||||||
|
|
|
@ -11,6 +11,8 @@ import itertools
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
from homeassistant.components.system_log import LogEntry, _figure_out_source
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
from homeassistant.helpers.entity_component import EntityComponent
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
|
@ -18,7 +20,11 @@ from .const import (
|
||||||
DATA_ZHA, DATA_ZHA_CORE_COMPONENT, DOMAIN, SIGNAL_REMOVE, DATA_ZHA_GATEWAY,
|
DATA_ZHA, DATA_ZHA_CORE_COMPONENT, DOMAIN, SIGNAL_REMOVE, DATA_ZHA_GATEWAY,
|
||||||
CONF_USB_PATH, CONF_BAUDRATE, DEFAULT_BAUDRATE, CONF_RADIO_TYPE,
|
CONF_USB_PATH, CONF_BAUDRATE, DEFAULT_BAUDRATE, CONF_RADIO_TYPE,
|
||||||
DATA_ZHA_RADIO, CONF_DATABASE, DEFAULT_DATABASE_NAME, DATA_ZHA_BRIDGE_ID,
|
DATA_ZHA_RADIO, CONF_DATABASE, DEFAULT_DATABASE_NAME, DATA_ZHA_BRIDGE_ID,
|
||||||
RADIO, CONTROLLER, RADIO_DESCRIPTION
|
RADIO, CONTROLLER, RADIO_DESCRIPTION, BELLOWS, ZHA, ZIGPY, ZIGPY_XBEE,
|
||||||
|
ZIGPY_DECONZ, ORIGINAL, CURRENT, DEBUG_LEVELS, ADD_DEVICE_RELAY_LOGGERS,
|
||||||
|
TYPE, NWK, IEEE, MODEL, SIGNATURE, ATTR_MANUFACTURER, RAW_INIT,
|
||||||
|
ZHA_GW_MSG, DEVICE_REMOVED, DEVICE_INFO, DEVICE_FULL_INIT, DEVICE_JOINED,
|
||||||
|
LOG_OUTPUT, LOG_ENTRY
|
||||||
)
|
)
|
||||||
from .device import ZHADevice, DeviceStatus
|
from .device import ZHADevice, DeviceStatus
|
||||||
from .channels import (
|
from .channels import (
|
||||||
|
@ -32,6 +38,7 @@ from .discovery import (
|
||||||
from .store import async_get_registry
|
from .store import async_get_registry
|
||||||
from .patches import apply_application_controller_patch
|
from .patches import apply_application_controller_patch
|
||||||
from .registries import RADIO_TYPES
|
from .registries import RADIO_TYPES
|
||||||
|
from ..api import async_get_device_info
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -54,6 +61,12 @@ class ZHAGateway:
|
||||||
self.radio_description = None
|
self.radio_description = None
|
||||||
hass.data[DATA_ZHA][DATA_ZHA_CORE_COMPONENT] = self._component
|
hass.data[DATA_ZHA][DATA_ZHA_CORE_COMPONENT] = self._component
|
||||||
hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] = self
|
hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] = self
|
||||||
|
self._log_levels = {
|
||||||
|
ORIGINAL: async_capture_log_levels(),
|
||||||
|
CURRENT: async_capture_log_levels()
|
||||||
|
}
|
||||||
|
self.debug_enabled = False
|
||||||
|
self._log_relay_handler = LogRelayHandler(hass, self)
|
||||||
|
|
||||||
async def async_initialize(self, config_entry):
|
async def async_initialize(self, config_entry):
|
||||||
"""Initialize controller and connect radio."""
|
"""Initialize controller and connect radio."""
|
||||||
|
@ -94,13 +107,37 @@ class ZHAGateway:
|
||||||
At this point, no information about the device is known other than its
|
At this point, no information about the device is known other than its
|
||||||
address
|
address
|
||||||
"""
|
"""
|
||||||
# Wait for device_initialized, instead
|
async_dispatcher_send(
|
||||||
pass
|
self._hass,
|
||||||
|
ZHA_GW_MSG,
|
||||||
|
{
|
||||||
|
TYPE: DEVICE_JOINED,
|
||||||
|
NWK: device.nwk,
|
||||||
|
IEEE: str(device.ieee)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
def raw_device_initialized(self, device):
|
def raw_device_initialized(self, device):
|
||||||
"""Handle a device initialization without quirks loaded."""
|
"""Handle a device initialization without quirks loaded."""
|
||||||
# Wait for device_initialized, instead
|
endpoint_ids = device.endpoints.keys()
|
||||||
pass
|
ept_id = next((ept_id for ept_id in endpoint_ids if ept_id != 0), None)
|
||||||
|
manufacturer = 'Unknown'
|
||||||
|
model = 'Unknown'
|
||||||
|
if ept_id is not None:
|
||||||
|
manufacturer = device.endpoints[ept_id].manufacturer
|
||||||
|
model = device.endpoints[ept_id].model
|
||||||
|
async_dispatcher_send(
|
||||||
|
self._hass,
|
||||||
|
ZHA_GW_MSG,
|
||||||
|
{
|
||||||
|
TYPE: RAW_INIT,
|
||||||
|
NWK: device.nwk,
|
||||||
|
IEEE: str(device.ieee),
|
||||||
|
MODEL: model,
|
||||||
|
ATTR_MANUFACTURER: manufacturer,
|
||||||
|
SIGNATURE: device.get_signature()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
def device_initialized(self, device):
|
def device_initialized(self, device):
|
||||||
"""Handle device joined and basic information discovered."""
|
"""Handle device joined and basic information discovered."""
|
||||||
|
@ -116,11 +153,21 @@ class ZHAGateway:
|
||||||
device = self._devices.pop(device.ieee, None)
|
device = self._devices.pop(device.ieee, None)
|
||||||
self._device_registry.pop(device.ieee, None)
|
self._device_registry.pop(device.ieee, None)
|
||||||
if device is not None:
|
if device is not None:
|
||||||
|
device_info = async_get_device_info(self._hass, device)
|
||||||
self._hass.async_create_task(device.async_unsub_dispatcher())
|
self._hass.async_create_task(device.async_unsub_dispatcher())
|
||||||
async_dispatcher_send(
|
async_dispatcher_send(
|
||||||
self._hass,
|
self._hass,
|
||||||
"{}_{}".format(SIGNAL_REMOVE, str(device.ieee))
|
"{}_{}".format(SIGNAL_REMOVE, str(device.ieee))
|
||||||
)
|
)
|
||||||
|
if device_info is not None:
|
||||||
|
async_dispatcher_send(
|
||||||
|
self._hass,
|
||||||
|
ZHA_GW_MSG,
|
||||||
|
{
|
||||||
|
TYPE: DEVICE_REMOVED,
|
||||||
|
DEVICE_INFO: device_info
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
def get_device(self, ieee_str):
|
def get_device(self, ieee_str):
|
||||||
"""Return ZHADevice for given ieee."""
|
"""Return ZHADevice for given ieee."""
|
||||||
|
@ -157,6 +204,28 @@ class ZHAGateway:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_enable_debug_mode(self):
|
||||||
|
"""Enable debug mode for ZHA."""
|
||||||
|
self._log_levels[ORIGINAL] = async_capture_log_levels()
|
||||||
|
async_set_logger_levels(DEBUG_LEVELS)
|
||||||
|
self._log_levels[CURRENT] = async_capture_log_levels()
|
||||||
|
|
||||||
|
for logger_name in ADD_DEVICE_RELAY_LOGGERS:
|
||||||
|
logging.getLogger(logger_name).addHandler(self._log_relay_handler)
|
||||||
|
|
||||||
|
self.debug_enabled = True
|
||||||
|
|
||||||
|
@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:
|
||||||
|
logging.getLogger(logger_name).removeHandler(
|
||||||
|
self._log_relay_handler)
|
||||||
|
self.debug_enabled = False
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_get_or_create_device(self, zigpy_device, is_new_join):
|
def _async_get_or_create_device(self, zigpy_device, is_new_join):
|
||||||
"""Get or create a ZHA device."""
|
"""Get or create a ZHA device."""
|
||||||
|
@ -231,3 +300,64 @@ class ZHAGateway:
|
||||||
|
|
||||||
device_entity = async_create_device_entity(zha_device)
|
device_entity = async_create_device_entity(zha_device)
|
||||||
await self._component.async_add_entities([device_entity])
|
await self._component.async_add_entities([device_entity])
|
||||||
|
|
||||||
|
if is_new_join:
|
||||||
|
device_info = async_get_device_info(self._hass, zha_device)
|
||||||
|
async_dispatcher_send(
|
||||||
|
self._hass,
|
||||||
|
ZHA_GW_MSG,
|
||||||
|
{
|
||||||
|
TYPE: DEVICE_FULL_INIT,
|
||||||
|
DEVICE_INFO: device_info
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
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(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@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])
|
||||||
|
|
||||||
|
|
||||||
|
class LogRelayHandler(logging.Handler):
|
||||||
|
"""Log handler for error messages."""
|
||||||
|
|
||||||
|
def __init__(self, hass, gateway):
|
||||||
|
"""Initialize a new LogErrorHandler."""
|
||||||
|
super().__init__()
|
||||||
|
self.hass = hass
|
||||||
|
self.gateway = gateway
|
||||||
|
|
||||||
|
def emit(self, record):
|
||||||
|
"""Relay log message via dispatcher."""
|
||||||
|
stack = []
|
||||||
|
if record.levelno >= logging.WARN:
|
||||||
|
if not record.exc_info:
|
||||||
|
stack = [f for f, _, _, _ in traceback.extract_stack()]
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue