diff --git a/README.md b/README.md index 66cf44d..a7815f1 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Credits: Thanks to [Rytilahti](https://github.com/rytilahti/python-miio) for all | | chunmi.cooker.normal5 | | | Mi Smart Pressure Cooker | chunmi.cooker.press1 | YLIH01CM | | | chunmi.cooker.press2 | | +| Mi Smart Multi Cooker | chunmi.cooker.eh1 | | ## Features @@ -152,6 +153,172 @@ icon_height: 40px ![Lovelace button to start cooking](lovelace-button-start-cooking.png "lovelace button") +## Advanced Setup Example (only chunmi.cooker.eh1) [WIP] +The following is an advanced example for a configuration of chunmi.cooker.eh1 supporting the following: + +- Show current cooker status: mode, temp, cooking time +- Start the cooker + - with cooking profile selection + - with optional schedule +- Stop the cooker + +![Lovelace button to start cooking](lovelace_advanced_example_multi_cooker_0.png "Multi Cooker Example") +![Lovelace button to start cooking](lovelace_advanced_example_multi_cooker_1.png "Multi Cooker Example") + +```yaml +# lovelace +type: vertical-stack +title: Multi Cooker +cards: + - type: entities + state_color: false + entities: + - entity: sensor.xiaomi_miio_cooker_mode + - entity: sensor.xiaomi_miio_cooker_temperature + - entity: sensor.cooker_time_remaining + name: Remaining Cooking Time + - type: conditional + conditions: + - entity: sensor.xiaomi_miio_cooker_mode + state_not: Waiting + - entity: sensor.xiaomi_miio_cooker_mode + state_not: Unknown + card: + type: horizontal-stack + cards: + - type: entities + entities: + - entity: sensor.xiaomi_miio_cooker_menu + show_header_toggle: true + - type: button + tap_action: + action: call-service + service: script.rice_cooker_stop + show_icon: true + name: Stop Cooking + show_state: false + icon: 'mdi:gesture-tap' + icon_height: 40px + - type: conditional + conditions: + - entity: sensor.xiaomi_miio_cooker_mode + state: Waiting + card: + type: horizontal-stack + cards: + - type: entities + entities: + - entity: input_select.cooker_programm + show_header_toggle: true + - type: button + tap_action: + action: call-service + service: script.rice_cooker_start + show_icon: true + name: Start Cooking + show_state: false + show_name: true + icon: 'mdi:gesture-tap' + icon_height: 40px + - type: conditional + conditions: + - entity: sensor.xiaomi_miio_cooker_mode + state: Waiting + card: + type: entities + entities: + - entity: input_boolean.rice_cooker_schedule + - type: conditional + conditions: + - entity: input_boolean.rice_cooker_schedule + state: 'on' + card: + type: entities + entities: + - entity: input_datetime.rice_cooker_schedule_time +``` + +```yaml +# configuration.yaml +sensor: + - platform: template + sensors: + cooker_time_remaining: + friendly_name: "Kochzeit" + icon_template: "mdi:clock-outline" + value_template: > + {% if is_state('sensor.xiaomi_miio_cooker_mode', 'Waiting') %} + 0:00 + {% else %} + {{ ('%02d' % (((states('sensor.xiaomi_miio_cooker_remaining') | int) / 60) | int)) | string + ':' + ( ('%02d' % ((states('sensor.xiaomi_miio_cooker_remaining') | int) % 60)) | string) }} + {% endif %} + cooker_menu: + friendly_name: "Menu" + icon_template: "mdi:menu" + value_template: > + {{ + { + "0000000000000000000000000000000000000001": "Fine Rice", + "0101000000000000000000000000000000000002": "Quick Rice", + "0202000000000000000000000000000000000003": "Congee", + "0303000000000000000000000000000000000004": "Keep warm", + "0505000000000000000000000000000000000009": "Cake" + }[states('sensor.xiaomi_miio_cooker_menu')] + }} +input_datetime: + rice_cooker_schedule_time: + name: Time + has_time: true + has_date: true +input_boolean: + rice_cooker_schedule: + name: Schedule +input_select: + cooker_programm: + name: Modus + options: + - Fine Rice + - Quick Rice + - Congee + - Keep warm + - Cake + initial: Fine Rice + icon: mdi:menu +``` + +```yaml +# scripts.yaml +rice_cooker_start: + alias: StartRiceCooker + sequence: + - service: xiaomi_miio_cooker.start + data: + schedule: | + {% if is_state('input_boolean.rice_cooker_schedule', 'on') %} + {{ ((state_attr('input_datetime.rice_cooker_schedule_time', 'timestamp') - now().timestamp()) / 60) | int }} + {% else %} + 0 + {% endif %} + profile: | + {{ + { + "Fine Rice": "02010000000001e101000000000000800101050814000000002091827d7800050091822d781c0a0091823c781c1e0091ff827820ffff91828278000500ffff8278ffffff91828278000d00ff828778ff000091827d7800000091827d7800ffff91826078ff0100490366780701086c0078090301af540266780801086c00780a02023c5701667b0e010a71007a0d02ffff5701667b0f010a73007d0d032005000000000000000000000000000000cf53", + "Quick Rice": "02010100000002e100280000000000800101050614000000002091827d7800000091823c7820000091823c781c1e0091ff827820ffff91828278000500ffff8278ffffff91828278000d00ff828778ff000082827d7800000091827d7800ffff91826078ff0164490366780701086c007409030200540266780801086c00760a0202785701667b0e010a7100780a02ffff5701667b0f010a73007b0a032005000000000000000000000000000000ddba", + "Congee": "02010200000003e2011e0400002800800101050614000000002091827d7800000091827d7800000091827d78001e0091ff877820ffff91827d78001e0091ff8278ffffff91828278001e0091828278060f0091827d7804000091827d7800000091827d780001f54e0255261802062a0482030002eb4e0255261802062a04820300032d4e0252261802062c04820501ffff4e0152241802062c0482050120000000000000000000000000000000009ce2", + "Cake": "02010400000afe8801000100003700000100000000000000002091827d7800000091827d7800000091827d78001e0066787d7816000091827d7800000091826e7800000091827d7800000091826e7810ffff918266780a000091827d7800000091827d78000000000078821400108714780300000000007882140010871478030000000000788214001087147a050100000000788214001087147d05012000000000000000000000000000000000aa25", + "Keep warm": "020103000000040c00001800000100800100000000000000002091827d7800000091827d7800000091827d78000000915a7d7820000091827d7800000091826e78ff000091827d7800000091826e7810000091826e7810000091827d7800000091827d780000a082007882140010871478030000eb820078821400108714780300012d8200788214001087147a0501ffff8200788214001087147d0501200000000000000000000000000000000090e5" + }[states('input_select.cooker_programm')] + }} + - service: input_boolean.turn_off + data: {} + entity_id: input_boolean.rice_cooker_schedule + mode: single +rice_cooker_stop: + alias: StopRiceCooker + sequence: + - service: xiaomi_miio_cooker.stop +``` + ## Debugging If the custom component doesn't work out of the box for your device please update your configuration to increase the log level: diff --git a/custom_components/xiaomi_miio_cooker/__init__.py b/custom_components/xiaomi_miio_cooker/__init__.py index fa7b3ff..b62c50f 100644 --- a/custom_components/xiaomi_miio_cooker/__init__.py +++ b/custom_components/xiaomi_miio_cooker/__init__.py @@ -10,8 +10,10 @@ from homeassistant.helpers.entity import Entity from homeassistant.helpers.event import track_time_interval from homeassistant.util.dt import utcnow -from miio import Cooker, Device, DeviceException -from miio.cooker import OperationMode +from miio import Device +from miio.exceptions import DeviceException +from miio.integrations.chunmi.cooker import Cooker +from miio.integrations.chunmi.cooker_multi import MultiCooker _LOGGER = logging.getLogger(__name__) @@ -32,6 +34,7 @@ MODEL_NORMAL3 = "chunmi.cooker.normal3" MODEL_NORMAL4 = "chunmi.cooker.normal4" MODEL_NORMAL5 = "chunmi.cooker.normal5" +MODEL_MULTI = "chunmi.cooker.eh1" SUPPORTED_MODELS = [ MODEL_PRESSURE1, @@ -41,6 +44,7 @@ MODEL_NORMAL3, MODEL_NORMAL4, MODEL_NORMAL5, + MODEL_MULTI, ] CONFIG_SCHEMA = vol.Schema( @@ -62,6 +66,9 @@ ATTR_MODEL = "model" ATTR_PROFILE = "profile" +ATTR_DURATION = "duration" +ATTR_SCHEDULE = "schedule" +ATTR_AKW = "akw" SUCCESS = ["ok"] @@ -71,7 +78,14 @@ } ) -SERVICE_SCHEMA_START = SERVICE_SCHEMA.extend({vol.Required(ATTR_PROFILE): cv.string}) +SERVICE_SCHEMA_START = SERVICE_SCHEMA.extend( + { + vol.Required(ATTR_PROFILE): cv.string, + vol.Optional(ATTR_DURATION): cv.positive_int, + vol.Optional(ATTR_SCHEDULE): cv.positive_int, + vol.Optional(ATTR_AKW): cv.boolean, + } +) SERVICE_START = "start" SERVICE_STOP = "stop" @@ -110,7 +124,10 @@ def setup(hass, config): raise PlatformNotReady if model in SUPPORTED_MODELS: - cooker = Cooker(host, token) + if model == MODEL_MULTI: + cooker = MultiCooker(host, token) + else: + cooker = Cooker(host, token) hass.data[DOMAIN][host] = cooker @@ -134,7 +151,7 @@ def update(event_time): _LOGGER.debug("Got new state: %s", state) hass.data[DATA_KEY][host][DATA_STATE] = state - if state.mode in [OperationMode.Running, OperationMode.AutoKeepWarm]: + if state.mode in ["running", "autokeepwarm"]: hass.data[DATA_KEY][host][ DATA_TEMPERATURE_HISTORY ] = cooker.get_temperature_history() @@ -151,7 +168,14 @@ def update(event_time): def start_service(call): """Service to start cooking.""" profile = call.data.get(ATTR_PROFILE) - cooker.start(profile) + duration = call.data.get(ATTR_DURATION) + schedule = call.data.get(ATTR_SCHEDULE) + akw = call.data.get(ATTR_AKW) + + if model == MODEL_MULTI: + cooker.start(profile, duration, schedule, akw) + else: + cooker.start(profile) def stop_service(call): """Service to stop cooking.""" diff --git a/custom_components/xiaomi_miio_cooker/manifest.json b/custom_components/xiaomi_miio_cooker/manifest.json index 35f3dae..c5b3e06 100644 --- a/custom_components/xiaomi_miio_cooker/manifest.json +++ b/custom_components/xiaomi_miio_cooker/manifest.json @@ -11,7 +11,7 @@ "issue_tracker": "https://github.com/syssi/xiaomi_cooker/issues", "requirements": [ "construct==2.10.68", - "python-miio>=0.5.12" + "git+https://github.com/sschirr/python-miio.git@master#python-miio==0.6.0.dev0" ], "version": "2023.12.0.0" } diff --git a/custom_components/xiaomi_miio_cooker/sensor.py b/custom_components/xiaomi_miio_cooker/sensor.py index b1f7f05..a2b4b71 100644 --- a/custom_components/xiaomi_miio_cooker/sensor.py +++ b/custom_components/xiaomi_miio_cooker/sensor.py @@ -80,8 +80,6 @@ def name(self): @callback def async_update_callback(self, host): """Update state.""" - from miio.cooker import OperationMode - if self._host is not host: return @@ -104,7 +102,7 @@ def async_update_callback(self, host): if ( self._attr == "temperature" and state.mode - in [OperationMode.Running, OperationMode.AutoKeepWarm] + in ["running", "autokeepwarm"] and temperature_history ): self._state = temperature_history.temperatures.pop() diff --git a/lovelace_advanced_example_multi_cooker_0.png b/lovelace_advanced_example_multi_cooker_0.png new file mode 100644 index 0000000..1c7e3f8 Binary files /dev/null and b/lovelace_advanced_example_multi_cooker_0.png differ diff --git a/lovelace_advanced_example_multi_cooker_1.png b/lovelace_advanced_example_multi_cooker_1.png new file mode 100644 index 0000000..ab69257 Binary files /dev/null and b/lovelace_advanced_example_multi_cooker_1.png differ