From 18135bb1a16fd38f6edbe01d50b535804710ca73 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 16 Nov 2020 20:10:55 +0100 Subject: [PATCH 1/8] Make MQTT climate return PRESET_NONE when no preset is set (#43257) --- homeassistant/components/mqtt/climate.py | 2 +- tests/components/mqtt/test_climate.py | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/mqtt/climate.py b/homeassistant/components/mqtt/climate.py index 68579559e35..8b762a82f02 100644 --- a/homeassistant/components/mqtt/climate.py +++ b/homeassistant/components/mqtt/climate.py @@ -640,7 +640,7 @@ class MqttClimate( return self._hold if self._away: return PRESET_AWAY - return None + return PRESET_NONE @property def preset_modes(self): diff --git a/tests/components/mqtt/test_climate.py b/tests/components/mqtt/test_climate.py index 3c629a82012..4d049753f43 100644 --- a/tests/components/mqtt/test_climate.py +++ b/tests/components/mqtt/test_climate.py @@ -438,11 +438,11 @@ async def test_set_away_mode_pessimistic(hass, mqtt_mock): await hass.async_block_till_done() state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("preset_mode") is None + assert state.attributes.get("preset_mode") == "none" await common.async_set_preset_mode(hass, "away", ENTITY_CLIMATE) state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("preset_mode") is None + assert state.attributes.get("preset_mode") == "none" async_fire_mqtt_message(hass, "away-state", "ON") state = hass.states.get(ENTITY_CLIMATE) @@ -450,11 +450,11 @@ async def test_set_away_mode_pessimistic(hass, mqtt_mock): async_fire_mqtt_message(hass, "away-state", "OFF") state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("preset_mode") is None + assert state.attributes.get("preset_mode") == "none" async_fire_mqtt_message(hass, "away-state", "nonsense") state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("preset_mode") is None + assert state.attributes.get("preset_mode") == "none" async def test_set_away_mode(hass, mqtt_mock): @@ -467,7 +467,7 @@ async def test_set_away_mode(hass, mqtt_mock): await hass.async_block_till_done() state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("preset_mode") is None + assert state.attributes.get("preset_mode") == "none" await common.async_set_preset_mode(hass, "away", ENTITY_CLIMATE) mqtt_mock.async_publish.assert_called_once_with("away-mode-topic", "AN", 0, False) mqtt_mock.async_publish.reset_mock() @@ -477,7 +477,7 @@ async def test_set_away_mode(hass, mqtt_mock): await common.async_set_preset_mode(hass, PRESET_NONE, ENTITY_CLIMATE) mqtt_mock.async_publish.assert_called_once_with("away-mode-topic", "AUS", 0, False) state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("preset_mode") is None + assert state.attributes.get("preset_mode") == "none" await common.async_set_preset_mode(hass, "hold-on", ENTITY_CLIMATE) mqtt_mock.async_publish.reset_mock() @@ -525,7 +525,7 @@ async def test_set_hold_pessimistic(hass, mqtt_mock): async_fire_mqtt_message(hass, "hold-state", "off") state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("preset_mode") is None + assert state.attributes.get("preset_mode") == "none" async def test_set_hold(hass, mqtt_mock): @@ -534,7 +534,7 @@ async def test_set_hold(hass, mqtt_mock): await hass.async_block_till_done() state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("preset_mode") is None + assert state.attributes.get("preset_mode") == "none" await common.async_set_preset_mode(hass, "hold-on", ENTITY_CLIMATE) mqtt_mock.async_publish.assert_called_once_with("hold-topic", "hold-on", 0, False) mqtt_mock.async_publish.reset_mock() @@ -550,7 +550,7 @@ async def test_set_hold(hass, mqtt_mock): await common.async_set_preset_mode(hass, PRESET_NONE, ENTITY_CLIMATE) mqtt_mock.async_publish.assert_called_once_with("hold-topic", "off", 0, False) state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("preset_mode") is None + assert state.attributes.get("preset_mode") == "none" async def test_set_preset_mode_twice(hass, mqtt_mock): @@ -559,7 +559,7 @@ async def test_set_preset_mode_twice(hass, mqtt_mock): await hass.async_block_till_done() state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("preset_mode") is None + assert state.attributes.get("preset_mode") == "none" await common.async_set_preset_mode(hass, "hold-on", ENTITY_CLIMATE) mqtt_mock.async_publish.assert_called_once_with("hold-topic", "hold-on", 0, False) mqtt_mock.async_publish.reset_mock() @@ -735,7 +735,7 @@ async def test_set_with_templates(hass, mqtt_mock, caplog): assert state.attributes.get("temperature") == 1031 # Away Mode - assert state.attributes.get("preset_mode") is None + assert state.attributes.get("preset_mode") == "none" async_fire_mqtt_message(hass, "away-state", '"ON"') state = hass.states.get(ENTITY_CLIMATE) assert state.attributes.get("preset_mode") == "away" @@ -743,7 +743,7 @@ async def test_set_with_templates(hass, mqtt_mock, caplog): # Away Mode with JSON values async_fire_mqtt_message(hass, "away-state", "false") state = hass.states.get(ENTITY_CLIMATE) - assert state.attributes.get("preset_mode") is None + assert state.attributes.get("preset_mode") == "none" async_fire_mqtt_message(hass, "away-state", "true") state = hass.states.get(ENTITY_CLIMATE) From 94f7f70f2d196ee32be42f3b5c788dbb70b6376a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20RAMAGE?= Date: Fri, 20 Nov 2020 14:05:51 +0100 Subject: [PATCH 2/8] Update zigpy-zigate to 0.7.3 (#43427) * Update zigpy-zigate to 0.7.3 Fix probing pizigate * Update zigpy-zigate to 0.7.3 Fix probing pizigate --- homeassistant/components/zha/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index 0dfb9ab5098..ffbdfdf386b 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -11,7 +11,7 @@ "zigpy-deconz==0.11.0", "zigpy==0.27.0", "zigpy-xbee==0.13.0", - "zigpy-zigate==0.7.2", + "zigpy-zigate==0.7.3", "zigpy-znp==0.2.2" ], "codeowners": ["@dmulcahey", "@adminiuga"] diff --git a/requirements_all.txt b/requirements_all.txt index fc26d7f9f91..4959f756c3e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2353,7 +2353,7 @@ zigpy-deconz==0.11.0 zigpy-xbee==0.13.0 # homeassistant.components.zha -zigpy-zigate==0.7.2 +zigpy-zigate==0.7.3 # homeassistant.components.zha zigpy-znp==0.2.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index f0ab950c6dd..49f421ba3ba 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1131,7 +1131,7 @@ zigpy-deconz==0.11.0 zigpy-xbee==0.13.0 # homeassistant.components.zha -zigpy-zigate==0.7.2 +zigpy-zigate==0.7.3 # homeassistant.components.zha zigpy-znp==0.2.2 From 44c8fce33b042fb67c376956e4a93c4d3ce400e2 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 24 Nov 2020 21:44:31 +0100 Subject: [PATCH 3/8] Fix duplicate check on onewire config flow (#43590) --- .../components/onewire/config_flow.py | 2 +- tests/components/onewire/__init__.py | 6 ++-- tests/components/onewire/test_config_flow.py | 33 +++++++++++++++++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/onewire/config_flow.py b/homeassistant/components/onewire/config_flow.py index f83431111d8..9ad4d5347f0 100644 --- a/homeassistant/components/onewire/config_flow.py +++ b/homeassistant/components/onewire/config_flow.py @@ -56,7 +56,7 @@ def is_duplicate_owserver_entry(hass: HomeAssistantType, user_input): if ( config_entry.data[CONF_TYPE] == CONF_TYPE_OWSERVER and config_entry.data[CONF_HOST] == user_input[CONF_HOST] - and config_entry.data[CONF_PORT] == str(user_input[CONF_PORT]) + and config_entry.data[CONF_PORT] == user_input[CONF_PORT] ): return True return False diff --git a/tests/components/onewire/__init__.py b/tests/components/onewire/__init__.py index eb9b42ea996..39a3c438cf9 100644 --- a/tests/components/onewire/__init__.py +++ b/tests/components/onewire/__init__.py @@ -48,9 +48,8 @@ async def setup_onewire_owserver_integration(hass): data={ CONF_TYPE: CONF_TYPE_OWSERVER, CONF_HOST: "1.2.3.4", - CONF_PORT: "1234", + CONF_PORT: 1234, }, - unique_id=f"{CONF_TYPE_OWSERVER}:1.2.3.4:1234", connection_class=CONN_CLASS_LOCAL_POLL, options={}, entry_id="2", @@ -74,12 +73,11 @@ async def setup_onewire_patched_owserver_integration(hass): data={ CONF_TYPE: CONF_TYPE_OWSERVER, CONF_HOST: "1.2.3.4", - CONF_PORT: "1234", + CONF_PORT: 1234, CONF_NAMES: { "10.111111111111": "My DS18B20", }, }, - unique_id=f"{CONF_TYPE_OWSERVER}:1.2.3.4:1234", connection_class=CONN_CLASS_LOCAL_POLL, options={}, entry_id="2", diff --git a/tests/components/onewire/test_config_flow.py b/tests/components/onewire/test_config_flow.py index dfb64a3846e..ba0ae090ed2 100644 --- a/tests/components/onewire/test_config_flow.py +++ b/tests/components/onewire/test_config_flow.py @@ -318,7 +318,7 @@ async def test_import_owserver_with_port(hass): data={ CONF_TYPE: CONF_TYPE_OWSERVER, CONF_HOST: "1.2.3.4", - CONF_PORT: "1234", + CONF_PORT: 1234, }, ) assert result["type"] == RESULT_TYPE_CREATE_ENTRY @@ -326,8 +326,37 @@ async def test_import_owserver_with_port(hass): assert result["data"] == { CONF_TYPE: CONF_TYPE_OWSERVER, CONF_HOST: "1.2.3.4", - CONF_PORT: "1234", + CONF_PORT: 1234, } await hass.async_block_till_done() assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_import_owserver_duplicate(hass): + """Test OWServer flow.""" + # Initialise with single entry + with patch( + "homeassistant.components.onewire.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.onewire.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + await setup_onewire_owserver_integration(hass) + assert len(hass.config_entries.async_entries(DOMAIN)) == 1 + + # Import duplicate entry + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data={ + CONF_TYPE: CONF_TYPE_OWSERVER, + CONF_HOST: "1.2.3.4", + CONF_PORT: 1234, + }, + ) + assert result["type"] == RESULT_TYPE_ABORT + assert result["reason"] == "already_configured" + await hass.async_block_till_done() + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 From 373ad447608718b6086e1fb1c8d7b6f32c902c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren?= Date: Wed, 25 Nov 2020 08:25:09 +0100 Subject: [PATCH 4/8] Bump avea to 1.5.1 (#43618) --- homeassistant/components/avea/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/avea/manifest.json b/homeassistant/components/avea/manifest.json index 8d39600ed46..bf2b1a6a6ec 100644 --- a/homeassistant/components/avea/manifest.json +++ b/homeassistant/components/avea/manifest.json @@ -3,5 +3,5 @@ "name": "Elgato Avea", "documentation": "https://www.home-assistant.io/integrations/avea", "codeowners": ["@pattyland"], - "requirements": ["avea==1.5"] + "requirements": ["avea==1.5.1"] } diff --git a/requirements_all.txt b/requirements_all.txt index 4959f756c3e..937d1671d5f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -303,7 +303,7 @@ aurorapy==0.2.6 av==8.0.2 # homeassistant.components.avea -# avea==1.5 +# avea==1.5.1 # homeassistant.components.avion # avion==0.10 From c4108d4ef1c8240f149fb3104af2bdc07c632f3b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 13 Nov 2020 13:22:29 +0100 Subject: [PATCH 5/8] Disable parsing scientific/complex number notation in template type (#43170) --- homeassistant/helpers/template.py | 16 +++++++++++++++- tests/helpers/test_template.py | 13 ++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index c6efa717fa7..09a9170c79a 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -49,6 +49,8 @@ _RENDER_INFO = "template.render_info" _ENVIRONMENT = "template.environment" _RE_JINJA_DELIMITERS = re.compile(r"\{%|\{\{|\{#") +# Match "simple" ints and floats. -1.0, 1, +5, 5.0 +_IS_NUMERIC = re.compile(r"^[+-]?\d*(?:\.\d*)?$") _RESERVED_NAMES = {"contextfunction", "evalcontextfunction", "environmentfunction"} @@ -373,7 +375,19 @@ class Template: # render, by not returning right here. The evaluation of strings # resulting in strings impacts quotes, to avoid unexpected # output; use the original render instead of the evaluated one. - if not isinstance(result, str): + # Complex and scientific values are also unexpected. Filter them out. + if ( + # Filter out string and complex numbers + not isinstance(result, (str, complex)) + and ( + # Pass if not numeric and not a boolean + not isinstance(result, (int, float)) + # Or it's a boolean (inherit from int) + or isinstance(result, bool) + # Or if it's a digit + or _IS_NUMERIC.match(render_result) is not None + ) + ): return result except (ValueError, TypeError, SyntaxError, MemoryError): pass diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index fe2f23c0033..53186ed35a1 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -346,7 +346,7 @@ def test_tan(hass): (0, 0.0), (math.pi, -0.0), (math.pi / 180 * 45, 1.0), - (math.pi / 180 * 90, 1.633123935319537e16), + (math.pi / 180 * 90, "1.633123935319537e+16"), (math.pi / 180 * 135, -1.0), ("'error'", "error"), ] @@ -2416,5 +2416,16 @@ async def test_parse_result(hass): ('{{ "{{}}" }}', "{{}}"), ("not-something", "not-something"), ("2a", "2a"), + ("123E5", "123E5"), + ("1j", "1j"), + ("1e+100", "1e+100"), + ("0xface", "0xface"), + ("123", 123), + ("123.0", 123.0), + (".5", 0.5), + ("-1", -1), + ("-1.0", -1.0), + ("+1", 1), + ("5.", 5.0), ): assert template.Template(tpl, hass).async_render() == result From 793fdb53172ac8fe0c104b52a4b11c04b2e49a93 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 25 Nov 2020 16:10:33 +0100 Subject: [PATCH 6/8] Tweak template digit detection (#43621) --- homeassistant/helpers/template.py | 2 +- tests/helpers/test_template.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index 09a9170c79a..fb3e6ba40b5 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -50,7 +50,7 @@ _ENVIRONMENT = "template.environment" _RE_JINJA_DELIMITERS = re.compile(r"\{%|\{\{|\{#") # Match "simple" ints and floats. -1.0, 1, +5, 5.0 -_IS_NUMERIC = re.compile(r"^[+-]?\d*(?:\.\d*)?$") +_IS_NUMERIC = re.compile(r"^[+-]?(?!0\d)\d*(?:\.\d*)?$") _RESERVED_NAMES = {"contextfunction", "evalcontextfunction", "environmentfunction"} diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index 53186ed35a1..c8a8bc0710c 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -2421,11 +2421,17 @@ async def test_parse_result(hass): ("1e+100", "1e+100"), ("0xface", "0xface"), ("123", 123), + ("10", 10), ("123.0", 123.0), (".5", 0.5), + ("0.5", 0.5), ("-1", -1), ("-1.0", -1.0), ("+1", 1), ("5.", 5.0), + ("123_123_123", "123_123_123"), + # ("+48100200300", "+48100200300"), # phone number + ("010", "010"), + ("0011101.00100001010001", "0011101.00100001010001"), ): assert template.Template(tpl, hass).async_render() == result From ecaa9d925b7479f658c7b10d30afaca32d9ca98a Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 26 Nov 2020 11:38:30 +0100 Subject: [PATCH 7/8] Fix deadlock if an integration from stage_1 fails (#43657) --- homeassistant/bootstrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 0d63307a020..5299ac0d301 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -534,7 +534,7 @@ async def _async_set_up_integrations( _LOGGER.warning("Setup timed out for stage 1 - moving forward") # Enables after dependencies - async_set_domains_to_be_loaded(hass, stage_1_domains | stage_2_domains) + async_set_domains_to_be_loaded(hass, stage_2_domains) if stage_2_domains: _LOGGER.info("Setting up stage 2: %s", stage_2_domains) From 0ede3da686bdf95691c33623d2977cc63576d984 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 26 Nov 2020 16:02:28 +0000 Subject: [PATCH 8/8] Bumped version to 0.118.4 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 927773be73d..37b495d8c24 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 118 -PATCH_VERSION = "3" +PATCH_VERSION = "4" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 1)