diff --git a/homeassistant/components/bmw_connected_drive/manifest.json b/homeassistant/components/bmw_connected_drive/manifest.json index c6b180ca728c31463000b10fbb6506d0306d240b..d90b35187aa93aab67f61e3429c20f5af883b983 100644 --- a/homeassistant/components/bmw_connected_drive/manifest.json +++ b/homeassistant/components/bmw_connected_drive/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/bmw_connected_drive", "iot_class": "cloud_polling", "loggers": ["bimmer_connected"], - "requirements": ["bimmer-connected[china]==0.15.2"] + "requirements": ["bimmer-connected[china]==0.15.3"] } diff --git a/homeassistant/components/bmw_connected_drive/sensor.py b/homeassistant/components/bmw_connected_drive/sensor.py index d3366543c551a810ff374e3670602320aa682c9f..0e8ad9726f115af50f7823b0c2680cf28b8a9ee0 100644 --- a/homeassistant/components/bmw_connected_drive/sensor.py +++ b/homeassistant/components/bmw_connected_drive/sensor.py @@ -4,6 +4,7 @@ from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass +import datetime import logging from typing import cast @@ -21,6 +22,7 @@ from homeassistant.const import LENGTH, PERCENTAGE, VOLUME, UnitOfElectricCurren from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import StateType +from homeassistant.util import dt as dt_util from . import BMWBaseEntity from .const import CLIMATE_ACTIVITY_STATE, DOMAIN, UNIT_MAP @@ -219,6 +221,11 @@ class BMWSensor(BMWBaseEntity, SensorEntity): getattr(self.vehicle, self.entity_description.key_class), self.entity_description.key, ) + + # For datetime without tzinfo, we assume it to be the same timezone as the HA instance + if isinstance(state, datetime.datetime) and state.tzinfo is None: + state = state.replace(tzinfo=dt_util.get_default_time_zone()) + self._attr_native_value = cast( StateType, self.entity_description.value(state, self.hass) ) diff --git a/requirements_all.txt b/requirements_all.txt index a4862b9755cbe14f4dae4600af52d55b600a3d7b..32987086346606c70099cfbf51c04797ea67a216 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -553,7 +553,7 @@ beautifulsoup4==4.12.3 bellows==0.38.4 # homeassistant.components.bmw_connected_drive -bimmer-connected[china]==0.15.2 +bimmer-connected[china]==0.15.3 # homeassistant.components.bizkaibus bizkaibus==0.1.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index f345779920e058a016b709c1408e035ee4a0ba1f..7544577275195cef81ab843e0a5dc469cce7651f 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -478,7 +478,7 @@ beautifulsoup4==4.12.3 bellows==0.38.4 # homeassistant.components.bmw_connected_drive -bimmer-connected[china]==0.15.2 +bimmer-connected[china]==0.15.3 # homeassistant.components.eq3btsmart # homeassistant.components.esphome diff --git a/tests/components/bmw_connected_drive/__init__.py b/tests/components/bmw_connected_drive/__init__.py index e737fce6897e6a4969e79b0eeb3ad02a92633bb4..c11d5ef0021f91af6cab08f259c276fdacbf6ba8 100644 --- a/tests/components/bmw_connected_drive/__init__.py +++ b/tests/components/bmw_connected_drive/__init__.py @@ -43,6 +43,7 @@ FIXTURE_CONFIG_ENTRY = { async def setup_mocked_integration(hass: HomeAssistant) -> MockConfigEntry: """Mock a fully setup config entry and all components based on fixtures.""" + # Mock config entry and add to HA mock_config_entry = MockConfigEntry(**FIXTURE_CONFIG_ENTRY) mock_config_entry.add_to_hass(hass) diff --git a/tests/components/bmw_connected_drive/snapshots/test_diagnostics.ambr b/tests/components/bmw_connected_drive/snapshots/test_diagnostics.ambr index 351c0f062fdeb07a7a365a9df56b631a1b89fdc3..477cd24376dd5412288c2a493fab0d1fc34a6ea3 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_diagnostics.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_diagnostics.ambr @@ -1706,7 +1706,23 @@ 'windows', ]), 'brand': 'bmw', - 'charging_profile': None, + 'charging_profile': dict({ + 'ac_available_limits': None, + 'ac_current_limit': None, + 'charging_mode': 'IMMEDIATE_CHARGING', + 'charging_preferences': 'NO_PRESELECTION', + 'charging_preferences_service_pack': None, + 'departure_times': list([ + ]), + 'is_pre_entry_climatization_enabled': False, + 'preferred_charging_window': dict({ + '_window_dict': dict({ + }), + 'end_time': '00:00:00', + 'start_time': '00:00:00', + }), + 'timer_type': 'UNKNOWN', + }), 'check_control_messages': dict({ 'has_check_control_messages': False, 'messages': list([ @@ -2861,7 +2877,7 @@ ]), 'fuel_and_battery': dict({ 'charging_end_time': None, - 'charging_start_time': '2022-07-10T18:01:00+00:00', + 'charging_start_time': '2022-07-10T18:01:00', 'charging_status': 'WAITING_FOR_CHARGING', 'charging_target': 100, 'is_charger_connected': True, @@ -5263,7 +5279,7 @@ ]), 'fuel_and_battery': dict({ 'charging_end_time': None, - 'charging_start_time': '2022-07-10T18:01:00+00:00', + 'charging_start_time': '2022-07-10T18:01:00', 'charging_status': 'WAITING_FOR_CHARGING', 'charging_target': 100, 'is_charger_connected': True, diff --git a/tests/components/bmw_connected_drive/snapshots/test_sensor.ambr b/tests/components/bmw_connected_drive/snapshots/test_sensor.ambr index dcf68622fdcf7f6c2ada1e5d230cce57bbec6d4a..bf35398cd9051f7d6ffee9e9352b101a19c2eff4 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_sensor.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_sensor.ambr @@ -1,6 +1,32 @@ # serializer version: 1 # name: test_entity_state_attrs list([ + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'iX xDrive50 AC current limit', + 'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>, + }), + 'context': <ANY>, + 'entity_id': 'sensor.ix_xdrive50_ac_current_limit', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': '16', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'device_class': 'timestamp', + 'friendly_name': 'iX xDrive50 Charging start time', + }), + 'context': <ANY>, + 'entity_id': 'sensor.ix_xdrive50_charging_start_time', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': 'unknown', + }), StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by MyBMW', @@ -115,6 +141,32 @@ 'last_updated': <ANY>, 'state': 'inactive', }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'i4 eDrive40 AC current limit', + 'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>, + }), + 'context': <ANY>, + 'entity_id': 'sensor.i4_edrive40_ac_current_limit', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': '16', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'device_class': 'timestamp', + 'friendly_name': 'i4 eDrive40 Charging start time', + }), + 'context': <ANY>, + 'entity_id': 'sensor.i4_edrive40_charging_start_time', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': 'unknown', + }), StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by MyBMW', @@ -318,6 +370,32 @@ 'last_updated': <ANY>, 'state': 'inactive', }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'friendly_name': 'i3 (+ REX) AC current limit', + 'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>, + }), + 'context': <ANY>, + 'entity_id': 'sensor.i3_rex_ac_current_limit', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': 'unknown', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by MyBMW', + 'device_class': 'timestamp', + 'friendly_name': 'i3 (+ REX) Charging start time', + }), + 'context': <ANY>, + 'entity_id': 'sensor.i3_rex_charging_start_time', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': '2023-06-23T01:01:00+00:00', + }), StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by MyBMW', diff --git a/tests/components/bmw_connected_drive/test_button.py b/tests/components/bmw_connected_drive/test_button.py index f55e199682f9267dce8f16546fef7ee6d081ab7f..25d01fa74c96d2504abe87b5c006b3ae0e768d64 100644 --- a/tests/components/bmw_connected_drive/test_button.py +++ b/tests/components/bmw_connected_drive/test_button.py @@ -17,6 +17,7 @@ from . import check_remote_service_call, setup_mocked_integration async def test_entity_state_attrs( hass: HomeAssistant, bmw_fixture: respx.Router, + entity_registry_enabled_by_default: None, snapshot: SnapshotAssertion, ) -> None: """Test button options and values.""" diff --git a/tests/components/bmw_connected_drive/test_diagnostics.py b/tests/components/bmw_connected_drive/test_diagnostics.py index 2f58bc0e4a093d70a7955ecdd2536399192152cf..fedfb1c23513b835d570bbe4c2bfb848a796f396 100644 --- a/tests/components/bmw_connected_drive/test_diagnostics.py +++ b/tests/components/bmw_connected_drive/test_diagnostics.py @@ -23,6 +23,7 @@ async def test_config_entry_diagnostics( hass: HomeAssistant, hass_client: ClientSessionGenerator, bmw_fixture, + entity_registry_enabled_by_default: None, snapshot: SnapshotAssertion, ) -> None: """Test config entry diagnostics.""" @@ -42,6 +43,7 @@ async def test_device_diagnostics( hass_client: ClientSessionGenerator, device_registry: dr.DeviceRegistry, bmw_fixture, + entity_registry_enabled_by_default: None, snapshot: SnapshotAssertion, ) -> None: """Test device diagnostics.""" @@ -66,6 +68,7 @@ async def test_device_diagnostics_vehicle_not_found( hass_client: ClientSessionGenerator, device_registry: dr.DeviceRegistry, bmw_fixture, + entity_registry_enabled_by_default: None, snapshot: SnapshotAssertion, ) -> None: """Test device diagnostics when the vehicle cannot be found.""" diff --git a/tests/components/bmw_connected_drive/test_number.py b/tests/components/bmw_connected_drive/test_number.py index 30214555b926f81a96811991f8f458e55e56743b..1047e595c951919cf71cf24637110ca4335880a1 100644 --- a/tests/components/bmw_connected_drive/test_number.py +++ b/tests/components/bmw_connected_drive/test_number.py @@ -17,6 +17,7 @@ from . import check_remote_service_call, setup_mocked_integration async def test_entity_state_attrs( hass: HomeAssistant, bmw_fixture: respx.Router, + entity_registry_enabled_by_default: None, snapshot: SnapshotAssertion, ) -> None: """Test number options and values..""" diff --git a/tests/components/bmw_connected_drive/test_select.py b/tests/components/bmw_connected_drive/test_select.py index cb20805c809412c6ec102d20242a1d9c320ce278..0c78d89cd8a37fa1bdd6b664ef2cba9d0e9593f7 100644 --- a/tests/components/bmw_connected_drive/test_select.py +++ b/tests/components/bmw_connected_drive/test_select.py @@ -17,6 +17,7 @@ from . import check_remote_service_call, setup_mocked_integration async def test_entity_state_attrs( hass: HomeAssistant, bmw_fixture: respx.Router, + entity_registry_enabled_by_default: None, snapshot: SnapshotAssertion, ) -> None: """Test select options and values..""" diff --git a/tests/components/bmw_connected_drive/test_sensor.py b/tests/components/bmw_connected_drive/test_sensor.py index a066b96725014a4fe021329c05ab055d6d4dfb9a..18c589bb72af623f87740fd9a72f914dc78050b5 100644 --- a/tests/components/bmw_connected_drive/test_sensor.py +++ b/tests/components/bmw_connected_drive/test_sensor.py @@ -19,6 +19,7 @@ from . import setup_mocked_integration async def test_entity_state_attrs( hass: HomeAssistant, bmw_fixture: respx.Router, + entity_registry_enabled_by_default: None, snapshot: SnapshotAssertion, ) -> None: """Test sensor options and values..""" diff --git a/tests/components/bmw_connected_drive/test_switch.py b/tests/components/bmw_connected_drive/test_switch.py index b759c33ca3b15c2641fe60c131fdb8e11237a220..a667966d0999550874bc1b49025b0907c21e1ce7 100644 --- a/tests/components/bmw_connected_drive/test_switch.py +++ b/tests/components/bmw_connected_drive/test_switch.py @@ -17,6 +17,7 @@ from . import check_remote_service_call, setup_mocked_integration async def test_entity_state_attrs( hass: HomeAssistant, bmw_fixture: respx.Router, + entity_registry_enabled_by_default: None, snapshot: SnapshotAssertion, ) -> None: """Test switch options and values.."""