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

Commit

Permalink
Air Fryer Properties (AirFryer158) (#175)
Browse files Browse the repository at this point in the history
* Air Fryer Properties (AirFryer158)

* Fix icon error

[*] Fix icon error
[*] Frist BETA Air Fryer Methods

* Add olther model AIRFRYER

* Fix Linters error

* Fix Linters error

* pass in Linters (flake8, black, isort)
  • Loading branch information
tv4you2016 authored Oct 27, 2023
1 parent 2f014ef commit 8ef52f3
Show file tree
Hide file tree
Showing 15 changed files with 365 additions and 61 deletions.
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
50 changes: 48 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"):
for stype in BINARY_SENSOR_TYPES_AIRFRYER.values():
entities.append(
VeSyncairfryerSensor(
dev,
coordinator,
stype,
)
)
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,47 @@ 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."""
value = getattr(self.airfryer, self.stype[0], None)
return value
# 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
95 changes: 95 additions & 0 deletions custom_components/vesync/button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""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"):
for stype in SENSOR_TYPES_CS158.values():
entities.append(
VeSyncairfryerButton(
dev,
coordinator,
stype,
)
)

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

0 comments on commit 8ef52f3

Please sign in to comment.