mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 05:37:44 +00:00
2025.1.4 (#136407)
Co-authored-by: Robert Resch <robert@resch.dev> Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: Matt Doran <mattdoran76@gmail.com> Co-authored-by: G Johansson <goran.johansson@shiftit.se> Co-authored-by: Makrit <sinticlee@gmail.com> Co-authored-by: Claudio Ruggeri - CR-Tech <41435902+crug80@users.noreply.github.com> Co-authored-by: Simon Lamon <32477463+silamon@users.noreply.github.com> Co-authored-by: Yuxin Wang <yuxinwang.dev@gmail.com> Co-authored-by: Åke Strandberg <ake@strandberg.eu> Co-authored-by: Paul Bottein <paul.bottein@gmail.com> Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> Co-authored-by: Klaas Schoute <klaas_schoute@hotmail.com> Fix slave id equal to 0 (#136263)
This commit is contained in:
commit
6145ea2323
@ -44,7 +44,10 @@ class APCUPSdData(dict[str, str]):
|
||||
@property
|
||||
def serial_no(self) -> str | None:
|
||||
"""Return the unique serial number of the UPS, if available."""
|
||||
return self.get("SERIALNO")
|
||||
sn = self.get("SERIALNO")
|
||||
# We had user reports that some UPS models simply return "Blank" as serial number, in
|
||||
# which case we fall back to `None` to indicate that it is actually not available.
|
||||
return None if sn == "Blank" else sn
|
||||
|
||||
|
||||
class APCUPSdCoordinator(DataUpdateCoordinator[APCUPSdData]):
|
||||
|
@ -21,5 +21,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||
"integration_type": "system",
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["home-assistant-frontend==20250109.0"]
|
||||
"requirements": ["home-assistant-frontend==20250109.2"]
|
||||
}
|
||||
|
@ -5,5 +5,5 @@
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/holiday",
|
||||
"iot_class": "local_polling",
|
||||
"requirements": ["holidays==0.64", "babel==2.15.0"]
|
||||
"requirements": ["holidays==0.65", "babel==2.15.0"]
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ ZONE_BINARY_SENSORS: tuple[HydrawiseBinarySensorEntityDescription, ...] = (
|
||||
)
|
||||
|
||||
SCHEMA_START_WATERING: VolDictType = {
|
||||
vol.Optional("duration"): vol.All(vol.Coerce(int), vol.Range(min=0, max=90)),
|
||||
vol.Optional("duration"): vol.All(vol.Coerce(int), vol.Range(min=0, max=1440)),
|
||||
}
|
||||
SCHEMA_SUSPEND: VolDictType = {
|
||||
vol.Required("until"): cv.datetime,
|
||||
|
@ -10,7 +10,7 @@ start_watering:
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 90
|
||||
max: 1440
|
||||
unit_of_measurement: min
|
||||
mode: box
|
||||
suspend:
|
||||
|
@ -44,9 +44,15 @@ class LinkPlayBaseEntity(Entity):
|
||||
if model != MANUFACTURER_GENERIC:
|
||||
model_id = bridge.device.properties["project"]
|
||||
|
||||
connections: set[tuple[str, str]] = set()
|
||||
if "MAC" in bridge.device.properties:
|
||||
connections.add(
|
||||
(dr.CONNECTION_NETWORK_MAC, bridge.device.properties["MAC"])
|
||||
)
|
||||
|
||||
self._attr_device_info = dr.DeviceInfo(
|
||||
configuration_url=bridge.endpoint,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, bridge.device.properties["MAC"])},
|
||||
connections=connections,
|
||||
hw_version=bridge.device.properties["hardware"],
|
||||
identifiers={(DOMAIN, bridge.device.uuid)},
|
||||
manufacturer=manufacturer,
|
||||
|
@ -79,7 +79,10 @@ class BasePlatform(Entity):
|
||||
"""Initialize the Modbus binary sensor."""
|
||||
|
||||
self._hub = hub
|
||||
self._slave = entry.get(CONF_SLAVE) or entry.get(CONF_DEVICE_ADDRESS, 0)
|
||||
if (conf_slave := entry.get(CONF_SLAVE)) is not None:
|
||||
self._slave = conf_slave
|
||||
else:
|
||||
self._slave = entry.get(CONF_DEVICE_ADDRESS, 1)
|
||||
self._address = int(entry[CONF_ADDRESS])
|
||||
self._input_type = entry[CONF_INPUT_TYPE]
|
||||
self._value: str | None = None
|
||||
|
@ -368,7 +368,9 @@ class ModbusHub:
|
||||
self, slave: int | None, address: int, value: int | list[int], use_call: str
|
||||
) -> ModbusPDU | None:
|
||||
"""Call sync. pymodbus."""
|
||||
kwargs = {"slave": slave} if slave else {}
|
||||
kwargs: dict[str, Any] = (
|
||||
{ATTR_SLAVE: slave} if slave is not None else {ATTR_SLAVE: 1}
|
||||
)
|
||||
entry = self._pb_request[use_call]
|
||||
try:
|
||||
result: ModbusPDU = await entry.func(address, value, **kwargs)
|
||||
|
@ -325,10 +325,10 @@ class MyUplinkEnumSensor(MyUplinkDevicePointSensor):
|
||||
}
|
||||
|
||||
@property
|
||||
def native_value(self) -> str:
|
||||
def native_value(self) -> str | None:
|
||||
"""Sensor state value for enum sensor."""
|
||||
device_point = self.coordinator.data.points[self.device_id][self.point_id]
|
||||
return self.options_map[str(int(device_point.value))] # type: ignore[no-any-return]
|
||||
return self.options_map.get(str(int(device_point.value)))
|
||||
|
||||
|
||||
class MyUplinkEnumRawSensor(MyUplinkDevicePointSensor):
|
||||
|
@ -23,7 +23,7 @@ PEBLAR_CHARGE_LIMITER_TO_HOME_ASSISTANT = {
|
||||
ChargeLimiter.INSTALLATION_LIMIT: "installation_limit",
|
||||
ChargeLimiter.LOCAL_MODBUS_API: "local_modbus_api",
|
||||
ChargeLimiter.LOCAL_REST_API: "local_rest_api",
|
||||
ChargeLimiter.LOCAL_SCHEDULED: "local_scheduled",
|
||||
ChargeLimiter.LOCAL_SCHEDULED_CHARGING: "local_scheduled_charging",
|
||||
ChargeLimiter.OCPP_SMART_CHARGING: "ocpp_smart_charging",
|
||||
ChargeLimiter.OVERCURRENT_PROTECTION: "overcurrent_protection",
|
||||
ChargeLimiter.PHASE_IMBALANCE: "phase_imbalance",
|
||||
|
@ -7,6 +7,6 @@
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_polling",
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["peblar==0.3.3"],
|
||||
"requirements": ["peblar==0.4.0"],
|
||||
"zeroconf": [{ "type": "_http._tcp.local.", "name": "pblr-*" }]
|
||||
}
|
||||
|
@ -96,6 +96,7 @@
|
||||
"installation_limit": "Installation limit",
|
||||
"local_modbus_api": "Modbus API",
|
||||
"local_rest_api": "REST API",
|
||||
"local_scheduled_charging": "Scheduled charging",
|
||||
"ocpp_smart_charging": "OCPP smart charging",
|
||||
"overcurrent_protection": "Overcurrent protection",
|
||||
"phase_imbalance": "Phase imbalance",
|
||||
|
@ -6,7 +6,7 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/powerfox",
|
||||
"iot_class": "cloud_polling",
|
||||
"quality_scale": "silver",
|
||||
"requirements": ["powerfox==1.2.0"],
|
||||
"requirements": ["powerfox==1.2.1"],
|
||||
"zeroconf": [
|
||||
{
|
||||
"type": "_http._tcp.local.",
|
||||
|
@ -122,7 +122,7 @@ class TwitchCoordinator(DataUpdateCoordinator[dict[str, TwitchUpdate]]):
|
||||
stream.game_name if stream else None,
|
||||
stream.title if stream else None,
|
||||
stream.started_at if stream else None,
|
||||
stream.thumbnail_url if stream else None,
|
||||
stream.thumbnail_url.format(width="", height="") if stream else None,
|
||||
channel.profile_image_url,
|
||||
bool(sub),
|
||||
sub.is_gift if sub else None,
|
||||
|
@ -13,5 +13,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/withings",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["aiowithings"],
|
||||
"requirements": ["aiowithings==3.1.4"]
|
||||
"requirements": ["aiowithings==3.1.5"]
|
||||
}
|
||||
|
@ -7,5 +7,5 @@
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["holidays"],
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["holidays==0.64"]
|
||||
"requirements": ["holidays==0.65"]
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ if TYPE_CHECKING:
|
||||
APPLICATION_NAME: Final = "HomeAssistant"
|
||||
MAJOR_VERSION: Final = 2025
|
||||
MINOR_VERSION: Final = 1
|
||||
PATCH_VERSION: Final = "3"
|
||||
PATCH_VERSION: Final = "4"
|
||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 12, 0)
|
||||
|
@ -35,7 +35,7 @@ habluetooth==3.7.0
|
||||
hass-nabucasa==0.87.0
|
||||
hassil==2.1.0
|
||||
home-assistant-bluetooth==1.13.0
|
||||
home-assistant-frontend==20250109.0
|
||||
home-assistant-frontend==20250109.2
|
||||
home-assistant-intents==2025.1.1
|
||||
httpx==0.27.2
|
||||
ifaddr==0.2.0
|
||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "homeassistant"
|
||||
version = "2025.1.3"
|
||||
version = "2025.1.4"
|
||||
license = {text = "Apache-2.0"}
|
||||
description = "Open-source home automation platform running on Python 3."
|
||||
readme = "README.rst"
|
||||
|
@ -416,7 +416,7 @@ aiowatttime==0.1.1
|
||||
aiowebostv==0.4.2
|
||||
|
||||
# homeassistant.components.withings
|
||||
aiowithings==3.1.4
|
||||
aiowithings==3.1.5
|
||||
|
||||
# homeassistant.components.yandex_transport
|
||||
aioymaps==1.2.5
|
||||
@ -1131,10 +1131,10 @@ hole==0.8.0
|
||||
|
||||
# homeassistant.components.holiday
|
||||
# homeassistant.components.workday
|
||||
holidays==0.64
|
||||
holidays==0.65
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20250109.0
|
||||
home-assistant-frontend==20250109.2
|
||||
|
||||
# homeassistant.components.conversation
|
||||
home-assistant-intents==2025.1.1
|
||||
@ -1603,7 +1603,7 @@ panasonic-viera==0.4.2
|
||||
pdunehd==1.3.2
|
||||
|
||||
# homeassistant.components.peblar
|
||||
peblar==0.3.3
|
||||
peblar==0.4.0
|
||||
|
||||
# homeassistant.components.peco
|
||||
peco==0.0.30
|
||||
@ -1650,7 +1650,7 @@ pmsensor==0.4
|
||||
poolsense==0.0.8
|
||||
|
||||
# homeassistant.components.powerfox
|
||||
powerfox==1.2.0
|
||||
powerfox==1.2.1
|
||||
|
||||
# homeassistant.components.reddit
|
||||
praw==7.5.0
|
||||
|
@ -398,7 +398,7 @@ aiowatttime==0.1.1
|
||||
aiowebostv==0.4.2
|
||||
|
||||
# homeassistant.components.withings
|
||||
aiowithings==3.1.4
|
||||
aiowithings==3.1.5
|
||||
|
||||
# homeassistant.components.yandex_transport
|
||||
aioymaps==1.2.5
|
||||
@ -960,10 +960,10 @@ hole==0.8.0
|
||||
|
||||
# homeassistant.components.holiday
|
||||
# homeassistant.components.workday
|
||||
holidays==0.64
|
||||
holidays==0.65
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20250109.0
|
||||
home-assistant-frontend==20250109.2
|
||||
|
||||
# homeassistant.components.conversation
|
||||
home-assistant-intents==2025.1.1
|
||||
@ -1330,7 +1330,7 @@ panasonic-viera==0.4.2
|
||||
pdunehd==1.3.2
|
||||
|
||||
# homeassistant.components.peblar
|
||||
peblar==0.3.3
|
||||
peblar==0.4.0
|
||||
|
||||
# homeassistant.components.peco
|
||||
peco==0.0.30
|
||||
@ -1360,7 +1360,7 @@ plumlightpad==0.0.11
|
||||
poolsense==0.0.8
|
||||
|
||||
# homeassistant.components.powerfox
|
||||
powerfox==1.2.0
|
||||
powerfox==1.2.1
|
||||
|
||||
# homeassistant.components.reddit
|
||||
praw==7.5.0
|
||||
|
@ -125,6 +125,8 @@ async def test_flow_works(hass: HomeAssistant) -> None:
|
||||
({"UPSNAME": "Friendly Name"}, "Friendly Name"),
|
||||
({"MODEL": "MODEL X"}, "MODEL X"),
|
||||
({"SERIALNO": "ZZZZ"}, "ZZZZ"),
|
||||
# Some models report "Blank" as serial number, which we should treat it as not reported.
|
||||
({"SERIALNO": "Blank"}, "APC UPS"),
|
||||
({}, "APC UPS"),
|
||||
],
|
||||
)
|
||||
|
@ -31,6 +31,8 @@ from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
# Does not contain either "SERIALNO" field.
|
||||
# We should _not_ create devices for the entities and their IDs will not have prefixes.
|
||||
MOCK_MINIMAL_STATUS,
|
||||
# Some models report "Blank" as SERIALNO, but we should treat it as not reported.
|
||||
MOCK_MINIMAL_STATUS | {"SERIALNO": "Blank"},
|
||||
],
|
||||
)
|
||||
async def test_async_setup_entry(hass: HomeAssistant, status: OrderedDict) -> None:
|
||||
@ -41,7 +43,7 @@ async def test_async_setup_entry(hass: HomeAssistant, status: OrderedDict) -> No
|
||||
await async_init_integration(hass, status=status)
|
||||
|
||||
prefix = ""
|
||||
if "SERIALNO" in status:
|
||||
if "SERIALNO" in status and status["SERIALNO"] != "Blank":
|
||||
prefix = slugify(status.get("UPSNAME", "APC UPS")) + "_"
|
||||
|
||||
# Verify successful setup by querying the status sensor.
|
||||
@ -56,6 +58,8 @@ async def test_async_setup_entry(hass: HomeAssistant, status: OrderedDict) -> No
|
||||
[
|
||||
# We should not create device entries if SERIALNO is not reported.
|
||||
MOCK_MINIMAL_STATUS,
|
||||
# Some models report "Blank" as SERIALNO, but we should treat it as not reported.
|
||||
MOCK_MINIMAL_STATUS | {"SERIALNO": "Blank"},
|
||||
# We should set the device name to be the friendly UPSNAME field if available.
|
||||
MOCK_MINIMAL_STATUS | {"SERIALNO": "XXXX", "UPSNAME": "MyUPS"},
|
||||
# Otherwise, we should fall back to default device name --- "APC UPS".
|
||||
@ -71,7 +75,7 @@ async def test_device_entry(
|
||||
await async_init_integration(hass, status=status)
|
||||
|
||||
# Verify device info is properly set up.
|
||||
if "SERIALNO" not in status:
|
||||
if "SERIALNO" not in status or status["SERIALNO"] == "Blank":
|
||||
assert len(device_registry.devices) == 0
|
||||
return
|
||||
|
||||
|
@ -1265,3 +1265,56 @@ async def test_no_entities(hass: HomeAssistant) -> None:
|
||||
]
|
||||
}
|
||||
assert await async_setup_component(hass, DOMAIN, config) is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("do_config", "expected_slave_value"),
|
||||
[
|
||||
(
|
||||
{
|
||||
CONF_SENSORS: [
|
||||
{
|
||||
CONF_NAME: "dummy",
|
||||
CONF_ADDRESS: 1234,
|
||||
},
|
||||
],
|
||||
},
|
||||
1,
|
||||
),
|
||||
(
|
||||
{
|
||||
CONF_SENSORS: [
|
||||
{
|
||||
CONF_NAME: "dummy",
|
||||
CONF_ADDRESS: 1234,
|
||||
CONF_SLAVE: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
0,
|
||||
),
|
||||
(
|
||||
{
|
||||
CONF_SENSORS: [
|
||||
{
|
||||
CONF_NAME: "dummy",
|
||||
CONF_ADDRESS: 1234,
|
||||
CONF_DEVICE_ADDRESS: 6,
|
||||
},
|
||||
],
|
||||
},
|
||||
6,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_check_default_slave(
|
||||
hass: HomeAssistant,
|
||||
mock_modbus,
|
||||
do_config,
|
||||
mock_do_cycle,
|
||||
expected_slave_value: int,
|
||||
) -> None:
|
||||
"""Test default slave."""
|
||||
assert mock_modbus.read_holding_registers.mock_calls
|
||||
first_call = mock_modbus.read_holding_registers.mock_calls[0]
|
||||
assert first_call.kwargs["slave"] == expected_slave_value
|
||||
|
@ -822,7 +822,7 @@
|
||||
"parameterUnit": "",
|
||||
"writable": false,
|
||||
"timestamp": "2024-02-08T19:13:05+00:00",
|
||||
"value": 30,
|
||||
"value": 31,
|
||||
"strVal": "Heating",
|
||||
"smartHomeCategories": [],
|
||||
"minValue": null,
|
||||
|
@ -883,7 +883,7 @@
|
||||
"parameterUnit": "",
|
||||
"writable": false,
|
||||
"timestamp": "2024-02-08T19:13:05+00:00",
|
||||
"value": 30,
|
||||
"value": 31,
|
||||
"strVal": "Heating",
|
||||
"smartHomeCategories": [],
|
||||
"minValue": null,
|
||||
@ -2045,7 +2045,7 @@
|
||||
"parameterUnit": "",
|
||||
"writable": false,
|
||||
"timestamp": "2024-02-08T19:13:05+00:00",
|
||||
"value": 30,
|
||||
"value": 31,
|
||||
"strVal": "Heating",
|
||||
"smartHomeCategories": [],
|
||||
"minValue": null,
|
||||
|
@ -3396,7 +3396,7 @@
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'Heating',
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor_states[sensor.gotham_city_priority_2-entry]
|
||||
@ -3462,7 +3462,7 @@
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'Heating',
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor_states[sensor.gotham_city_priority_raw-entry]
|
||||
@ -3508,7 +3508,7 @@
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '30',
|
||||
'state': '31',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor_states[sensor.gotham_city_priority_raw_2-entry]
|
||||
@ -3554,7 +3554,7 @@
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '30',
|
||||
'state': '31',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensor_states[sensor.gotham_city_r_start_diff_additional_heat-entry]
|
||||
|
@ -51,10 +51,8 @@
|
||||
'Hostname': 'PBLR-0000645',
|
||||
'HwFixedCableRating': 20,
|
||||
'HwFwCompat': 'wlac-2',
|
||||
'HwHas4pRelay': False,
|
||||
'HwHasBop': True,
|
||||
'HwHasBuzzer': True,
|
||||
'HwHasDualSocket': False,
|
||||
'HwHasEichrechtLaserMarking': False,
|
||||
'HwHasEthernet': True,
|
||||
'HwHasLed': True,
|
||||
@ -64,13 +62,11 @@
|
||||
'HwHasPlc': False,
|
||||
'HwHasRfid': True,
|
||||
'HwHasRs485': True,
|
||||
'HwHasShutter': False,
|
||||
'HwHasSocket': False,
|
||||
'HwHasTpm': False,
|
||||
'HwHasWlan': True,
|
||||
'HwMaxCurrent': 16,
|
||||
'HwOneOrThreePhase': 3,
|
||||
'HwUKCompliant': False,
|
||||
'MainboardPn': '6004-2300-7600',
|
||||
'MainboardSn': '23-38-A4E-2MC',
|
||||
'MeterCalIGainA': 267369,
|
||||
@ -86,7 +82,6 @@
|
||||
'MeterCalVGainB': 246074,
|
||||
'MeterCalVGainC': 230191,
|
||||
'MeterFwIdent': 'b9cbcd',
|
||||
'NorFlash': 'True',
|
||||
'ProductModelName': 'WLAC1-H11R0WE0ICR00',
|
||||
'ProductPn': '6004-2300-8002',
|
||||
'ProductSn': '23-45-A4O-MOF',
|
||||
|
@ -302,7 +302,7 @@
|
||||
'installation_limit',
|
||||
'local_modbus_api',
|
||||
'local_rest_api',
|
||||
'local_scheduled',
|
||||
'local_scheduled_charging',
|
||||
'ocpp_smart_charging',
|
||||
'overcurrent_protection',
|
||||
'phase_imbalance',
|
||||
@ -354,7 +354,7 @@
|
||||
'installation_limit',
|
||||
'local_modbus_api',
|
||||
'local_rest_api',
|
||||
'local_scheduled',
|
||||
'local_scheduled_charging',
|
||||
'ocpp_smart_charging',
|
||||
'overcurrent_protection',
|
||||
'phase_imbalance',
|
||||
|
Loading…
x
Reference in New Issue
Block a user