Skip to content

Commit

Permalink
Merge branch 'master' into vacuum_gen2
Browse files Browse the repository at this point in the history
  • Loading branch information
rytilahti authored Nov 11, 2018
2 parents 5063646 + a271245 commit 7f0f62f
Show file tree
Hide file tree
Showing 23 changed files with 552 additions and 99 deletions.
60 changes: 60 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,65 @@
# Change Log

## [0.4.3](https://github.com/rytilahti/python-miio/tree/0.4.3)

This is a bugfix release which provides improved compatibility.

[Full Changelog](https://github.com/rytilahti/python-miio/compare/0.4.2...0.4.3)

**Closed issues:**

- unsupported device zhimi airmonitor v1 [\#393](https://github.com/rytilahti/python-miio/issues/393)
- Unsupported device found: chuangmi.ir.v2 [\#392](https://github.com/rytilahti/python-miio/issues/392)
- TypeError: not all arguments converted during string formatting [\#385](https://github.com/rytilahti/python-miio/issues/385)
- Status not worked for AirHumidifier CA1 [\#383](https://github.com/rytilahti/python-miio/issues/383)
- Xiaomi Rice Cooker Normal5: get\_prop only works if "all" properties are requested [\#380](https://github.com/rytilahti/python-miio/issues/380)
- python-construct-2.9.45 [\#374](https://github.com/rytilahti/python-miio/issues/374)

**Merged pull requests:**

- Update commands in manual [\#398](https://github.com/rytilahti/python-miio/pull/398) ([olskar](https://github.com/olskar))
- Add cli interface for yeelight devices [\#397](https://github.com/rytilahti/python-miio/pull/397) ([rytilahti](https://github.com/rytilahti))
- Add last\_clean\_details to return information from the last clean [\#395](https://github.com/rytilahti/python-miio/pull/395) ([rytilahti](https://github.com/rytilahti))
- Add discovery of the Xiaomi Air Quality Monitor \(PM2.5\) \(Closes: \#393\) [\#394](https://github.com/rytilahti/python-miio/pull/394) ([syssi](https://github.com/syssi))
- Add miiocli support for the Air Humidifier CA1 [\#391](https://github.com/rytilahti/python-miio/pull/391) ([syssi](https://github.com/syssi))
- Add property LED to the Xiaomi Air Fresh [\#390](https://github.com/rytilahti/python-miio/pull/390) ([syssi](https://github.com/syssi))
- Fix Cooker Normal5: get\_prop only works if "all" properties are requested \(Closes: \#380\) [\#389](https://github.com/rytilahti/python-miio/pull/389) ([syssi](https://github.com/syssi))
- Improve the support of the Air Humidifier CA1 \(Closes: \#383\) [\#388](https://github.com/rytilahti/python-miio/pull/388) ([syssi](https://github.com/syssi))


## [0.4.2](https://github.com/rytilahti/python-miio/tree/0.4.2)

This release removes the version pinning for "construct" library as its API has been stabilized and we don't want to force our downstreams for our version choices.
Another notable change is dropping the "mirobo" package which has been deprecated for a very long time, and everyone using it should have had converted to use "miio" already.
Furthermore the client tools work now with click's version 7+.

This release also changes the behavior of vacuum's `got_error` property to signal properly if an error has occured. The previous behavior was based on checking the state instead of the error number, which changed after an error to 'idle' after a short while.

[Full Changelog](https://github.com/rytilahti/python-miio/compare/0.4.1...0.4.2)

**Fixed bugs:**

- Zoned cleanup start and stops imediately [\#355](https://github.com/rytilahti/python-miio/issues/355)

**Closed issues:**

- STATE not supported: Updating, state\_code: 14 [\#381](https://github.com/rytilahti/python-miio/issues/381)
- cant get it to work with xiaomi robot vacuum cleaner s50 [\#378](https://github.com/rytilahti/python-miio/issues/378)
- airfresh problem [\#377](https://github.com/rytilahti/python-miio/issues/377)
- get device token is 000000000000000000 [\#366](https://github.com/rytilahti/python-miio/issues/366)
- Rockrobo firmware 3.3.9\_003254 [\#358](https://github.com/rytilahti/python-miio/issues/358)
- No response from the device on Xiaomi Roborock v2 [\#349](https://github.com/rytilahti/python-miio/issues/349)
- Information : Xiaomi Aqara Smart Camera Hack [\#347](https://github.com/rytilahti/python-miio/issues/347)

**Merged pull requests:**

- Fix click7 compatibility [\#387](https://github.com/rytilahti/python-miio/pull/387) ([rytilahti](https://github.com/rytilahti))
- Expand documentation for token from Android backup [\#382](https://github.com/rytilahti/python-miio/pull/382) ([sgtio](https://github.com/sgtio))
- vacuum's got\_error: compare against error code, not against the state [\#379](https://github.com/rytilahti/python-miio/pull/379) ([rytilahti](https://github.com/rytilahti))
- Add tqdm to requirements list [\#369](https://github.com/rytilahti/python-miio/pull/369) ([pluehne](https://github.com/pluehne))
- Improve repr format [\#368](https://github.com/rytilahti/python-miio/pull/368) ([syssi](https://github.com/syssi))


## [0.4.1](https://github.com/rytilahti/python-miio/tree/0.4.1)

This release provides support for some new devices, improved support of existing devices and various fixes.
Expand Down
11 changes: 10 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
include miio/data/*
include *.md
include *.txt
include .flake8.ini
include LICENSE
include tox.ini
recursive-include docs *.py
recursive-include docs *.rst
recursive-include docs Makefile
recursive-include miio *.json
recursive-include miio *.py
30 changes: 27 additions & 3 deletions docs/discovery.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,38 @@ or database from the Mi Home app.
The procedure is briefly described below,
but you may find the following links also useful:

- https://github.com/jghaanstra/com.xiaomi-miio/blob/master/docs/obtain\_token\_mirobot\_new.md
- https://github.com/jghaanstra/com.xiaomi-miio/blob/master/docs/obtain_token.md
- https://github.com/homeassistantchina/custom_components/blob/master/doc/chuang_mi_ir_remote.md

Android
~~~~~~~

To do a backup of an Android app you need to have the developer mode active,
and your device has to be accessible with ``adb``.
Start by installing the newest version of the Mi Home app from Google Play and
setting up your account. When the app asks you which server you want to use,
it's important to pick one that is also available in older versions of Mi
Home (we'll see why a bit later). U.S or china servers are OK, but the european
server is not supported by the old app. Then, set up your Xiaomi device with the
Mi Home app.

After the setup is completed, and the device has been connected to the Wi-Fi
network of your choice, it is necessary to downgrade the Mi Home app to some
version equal or below 5.0.19. As explained `here <https://github.com/jghaanstra/com.xiaomi-miio/blob/master/docs/obtain_token.md#method-3---obtain-mi-home-device-token-for-devices-that-hide-their-tokens-after-setup>`_
and `here <https://github.com/rytilahti/python-miio/issues/185>`_, newer versions
of the app do not download the token into the local database, which means that
we can't retrieve the token from the backup. You can find older versions of the
Mi Home app in `apkmirror <https://www.apkmirror.com/apk/xiaomi-inc/mihome/>`_.

Download, install and start up the older version of the Mi Home app. When the
app asks which server should be used, pick the same one you used with the newer
version of the app. Then, log into your account.

After this point, you are ready to perform the backup and extract the token.
Please note that it's possible that your device does not show under the old app.
As long as you picked the same server, it should be OK, and the token should
have been downloaded and stored into the database.

To do a backup of an Android app you need to have the developer mode active, and
your device has to be accessible with ``adb``.

.. TODO::
Add a link how to check and enable the developer mode.
Expand Down
16 changes: 8 additions & 8 deletions docs/vacuum.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Cleaning history

::

$ mirobo cleaning_history
$ mirobo cleaning-history
Total clean count: 43
Clean #0: 2017-03-05 19:09:40-2017-03-05 19:09:50 (complete: False, unknown: 0)
Area cleaned: 0.0 m²
Expand Down Expand Up @@ -147,13 +147,13 @@ There are two ways to install install sound packs:

::

mirobo install_sound my_sounds.pkg
mirobo install-sound my_sounds.pkg

2. Install from an URL, in which case you need to pass the md5 hash of the file as a second parameter.

::

mirobo install_sound http://10.10.20.1:8000/my_sounds.pkg b50cfea27e52ebd5f46038ac7b9330c8
mirobo install-sound http://10.10.20.1:8000/my_sounds.pkg b50cfea27e52ebd5f46038ac7b9330c8

`--sid` can be used to select the sound ID (SID) for the new file,
using an existing SID will overwrite the old.
Expand Down Expand Up @@ -186,7 +186,7 @@ and updating from an URL requires you to pass the md5 hash of the file.

::

mirobo update_firmware v11_003094.pkg
mirobo update-firmware v11_003094.pkg


DND functionality
Expand Down Expand Up @@ -215,14 +215,14 @@ To enable:

::

mirobo carpet_mode 1 (or any other true-value, such as 'true')
mirobo carpet-mode 1 (or any other true-value, such as 'true')


To disable:

::

mirobo carpet_mode 0
mirobo carpet-mode 0


Raw commands
Expand All @@ -234,13 +234,13 @@ It is also possible to run raw commands, which can be useful

::

mirobo raw_command app_start
mirobo raw-command app_start

or with parameters (same as above dnd on):

::

mirobo raw_command set_dnd_timer '[22,0,6,0]'
mirobo raw-command set_dnd_timer '[22,0,6,0]'

The input is passed as it is to the device as the `params` value,
so it is also possible to pass dicts.
Expand Down
22 changes: 22 additions & 0 deletions miio/airfresh.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ def mode(self) -> OperationMode:
"""Current operation mode."""
return OperationMode(self.data["mode"])

@property
def led(self) -> bool:
"""Return True if LED is on."""
return self.data["led"] == "on"

@property
def led_brightness(self) -> Optional[LedBrightness]:
"""Brightness of the LED."""
Expand Down Expand Up @@ -137,6 +142,7 @@ def __repr__(self) -> str:
"humidity=%s%%, " \
"co2=%s, " \
"mode=%s, " \
"led=%s, " \
"led_brightness=%s, " \
"buzzer=%s, " \
"child_lock=%s, " \
Expand All @@ -152,6 +158,7 @@ def __repr__(self) -> str:
self.humidity,
self.co2,
self.mode,
self.led,
self.led_brightness,
self.buzzer,
self.child_lock,
Expand Down Expand Up @@ -179,6 +186,7 @@ class AirFresh(Device):
"Humidity: {result.humidity} %\n"
"CO2: {result.co2} %\n"
"Mode: {result.mode.value}\n"
"LED: {result.led}\n"
"LED brightness: {result.led_brightness}\n"
"Buzzer: {result.buzzer}\n"
"Child lock: {result.child_lock}\n"
Expand Down Expand Up @@ -237,6 +245,20 @@ def set_mode(self, mode: OperationMode):
"""Set mode."""
return self.send("set_mode", [mode.value])

@command(
click.argument("led", type=bool),
default_output=format_output(
lambda led: "Turning on LED"
if led else "Turning off LED"
)
)
def set_led(self, led: bool):
"""Turn led on/off."""
if led:
return self.send("set_led", ['on'])
else:
return self.send("set_led", ['off'])

@command(
click.argument("brightness", type=EnumType(LedBrightness, False)),
default_output=format_output(
Expand Down
80 changes: 64 additions & 16 deletions miio/airhumidifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@

_LOGGER = logging.getLogger(__name__)

MODEL_HUMIDIFIER_V1 = 'zhimi.humidifier.v1'
MODEL_HUMIDIFIER_CA1 = 'zhimi.humidifier.ca1'

AVAILABLE_PROPERTIES_COMMON = [
'power',
'mode',
'temp_dec',
'humidity',
'buzzer',
'led_b',
'child_lock',
'limit_hum',
'use_time',
'hw_version',
]

AVAILABLE_PROPERTIES = {
MODEL_HUMIDIFIER_V1: AVAILABLE_PROPERTIES_COMMON + ['trans_level', 'button_pressed'],
MODEL_HUMIDIFIER_CA1: AVAILABLE_PROPERTIES_COMMON + ['speed', 'depth', 'dry'],
}


class AirHumidifierException(DeviceException):
pass
Expand Down Expand Up @@ -96,13 +117,15 @@ def target_humidity(self) -> int:
return self.data["limit_hum"]

@property
def trans_level(self) -> int:
def trans_level(self) -> Optional[int]:
"""
The meaning of the property is unknown.
The property is used to determine the strong mode is enabled on old firmware.
"""
return self.data["trans_level"]
if "trans_level" in self.data and self.data["trans_level"] is not None:
return self.data["trans_level"]
return None

@property
def strong_mode_enabled(self) -> bool:
Expand Down Expand Up @@ -133,12 +156,16 @@ def firmware_version_minor(self) -> int:
@property
def speed(self) -> Optional[int]:
"""Current fan speed."""
return self.data["speed"]
if "speed" in self.data and self.data["speed"] is not None:
return self.data["speed"]
return None

@property
def depth(self) -> Optional[int]:
"""The remaining amount of water in percent."""
return self.data["depth"]
if "depth" in self.data and self.data["depth"] is not None:
return self.data["depth"]
return None

@property
def dry(self) -> Optional[bool]:
Expand All @@ -147,7 +174,7 @@ def dry(self) -> Optional[bool]:
Return True if dry mode is on if available.
"""
if self.data["dry"] is not None:
if "dry" in self.data and self.data["dry"] is not None:
return self.data["dry"] == "on"
return None

Expand All @@ -164,7 +191,9 @@ def hardware_version(self) -> Optional[str]:
@property
def button_pressed(self) -> Optional[str]:
"""Last pressed button."""
return self.data["button_pressed"]
if "button_pressed" in self.data and self.data["button_pressed"] is not None:
return self.data["button_pressed"]
return None

def __repr__(self) -> str:
s = "<AirHumidiferStatus power=%s, " \
Expand Down Expand Up @@ -213,9 +242,15 @@ class AirHumidifier(Device):
"""Implementation of Xiaomi Mi Air Humidifier."""

def __init__(self, ip: str = None, token: str = None, start_id: int = 0,
debug: int = 0, lazy_discover: bool = True) -> None:
debug: int = 0, lazy_discover: bool = True,
model: str = MODEL_HUMIDIFIER_V1) -> None:
super().__init__(ip, token, start_id, debug, lazy_discover)

if model in AVAILABLE_PROPERTIES:
self.model = model
else:
self.model = MODEL_HUMIDIFIER_V1

self.device_info = None

@command(
Expand Down Expand Up @@ -244,20 +279,26 @@ def status(self) -> AirHumidifierStatus:
if self.device_info is None:
self.device_info = self.info()

properties = ['power', 'mode', 'temp_dec', 'humidity', 'buzzer',
'led_b', 'child_lock', 'limit_hum', 'trans_level',
'speed', 'depth', 'dry', 'use_time', 'button_pressed',
'hw_version', ]
properties = AVAILABLE_PROPERTIES[self.model]

values = self.send(
"get_prop",
properties
)
# A single request is limited to 16 properties. Therefore the
# properties are divided into multiple requests
_props_per_request = 15

# The CA1 is limited to a single property per request
if self.model == MODEL_HUMIDIFIER_CA1:
_props_per_request = 1

_props = properties.copy()
values = []
while _props:
values.extend(self.send("get_prop", _props[:_props_per_request]))
_props[:] = _props[_props_per_request:]

properties_count = len(properties)
values_count = len(values)
if properties_count != values_count:
_LOGGER.debug(
_LOGGER.error(
"Count (%s) of requested properties does not match the "
"count (%s) of received values.",
properties_count, values_count)
Expand Down Expand Up @@ -349,3 +390,10 @@ def set_dry(self, dry: bool):
return self.send("set_dry", ["on"])
else:
return self.send("set_dry", ["off"])


class AirHumidifierCA1(AirHumidifier):
def __init__(self, ip: str = None, token: str = None, start_id: int = 0,
debug: int = 0, lazy_discover: bool = True) -> None:
super().__init__(ip, token, start_id, debug, lazy_discover,
model=MODEL_HUMIDIFIER_CA1)
Loading

0 comments on commit 7f0f62f

Please sign in to comment.