From 74d10b9824444350a4007085200ea6810a678ee2 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Mon, 22 Jul 2024 01:11:05 +0200 Subject: [PATCH 01/16] Bump `aiotractive` to 0.6.0 (#121155) Co-authored-by: Maciej Bieniek <478555+bieniu@users.noreply.github.com> Co-authored-by: J. Nick Koston --- homeassistant/components/tractive/__init__.py | 2 +- homeassistant/components/tractive/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/tractive/__init__.py b/homeassistant/components/tractive/__init__.py index fd5abe24c06..4f0de7b14cd 100644 --- a/homeassistant/components/tractive/__init__.py +++ b/homeassistant/components/tractive/__init__.py @@ -132,7 +132,7 @@ async def _generate_trackables( trackable = await trackable.details() # Check that the pet has tracker linked. - if not trackable["device_id"]: + if not trackable.get("device_id"): return None if "details" not in trackable: diff --git a/homeassistant/components/tractive/manifest.json b/homeassistant/components/tractive/manifest.json index 75ddf065bd7..903c5347d52 100644 --- a/homeassistant/components/tractive/manifest.json +++ b/homeassistant/components/tractive/manifest.json @@ -7,5 +7,5 @@ "integration_type": "device", "iot_class": "cloud_push", "loggers": ["aiotractive"], - "requirements": ["aiotractive==0.5.6"] + "requirements": ["aiotractive==0.6.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index 1512acef5e8..6c87b9bd19a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -386,7 +386,7 @@ aiosyncthing==0.5.1 aiotankerkoenig==0.4.1 # homeassistant.components.tractive -aiotractive==0.5.6 +aiotractive==0.6.0 # homeassistant.components.unifi aiounifi==79 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index a7cbf46c54b..a0b1497a185 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -359,7 +359,7 @@ aiosyncthing==0.5.1 aiotankerkoenig==0.4.1 # homeassistant.components.tractive -aiotractive==0.5.6 +aiotractive==0.6.0 # homeassistant.components.unifi aiounifi==79 From cf20e67f1f541a8d28703b4dceb218403c2ba1e4 Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Sun, 21 Jul 2024 12:36:06 +0200 Subject: [PATCH 02/16] Ensure mqtt subscriptions are in a set (#122201) --- homeassistant/components/mqtt/__init__.py | 2 +- homeassistant/components/mqtt/client.py | 8 ++++---- homeassistant/components/mqtt/models.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index f057dab8bc4..2b3aa21aa22 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -251,7 +251,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: mqtt_data.client.async_restore_tracked_subscriptions( mqtt_data.subscriptions_to_restore ) - mqtt_data.subscriptions_to_restore = [] + mqtt_data.subscriptions_to_restore = set() mqtt_data.reload_dispatchers.append( entry.add_update_listener(_async_config_entry_updated) ) diff --git a/homeassistant/components/mqtt/client.py b/homeassistant/components/mqtt/client.py index f65769badfa..d242ec019c6 100644 --- a/homeassistant/components/mqtt/client.py +++ b/homeassistant/components/mqtt/client.py @@ -428,12 +428,12 @@ class MQTT: await self.async_init_client() @property - def subscriptions(self) -> list[Subscription]: + def subscriptions(self) -> set[Subscription]: """Return the tracked subscriptions.""" - return [ + return { *chain.from_iterable(self._simple_subscriptions.values()), *self._wildcard_subscriptions, - ] + } def cleanup(self) -> None: """Clean up listeners.""" @@ -736,7 +736,7 @@ class MQTT: @callback def async_restore_tracked_subscriptions( - self, subscriptions: list[Subscription] + self, subscriptions: set[Subscription] ) -> None: """Restore tracked subscriptions after reload.""" for subscription in subscriptions: diff --git a/homeassistant/components/mqtt/models.py b/homeassistant/components/mqtt/models.py index e5a9a9c44da..c355510a5c2 100644 --- a/homeassistant/components/mqtt/models.py +++ b/homeassistant/components/mqtt/models.py @@ -423,7 +423,7 @@ class MqttData: reload_handlers: dict[str, CALLBACK_TYPE] = field(default_factory=dict) reload_schema: dict[str, VolSchemaType] = field(default_factory=dict) state_write_requests: EntityTopicState = field(default_factory=EntityTopicState) - subscriptions_to_restore: list[Subscription] = field(default_factory=list) + subscriptions_to_restore: set[Subscription] = field(default_factory=set) tags: dict[str, dict[str, MQTTTagScanner]] = field(default_factory=dict) From 683069cb9850e724594306ddd73fee92c713bbbf Mon Sep 17 00:00:00 2001 From: Alexander Schneider Date: Sun, 21 Jul 2024 14:51:10 -0700 Subject: [PATCH 03/16] Add Z-Wave discovery schema for ZVIDAR roller shades (#122332) Add discovery schema for ZVIDAR roller shades --- .../components/zwave_js/discovery.py | 9 + tests/components/zwave_js/conftest.py | 14 + .../zwave_js/fixtures/cover_zvidar_state.json | 1120 +++++++++++++++++ tests/components/zwave_js/test_discovery.py | 12 + 4 files changed, 1155 insertions(+) create mode 100644 tests/components/zwave_js/fixtures/cover_zvidar_state.json diff --git a/homeassistant/components/zwave_js/discovery.py b/homeassistant/components/zwave_js/discovery.py index 0b66567c036..6798e644a02 100644 --- a/homeassistant/components/zwave_js/discovery.py +++ b/homeassistant/components/zwave_js/discovery.py @@ -579,6 +579,15 @@ DISCOVERY_SCHEMAS = [ ), entity_registry_enabled_default=False, ), + # ZVIDAR Z-CM-V01 (SmartWings/Deyi WM25L/V Z-Wave Motor for Roller Shade) + ZWaveDiscoverySchema( + platform=Platform.COVER, + hint="shade", + manufacturer_id={0x045A}, + product_id={0x0507}, + product_type={0x0904}, + primary_value=SWITCH_MULTILEVEL_CURRENT_VALUE_SCHEMA, + ), # Vision Security ZL7432 In Wall Dual Relay Switch ZWaveDiscoverySchema( platform=Platform.SWITCH, diff --git a/tests/components/zwave_js/conftest.py b/tests/components/zwave_js/conftest.py index a2a4c217b8b..31c9c5affa5 100644 --- a/tests/components/zwave_js/conftest.py +++ b/tests/components/zwave_js/conftest.py @@ -472,6 +472,12 @@ def iblinds_v3_state_fixture(): return json.loads(load_fixture("zwave_js/cover_iblinds_v3_state.json")) +@pytest.fixture(name="zvidar_state", scope="package") +def zvidar_state_fixture(): + """Load the ZVIDAR node state fixture data.""" + return json.loads(load_fixture("zwave_js/cover_zvidar_state.json")) + + @pytest.fixture(name="qubino_shutter_state", scope="package") def qubino_shutter_state_fixture(): """Load the Qubino Shutter node state fixture data.""" @@ -1081,6 +1087,14 @@ def iblinds_v3_cover_fixture(client, iblinds_v3_state): return node +@pytest.fixture(name="zvidar") +def zvidar_cover_fixture(client, zvidar_state): + """Mock a ZVIDAR window cover node.""" + node = Node(client, copy.deepcopy(zvidar_state)) + client.driver.controller.nodes[node.node_id] = node + return node + + @pytest.fixture(name="qubino_shutter") def qubino_shutter_cover_fixture(client, qubino_shutter_state): """Mock a Qubino flush shutter node.""" diff --git a/tests/components/zwave_js/fixtures/cover_zvidar_state.json b/tests/components/zwave_js/fixtures/cover_zvidar_state.json new file mode 100644 index 00000000000..05118931026 --- /dev/null +++ b/tests/components/zwave_js/fixtures/cover_zvidar_state.json @@ -0,0 +1,1120 @@ +{ + "nodeId": 270, + "index": 0, + "installerIcon": 6656, + "userIcon": 6656, + "status": 4, + "ready": true, + "isListening": false, + "isRouting": false, + "isSecure": true, + "manufacturerId": 1114, + "productId": 1287, + "productType": 2308, + "firmwareVersion": "1.10.0", + "zwavePlusVersion": 2, + "name": "Window Blind Controller", + "location": "**REDACTED**", + "deviceConfig": { + "filename": "/snapshot/build/node_modules/@zwave-js/config/config/devices/0x045a/Z-CM-V01.json", + "isEmbedded": true, + "manufacturer": "ZVIDAR", + "manufacturerId": 1114, + "label": "Z-CM-V01", + "description": "Smart Curtain Motor", + "devices": [ + { + "productType": 2308, + "productId": 1287 + } + ], + "firmwareVersion": { + "min": "0.0", + "max": "255.255" + }, + "preferred": false, + "paramInformation": { + "_map": {} + }, + "compat": { + "removeCCs": {} + } + }, + "label": "Z-CM-V01", + "interviewAttempts": 0, + "isFrequentListening": "1000ms", + "maxDataRate": 100000, + "supportedDataRates": [100000], + "protocolVersion": 3, + "supportsBeaming": false, + "supportsSecurity": true, + "nodeType": 1, + "zwavePlusNodeType": 0, + "zwavePlusRoleType": 7, + "deviceClass": { + "basic": { + "key": 3, + "label": "End Node" + }, + "generic": { + "key": 17, + "label": "Multilevel Switch" + }, + "specific": { + "key": 0, + "label": "Unused" + } + }, + "interviewStage": "Complete", + "deviceDatabaseUrl": "https://devices.zwave-js.io/?jumpTo=0x045a:0x0904:0x0507:1.10.0", + "statistics": { + "commandsTX": 2, + "commandsRX": 1, + "commandsDroppedRX": 1, + "commandsDroppedTX": 0, + "timeoutResponse": 0, + "rtt": 357.6, + "lastSeen": "2024-07-21T16:42:38.086Z", + "rssi": -89, + "lwr": { + "protocolDataRate": 4, + "repeaters": [], + "rssi": -91, + "repeaterRSSI": [] + } + }, + "highestSecurityClass": 1, + "isControllerNode": false, + "keepAwake": false, + "lastSeen": "2024-07-21T16:42:38.086Z", + "protocol": 1, + "values": [ + { + "endpoint": 0, + "commandClass": 38, + "commandClassName": "Multilevel Switch", + "property": "targetValue", + "propertyName": "targetValue", + "ccVersion": 4, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Target value", + "valueChangeOptions": ["transitionDuration"], + "min": 0, + "max": 99, + "stateful": true, + "secret": false + }, + "value": 0 + }, + { + "endpoint": 0, + "commandClass": 38, + "commandClassName": "Multilevel Switch", + "property": "duration", + "propertyName": "duration", + "ccVersion": 4, + "metadata": { + "type": "duration", + "readable": true, + "writeable": false, + "label": "Remaining duration", + "stateful": true, + "secret": false + }, + "value": "unknown" + }, + { + "endpoint": 0, + "commandClass": 38, + "commandClassName": "Multilevel Switch", + "property": "currentValue", + "propertyName": "currentValue", + "ccVersion": 4, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "label": "Current value", + "min": 0, + "max": 99, + "stateful": true, + "secret": false + }, + "value": 0 + }, + { + "endpoint": 0, + "commandClass": 38, + "commandClassName": "Multilevel Switch", + "property": "Up", + "propertyName": "Up", + "ccVersion": 4, + "metadata": { + "type": "boolean", + "readable": false, + "writeable": true, + "label": "Perform a level change (Up)", + "ccSpecific": { + "switchType": 2 + }, + "valueChangeOptions": ["transitionDuration"], + "states": { + "true": "Start", + "false": "Stop" + }, + "stateful": true, + "secret": false + }, + "value": true + }, + { + "endpoint": 0, + "commandClass": 38, + "commandClassName": "Multilevel Switch", + "property": "Down", + "propertyName": "Down", + "ccVersion": 4, + "metadata": { + "type": "boolean", + "readable": false, + "writeable": true, + "label": "Perform a level change (Down)", + "ccSpecific": { + "switchType": 2 + }, + "valueChangeOptions": ["transitionDuration"], + "states": { + "true": "Start", + "false": "Stop" + }, + "stateful": true, + "secret": false + }, + "value": true + }, + { + "endpoint": 0, + "commandClass": 38, + "commandClassName": "Multilevel Switch", + "property": "restorePrevious", + "propertyName": "restorePrevious", + "ccVersion": 4, + "metadata": { + "type": "boolean", + "readable": false, + "writeable": true, + "label": "Restore previous value", + "states": { + "true": "Restore" + }, + "stateful": true, + "secret": false + } + }, + { + "endpoint": 0, + "commandClass": 112, + "commandClassName": "Configuration", + "property": 1, + "propertyName": "Hand Button Action", + "ccVersion": 4, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Hand Button Action", + "default": 1, + "min": 0, + "max": 1, + "states": { + "0": "Close", + "1": "Open" + }, + "valueSize": 1, + "format": 0, + "allowManualEntry": false, + "isFromConfig": true + }, + "value": 1 + }, + { + "endpoint": 0, + "commandClass": 112, + "commandClassName": "Configuration", + "property": 2, + "propertyName": "Motor Direction", + "ccVersion": 4, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Motor Direction", + "default": 1, + "min": 1, + "max": 3, + "states": { + "1": "Forward", + "2": "Opposite", + "3": "Reverse" + }, + "valueSize": 1, + "format": 0, + "allowManualEntry": false, + "isFromConfig": true + }, + "value": 1 + }, + { + "endpoint": 0, + "commandClass": 112, + "commandClassName": "Configuration", + "property": 3, + "propertyName": "Manually Set Open Boundary", + "ccVersion": 4, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Manually Set Open Boundary", + "default": 0, + "min": 0, + "max": 1, + "states": { + "0": "Cancel", + "1": "Start" + }, + "valueSize": 1, + "format": 0, + "allowManualEntry": false, + "isFromConfig": true + }, + "value": 0 + }, + { + "endpoint": 0, + "commandClass": 112, + "commandClassName": "Configuration", + "property": 4, + "propertyName": "Manually Set Closed Boundary", + "ccVersion": 4, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Manually Set Closed Boundary", + "default": 0, + "min": 0, + "max": 1, + "states": { + "0": "Cancel", + "1": "Start" + }, + "valueSize": 1, + "format": 0, + "allowManualEntry": false, + "isFromConfig": true + }, + "value": 0 + }, + { + "endpoint": 0, + "commandClass": 112, + "commandClassName": "Configuration", + "property": 5, + "propertyName": "Control Motor", + "ccVersion": 4, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Control Motor", + "default": 3, + "min": 1, + "max": 3, + "states": { + "1": "Open (Up)", + "2": "Close (Down)", + "3": "Stop" + }, + "valueSize": 1, + "format": 0, + "allowManualEntry": false, + "isFromConfig": true + }, + "value": 3 + }, + { + "endpoint": 0, + "commandClass": 112, + "commandClassName": "Configuration", + "property": 6, + "propertyName": "Calibrate Limit Position", + "ccVersion": 4, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Calibrate Limit Position", + "default": 1, + "min": 1, + "max": 3, + "states": { + "1": "Upper limit", + "2": "Lower limit", + "3": "Third limit" + }, + "valueSize": 1, + "format": 0, + "allowManualEntry": false, + "isFromConfig": true + }, + "value": 1 + }, + { + "endpoint": 0, + "commandClass": 112, + "commandClassName": "Configuration", + "property": 7, + "propertyName": "Delete Limit Position", + "ccVersion": 4, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Delete Limit Position", + "default": 0, + "min": 0, + "max": 3, + "states": { + "0": "All limits", + "1": "Only upper limit", + "2": "Only lower limit", + "3": "Only third limit" + }, + "valueSize": 1, + "format": 0, + "allowManualEntry": false, + "isFromConfig": true + }, + "value": 0 + }, + { + "endpoint": 0, + "commandClass": 112, + "commandClassName": "Configuration", + "property": 8, + "propertyName": "Low Battery Level Alarm Threshold", + "ccVersion": 4, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Low Battery Level Alarm Threshold", + "default": 10, + "min": 0, + "max": 50, + "unit": "%", + "valueSize": 1, + "format": 0, + "allowManualEntry": true, + "isFromConfig": true + }, + "value": 10 + }, + { + "endpoint": 0, + "commandClass": 112, + "commandClassName": "Configuration", + "property": 9, + "propertyName": "Battery Report Interval", + "ccVersion": 4, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Battery Report Interval", + "default": 3600, + "min": 0, + "max": 2678400, + "unit": "seconds", + "valueSize": 4, + "format": 0, + "allowManualEntry": true, + "isFromConfig": true + }, + "value": 3600 + }, + { + "endpoint": 0, + "commandClass": 112, + "commandClassName": "Configuration", + "property": 10, + "propertyName": "Battery Change Report Threshold", + "ccVersion": 4, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Battery Change Report Threshold", + "default": 5, + "min": 0, + "max": 50, + "unit": "%", + "valueSize": 1, + "format": 0, + "allowManualEntry": true, + "isFromConfig": true + }, + "value": 5 + }, + { + "endpoint": 0, + "commandClass": 113, + "commandClassName": "Notification", + "property": "Power Management", + "propertyKey": "Mains status", + "propertyName": "Power Management", + "propertyKeyName": "Mains status", + "ccVersion": 8, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "label": "Mains status", + "ccSpecific": { + "notificationType": 8 + }, + "min": 0, + "max": 255, + "states": { + "2": "AC mains disconnected", + "3": "AC mains re-connected" + }, + "stateful": true, + "secret": false + } + }, + { + "endpoint": 0, + "commandClass": 113, + "commandClassName": "Notification", + "property": "alarmType", + "propertyName": "alarmType", + "ccVersion": 8, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "label": "Alarm Type", + "min": 0, + "max": 255, + "stateful": true, + "secret": false + } + }, + { + "endpoint": 0, + "commandClass": 113, + "commandClassName": "Notification", + "property": "alarmLevel", + "propertyName": "alarmLevel", + "ccVersion": 8, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "label": "Alarm Level", + "min": 0, + "max": 255, + "stateful": true, + "secret": false + } + }, + { + "endpoint": 0, + "commandClass": 114, + "commandClassName": "Manufacturer Specific", + "property": "manufacturerId", + "propertyName": "manufacturerId", + "ccVersion": 2, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "label": "Manufacturer ID", + "min": 0, + "max": 65535, + "stateful": true, + "secret": false + }, + "value": 1114 + }, + { + "endpoint": 0, + "commandClass": 114, + "commandClassName": "Manufacturer Specific", + "property": "productType", + "propertyName": "productType", + "ccVersion": 2, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "label": "Product type", + "min": 0, + "max": 65535, + "stateful": true, + "secret": false + }, + "value": 2308 + }, + { + "endpoint": 0, + "commandClass": 114, + "commandClassName": "Manufacturer Specific", + "property": "productId", + "propertyName": "productId", + "ccVersion": 2, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "label": "Product ID", + "min": 0, + "max": 65535, + "stateful": true, + "secret": false + }, + "value": 1287 + }, + { + "endpoint": 0, + "commandClass": 128, + "commandClassName": "Battery", + "property": "level", + "propertyName": "level", + "ccVersion": 1, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "label": "Battery level", + "min": 0, + "max": 100, + "unit": "%", + "stateful": true, + "secret": false + }, + "value": 86 + }, + { + "endpoint": 0, + "commandClass": 128, + "commandClassName": "Battery", + "property": "isLow", + "propertyName": "isLow", + "ccVersion": 1, + "metadata": { + "type": "boolean", + "readable": true, + "writeable": false, + "label": "Low battery level", + "stateful": true, + "secret": false + }, + "value": false + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "libraryType", + "propertyName": "libraryType", + "ccVersion": 3, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "label": "Library type", + "states": { + "0": "Unknown", + "1": "Static Controller", + "2": "Controller", + "3": "Enhanced Slave", + "4": "Slave", + "5": "Installer", + "6": "Routing Slave", + "7": "Bridge Controller", + "8": "Device under Test", + "9": "N/A", + "10": "AV Remote", + "11": "AV Device" + }, + "stateful": true, + "secret": false + }, + "value": 3 + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "protocolVersion", + "propertyName": "protocolVersion", + "ccVersion": 3, + "metadata": { + "type": "string", + "readable": true, + "writeable": false, + "label": "Z-Wave protocol version", + "stateful": true, + "secret": false + }, + "value": "7.16" + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "firmwareVersions", + "propertyName": "firmwareVersions", + "ccVersion": 3, + "metadata": { + "type": "string[]", + "readable": true, + "writeable": false, + "label": "Z-Wave chip firmware versions", + "stateful": true, + "secret": false + }, + "value": ["1.10"] + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "hardwareVersion", + "propertyName": "hardwareVersion", + "ccVersion": 3, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "label": "Z-Wave chip hardware version", + "stateful": true, + "secret": false + }, + "value": 1 + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "sdkVersion", + "propertyName": "sdkVersion", + "ccVersion": 3, + "metadata": { + "type": "string", + "readable": true, + "writeable": false, + "label": "SDK version", + "stateful": true, + "secret": false + }, + "value": "7.16.3" + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "applicationFrameworkAPIVersion", + "propertyName": "applicationFrameworkAPIVersion", + "ccVersion": 3, + "metadata": { + "type": "string", + "readable": true, + "writeable": false, + "label": "Z-Wave application framework API version", + "stateful": true, + "secret": false + }, + "value": "10.16.3" + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "applicationFrameworkBuildNumber", + "propertyName": "applicationFrameworkBuildNumber", + "ccVersion": 3, + "metadata": { + "type": "string", + "readable": true, + "writeable": false, + "label": "Z-Wave application framework API build number", + "stateful": true, + "secret": false + }, + "value": 297 + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "hostInterfaceVersion", + "propertyName": "hostInterfaceVersion", + "ccVersion": 3, + "metadata": { + "type": "string", + "readable": true, + "writeable": false, + "label": "Serial API version", + "stateful": true, + "secret": false + }, + "value": "unused" + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "hostInterfaceBuildNumber", + "propertyName": "hostInterfaceBuildNumber", + "ccVersion": 3, + "metadata": { + "type": "string", + "readable": true, + "writeable": false, + "label": "Serial API build number", + "stateful": true, + "secret": false + }, + "value": 0 + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "zWaveProtocolVersion", + "propertyName": "zWaveProtocolVersion", + "ccVersion": 3, + "metadata": { + "type": "string", + "readable": true, + "writeable": false, + "label": "Z-Wave protocol version", + "stateful": true, + "secret": false + }, + "value": "7.16.3" + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "zWaveProtocolBuildNumber", + "propertyName": "zWaveProtocolBuildNumber", + "ccVersion": 3, + "metadata": { + "type": "string", + "readable": true, + "writeable": false, + "label": "Z-Wave protocol build number", + "stateful": true, + "secret": false + }, + "value": 297 + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "applicationVersion", + "propertyName": "applicationVersion", + "ccVersion": 3, + "metadata": { + "type": "string", + "readable": true, + "writeable": false, + "label": "Application version", + "stateful": true, + "secret": false + }, + "value": "1.10.0" + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "applicationBuildNumber", + "propertyName": "applicationBuildNumber", + "ccVersion": 3, + "metadata": { + "type": "string", + "readable": true, + "writeable": false, + "label": "Application build number", + "stateful": true, + "secret": false + }, + "value": 43707 + }, + { + "endpoint": 0, + "commandClass": 135, + "commandClassName": "Indicator", + "property": 80, + "propertyKey": 3, + "propertyName": "Node Identify", + "propertyKeyName": "On/Off Period: Duration", + "ccVersion": 3, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "description": "Sets the duration of an on/off period in 1/10th seconds. Must be set together with \"On/Off Cycle Count\"", + "label": "Node Identify - On/Off Period: Duration", + "ccSpecific": { + "indicatorId": 80, + "propertyId": 3 + }, + "stateful": true, + "secret": false + }, + "value": 0 + }, + { + "endpoint": 0, + "commandClass": 135, + "commandClassName": "Indicator", + "property": 80, + "propertyKey": 4, + "propertyName": "Node Identify", + "propertyKeyName": "On/Off Cycle Count", + "ccVersion": 3, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "description": "Sets the number of on/off periods. 0xff means infinite. Must be set together with \"On/Off Period duration\"", + "label": "Node Identify - On/Off Cycle Count", + "ccSpecific": { + "indicatorId": 80, + "propertyId": 4 + }, + "stateful": true, + "secret": false + }, + "value": 0 + }, + { + "endpoint": 0, + "commandClass": 135, + "commandClassName": "Indicator", + "property": 80, + "propertyKey": 5, + "propertyName": "Node Identify", + "propertyKeyName": "On/Off Period: On time", + "ccVersion": 3, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "description": "This property is used to set the length of the On time during an On/Off period. It allows asymmetric On/Off periods. The value 0x00 MUST represent symmetric On/Off period (On time equal to Off time)", + "label": "Node Identify - On/Off Period: On time", + "ccSpecific": { + "indicatorId": 80, + "propertyId": 5 + }, + "stateful": true, + "secret": false + }, + "value": 0 + }, + { + "endpoint": 0, + "commandClass": 135, + "commandClassName": "Indicator", + "property": "value", + "propertyName": "value", + "ccVersion": 3, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Indicator value", + "ccSpecific": { + "indicatorId": 0 + }, + "min": 0, + "max": 255, + "stateful": true, + "secret": false + } + }, + { + "endpoint": 0, + "commandClass": 135, + "commandClassName": "Indicator", + "property": "identify", + "propertyName": "identify", + "ccVersion": 3, + "metadata": { + "type": "boolean", + "readable": false, + "writeable": true, + "label": "Identify", + "states": { + "true": "Identify" + }, + "stateful": true, + "secret": false + } + }, + { + "endpoint": 0, + "commandClass": 135, + "commandClassName": "Indicator", + "property": "timeout", + "propertyName": "timeout", + "ccVersion": 3, + "metadata": { + "type": "string", + "readable": true, + "writeable": true, + "label": "Timeout", + "stateful": true, + "secret": false + } + } + ], + "endpoints": [ + { + "nodeId": 261, + "index": 0, + "installerIcon": 6656, + "userIcon": 6656, + "deviceClass": { + "basic": { + "key": 3, + "label": "End Node" + }, + "generic": { + "key": 17, + "label": "Multilevel Switch" + }, + "specific": { + "key": 0, + "label": "Unused" + } + }, + "commandClasses": [ + { + "id": 94, + "name": "Z-Wave Plus Info", + "version": 2, + "isSecure": false + }, + { + "id": 85, + "name": "Transport Service", + "version": 2, + "isSecure": false + }, + { + "id": 159, + "name": "Security 2", + "version": 1, + "isSecure": true + }, + { + "id": 108, + "name": "Supervision", + "version": 1, + "isSecure": false + }, + { + "id": 38, + "name": "Multilevel Switch", + "version": 4, + "isSecure": true + }, + { + "id": 112, + "name": "Configuration", + "version": 4, + "isSecure": true + }, + { + "id": 133, + "name": "Association", + "version": 2, + "isSecure": true + }, + { + "id": 89, + "name": "Association Group Information", + "version": 3, + "isSecure": true + }, + { + "id": 142, + "name": "Multi Channel Association", + "version": 3, + "isSecure": true + }, + { + "id": 134, + "name": "Version", + "version": 3, + "isSecure": true + }, + { + "id": 114, + "name": "Manufacturer Specific", + "version": 2, + "isSecure": true + }, + { + "id": 90, + "name": "Device Reset Locally", + "version": 1, + "isSecure": true + }, + { + "id": 128, + "name": "Battery", + "version": 1, + "isSecure": true + }, + { + "id": 113, + "name": "Notification", + "version": 8, + "isSecure": true + }, + { + "id": 122, + "name": "Firmware Update Meta Data", + "version": 5, + "isSecure": true + }, + { + "id": 115, + "name": "Powerlevel", + "version": 1, + "isSecure": true + }, + { + "id": 135, + "name": "Indicator", + "version": 3, + "isSecure": true + } + ] + } + ] +} diff --git a/tests/components/zwave_js/test_discovery.py b/tests/components/zwave_js/test_discovery.py index 1179d8e843c..57841ef2a83 100644 --- a/tests/components/zwave_js/test_discovery.py +++ b/tests/components/zwave_js/test_discovery.py @@ -49,6 +49,18 @@ async def test_iblinds_v2(hass: HomeAssistant, client, iblinds_v2, integration) assert state +async def test_zvidar_state(hass: HomeAssistant, client, zvidar, integration) -> None: + """Test that an ZVIDAR Z-CM-V01 multilevel switch value is discovered as a cover.""" + node = zvidar + assert node.device_class.specific.label == "Unused" + + state = hass.states.get("light.window_blind_controller") + assert not state + + state = hass.states.get("cover.window_blind_controller") + assert state + + async def test_ge_12730(hass: HomeAssistant, client, ge_12730, integration) -> None: """Test GE 12730 Fan Controller v2.0 multilevel switch is discovered as a fan.""" node = ge_12730 From b63bc72450631c7d04ea6dd5430265bbb50c7e2a Mon Sep 17 00:00:00 2001 From: Christopher Fenner <9592452+CFenner@users.noreply.github.com> Date: Tue, 23 Jul 2024 21:56:46 +0200 Subject: [PATCH 04/16] Fix device class on sensor in ViCare (#122334) update device class on init --- homeassistant/components/vicare/sensor.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homeassistant/components/vicare/sensor.py b/homeassistant/components/vicare/sensor.py index 0e98729e40f..0271ffc9798 100644 --- a/homeassistant/components/vicare/sensor.py +++ b/homeassistant/components/vicare/sensor.py @@ -950,6 +950,8 @@ class ViCareSensor(ViCareEntity, SensorEntity): """Initialize the sensor.""" super().__init__(device_config, api, description.key) self.entity_description = description + # run update to have device_class set depending on unit_of_measurement + self.update() @property def available(self) -> bool: From f739644735525d693e1d6a66a0a39a6256b6ef5b Mon Sep 17 00:00:00 2001 From: Denis Shulyaka Date: Mon, 22 Jul 2024 07:54:31 +0300 Subject: [PATCH 05/16] Goofle Generative AI: Fix string format (#122348) * Ignore format for string tool args * Add tests --- .../google_generative_ai_conversation/conversation.py | 2 ++ .../snapshots/test_conversation.ambr | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/google_generative_ai_conversation/conversation.py b/homeassistant/components/google_generative_ai_conversation/conversation.py index 8052ee66f40..c80581a1f57 100644 --- a/homeassistant/components/google_generative_ai_conversation/conversation.py +++ b/homeassistant/components/google_generative_ai_conversation/conversation.py @@ -81,6 +81,8 @@ def _format_schema(schema: dict[str, Any]) -> dict[str, Any]: key = "type_" val = val.upper() elif key == "format": + if schema.get("type") == "string" and val != "enum": + continue key = "format_" elif key == "items": val = _format_schema(val) diff --git a/tests/components/google_generative_ai_conversation/snapshots/test_conversation.ambr b/tests/components/google_generative_ai_conversation/snapshots/test_conversation.ambr index 7f28c172970..66caf4c7218 100644 --- a/tests/components/google_generative_ai_conversation/snapshots/test_conversation.ambr +++ b/tests/components/google_generative_ai_conversation/snapshots/test_conversation.ambr @@ -449,7 +449,6 @@ description: "Test parameters" items { type_: STRING - format_: "lower" } } } From 9d6bd359c497de39b61dc8578fe180796698da5a Mon Sep 17 00:00:00 2001 From: Denis Shulyaka Date: Mon, 22 Jul 2024 12:11:09 +0300 Subject: [PATCH 06/16] Ensure script llm tool name does not start with a digit (#122349) * Ensure script tool name does not start with a digit * Fix test name --- homeassistant/helpers/llm.py | 5 ++++- tests/helpers/test_llm.py | 40 ++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/homeassistant/helpers/llm.py b/homeassistant/helpers/llm.py index 506cadbf168..f386fb3ddec 100644 --- a/homeassistant/helpers/llm.py +++ b/homeassistant/helpers/llm.py @@ -615,6 +615,9 @@ class ScriptTool(Tool): entity_registry = er.async_get(hass) self.name = split_entity_id(script_entity_id)[1] + if self.name[0].isdigit(): + self.name = "_" + self.name + self._entity_id = script_entity_id self.parameters = vol.Schema({}) entity_entry = entity_registry.async_get(script_entity_id) if entity_entry and entity_entry.unique_id: @@ -715,7 +718,7 @@ class ScriptTool(Tool): SCRIPT_DOMAIN, SERVICE_TURN_ON, { - ATTR_ENTITY_ID: SCRIPT_DOMAIN + "." + self.name, + ATTR_ENTITY_ID: self._entity_id, ATTR_VARIABLES: tool_input.tool_args, }, context=llm_context.context, diff --git a/tests/helpers/test_llm.py b/tests/helpers/test_llm.py index 81fa573852e..e1f55942d10 100644 --- a/tests/helpers/test_llm.py +++ b/tests/helpers/test_llm.py @@ -780,6 +780,46 @@ async def test_script_tool( } +async def test_script_tool_name(hass: HomeAssistant) -> None: + """Test that script tool name is not started with a digit.""" + assert await async_setup_component(hass, "homeassistant", {}) + context = Context() + llm_context = llm.LLMContext( + platform="test_platform", + context=context, + user_prompt="test_text", + language="*", + assistant="conversation", + device_id=None, + ) + + # Create a script with a unique ID + assert await async_setup_component( + hass, + "script", + { + "script": { + "123456": { + "description": "This is a test script", + "sequence": [], + "fields": { + "beer": {"description": "Number of beers", "required": True}, + }, + }, + } + }, + ) + async_expose_entity(hass, "conversation", "script.123456", True) + + api = await llm.async_get_api(hass, "assist", llm_context) + + tools = [tool for tool in api.tools if isinstance(tool, llm.ScriptTool)] + assert len(tools) == 1 + + tool = tools[0] + assert tool.name == "_123456" + + async def test_selector_serializer( hass: HomeAssistant, llm_context: llm.LLMContext ) -> None: From 7135a919e3338741f4a8a816bec9f1eee02de4d4 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Mon, 22 Jul 2024 11:09:03 +0200 Subject: [PATCH 07/16] Bump reolink-aio to 0.9.5 (#122366) --- homeassistant/components/reolink/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/reolink/manifest.json b/homeassistant/components/reolink/manifest.json index ee3ebe8a13a..c329289790b 100644 --- a/homeassistant/components/reolink/manifest.json +++ b/homeassistant/components/reolink/manifest.json @@ -18,5 +18,5 @@ "documentation": "https://www.home-assistant.io/integrations/reolink", "iot_class": "local_push", "loggers": ["reolink_aio"], - "requirements": ["reolink-aio==0.9.4"] + "requirements": ["reolink-aio==0.9.5"] } diff --git a/requirements_all.txt b/requirements_all.txt index 6c87b9bd19a..e8d846ef099 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2460,7 +2460,7 @@ renault-api==0.2.4 renson-endura-delta==1.7.1 # homeassistant.components.reolink -reolink-aio==0.9.4 +reolink-aio==0.9.5 # homeassistant.components.idteck_prox rfk101py==0.0.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index a0b1497a185..787b2af38fc 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1924,7 +1924,7 @@ renault-api==0.2.4 renson-endura-delta==1.7.1 # homeassistant.components.reolink -reolink-aio==0.9.4 +reolink-aio==0.9.5 # homeassistant.components.rflink rflink==0.0.66 From 56f51d3e3511752c3ff8f746c64d57a5bd325606 Mon Sep 17 00:00:00 2001 From: Denis Shulyaka Date: Tue, 23 Jul 2024 03:56:13 +0300 Subject: [PATCH 08/16] Fix gemini api format conversion (#122403) * Fix gemini api format conversion * add tests * fix tests * fix tests * fix coverage --- .../conversation.py | 18 +++++++++++++++++- .../snapshots/test_conversation.ambr | 18 ++++++++++++++++++ .../test_conversation.py | 4 +++- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/google_generative_ai_conversation/conversation.py b/homeassistant/components/google_generative_ai_conversation/conversation.py index c80581a1f57..69a68121c7b 100644 --- a/homeassistant/components/google_generative_ai_conversation/conversation.py +++ b/homeassistant/components/google_generative_ai_conversation/conversation.py @@ -73,6 +73,14 @@ SUPPORTED_SCHEMA_KEYS = { def _format_schema(schema: dict[str, Any]) -> dict[str, Any]: """Format the schema to protobuf.""" + if (subschemas := schema.get("anyOf")) or (subschemas := schema.get("allOf")): + for subschema in subschemas: # Gemini API does not support anyOf and allOf keys + if "type" in subschema: # Fallback to first subschema with 'type' field + return _format_schema(subschema) + return _format_schema( + subschemas[0] + ) # Or, if not found, to any of the subschemas + result = {} for key, val in schema.items(): if key not in SUPPORTED_SCHEMA_KEYS: @@ -81,7 +89,9 @@ def _format_schema(schema: dict[str, Any]) -> dict[str, Any]: key = "type_" val = val.upper() elif key == "format": - if schema.get("type") == "string" and val != "enum": + if (schema.get("type") == "string" and val != "enum") or ( + schema.get("type") not in ("number", "integer", "string") + ): continue key = "format_" elif key == "items": @@ -89,6 +99,12 @@ def _format_schema(schema: dict[str, Any]) -> dict[str, Any]: elif key == "properties": val = {k: _format_schema(v) for k, v in val.items()} result[key] = val + + if result.get("type_") == "OBJECT" and not result.get("properties"): + # An object with undefined properties is not supported by Gemini API. + # Fallback to JSON string. This will probably fail for most tools that want it, + # but we don't have a better fallback strategy so far. + result["properties"] = {"json": {"type_": "STRING"}} return result diff --git a/tests/components/google_generative_ai_conversation/snapshots/test_conversation.ambr b/tests/components/google_generative_ai_conversation/snapshots/test_conversation.ambr index 66caf4c7218..abd3658e869 100644 --- a/tests/components/google_generative_ai_conversation/snapshots/test_conversation.ambr +++ b/tests/components/google_generative_ai_conversation/snapshots/test_conversation.ambr @@ -442,6 +442,24 @@ description: "Test function" parameters { type_: OBJECT + properties { + key: "param3" + value { + type_: OBJECT + properties { + key: "json" + value { + type_: STRING + } + } + } + } + properties { + key: "param2" + value { + type_: NUMBER + } + } properties { key: "param1" value { diff --git a/tests/components/google_generative_ai_conversation/test_conversation.py b/tests/components/google_generative_ai_conversation/test_conversation.py index 30016335f3b..a7ab2c1b337 100644 --- a/tests/components/google_generative_ai_conversation/test_conversation.py +++ b/tests/components/google_generative_ai_conversation/test_conversation.py @@ -185,7 +185,9 @@ async def test_function_call( { vol.Optional("param1", description="Test parameters"): [ vol.All(str, vol.Lower) - ] + ], + vol.Optional("param2"): vol.Any(float, int), + vol.Optional("param3"): dict, } ) From 75f0384a15d8ed2a61f8186911d8a2915f1e4cff Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Wed, 24 Jul 2024 20:12:51 +0200 Subject: [PATCH 09/16] Fix typo in Matter lock platform (#122536) --- homeassistant/components/matter/lock.py | 4 ++-- .../matter/{test_door_lock.py => test_lock.py} | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) rename tests/components/matter/{test_door_lock.py => test_lock.py} (95%) diff --git a/homeassistant/components/matter/lock.py b/homeassistant/components/matter/lock.py index ae01faa3bc7..31ae5e496ce 100644 --- a/homeassistant/components/matter/lock.py +++ b/homeassistant/components/matter/lock.py @@ -168,10 +168,10 @@ class MatterLock(MatterEntity, LockEntity): LOGGER.debug("Lock state: %s for %s", lock_state, self.entity_id) - if lock_state is clusters.DoorLock.Enums.DlLockState.kUnlatched: + if lock_state == clusters.DoorLock.Enums.DlLockState.kUnlatched: self._attr_is_locked = False self._attr_is_open = True - if lock_state is clusters.DoorLock.Enums.DlLockState.kLocked: + elif lock_state == clusters.DoorLock.Enums.DlLockState.kLocked: self._attr_is_locked = True self._attr_is_open = False elif lock_state in ( diff --git a/tests/components/matter/test_door_lock.py b/tests/components/matter/test_lock.py similarity index 95% rename from tests/components/matter/test_door_lock.py rename to tests/components/matter/test_lock.py index 461cc1b7f3d..1180e6ee469 100644 --- a/tests/components/matter/test_door_lock.py +++ b/tests/components/matter/test_lock.py @@ -8,6 +8,7 @@ import pytest from homeassistant.components.lock import ( STATE_LOCKED, + STATE_OPEN, STATE_UNLOCKED, LockEntityFeature, ) @@ -82,12 +83,12 @@ async def test_lock( assert state assert state.state == STATE_UNLOCKED - set_node_attribute(door_lock, 1, 257, 0, 0) + set_node_attribute(door_lock, 1, 257, 0, 1) await trigger_subscription_callback(hass, matter_client) state = hass.states.get("lock.mock_door_lock_lock") assert state - assert state.state == STATE_UNLOCKED + assert state.state == STATE_LOCKED set_node_attribute(door_lock, 1, 257, 0, None) await trigger_subscription_callback(hass, matter_client) @@ -213,9 +214,16 @@ async def test_lock_with_unbolt( assert state assert state.state == STATE_OPENING - set_node_attribute(door_lock_with_unbolt, 1, 257, 3, 0) + set_node_attribute(door_lock_with_unbolt, 1, 257, 0, 0) await trigger_subscription_callback(hass, matter_client) state = hass.states.get("lock.mock_door_lock_lock") assert state - assert state.state == STATE_LOCKED + assert state.state == STATE_UNLOCKED + + set_node_attribute(door_lock_with_unbolt, 1, 257, 0, 3) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get("lock.mock_door_lock_lock") + assert state + assert state.state == STATE_OPEN From 586a0b12ab36043c1fa3d7b6ce6c5e85a4204025 Mon Sep 17 00:00:00 2001 From: Andrew Jackson Date: Wed, 24 Jul 2024 17:19:12 +0100 Subject: [PATCH 10/16] Fix target service attribute on Mastodon integration (#122546) * Fix target * Fix --- homeassistant/components/mastodon/notify.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/mastodon/notify.py b/homeassistant/components/mastodon/notify.py index f15b8c6f0ab..99999275aeb 100644 --- a/homeassistant/components/mastodon/notify.py +++ b/homeassistant/components/mastodon/notify.py @@ -3,7 +3,7 @@ from __future__ import annotations import mimetypes -from typing import Any +from typing import Any, cast from mastodon import Mastodon from mastodon.Mastodon import MastodonAPIError, MastodonUnauthorizedError @@ -71,11 +71,15 @@ class MastodonNotificationService(BaseNotificationService): def send_message(self, message: str = "", **kwargs: Any) -> None: """Toot a message, with media perhaps.""" + + target = None + if (target_list := kwargs.get(ATTR_TARGET)) is not None: + target = cast(list[str], target_list)[0] + data = kwargs.get(ATTR_DATA) media = None mediadata = None - target = None sensitive = False content_warning = None @@ -87,7 +91,6 @@ class MastodonNotificationService(BaseNotificationService): return mediadata = self._upload_media(media) - target = data.get(ATTR_TARGET) sensitive = data.get(ATTR_MEDIA_WARNING) content_warning = data.get(ATTR_CONTENT_WARNING) From 9940d0281bc527e7b85fc7ff9cd1792807c5287a Mon Sep 17 00:00:00 2001 From: Avi Miller Date: Thu, 25 Jul 2024 09:44:56 +1000 Subject: [PATCH 11/16] Bump aiolifx to 1.0.6 (#122569) --- homeassistant/components/lifx/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/lifx/manifest.json b/homeassistant/components/lifx/manifest.json index 3d0bd1d73d1..59b336373c2 100644 --- a/homeassistant/components/lifx/manifest.json +++ b/homeassistant/components/lifx/manifest.json @@ -48,7 +48,7 @@ "iot_class": "local_polling", "loggers": ["aiolifx", "aiolifx_effects", "bitstring"], "requirements": [ - "aiolifx==1.0.5", + "aiolifx==1.0.6", "aiolifx-effects==0.3.2", "aiolifx-themes==0.4.15" ] diff --git a/requirements_all.txt b/requirements_all.txt index e8d846ef099..1195f7b50eb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -282,7 +282,7 @@ aiolifx-effects==0.3.2 aiolifx-themes==0.4.15 # homeassistant.components.lifx -aiolifx==1.0.5 +aiolifx==1.0.6 # homeassistant.components.livisi aiolivisi==0.0.19 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 787b2af38fc..9bfd0311b25 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -255,7 +255,7 @@ aiolifx-effects==0.3.2 aiolifx-themes==0.4.15 # homeassistant.components.lifx -aiolifx==1.0.5 +aiolifx==1.0.6 # homeassistant.components.livisi aiolivisi==0.0.19 From aa44c54a1912ec948adffb19fe295e7e5d56ac22 Mon Sep 17 00:00:00 2001 From: Robert Resch Date: Thu, 25 Jul 2024 21:23:14 +0200 Subject: [PATCH 12/16] Bump deebot-client to 8.2.0 (#122612) --- homeassistant/components/ecovacs/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/ecovacs/manifest.json b/homeassistant/components/ecovacs/manifest.json index 6ca9b9e3edc..5a21facab71 100644 --- a/homeassistant/components/ecovacs/manifest.json +++ b/homeassistant/components/ecovacs/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/ecovacs", "iot_class": "cloud_push", "loggers": ["sleekxmppfs", "sucks", "deebot_client"], - "requirements": ["py-sucks==0.9.10", "deebot-client==8.1.1"] + "requirements": ["py-sucks==0.9.10", "deebot-client==8.2.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index 1195f7b50eb..f8c62aa75b0 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -709,7 +709,7 @@ debugpy==1.8.1 # decora==0.6 # homeassistant.components.ecovacs -deebot-client==8.1.1 +deebot-client==8.2.0 # homeassistant.components.ihc # homeassistant.components.namecheapdns diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9bfd0311b25..579f24fb4bb 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -590,7 +590,7 @@ dbus-fast==2.22.1 debugpy==1.8.1 # homeassistant.components.ecovacs -deebot-client==8.1.1 +deebot-client==8.2.0 # homeassistant.components.ihc # homeassistant.components.namecheapdns From 00c3b0d888e5d5427588a83e7b05036dfba83b02 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Mon, 29 Jul 2024 11:59:13 +0200 Subject: [PATCH 13/16] Bump aiohue to version 4.7.2 (#122651) --- homeassistant/components/hue/manifest.json | 2 +- homeassistant/components/hue/v2/hue_event.py | 4 ++-- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/hue/fixtures/v2_resources.json | 12 ++++++++++++ tests/components/hue/test_device_trigger_v2.py | 9 +++++++-- 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/hue/manifest.json b/homeassistant/components/hue/manifest.json index e8d214da3c8..71aabd4c204 100644 --- a/homeassistant/components/hue/manifest.json +++ b/homeassistant/components/hue/manifest.json @@ -11,6 +11,6 @@ "iot_class": "local_push", "loggers": ["aiohue"], "quality_scale": "platinum", - "requirements": ["aiohue==4.7.1"], + "requirements": ["aiohue==4.7.2"], "zeroconf": ["_hue._tcp.local."] } diff --git a/homeassistant/components/hue/v2/hue_event.py b/homeassistant/components/hue/v2/hue_event.py index b0e0de234f1..b286a11aade 100644 --- a/homeassistant/components/hue/v2/hue_event.py +++ b/homeassistant/components/hue/v2/hue_event.py @@ -55,7 +55,7 @@ async def async_setup_hue_events(bridge: HueBridge): CONF_ID: slugify(f"{hue_device.metadata.name} Button"), CONF_DEVICE_ID: device.id, # type: ignore[union-attr] CONF_UNIQUE_ID: hue_resource.id, - CONF_TYPE: hue_resource.button.last_event.value, + CONF_TYPE: hue_resource.button.button_report.event.value, CONF_SUBTYPE: hue_resource.metadata.control_id, } hass.bus.async_fire(ATTR_HUE_EVENT, data) @@ -79,7 +79,7 @@ async def async_setup_hue_events(bridge: HueBridge): data = { CONF_DEVICE_ID: device.id, # type: ignore[union-attr] CONF_UNIQUE_ID: hue_resource.id, - CONF_TYPE: hue_resource.relative_rotary.last_event.action.value, + CONF_TYPE: hue_resource.relative_rotary.rotary_report.action.value, CONF_SUBTYPE: hue_resource.relative_rotary.last_event.rotation.direction.value, CONF_DURATION: hue_resource.relative_rotary.last_event.rotation.duration, CONF_STEPS: hue_resource.relative_rotary.last_event.rotation.steps, diff --git a/requirements_all.txt b/requirements_all.txt index f8c62aa75b0..6c7f7bbc000 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -264,7 +264,7 @@ aioharmony==0.2.10 aiohomekit==3.1.5 # homeassistant.components.hue -aiohue==4.7.1 +aiohue==4.7.2 # homeassistant.components.imap aioimaplib==1.1.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 579f24fb4bb..fc830f0fe7a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -240,7 +240,7 @@ aioharmony==0.2.10 aiohomekit==3.1.5 # homeassistant.components.hue -aiohue==4.7.1 +aiohue==4.7.2 # homeassistant.components.imap aioimaplib==1.1.0 diff --git a/tests/components/hue/fixtures/v2_resources.json b/tests/components/hue/fixtures/v2_resources.json index 662e1107ca9..980086d0988 100644 --- a/tests/components/hue/fixtures/v2_resources.json +++ b/tests/components/hue/fixtures/v2_resources.json @@ -1487,6 +1487,10 @@ "on": { "on": true }, + "owner": { + "rid": "7cee478d-6455-483a-9e32-9f9fdcbcc4f6", + "rtype": "zone" + }, "type": "grouped_light" }, { @@ -1498,6 +1502,10 @@ "on": { "on": true }, + "owner": { + "rid": "7cee478d-6455-483a-9e32-9f9fdcbcc4f6", + "rtype": "zone" + }, "type": "grouped_light" }, { @@ -1509,6 +1517,10 @@ "on": { "on": false }, + "owner": { + "rid": "7cee478d-6455-483a-9e32-9f9fdcbcc4f6", + "rtype": "zone" + }, "type": "grouped_light" }, { diff --git a/tests/components/hue/test_device_trigger_v2.py b/tests/components/hue/test_device_trigger_v2.py index 0a89b3263c7..efdc33375a6 100644 --- a/tests/components/hue/test_device_trigger_v2.py +++ b/tests/components/hue/test_device_trigger_v2.py @@ -28,7 +28,12 @@ async def test_hue_event( # Emit button update event btn_event = { - "button": {"last_event": "initial_press"}, + "button": { + "button_report": { + "event": "initial_press", + "updated": "2021-10-01T12:00:00Z", + } + }, "id": "c658d3d8-a013-4b81-8ac6-78b248537e70", "metadata": {"control_id": 1}, "type": "button", @@ -41,7 +46,7 @@ async def test_hue_event( assert len(events) == 1 assert events[0].data["id"] == "wall_switch_with_2_controls_button" assert events[0].data["unique_id"] == btn_event["id"] - assert events[0].data["type"] == btn_event["button"]["last_event"] + assert events[0].data["type"] == btn_event["button"]["button_report"]["event"] assert events[0].data["subtype"] == btn_event["metadata"]["control_id"] From e5fd9819da291fef90726c1a88270586fe05bce2 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Fri, 26 Jul 2024 16:59:12 +0200 Subject: [PATCH 14/16] Return unknown when data is missing in Trafikverket Weather (#122652) Return unknown when data is missing --- .../trafikverket_weatherstation/sensor.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/trafikverket_weatherstation/sensor.py b/homeassistant/components/trafikverket_weatherstation/sensor.py index 4bd14448546..8856482d885 100644 --- a/homeassistant/components/trafikverket_weatherstation/sensor.py +++ b/homeassistant/components/trafikverket_weatherstation/sensor.py @@ -61,7 +61,7 @@ SENSOR_TYPES: tuple[TrafikverketSensorEntityDescription, ...] = ( TrafikverketSensorEntityDescription( key="air_temp", translation_key="air_temperature", - value_fn=lambda data: data.air_temp or 0, + value_fn=lambda data: data.air_temp, native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, @@ -69,7 +69,7 @@ SENSOR_TYPES: tuple[TrafikverketSensorEntityDescription, ...] = ( TrafikverketSensorEntityDescription( key="road_temp", translation_key="road_temperature", - value_fn=lambda data: data.road_temp or 0, + value_fn=lambda data: data.road_temp, native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, @@ -91,7 +91,7 @@ SENSOR_TYPES: tuple[TrafikverketSensorEntityDescription, ...] = ( ), TrafikverketSensorEntityDescription( key="wind_speed", - value_fn=lambda data: data.windforce or 0, + value_fn=lambda data: data.windforce, native_unit_of_measurement=UnitOfSpeed.METERS_PER_SECOND, device_class=SensorDeviceClass.WIND_SPEED, state_class=SensorStateClass.MEASUREMENT, @@ -99,7 +99,7 @@ SENSOR_TYPES: tuple[TrafikverketSensorEntityDescription, ...] = ( TrafikverketSensorEntityDescription( key="wind_speed_max", translation_key="wind_speed_max", - value_fn=lambda data: data.windforcemax or 0, + value_fn=lambda data: data.windforcemax, native_unit_of_measurement=UnitOfSpeed.METERS_PER_SECOND, device_class=SensorDeviceClass.WIND_SPEED, entity_registry_enabled_default=False, @@ -107,7 +107,7 @@ SENSOR_TYPES: tuple[TrafikverketSensorEntityDescription, ...] = ( ), TrafikverketSensorEntityDescription( key="humidity", - value_fn=lambda data: data.humidity or 0, + value_fn=lambda data: data.humidity, native_unit_of_measurement=PERCENTAGE, device_class=SensorDeviceClass.HUMIDITY, entity_registry_enabled_default=False, @@ -115,7 +115,7 @@ SENSOR_TYPES: tuple[TrafikverketSensorEntityDescription, ...] = ( ), TrafikverketSensorEntityDescription( key="precipitation_amount", - value_fn=lambda data: data.precipitation_amount or 0, + value_fn=lambda data: data.precipitation_amount, native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR, device_class=SensorDeviceClass.PRECIPITATION_INTENSITY, state_class=SensorStateClass.MEASUREMENT, @@ -130,7 +130,7 @@ SENSOR_TYPES: tuple[TrafikverketSensorEntityDescription, ...] = ( TrafikverketSensorEntityDescription( key="dew_point", translation_key="dew_point", - value_fn=lambda data: data.dew_point or 0, + value_fn=lambda data: data.dew_point, native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, From d51d584aed3d2adfbde15a0afe133b51a7a45d1f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 29 Jul 2024 04:59:31 -0500 Subject: [PATCH 15/16] Retry later on OSError during apple_tv entry setup (#122747) --- homeassistant/components/apple_tv/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/apple_tv/__init__.py b/homeassistant/components/apple_tv/__init__.py index 4e5c8791acd..08372aa79ae 100644 --- a/homeassistant/components/apple_tv/__init__.py +++ b/homeassistant/components/apple_tv/__init__.py @@ -60,6 +60,7 @@ AUTH_EXCEPTIONS = ( exceptions.NoCredentialsError, ) CONNECTION_TIMEOUT_EXCEPTIONS = ( + OSError, asyncio.CancelledError, TimeoutError, exceptions.ConnectionLostError, From 02c592d6afe64ea1f19f0cc1ee7a86a29537b095 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Mon, 29 Jul 2024 14:40:02 +0200 Subject: [PATCH 16/16] Bump version to 2024.7.4 --- homeassistant/const.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index f706b2d1243..71b7d79cb01 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -24,7 +24,7 @@ if TYPE_CHECKING: APPLICATION_NAME: Final = "HomeAssistant" MAJOR_VERSION: Final = 2024 MINOR_VERSION: Final = 7 -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) diff --git a/pyproject.toml b/pyproject.toml index f044551ce1e..55f96c3e0b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2024.7.3" +version = "2024.7.4" license = {text = "Apache-2.0"} description = "Open-source home automation platform running on Python 3." readme = "README.rst"