Skip to content

Commit

Permalink
Merge branch 'release/0.3.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
syssi committed May 8, 2021
2 parents 1e31013 + 35b0d40 commit cc12fc9
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 11 deletions.
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ Credits: Thanks to [Rytilahti](https://github.com/rytilahti/python-miio) for all
| Pedestal Fan Fan ZA1 | zhimi.fan.za1 | | |
| Pedestal Fan Fan ZA3 | zhimi.fan.za3 | | |
| Pedestal Fan Fan ZA4 | zhimi.fan.za4 | | |
| Pedestal Fan Fan 1C | dmaker.fan.1c | | |
| Pedestal Fan Fan P5 | dmaker.fan.p5 | | |
| Pedestal Fan Fan P8 | dmaker.fan.p8 | | |
| Pedestal Fan Fan P9 | dmaker.fan.p9 | | |
| Pedestal Fan Fan P10 | dmaker.fan.p10 | | |
| Mijia Pedestal Fan | dmaker.fan.p11 | BPLDS03DM | 2800mAh, 24W, <=58dB |
Expand Down Expand Up @@ -140,7 +142,7 @@ Rotates the fan 5 degrees to the left/right.
| `entity_id` | yes | Only act on a specific fan entity. Else targets all. |
| `direction` | no | Rotate the fan 5 degrees. Valid values are `left` and `right`. |

#### Service `fan.xiaomi_miio_set_oscillation_angle`
#### Service `xiaomi_miio_fan.fan_set_oscillation_angle`

Set the oscillation angle. Supported values are 30, 60, 90 and 120 degrees.

Expand All @@ -149,7 +151,7 @@ Set the oscillation angle. Supported values are 30, 60, 90 and 120 degrees.
| `entity_id` | yes | Only act on a specific xiaomi miio entity. Else targets all. |
| `angle` | no | Angle in degrees. Valid values are `30`, `60`, `90` and `120`. |

#### Service `fan.xiaomi_miio_set_delay_off`
#### Service `xiaomi_miio_fan.fan_set_delay_off`

Set the scheduled turn off time. Supported values are 0, 60, 120, 180, 240, 300, 360, 420, 480 minutes. When 0 is passed, delay_off is disabled.

Expand All @@ -159,55 +161,55 @@ Set the scheduled turn off time. Supported values are 0, 60, 120, 180, 240, 300,
| `entity_id` | yes | Only act on a specific xiaomi miio entity. Else targets all. |
| `delay_off_countdown` | no | Time in minutes. Valid values are `0`, `60`, `120`, `180`, `240`, `300`, `240`, `300`, `360`, `420`, `480` minutes. |

#### Service `fan.xiaomi_miio_set_natural_mode_on`
#### Service `xiaomi_miio_fan.fan_set_natural_mode_on`

Turn the natural mode on.

| Service data attribute | Optional | Description |
|---------------------------|----------|----------------------------------------------------------------------|
| `entity_id` | yes | Only act on a specific xiaomi miio entity. Else targets all. |

#### Service `fan.xiaomi_miio_set_natural_mode_off`
#### Service `xiaomi_miio_fan.fan_set_natural_mode_off`

Turn the natural mode off.

| Service data attribute | Optional | Description |
|---------------------------|----------|----------------------------------------------------------------------|
| `entity_id` | yes | Only act on a specific xiaomi miio entity. Else targets all. |

#### Service `fan.xiaomi_miio_set_buzzer_on`
#### Service `xiaomi_miio_fan.fan_set_buzzer_on`

Turn the buzzer on.

| Service data attribute | Optional | Description |
|---------------------------|----------|----------------------------------------------------------------------|
| `entity_id` | yes | Only act on a specific xiaomi miio entity. Else targets all. |

#### Service `fan.xiaomi_miio_set_buzzer_off`
#### Service `xiaomi_miio_fan.fan_set_buzzer_off`

Turn the buzzer off.

| Service data attribute | Optional | Description |
|---------------------------|----------|----------------------------------------------------------------------|
| `entity_id` | yes | Only act on a specific xiaomi miio entity. Else targets all. |

#### Service `fan.xiaomi_miio_set_child_lock_on`
#### Service `xiaomi_miio_fan.fan_set_child_lock_on`

Turn the child lock on.

| Service data attribute | Optional | Description |
|---------------------------|----------|----------------------------------------------------------------------|
| `entity_id` | yes | Only act on a specific xiaomi miio entity. Else targets all. |

#### Service `fan.xiaomi_miio_set_child_lock_off`
#### Service `xiaomi_miio_fan.fan_set_child_lock_off`

Turn the child lock off.

| Service data attribute | Optional | Description |
|---------------------------|----------|----------------------------------------------------------------------|
| `entity_id` | yes | Only act on a specific xiaomi miio entity. Else targets all. |

#### Service `fan.xiaomi_miio_set_led_brightness`
#### Service `xiaomi_miio_fan.fan_set_led_brightness`

Set the led brightness. Supported values are 0 (Bright), 1 (Dim), 2 (Off).

Expand Down
168 changes: 168 additions & 0 deletions custom_components/xiaomi_miio_fan/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
Fan,
FanLeshow,
FanP5,
Fan1C,
FanP9,
FanP10,
FanP11,
Expand All @@ -27,6 +28,9 @@
from miio.fan_leshow import ( # pylint: disable=import-error, import-error
OperationMode as FanLeshowOperationMode,
)
from miio.fan_miot import (
OperationModeMiot as FanOperationModeMiot
)
import voluptuous as vol

from homeassistant.components.fan import (
Expand Down Expand Up @@ -66,10 +70,12 @@
MODEL_FAN_ZA3 = "zhimi.fan.za3"
MODEL_FAN_ZA4 = "zhimi.fan.za4"
MODEL_FAN_P5 = "dmaker.fan.p5"
MODEL_FAN_P8 = "dmaker.fan.p8"
MODEL_FAN_P9 = "dmaker.fan.p9"
MODEL_FAN_P10 = "dmaker.fan.p10"
MODEL_FAN_P11 = "dmaker.fan.p11"
MODEL_FAN_LESHOW_SS4 = "leshow.fan.ss4"
MODEL_FAN_1C = "dmaker.fan.1c"

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
Expand All @@ -85,10 +91,12 @@
MODEL_FAN_ZA3,
MODEL_FAN_ZA4,
MODEL_FAN_P5,
MODEL_FAN_P8,
MODEL_FAN_P9,
MODEL_FAN_P10,
MODEL_FAN_P11,
MODEL_FAN_LESHOW_SS4,
MODEL_FAN_1C,
]
),
vol.Optional(CONF_RETRIES, default=DEFAULT_RETRIES): cv.positive_int,
Expand Down Expand Up @@ -163,6 +171,16 @@
ATTR_ERROR_DETECTED: "error_detected",
}

