Switch Netatmo integration to dispatcher for internal communication (#38590)
* Switch to dispatcher for internal communication * Fix method call * Update homeassistant/components/netatmo/camera.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/netatmo/camera.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/netatmo/climate.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/netatmo/climate.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Rename variables Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
3546a82cfb
commit
6930aebea2
7 changed files with 170 additions and 165 deletions
homeassistant/components/netatmo
|
@ -5,14 +5,10 @@ import pyatmo
|
|||
import requests
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.camera import (
|
||||
DOMAIN as CAMERA_DOMAIN,
|
||||
SUPPORT_STREAM,
|
||||
Camera,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from homeassistant.components.camera import SUPPORT_STREAM, Camera
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
from .const import (
|
||||
ATTR_PERSON,
|
||||
|
@ -21,10 +17,12 @@ from .const import (
|
|||
DATA_HANDLER,
|
||||
DATA_PERSONS,
|
||||
DOMAIN,
|
||||
EVENT_TYPE_OFF,
|
||||
EVENT_TYPE_ON,
|
||||
MANUFACTURER,
|
||||
MODELS,
|
||||
SERVICE_SETPERSONAWAY,
|
||||
SERVICE_SETPERSONSHOME,
|
||||
SERVICE_SET_PERSON_AWAY,
|
||||
SERVICE_SET_PERSONS_HOME,
|
||||
SIGNAL_NAME,
|
||||
)
|
||||
from .data_handler import CAMERA_DATA_CLASS_NAME
|
||||
|
@ -34,20 +32,6 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
DEFAULT_QUALITY = "high"
|
||||
|
||||
SCHEMA_SERVICE_SETPERSONSHOME = vol.Schema(
|
||||
{
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_domain(CAMERA_DOMAIN),
|
||||
vol.Required(ATTR_PERSONS): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
)
|
||||
|
||||
SCHEMA_SERVICE_SETPERSONAWAY = vol.Schema(
|
||||
{
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_domain(CAMERA_DOMAIN),
|
||||
vol.Optional(ATTR_PERSON): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, entry, async_add_entities):
|
||||
"""Set up the Netatmo camera platform."""
|
||||
|
@ -108,22 +92,17 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
|||
|
||||
if data_handler.data[CAMERA_DATA_CLASS_NAME] is not None:
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SETPERSONSHOME,
|
||||
SCHEMA_SERVICE_SETPERSONSHOME,
|
||||
"_service_setpersonshome",
|
||||
SERVICE_SET_PERSONS_HOME,
|
||||
{vol.Required(ATTR_PERSONS): vol.All(cv.ensure_list, [cv.string])},
|
||||
"_service_set_persons_home",
|
||||
)
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SETPERSONAWAY,
|
||||
SCHEMA_SERVICE_SETPERSONAWAY,
|
||||
"_service_setpersonaway",
|
||||
SERVICE_SET_PERSON_AWAY,
|
||||
{vol.Optional(ATTR_PERSON): cv.string},
|
||||
"_service_set_person_away",
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the Netatmo camera platform."""
|
||||
return
|
||||
|
||||
|
||||
class NetatmoCamera(NetatmoBase, Camera):
|
||||
"""Representation of a Netatmo camera."""
|
||||
|
||||
|
@ -156,16 +135,19 @@ class NetatmoCamera(NetatmoBase, Camera):
|
|||
"""Entity created."""
|
||||
await super().async_added_to_hass()
|
||||
|
||||
self._listeners.append(
|
||||
self.hass.bus.async_listen("netatmo_event", self.handle_event)
|
||||
)
|
||||
for event_type in (EVENT_TYPE_OFF, EVENT_TYPE_ON):
|
||||
self._listeners.append(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
f"signal-{DOMAIN}-webhook-{event_type}",
|
||||
self.handle_event,
|
||||
)
|
||||
)
|
||||
|
||||
async def handle_event(self, event):
|
||||
@callback
|
||||
def handle_event(self, event):
|
||||
"""Handle webhook events."""
|
||||
data = event.data["data"]
|
||||
|
||||
if not data.get("event_type"):
|
||||
return
|
||||
data = event["data"]
|
||||
|
||||
if not data.get("camera_id"):
|
||||
return
|
||||
|
@ -278,7 +260,7 @@ class NetatmoCamera(NetatmoBase, Camera):
|
|||
self._is_local = camera.get("is_local")
|
||||
self.is_streaming = bool(self._status == "on")
|
||||
|
||||
def _service_setpersonshome(self, **kwargs):
|
||||
def _service_set_persons_home(self, **kwargs):
|
||||
"""Service to change current home schedule."""
|
||||
persons = kwargs.get(ATTR_PERSONS)
|
||||
person_ids = []
|
||||
|
@ -288,9 +270,9 @@ class NetatmoCamera(NetatmoBase, Camera):
|
|||
person_ids.append(pid)
|
||||
|
||||
self._data.set_persons_home(person_ids=person_ids, home_id=self._home_id)
|
||||
_LOGGER.info("Set %s as at home", persons)
|
||||
_LOGGER.debug("Set %s as at home", persons)
|
||||
|
||||
def _service_setpersonaway(self, **kwargs):
|
||||
def _service_set_person_away(self, **kwargs):
|
||||
"""Service to mark a person as away or set the home as empty."""
|
||||
person = kwargs.get(ATTR_PERSON)
|
||||
person_id = None
|
||||
|
@ -303,10 +285,10 @@ class NetatmoCamera(NetatmoBase, Camera):
|
|||
self._data.set_persons_away(
|
||||
person_id=person_id, home_id=self._home_id,
|
||||
)
|
||||
_LOGGER.info("Set %s as away", person)
|
||||
_LOGGER.debug("Set %s as away", person)
|
||||
|
||||
else:
|
||||
self._data.set_persons_away(
|
||||
person_id=person_id, home_id=self._home_id,
|
||||
)
|
||||
_LOGGER.info("Set home as empty")
|
||||
_LOGGER.debug("Set home as empty")
|
||||
|
|
|
@ -4,7 +4,7 @@ from typing import List, Optional
|
|||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN, ClimateEntity
|
||||
from homeassistant.components.climate import ClimateEntity
|
||||
from homeassistant.components.climate.const import (
|
||||
CURRENT_HVAC_HEAT,
|
||||
CURRENT_HVAC_IDLE,
|
||||
|
@ -19,7 +19,6 @@ from homeassistant.components.climate.const import (
|
|||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_BATTERY_LEVEL,
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_TEMPERATURE,
|
||||
PRECISION_HALVES,
|
||||
STATE_OFF,
|
||||
|
@ -27,6 +26,7 @@ from homeassistant.const import (
|
|||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
from .const import (
|
||||
ATTR_HEATING_POWER_REQUEST,
|
||||
|
@ -35,8 +35,11 @@ from .const import (
|
|||
DATA_HOMES,
|
||||
DATA_SCHEDULES,
|
||||
DOMAIN,
|
||||
EVENT_TYPE_CANCEL_SET_POINT,
|
||||
EVENT_TYPE_SET_POINT,
|
||||
EVENT_TYPE_THERM_MODE,
|
||||
MANUFACTURER,
|
||||
SERVICE_SETSCHEDULE,
|
||||
SERVICE_SET_SCHEDULE,
|
||||
SIGNAL_NAME,
|
||||
)
|
||||
from .data_handler import HOMEDATA_DATA_CLASS_NAME, HOMESTATUS_DATA_CLASS_NAME
|
||||
|
@ -95,13 +98,6 @@ DEFAULT_MAX_TEMP = 30
|
|||
NA_THERM = "NATherm1"
|
||||
NA_VALVE = "NRV"
|
||||
|
||||
SCHEMA_SERVICE_SETSCHEDULE = vol.Schema(
|
||||
{
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_domain(CLIMATE_DOMAIN),
|
||||
vol.Required(ATTR_SCHEDULE_NAME): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, entry, async_add_entities):
|
||||
"""Set up the Netatmo energy platform."""
|
||||
|
@ -156,15 +152,12 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
|||
|
||||
if home_data is not None:
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SETSCHEDULE, SCHEMA_SERVICE_SETSCHEDULE, "_service_setschedule",
|
||||
SERVICE_SET_SCHEDULE,
|
||||
{vol.Required(ATTR_SCHEDULE_NAME): cv.string},
|
||||
"_service_set_schedule",
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the Netatmo energy sensors."""
|
||||
return
|
||||
|
||||
|
||||
class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
||||
"""Representation a Netatmo thermostat."""
|
||||
|
||||
|
@ -229,23 +222,29 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
|||
"""Entity created."""
|
||||
await super().async_added_to_hass()
|
||||
|
||||
self._listeners.append(
|
||||
self.hass.bus.async_listen("netatmo_event", self.handle_event)
|
||||
)
|
||||
for event_type in (
|
||||
EVENT_TYPE_SET_POINT,
|
||||
EVENT_TYPE_THERM_MODE,
|
||||
EVENT_TYPE_CANCEL_SET_POINT,
|
||||
):
|
||||
self._listeners.append(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
f"signal-{DOMAIN}-webhook-{event_type}",
|
||||
self.handle_event,
|
||||
)
|
||||
)
|
||||
|
||||
async def handle_event(self, event):
|
||||
"""Handle webhook events."""
|
||||
data = event.data["data"]
|
||||
|
||||
if not data.get("event_type"):
|
||||
return
|
||||
data = event["data"]
|
||||
|
||||
if not data.get("home"):
|
||||
return
|
||||
|
||||
home = data["home"]
|
||||
if self._home_id == home["id"] and data["event_type"] == "therm_mode":
|
||||
self._preset = NETATMO_MAP_PRESET[home["therm_mode"]]
|
||||
if self._home_id == home["id"] and data["event_type"] == EVENT_TYPE_THERM_MODE:
|
||||
self._preset = NETATMO_MAP_PRESET[home[EVENT_TYPE_THERM_MODE]]
|
||||
self._hvac_mode = HVAC_MAP_NETATMO[self._preset]
|
||||
if self._preset == PRESET_FROST_GUARD:
|
||||
self._target_temperature = self._hg_temperature
|
||||
|
@ -260,7 +259,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
|||
return
|
||||
|
||||
for room in home["rooms"]:
|
||||
if data["event_type"] == "set_point":
|
||||
if data["event_type"] == EVENT_TYPE_SET_POINT:
|
||||
if self._id == room["id"]:
|
||||
if room["therm_setpoint_mode"] == "off":
|
||||
self._hvac_mode = HVAC_MODE_OFF
|
||||
|
@ -269,7 +268,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
|||
self.async_write_ha_state()
|
||||
break
|
||||
|
||||
elif data["event_type"] == "cancel_set_point":
|
||||
elif data["event_type"] == EVENT_TYPE_CANCEL_SET_POINT:
|
||||
if self._id == room["id"]:
|
||||
self.async_update_callback()
|
||||
self.async_write_ha_state()
|
||||
|
@ -411,10 +410,20 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
|||
def async_update_callback(self):
|
||||
"""Update the entity's state."""
|
||||
self._home_status = self.data_handler.data[self._home_status_class]
|
||||
self._room_status = self._home_status.rooms[self._id]
|
||||
self._room_data = self._data.rooms[self._home_id][self._id]
|
||||
self._room_status = self._home_status.rooms.get(self._id)
|
||||
self._room_data = self._data.rooms.get(self._home_id, {}).get(self._id)
|
||||
|
||||
roomstatus = {"roomID": self._room_status["id"]}
|
||||
if not self._room_status or not self._room_data:
|
||||
if self._connected:
|
||||
_LOGGER.info(
|
||||
"The thermostat in room %s seems to be out of reach",
|
||||
self._device_name,
|
||||
)
|
||||
|
||||
self._connected = False
|
||||
return
|
||||
|
||||
roomstatus = {"roomID": self._room_status.get("id", {})}
|
||||
if self._room_status.get("reachable"):
|
||||
roomstatus.update(self._build_room_status())
|
||||
|
||||
|
@ -422,25 +431,17 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
|||
self._hg_temperature = self._data.get_hg_temp(self._home_id)
|
||||
self._setpoint_duration = self._data.setpoint_duration[self._home_id]
|
||||
|
||||
try:
|
||||
if self._model is None:
|
||||
self._model = roomstatus["module_type"]
|
||||
self._current_temperature = roomstatus["current_temperature"]
|
||||
self._target_temperature = roomstatus["target_temperature"]
|
||||
self._preset = NETATMO_MAP_PRESET[roomstatus["setpoint_mode"]]
|
||||
self._hvac_mode = HVAC_MAP_NETATMO[self._preset]
|
||||
self._battery_level = roomstatus.get("battery_level")
|
||||
self._connected = True
|
||||
if "current_temperature" not in roomstatus:
|
||||
return
|
||||
|
||||
except KeyError as err:
|
||||
if self._connected:
|
||||
_LOGGER.debug(
|
||||
"The thermostat in room %s seems to be out of reach. (%s)",
|
||||
self._device_name,
|
||||
err,
|
||||
)
|
||||
|
||||
self._connected = False
|
||||
if self._model is None:
|
||||
self._model = roomstatus["module_type"]
|
||||
self._current_temperature = roomstatus["current_temperature"]
|
||||
self._target_temperature = roomstatus["target_temperature"]
|
||||
self._preset = NETATMO_MAP_PRESET[roomstatus["setpoint_mode"]]
|
||||
self._hvac_mode = HVAC_MAP_NETATMO[self._preset]
|
||||
self._battery_level = roomstatus.get("battery_level")
|
||||
self._connected = True
|
||||
|
||||
self._away = self._hvac_mode == HVAC_MAP_NETATMO[STATE_NETATMO_AWAY]
|
||||
|
||||
|
@ -503,7 +504,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
|||
|
||||
return {}
|
||||
|
||||
def _service_setschedule(self, **kwargs):
|
||||
def _service_set_schedule(self, **kwargs):
|
||||
schedule_name = kwargs.get(ATTR_SCHEDULE_NAME)
|
||||
schedule_id = None
|
||||
for sid, name in self.hass.data[DOMAIN][DATA_SCHEDULES][self._home_id].items():
|
||||
|
@ -515,7 +516,7 @@ class NetatmoThermostat(NetatmoBase, ClimateEntity):
|
|||
return
|
||||
|
||||
self._data.switch_home_schedule(home_id=self._home_id, schedule_id=schedule_id)
|
||||
_LOGGER.info(
|
||||
_LOGGER.debug(
|
||||
"Setting %s schedule to %s (%s)",
|
||||
self._home_id,
|
||||
kwargs.get(ATTR_SCHEDULE_NAME),
|
||||
|
|
|
@ -69,7 +69,7 @@ class NetatmoFlowHandler(
|
|||
"""Handle a flow start."""
|
||||
await self.async_set_unique_id(DOMAIN)
|
||||
|
||||
if self.hass.config_entries.async_entries(DOMAIN):
|
||||
if self._async_current_entries():
|
||||
return self.async_abort(reason="single_instance_allowed")
|
||||
|
||||
return await super().async_step_user(user_input)
|
||||
|
@ -108,7 +108,7 @@ class NetatmoOptionsFlowHandler(config_entries.OptionsFlow):
|
|||
user_input={CONF_NEW_AREA: new_client}
|
||||
)
|
||||
|
||||
return self._update_options()
|
||||
return self._create_options_entry()
|
||||
|
||||
weather_areas = list(self.options[CONF_WEATHER_AREAS])
|
||||
|
||||
|
@ -183,7 +183,7 @@ class NetatmoOptionsFlowHandler(config_entries.OptionsFlow):
|
|||
|
||||
return self.async_show_form(step_id="public_weather", data_schema=data_schema)
|
||||
|
||||
def _update_options(self):
|
||||
def _create_options_entry(self):
|
||||
"""Update config entry options."""
|
||||
return self.async_create_entry(
|
||||
title="Netatmo Public Weather", data=self.options
|
||||
|
|
|
@ -73,6 +73,13 @@ ATTR_SCHEDULE_NAME = "schedule_name"
|
|||
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=5)
|
||||
MIN_TIME_BETWEEN_EVENT_UPDATES = timedelta(seconds=5)
|
||||
|
||||
SERVICE_SETSCHEDULE = "set_schedule"
|
||||
SERVICE_SETPERSONSHOME = "set_persons_home"
|
||||
SERVICE_SETPERSONAWAY = "set_person_away"
|
||||
SERVICE_SET_SCHEDULE = "set_schedule"
|
||||
SERVICE_SET_PERSONS_HOME = "set_persons_home"
|
||||
SERVICE_SET_PERSON_AWAY = "set_person_away"
|
||||
|
||||
EVENT_TYPE_CANCEL_SET_POINT = "cancel_set_point"
|
||||
EVENT_TYPE_LIGHT_MODE = "light_mode"
|
||||
EVENT_TYPE_OFF = "off"
|
||||
EVENT_TYPE_ON = "on"
|
||||
EVENT_TYPE_SET_POINT = "set_point"
|
||||
EVENT_TYPE_THERM_MODE = "therm_mode"
|
||||
|
|
|
@ -11,6 +11,7 @@ import pyatmo
|
|||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
|
||||
from .const import AUTH, DOMAIN, MANUFACTURER
|
||||
|
@ -69,7 +70,9 @@ class NetatmoDataHandler:
|
|||
)
|
||||
|
||||
self.listeners.append(
|
||||
self.hass.bus.async_listen("netatmo_event", self.handle_event)
|
||||
async_dispatcher_connect(
|
||||
self.hass, f"signal-{DOMAIN}-webhook-None", self.handle_event,
|
||||
)
|
||||
)
|
||||
|
||||
async def async_update(self, event_time):
|
||||
|
@ -99,11 +102,11 @@ class NetatmoDataHandler:
|
|||
|
||||
async def handle_event(self, event):
|
||||
"""Handle webhook events."""
|
||||
if event.data["data"]["push_type"] == "webhook_activation":
|
||||
if event["data"]["push_type"] == "webhook_activation":
|
||||
_LOGGER.info("%s webhook successfully registered", MANUFACTURER)
|
||||
self._webhook = True
|
||||
|
||||
elif event.data["data"]["push_type"] == "NACamera-connection":
|
||||
elif event["data"]["push_type"] == "NACamera-connection":
|
||||
_LOGGER.debug("%s camera reconnected", MANUFACTURER)
|
||||
self._data_classes[CAMERA_DATA_CLASS_NAME][NEXT_SCAN] = time()
|
||||
|
||||
|
@ -126,27 +129,27 @@ class NetatmoDataHandler:
|
|||
self, data_class_name, data_class_entry, update_callback, **kwargs
|
||||
):
|
||||
"""Register data class."""
|
||||
if data_class_entry not in self._data_classes:
|
||||
self._data_classes[data_class_entry] = {
|
||||
"class": DATA_CLASSES[data_class_name],
|
||||
"name": data_class_entry,
|
||||
"interval": DEFAULT_INTERVALS[data_class_name],
|
||||
NEXT_SCAN: time() + DEFAULT_INTERVALS[data_class_name],
|
||||
"kwargs": kwargs,
|
||||
"subscriptions": [update_callback],
|
||||
}
|
||||
|
||||
await self.async_fetch_data(
|
||||
DATA_CLASSES[data_class_name], data_class_entry, **kwargs
|
||||
)
|
||||
|
||||
self._queue.append(self._data_classes[data_class_entry])
|
||||
_LOGGER.debug("Data class %s added", data_class_entry)
|
||||
|
||||
else:
|
||||
if data_class_entry in self._data_classes:
|
||||
self._data_classes[data_class_entry]["subscriptions"].append(
|
||||
update_callback
|
||||
)
|
||||
return
|
||||
|
||||
self._data_classes[data_class_entry] = {
|
||||
"class": DATA_CLASSES[data_class_name],
|
||||
"name": data_class_entry,
|
||||
"interval": DEFAULT_INTERVALS[data_class_name],
|
||||
NEXT_SCAN: time() + DEFAULT_INTERVALS[data_class_name],
|
||||
"kwargs": kwargs,
|
||||
"subscriptions": [update_callback],
|
||||
}
|
||||
|
||||
await self.async_fetch_data(
|
||||
DATA_CLASSES[data_class_name], data_class_entry, **kwargs
|
||||
)
|
||||
|
||||
self._queue.append(self._data_classes[data_class_entry])
|
||||
_LOGGER.debug("Data class %s added", data_class_entry)
|
||||
|
||||
async def unregister_data_class(self, data_class_entry, update_callback):
|
||||
"""Unregister data class."""
|
||||
|
|
|
@ -6,8 +6,15 @@ import pyatmo
|
|||
from homeassistant.components.light import LightEntity
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
from .const import DATA_HANDLER, DOMAIN, MANUFACTURER, SIGNAL_NAME
|
||||
from .const import (
|
||||
DATA_HANDLER,
|
||||
DOMAIN,
|
||||
EVENT_TYPE_LIGHT_MODE,
|
||||
MANUFACTURER,
|
||||
SIGNAL_NAME,
|
||||
)
|
||||
from .data_handler import CAMERA_DATA_CLASS_NAME, NetatmoDataHandler
|
||||
from .netatmo_entity_base import NetatmoBase
|
||||
|
||||
|
@ -31,42 +38,36 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
|||
)
|
||||
|
||||
entities = []
|
||||
all_cameras = []
|
||||
|
||||
if CAMERA_DATA_CLASS_NAME not in data_handler.data:
|
||||
raise PlatformNotReady
|
||||
|
||||
try:
|
||||
all_cameras = []
|
||||
for home in data_handler.data[CAMERA_DATA_CLASS_NAME].cameras.values():
|
||||
for camera in home.values():
|
||||
all_cameras.append(camera)
|
||||
|
||||
for camera in all_cameras:
|
||||
if camera["type"] == "NOC":
|
||||
if not data_handler.webhook:
|
||||
raise PlatformNotReady
|
||||
|
||||
_LOGGER.debug(
|
||||
"Adding camera light %s %s", camera["id"], camera["name"]
|
||||
)
|
||||
entities.append(
|
||||
NetatmoLight(
|
||||
data_handler,
|
||||
camera["id"],
|
||||
camera["type"],
|
||||
camera["home_id"],
|
||||
)
|
||||
)
|
||||
|
||||
except pyatmo.NoDevice:
|
||||
_LOGGER.debug("No cameras found")
|
||||
|
||||
for camera in all_cameras:
|
||||
if camera["type"] == "NOC":
|
||||
if not data_handler.webhook:
|
||||
raise PlatformNotReady
|
||||
|
||||
_LOGGER.debug("Adding camera light %s %s", camera["id"], camera["name"])
|
||||
entities.append(
|
||||
NetatmoLight(
|
||||
data_handler, camera["id"], camera["type"], camera["home_id"],
|
||||
)
|
||||
)
|
||||
|
||||
return entities
|
||||
|
||||
async_add_entities(await get_entities(), True)
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the Netatmo camera platform."""
|
||||
return
|
||||
|
||||
|
||||
class NetatmoLight(NetatmoBase, LightEntity):
|
||||
"""Representation of a Netatmo Presence camera light."""
|
||||
|
||||
|
@ -97,15 +98,17 @@ class NetatmoLight(NetatmoBase, LightEntity):
|
|||
await super().async_added_to_hass()
|
||||
|
||||
self._listeners.append(
|
||||
self.hass.bus.async_listen("netatmo_event", self.handle_event)
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
f"signal-{DOMAIN}-webhook-{EVENT_TYPE_LIGHT_MODE}",
|
||||
self.handle_event,
|
||||
)
|
||||
)
|
||||
|
||||
async def handle_event(self, event):
|
||||
@callback
|
||||
def handle_event(self, event):
|
||||
"""Handle webhook events."""
|
||||
data = event.data["data"]
|
||||
|
||||
if not data.get("event_type"):
|
||||
return
|
||||
data = event["data"]
|
||||
|
||||
if not data.get("camera_id"):
|
||||
return
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import logging
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
|
||||
from .const import (
|
||||
ATTR_EVENT_TYPE,
|
||||
|
@ -36,10 +37,9 @@ async def handle_webhook(hass, webhook_id, request):
|
|||
|
||||
event_type = data.get(ATTR_EVENT_TYPE)
|
||||
|
||||
if event_type in ["outdoor", "therm_mode"]:
|
||||
hass.bus.async_fire(
|
||||
event_type=NETATMO_EVENT, event_data={"type": event_type, "data": data}
|
||||
)
|
||||
if event_type in EVENT_TYPE_MAP:
|
||||
async_send_event(hass, event_type, data)
|
||||
|
||||
for event_data in data.get(EVENT_TYPE_MAP[event_type], []):
|
||||
async_evaluate_event(hass, event_data)
|
||||
|
||||
|
@ -61,13 +61,22 @@ def async_evaluate_event(hass, event_data):
|
|||
)
|
||||
person_event_data[ATTR_IS_KNOWN] = person.get(ATTR_IS_KNOWN)
|
||||
person_event_data[ATTR_FACE_URL] = person.get(ATTR_FACE_URL)
|
||||
hass.bus.async_fire(
|
||||
event_type=NETATMO_EVENT,
|
||||
event_data={"type": event_type, "data": person_event_data},
|
||||
)
|
||||
|
||||
async_send_event(hass, event_type, person_event_data)
|
||||
|
||||
else:
|
||||
_LOGGER.debug("%s: %s", event_type, event_data)
|
||||
hass.bus.async_fire(
|
||||
event_type=NETATMO_EVENT,
|
||||
event_data={"type": event_type, "data": event_data},
|
||||
)
|
||||
async_send_event(hass, event_type, event_data)
|
||||
|
||||
|
||||
@callback
|
||||
def async_send_event(hass, event_type, data):
|
||||
"""Send events."""
|
||||
hass.bus.async_fire(
|
||||
event_type=NETATMO_EVENT, event_data={"type": event_type, "data": data}
|
||||
)
|
||||
async_dispatcher_send(
|
||||
hass,
|
||||
f"signal-{DOMAIN}-webhook-{event_type}",
|
||||
{"type": event_type, "data": data},
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue