Compare commits

...

36 Commits

Author SHA1 Message Date
Paulus Schoutsen
ebc0ed1e22 Merge pull request #29039 from home-assistant/rc
0.102.2
2019-11-24 21:16:56 -08:00
Paulus Schoutsen
8a467bbf5c Bumped version to 0.102.2 2019-11-24 19:57:50 -08:00
Franck Nijhof
b10d42e330 Alexa gracefully handle climate devices without presets (#29010) 2019-11-24 19:57:43 -08:00
Bram Kragten
2af1ba7492 Updated frontend to 20191119.6 (#28996) 2019-11-24 19:57:42 -08:00
shred86
a56f7f5d75 Fix temp not being reported properly (#28973) 2019-11-24 19:57:42 -08:00
cgtobi
481f71107b Fix manual config (#28956) 2019-11-24 19:57:41 -08:00
Pascal Vizeli
2e85e3662f Fix ikea lights on deconz (#28949)
* Fix ikea lights on deconz

* check for None

* Use cleaner code style
2019-11-24 19:57:40 -08:00
jjlawren
c382406735 Fix Plex setup race condition v2 (#28943)
* Connect websocket when platforms ready, not when HA is ready

* Use callbacks from platform setup tasks instead

* Convert setup to async

* Apply suggestions from code review

Co-Authored-By: Martin Hjelmare <marhje52@gmail.com>
2019-11-24 19:57:40 -08:00
Paulus Schoutsen
37f808f4d8 Merge pull request #28932 from home-assistant/rc
0.102.1
2019-11-21 15:06:27 -08:00
jjlawren
ab9a60f83f Delay Plex websocket connection to avoid race (#28934) 2019-11-21 12:39:39 -08:00
Paulus Schoutsen
3391fc660a Bumped version to 0.102.1 2019-11-21 12:25:12 -08:00
Bram Kragten
42809ad6a9 Updated frontend to 20191119.5 (#28925)
* Updated frontend to 20191119.4

* Updated frontend to 20191119.5
2019-11-21 12:25:05 -08:00
cgtobi
dba87fd2e1 Fix missing Netatmo sensors (#28899)
* Update pyatmo to 3.0.1

* Improve sensor name

* Fix missing sensors

* Update pyatmo module

* Update pyatmo to 3.1.0

* Update requirements

* Fix method call
2019-11-21 12:25:04 -08:00
Paulus Schoutsen
df3e17a983 Merge pull request #28909 from home-assistant/rc
0.102.0
2019-11-20 14:04:30 -08:00
Paulus Schoutsen
138cee8069 Version bump to 0.102.0 2019-11-20 13:05:54 -08:00
Bram Kragten
787aac7cf2 Fix Almond onboarding url when using cloud (#28908) 2019-11-20 13:05:37 -08:00
Bram Kragten
bca93ca2ec Bumped version to 0.102.0b3 2019-11-20 12:33:39 +01:00
Bram Kragten
98c7ddc0cf Updated frontend to 20191119.2 (#28896) 2019-11-20 12:32:13 +01:00
Bram Kragten
9fb289ad93 Updated frontend to 20191119.1 (#28881) 2019-11-20 12:32:12 +01:00
Bram Kragten
69b096023a Updated frontend to 20191119.0 (#28875) 2019-11-20 12:32:11 +01:00
Santobert
ab41310847 Fix setting colors while reproducing a lights state (#28871)
* Fix setting colors while reproducing state

* Reorder list
2019-11-20 12:32:10 +01:00
Andi
687b7fc8cb Fix Synology camera whitelist (#28822)
* Fix Synology camera whitelist

If whitelist config is set, not camera is added to HA at all.

* Fix Synology Camera whitelist

Fix typo in config key.

* Update camera.py

Access config dict the voluptuous way
2019-11-20 12:32:09 +01:00
Franck Nijhof
89cd5d46cd Fix documentation URL in failed platform config check (#28814)
* Fix documentation URL in failed platform config check

* Replace pop from list by access using negative index

* Use of split instead of rsplit
2019-11-20 12:32:09 +01:00
Bram Kragten
7966411274 Bump version 2019-11-18 15:44:17 +01:00
Bram Kragten
bf4c81aa5e Updated frontend to 20191118.0 (#28852) 2019-11-18 15:43:20 +01:00
cgtobi
d91eddc4f0 Update pyatmo to 3.0.1 (#28829) 2019-11-18 15:43:19 +01:00
Jackie Yang
fb1fd19aae Fix miio air quality sensor (#28828)
Fix https://github.com/home-assistant/home-assistant/issues/28827
2019-11-18 15:43:18 +01:00
Michaël Arnauts
c6343c9e88 Fix Comfoconnect errors during startup (#28802)
* Add callback registrations to async_added_to_hass

* Fix CODEOWNERS

* Fix code formatting

* Requested changes.

* Don't pass unused hass and fix string formatting

* Fix import order.
2019-11-18 15:43:17 +01:00
Bram Kragten
b964fcc5b1 Updated frontend to 20191115.0 (#28797) 2019-11-18 15:43:17 +01:00
Peter Nijssen
31cbdbf1dd Fix broken postnl sensor (#28794)
* fix broken postnl sensor

* make sure shipment list is not growing indefinitely
2019-11-18 15:43:16 +01:00
LeoCal
f8be1512b8 Fix Swisscom empty response received (#28782) 2019-11-18 15:43:15 +01:00
SukramJ
5ff24ecf77 Fix HomematicIP Cloud Alarm Control Panel support for basic mode (#28778) 2019-11-18 15:43:14 +01:00
Morten Trab
fe5f30ba78 Fix Repetier integration entity indexing (#28766)
* Fixed multi extruder/beds/chambers index issue, #28130

* Switched from .format to f style name formatting

* Fixed incorrect indexing

* Removed VS files

* Removed not need temp_id subtraction

* Removed VS files

* Fixed access mode

* Fixed access mode

* Fixing access mode - again
2019-11-18 15:43:13 +01:00
Tyler Page
5f0f5ca557 Fix changing venstar operation_mode (#28754) 2019-11-18 15:43:12 +01:00
fredericvl
1479e7353b Change unique id for SAJ sensor based on device SN (#28663)
* Change unique id for SAJ sensor based on device SN

* Add SAJ device name + sn to state attributes

* Revert device state attributes (after review)
2019-11-18 15:43:12 +01:00
Brendon Baumgartner
326c25a766 Fix amazon dependency conflicts (#28217)
* fix amazon dependency conflicts

* bump boto3 for route53
2019-11-18 15:43:11 +01:00
39 changed files with 196 additions and 231 deletions

View File

@@ -61,6 +61,7 @@ homeassistant/components/cisco_webex_teams/* @fbradyirl
homeassistant/components/ciscospark/* @fbradyirl
homeassistant/components/cloud/* @home-assistant/cloud
homeassistant/components/cloudflare/* @ludeeus
homeassistant/components/comfoconnect/* @michaelarnauts
homeassistant/components/config/* @home-assistant/core
homeassistant/components/configurator/* @home-assistant/core
homeassistant/components/conversation/* @home-assistant/core

View File

@@ -72,19 +72,19 @@ class AbodeSensor(AbodeDevice):
@property
def state(self):
"""Return the state of the sensor."""
if self._sensor_type == "temp":
if self._sensor_type == CONST.TEMP_STATUS_KEY:
return self._device.temp
if self._sensor_type == "humidity":
if self._sensor_type == CONST.HUMI_STATUS_KEY:
return self._device.humidity
if self._sensor_type == "lux":
if self._sensor_type == CONST.LUX_STATUS_KEY:
return self._device.lux
@property
def unit_of_measurement(self):
"""Return the units of measurement."""
if self._sensor_type == "temp":
if self._sensor_type == CONST.TEMP_STATUS_KEY:
return self._device.temp_unit
if self._sensor_type == "humidity":
if self._sensor_type == CONST.HUMI_STATUS_KEY:
return self._device.humidity_unit
if self._sensor_type == "lux":
if self._sensor_type == CONST.LUX_STATUS_KEY:
return self._device.lux_unit

View File

@@ -752,10 +752,11 @@ class AlexaThermostatController(AlexaCapability):
supported_modes.append(thermostat_mode)
preset_modes = self.entity.attributes.get(climate.ATTR_PRESET_MODES)
for mode in preset_modes:
thermostat_mode = API_THERMOSTAT_PRESETS.get(mode)
if thermostat_mode:
supported_modes.append(thermostat_mode)
if preset_modes:
for mode in preset_modes:
thermostat_mode = API_THERMOSTAT_PRESETS.get(mode)
if thermostat_mode:
supported_modes.append(thermostat_mode)
# Return False for supportsScheduling until supported with event listener in handler.
configuration = {"supportsScheduling": False}

View File

@@ -263,8 +263,6 @@ class AlmondAgent(conversation.AbstractConversationAgent):
host = self.entry.data["host"]
if self.entry.data.get("is_hassio"):
host = "/core_almond"
elif self.entry.data["type"] != TYPE_LOCAL:
host = f"{host}/me"
return {
"text": "Would you like to opt-in to share your anonymized commands with Stanford to improve Almond's responses?",
"url": f"{host}/conversation",

View File

@@ -3,10 +3,10 @@
"name": "Amazon polly",
"documentation": "https://www.home-assistant.io/integrations/amazon_polly",
"requirements": [
"boto3==1.9.233"
"boto3==1.9.252"
],
"dependencies": [],
"codeowners": [
"@robbiet480"
]
}
}

View File

@@ -3,7 +3,7 @@
"name": "Aws",
"documentation": "https://www.home-assistant.io/integrations/aws",
"requirements": [
"aiobotocore==0.10.2"
"aiobotocore==0.10.4"
],
"dependencies": [],
"codeowners": [

View File

@@ -102,7 +102,6 @@ class ComfoConnectBridge:
def __init__(self, hass, bridge, name, token, friendly_name, pin):
"""Initialize the ComfoConnect bridge."""
self.data = {}
self.name = name
self.hass = hass
@@ -136,7 +135,3 @@ class ComfoConnectBridge:
# Notify listeners that we have received an update
dispatcher_send(self.hass, SIGNAL_COMFOCONNECT_UPDATE_RECEIVED, var)
def subscribe_sensor(self, sensor_id):
"""Subscribe for the specified sensor."""
self.comfoconnect.register_sensor(sensor_id)

View File

@@ -17,7 +17,7 @@ from homeassistant.components.fan import (
SUPPORT_SET_SPEED,
FanEntity,
)
from homeassistant.helpers.dispatcher import dispatcher_connect
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from . import DOMAIN, SIGNAL_COMFOCONNECT_UPDATE_RECEIVED, ComfoConnectBridge
@@ -30,28 +30,36 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the ComfoConnect fan platform."""
ccb = hass.data[DOMAIN]
add_entities([ComfoConnectFan(hass, name=ccb.name, ccb=ccb)], True)
add_entities([ComfoConnectFan(ccb.name, ccb)], True)
class ComfoConnectFan(FanEntity):
"""Representation of the ComfoConnect fan platform."""
def __init__(self, hass, name, ccb: ComfoConnectBridge) -> None:
def __init__(self, name, ccb: ComfoConnectBridge) -> None:
"""Initialize the ComfoConnect fan."""
self._ccb = ccb
self._name = name
# Ask the bridge to keep us updated
self._ccb.comfoconnect.register_sensor(SENSOR_FAN_SPEED_MODE)
async def async_added_to_hass(self):
"""Register for sensor updates."""
await self.hass.async_add_executor_job(
self._ccb.comfoconnect.register_sensor, SENSOR_FAN_SPEED_MODE
)
async_dispatcher_connect(
self.hass, SIGNAL_COMFOCONNECT_UPDATE_RECEIVED, self._handle_update
)
def _handle_update(var):
if var == SENSOR_FAN_SPEED_MODE:
_LOGGER.debug("Dispatcher update for %s", var)
self.schedule_update_ha_state()
def _handle_update(self, var):
"""Handle update callbacks."""
if var == SENSOR_FAN_SPEED_MODE:
_LOGGER.debug("Received update for %s", var)
self.schedule_update_ha_state()
# Register for dispatcher updates
dispatcher_connect(hass, SIGNAL_COMFOCONNECT_UPDATE_RECEIVED, _handle_update)
@property
def should_poll(self) -> bool:
"""Do not poll."""
return False
@property
def name(self):
@@ -71,7 +79,6 @@ class ComfoConnectFan(FanEntity):
@property
def speed(self):
"""Return the current fan mode."""
try:
speed = self._ccb.data[SENSOR_FAN_SPEED_MODE]
return SPEED_MAPPING[speed]
@@ -95,7 +102,7 @@ class ComfoConnectFan(FanEntity):
def set_speed(self, speed: str):
"""Set fan speed."""
_LOGGER.debug("Changing fan speed to %s.", speed)
_LOGGER.debug("Changing fan speed to %s", speed)
if speed == SPEED_OFF:
self._ccb.comfoconnect.cmd_rmi_request(CMD_FAN_MODE_AWAY)

View File

@@ -6,5 +6,5 @@
"pycomfoconnect==0.3"
],
"dependencies": [],
"codeowners": []
"codeowners": ["@michaelarnauts"]
}

View File

@@ -11,7 +11,7 @@ from pycomfoconnect import (
)
from homeassistant.const import CONF_RESOURCES, TEMP_CELSIUS
from homeassistant.helpers.dispatcher import dispatcher_connect
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity
from . import (
@@ -81,13 +81,12 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
sensor_type = resource.lower()
if sensor_type not in SENSOR_TYPES:
_LOGGER.warning("Sensor type: %s is not a valid sensor.", sensor_type)
_LOGGER.warning("Sensor type: %s is not a valid sensor", sensor_type)
continue
sensors.append(
ComfoConnectSensor(
hass,
name="%s %s" % (ccb.name, SENSOR_TYPES[sensor_type][0]),
name=f"{ccb.name} {SENSOR_TYPES[sensor_type][0]}",
ccb=ccb,
sensor_type=sensor_type,
)
@@ -99,23 +98,27 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
class ComfoConnectSensor(Entity):
"""Representation of a ComfoConnect sensor."""
def __init__(self, hass, name, ccb: ComfoConnectBridge, sensor_type) -> None:
def __init__(self, name, ccb: ComfoConnectBridge, sensor_type) -> None:
"""Initialize the ComfoConnect sensor."""
self._ccb = ccb
self._sensor_type = sensor_type
self._sensor_id = SENSOR_TYPES[self._sensor_type][3]
self._name = name
# Register the requested sensor
self._ccb.comfoconnect.register_sensor(self._sensor_id)
async def async_added_to_hass(self):
"""Register for sensor updates."""
await self.hass.async_add_executor_job(
self._ccb.comfoconnect.register_sensor, self._sensor_id
)
async_dispatcher_connect(
self.hass, SIGNAL_COMFOCONNECT_UPDATE_RECEIVED, self._handle_update
)
def _handle_update(var):
if var == self._sensor_id:
_LOGGER.debug("Dispatcher update for %s.", var)
self.schedule_update_ha_state()
# Register for dispatcher updates
dispatcher_connect(hass, SIGNAL_COMFOCONNECT_UPDATE_RECEIVED, _handle_update)
def _handle_update(self, var):
"""Handle update callbacks."""
if var == self._sensor_id:
_LOGGER.debug("Received update for %s", var)
self.schedule_update_ha_state()
@property
def state(self):
@@ -125,6 +128,11 @@ class ComfoConnectSensor(Entity):
except KeyError:
return None
@property
def should_poll(self) -> bool:
"""Do not poll."""
return False
@property
def name(self):
"""Return the name of the sensor."""

View File

@@ -152,6 +152,8 @@ class DeconzLight(DeconzDevice, Light):
if ATTR_TRANSITION in kwargs:
data["transitiontime"] = int(kwargs[ATTR_TRANSITION] * 10)
elif "IKEA" in (self._device.manufacturer or ""):
data["transitiontime"] = 0
if ATTR_FLASH in kwargs:
if kwargs[ATTR_FLASH] == FLASH_SHORT:

View File

@@ -3,7 +3,7 @@
"name": "Home Assistant Frontend",
"documentation": "https://www.home-assistant.io/integrations/frontend",
"requirements": [
"home-assistant-frontend==20191114.0"
"home-assistant-frontend==20191119.6"
],
"dependencies": [
"api",

View File

@@ -1,8 +1,7 @@
"""Support for HomematicIP Cloud alarm control panel."""
import logging
from homematicip.aio.group import AsyncSecurityZoneGroup
from homematicip.base.enums import WindowState
from homematicip.functionalHomes import SecurityAndAlarmHome
from homeassistant.components.alarm_control_panel import AlarmControlPanel
from homeassistant.config_entries import ConfigEntry
@@ -32,34 +31,15 @@ async def async_setup_entry(
) -> None:
"""Set up the HomematicIP alrm control panel from a config entry."""
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
devices = []
security_zones = []
for group in hap.home.groups:
if isinstance(group, AsyncSecurityZoneGroup):
security_zones.append(group)
if security_zones:
devices.append(HomematicipAlarmControlPanel(hap, security_zones))
if devices:
async_add_entities(devices)
async_add_entities([HomematicipAlarmControlPanel(hap)])
class HomematicipAlarmControlPanel(AlarmControlPanel):
"""Representation of an alarm control panel."""
def __init__(self, hap: HomematicipHAP, security_zones) -> None:
def __init__(self, hap: HomematicipHAP) -> None:
"""Initialize the alarm control panel."""
self._home = hap.home
self.alarm_state = STATE_ALARM_DISARMED
self._internal_alarm_zone = None
self._external_alarm_zone = None
for security_zone in security_zones:
if security_zone.label == "INTERNAL":
self._internal_alarm_zone = security_zone
elif security_zone.label == "EXTERNAL":
self._external_alarm_zone = security_zone
@property
def device_info(self):
@@ -75,28 +55,23 @@ class HomematicipAlarmControlPanel(AlarmControlPanel):
@property
def state(self) -> str:
"""Return the state of the device."""
# check for triggered alarm
if self._security_and_alarm.alarmActive:
return STATE_ALARM_TRIGGERED
activation_state = self._home.get_security_zones_activation()
# check arm_away
if activation_state == (True, True):
if self._internal_alarm_zone_state or self._external_alarm_zone_state:
return STATE_ALARM_TRIGGERED
return STATE_ALARM_ARMED_AWAY
# check arm_home
if activation_state == (False, True):
if self._external_alarm_zone_state:
return STATE_ALARM_TRIGGERED
return STATE_ALARM_ARMED_HOME
return STATE_ALARM_DISARMED
@property
def _internal_alarm_zone_state(self) -> bool:
return _get_zone_alarm_state(self._internal_alarm_zone)
@property
def _external_alarm_zone_state(self) -> bool:
"""Return the state of the device."""
return _get_zone_alarm_state(self._external_alarm_zone)
def _security_and_alarm(self):
return self._home.get_functionalHome(SecurityAndAlarmHome)
async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
@@ -112,10 +87,7 @@ class HomematicipAlarmControlPanel(AlarmControlPanel):
async def async_added_to_hass(self):
"""Register callbacks."""
if self._internal_alarm_zone:
self._internal_alarm_zone.on_update(self._async_device_changed)
if self._external_alarm_zone:
self._external_alarm_zone.on_update(self._async_device_changed)
self._home.on_update(self._async_device_changed)
def _async_device_changed(self, *args, **kwargs):
"""Handle device state changes."""
@@ -138,26 +110,9 @@ class HomematicipAlarmControlPanel(AlarmControlPanel):
@property
def available(self) -> bool:
"""Device available."""
return (
not self._internal_alarm_zone.unreach
or not self._external_alarm_zone.unreach
)
return self._home.connected
@property
def unique_id(self) -> str:
"""Return a unique ID."""
return f"{self.__class__.__name__}_{self._home.id}"
def _get_zone_alarm_state(security_zone) -> bool:
if security_zone and security_zone.active:
if (
security_zone.sabotage
or security_zone.motionDetected
or security_zone.presenceDetected
or security_zone.windowState == WindowState.OPEN
or security_zone.windowState == WindowState.TILTED
):
return True
return False

View File

@@ -45,13 +45,14 @@ ATTR_GROUP = [
]
COLOR_GROUP = [
ATTR_COLOR_NAME,
ATTR_COLOR_TEMP,
ATTR_HS_COLOR,
ATTR_KELVIN,
ATTR_PROFILE,
ATTR_COLOR_TEMP,
ATTR_RGB_COLOR,
ATTR_XY_COLOR,
# The following color attributes are deprecated
ATTR_PROFILE,
ATTR_COLOR_NAME,
ATTR_KELVIN,
]
DEPRECATED_GROUP = [

View File

@@ -259,4 +259,4 @@ class CameraData:
@Throttle(MIN_TIME_BETWEEN_EVENT_UPDATES)
def update_event(self):
"""Call the Netatmo API to update the events."""
self.camera_data.updateEvent(home=self.home, cameratype=self.camera_type)
self.camera_data.updateEvent(home=self.home, devicetype=self.camera_type)

View File

@@ -3,10 +3,10 @@
"name": "Netatmo",
"documentation": "https://www.home-assistant.io/integrations/netatmo",
"requirements": [
"pyatmo==2.3.3"
"pyatmo==3.1.0"
],
"dependencies": [
"webhook"
],
"codeowners": []
}
}

View File

@@ -155,14 +155,12 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
for module in all_module_infos.values():
if module["module_name"] not in module_names:
continue
_LOGGER.debug(
"Adding module %s %s", module["module_name"], module["id"]
)
for condition in data.station_data.monitoredConditions(
moduleId=module["id"]
):
_LOGGER.debug(
"Adding %s %s",
module["module_name"],
data.station_data.moduleById(mid=module["id"]),
)
entities.append(NetatmoSensor(data, module, condition.lower()))
return entities
@@ -200,18 +198,26 @@ class NetatmoSensor(Entity):
def __init__(self, netatmo_data, module_info, sensor_type):
"""Initialize the sensor."""
self.netatmo_data = netatmo_data
module = self.netatmo_data.station_data.moduleById(mid=module_info["id"])
if module["type"] == "NHC":
device = self.netatmo_data.station_data.moduleById(mid=module_info["id"])
if not device:
# Assume it's a station if module can't be found
device = self.netatmo_data.station_data.stationById(sid=module_info["id"])
if device["type"] == "NHC":
self.module_name = module_info["station_name"]
else:
self.module_name = module_info["module_name"]
self.module_name = (
f"{module_info['station_name']} {module_info['module_name']}"
)
self._name = f"{DOMAIN} {self.module_name} {SENSOR_TYPES[sensor_type][0]}"
self.type = sensor_type
self._state = None
self._device_class = SENSOR_TYPES[self.type][3]
self._icon = SENSOR_TYPES[self.type][2]
self._unit_of_measurement = SENSOR_TYPES[self.type][1]
self._module_type = module["type"]
self._module_type = device["type"]
self._module_id = module_info["id"]
self._unique_id = f"{self._module_id}-{self.type}"
@@ -541,13 +547,18 @@ class NetatmoData:
self.data = {}
self.station_data = self.data_class(self.auth)
self.station = station
self.station_id = None
if station:
station_data = self.station_data.stationByName(self.station)
if station_data:
self.station_id = station_data.get("_id")
self._next_update = time()
self._update_in_progress = threading.Lock()
def get_module_infos(self):
"""Return all modules available on the API as a dict."""
if self.station is not None:
return self.station_data.getModules(station=self.station)
if self.station_id is not None:
return self.station_data.getModules(station_id=self.station_id)
return self.station_data.getModules()
def update(self):
@@ -573,7 +584,7 @@ class NetatmoData:
return
data = self.station_data.lastData(
station=self.station, exclude=3600, byId=True
station=self.station_id, exclude=3600, byId=True
)
if not data:
self._next_update = time() + NETATMO_UPDATE_INTERVAL

View File

@@ -1,5 +1,6 @@
"""Support to embed Plex."""
import asyncio
import functools
import logging
import plexapi.exceptions
@@ -36,6 +37,7 @@ from .const import (
DISPATCHERS,
DOMAIN as PLEX_DOMAIN,
PLATFORMS,
PLATFORMS_COMPLETED,
PLEX_MEDIA_PLAYER_OPTIONS,
PLEX_SERVER_CONFIG,
PLEX_UPDATE_PLATFORMS_SIGNAL,
@@ -71,18 +73,21 @@ CONFIG_SCHEMA = vol.Schema({PLEX_DOMAIN: SERVER_CONFIG_SCHEMA}, extra=vol.ALLOW_
_LOGGER = logging.getLogger(__package__)
def setup(hass, config):
async def async_setup(hass, config):
"""Set up the Plex component."""
hass.data.setdefault(PLEX_DOMAIN, {SERVERS: {}, DISPATCHERS: {}, WEBSOCKETS: {}})
hass.data.setdefault(
PLEX_DOMAIN,
{SERVERS: {}, DISPATCHERS: {}, WEBSOCKETS: {}, PLATFORMS_COMPLETED: {}},
)
plex_config = config.get(PLEX_DOMAIN, {})
if plex_config:
_setup_plex(hass, plex_config)
_async_setup_plex(hass, plex_config)
return True
def _setup_plex(hass, config):
def _async_setup_plex(hass, config):
"""Pass configuration to a config flow."""
server_config = dict(config)
if MP_DOMAIN in server_config:
@@ -140,11 +145,7 @@ async def async_setup_entry(hass, entry):
)
server_id = plex_server.machine_identifier
hass.data[PLEX_DOMAIN][SERVERS][server_id] = plex_server
for platform in PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, platform)
)
hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id] = set()
entry.add_update_listener(async_options_updated)
@@ -164,9 +165,13 @@ async def async_setup_entry(hass, entry):
websocket = PlexWebsocket(
plex_server.plex_server, update_plex, session=session, verify_ssl=verify_ssl
)
hass.loop.create_task(websocket.listen())
hass.data[PLEX_DOMAIN][WEBSOCKETS][server_id] = websocket
def start_websocket_session(platform, _):
hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id].add(platform)
if hass.data[PLEX_DOMAIN][PLATFORMS_COMPLETED][server_id] == PLATFORMS:
hass.loop.create_task(websocket.listen())
def close_websocket_session(_):
websocket.close()
@@ -175,6 +180,12 @@ async def async_setup_entry(hass, entry):
)
hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)
for platform in PLATFORMS:
task = hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, platform)
)
task.add_done_callback(functools.partial(start_websocket_session, platform))
return True

View File

@@ -9,7 +9,8 @@ DEFAULT_SSL = False
DEFAULT_VERIFY_SSL = True
DISPATCHERS = "dispatchers"
PLATFORMS = ["media_player", "sensor"]
PLATFORMS = frozenset(["media_player", "sensor"])
PLATFORMS_COMPLETED = "platforms_completed"
SERVERS = "servers"
WEBSOCKETS = "websockets"

View File

@@ -68,6 +68,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
hass, PLEX_NEW_MP_SIGNAL.format(server_id), async_new_media_players
)
hass.data[PLEX_DOMAIN][DISPATCHERS][server_id].append(unsub)
_LOGGER.debug("New entity listener created")
@callback

View File

@@ -3,7 +3,7 @@
"name": "Postnl",
"documentation": "https://www.home-assistant.io/integrations/postnl",
"requirements": [
"postnl_api==1.0.2"
"postnl_api==1.2.2"
],
"dependencies": [],
"codeowners": []

View File

@@ -58,7 +58,7 @@ class PostNLSensor(Entity):
def __init__(self, api, name):
"""Initialize the PostNL sensor."""
self._name = name
self._attributes = {ATTR_ATTRIBUTION: ATTRIBUTION}
self._attributes = {ATTR_ATTRIBUTION: ATTRIBUTION, "shipments": []}
self._state = None
self._api = api
@@ -90,6 +90,11 @@ class PostNLSensor(Entity):
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
"""Update device state."""
shipments = self._api.get_relevant_shipments()
self._attributes["shipments"] = shipments
shipments = self._api.get_relevant_deliveries()
self._attributes["shipments"] = []
for shipment in shipments:
self._attributes["shipments"].append(vars(shipment))
self._state = len(shipments)

View File

@@ -108,7 +108,7 @@ def has_all_unique_names(value):
SENSOR_TYPES = {
# Type, Unit, Icon
# Type, Unit, Icon, post
"bed_temperature": ["temperature", TEMP_CELSIUS, "mdi:thermometer", "_bed_"],
"extruder_temperature": [
"temperature",
@@ -248,12 +248,12 @@ class PrinterAPI:
if prop_data is None:
continue
for idx, _ in enumerate(prop_data):
info["temp_id"] = idx
sensor_info.append(info)
prop_info = info.copy()
prop_info["temp_id"] = idx
sensor_info.append(prop_info)
else:
info["temp_id"] = None
sensor_info.append(info)
self._known_entities.add(known)
if not sensor_info:

View File

@@ -35,11 +35,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
printer_id = info["printer_id"]
sensor_type = info["sensor_type"]
temp_id = info["temp_id"]
name = info["name"]
name = f"{info['name']}{SENSOR_TYPES[sensor_type][3]}"
if temp_id is not None:
name = "{}{}{}".format(name, SENSOR_TYPES[sensor_type][3], temp_id)
else:
name = "{}{}".format(name, SENSOR_TYPES[sensor_type][3])
_LOGGER.debug("%s Temp_id: %s", sensor_type, temp_id)
name = f"{name}{temp_id}"
sensor_class = sensor_map[sensor_type]
entity = sensor_class(api, temp_id, name, printer_id, sensor_type)
entities.append(entity)

View File

@@ -3,7 +3,7 @@
"name": "Route53",
"documentation": "https://www.home-assistant.io/integrations/route53",
"requirements": [
"boto3==1.9.233",
"boto3==1.9.252",
"ipify==1.0.0"
],
"dependencies": [],

View File

@@ -3,7 +3,7 @@
"name": "SAJ",
"documentation": "https://www.home-assistant.io/integrations/saj",
"requirements": [
"pysaj==0.0.13"
"pysaj==0.0.14"
],
"dependencies": [],
"codeowners": [

View File

@@ -69,9 +69,6 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
# Use all sensors by default
hass_sensors = []
for sensor in sensor_def:
hass_sensors.append(SAJsensor(sensor, inverter_name=config.get(CONF_NAME)))
kwargs = {}
if wifi:
kwargs["wifi"] = True
@@ -81,7 +78,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
try:
saj = pysaj.SAJ(config[CONF_HOST], **kwargs)
await saj.read(sensor_def)
done = await saj.read(sensor_def)
except pysaj.UnauthorizedException:
_LOGGER.error("Username and/or password is wrong.")
return
@@ -91,7 +88,13 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
)
return
async_add_entities(hass_sensors)
if done:
for sensor in sensor_def:
hass_sensors.append(
SAJsensor(saj.serialnumber, sensor, inverter_name=config.get(CONF_NAME))
)
async_add_entities(hass_sensors)
async def async_saj():
"""Update all the SAJ sensors."""
@@ -163,10 +166,11 @@ def async_track_time_interval_backoff(hass, action) -> CALLBACK_TYPE:
class SAJsensor(Entity):
"""Representation of a SAJ sensor."""
def __init__(self, pysaj_sensor, inverter_name=None):
def __init__(self, serialnumber, pysaj_sensor, inverter_name=None):
"""Initialize the sensor."""
self._sensor = pysaj_sensor
self._inverter_name = inverter_name
self._serialnumber = serialnumber
self._state = self._sensor.value
@property
@@ -235,7 +239,4 @@ class SAJsensor(Entity):
@property
def unique_id(self):
"""Return a unique identifier for this sensor."""
if self._inverter_name:
return f"{self._inverter_name}_{self._sensor.name}"
return f"{self._sensor.name}"
return f"{self._serialnumber}_{self._sensor.name}"

View File

@@ -92,6 +92,10 @@ class SwisscomDeviceScanner(DeviceScanner):
_LOGGER.info("No response from Swisscom Internet Box")
return devices
if "status" not in request.json():
_LOGGER.info("No status in response from Swisscom Internet Box")
return devices
for device in request.json()["status"]:
try:
devices[device["Key"]] = {

View File

@@ -62,7 +62,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
# add cameras
devices = []
for camera in cameras:
if not config.get(CONF_WHITELIST):
if not config[CONF_WHITELIST] or camera.name in config[CONF_WHITELIST]:
device = SynologyCamera(surveillance, camera.camera_id, verify_ssl)
devices.append(device)

View File

@@ -278,7 +278,7 @@ class VenstarThermostat(ClimateDevice):
temperature = kwargs.get(ATTR_TEMPERATURE)
if operation_mode and self._mode_map.get(operation_mode) != self._client.mode:
set_temp = self._set_operation_mode(self._mode_map.get(operation_mode))
set_temp = self._set_operation_mode(operation_mode)
if set_temp:
if (

View File

@@ -54,7 +54,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
device_info.firmware_version,
device_info.hardware_version,
)
device = AirMonitorB1(name, AirQualityMonitor(host, token, model), unique_id)
device = AirMonitorB1(name, AirQualityMonitor(host, token, model=model), unique_id)
async_add_entities([device], update_before_add=True)

View File

@@ -456,9 +456,10 @@ def _format_config_error(ex: Exception, domain: str, config: Dict) -> str:
)
if domain != CONF_CORE:
integration = domain.split(".")[-1]
message += (
"Please check the docs at "
"https://home-assistant.io/integrations/{}/".format(domain)
f"https://home-assistant.io/integrations/{integration}/"
)
return message

View File

@@ -1,7 +1,7 @@
"""Constants used by Home Assistant components."""
MAJOR_VERSION = 0
MINOR_VERSION = 102
PATCH_VERSION = "0b1"
PATCH_VERSION = "2"
__short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION)
__version__ = "{}.{}".format(__short_version__, PATCH_VERSION)
REQUIRED_PYTHON_VER = (3, 6, 1)

View File

@@ -11,7 +11,7 @@ contextvars==2.4;python_version<"3.7"
cryptography==2.8
distro==1.4.0
hass-nabucasa==0.29
home-assistant-frontend==20191114.0
home-assistant-frontend==20191119.6
importlib-metadata==0.23
jinja2>=2.10.3
netdisco==2.6.0

View File

@@ -136,7 +136,7 @@ aioasuswrt==1.1.22
aioautomatic==0.6.5
# homeassistant.components.aws
aiobotocore==0.10.2
aiobotocore==0.10.4
# homeassistant.components.dnsip
aiodns==2.0.0
@@ -317,7 +317,7 @@ bomradarloop==0.1.3
# homeassistant.components.amazon_polly
# homeassistant.components.route53
boto3==1.9.233
boto3==1.9.252
# homeassistant.components.braviatv
braviarc-homeassistant==0.3.7.dev0
@@ -655,7 +655,7 @@ hole==0.5.0
holidays==0.9.11
# homeassistant.components.frontend
home-assistant-frontend==20191114.0
home-assistant-frontend==20191119.6
# homeassistant.components.zwave
homeassistant-pyozw==0.1.4
@@ -999,7 +999,7 @@ pmsensor==0.4
pocketcasts==0.1
# homeassistant.components.postnl
postnl_api==1.0.2
postnl_api==1.2.2
# homeassistant.components.reddit
praw==6.4.0
@@ -1105,7 +1105,7 @@ pyalmond==0.0.2
pyarlo==0.2.3
# homeassistant.components.netatmo
pyatmo==2.3.3
pyatmo==3.1.0
# homeassistant.components.atome
pyatome==0.1.1
@@ -1435,7 +1435,7 @@ pyrepetier==3.0.5
pysabnzbd==1.1.0
# homeassistant.components.saj
pysaj==0.0.13
pysaj==0.0.14
# homeassistant.components.sony_projector
pysdcp==1

View File

@@ -47,7 +47,7 @@ aioasuswrt==1.1.22
aioautomatic==0.6.5
# homeassistant.components.aws
aiobotocore==0.10.2
aiobotocore==0.10.4
# homeassistant.components.esphome
aioesphomeapi==2.5.0
@@ -222,7 +222,7 @@ hole==0.5.0
holidays==0.9.11
# homeassistant.components.frontend
home-assistant-frontend==20191114.0
home-assistant-frontend==20191119.6
# homeassistant.components.zwave
homeassistant-pyozw==0.1.4

View File

@@ -1,7 +1,4 @@
"""Tests for HomematicIP Cloud alarm control panel."""
from homematicip.base.enums import WindowState
from homematicip.group import SecurityZoneGroup
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
)
@@ -17,29 +14,24 @@ from homeassistant.setup import async_setup_component
from .helper import get_and_check_entity_basics
def _get_security_zones(groups): # pylint: disable=W0221
"""Get the security zones."""
for group in groups:
if isinstance(group, SecurityZoneGroup):
if group.label == "EXTERNAL":
external = group
elif group.label == "INTERNAL":
internal = group
return internal, external
async def _async_manipulate_security_zones(
hass, home, internal_active, external_active, window_state
hass, home, internal_active=False, external_active=False, alarm_triggered=False
):
"""Set new values on hmip security zones."""
internal_zone, external_zone = _get_security_zones(home.groups)
json = home._rawJSONData # pylint: disable=W0212
json["functionalHomes"]["SECURITY_AND_ALARM"]["alarmActive"] = alarm_triggered
external_zone_id = json["functionalHomes"]["SECURITY_AND_ALARM"]["securityZones"][
"EXTERNAL"
]
internal_zone_id = json["functionalHomes"]["SECURITY_AND_ALARM"]["securityZones"][
"INTERNAL"
]
external_zone = home.search_group_by_id(external_zone_id)
external_zone.active = external_active
external_zone.windowState = window_state
internal_zone = home.search_group_by_id(internal_zone_id)
internal_zone.active = internal_active
# Just one call to a security zone is required to refresh the ACP.
internal_zone.fire_update_event()
home.fire_update_event(json)
await hass.async_block_till_done()
@@ -70,79 +62,49 @@ async def test_hmip_alarm_control_panel(hass, default_mock_hap):
assert not hmip_device
home = default_mock_hap.home
service_call_counter = len(home.mock_calls)
await hass.services.async_call(
"alarm_control_panel", "alarm_arm_away", {"entity_id": entity_id}, blocking=True
)
assert len(home.mock_calls) == service_call_counter + 1
assert home.mock_calls[-1][0] == "set_security_zones_activation"
assert home.mock_calls[-1][1] == (True, True)
await _async_manipulate_security_zones(
hass,
home,
internal_active=True,
external_active=True,
window_state=WindowState.CLOSED,
hass, home, internal_active=True, external_active=True
)
assert hass.states.get(entity_id).state is STATE_ALARM_ARMED_AWAY
await hass.services.async_call(
"alarm_control_panel", "alarm_arm_home", {"entity_id": entity_id}, blocking=True
)
assert len(home.mock_calls) == service_call_counter + 3
assert home.mock_calls[-1][0] == "set_security_zones_activation"
assert home.mock_calls[-1][1] == (False, True)
await _async_manipulate_security_zones(
hass,
home,
internal_active=False,
external_active=True,
window_state=WindowState.CLOSED,
)
await _async_manipulate_security_zones(hass, home, external_active=True)
assert hass.states.get(entity_id).state is STATE_ALARM_ARMED_HOME
await hass.services.async_call(
"alarm_control_panel", "alarm_disarm", {"entity_id": entity_id}, blocking=True
)
assert len(home.mock_calls) == service_call_counter + 5
assert home.mock_calls[-1][0] == "set_security_zones_activation"
assert home.mock_calls[-1][1] == (False, False)
await _async_manipulate_security_zones(
hass,
home,
internal_active=False,
external_active=False,
window_state=WindowState.CLOSED,
)
await _async_manipulate_security_zones(hass, home)
assert hass.states.get(entity_id).state is STATE_ALARM_DISARMED
await hass.services.async_call(
"alarm_control_panel", "alarm_arm_away", {"entity_id": entity_id}, blocking=True
)
assert len(home.mock_calls) == service_call_counter + 7
assert home.mock_calls[-1][0] == "set_security_zones_activation"
assert home.mock_calls[-1][1] == (True, True)
await _async_manipulate_security_zones(
hass,
home,
internal_active=True,
external_active=True,
window_state=WindowState.OPEN,
hass, home, internal_active=True, external_active=True, alarm_triggered=True
)
assert hass.states.get(entity_id).state is STATE_ALARM_TRIGGERED
await hass.services.async_call(
"alarm_control_panel", "alarm_arm_home", {"entity_id": entity_id}, blocking=True
)
assert len(home.mock_calls) == service_call_counter + 9
assert home.mock_calls[-1][0] == "set_security_zones_activation"
assert home.mock_calls[-1][1] == (False, True)
await _async_manipulate_security_zones(
hass,
home,
internal_active=False,
external_active=True,
window_state=WindowState.OPEN,
hass, home, external_active=True, alarm_triggered=True
)
assert hass.states.get(entity_id).state is STATE_ALARM_TRIGGERED

View File

@@ -343,6 +343,7 @@ async def test_hmip_heating_group_heat_with_switch(hass, default_mock_hap):
hass, default_mock_hap, entity_id, entity_name, device_model
)
assert hmip_device
assert ha_state.state == HVAC_MODE_AUTO
assert ha_state.attributes["current_temperature"] == 24.7
assert ha_state.attributes["min_temp"] == 5.0

View File

@@ -161,5 +161,5 @@ async def test_hmip_dump_hap_config_services(hass, mock_hap_with_service):
)
home = mock_hap_with_service.home
assert home.mock_calls[-1][0] == "download_configuration"
assert len(home.mock_calls) == 8 # pylint: disable=W0212
assert len(write_mock.mock_calls) > 0
assert home.mock_calls
assert write_mock.mock_calls