diff --git a/homeassistant/components/airvisual/manifest.json b/homeassistant/components/airvisual/manifest.json index d11f3ab69a9..351c7251102 100644 --- a/homeassistant/components/airvisual/manifest.json +++ b/homeassistant/components/airvisual/manifest.json @@ -3,6 +3,6 @@ "name": "AirVisual", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/airvisual", - "requirements": ["pyairvisual==5.0.3"], + "requirements": ["pyairvisual==5.0.4"], "codeowners": ["@bachya"] } diff --git a/homeassistant/components/bmw_connected_drive/manifest.json b/homeassistant/components/bmw_connected_drive/manifest.json index bd76294c8e8..6a886fc9ef4 100644 --- a/homeassistant/components/bmw_connected_drive/manifest.json +++ b/homeassistant/components/bmw_connected_drive/manifest.json @@ -2,7 +2,7 @@ "domain": "bmw_connected_drive", "name": "BMW Connected Drive", "documentation": "https://www.home-assistant.io/integrations/bmw_connected_drive", - "requirements": ["bimmer_connected==0.7.8"], + "requirements": ["bimmer_connected==0.7.11"], "dependencies": [], "codeowners": ["@gerard33", "@rikroe"] } diff --git a/homeassistant/components/evohome/__init__.py b/homeassistant/components/evohome/__init__.py index f429f5bd2f1..818744f7d05 100644 --- a/homeassistant/components/evohome/__init__.py +++ b/homeassistant/components/evohome/__init__.py @@ -431,7 +431,7 @@ class EvoBroker: return if refresh: - self.hass.helpers.event.async_call_later(1, self.async_update()) + self.hass.helpers.event.async_call_later(1, self.async_update) return result diff --git a/homeassistant/components/maxcube/binary_sensor.py b/homeassistant/components/maxcube/binary_sensor.py index 06b53456973..376076352a6 100644 --- a/homeassistant/components/maxcube/binary_sensor.py +++ b/homeassistant/components/maxcube/binary_sensor.py @@ -16,7 +16,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): name = f"{cube.room_by_id(device.room_id).name} {device.name}" # Only add Window Shutters - if cube.is_windowshutter(device): + if device.is_windowshutter(): devices.append(MaxCubeShutter(handler, name, device.rf_address)) if devices: diff --git a/homeassistant/components/maxcube/climate.py b/homeassistant/components/maxcube/climate.py index e222784ca57..c17cc988c1d 100644 --- a/homeassistant/components/maxcube/climate.py +++ b/homeassistant/components/maxcube/climate.py @@ -70,7 +70,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): for device in cube.devices: name = f"{cube.room_by_id(device.room_id).name} {device.name}" - if cube.is_thermostat(device) or cube.is_wallthermostat(device): + if device.is_thermostat() or device.is_wallthermostat(): devices.append(MaxCubeClimate(handler, name, device.rf_address)) if devices: @@ -180,11 +180,11 @@ class MaxCubeClimate(ClimateEntity): device = cube.device_by_rf(self._rf_address) valve = 0 - if cube.is_thermostat(device): + if device.is_thermostat(): valve = device.valve_position - elif cube.is_wallthermostat(device): + elif device.is_wallthermostat(): for device in cube.devices_by_room(cube.room_by_id(device.room_id)): - if cube.is_thermostat(device) and device.valve_position > 0: + if device.is_thermostat() and device.valve_position > 0: valve = device.valve_position break else: @@ -287,7 +287,7 @@ class MaxCubeClimate(ClimateEntity): cube = self._cubehandle.cube device = cube.device_by_rf(self._rf_address) - if not cube.is_thermostat(device): + if not device.is_thermostat(): return {} return {ATTR_VALVE_POSITION: device.valve_position} diff --git a/homeassistant/components/netatmo/manifest.json b/homeassistant/components/netatmo/manifest.json index 12c9220c361..824b835b01a 100644 --- a/homeassistant/components/netatmo/manifest.json +++ b/homeassistant/components/netatmo/manifest.json @@ -3,7 +3,7 @@ "name": "Netatmo", "documentation": "https://www.home-assistant.io/integrations/netatmo", "requirements": [ - "pyatmo==4.1.0" + "pyatmo==4.2.0" ], "after_dependencies": [ "cloud", diff --git a/homeassistant/components/rest/binary_sensor.py b/homeassistant/components/rest/binary_sensor.py index ec8b3ba0122..c19bfe307d0 100644 --- a/homeassistant/components/rest/binary_sensor.py +++ b/homeassistant/components/rest/binary_sensor.py @@ -84,7 +84,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= if resource_template is not None: resource_template.hass = hass - resource = resource_template.render(parse_result=False) + resource = resource_template.async_render(parse_result=False) if value_template is not None: value_template.hass = hass @@ -189,6 +189,6 @@ class RestBinarySensor(BinarySensorEntity): async def async_update(self): """Get the latest data from REST API and updates the state.""" if self._resource_template is not None: - self.rest.set_url(self._resource_template.render(parse_result=False)) + self.rest.set_url(self._resource_template.async_render(parse_result=False)) await self.rest.async_update() diff --git a/homeassistant/components/rest/sensor.py b/homeassistant/components/rest/sensor.py index 323447ba1b3..826160604ba 100644 --- a/homeassistant/components/rest/sensor.py +++ b/homeassistant/components/rest/sensor.py @@ -103,7 +103,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= if resource_template is not None: resource_template.hass = hass - resource = resource_template.render(parse_result=False) + resource = resource_template.async_render(parse_result=False) if username and password: if config.get(CONF_AUTHENTICATION) == HTTP_DIGEST_AUTHENTICATION: @@ -202,7 +202,7 @@ class RestSensor(Entity): async def async_update(self): """Get the latest data from REST API and update the state.""" if self._resource_template is not None: - self.rest.set_url(self._resource_template.render(parse_result=False)) + self.rest.set_url(self._resource_template.async_render(parse_result=False)) await self.rest.async_update() diff --git a/homeassistant/components/rfxtrx/config_flow.py b/homeassistant/components/rfxtrx/config_flow.py index 624b7ade69d..f81fdde3c4c 100644 --- a/homeassistant/components/rfxtrx/config_flow.py +++ b/homeassistant/components/rfxtrx/config_flow.py @@ -360,13 +360,17 @@ class OptionsFlow(config_entries.OptionsFlow): """Check if device can be replaced with selected device.""" device_data = self._get_device_data(entry_id) event_code = device_data[CONF_EVENT_CODE] - rfx_obj = get_rfx_object(event_code) - if ( - rfx_obj.device.packettype == self._selected_device_object.device.packettype - and rfx_obj.device.subtype == self._selected_device_object.device.subtype - and self._selected_device_event_code != event_code - ): - return True + + if event_code is not None: + rfx_obj = get_rfx_object(event_code) + if ( + rfx_obj.device.packettype + == self._selected_device_object.device.packettype + and rfx_obj.device.subtype + == self._selected_device_object.device.subtype + and self._selected_device_event_code != event_code + ): + return True return False diff --git a/homeassistant/components/simplisafe/alarm_control_panel.py b/homeassistant/components/simplisafe/alarm_control_panel.py index 11f794eef5d..7634f1cce86 100644 --- a/homeassistant/components/simplisafe/alarm_control_panel.py +++ b/homeassistant/components/simplisafe/alarm_control_panel.py @@ -159,7 +159,7 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity): try: await self._system.set_off() except SimplipyError as err: - LOGGER.error('Error while disarming "%s": %s', self._system.name, err) + LOGGER.error('Error while disarming "%s": %s', self._system.system_id, err) return self._state = STATE_ALARM_DISARMED @@ -172,7 +172,9 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity): try: await self._system.set_home() except SimplipyError as err: - LOGGER.error('Error while arming "%s" (home): %s', self._system.name, err) + LOGGER.error( + 'Error while arming "%s" (home): %s', self._system.system_id, err + ) return self._state = STATE_ALARM_ARMED_HOME @@ -185,7 +187,9 @@ class SimpliSafeAlarm(SimpliSafeEntity, AlarmControlPanelEntity): try: await self._system.set_away() except SimplipyError as err: - LOGGER.error('Error while arming "%s" (away): %s', self._system.name, err) + LOGGER.error( + 'Error while arming "%s" (away): %s', self._system.system_id, err + ) return self._state = STATE_ALARM_ARMING diff --git a/homeassistant/components/synology_dsm/__init__.py b/homeassistant/components/synology_dsm/__init__.py index 44a68b4c18c..a9c2f47e6b9 100644 --- a/homeassistant/components/synology_dsm/__init__.py +++ b/homeassistant/components/synology_dsm/__init__.py @@ -258,10 +258,9 @@ class SynoApi: self._entry.data[CONF_PASSWORD], self._entry.data[CONF_SSL], timeout=self._entry.options.get(CONF_TIMEOUT), + device_token=self._entry.data.get("device_token"), ) - await self._hass.async_add_executor_job( - self.dsm.login, self._entry.data.get("device_token") - ) + await self._hass.async_add_executor_job(self.dsm.login) self._with_surveillance_station = bool( self.dsm.apis.get(SynoSurveillanceStation.CAMERA_API_KEY) diff --git a/homeassistant/components/tasmota/light.py b/homeassistant/components/tasmota/light.py index 1a41e7373fd..a680d873f9f 100644 --- a/homeassistant/components/tasmota/light.py +++ b/homeassistant/components/tasmota/light.py @@ -128,6 +128,11 @@ class TasmotaLight( white_value = float(attributes["white_value"]) percent_white = white_value / TASMOTA_BRIGHTNESS_MAX self._white_value = percent_white * 255 + if self._white_value == 0: + self._color_temp = None + self._white_value = None + if self._white_value is not None and self._white_value > 0: + self._hs = None self.async_write_ha_state() @property diff --git a/homeassistant/components/vizio/config_flow.py b/homeassistant/components/vizio/config_flow.py index f3b7720a33e..b6d6d9bfb05 100644 --- a/homeassistant/components/vizio/config_flow.py +++ b/homeassistant/components/vizio/config_flow.py @@ -348,9 +348,11 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Handle zeroconf discovery.""" assert self.hass - discovery_info[ - CONF_HOST - ] = f"{discovery_info[CONF_HOST]}:{discovery_info[CONF_PORT]}" + # If host already has port, no need to add it again + if ":" not in discovery_info[CONF_HOST]: + discovery_info[ + CONF_HOST + ] = f"{discovery_info[CONF_HOST]}:{discovery_info[CONF_PORT]}" # Set default name to discovered device name by stripping zeroconf service # (`type`) from `name` diff --git a/homeassistant/const.py b/homeassistant/const.py index 44c3669db9e..2360191b144 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 117 -PATCH_VERSION = "2" +PATCH_VERSION = "3" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 1) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 203bbb62027..01c2a30d2de 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -8,7 +8,7 @@ attrs==19.3.0 bcrypt==3.1.7 certifi>=2020.6.20 ciso8601==2.1.3 -cryptography==3.2.0 +cryptography==3.2 defusedxml==0.6.0 distro==1.5.0 emoji==0.5.4 diff --git a/requirements.txt b/requirements.txt index 1586fdddee4..498b948e478 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ httpx==0.16.1 importlib-metadata==1.6.0;python_version<'3.8' jinja2>=2.11.2 PyJWT==1.7.1 -cryptography==3.2.0 +cryptography==3.2 pip>=8.0.3 python-slugify==4.0.1 pytz>=2020.1 diff --git a/requirements_all.txt b/requirements_all.txt index 0113e7e81bf..4121b1ad034 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -342,7 +342,7 @@ beautifulsoup4==4.9.1 bellows==0.20.3 # homeassistant.components.bmw_connected_drive -bimmer_connected==0.7.8 +bimmer_connected==0.7.11 # homeassistant.components.bizkaibus bizkaibus==0.1.1 @@ -1252,7 +1252,7 @@ pyaehw4a1==0.3.9 pyaftership==0.1.2 # homeassistant.components.airvisual -pyairvisual==5.0.3 +pyairvisual==5.0.4 # homeassistant.components.almond pyalmond==0.0.2 @@ -1264,7 +1264,7 @@ pyarlo==0.2.3 pyatag==0.3.4.4 # homeassistant.components.netatmo -pyatmo==4.1.0 +pyatmo==4.2.0 # homeassistant.components.atome pyatome==0.1.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 81c138dbda2..9bd8137a1e6 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -615,7 +615,7 @@ py_nextbusnext==0.1.4 pyaehw4a1==0.3.9 # homeassistant.components.airvisual -pyairvisual==5.0.3 +pyairvisual==5.0.4 # homeassistant.components.almond pyalmond==0.0.2 @@ -627,7 +627,7 @@ pyarlo==0.2.3 pyatag==0.3.4.4 # homeassistant.components.netatmo -pyatmo==4.1.0 +pyatmo==4.2.0 # homeassistant.components.blackbird pyblackbird==0.5 diff --git a/setup.py b/setup.py index e501ac6cf12..a1794f7880b 100755 --- a/setup.py +++ b/setup.py @@ -44,7 +44,7 @@ REQUIRES = [ "jinja2>=2.11.2", "PyJWT==1.7.1", # PyJWT has loose dependency. We want the latest one. - "cryptography==3.2.0", + "cryptography==3.2", "pip>=8.0.3", "python-slugify==4.0.1", "pytz>=2020.1", diff --git a/tests/components/rest/test_binary_sensor.py b/tests/components/rest/test_binary_sensor.py index 276dc293f87..1f2c88f4278 100644 --- a/tests/components/rest/test_binary_sensor.py +++ b/tests/components/rest/test_binary_sensor.py @@ -116,7 +116,7 @@ async def test_setup_minimum_resource_template(hass): { "binary_sensor": { "platform": "rest", - "resource_template": "http://localhost", + "resource_template": "{% set url = 'http://localhost' %}{{ url }}", } }, ) diff --git a/tests/components/rest/test_sensor.py b/tests/components/rest/test_sensor.py index 6a7e444cedd..d841f69e45f 100644 --- a/tests/components/rest/test_sensor.py +++ b/tests/components/rest/test_sensor.py @@ -102,7 +102,7 @@ async def test_setup_minimum_resource_template(hass): { "sensor": { "platform": "rest", - "resource_template": "http://localhost", + "resource_template": "{% set url = 'http://localhost' %}{{ url }}", } }, ) diff --git a/tests/components/tasmota/test_light.py b/tests/components/tasmota/test_light.py index 48b1dec7232..9210c577a5e 100644 --- a/tests/components/tasmota/test_light.py +++ b/tests/components/tasmota/test_light.py @@ -432,6 +432,8 @@ async def test_controlling_state_via_mqtt_rgbww(hass, mqtt_mock, setup_tasmota): state = hass.states.get("light.test") assert state.state == STATE_ON assert state.attributes.get("white_value") == 127.5 + # Setting white > 0 should clear the color + assert not state.attributes.get("rgb_color") async_fire_mqtt_message( hass, "tasmota_49A3BC/tele/STATE", '{"POWER":"ON","CT":300}' @@ -440,6 +442,15 @@ async def test_controlling_state_via_mqtt_rgbww(hass, mqtt_mock, setup_tasmota): assert state.state == STATE_ON assert state.attributes.get("color_temp") == 300 + async_fire_mqtt_message( + hass, "tasmota_49A3BC/tele/STATE", '{"POWER":"ON","White":0}' + ) + state = hass.states.get("light.test") + assert state.state == STATE_ON + # Setting white to 0 should clear the white_value and color_temp + assert not state.attributes.get("white_value") + assert not state.attributes.get("color_temp") + async_fire_mqtt_message( hass, "tasmota_49A3BC/tele/STATE", '{"POWER":"ON","Scheme":3}' ) diff --git a/tests/components/vizio/test_config_flow.py b/tests/components/vizio/test_config_flow.py index 5cbc2fa5564..32469fabd05 100644 --- a/tests/components/vizio/test_config_flow.py +++ b/tests/components/vizio/test_config_flow.py @@ -27,6 +27,7 @@ from homeassistant.const import ( CONF_HOST, CONF_NAME, CONF_PIN, + CONF_PORT, ) from homeassistant.helpers.typing import HomeAssistantType @@ -777,6 +778,35 @@ async def test_zeroconf_flow_already_configured( assert result["reason"] == "already_configured" +async def test_zeroconf_flow_with_port_in_host( + hass: HomeAssistantType, + vizio_connect: pytest.fixture, + vizio_bypass_setup: pytest.fixture, + vizio_guess_device_type: pytest.fixture, +) -> None: + """Test entity is already configured during zeroconf setup when port is in host.""" + entry = MockConfigEntry( + domain=DOMAIN, + data=MOCK_SPEAKER_CONFIG, + options={CONF_VOLUME_STEP: VOLUME_STEP}, + unique_id=UNIQUE_ID, + ) + entry.add_to_hass(hass) + + # Try rediscovering same device, this time with port already in host + discovery_info = MOCK_ZEROCONF_SERVICE_INFO.copy() + discovery_info[ + CONF_HOST + ] = f"{discovery_info[CONF_HOST]}:{discovery_info[CONF_PORT]}" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info + ) + + # Flow should abort because device is already setup + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "already_configured" + + async def test_zeroconf_dupe_fail( hass: HomeAssistantType, vizio_connect: pytest.fixture,