Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update to the new fan platform #542

Merged
merged 53 commits into from
Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
ec793a1
Update en.json
tinglis1 Aug 18, 2021
5217014
Update const.py
tinglis1 Aug 18, 2021
761a5f1
Update fan.py
tinglis1 Aug 18, 2021
4eb1806
Update fan.py
tinglis1 Aug 18, 2021
b8acadc
working
tinglis1 Aug 18, 2021
e613075
update to new fan entity percentage configuration
tinglis1 Aug 19, 2021
94c3af1
update to new fan entity percentage
tinglis1 Aug 19, 2021
4cc7ffc
update to new fan entity configuration
tinglis1 Aug 19, 2021
5cbf556
remove comments
tinglis1 Aug 19, 2021
45890cf
Merge branch 'master' into master
tinglis1 Aug 26, 2021
8196703
fixed logger error
tinglis1 Sep 2, 2021
3eacbbd
spelling error
tinglis1 Oct 5, 2021
3fca556
Update fan.py
psbankar Oct 6, 2021
3f2606a
Merge pull request #1 from psbankar/master
tinglis1 Oct 20, 2021
30f95d8
Merge branch 'master' into master
tinglis1 Oct 22, 2021
ec223ba
add presets and integer/string option
tinglis1 Oct 26, 2021
6f281a0
missing imports
tinglis1 Oct 26, 2021
0c59ddc
correctly split preset and speed in updates
tinglis1 Oct 26, 2021
7ac4fe5
Revert "correctly split preset and speed in updates"
tinglis1 Oct 26, 2021
0f43923
Revert "missing imports"
tinglis1 Oct 26, 2021
c8e660d
Revert "add presets and integer/string option"
tinglis1 Oct 26, 2021
c99a93b
Fix speed variable error
tinglis1 Nov 9, 2021
9bf9b9f
fix formatting errors
tinglis1 Nov 11, 2021
af9f11a
fix formatting errors
tinglis1 Nov 11, 2021
77f9159
workflow_dispatch
tinglis1 Nov 11, 2021
eda45fc
fix tox errors
tinglis1 Nov 11, 2021
e741b2f
Merge branch 'master' of https://github.com/tinglis1/localtuya
tinglis1 Nov 11, 2021
f175394
checks updates and tox fixes
tinglis1 Nov 11, 2021
c30c68d
tox
tinglis1 Nov 11, 2021
01b9b00
fix requirements
tinglis1 Nov 11, 2021
6e6cd08
fix tox errors
tinglis1 Nov 11, 2021
95ef271
more tox fixes
tinglis1 Nov 11, 2021
a171430
fix error
tinglis1 Nov 11, 2021
e55cd20
line length issue
tinglis1 Nov 11, 2021
8d5da3d
remove dev tool changes fro branch
tinglis1 Nov 11, 2021
c9c96ad
revert dev tool config files for master branch
tinglis1 Nov 11, 2021
44ba820
Merge pull request #2 from tinglis1/dev
tinglis1 Nov 11, 2021
e979a4b
update dev checker tools
tinglis1 Nov 11, 2021
994aac3
Merge branch 'add-string/integer-and-preset' of https://github.com/ti…
tinglis1 Nov 11, 2021
445b62e
tox.yaml
tinglis1 Nov 11, 2021
1c2f4ba
Delete settings.json
tinglis1 Nov 11, 2021
e8aa5ac
integration inputs
tinglis1 Nov 11, 2021
d600cba
fix tox errors
tinglis1 Nov 11, 2021
ced1550
Merge branch 'master' into master
tinglis1 Dec 17, 2021
88a5a73
Merge branch 'master' into master
rospogrigio Dec 21, 2021
e1ac7de
remove blank line
tinglis1 Dec 22, 2021
a25bf75
tox fixes
tinglis1 Dec 22, 2021
0e048af
fix issue with last tox fix
tinglis1 Dec 22, 2021
b748f04
Remove blank line
tinglis1 Dec 22, 2021
a6ef6a4
Merge branch 'add-string/integer-and-preset' into master
tinglis1 Dec 22, 2021
d878391
readme updated
tinglis1 Dec 22, 2021
ddee11f
Revert "Merge branch 'add-string/integer-and-preset' into master"
tinglis1 Dec 22, 2021
764993f
Merge branch 'master' into master
rospogrigio Jan 3, 2022
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: 6 additions & 3 deletions custom_components/localtuya/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@
# fan
CONF_FAN_SPEED_CONTROL = "fan_speed_control"
CONF_FAN_OSCILLATING_CONTROL = "fan_oscillating_control"
CONF_FAN_SPEED_LOW = "fan_speed_low"
CONF_FAN_SPEED_MEDIUM = "fan_speed_medium"
CONF_FAN_SPEED_HIGH = "fan_speed_high"
CONF_FAN_SPEED_MIN = "fan_speed_min"
CONF_FAN_SPEED_MAX = "fan_speed_max"
CONF_FAN_ORDERED_LIST = "fan_speed_ordered_list"
CONF_FAN_DIRECTION = "fan_direction"
CONF_FAN_DIRECTION_FWD = "fan_direction_forward"
CONF_FAN_DIRECTION_REV = "fan_direction_reverse"

