Pittini / iobroker-nodemihome

Steuerung von bisher nicht unterstützten Xiaomi Geräten in Iobroker via node-mihome
MIT License
27 stars 15 forks source link

Run actions #53

Closed spicchio72 closed 2 years ago

spicchio72 commented 2 years ago

Is there any way to execute actions on devices? I succesfully integrated some read states for the Mi Smart Air Fryer (careli.fryer.maf02). This machine though has actions (AIID) to run a cooking and I can't understand how and if I can use them.

Pittini commented 2 years ago

and I can't understand how and if I can use them.

Welcome in the club. As there is no good documentation in node-mihome and the Dev don't answers to issues, pr's or questions, i see no way to implement actions. So, at last, its not an issue here, rather then node-mihome direct.

spicchio72 commented 2 years ago

I understand. I've also tried the Homebridge adapter for iobroker togheter with the homebridge-miot plugin. It recognizes without any configuration both the device and actions available (shows information in the log file) and tells it's ready to be controlled, but since I discovered that this plugin doesen't create any datapoint it's useless for iobroker.

spicchio72 commented 2 years ago

Just some notes to help other people that are looking for a way to run actions from Iobroker with the Pittini's nodemihome script, and until someone else will find out how to extend the node-mihome module for actions:

Actions need the MI Cloud support and can't be run on local LAN with the miio protocol. The only way that I found to run an action from iobroker is through a CLI python script that has the Mi cloud protocol support for actions:

https://github.com/Yonsm/MiService

I've been able in this way to configure and run all the actions present in the Mi Smart Air Fryer.

Immagine2

Steps:

  1. Install the python module by running this command from a shell: pip3 install miservice

  2. In Pittini's script create the commons for your actions in the DefineDevice[x] by following normal rules like you would when setting a PIID but keep them write only and set the type to boolean (to control actions through a pushbutton later in vis). example:

    { name: "air-fryer.start-cook", type: "boolean", read: false, write: true, min: false, max: true}]

  3. Create a setter for each common related to an action in this way:

     "air-fryer.start-cook": function () { exec("export MI_USER=username && export MI_PASS=password && micli.py action '{"did":"406614713","siid":2,"aiid":1,"in":[]}'", function (error, stdout, stderr) {
                console.log(stdout);
            });
  4. Find out the did for your device, the AIID (action ID) and SIID (service ID) to be included in this call. To find them I used the https://home.miot-spec.com website. The "in" parameter passed in the call are extra options for this action and might be an empty array or include values from other PIIDs (parameter IDs) present in the same SIID.

Immagine

Next an example of a setter to start cooking that shows how those extra parameters have been used.

    "custom.start-custom-cook": function (){ exec("export MI_USER=username && export MI_PASS=password && micli.py action '{"did":"406614713","siid":3,"aiid":1,"in":["",2,40,0,0,0]}'", function (error, stdout, stderr) {
            console.log(stdout);
        });

In short, the action 'start-custom-cook', or Action ID 1 (AIID 1) for Service ID 3 (SIID 3) has as 'in' parameter an array of values defined by the values of the indicated PIIDs. The 'in' value will be then an array of parameters like this: ["", 2, 40, 0, 0, 0]

  1. Now you can connect this action to a button is VIS or execute it from a script to start the cooking.

The downside of this simple method to run actions is that the function setDevices() in Pittini's script will be executed at the same time. Since it won't run anything useful it doesen't create problems, but Pittini himself has surely better skills than me to eventually modify the script and include the execution of actions in this way without affecting the normal behaviour of the setDevice() function.

spicchio72 commented 2 years ago

Next the device definition for the careli.fryer.maf02 (modify with the DID for your device and with the parameters you like as options for the action:

DefineDevice[1] = { // Tested and working
    info: {},
    model: "careli.fryer.maf02",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:air-fryer:0000A0A4:careli-maf02:1
    description: "Xiaomi Air Fryer",
    setter: {
        "air-fryer.target-time": async function (obj, val) { await device[obj].setTargetTime(val) },
        "air-fryer.target-temperature": async function (obj, val) { await device[obj].setTargetTemperature(val) },
        "air-fryer.start-cook": function () { exec("export MI_USER=username && export MI_PASS=password && micli.py action '{"did":"<your_did>","siid":2,"aiid":1,"in":[]}'", function (error, stdout, stderr) {
                console.log(stdout);
            });
         },
        "air-fryer.cancel-cooking": function () { exec("export MI_USER=username && export MI_PASS=password && micli.py action '{"did":"<your_did>","siid":2,"aiid":2,"in":[]}'", function (error, stdout, stderr) {
                console.log(stdout);
            });
         },
        "air-fryer.pause": function () { exec("export MI_USER=username && export MI_PASS=password && micli.py action '{"did":"<your_did>","siid":2,"aiid":3,"in":[]}'", function (error, stdout, stderr) {
                    console.log(stdout);
            });
         },
        "custom.start-custom-cook": function (){ exec("export MI_USER=username && export MI_PASS=password && micli.py action '{"did":"<your_did>","siid":3,"aiid":1,"in":[<your_parameters>]}'", function (error, stdout, stderr) {
               console.log(stdout);
            });
        }
    },
    common:
        [{ name: "air-fryer.status", type: "number", read: true, write: false, min: 0, max: 9, states: { 0: "Shutdown", 1: "Standby", 2: "Pause", 3: "Appointment", 4: "Cooking", 5: "Preheat", 6: "Cooked", 7: "Preheat Finish", 8: "Preheat Pause", 9: "Pause2" }},
         { name: "air-fryer.target-time", type: "number", read: true, write: true, min: 1, max: 1440, unit: "min" },
         { name: "air-fryer.target-temperature", type: "number", read: true, write: true, min: 40, max: 200, unit: "°C." },
         { name: "air-fryer.left-time", type: "number", read: true, write: false, min: 0, max: 1440, unit: "min"},
         { name: "air-fryer.start-cook", type: "boolean", read: false, write: true, min: false, max: true},
         { name: "air-fryer.cancel-cooking", type: "boolean", read: false, write: true, min: false, max: true},
         { name: "air-fryer.pause", type: "boolean", read: false, write: true, min: false, max: true},
         { name: "custom.recipe-id", type: "string", read: true, write: false},
         { name: "custom.appoint-time", type: "number", read: true, write: false, min: 0, max: 1440, unit: "min"},
         { name: "custom.food-quanty", type: "number", read: true, write: false, min: 0, max: 4, states: {0: "Null", 1: "Single", 2: "Double", 3: "Half", 4: "Full"}},
         { name: "custom.preheat-switch", type: "number", read: true, write: true, min: 0, max: 2, states: { 0: "Null", 1: "On", 2: "Off"}},
         { name: "custom.appoint-time-left", type: "number", read: false, write: false, min: 0, max: 1440, unit: "min"},
         { name: "custom.turn-pot", type: "number", read: true, write: true, min: 0, max: 2, states: { 0: "Not Turn Pot", 1: "Switch Off", 2: "Turn Pot"}},
         { name: "custom.start-custom-cook", type: "boolean", read: false, write: true, min: false, max: true}]
};
spicchio72 commented 2 years ago

and the content for the device file that has to be added to /node-mihome/lib/devices folder (rename it as careli.fryer.maf02.js):

careli.fryer.maf02.js.txt

Pittini commented 2 years ago

Really great work. But I do not integrate this in the script, because its very special, needs a separate installation and so on. But I have pinned this, so if somebody needs it, he can find it. Tnx for your time and work.