mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 20:27:08 +00:00
Merge pull request #43664 from home-assistant/rc
This commit is contained in:
commit
a15abf8802
@ -534,7 +534,7 @@ async def _async_set_up_integrations(
|
|||||||
_LOGGER.warning("Setup timed out for stage 1 - moving forward")
|
_LOGGER.warning("Setup timed out for stage 1 - moving forward")
|
||||||
|
|
||||||
# Enables after dependencies
|
# 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:
|
if stage_2_domains:
|
||||||
_LOGGER.info("Setting up stage 2: %s", stage_2_domains)
|
_LOGGER.info("Setting up stage 2: %s", stage_2_domains)
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
"name": "Elgato Avea",
|
"name": "Elgato Avea",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/avea",
|
"documentation": "https://www.home-assistant.io/integrations/avea",
|
||||||
"codeowners": ["@pattyland"],
|
"codeowners": ["@pattyland"],
|
||||||
"requirements": ["avea==1.5"]
|
"requirements": ["avea==1.5.1"]
|
||||||
}
|
}
|
||||||
|
@ -640,7 +640,7 @@ class MqttClimate(
|
|||||||
return self._hold
|
return self._hold
|
||||||
if self._away:
|
if self._away:
|
||||||
return PRESET_AWAY
|
return PRESET_AWAY
|
||||||
return None
|
return PRESET_NONE
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def preset_modes(self):
|
def preset_modes(self):
|
||||||
|
@ -56,7 +56,7 @@ def is_duplicate_owserver_entry(hass: HomeAssistantType, user_input):
|
|||||||
if (
|
if (
|
||||||
config_entry.data[CONF_TYPE] == CONF_TYPE_OWSERVER
|
config_entry.data[CONF_TYPE] == CONF_TYPE_OWSERVER
|
||||||
and config_entry.data[CONF_HOST] == user_input[CONF_HOST]
|
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 True
|
||||||
return False
|
return False
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"zigpy-deconz==0.11.0",
|
"zigpy-deconz==0.11.0",
|
||||||
"zigpy==0.27.0",
|
"zigpy==0.27.0",
|
||||||
"zigpy-xbee==0.13.0",
|
"zigpy-xbee==0.13.0",
|
||||||
"zigpy-zigate==0.7.2",
|
"zigpy-zigate==0.7.3",
|
||||||
"zigpy-znp==0.2.2"
|
"zigpy-znp==0.2.2"
|
||||||
],
|
],
|
||||||
"codeowners": ["@dmulcahey", "@adminiuga"]
|
"codeowners": ["@dmulcahey", "@adminiuga"]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Constants used by Home Assistant components."""
|
"""Constants used by Home Assistant components."""
|
||||||
MAJOR_VERSION = 0
|
MAJOR_VERSION = 0
|
||||||
MINOR_VERSION = 118
|
MINOR_VERSION = 118
|
||||||
PATCH_VERSION = "3"
|
PATCH_VERSION = "4"
|
||||||
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||||
__version__ = f"{__short_version__}.{PATCH_VERSION}"
|
__version__ = f"{__short_version__}.{PATCH_VERSION}"
|
||||||
REQUIRED_PYTHON_VER = (3, 7, 1)
|
REQUIRED_PYTHON_VER = (3, 7, 1)
|
||||||
|
@ -49,6 +49,8 @@ _RENDER_INFO = "template.render_info"
|
|||||||
_ENVIRONMENT = "template.environment"
|
_ENVIRONMENT = "template.environment"
|
||||||
|
|
||||||
_RE_JINJA_DELIMITERS = re.compile(r"\{%|\{\{|\{#")
|
_RE_JINJA_DELIMITERS = re.compile(r"\{%|\{\{|\{#")
|
||||||
|
# Match "simple" ints and floats. -1.0, 1, +5, 5.0
|
||||||
|
_IS_NUMERIC = re.compile(r"^[+-]?(?!0\d)\d*(?:\.\d*)?$")
|
||||||
|
|
||||||
_RESERVED_NAMES = {"contextfunction", "evalcontextfunction", "environmentfunction"}
|
_RESERVED_NAMES = {"contextfunction", "evalcontextfunction", "environmentfunction"}
|
||||||
|
|
||||||
@ -373,7 +375,19 @@ class Template:
|
|||||||
# render, by not returning right here. The evaluation of strings
|
# render, by not returning right here. The evaluation of strings
|
||||||
# resulting in strings impacts quotes, to avoid unexpected
|
# resulting in strings impacts quotes, to avoid unexpected
|
||||||
# output; use the original render instead of the evaluated one.
|
# 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
|
return result
|
||||||
except (ValueError, TypeError, SyntaxError, MemoryError):
|
except (ValueError, TypeError, SyntaxError, MemoryError):
|
||||||
pass
|
pass
|
||||||
|
@ -303,7 +303,7 @@ aurorapy==0.2.6
|
|||||||
av==8.0.2
|
av==8.0.2
|
||||||
|
|
||||||
# homeassistant.components.avea
|
# homeassistant.components.avea
|
||||||
# avea==1.5
|
# avea==1.5.1
|
||||||
|
|
||||||
# homeassistant.components.avion
|
# homeassistant.components.avion
|
||||||
# avion==0.10
|
# avion==0.10
|
||||||
@ -2353,7 +2353,7 @@ zigpy-deconz==0.11.0
|
|||||||
zigpy-xbee==0.13.0
|
zigpy-xbee==0.13.0
|
||||||
|
|
||||||
# homeassistant.components.zha
|
# homeassistant.components.zha
|
||||||
zigpy-zigate==0.7.2
|
zigpy-zigate==0.7.3
|
||||||
|
|
||||||
# homeassistant.components.zha
|
# homeassistant.components.zha
|
||||||
zigpy-znp==0.2.2
|
zigpy-znp==0.2.2
|
||||||
|
@ -1131,7 +1131,7 @@ zigpy-deconz==0.11.0
|
|||||||
zigpy-xbee==0.13.0
|
zigpy-xbee==0.13.0
|
||||||
|
|
||||||
# homeassistant.components.zha
|
# homeassistant.components.zha
|
||||||
zigpy-zigate==0.7.2
|
zigpy-zigate==0.7.3
|
||||||
|
|
||||||
# homeassistant.components.zha
|
# homeassistant.components.zha
|
||||||
zigpy-znp==0.2.2
|
zigpy-znp==0.2.2
|
||||||
|
@ -438,11 +438,11 @@ async def test_set_away_mode_pessimistic(hass, mqtt_mock):
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
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)
|
await common.async_set_preset_mode(hass, "away", ENTITY_CLIMATE)
|
||||||
state = hass.states.get(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")
|
async_fire_mqtt_message(hass, "away-state", "ON")
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
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")
|
async_fire_mqtt_message(hass, "away-state", "OFF")
|
||||||
state = hass.states.get(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", "nonsense")
|
async_fire_mqtt_message(hass, "away-state", "nonsense")
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
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):
|
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()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
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)
|
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.assert_called_once_with("away-mode-topic", "AN", 0, False)
|
||||||
mqtt_mock.async_publish.reset_mock()
|
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)
|
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)
|
mqtt_mock.async_publish.assert_called_once_with("away-mode-topic", "AUS", 0, False)
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
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)
|
await common.async_set_preset_mode(hass, "hold-on", ENTITY_CLIMATE)
|
||||||
mqtt_mock.async_publish.reset_mock()
|
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")
|
async_fire_mqtt_message(hass, "hold-state", "off")
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
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):
|
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()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
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)
|
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.assert_called_once_with("hold-topic", "hold-on", 0, False)
|
||||||
mqtt_mock.async_publish.reset_mock()
|
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)
|
await common.async_set_preset_mode(hass, PRESET_NONE, ENTITY_CLIMATE)
|
||||||
mqtt_mock.async_publish.assert_called_once_with("hold-topic", "off", 0, False)
|
mqtt_mock.async_publish.assert_called_once_with("hold-topic", "off", 0, False)
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
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):
|
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()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
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)
|
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.assert_called_once_with("hold-topic", "hold-on", 0, False)
|
||||||
mqtt_mock.async_publish.reset_mock()
|
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
|
assert state.attributes.get("temperature") == 1031
|
||||||
|
|
||||||
# Away Mode
|
# 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"')
|
async_fire_mqtt_message(hass, "away-state", '"ON"')
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
state = hass.states.get(ENTITY_CLIMATE)
|
||||||
assert state.attributes.get("preset_mode") == "away"
|
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
|
# Away Mode with JSON values
|
||||||
async_fire_mqtt_message(hass, "away-state", "false")
|
async_fire_mqtt_message(hass, "away-state", "false")
|
||||||
state = hass.states.get(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", "true")
|
async_fire_mqtt_message(hass, "away-state", "true")
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
state = hass.states.get(ENTITY_CLIMATE)
|
||||||
|
@ -48,9 +48,8 @@ async def setup_onewire_owserver_integration(hass):
|
|||||||
data={
|
data={
|
||||||
CONF_TYPE: CONF_TYPE_OWSERVER,
|
CONF_TYPE: CONF_TYPE_OWSERVER,
|
||||||
CONF_HOST: "1.2.3.4",
|
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,
|
connection_class=CONN_CLASS_LOCAL_POLL,
|
||||||
options={},
|
options={},
|
||||||
entry_id="2",
|
entry_id="2",
|
||||||
@ -74,12 +73,11 @@ async def setup_onewire_patched_owserver_integration(hass):
|
|||||||
data={
|
data={
|
||||||
CONF_TYPE: CONF_TYPE_OWSERVER,
|
CONF_TYPE: CONF_TYPE_OWSERVER,
|
||||||
CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
CONF_PORT: "1234",
|
CONF_PORT: 1234,
|
||||||
CONF_NAMES: {
|
CONF_NAMES: {
|
||||||
"10.111111111111": "My DS18B20",
|
"10.111111111111": "My DS18B20",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
unique_id=f"{CONF_TYPE_OWSERVER}:1.2.3.4:1234",
|
|
||||||
connection_class=CONN_CLASS_LOCAL_POLL,
|
connection_class=CONN_CLASS_LOCAL_POLL,
|
||||||
options={},
|
options={},
|
||||||
entry_id="2",
|
entry_id="2",
|
||||||
|
@ -318,7 +318,7 @@ async def test_import_owserver_with_port(hass):
|
|||||||
data={
|
data={
|
||||||
CONF_TYPE: CONF_TYPE_OWSERVER,
|
CONF_TYPE: CONF_TYPE_OWSERVER,
|
||||||
CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
CONF_PORT: "1234",
|
CONF_PORT: 1234,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
@ -326,8 +326,37 @@ async def test_import_owserver_with_port(hass):
|
|||||||
assert result["data"] == {
|
assert result["data"] == {
|
||||||
CONF_TYPE: CONF_TYPE_OWSERVER,
|
CONF_TYPE: CONF_TYPE_OWSERVER,
|
||||||
CONF_HOST: "1.2.3.4",
|
CONF_HOST: "1.2.3.4",
|
||||||
CONF_PORT: "1234",
|
CONF_PORT: 1234,
|
||||||
}
|
}
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(mock_setup.mock_calls) == 1
|
assert len(mock_setup.mock_calls) == 1
|
||||||
assert len(mock_setup_entry.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
|
||||||
|
@ -346,7 +346,7 @@ def test_tan(hass):
|
|||||||
(0, 0.0),
|
(0, 0.0),
|
||||||
(math.pi, -0.0),
|
(math.pi, -0.0),
|
||||||
(math.pi / 180 * 45, 1.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),
|
(math.pi / 180 * 135, -1.0),
|
||||||
("'error'", "error"),
|
("'error'", "error"),
|
||||||
]
|
]
|
||||||
@ -2416,5 +2416,22 @@ async def test_parse_result(hass):
|
|||||||
('{{ "{{}}" }}', "{{}}"),
|
('{{ "{{}}" }}', "{{}}"),
|
||||||
("not-something", "not-something"),
|
("not-something", "not-something"),
|
||||||
("2a", "2a"),
|
("2a", "2a"),
|
||||||
|
("123E5", "123E5"),
|
||||||
|
("1j", "1j"),
|
||||||
|
("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
|
assert template.Template(tpl, hass).async_render() == result
|
||||||
|
Loading…
x
Reference in New Issue
Block a user