Skip to content
This repository has been archived by the owner on Dec 21, 2023. It is now read-only.

Air Fryer Properties (AirFryer158) (Sourcery refactored) #177

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

# **Important message**
>
> Unfortunately, I no longer have time to maintain this repo. I am therefore looking for someone to take it over before archiving it. If interested please contact me.
Expand Down Expand Up @@ -44,6 +45,13 @@ logger:
pyvesync: debug
```

## TODO LIST
```
- [x] Air Fryer Properties (AirFryer158)
- [ ] Air Fryer Methods
- [ ] Create the Card
```

### Contributing

All contributions are very welcomed!
Expand All @@ -54,3 +62,4 @@ pip install pre-commit
pre-commit install
pre-commit run --all-files
```

2 changes: 2 additions & 0 deletions custom_components/vesync/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
DOMAIN,
SERVICE_UPDATE_DEVS,
VS_BINARY_SENSORS,
VS_BUTTON,
VS_DISCOVERY,
VS_FANS,
VS_HUMIDIFIERS,
Expand All @@ -33,6 +34,7 @@
Platform.HUMIDIFIER: VS_HUMIDIFIERS,
Platform.NUMBER: VS_NUMBERS,
Platform.BINARY_SENSOR: VS_BINARY_SENSORS,
Platform.BUTTON: VS_BUTTON,
}

_LOGGER = logging.getLogger(__name__)
Expand Down
49 changes: 47 additions & 2 deletions custom_components/vesync/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .common import VeSyncBaseEntity, has_feature
from .const import DOMAIN, VS_BINARY_SENSORS, VS_DISCOVERY
from .const import BINARY_SENSOR_TYPES_AIRFRYER, DOMAIN, VS_BINARY_SENSORS, VS_DISCOVERY

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -44,6 +44,15 @@ def _setup_entities(devices, async_add_entities, coordinator):
"""Check if device is online and add entity."""
entities = []
for dev in devices:
if hasattr(dev, "fryer_status"):
entities.extend(
VeSyncairfryerSensor(
dev,
coordinator,
stype,
)
for stype in BINARY_SENSOR_TYPES_AIRFRYER.values()
)
if has_feature(dev, "details", "water_lacks"):
entities.append(VeSyncOutOfWaterSensor(dev, coordinator))
if has_feature(dev, "details", "water_tank_lifted"):
Expand All @@ -52,10 +61,46 @@ def _setup_entities(devices, async_add_entities, coordinator):
async_add_entities(entities, update_before_add=True)


class VeSyncairfryerSensor(VeSyncBaseEntity, BinarySensorEntity):
"""Class representing a VeSyncairfryerSensor."""

def __init__(self, airfryer, coordinator, stype) -> None:
"""Initialize the VeSync humidifier device."""
super().__init__(airfryer, coordinator)
self.airfryer = airfryer
self.stype = stype

@property
def entity_category(self):
"""Return the diagnostic entity category."""
return EntityCategory.DIAGNOSTIC

@property
def unique_id(self):
"""Return unique ID for water tank lifted sensor on device."""
return f"{super().unique_id}-{self.stype[0]}"

@property
def name(self):
"""Return sensor name."""
return self.stype[1]

@property
def is_on(self) -> bool:
"""Return a value indicating whether the Humidifier's water tank is lifted."""
return getattr(self.airfryer, self.stype[0], None)
# return self.smarthumidifier.details["water_tank_lifted"]

@property
def icon(self):
"""Return the icon to use in the frontend, if any."""
return self.stype[2]


class VeSyncBinarySensorEntity(VeSyncBaseEntity, BinarySensorEntity):
"""Representation of a binary sensor describing diagnostics of a VeSync humidifier."""

def __init__(self, humidifier, coordinator):
def __init__(self, humidifier, coordinator) -> None:
"""Initialize the VeSync humidifier device."""
super().__init__(humidifier, coordinator)
self.smarthumidifier = humidifier
Expand Down
94 changes: 94 additions & 0 deletions custom_components/vesync/button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"""Support for VeSync button."""
import logging

from homeassistant.components.button import ButtonEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .common import VeSyncBaseEntity
from .const import DOMAIN, VS_BUTTON, VS_DISCOVERY

_LOGGER = logging.getLogger(__name__)