AVAILABLE_ATTRIBUTES_FAN_1C = {
ATTR_MODE: "mode",
ATTR_RAW_SPEED: "speed",
ATTR_BUZZER: "buzzer",
ATTR_OSCILLATE: "oscillate",
ATTR_DELAY_OFF_COUNTDOWN: "delay_off_countdown",
ATTR_LED: "led",
ATTR_CHILD_LOCK: "child_lock",
}

FAN_SPEED_LEVEL1 = "Level 1"
FAN_SPEED_LEVEL2 = "Level 2"
FAN_SPEED_LEVEL3 = "Level 3"
Expand Down Expand Up @@ -192,6 +210,13 @@
FAN_SPEED_LEVEL4: 100,
}

FAN_PRESET_MODES_1C = {
SPEED_OFF: 0,
FAN_SPEED_LEVEL1: 1,
FAN_SPEED_LEVEL2: 2,
FAN_SPEED_LEVEL3: 3,
}

SUCCESS = ["ok"]

FEATURE_SET_BUZZER = 1
Expand All @@ -218,6 +243,7 @@
)

FEATURE_FLAGS_FAN_LESHOW_SS4 = FEATURE_SET_BUZZER
FEATURE_FLAGS_FAN_1C = FEATURE_FLAGS_FAN

SERVICE_SET_BUZZER_ON = "fan_set_buzzer_on"
SERVICE_SET_BUZZER_OFF = "fan_set_buzzer_off"
Expand Down Expand Up @@ -324,6 +350,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
elif model == MODEL_FAN_LESHOW_SS4:
fan = FanLeshow(host, token, model=model)
device = XiaomiFanLeshow(name, fan, model, unique_id, retries)
elif model in [MODEL_FAN_1C, MODEL_FAN_P8]:
fan = Fan1C(host, token, model=model)
device = XiaomiFan1C(name, fan, model, unique_id, retries)
else:
_LOGGER.error(
"Unsupported device found! Please create an issue at "
Expand Down Expand Up @@ -995,3 +1024,142 @@ async def async_set_delay_off(self, delay_off_countdown: int) -> None:
self._device.delay_off,
delay_off_countdown,
)


