Skip to content

Commit ae05ce8

Browse files
committed
Add skeleton
1 parent c9054c1 commit ae05ce8

File tree

5 files changed

+223
-0
lines changed

5 files changed

+223
-0
lines changed

.flake8.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[flake8]
2+
exclude = .git,.tox,__pycache__
3+
max-line-length = 100

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
.idea/

.hound.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
python:
2+
enabled: true
3+
config_file: .flake8.ini

README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Xiaomi Mi Electric Rice Cooker
2+
3+
This is a custom component for home assistant to integrate the Xiaomi Mi Electric Rice Cooker V2.
4+
5+
Please follow the instructions on [Retrieving the Access Token](https://home-assistant.io/components/xiaomi/#retrieving-the-access-token) to get the API token to use in the configuration.yaml file.
6+
7+
Credits: Thanks to [Rytilahti](https://github.com/rytilahti/python-miio) for all the work.
8+
9+
## Features
10+
11+
### Rice Cooker V2
12+
13+
* Start cooking a profile
14+
* Stop cooking
15+
* Attributes
16+
- mode
17+
- menu
18+
- temperature
19+
- start_time
20+
- remaining
21+
- cooking_delayed
22+
- duration
23+
- settings
24+
- favorite
25+
- stage(?)
26+
27+
## Setup
28+
29+
```yaml
30+
# configuration.yaml
31+
32+
platform: xiaomi_cooker
33+
host: 192.168.130.88
34+
token: b7c4a758c251955d2c24b1d9e41ce47d
35+
model: chunmi.cooker.normal2
36+
```
37+
38+
Configuration variables:
39+
- **host** (*Required*): The IP of your cooker.
40+
- **token** (*Required*): The API token of your cooker.
41+
- **model** (*Optional*): The model of your device. Valid values are `chunmi.cooker.normal2` and `chunmi.cooker.normal5`. This setting can be used to bypass the device model detection and is recommended if your device isn't always available.
42+
43+
## Platform services
44+
45+
#### Service `xiaomi_cooker.start`
46+
47+
Start cooking a profile.
48+
49+
| Service data attribute | Optional | Description |
50+
|---------------------------|----------|----------------------------------------------------------------------|
51+
| `entity_id` | yes | Only act on a specific air purifier. Else targets all. |
52+
| `profile` | no | Profile data which describes the temperature curve. |
53+
54+
#### Service `xiaomi_cooker.stop`
55+
56+
Stop the cooking process.
57+
58+
| Service data attribute | Optional | Description |
59+
|---------------------------|----------|----------------------------------------------------------------------|
60+
| `entity_id` | yes | Only act on a specific air purifier. Else targets all. |

custom_components/xiaomi_cooker.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
from collections import defaultdict
2+
import asyncio
3+
from functools import partial
4+
import logging
5+
6+
import voluptuous as vol
7+
8+
import homeassistant.helpers.config_validation as cv
9+
from homeassistant.helpers.entity import Entity
10+
from homeassistant.helpers import discovery
11+
from homeassistant.const import (CONF_NAME, CONF_HOST, CONF_TOKEN,
12+
ATTR_ENTITY_ID, )
13+
from homeassistant.exceptions import PlatformNotReady
14+
15+
_LOGGER = logging.getLogger(__name__)
16+
17+
DOMAIN = DATA_KEY = 'xiaomi_cooker'
18+
19+
CONF_MODEL = 'model'
20+
21+
SUPPORTED_MODELS = ['chunmi.cooker.normal2',
22+
'chunmi.cooker.normal5']
23+
24+
CONFIG_SCHEMA = vol.Schema({
25+
DOMAIN: vol.Schema({
26+
vol.Required(CONF_HOST): cv.string,
27+
vol.Required(CONF_TOKEN): vol.All(cv.string,
28+
vol.Length(min=32, max=32)),
29+
vol.Optional(CONF_MODEL): vol.In(SUPPORTED_MODELS),
30+
})
31+
}, extra=vol.ALLOW_EXTRA)
32+
33+
REQUIREMENTS = ['python-miio>=0.3.7']
34+
35+
ATTR_MODEL = 'model'
36+
ATTR_PROFILE = 'profile'
37+
38+
SUCCESS = ['ok']
39+
40+
SERVICE_SCHEMA = vol.Schema({
41+
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
42+
})
43+
44+
SERVICE_SCHEMA_START = SERVICE_SCHEMA.extend({
45+
vol.Required(ATTR_PROFILE): cv.string,
46+
})
47+
48+
SERVICE_START = 'start'
49+
SERVICE_STOP = 'stop'
50+
51+
SERVICE_TO_METHOD = {
52+
SERVICE_START: {'method': 'async_start', 'schema': SERVICE_SCHEMA_START},
53+
SERVICE_STOP: {'method': 'async_stop'},
54+
}
55+
56+
57+
# pylint: disable=unused-argument
58+
def setup(hass, config):
59+
"""Set up the platform from config."""
60+
from miio import Device, DeviceException
61+
if DATA_KEY not in hass.data:
62+
hass.data[DATA_KEY] = {}
63+
64+
if DOMAIN in config:
65+
host = config[DOMAIN][CONF_HOST]
66+
token = config[DOMAIN][CONF_TOKEN]
67+
model = config[DOMAIN].get(CONF_MODEL)
68+
69+
_LOGGER.info("Initializing with host %s (token %s...)", host, token[:5])
70+
71+
if model is None:
72+
try:
73+
miio_device = Device(host, token)
74+
device_info = miio_device.info()
75+
model = device_info.model
76+
_LOGGER.info("%s %s %s detected",
77+
model,
78+
device_info.firmware_version,
79+
device_info.hardware_version)
80+
except DeviceException:
81+
raise PlatformNotReady
82+
83+
if model in SUPPORTED_MODELS:
84+
from miio import Cooker
85+
cooker = Cooker(host, token)
86+
87+
hass.data[DATA_KEY][host] = cooker
88+
89+
# for component in ['sensor', 'switch']:
90+
# discovery.load_platform(hass, component, DOMAIN, {}, config)
91+
92+
else:
93+
_LOGGER.error(
94+
'Unsupported device found! Please create an issue at '
95+
'https://github.com/syssi/xiaomi_cooker/issues '
96+
'and provide the following data: %s', model)
97+
return False
98+
99+
return True
100+
101+
102+
class XiaomiMiioDevice(Entity):
103+
"""Representation of a Xiaomi MiIO device."""
104+
105+
def __init__(self, device, name):
106+
"""Initialize the entity."""
107+
self._device = device
108+
self._name = name
109+
110+
self._available = None
111+
self._state = None
112+
self._state_attrs = {}
113+
114+
@property
115+
def should_poll(self):
116+
"""Poll the miio device."""
117+
return True
118+
119+
@property
120+
def name(self):
121+
"""Return the name of this entity, if any."""
122+
return self._name
123+
124+
@property
125+
def available(self):
126+
"""Return true when state is known."""
127+
return self._available
128+
129+
@property
130+
def state(self):
131+
"""Return the state of the device."""
132+
return self._state
133+
134+
@property
135+
def device_state_attributes(self):
136+
"""Return the state attributes of the device."""
137+
return self._state_attrs
138+
139+
async def _try_command(self, mask_error, func, *args, **kwargs):
140+
"""Call a device command handling error messages."""
141+
from miio import DeviceException
142+
try:
143+
result = await self.hass.async_add_job(
144+
partial(func, *args, **kwargs))
145+
146+
_LOGGER.info("Response received from miio device: %s", result)
147+
148+
return result == SUCCESS
149+
except DeviceException as exc:
150+
_LOGGER.error(mask_error, exc)
151+
return False

0 commit comments

Comments
 (0)