SENSOR_TYPES_CS158 = {
# unique_id,name # icon,
"end": [
"end",
"End cooking or preheating ",
"mdi:stop",
],
}


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up switches."""

coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]

@callback
def discover(devices):
"""Add new devices to platform."""
_setup_entities(devices, async_add_entities, coordinator)

config_entry.async_on_unload(
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_BUTTON), discover)
)

_setup_entities(
hass.data[DOMAIN][config_entry.entry_id][VS_BUTTON],
async_add_entities,
coordinator,
)


@callback
def _setup_entities(devices, async_add_entities, coordinator):
"""Check if device is online and add entity."""
entities = []
for dev in devices:
if hasattr(dev, "cook_set_temp"):
entities.extend(
VeSyncairfryerButton(
dev,
coordinator,
stype,
)
for stype in SENSOR_TYPES_CS158.values()
)
async_add_entities(entities, update_before_add=True)


class VeSyncairfryerButton(VeSyncBaseEntity, ButtonEntity):
"""Base class for VeSync switch Device Representations."""

def __init__(self, airfryer, coordinator, stype) -> None:
"""Initialize the VeSync humidifier device."""
super().__init__(airfryer, coordinator)
self.airfryer = airfryer
self.stype = stype

@property
def unique_id(self):
"""Return unique ID for water tank lifted sensor on device."""
return f"{super().unique_id}-{self.stype[0]}"

@property
def name(self):
"""Return sensor name."""
return self.stype[1]

@property
def icon(self):
"""Return the icon to use in the frontend, if any."""
return self.stype[2]

def press(self) -> None:
"""Return True if device is on."""
self.airfryer.end()
55 changes: 35 additions & 20 deletions custom_components/vesync/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.helpers.entity import Entity, ToggleEntity
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from pyvesync.vesyncfan import model_features
from pyvesync.vesyncfan import model_features as fan_model_features
from pyvesync.vesynckitchen import model_features as kitchen_model_features

from .const import (
DOMAIN,
VS_AIRFRYER_TYPES,
VS_BINARY_SENSORS,
VS_BUTTON,
VS_FAN_TYPES,
VS_FANS,
VS_HUMIDIFIERS,
Expand All @@ -27,16 +30,6 @@ def has_feature(device, dictionary, attribute):
return getattr(device, dictionary, {}).get(attribute, None) is not None


def is_humidifier(device_type: str) -> bool:
"""Return true if the device type is a humidifier."""
return model_features(device_type)["module"] in VS_HUMIDIFIERS_TYPES


def is_air_purifier(device_type: str) -> bool:
"""Return true if the device type is a an air purifier."""
return model_features(device_type)["module"] in VS_FAN_TYPES


async def async_process_devices(hass, manager):
"""Assign devices to proper component."""
devices = {
Expand All @@ -47,21 +40,23 @@ async def async_process_devices(hass, manager):
VS_HUMIDIFIERS: [],
VS_NUMBERS: [],
VS_BINARY_SENSORS: [],
VS_BUTTON: [],
}

redacted = async_redact_data(
{k: [d.__dict__ for d in v] for k, v in manager._dev_list.items()},
["cid", "uuid", "mac_id"],
)

_LOGGER.debug(
_LOGGER.warning(
"Found the following devices: %s",
redacted,
)

if (
manager.fans is None
and manager.bulbs is None
manager.bulbs is None
and manager.fans is None
and manager.kitchen is None
and manager.outlets is None
and manager.switches is None
):
Expand All @@ -70,13 +65,13 @@ async def async_process_devices(hass, manager):
if manager.fans:
for fan in manager.fans:
# VeSync classifies humidifiers as fans
if is_humidifier(fan.device_type):
if fan_model_features(fan.device_type)["module"] in VS_HUMIDIFIERS_TYPES:
devices[VS_HUMIDIFIERS].append(fan)
elif is_air_purifier(fan.device_type):
elif fan_model_features(fan.device_type)["module"] in VS_FAN_TYPES:
devices[VS_FANS].append(fan)
else:
_LOGGER.warning(
"Unknown device type %s %s (enable debug for more info)",
"Unknown fan type %s %s (enable debug for more info)",
fan.device_name,
fan.device_type,
)
Expand All @@ -102,13 +97,33 @@ async def async_process_devices(hass, manager):
else:
devices[VS_LIGHTS].append(switch)

if manager.kitchen:
for airfryer in manager.kitchen:
if (
kitchen_model_features(airfryer.device_type)["module"]
in VS_AIRFRYER_TYPES
):
_LOGGER.warning(
"Found air fryer %s, support in progress.\n%s", airfryer.device_name
)
devices[VS_SENSORS].append(airfryer)
devices[VS_BINARY_SENSORS].append(airfryer)
devices[VS_SWITCHES].append(airfryer)
devices[VS_BUTTON].append(airfryer)
else:
_LOGGER.warning(
"Unknown device type %s %s (enable debug for more info)",
airfryer.device_name,
airfryer.device_type,
)

return devices


class VeSyncBaseEntity(CoordinatorEntity, Entity):
"""Base class for VeSync Entity Representations."""

def __init__(self, device, coordinator):
def __init__(self, device, coordinator) -> None:
"""Initialize the VeSync device."""
self.device = device
super().__init__(coordinator, context=device)
Expand All @@ -130,7 +145,7 @@ def unique_id(self):
@property
def base_name(self):
"""Return the name of the device."""
return self.device.device_name
return self.device.device_type

@property
def name(self):
Expand Down Expand Up @@ -163,7 +178,7 @@ async def async_added_to_hass(self):
class VeSyncDevice(VeSyncBaseEntity, ToggleEntity):
"""Base class for VeSync Device Representations."""

def __init__(self, device, coordinator):
def __init__(self, device, coordinator) -> None:
"""Initialize the VeSync device."""
super().__init__(device, coordinator)

Expand Down
2 changes: 1 addition & 1 deletion custom_components/vesync/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class VeSyncFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):

VERSION = 1

def __init__(self):
def __init__(self) -> None:
"""Instantiate config flow."""
self._username = None
self._password = None
Expand Down
Loading
Loading