mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 07:07:28 +00:00
Merge pull request #49424 from home-assistant/rc
This commit is contained in:
commit
5ee373869a
@ -791,7 +791,7 @@ class TemperatureSettingTrait(_Trait):
|
|||||||
if preset in self.preset_to_google:
|
if preset in self.preset_to_google:
|
||||||
response["thermostatMode"] = self.preset_to_google[preset]
|
response["thermostatMode"] = self.preset_to_google[preset]
|
||||||
else:
|
else:
|
||||||
response["thermostatMode"] = self.hvac_to_google.get(operation)
|
response["thermostatMode"] = self.hvac_to_google.get(operation, "none")
|
||||||
|
|
||||||
current_temp = attrs.get(climate.ATTR_CURRENT_TEMPERATURE)
|
current_temp = attrs.get(climate.ATTR_CURRENT_TEMPERATURE)
|
||||||
if current_temp is not None:
|
if current_temp is not None:
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
"name": "Meteorologisk institutt (Met.no)",
|
"name": "Meteorologisk institutt (Met.no)",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/met",
|
"documentation": "https://www.home-assistant.io/integrations/met",
|
||||||
"requirements": ["pyMetno==0.8.1"],
|
"requirements": ["pyMetno==0.8.2"],
|
||||||
"codeowners": ["@danielhiversen", "@thimic"]
|
"codeowners": ["@danielhiversen", "@thimic"]
|
||||||
}
|
}
|
||||||
|
@ -319,7 +319,19 @@ class ModbusRegisterSensor(RestoreEntity, SensorEntity):
|
|||||||
# If unpack() returns a tuple greater than 1, don't try to process the value.
|
# If unpack() returns a tuple greater than 1, don't try to process the value.
|
||||||
# Instead, return the values of unpack(...) separated by commas.
|
# Instead, return the values of unpack(...) separated by commas.
|
||||||
if len(val) > 1:
|
if len(val) > 1:
|
||||||
self._value = ",".join(map(str, val))
|
# Apply scale and precision to floats and ints
|
||||||
|
v_result = []
|
||||||
|
for entry in val:
|
||||||
|
v_temp = self._scale * entry + self._offset
|
||||||
|
|
||||||
|
# We could convert int to float, and the code would still work; however
|
||||||
|
# we lose some precision, and unit tests will fail. Therefore, we do
|
||||||
|
# the conversion only when it's absolutely necessary.
|
||||||
|
if isinstance(v_temp, int) and self._precision == 0:
|
||||||
|
v_result.append(str(v_temp))
|
||||||
|
else:
|
||||||
|
v_result.append(f"{float(v_temp):.{self._precision}f}")
|
||||||
|
self._value = ",".join(map(str, v_result))
|
||||||
else:
|
else:
|
||||||
val = val[0]
|
val = val[0]
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ def round_state(func):
|
|||||||
|
|
||||||
|
|
||||||
class AirSensor(AirQualityEntity):
|
class AirSensor(AirQualityEntity):
|
||||||
"""Representation of an Yr.no sensor."""
|
"""Representation of an air quality sensor."""
|
||||||
|
|
||||||
def __init__(self, name, coordinates, forecast, session):
|
def __init__(self, name, coordinates, forecast, session):
|
||||||
"""Initialize the sensor."""
|
"""Initialize the sensor."""
|
||||||
|
@ -2,6 +2,6 @@
|
|||||||
"domain": "norway_air",
|
"domain": "norway_air",
|
||||||
"name": "Om Luftkvalitet i Norge (Norway Air)",
|
"name": "Om Luftkvalitet i Norge (Norway Air)",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/norway_air",
|
"documentation": "https://www.home-assistant.io/integrations/norway_air",
|
||||||
"requirements": ["pyMetno==0.8.1"],
|
"requirements": ["pyMetno==0.8.2"],
|
||||||
"codeowners": []
|
"codeowners": []
|
||||||
}
|
}
|
||||||
|
@ -328,9 +328,8 @@ async def _async_discover_roombas(hass, host):
|
|||||||
discovery = _async_get_roomba_discovery()
|
discovery = _async_get_roomba_discovery()
|
||||||
try:
|
try:
|
||||||
if host:
|
if host:
|
||||||
discovered = [
|
device = await hass.async_add_executor_job(discovery.get, host)
|
||||||
await hass.async_add_executor_job(discovery.get, host)
|
discovered = [device] if device else []
|
||||||
]
|
|
||||||
else:
|
else:
|
||||||
discovered = await hass.async_add_executor_job(discovery.get_all)
|
discovered = await hass.async_add_executor_job(discovery.get_all)
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Constants used by Home Assistant components."""
|
"""Constants used by Home Assistant components."""
|
||||||
MAJOR_VERSION = 2021
|
MAJOR_VERSION = 2021
|
||||||
MINOR_VERSION = 4
|
MINOR_VERSION = 4
|
||||||
PATCH_VERSION = "5"
|
PATCH_VERSION = "6"
|
||||||
__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, 8, 0)
|
REQUIRED_PYTHON_VER = (3, 8, 0)
|
||||||
|
@ -1203,12 +1203,9 @@ class Script:
|
|||||||
self._changed()
|
self._changed()
|
||||||
raise
|
raise
|
||||||
|
|
||||||
async def _async_stop(self, update_state, spare=None):
|
async def _async_stop(
|
||||||
aws = [
|
self, aws: list[asyncio.Task], update_state: bool, spare: _ScriptRun | None
|
||||||
asyncio.create_task(run.async_stop()) for run in self._runs if run != spare
|
) -> None:
|
||||||
]
|
|
||||||
if not aws:
|
|
||||||
return
|
|
||||||
await asyncio.wait(aws)
|
await asyncio.wait(aws)
|
||||||
if update_state:
|
if update_state:
|
||||||
self._changed()
|
self._changed()
|
||||||
@ -1217,7 +1214,15 @@ class Script:
|
|||||||
self, update_state: bool = True, spare: _ScriptRun | None = None
|
self, update_state: bool = True, spare: _ScriptRun | None = None
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Stop running script."""
|
"""Stop running script."""
|
||||||
await asyncio.shield(self._async_stop(update_state, spare))
|
# Collect a a list of script runs to stop. This must be done before calling
|
||||||
|
# asyncio.shield as asyncio.shield yields to the event loop, which would cause
|
||||||
|
# us to wait for script runs added after the call to async_stop.
|
||||||
|
aws = [
|
||||||
|
asyncio.create_task(run.async_stop()) for run in self._runs if run != spare
|
||||||
|
]
|
||||||
|
if not aws:
|
||||||
|
return
|
||||||
|
await asyncio.shield(self._async_stop(aws, update_state, spare))
|
||||||
|
|
||||||
async def _async_get_condition(self, config):
|
async def _async_get_condition(self, config):
|
||||||
if isinstance(config, template.Template):
|
if isinstance(config, template.Template):
|
||||||
|
@ -1229,7 +1229,7 @@ pyHS100==0.3.5.2
|
|||||||
|
|
||||||
# homeassistant.components.met
|
# homeassistant.components.met
|
||||||
# homeassistant.components.norway_air
|
# homeassistant.components.norway_air
|
||||||
pyMetno==0.8.1
|
pyMetno==0.8.2
|
||||||
|
|
||||||
# homeassistant.components.rfxtrx
|
# homeassistant.components.rfxtrx
|
||||||
pyRFXtrx==0.26.1
|
pyRFXtrx==0.26.1
|
||||||
|
@ -648,7 +648,7 @@ pyHS100==0.3.5.2
|
|||||||
|
|
||||||
# homeassistant.components.met
|
# homeassistant.components.met
|
||||||
# homeassistant.components.norway_air
|
# homeassistant.components.norway_air
|
||||||
pyMetno==0.8.1
|
pyMetno==0.8.2
|
||||||
|
|
||||||
# homeassistant.components.rfxtrx
|
# homeassistant.components.rfxtrx
|
||||||
pyRFXtrx==0.26.1
|
pyRFXtrx==0.26.1
|
||||||
|
@ -14,6 +14,7 @@ from homeassistant.components.modbus.const import (
|
|||||||
CONF_REVERSE_ORDER,
|
CONF_REVERSE_ORDER,
|
||||||
CONF_SCALE,
|
CONF_SCALE,
|
||||||
CONF_SENSORS,
|
CONF_SENSORS,
|
||||||
|
DATA_TYPE_CUSTOM,
|
||||||
DATA_TYPE_FLOAT,
|
DATA_TYPE_FLOAT,
|
||||||
DATA_TYPE_INT,
|
DATA_TYPE_INT,
|
||||||
DATA_TYPE_STRING,
|
DATA_TYPE_STRING,
|
||||||
@ -26,6 +27,7 @@ from homeassistant.const import (
|
|||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_OFFSET,
|
CONF_OFFSET,
|
||||||
CONF_SLAVE,
|
CONF_SLAVE,
|
||||||
|
CONF_STRUCTURE,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .conftest import base_config_test, base_test
|
from .conftest import base_config_test, base_test
|
||||||
@ -338,6 +340,7 @@ async def test_config_sensor(hass, do_discovery, do_config):
|
|||||||
)
|
)
|
||||||
async def test_all_sensor(hass, cfg, regs, expected):
|
async def test_all_sensor(hass, cfg, regs, expected):
|
||||||
"""Run test for sensor."""
|
"""Run test for sensor."""
|
||||||
|
|
||||||
sensor_name = "modbus_test_sensor"
|
sensor_name = "modbus_test_sensor"
|
||||||
state = await base_test(
|
state = await base_test(
|
||||||
hass,
|
hass,
|
||||||
@ -352,3 +355,41 @@ async def test_all_sensor(hass, cfg, regs, expected):
|
|||||||
scan_interval=5,
|
scan_interval=5,
|
||||||
)
|
)
|
||||||
assert state == expected
|
assert state == expected
|
||||||
|
|
||||||
|
|
||||||
|
async def test_struct_sensor(hass):
|
||||||
|
"""Run test for sensor struct."""
|
||||||
|
|
||||||
|
sensor_name = "modbus_test_sensor"
|
||||||
|
# floats: 7.931250095367432, 10.600000381469727,
|
||||||
|
# 1.000879611487865e-28, 10.566553115844727
|
||||||
|
expected = "7.93,10.60,0.00,10.57"
|
||||||
|
state = await base_test(
|
||||||
|
hass,
|
||||||
|
{
|
||||||
|
CONF_NAME: sensor_name,
|
||||||
|
CONF_REGISTER: 1234,
|
||||||
|
CONF_COUNT: 8,
|
||||||
|
CONF_PRECISION: 2,
|
||||||
|
CONF_DATA_TYPE: DATA_TYPE_CUSTOM,
|
||||||
|
CONF_STRUCTURE: ">4f",
|
||||||
|
},
|
||||||
|
sensor_name,
|
||||||
|
SENSOR_DOMAIN,
|
||||||
|
CONF_SENSORS,
|
||||||
|
CONF_REGISTERS,
|
||||||
|
[
|
||||||
|
0x40FD,
|
||||||
|
0xCCCD,
|
||||||
|
0x4129,
|
||||||
|
0x999A,
|
||||||
|
0x10FD,
|
||||||
|
0xC0CD,
|
||||||
|
0x4129,
|
||||||
|
0x109A,
|
||||||
|
],
|
||||||
|
expected,
|
||||||
|
method_discovery=False,
|
||||||
|
scan_interval=5,
|
||||||
|
)
|
||||||
|
assert state == expected
|
||||||
|
@ -711,7 +711,7 @@ async def test_dhcp_discovery_and_roomba_discovery_finds(hass, discovery_data):
|
|||||||
|
|
||||||
@pytest.mark.parametrize("discovery_data", DHCP_DISCOVERY_DEVICES_WITHOUT_MATCHING_IP)
|
@pytest.mark.parametrize("discovery_data", DHCP_DISCOVERY_DEVICES_WITHOUT_MATCHING_IP)
|
||||||
async def test_dhcp_discovery_falls_back_to_manual(hass, discovery_data):
|
async def test_dhcp_discovery_falls_back_to_manual(hass, discovery_data):
|
||||||
"""Test we can process the discovery from dhcp but roomba discovery cannot find the device."""
|
"""Test we can process the discovery from dhcp but roomba discovery cannot find the specific device."""
|
||||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||||
|
|
||||||
mocked_roomba = _create_mocked_roomba(
|
mocked_roomba = _create_mocked_roomba(
|
||||||
@ -782,6 +782,68 @@ async def test_dhcp_discovery_falls_back_to_manual(hass, discovery_data):
|
|||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("discovery_data", DHCP_DISCOVERY_DEVICES_WITHOUT_MATCHING_IP)
|
||||||
|
async def test_dhcp_discovery_no_devices_falls_back_to_manual(hass, discovery_data):
|
||||||
|
"""Test we can process the discovery from dhcp but roomba discovery cannot find any devices."""
|
||||||
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||||
|
|
||||||
|
mocked_roomba = _create_mocked_roomba(
|
||||||
|
roomba_connected=True,
|
||||||
|
master_state={"state": {"reported": {"name": "myroomba"}}},
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.roomba.config_flow.RoombaDiscovery",
|
||||||
|
_mocked_no_devices_found_discovery,
|
||||||
|
):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_DHCP},
|
||||||
|
data=discovery_data,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
|
assert result["errors"] is None
|
||||||
|
assert result["step_id"] == "manual"
|
||||||
|
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{CONF_HOST: MOCK_IP, CONF_BLID: "blid"},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
|
assert result2["errors"] is None
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.roomba.config_flow.Roomba",
|
||||||
|
return_value=mocked_roomba,
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.roomba.config_flow.RoombaPassword",
|
||||||
|
_mocked_getpassword,
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.roomba.async_setup_entry",
|
||||||
|
return_value=True,
|
||||||
|
) as mock_setup_entry:
|
||||||
|
result3 = await hass.config_entries.flow.async_configure(
|
||||||
|
result2["flow_id"],
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result3["title"] == "myroomba"
|
||||||
|
assert result3["result"].unique_id == "BLID"
|
||||||
|
assert result3["data"] == {
|
||||||
|
CONF_BLID: "BLID",
|
||||||
|
CONF_CONTINUOUS: True,
|
||||||
|
CONF_DELAY: 1,
|
||||||
|
CONF_HOST: MOCK_IP,
|
||||||
|
CONF_PASSWORD: "password",
|
||||||
|
}
|
||||||
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_dhcp_discovery_with_ignored(hass):
|
async def test_dhcp_discovery_with_ignored(hass):
|
||||||
"""Test ignored entries do not break checking for existing entries."""
|
"""Test ignored entries do not break checking for existing entries."""
|
||||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user