From d49029e9fcd01561d4ccf1df786da7ad0b4ccec8 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Mon, 21 Feb 2022 20:07:43 +0100 Subject: [PATCH] Add door and lock status to Renault integration (#66698) * Add coordinator for lock status * Add fixture for lock status * Add lock status binary sensor * Add to test constants * Adjust conftest * Fix inverted state * Add door status Co-authored-by: epenet --- .../components/renault/binary_sensor.py | 82 ++++++++---- .../components/renault/renault_vehicle.py | 5 + tests/components/renault/conftest.py | 14 +++ tests/components/renault/const.py | 117 +++++++++++++++++- .../renault/fixtures/lock_status.1.json | 15 +++ 5 files changed, 207 insertions(+), 26 deletions(-) create mode 100644 tests/components/renault/fixtures/lock_status.1.json diff --git a/homeassistant/components/renault/binary_sensor.py b/homeassistant/components/renault/binary_sensor.py index 3d96624e6280..a24c9be4e6d5 100644 --- a/homeassistant/components/renault/binary_sensor.py +++ b/homeassistant/components/renault/binary_sensor.py @@ -79,29 +79,61 @@ class RenaultBinarySensor( return None -BINARY_SENSOR_TYPES: tuple[RenaultBinarySensorEntityDescription, ...] = ( - RenaultBinarySensorEntityDescription( - key="plugged_in", - coordinator="battery", - device_class=BinarySensorDeviceClass.PLUG, - name="Plugged In", - on_key="plugStatus", - on_value=PlugState.PLUGGED.value, - ), - RenaultBinarySensorEntityDescription( - key="charging", - coordinator="battery", - device_class=BinarySensorDeviceClass.BATTERY_CHARGING, - name="Charging", - on_key="chargingStatus", - on_value=ChargeState.CHARGE_IN_PROGRESS.value, - ), - RenaultBinarySensorEntityDescription( - key="hvac_status", - coordinator="hvac_status", - icon_fn=lambda e: "mdi:fan" if e.is_on else "mdi:fan-off", - name="HVAC", - on_key="hvacStatus", - on_value="on", - ), +BINARY_SENSOR_TYPES: tuple[RenaultBinarySensorEntityDescription, ...] = tuple( + [ + RenaultBinarySensorEntityDescription( + key="plugged_in", + coordinator="battery", + device_class=BinarySensorDeviceClass.PLUG, + name="Plugged In", + on_key="plugStatus", + on_value=PlugState.PLUGGED.value, + ), + RenaultBinarySensorEntityDescription( + key="charging", + coordinator="battery", + device_class=BinarySensorDeviceClass.BATTERY_CHARGING, + name="Charging", + on_key="chargingStatus", + on_value=ChargeState.CHARGE_IN_PROGRESS.value, + ), + RenaultBinarySensorEntityDescription( + key="hvac_status", + coordinator="hvac_status", + icon_fn=lambda e: "mdi:fan" if e.is_on else "mdi:fan-off", + name="HVAC", + on_key="hvacStatus", + on_value="on", + ), + RenaultBinarySensorEntityDescription( + key="lock_status", + coordinator="lock_status", + # lock: on means open (unlocked), off means closed (locked) + device_class=BinarySensorDeviceClass.LOCK, + name="Lock", + on_key="lockStatus", + on_value="unlocked", + ), + RenaultBinarySensorEntityDescription( + key="hatch_status", + coordinator="lock_status", + # On means open, Off means closed + device_class=BinarySensorDeviceClass.DOOR, + name="Hatch", + on_key="hatchStatus", + on_value="open", + ), + ] + + [ + RenaultBinarySensorEntityDescription( + key=f"{door.replace(' ','_').lower()}_door_status", + coordinator="lock_status", + # On means open, Off means closed + device_class=BinarySensorDeviceClass.DOOR, + name=f"{door} Door", + on_key=f"doorStatus{door.replace(' ','')}", + on_value="open", + ) + for door in ("Rear Left", "Rear Right", "Driver", "Passenger") + ], ) diff --git a/homeassistant/components/renault/renault_vehicle.py b/homeassistant/components/renault/renault_vehicle.py index 462c5bbc2397..c4e42a7be5be 100644 --- a/homeassistant/components/renault/renault_vehicle.py +++ b/homeassistant/components/renault/renault_vehicle.py @@ -148,4 +148,9 @@ COORDINATORS: tuple[RenaultCoordinatorDescription, ...] = ( requires_electricity=True, update_method=lambda x: x.get_charge_mode, ), + RenaultCoordinatorDescription( + endpoint="lock-status", + key="lock_status", + update_method=lambda x: x.get_lock_status, + ), ) diff --git a/tests/components/renault/conftest.py b/tests/components/renault/conftest.py index a1f3b42167c1..da86b41e3b05 100644 --- a/tests/components/renault/conftest.py +++ b/tests/components/renault/conftest.py @@ -102,6 +102,11 @@ def _get_fixtures(vehicle_type: str) -> MappingProxyType: if "location" in mock_vehicle["endpoints"] else load_fixture("renault/no_data.json") ).get_attributes(schemas.KamereonVehicleLocationDataSchema), + "lock_status": schemas.KamereonVehicleDataResponseSchema.loads( + load_fixture(f"renault/{mock_vehicle['endpoints']['lock_status']}") + if "lock_status" in mock_vehicle["endpoints"] + else load_fixture("renault/no_data.json") + ).get_attributes(schemas.KamereonVehicleLockStatusDataSchema), } @@ -125,6 +130,9 @@ def patch_fixtures_with_data(vehicle_type: str): ), patch( "renault_api.renault_vehicle.RenaultVehicle.get_location", return_value=mock_fixtures["location"], + ), patch( + "renault_api.renault_vehicle.RenaultVehicle.get_lock_status", + return_value=mock_fixtures["lock_status"], ): yield @@ -149,6 +157,9 @@ def patch_fixtures_with_no_data(): ), patch( "renault_api.renault_vehicle.RenaultVehicle.get_location", return_value=mock_fixtures["location"], + ), patch( + "renault_api.renault_vehicle.RenaultVehicle.get_lock_status", + return_value=mock_fixtures["lock_status"], ): yield @@ -171,6 +182,9 @@ def _patch_fixtures_with_side_effect(side_effect: Any): ), patch( "renault_api.renault_vehicle.RenaultVehicle.get_location", side_effect=side_effect, + ), patch( + "renault_api.renault_vehicle.RenaultVehicle.get_lock_status", + side_effect=side_effect, ): yield diff --git a/tests/components/renault/const.py b/tests/components/renault/const.py index 90a1665b75b9..d0fadc540304 100644 --- a/tests/components/renault/const.py +++ b/tests/components/renault/const.py @@ -252,6 +252,7 @@ MOCK_VEHICLES = { True, # location True, # battery-status True, # charge-mode + True, # lock-status ], "endpoints": { "battery_status": "battery_status_not_charging.json", @@ -259,6 +260,7 @@ MOCK_VEHICLES = { "cockpit": "cockpit_ev.json", "hvac_status": "hvac_status.2.json", "location": "location.json", + "lock_status": "lock_status.1.json", }, Platform.BINARY_SENSOR: [ { @@ -279,6 +281,42 @@ MOCK_VEHICLES = { ATTR_STATE: STATE_OFF, ATTR_UNIQUE_ID: "vf1aaaaa555777999_hvac_status", }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.LOCK, + ATTR_ENTITY_ID: "binary_sensor.reg_number_lock", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777999_lock_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_rear_left_door", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777999_rear_left_door_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_rear_right_door", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777999_rear_right_door_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_driver_door", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777999_driver_door_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_passenger_door", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777999_passenger_door_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_hatch", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777999_hatch_status", + }, ], Platform.BUTTON: [ { @@ -434,12 +472,14 @@ MOCK_VEHICLES = { True, # location True, # battery-status True, # charge-mode + True, # lock-status ], "endpoints": { "battery_status": "battery_status_charging.json", "charge_mode": "charge_mode_always.json", "cockpit": "cockpit_fuel.json", "location": "location.json", + "lock_status": "lock_status.1.json", }, Platform.BINARY_SENSOR: [ { @@ -454,6 +494,42 @@ MOCK_VEHICLES = { ATTR_STATE: STATE_ON, ATTR_UNIQUE_ID: "vf1aaaaa555777123_charging", }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.LOCK, + ATTR_ENTITY_ID: "binary_sensor.reg_number_lock", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777123_lock_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_rear_left_door", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777123_rear_left_door_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_rear_right_door", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777123_rear_right_door_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_driver_door", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777123_driver_door_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_passenger_door", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777123_passenger_door_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_hatch", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777123_hatch_status", + }, ], Platform.BUTTON: [ { @@ -604,12 +680,51 @@ MOCK_VEHICLES = { True, # location # Ignore, # battery-status # Ignore, # charge-mode + True, # lock-status ], "endpoints": { "cockpit": "cockpit_fuel.json", "location": "location.json", + "lock_status": "lock_status.1.json", }, - Platform.BINARY_SENSOR: [], + Platform.BINARY_SENSOR: [ + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.LOCK, + ATTR_ENTITY_ID: "binary_sensor.reg_number_lock", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777123_lock_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_rear_left_door", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777123_rear_left_door_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_rear_right_door", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777123_rear_right_door_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_driver_door", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777123_driver_door_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_passenger_door", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777123_passenger_door_status", + }, + { + ATTR_DEVICE_CLASS: BinarySensorDeviceClass.DOOR, + ATTR_ENTITY_ID: "binary_sensor.reg_number_hatch", + ATTR_STATE: STATE_OFF, + ATTR_UNIQUE_ID: "vf1aaaaa555777123_hatch_status", + }, + ], Platform.BUTTON: [ { ATTR_ENTITY_ID: "button.reg_number_start_air_conditioner", diff --git a/tests/components/renault/fixtures/lock_status.1.json b/tests/components/renault/fixtures/lock_status.1.json new file mode 100644 index 000000000000..9cda30d5a626 --- /dev/null +++ b/tests/components/renault/fixtures/lock_status.1.json @@ -0,0 +1,15 @@ +{ + "data": { + "type": "Car", + "id": "VF1AAAAA555777999", + "attributes": { + "lockStatus": "locked", + "doorStatusRearLeft": "closed", + "doorStatusRearRight": "closed", + "doorStatusDriver": "closed", + "doorStatusPassenger": "closed", + "hatchStatus": "closed", + "lastUpdateTime": "2022-02-02T13:51:13Z" + } + } + } \ No newline at end of file