# sensor
CONF_SCALING = "scaling"
Expand Down
199 changes: 140 additions & 59 deletions custom_components/localtuya/fan.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
"""Platform to locally control Tuya-based fan devices."""
import logging
from functools import partial
import math

import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from homeassistant.components.fan import (
DOMAIN,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
DIRECTION_FORWARD,
DIRECTION_REVERSE,
SUPPORT_DIRECTION,
SUPPORT_OSCILLATE,
SUPPORT_SET_SPEED,
FanEntity,
Expand All @@ -18,9 +19,20 @@
from .const import (
CONF_FAN_OSCILLATING_CONTROL,
CONF_FAN_SPEED_CONTROL,
CONF_FAN_SPEED_HIGH,
CONF_FAN_SPEED_LOW,
CONF_FAN_SPEED_MEDIUM,
CONF_FAN_DIRECTION,
CONF_FAN_DIRECTION_FWD,
CONF_FAN_DIRECTION_REV,
CONF_FAN_SPEED_MIN,
CONF_FAN_SPEED_MAX,
CONF_FAN_ORDERED_LIST
)

from homeassistant.util.percentage import (
ordered_list_item_to_percentage,
percentage_to_ordered_list_item,
percentage_to_ranged_value,
ranged_value_to_percentage,
int_states_in_range
)

_LOGGER = logging.getLogger(__name__)
Expand All @@ -31,15 +43,12 @@ def flow_schema(dps):
return {
vol.Optional(CONF_FAN_SPEED_CONTROL): vol.In(dps),
vol.Optional(CONF_FAN_OSCILLATING_CONTROL): vol.In(dps),
vol.Optional(CONF_FAN_SPEED_LOW, default=SPEED_LOW): vol.In(
[SPEED_LOW, "1", "2", "small"]
),
vol.Optional(CONF_FAN_SPEED_MEDIUM, default=SPEED_MEDIUM): vol.In(
[SPEED_MEDIUM, "mid", "2", "3"]
),
vol.Optional(CONF_FAN_SPEED_HIGH, default=SPEED_HIGH): vol.In(
[SPEED_HIGH, "auto", "3", "4", "large", "big"]
),
vol.Optional(CONF_FAN_DIRECTION): vol.In(dps),
vol.Optional(CONF_FAN_DIRECTION_FWD, default="forward"): cv.string,
vol.Optional(CONF_FAN_DIRECTION_REV, default="reverse"): cv.string,
vol.Optional(CONF_FAN_SPEED_MIN, default=1): cv.positive_int,
vol.Optional(CONF_FAN_SPEED_MAX, default=9): cv.positive_int,
vol.Optional(CONF_FAN_ORDERED_LIST, default="disabled"): cv.string,
}


Expand All @@ -56,31 +65,48 @@ def __init__(
"""Initialize the entity."""
super().__init__(device, config_entry, fanid, _LOGGER, **kwargs)
self._is_on = False
self._speed = None
self._oscillating = None
self._direction = None
self._percentage = None
self._speed_range = (
self._config.get(CONF_FAN_SPEED_MIN),
self._config.get(CONF_FAN_SPEED_MAX),
)
self._ordered_list = self._config.get(CONF_FAN_ORDERED_LIST).split(",")
self._ordered_list_mode = None

if (type(self._ordered_list) is list and len(self._ordered_list) > 1):
self._use_ordered_list = True
_LOGGER.debug("Fan _use_ordered_list: %s > %s", self._use_ordered_list, self._ordered_list)

else:
self._use_ordered_list = False
_LOGGER.debug("Fan _use_ordered_list: %s", self._use_ordered_list)


@property
def oscillating(self):
"""Return current oscillating status."""
return self._oscillating

@property
def current_direction(self):
"""Return the current direction of the fan."""
return self._direction

@property
def is_on(self):
"""Check if Tuya fan is on."""
return self._is_on

@property
def speed(self) -> str:
"""Return the current speed."""
return self._speed

@property
def speed_list(self) -> list:
"""Get the list of available speeds."""
return [SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]
def percentage(self):
"""Return the current percentage."""
return self._percentage

async def async_turn_on(self, speed: str = None, **kwargs) -> None:
"""Turn on the entity."""
_LOGGER.debug("Fan async_turn_on")
await self._device.set_dp(True, self._dp_id)
if speed is not None:
await self.async_set_speed(speed)
Expand All @@ -89,68 +115,123 @@ async def async_turn_on(self, speed: str = None, **kwargs) -> None:

async def async_turn_off(self, **kwargs) -> None:
"""Turn off the entity."""

_LOGGER.debug("Fan async_turn_on")

await self._device.set_dp(False, self._dp_id)
self.schedule_update_ha_state()

async def async_set_speed(self, speed: str) -> None:
async def async_set_percentage(self, percentage):
"""Set the speed of the fan."""
mapping = {
SPEED_LOW: self._config.get(CONF_FAN_SPEED_LOW),
SPEED_MEDIUM: self._config.get(CONF_FAN_SPEED_MEDIUM),
SPEED_HIGH: self._config.get(CONF_FAN_SPEED_HIGH),
}

if speed == SPEED_OFF:
await self._device.set_dp(False, self._dp_id)
else:
await self._device.set_dp(
mapping.get(speed), self._config.get(CONF_FAN_SPEED_CONTROL)
)

_LOGGER.debug("Fan async_set_percentage: %s", percentage)

if percentage == 0:
return await self.async_turn_off()

if not self.is_on:
await self.async_turn_on()

if percentage is not None:
if self._use_ordered_list:
await self._device.set_dp(
str(
percentage_to_ordered_list_item(self._ordered_list, percentage)
),
self._config.get(CONF_FAN_SPEED_CONTROL)
)
_LOGGER.debug("Fan async_set_percentage: %s > %s", percentage, percentage_to_ordered_list_item(self._ordered_list, percentage))

else:
await self._device.set_dp(
str(math.ceil(
percentage_to_ranged_value(self._speed_range, percentage)
)),
self._config.get(CONF_FAN_SPEED_CONTROL)
)
_LOGGER.debug("Fan async_set_percentage: %s > %s", percentage, percentage_to_ranged_value(self._ordered_list, percentage))

self.schedule_update_ha_state()

async def async_oscillate(self, oscillating: bool) -> None:
"""Set oscillation."""
_LOGGER.debug("Fan async_oscillate: %s", oscillating)
await self._device.set_dp(
oscillating, self._config.get(CONF_FAN_OSCILLATING_CONTROL)
)
self.schedule_update_ha_state()

async def async_set_direction(self, direction):
"""Set the direction of the fan."""
_LOGGER.debug("Fan async_set_direction: %s", direction)

if direction == DIRECTION_FORWARD:
value = self._config.get(CONF_FAN_DIRECTION_FWD)

if direction == DIRECTION_REVERSE:
value = self._config.get(CONF_FAN_DIRECTION_REV)

await self._device.set_dp(
value, self._config.get(CONF_FAN_DIRECTION)
)
self.schedule_update_ha_state()

@property
def supported_features(self) -> int:
"""Flag supported features."""
supports = 0
features = 0

if self.has_config(CONF_FAN_OSCILLATING_CONTROL):
supports |= SUPPORT_OSCILLATE
features |= SUPPORT_OSCILLATE

if self.has_config(CONF_FAN_SPEED_CONTROL):
supports |= SUPPORT_SET_SPEED
features |= SUPPORT_SET_SPEED

if self.has_config(CONF_FAN_DIRECTION):
features |= SUPPORT_DIRECTION

return features

@property
def speed_count(self) -> int:
"""Speed count for the fan."""
speed_count = int_states_in_range(self._speed_range)
_LOGGER.debug("Fan speed_count: %s", speed_count)
return speed_count

return supports

def status_updated(self):
"""Get state of Tuya fan."""
mappings = {
self._config.get(CONF_FAN_SPEED_LOW): SPEED_LOW,
self._config.get(CONF_FAN_SPEED_MEDIUM): SPEED_MEDIUM,
self._config.get(CONF_FAN_SPEED_HIGH): SPEED_HIGH,
}

self._is_on = self.dps(self._dp_id)

if self.has_config(CONF_FAN_SPEED_CONTROL):
self._speed = mappings.get(self.dps_conf(CONF_FAN_SPEED_CONTROL))
if self.speed is None:
self.warning(
"%s/%s: Ignoring unknown fan controller state: %s",
self.name,
self.entity_id,
self.dps_conf(CONF_FAN_SPEED_CONTROL),
)
self._speed = None
current_speed = self.dps_conf(CONF_FAN_SPEED_CONTROL)
if self._use_ordered_list:
_LOGGER.debug("Fan current_speed ordered_list_item_to_percentage: %s from %s", current_speed, self._ordered_list)
if current_speed is not None:
self._percentage = ordered_list_item_to_percentage(self._ordered_list, current_speed)

else:
_LOGGER.debug("Fan current_speed ranged_value_to_percentage: %s from %s", current_speed, self._speed_range)
if current_speed is not None:
self._percentage = ranged_value_to_percentage(self._speed_range, int(current_speed))

_LOGGER.debug("Fan current_percentage: %s", self._percentage)

if self.has_config(CONF_FAN_OSCILLATING_CONTROL):
self._oscillating = self.dps_conf(CONF_FAN_OSCILLATING_CONTROL)

_LOGGER.debug("Fan current_oscillating : %s", self._oscillating)


if self.has_config(CONF_FAN_DIRECTION):
value = self.dps_conf(CONF_FAN_DIRECTION)
if value is not None:
if value == self._config.get(CONF_FAN_DIRECTION_FWD):
self._direction = DIRECTION_FORWARD

if value == self._config.get(CONF_FAN_DIRECTION_REV):
self._direction = DIRECTION_REVERSE

_LOGGER.debug("Fan current_direction : %s > %s", value, self._direction)


async_setup_entry = partial(async_setup_entry, DOMAIN, LocaltuyaFan, flow_schema)
26 changes: 16 additions & 10 deletions custom_components/localtuya/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,14 @@
"color_temp_max_kelvin": "Maximum Color Temperature in K",
"music_mode": "Music mode available",
"scene": "Scene",
"fan_speed_control": "Fan Speed Control",
"fan_oscillating_control": "Fan Oscillating Control",
"fan_speed_low": "Fan Low Speed Setting",
"fan_speed_medium": "Fan Medium Speed Setting",
"fan_speed_high": "Fan High Speed Setting"
"fan_speed_control": "Fan Speed Control dps",
"fan_oscillating_control": "Fan Oscillating Control dps",
"fan_speed_min": "minimum fan speed integer",
"fan_speed_max": "maximum fan speed integer",
"fan_speed_ordered_list": "Fan speed modes list (overrides speed min/max)",
"fan_direction":"fan direction dps",
"fan_direction_forward": "forward dps string",
"fan_direction_reverse": "reverser dps string"
}
}
}
Expand Down Expand Up @@ -122,11 +125,14 @@
"color_temp_max_kelvin": "Maximum Color Temperature in K",
"music_mode": "Music mode available",
"scene": "Scene",
"fan_speed_control": "Fan Speed Control",
"fan_oscillating_control": "Fan Oscillating Control",
"fan_speed_low": "Fan Low Speed Setting",
"fan_speed_medium": "Fan Medium Speed Setting",
"fan_speed_high": "Fan High Speed Setting"
"fan_speed_control": "Fan Speed Control dps",
"fan_oscillating_control": "Fan Oscillating Control dps",
"fan_speed_min": "minimum fan speed integer",
"fan_speed_max": "maximum fan speed integer",
"fan_speed_ordered_list": "Fan speed modes list (overrides speed min/max)",
"fan_direction":"fan direction dps",
"fan_direction_forward": "forward dps string",
"fan_direction_reverse": "reverser dps string"
}
},
"yaml_import": {
Expand Down