class XiaomiFan1C(XiaomiFan):
"""Representation of a Xiaomi Fan 1C."""

def __init__(self, name, device, model, unique_id, retries):
"""Initialize the fan entity."""
super().__init__(name, device, model, unique_id, retries)

self._device_features = FEATURE_FLAGS_FAN_1C
self._available_attributes = AVAILABLE_ATTRIBUTES_FAN_1C
self._preset_modes = FAN_PRESET_MODES_1C
self._oscillate = None

self._state_attrs.update(
{attribute: None for attribute in self._available_attributes}
)

@property
def supported_features(self) -> int:
"""Supported features."""
return SUPPORT_PRESET_MODE | SUPPORT_OSCILLATE

async def async_update(self):
"""Fetch state from the device."""
# On state change the device doesn't provide the new state immediately.
if self._skip_update:
self._skip_update = False
return

try:
state = await self.hass.async_add_job(self._device.status)
_LOGGER.debug("Got new state: %s", state)

self._available = True
self._oscillate = state.oscillate
self._state = state.is_on

for preset_mode, value in FAN_PRESET_MODES_1C.items():
if state.speed == value:
self._preset_mode = preset_mode

self._state_attrs.update(
{
key: self._extract_value_from_attribute(state, value)
for key, value in self._available_attributes.items()
}
)
self._retry = 0

except DeviceException as ex:
self._retry = self._retry + 1
if self._retry < self._retries:
_LOGGER.info(
"Got exception while fetching the state: %s , _retry=%s",
ex,
self._retry,
)
else:
self._available = False
_LOGGER.error(
"Got exception while fetching the state: %s , _retry=%s",
ex,
self._retry,
)

@property
def preset_modes(self):
"""Get the list of available preset modes."""
return self._preset_modes

@property
def preset_mode(self):
"""Get the current preset mode."""
if self._state:
return self._preset_mode

return None

async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set the preset mode of the fan."""
_LOGGER.debug("Setting the preset mode to: %s", preset_mode)

await self._try_command(
"Setting preset mode of the miio device failed.",
self._device.set_speed,
FAN_PRESET_MODES_1C[preset_mode],
)

@property
def oscillating(self):
"""Return the oscillation state."""
return self._oscillate

async def async_oscillate(self, oscillating: bool) -> None:
"""Set oscillation."""
if oscillating:
await self._try_command(
"Setting oscillate on of the miio device failed.",
self._device.set_oscillate,
True,
)
else:
await self._try_command(
"Setting oscillate off of the miio device failed.",
self._device.set_oscillate,
False,
)

async def async_set_delay_off(self, delay_off_countdown: int) -> None:
"""Set scheduled off timer in minutes."""

await self._try_command(
"Setting delay off miio device failed.",
self._device.delay_off,
delay_off_countdown,
)

async def async_set_natural_mode_on(self):
"""Turn the natural mode on."""
if self._device_features & FEATURE_SET_NATURAL_MODE == 0:
return

await self._try_command(
"Setting fan natural mode of the miio device failed.",
self._device.set_mode,
FanOperationModeMiot.Nature,
)

async def async_set_natural_mode_off(self):
"""Turn the natural mode off."""
if self._device_features & FEATURE_SET_NATURAL_MODE == 0:
return

await self._try_command(
"Setting fan natural mode of the miio device failed.",
self._device.set_mode,
FanOperationModeMiot.Normal,
)
3 changes: 2 additions & 1 deletion custom_components/xiaomi_miio_fan/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
"domain": "xiaomi_miio_fan",
"name": "Xiaomi Mi Smart Pedestal Fan",
"version": "0.3.3",
"iot_class": "local_polling",
"documentation": "https://github.com/syssi/xiaomi_fan",
"requirements": [
"construct==2.10.56",
"python-miio>=0.5.5"
"python-miio>=0.5.6"
],
"dependencies": [],
"codeowners": [
Expand Down
2 changes: 1 addition & 1 deletion hacs.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"content_in_root": false,
"render_readme": true,
"iot_class": "local_polling",
"homeassistant": "2021.4.0"
"homeassistant": "2021.5.1"
}

0 comments on commit cc12fc9

Please sign in to comment.