-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added all the missing sensors and a camera that pulls image from api
- Loading branch information
Showing
6 changed files
with
344 additions
and
94 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
162 changes: 162 additions & 0 deletions
162
custom_components/volkswagen_we_connect_id/binary_sensor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
"""Platform for sensor integration.""" | ||
from __future__ import annotations | ||
|
||
from dataclasses import dataclass | ||
from datetime import timedelta | ||
import logging | ||
from typing import cast | ||
|
||
from weconnect import weconnect | ||
from weconnect.elements.plug_status import PlugStatus | ||
from weconnect.elements.window_heating_status import WindowHeatingStatus | ||
|
||
from homeassistant.components.binary_sensor import ( | ||
BinarySensorDeviceClass, | ||
BinarySensorEntity, | ||
BinarySensorEntityDescription, | ||
) | ||
from homeassistant.helpers.entity import EntityCategory | ||
from homeassistant.helpers.typing import StateType | ||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator | ||
|
||
from . import VolkswagenIDBaseEntity | ||
from .const import DOMAIN | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
@dataclass | ||
class VolkswagenIdBinaryEntityDescription(BinarySensorEntityDescription): | ||
"""Describes Volkswagen ID binary sensor entity.""" | ||
|
||
local_address: str | None = None | ||
on_value: None = None | ||
|
||
|
||
SENSORS: tuple[VolkswagenIdBinaryEntityDescription, ...] = ( | ||
VolkswagenIdBinaryEntityDescription( | ||
key="climatisationWithoutExternalPower", | ||
name="Climatisation Without External Power", | ||
local_address="/climatisation/climatisationSettings/climatisationWithoutExternalPower", | ||
on_value=True, | ||
), | ||
VolkswagenIdBinaryEntityDescription( | ||
key="climatizationAtUnlock", | ||
name="Climatisation At Unlock", | ||
local_address="/climatisation/climatisationSettings/climatizationAtUnlock", | ||
on_value=True, | ||
), | ||
VolkswagenIdBinaryEntityDescription( | ||
key="zoneFrontLeftEnabled", | ||
name="Zone Front Left Enabled", | ||
local_address="/climatisation/climatisationSettings/zoneFrontLeftEnabled", | ||
on_value=True, | ||
), | ||
VolkswagenIdBinaryEntityDescription( | ||
key="zoneFrontRightEnabled", | ||
name="Zone Front Right Enabled", | ||
local_address="/climatisation/climatisationSettings/zoneFrontRightEnabled", | ||
on_value=True, | ||
), | ||
VolkswagenIdBinaryEntityDescription( | ||
key="windowHeatingEnabled", | ||
name="Window Heating Enabled", | ||
local_address="/climatisation/climatisationSettings/windowHeatingEnabled", | ||
on_value=True, | ||
), | ||
VolkswagenIdBinaryEntityDescription( | ||
key="frontWindowHeatingState", | ||
name="Front Window Heating State", | ||
local_address="/climatisation/windowHeatingStatus/windows/front/windowHeatingState", | ||
on_value=WindowHeatingStatus.Window.WindowHeatingState.ON, | ||
), | ||
VolkswagenIdBinaryEntityDescription( | ||
key="rearWindowHeatingState", | ||
name="Rear Window Heating State", | ||
local_address="/climatisation/windowHeatingStatus/windows/rear/windowHeatingState", | ||
on_value=WindowHeatingStatus.Window.WindowHeatingState.ON, | ||
), | ||
VolkswagenIdBinaryEntityDescription( | ||
key="autoUnlockPlugWhenCharged", | ||
name="Auto Unlock Plug When Charged", | ||
local_address="/charging/chargingSettings/autoUnlockPlugWhenCharged", | ||
on_value=True, | ||
), | ||
VolkswagenIdBinaryEntityDescription( | ||
key="plugConnectionState", | ||
name="Plug Connection State", | ||
local_address="/charging/plugStatus/plugConnectionState", | ||
device_class=BinarySensorDeviceClass.PLUG, | ||
on_value=PlugStatus.PlugConnectionState.CONNECTED, | ||
), | ||
VolkswagenIdBinaryEntityDescription( | ||
key="plugLockState", | ||
name="Plug Lock State", | ||
local_address="/charging/plugStatus/plugLockState", | ||
device_class=BinarySensorDeviceClass.LOCK, | ||
on_value=PlugStatus.PlugLockState.LOCKED, | ||
), | ||
) | ||
|
||
|
||
async def async_setup_entry(hass, config_entry, async_add_entities): | ||
"""Add sensors for passed config_entry in HA.""" | ||
we_connect: weconnect.WeConnect | ||
we_connect = hass.data[DOMAIN][config_entry.entry_id] | ||
vehicles = hass.data[DOMAIN][config_entry.entry_id + "_vehicles"] | ||
|
||
async def async_update_data(): | ||
await hass.async_add_executor_job(we_connect.update) | ||
|
||
coordinator = DataUpdateCoordinator( | ||
hass, | ||
_LOGGER, | ||
# Name of the data. For logging purposes. | ||
name="volkswagen_we_connect_id_sensors", | ||
update_method=async_update_data, | ||
# Polling interval. Will only be polled if there are subscribers. | ||
update_interval=timedelta(seconds=30), | ||
) | ||
|
||
entities: list[VolkswagenIDSensor] = [] | ||
for vin, vehicle in vehicles.items(): | ||
for sensor in SENSORS: | ||
entities.append( | ||
VolkswagenIDSensor( | ||
vehicle, | ||
sensor, | ||
we_connect, | ||
coordinator, | ||
) | ||
) | ||
if entities: | ||
async_add_entities(entities) | ||
|
||
|
||
class VolkswagenIDSensor(VolkswagenIDBaseEntity, BinarySensorEntity): | ||
"""Representation of a VolkswagenID vehicle sensor.""" | ||
|
||
entity_description: VolkswagenIdBinaryEntityDescription | ||
|
||
def __init__( | ||
self, | ||
vehicle: weconnect.Vehicle, | ||
sensor: VolkswagenIdBinaryEntityDescription, | ||
we_connect: weconnect.WeConnect, | ||
coordinator: DataUpdateCoordinator, | ||
) -> None: | ||
"""Initialize VolkswagenID vehicle sensor.""" | ||
super().__init__(vehicle, sensor, we_connect, coordinator) | ||
|
||
self.entity_description = sensor | ||
self._coordinator = coordinator | ||
self._attr_name = f"Volkswagen ID {vehicle.nickname} {sensor.name}" | ||
self._attr_unique_id = f"{vehicle.vin}-{sensor.key}" | ||
self._data = f"/vehicles/{vehicle.vin}{sensor.local_address}" | ||
|
||
@property | ||
def is_on(self) -> bool: | ||
"""Return true if sensor is on.""" | ||
|
||
state = self._we_connect.getByAddressString(self._data) | ||
return state == self.entity_description.on_value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
"""Platform for sensor integration.""" | ||
from __future__ import annotations | ||
|
||
from datetime import timedelta | ||
import io | ||
import logging | ||
|
||
from PIL import Image | ||
from weconnect import weconnect | ||
|
||
from homeassistant.components.camera import Camera | ||
from homeassistant.helpers.entity import DeviceInfo | ||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator | ||
|
||
from .const import DOMAIN | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
async def async_setup_entry(hass, config_entry, async_add_entities): | ||
"""Add sensors for passed config_entry in HA.""" | ||
we_connect: weconnect.WeConnect | ||
we_connect = hass.data[DOMAIN][config_entry.entry_id] | ||
vehicles = hass.data[DOMAIN][config_entry.entry_id + "_vehicles"] | ||
|
||
async def async_update_data(): | ||
await hass.async_add_executor_job(we_connect.update) | ||
|
||
coordinator = DataUpdateCoordinator( | ||
hass, | ||
_LOGGER, | ||
# Name of the data. For logging purposes. | ||
name="volkswagen_we_connect_id_sensors", | ||
update_method=async_update_data, | ||
# Polling interval. Will only be polled if there are subscribers. | ||
update_interval=timedelta(minutes=60), | ||
) | ||
|
||
cameras: list[VolkswagenIDCamera] = [] | ||
for vin, vehicle in vehicles.items(): | ||
cameras.append( | ||
VolkswagenIDCamera( | ||
vehicle, | ||
we_connect, | ||
coordinator, | ||
) | ||
) | ||
|
||
if cameras: | ||
async_add_entities(cameras) | ||
|
||
|
||
class VolkswagenIDCamera(Camera): | ||
# Implement one of these methods. | ||
|
||
def __init__( | ||
self, | ||
vehicle: weconnect.Vehicle, | ||
we_connect: weconnect.WeConnect, | ||
coordinator: DataUpdateCoordinator, | ||
) -> None: | ||
"""Initialize VolkswagenID camera.""" | ||
|
||
Camera.__init__(self) | ||
|
||
self._attr_name = f"Volkswagen ID {vehicle.nickname} Image" | ||
self._attr_unique_id = f"{vehicle.vin}-Image" | ||
|
||
self._coordinator = coordinator | ||
self._we_connect = we_connect | ||
self._data = f"/vehicles/{vehicle.vin}/pictures/car" | ||
|
||
self._attr_device_info = DeviceInfo( | ||
identifiers={(DOMAIN, f"vw{vehicle.vin}")}, | ||
manufacturer="Volkswagen", | ||
model=f"{vehicle.model}", # format because of the ID.3/ID.4 names. | ||
name=f"Volkswagen {vehicle.nickname}", | ||
) | ||
|
||
def camera_image( | ||
self, width: int | None = None, height: int | None = None | ||
) -> bytes | None: | ||
"""Return image response.""" | ||
try: | ||
image = self._we_connect.getByAddressString(self._data).value | ||
imgByteArr = io.BytesIO() | ||
image.save(imgByteArr, format=image.format) | ||
imgByteArr = imgByteArr.getvalue() | ||
return imgByteArr | ||
|
||
except FileNotFoundError: | ||
_LOGGER.warning("Could not read camera %s image from file: %s") | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.