[
  {
    "path": ".github/FUNDING.yml",
    "content": "custom: [paypal.me/bkubesa]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/new-device.md",
    "content": "---\nname: New Device\nabout: Request support for a new device\ntitle: ''\nlabels: feature, new device\nassignees: ''\n\n---\n\n> As there is no official API and Xiaomi does not support third-party integration, being able to add a device to the Homey app depends on an existing integration, online documentation or donating the device to the developer. If neither of these can be fulfilled then integration is not possible.\n\n### Supply the device details\n* **Name:** << The name of the device >>\n* **Model ID:** << brand.type.id, for instance zhimi.airpurifier.mc1, can also be found using token extraction tool (see wiki) >>\n* **MIoT spec:** << find the link to the specs of this device on this website: https://home.miot-spec.com/ >>\n\n### Current support\n<< Have you tested an existing driver based on the currently supported devices list (see wiki) and what was the result / error / missing functionality? >>\n\n### Additional information\n<< Add any other context or screenshots about the feature request here. >>\n\n---- STOP EDITING HERE----\n### Donation\nI enjoy creating apps for Homey and try to support them as best as I can. If you enjoy using my apps a [donation](https://www.paypal.me/bkubesa) in return for the time I put into this is much appreciated.\n"
  },
  {
    "path": ".gitignore",
    "content": "/env.json\n/node_modules/\n/.homeybuild/\n.codegpt\n/.homeybuild\n/node_modules\nappdirectory.zip\nappdirectory_working.zip\n/.homeybuild\n/.homeybuild\n/tmp\n/.homeybuild\n/.homeybuild\n/.homeybuild\nAGENTS.md\n/.homeybuild\nAGENTS.md\n"
  },
  {
    "path": ".homeychangelog.json",
    "content": "{\n  \"2.13.3\": {\n    \"en\": \"Added a mechanism to refresh the device connection to prevent devices from not responding on the first try. Also moved installation instructions from app store to community support topic.\"\n  },\n  \"2.13.4\": {\n    \"en\": \"Fixed a mistake in the latest update that caused the app to crash.\"\n  },\n  \"2.13.5\": {\n    \"en\": \"Fixed an issue with the pairing of the gateway v3.\"\n  },\n  \"2.13.6\": {\n    \"en\": \"Fixed an issue with the pairing of the gateway v3.\"\n  },\n  \"2.13.7\": {\n    \"en\": \"Fixed an issue with the pairing of the gateway v3.\"\n  },\n  \"2.13.8\": {\n    \"en\": \"[IMPORTANT] Deprecated support for Yeelights, they will get their own standalone app. Please read the announcement in the support topic on migrating your Yeelights.\"\n  },\n  \"2.13.9\": {\n    \"en\": \"Deprecated the driver for the Xiaomi Gateway. Xiaomi changed something resulting in the current implementation not working anymore.\"\n  },\n  \"3.0.0\": {\n    \"en\": \"Added support for Xiaomi Gateway child devices, particularly a Mi motion sensor.\"\n  },\n  \"3.0.1\": {\n    \"en\": \"Added support for Aqara motion sensor.\"\n  },\n  \"3.0.2\": {\n    \"en\": \"Added support for Mi/Aqara magnet sensor.\"\n  },\n  \"3.0.3\": {\n    \"en\": \"Added support for Mi/Aqara temperature and humidity sensor and buttons.\"\n  },\n  \"3.0.4\": {\n    \"en\": \"Added support for Mi/Aqara cube, plug, wall switch no neutral single/double button.\"\n  },\n  \"3.0.5\": {\n    \"en\": \"Added support for Aqara wall switch with neutral single/double button, wirelles wall single/double switches.\"\n  },\n  \"3.0.6\": {\n    \"en\": \"Added support for Aqara water leak sensor, Aqara D1 single/double wall switches.\"\n  },\n  \"3.0.7\": {\n    \"en\": \"fix Aqara switches actions.\"\n  },\n  \"3.0.8\": {\n    \"en\": \"Added support for Aqara curtains.\"\n  },\n  \"3.0.9\": {\n    \"en\": \"No functional changes. Updated the app manifest to reflect a new developer and the possibility for future development and a possible upgrade to SDK3. See the forum support topic for further details.\"\n  },\n  \"3.1.0\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.1\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.2\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.3\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.4\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.5\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.6\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.7\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.8\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.9\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.10\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.11\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.12\": {\n    \"en\": \"This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten with SDK3 to make it futureproof. This new version also merged the devices from the community app Mi Homey. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.13\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.14\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.15\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.16\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.17\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.18\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.19\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.20\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.21\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.22\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.23\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.24\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.25\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.26\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.1.27\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.2.0\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.2.1\": {\n    \"en\": \"Development has been transferred to a new developer. This release is a complete rewrite of the app including many breaking changes. The app has been fully rewritten using SDK3 and has been tested with Homey Pro 2023 to make it futureproof. This new version also merged the devices from the Mi Homey community app. Some previously paired devices might continu to work but please re-pair your devices and/or fix your flows before reporting any issue. If the issue persists after re-pair please report it on the community forum or Github.\"\n  },\n  \"3.2.2\": {\n    \"en\": \"This release adds support for mijia.vacuum.v1 and mijia.vacuum.v2 (Mija Vacuum G1). It also attempts to add support for various Air Fryers  and  various Xiaomi Smart Pet Fountains (see supported devices). And it fixes a bug with humidity percentage calculation for deerma.humidifier.jsq5.\"\n  },\n  \"3.2.3\": {\n    \"en\": \"This release adds support for mijia.vacuum.v1 and mijia.vacuum.v2 (Mija Vacuum G1) and various Xiaomi Smart Pet Fountains (see supported devices). It also attempts to add support for various Air Fryers.\"\n  },\n  \"3.2.4\": {\n    \"en\": \"This release adds support for various Roidmi Eve/Eva vacuum cleaners.\"\n  },\n  \"3.2.5\": {\n    \"en\": \"This release adds support for various Roidmi Eve/Eva vacuum cleaners.\"\n  },\n  \"3.2.6\": {\n    \"en\": \"This release adds support for various Roidmi Eve/Eva vacuum cleaners. I|t also replaces the swing angle capability based on a dim level slider to a custom dropdown capability for the advanced Dmaker fan driver and added a flow action card for it as well.\"\n  },\n  \"3.2.7\": {\n    \"en\": \"This release adds support for various Roidmi Eve/Eva vacuum cleaners. It also replaces the swing angle capability based on a dim level slider to a custom dropdown capability for the advanced Dmaker fan driver and added flow action card for enabling it and setting the angle.\"\n  },\n  \"3.2.8\": {\n    \"en\": \"This release fixes the following issues. Setting the fanspeed on some Roborock vacuum cleaners using the advanced driver. Setting the vacuumcleaner state for Dreame Vacuum Cleaners. And setting the fanspeed on certain Zhimi fans.\"\n  },\n  \"3.2.9\": {\n    \"en\": \"This release adds support for for Dreame Bot W10 Pro under the Advanced Dreame Vacuum Cleaner MIoT driver and it fixes an issue with the swing angle capability of the advanced Dmaker fan driver and an issue with the action card for setting the vacuumspeed on the Advanced Roborock driver.\"\n  },\n  \"3.2.10\": {\n    \"en\": \"This release adds support for Roborock Vacuum S8 (roborock.vacuum.a51) and Mi Fresh Air Ventilator C1-80 (zhimi.airfresh.ua1). It fixes an issue with Dmaker fan model dmaker.fan.1c as it not supports setting the angle and also fixes an issue with Dreame Bot vacuum cleaners when in a specific state that is not support by the app resulting in the device not being available.\"\n  },\n  \"3.2.11\": {\n    \"en\": \"This release adds support for various Smartmi Smart Fan Heater models. It also fixes these issues. Another fix for Dmaker fan model dmaker.fan.1c as it not supports setting the angle. Another fix for setting fan speed on Zhimi fans using the advanced driver. Fix small issue with Rodmi vacuumcleaner that are in a specific and unrecognised state.\"\n  },\n  \"3.2.12\": {\n    \"en\": \"This release adds support for the Roborock S8 Ultra Pro (roborock.vacuum.a70). It also fixes an issue with with Smartmi Heater Fan (zhimi.heater.nb1), the Rodmi vacuumcleaner MIoT driver and some weird issue with the Gateway WiFi driver. And there is a fix for Mi Cleargrass Air (cgllc.airmonitor.s1) on firmware 4.x. This removes the measure_battery and alarm_battery capability as it's not reported anymore.\"\n  },\n  \"3.2.13\": {\n    \"en\": \"This release adds support for oscillation and heatlevel for Smartmi Smart Fan (zhimi.heater.nb1). It also adds an experimental action card for setting mop/vacuum mode and intensity for Roborock vacuumcleaners with mop capability. And it fixes setting docking / charging vacuumcleaner state for Roidmi Vacuum MioT driver and an issue with Mi Cleargrass Air Monitor (cgllc.airmonitor.s1).\"\n  },\n  \"3.2.14\": {\n    \"en\": \"This release adds an action card for setting the target temperature on a Smartmi Heater that supports it. It also fixes the issue for the oscillation action card for Smartmi Smart Fan (zhimi.heater.nb1) and the issue for sweep/mop action card for Roborock vacuumcleaners that have mop capability.\"\n  },\n  \"3.2.15\": {\n    \"en\": \"This release adds support for the Xiaomi Smart Air Purifier Elite, various Mi Robot Vacuum-Mop models (ijai.vacuum.*) and various Xiaomi Robot Vacuum models (xiaomi.vacuum.*).  It also contains a possible fix for room cleaning for Dreame vacuum cleaners.\"\n  },\n  \"3.2.16\": {\n    \"en\": \"This release adds support for the Roborock Vacuum Q8 Max (roborock.vacuum.a73). It also adds mop mode for Xiaomi vacuum models (xiaomi.vacuum.*) that support it. And it fixes a introduced bug in the vacuum room cleaning card for Roborock vacuum cleaners.\"\n  },\n  \"3.2.17\": {\n    \"en\": \"This release adds support for Roborock Q5 Pro (roborock.vacuum.a72) and it adds experimental and basic support for Xiaomi Smart Pet Food Feeder (mmgg.feeder.*). It also fixes a bug with on/off for certain Xiaomi Air Purifier models.\"\n  },\n  \"3.2.18\": {\n    \"en\": \"This release adds support for Smartmi Smart Convector Heater 1S (zhimi.heater.zb1a). It also saves the room ID’s of some Dreame vacuum models to be used in the room cleaning card. And there is a small fix for setting the mode on Xiaomi Smart Purifier Elite (zhimi.airp.meb1) in there.\"\n  },\n  \"3.2.19\": {\n    \"en\": \"This release adds for some Humidifier v2 models (zhimi.humidifier.cb1 & cb2), Mijia Mistless Humidifier 3 Pro (xiaomi.humidifier.airmx) and the Dreame D10 Plus (dreame.vacuum.r2205). It also adds an action card for enabling/disabling the LED light on certain models that support it. And it contains a possible fix for toggling the power on some Smartmi Humidifiers v1/v2 and crashes on the Airfryer driver.\"\n  },\n  \"3.2.20\": {\n    \"en\": \"This release attempts to fix the Advanced Dreame Vacuum Cleaner driver which is giving errors in certain scenarios. It also adds support for Roborock S7 Max Ultra (roborock.vacuum.a65), adds a pause cleaning session action card to Advanced Roborock driver and adds a enable notification sound action card to some models that support it and expanded support for the enable LED action card to more models.\"\n  },\n  \"3.2.21\": {\n    \"en\": \"This release adds support for the DreameBot L10s Ultra (dreame.vacuum.r2228o) and Xiaomi/Dreame Robot Vacuum X10 (dreame.vacuum.r2209) and for a a new model Mi Smart Plug (chuangmi.plug.hmi206). With this release the pause state of Roborock vacuum cleaners is now mapped to the \\\"stopped\\\" state in Homey instead of the the \\\"cleaning\\\" state. This makes sense for using it as condition. And it contains possible fixes for the LED light and notification sound toggle action card for some models like the Smart Mi Antibacterial Humidifier JSQ5 and a possible fix the room cleaning action card for Dreame vacuum cleaners.\"\n  },\n  \"3.2.22\": {\n    \"en\": \"This release add a themostat UI component for target temperature on the Smart Space/Fan Heater MIoT driver. It also adds a new action card for the Roborock advanced driver that allows room cleaning including setting the number of repeats. And it adds support for for Xiaomi Smart Air Purifier 4 Compact (xiaomi.airp.cpa4), the Xiaomi/Dreame Robot Vacuum X10+ (dreame.vacuum.p2114a) and the Xiaomi Smart Air Fryer 6.5L (careli.fryer.maf10a).\"\n  },\n  \"3.2.23\": {\n    \"en\": \"This release tries to add support for the Xiaomi Lightstrip Pro (philips.light.strip5), Xiaomi Smart Plug v2 EU (cuco.plug.v2eur) and Xiaomi/Dreame Robot Vacuum S10+ (dreame.vacuum.r2211o).\"\n  },\n  \"3.2.24\": {\n    \"en\": \"This release adds support for Xiaomi Smart Pet Food Feeder 2 (xiaomi.feeder.pi2001) and Dreame L10s Prime (dreame.vacuum.r2232c). And it fixes a bug for the Xiaomi Smart Air Purifier 4 Compact (xiaomi.airp.cpa4).\"\n  },\n  \"3.2.25\": {\n    \"en\": \"This release includes a fix for Mijia Smart Pet Food Feeder 2 (xiaomi.feeder.pi2001), tries to add support for Dreame L10s Pro Ultra (dreame.vacuum.r2338a) and updates device classes for airpurifiers, airfryers, humidifiers and petfeeders. It also adds localisation for other supported languages within Homey.\"\n  },\n  \"3.2.26\": {\n    \"en\": \"This release adds support for Mi Smart Evaporative Cooling Fan (dmaker.fan.p44) and allows to set the number of servings in the Pet Feeder serve food action card.\"\n  },\n  \"3.2.27\": {\n    \"en\": \"This release fixes the Mi Smart Evaporative Cooling Fan (dmaker.fan.p44) going offline and fixes the Pet Feeder serve food action card.\"\n  },\n  \"3.2.28\": {\n    \"en\": \"This release fixes the Mi Smart Evaporative Cooling Fan (dmaker.fan.p44) going offline and fixes the Pet Feeder serve food action card.\"\n  },\n  \"3.2.29\": {\n    \"en\": \"This release adds support for Mijia Smart Clothes Drying Rack (hyd.airer.znlyj4) and includes possible fixes for the Pet Feeder serve food action card, incorrect temperature and LED setting for zhimi.airfresh.va2 and the controls of the Xiaomi Smart Evaporative Cooling Fan (dmaker.fan.p44).\"\n  },\n  \"3.2.30\": {\n    \"en\": \"This release adds support for Mijia Smart Clothes Drying Rack (hyd.airer.znlyj4) and includes possible fixes for the Pet Feeder serve food action card, incorrect temperature and LED setting for zhimi.airfresh.va2 and the controls of the Xiaomi Smart Evaporative Cooling Fan (dmaker.fan.p44).\"\n  },\n  \"3.2.31\": {\n    \"en\": \"This release adds support for Smartmi Humidifier Rainforest (zhimi.humidifier.jd1) and Xiaomi Smart Tower Fan (dmaker.fan.p39). It reverts recent changes to the petfeeder servings flowcard as they do not work. And includes fixes for controlling the Mijia Smart Clothes Drying Rack (hyd.airer.znlyj4) and setting the mode on certain Dreame vacuum cleaners (mode names will be incorrect but it wont generate errors).\"\n  },\n  \"3.3.0\": {\n    \"en\": \"Breaking change: subcapabilities have been replaced by new capabilities available since Homey firmware 12.2.0. In some cases this might break your flows. You will have to update them with the new flow cards. This release also contains a fix for setting the fanlevel through a flowcard for the Advanced Mi Air Purifier MIoT driver and a fix for the Xiaomi Smart Tower Fan (dmaker.fan.p39).\"\n  },\n  \"3.4.0\": {\n    \"en\": \"Fan level fix for Xiaomi Mi Air Purifier Pro, Added support for Xiaomi Robot Vacuum X20+ and Xiaomi Smart Dehumidifier - all credits goes to https://www.paypal.me/jghaanstra\"\n  },\n  \"3.4.1\": {\n    \"en\": \"Fan level fix for Xiaomi Mi Air Purifier Pro, Added support for Xiaomi Robot Vacuum X20+ and Xiaomi Smart Dehumidifier - all credits goes to https://www.paypal.me/jghaanstra\"\n  },\n  \"3.4.2\": {\n    \"en\": \"Fan level fix for Xiaomi Mi Air Purifier Pro, Added support for Xiaomi Robot Vacuum X20+ and Xiaomi Smart Dehumidifier - all credits goes to [Phuturist](https://www.paypal.me/jghaanstra)\"\n  },\n  \"3.4.3\": {\n    \"en\": \"Fixes for used NodeJS modules\"\n  },\n  \"3.4.4\": {\n    \"en\": \"Temporary debug for Mi ClearGrass Air Detector\"\n  },\n  \"3.4.5\": {\n    \"en\": \"Attempt to fix modes for X20+\"\n  },\n  \"3.4.6\": {\n    \"en\": \"Attempt to fix modes for X20+\"\n  },\n  \"3.4.7\": {\n    \"en\": \"Mi ClearGrass Air Detector related improvements\"\n  },\n  \"3.4.8\": {\n    \"en\": \"Additional logging for X20+\"\n  },\n  \"3.4.9\": {\n    \"en\": \"Additional logging for Mi ClearGrass Air Detector, fixes for X20+ (mopmodes still not working as desired)\"\n  },\n  \"3.4.10\": {\n    \"en\": \"Mi ClearGrass Air Detector fixes\"\n  },\n  \"3.4.11\": {\n    \"en\": \"X20+ mop mode fixes\"\n  },\n  \"3.4.12\": {\n    \"en\": \"Added support for Mi Smart Pet Feeder 2 CN\"\n  },\n  \"3.4.13\": {\n    \"en\": \"Fix for Mi Smart Antibacterial Humidifier JSQ2W - the tank is empty\"\n  },\n  \"3.4.14\": {\n    \"en\": \"Additional logging for Use Smart Pet Food Feeder MIoT driver\"\n  },\n  \"3.4.15\": {\n    \"en\": \"Removing battery level capability for xiaomi.feeder.iv2001\"\n  },\n  \"3.4.16\": {\n    \"en\": \"Flow card trigger for petfeeder_mmgg_miot\"\n  },\n  \"3.4.17\": {\n    \"en\": \"Added support for Xiaomi Smart Tower Fan 2 (xiaomi.fan.p45)\"\n  },\n  \"3.4.18\": {\n    \"en\": \"Xiaomi Robot Vacuum X20 Pro and Xiaomi Robot Vacuum X20 Max\"\n  },\n  \"3.4.19\": {\n    \"en\": \"Added room cleaning options for Xiaomi Robot Vacuum X20, credits to @te85va\"\n  },\n  \"3.4.20\": {\n    \"en\": \"Logging optimisations for vacuum_xiaomi_vacuum_max driver\"\n  },\n  \"3.4.21\": {\n    \"en\": \"Translations\"\n  },\n  \"3.4.22\": {\n    \"en\": \"Added xiaomi.pet_waterer.iv02' / Xiaomi Smart Pet Fountain 2\"\n  },\n  \"3.4.23\": {\n    \"en\": \"Updates for the xiaomi.pet_waterer.iv02\"\n  },\n  \"3.4.24\": {\n    \"en\": \"Updates for the xiaomi.pet_waterer.iv02\"\n  },\n  \"3.4.25\": {\n    \"en\": \"MiiO library - discovery update / prevents crash\"\n  },\n  \"3.4.26\": {\n    \"en\": \"Xiaomi Robot Vacuum X20 - carpet avoidance for selective room cleaning, selective rooms cleaning respect order of room entered, adjustments for totals, attempt to add water empty alarm\"\n  },\n  \"3.4.27\": {\n    \"en\": \"Added new error code for Xiaomi Robot Vacuum X20\"\n  },\n  \"3.4.28\": {\n    \"en\": \"Added action cards for Xiaomi Smart Tower Fan 2 - rotate left/right\"\n  },\n  \"3.4.29\": {\n    \"en\": \"Fix for Mi Smart Standing Fan 2 Pro - rotate left/right\"\n  },\n  \"3.4.30\": {\n    \"en\": \"Fix for Mi Smart Standing Fan 2 Pro - rotate left/right\"\n  },\n  \"3.4.31\": {\n    \"en\": \"Fix for Mi Smart Standing Fan 2 Pro - rotate left/right\"\n  },\n  \"3.4.32\": {\n    \"en\": \"Enhancements for Xiaomi Robot Vacuum X20+\"\n  },\n  \"3.4.33\": {\n    \"en\": \"Enhancements for Xiaomi Robot Vacuum X20+\"\n  },\n  \"3.4.34\": {\n    \"en\": \"Xiaomi Feeder 2 improvements\"\n  },\n  \"3.4.35\": {\n    \"en\": \"Xiaomi Feeder 2 improvements\"\n  },\n  \"3.4.36\": {\n    \"en\": \"Xiaomi Feeder 2 improvements\"\n  },\n  \"3.4.37\": {\n    \"en\": \"Enhancements for Xiaomi Robot Vacuum X20+\"\n  },\n  \"3.4.38\": {\n    \"en\": \"Enhancements for Xiaomi Robot Vacuum X20+\"\n  },\n  \"3.4.39\": {\n    \"en\": \"Enhancements for Xiaomi Robot Vacuum X20+\"\n  },\n  \"3.4.40\": {\n    \"en\": \"Enhancements for Xiaomi Robot Vacuum X20+\"\n  },\n  \"3.4.41\": {\n    \"en\": \"Xiaomi Feeder 2 improvements\"\n  },\n  \"3.4.42\": {\n    \"en\": \"Xiaomi Feeder 2 improvements\"\n  },\n  \"3.4.43\": {\n    \"en\": \"Xiaomi Feeder 2 improvements\"\n  },\n  \"3.4.44\": {\n    \"en\": \"Xiaomi X20 / X20+ (c102gl), petfeeder_mmgg_miot and humidifier_deerma_humidifier_miot specific fixes\"\n  },\n  \"3.4.45\": {\n    \"en\": \"Petfeeder - work in progress, Xiaomi Vacuum Miot Max adjustments \"\n  },\n  \"3.4.46\": {\n    \"en\": \"Added remote.b1acn0 -  Chinese model of Aqara mini switch - credits MCFurry\"\n  },\n  \"3.4.47\": {\n    \"en\": \"X20Pro / xiaomi.vacuum.d102gl water level checks adjustments\"\n  },\n  \"3.4.48\": {\n    \"en\": \"X20Pro / xiaomi.vacuum.d102gl water level checks adjustments\"\n  },\n  \"3.4.49\": {\n    \"en\": \"Minor vacuum_xiaomi_vacuum_max related fixes in case of device unavailability\"\n  },\n  \"3.4.50\": {\n    \"en\": \"Fix pet_waterer_xiaomi ON/OFF status reporting.\"\n  },\n  \"3.4.51\": {\n    \"en\": \"Add support for Xiaomi Robot Vacuum S20+ (xiaomi.vacuum.b108gl)\"\n  },\n  \"3.4.52\": {\n    \"en\": \"Add support for Xiaomi Robot Vacuum S20+ (xiaomi.vacuum.b108gl)\"\n  },\n  \"3.4.53\": {\n    \"en\": \"Handled UDP unreachable errors in network.js as retries instead of crashes.\"\n  },\n  \"3.4.54\": {\n    \"en\": \"Support for Xiaomi Robot Vacuum H40 (*experimental) / Xiaomi Vacuum Cleaner MIoT MAX (WiFi) driver\"\n  },\n  \"3.4.55\": {\n    \"en\": \"Very experimental support for Mijia Smart Scent Diffuser (diffuser_xwhzp_diffuser_xwxfj) /  new driver Mijia Smart Scent Diffuser (WiFi)\"\n  },\n  \"3.4.56\": {\n    \"en\": \"Very experimental support for Mijia Smart Scent Diffuser (diffuser_xwhzp_diffuser_xwxfj) /  new driver Mijia Smart Scent Diffuser (WiFi)\"\n  },\n  \"3.4.57\": {\n    \"en\": \"Support for xiaomi.vacuum.ov51gl (Xiaomi Robot Vacuum H40 (EU) ) (*experimental) / Xiaomi Vacuum Cleaner MIoT MAX (WiFi) driver\"\n  },\n  \"3.4.58\": {\n    \"en\": \"Fixed zhimi.airpurifier.v7 to expose only Auto, Night, and Favorite modes and to scale favorite fan speed as 16 steps over 0–100% instead of 0–1600%\"\n  },\n  \"3.4.59\": {\n    \"en\": \"Fixed zhimi.airpurifier.v7 initialization \"\n  },\n  \"3.4.60\": {\n    \"en\": \"Restricted zhimi.airpurifier.v7 flow-card mode choices to supported options only\"\n  },\n  \"3.4.61\": {\n    \"en\": \"Fixed the air purifier Mode has changed trigger\"\n  },\n  \"3.4.62\": {\n    \"en\": \"Fix for zhimi.airpurifier.v7\"\n  },\n  \"3.4.63\": {\n    \"en\": \"Xiaomi Smart Pet Fountain 2 / xiaomi.pet_waterer.iv02 battery info\"\n  },\n  \"3.4.64\": {\n    \"en\": \"Support for Smartmi Evaporative Humidifier 3 / zhimi.humidifier.ca6\"\n  },\n  \"3.4.65\": {\n    \"en\": \"Adjusted the zhimi.humidifier.ca6 water-level mapping\"\n  },\n  \"3.4.66\": {\n    \"en\": \"Adjusted the zhimi.humidifier.ca6 water-level mapping\"\n  },\n  \"3.4.67\": {\n    \"en\": \"Added support for xiaomi.humidifier.600ek (Mijia Smart Evaporative Humidifier Pro)\"\n  },\n  \"3.4.68\": {\n    \"en\": \"Fixed xiaomi.humidifier.600ek target humidity scaling, X20 Max water-shortage fix\"\n  },\n  \"3.4.69\": {\n    \"en\": \"Fixed Mijia Smart Evaporative Humidifier Pro target humidity Insights\"\n  },\n  \"3.4.70\": {\n    \"en\": \"Added support for Xiaomi Smart Dehumidifier Lite and Mijia Smart Dehumidifier 13L, including the water tank full alarm capability.\"\n  },\n  \"3.4.71\": {\n    \"en\": \"Added support for Yeelight Arwen Ceiling Light D (yeelink.light.ceil43), including main light and ambient light controls.\"\n  },\n  \"3.4.72\": {\n    \"en\": \" Improved color picker handling and added Day/Night/Color/Flow mode selection for Yeelight Arwen Ceiling Light D (yeelink.light.ceil43)\"\n  }\n}\n"
  },
  {
    "path": ".homeycompose/app.json",
    "content": "{\n  \"id\": \"com.xiaomi-miio\",\n  \"sdk\": 3,\n  \"brandColor\": \"#FF6801\",\n  \"name\": {\n    \"en\": \"Xiaomi Mi Home\",\n    \"nl\": \"Xiaomi Mi Home\",\n    \"da\": \"Xiaomi Mi Home\",\n    \"de\": \"Xiaomi Mi Home\",\n    \"es\": \"Xiaomi Mi Home\",\n    \"fr\": \"Xiaomi Mi Home\",\n    \"it\": \"Xiaomi Mi Home\",\n    \"no\": \"Xiaomi Mi Home\",\n    \"sv\": \"Xiaomi Mi Home\",\n    \"pl\": \"Xiaomi Mi Home\",\n    \"ru\": \"Xiaomi Mi Home\",\n    \"ko\": \"Xiaomi Mi Home\"\n  },\n  \"tags\": {\n    \"en\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"vacuumcleaner\",\n      \"robot\",\n      \"purifier\",\n      \"humidifier\",\n      \"philips\",\n      \"eyecare\",\n      \"powerplug\",\n      \"gateway\"\n    ],\n    \"nl\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi home\",\n      \"miio\",\n      \"stofzuiger\",\n      \"robot\",\n      \"luchtreiniger\",\n      \"luchtbevochtiger\",\n      \"philips\",\n      \"eyecare\",\n      \"powerplug\",\n      \"gateway\"\n    ],\n    \"da\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"støvsuger\",\n      \"robot\",\n      \"luftrenser\",\n      \"luftfugter\",\n      \"philips\",\n      \"eyecare\",\n      \"stikdåse\",\n      \"gateway\"\n    ],\n    \"de\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"Staubsauger\",\n      \"Roboter\",\n      \"Luftreiniger\",\n      \"Luftbefeuchter\",\n      \"Philips\",\n      \"eyecare\",\n      \"Steckdose\",\n      \"Gateway\"\n    ],\n    \"es\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"aspiradora\",\n      \"robot\",\n      \"purificador\",\n      \"humidificador\",\n      \"philips\",\n      \"eyecare\",\n      \"enchufe\",\n      \"portal\"\n    ],\n    \"fr\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"aspirateur\",\n      \"robot\",\n      \"purificateur\",\n      \"humidificateur\",\n      \"philips\",\n      \"eyecare\",\n      \"prise\",\n      \"passerelle\"\n    ],\n    \"it\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"aspirapolvere\",\n      \"robot\",\n      \"purificatore\",\n      \"umidificatore\",\n      \"philips\",\n      \"eyecare\",\n      \"presa\",\n      \"gateway\"\n    ],\n    \"no\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"støvsuger\",\n      \"robot\",\n      \"luftrenser\",\n      \"luftfukter\",\n      \"philips\",\n      \"eyecare\",\n      \"strømplugg\",\n      \"gateway\"\n    ],\n    \"sv\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"dammsugare\",\n      \"robot\",\n      \"luftrenare\",\n      \"luftfuktare\",\n      \"philips\",\n      \"eyecare\",\n      \"strömuttag\",\n      \"gateway\"\n    ],\n    \"pl\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"odkurzacz\",\n      \"robot\",\n      \"oczyszczacz\",\n      \"nawilżacz\",\n      \"philips\",\n      \"eyecare\",\n      \"gniazdko\",\n      \"bramka\"\n    ],\n    \"ru\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"пылесос\",\n      \"робот\",\n      \"очиститель\",\n      \"увлажнитель\",\n      \"philips\",\n      \"eyecare\",\n      \"разъем питания\",\n      \"шлюз\"\n    ],\n    \"ko\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"진공청소기\",\n      \"로봇\",\n      \"공기청정기\",\n      \"가습기\",\n      \"philips\",\n      \"eyecare\",\n      \"전원플러그\",\n      \"게이트웨이\"\n    ]\n  },\n  \"version\": \"3.4.72\",\n  \"compatibility\": \">=12.2.0\",\n  \"platforms\": [\n    \"local\"\n  ],\n  \"author\": {\n    \"name\": \"Bretislav Kubesa\"\n  },\n  \"contributing\": {\n    \"donate\": {\n      \"paypal\": {\n        \"username\": \"bkubesa\"\n      }\n    }\n  },\n  \"contributors\": {\n    \"developers\": [\n      {\n        \"name\": \"Maxmudjon\"\n      },\n      {\n        \"name\": \"Jelger Haanstra\"\n      }\n    ]\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/shaarkys/com.xiaomi-miio/issues\"\n  },\n  \"homeyCommunityTopicId\": 118,\n  \"source\": \"https://github.com/shaarkys/com.xiaomi-miio\",\n  \"homepage\": \"https://community.athom.com/t/118\",\n  \"support\": \"https://community.homey.app/t/app-pro-xiaomi-mi-home-app/118/1770?u=sharkys\",\n  \"images\": {\n    \"large\": \"./assets/images/large.jpg\",\n    \"small\": \"./assets/images/small.jpg\"\n  },\n  \"category\": \"appliances\",\n  \"description\": {\n    \"en\": \"Control Xiaomi Mi Home devices using Homey\",\n    \"nl\": \"Bedien Xiaomi Mi Home apparaten via Homey\",\n    \"da\": \"Styr Xiaomi Mi Home enheder med Homey\",\n    \"de\": \"Steuere Xiaomi Mi Home Geräte mit Homey\",\n    \"es\": \"Controla dispositivos Xiaomi Mi Home con Homey\",\n    \"fr\": \"Contrôlez les appareils Xiaomi Mi Home avec Homey\",\n    \"it\": \"Controlla i dispositivi Xiaomi Mi Home con Homey\",\n    \"no\": \"Kontroller Xiaomi Mi Home-enheter med Homey\",\n    \"sv\": \"Styr Xiaomi Mi Home-enheter med Homey\",\n    \"pl\": \"Steruj urządzeniami Xiaomi Mi Home za pomocą Homey\",\n    \"ru\": \"Управляйте устройствами Xiaomi Mi Home с Homey\",\n    \"ko\": \"Homey를 사용하여 Xiaomi Mi Home 장치를 제어하세요\"\n  },\n  \"dependencies\": {\n    \"net\": \"*\"\n  },\n  \"api\": {\n    \"generate\": {\n      \"method\": \"post\",\n      \"path\": \"/generate\",\n      \"public\": false\n    },\n    \"testConnection\": {\n      \"method\": \"post\",\n      \"path\": \"/testConnection\",\n      \"public\": false\n    },\n    \"getGateways\": {\n      \"method\": \"get\",\n      \"path\": \"/getGateways\",\n      \"public\": false\n    },\n    \"removeChildDevice\": {\n      \"method\": \"post\",\n      \"path\": \"/removeChildDevice\",\n      \"public\": false\n    }\n  }\n}"
  },
  {
    "path": ".homeycompose/capabilities/airfryer_careli_food_quantity.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Food Quantity\",\n    \"nl\": \"Voedselhoeveelheid\",\n    \"da\": \"Mad Kvantitet\",\n    \"de\": \"Lebensmittelmenge\",\n    \"es\": \"Cantidad de Comida\",\n    \"fr\": \"Quantité de Nourriture\",\n    \"it\": \"Quantità di Cibo\",\n    \"no\": \"Mat Mengde\",\n    \"sv\": \"Matmängd\",\n    \"pl\": \"Ilość Jedzenia\",\n    \"ru\": \"Количество Еды\",\n    \"ko\": \"음식 양\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"None\",\n        \"nl\": \"Geen\",\n        \"da\": \"Ingen\",\n        \"de\": \"Kein\",\n        \"es\": \"Ninguna\",\n        \"fr\": \"Aucun\",\n        \"it\": \"Nessuno\",\n        \"no\": \"Ingen\",\n        \"sv\": \"Inget\",\n        \"pl\": \"Brak\",\n        \"ru\": \"Нет\",\n        \"ko\": \"없음\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Single\",\n        \"nl\": \"Enkel\",\n        \"da\": \"Enkelt\",\n        \"de\": \"Einzeln\",\n        \"es\": \"Único\",\n        \"fr\": \"Simple\",\n        \"it\": \"Singolo\",\n        \"no\": \"Enkelt\",\n        \"sv\": \"Enkel\",\n        \"pl\": \"Pojedynczy\",\n        \"ru\": \"Одинарный\",\n        \"ko\": \"단일\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Double\",\n        \"nl\": \"Dubbel\",\n        \"da\": \"Dobbelt\",\n        \"de\": \"Doppelt\",\n        \"es\": \"Doble\",\n        \"fr\": \"Double\",\n        \"it\": \"Doppio\",\n        \"no\": \"Dobbel\",\n        \"sv\": \"Dubbel\",\n        \"pl\": \"Podwójny\",\n        \"ru\": \"Двойной\",\n        \"ko\": \"더블\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Half\",\n        \"nl\": \"Half\",\n        \"da\": \"Halv\",\n        \"de\": \"Halb\",\n        \"es\": \"Medio\",\n        \"fr\": \"Moitié\",\n        \"it\": \"Metà\",\n        \"no\": \"Halv\",\n        \"sv\": \"Halv\",\n        \"pl\": \"Połowa\",\n        \"ru\": \"Половина\",\n        \"ko\": \"반\"\n      }\n    },\n    {\n      \"id\": \"4\",\n      \"title\": {\n        \"en\": \"Full\",\n        \"nl\": \"Vol\",\n        \"da\": \"Fuldt\",\n        \"de\": \"Voll\",\n        \"es\": \"Completo\",\n        \"fr\": \"Complet\",\n        \"it\": \"Pieno\",\n        \"no\": \"Full\",\n        \"sv\": \"Full\",\n        \"pl\": \"Pełny\",\n        \"ru\": \"Полный\",\n        \"ko\": \"가득\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/food-quantity.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/airfryer_careli_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Air Fryer Mode\",\n    \"nl\": \"Air Fryer Mode\",\n    \"da\": \"Airfryer-tilstand\",\n    \"de\": \"Airfryer Modus\",\n    \"es\": \"Modo Freidora de Aire\",\n    \"fr\": \"Mode Friteuse à Air\",\n    \"it\": \"Modalità Friggitrice ad Aria\",\n    \"no\": \"Luftfrityrmodus\",\n    \"sv\": \"Luftfritösläge\",\n    \"pl\": \"Tryb Frytownicy Powietrznej\",\n    \"ru\": \"Режим Аэрофритюрницы\",\n    \"ko\": \"에어프라이어 모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Shutdown\",\n        \"nl\": \"Uitgeschakeld\",\n        \"da\": \"Luk ned\",\n        \"de\": \"Abschalten\",\n        \"es\": \"Apagado\",\n        \"fr\": \"Arrêt\",\n        \"it\": \"Spegnimento\",\n        \"no\": \"Avslutte\",\n        \"sv\": \"Stänga av\",\n        \"pl\": \"Wyłączone\",\n        \"ru\": \"Выключение\",\n        \"ko\": \"종료\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Standby\",\n        \"nl\": \"Standby\",\n        \"da\": \"Stand-by\",\n        \"de\": \"Standby\",\n        \"es\": \"En Espera\",\n        \"fr\": \"Veille\",\n        \"it\": \"Standby\",\n        \"no\": \"Standby\",\n        \"sv\": \"Standby\",\n        \"pl\": \"Czekanie\",\n        \"ru\": \"Режим ожидания\",\n        \"ko\": \"대기 중\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Pause\",\n        \"nl\": \"Pauze\",\n        \"da\": \"Pause\",\n        \"de\": \"Pause\",\n        \"es\": \"Pausa\",\n        \"fr\": \"Pause\",\n        \"it\": \"Pausa\",\n        \"no\": \"Pause\",\n        \"sv\": \"Paus\",\n        \"pl\": \"Pauza\",\n        \"ru\": \"Пауза\",\n        \"ko\": \"일시 중지\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Schedule\",\n        \"nl\": \"Schema\",\n        \"da\": \"Planlægning\",\n        \"de\": \"Zeitplan\",\n        \"es\": \"Horario\",\n        \"fr\": \"Programme\",\n        \"it\": \"Programma\",\n        \"no\": \"Planlegge\",\n        \"sv\": \"Schema\",\n        \"pl\": \"Harmonogram\",\n        \"ru\": \"Расписание\",\n        \"ko\": \"일정\"\n      }\n    },\n    {\n      \"id\": \"4\",\n      \"title\": {\n        \"en\": \"Cooking\",\n        \"nl\": \"Bakken\",\n        \"da\": \"Madlavning\",\n        \"de\": \"Kochen\",\n        \"es\": \"Cocinando\",\n        \"fr\": \"Cuisson\",\n        \"it\": \"Cottura\",\n        \"no\": \"Matlaging\",\n        \"sv\": \"Matlagning\",\n        \"pl\": \"Gotowanie\",\n        \"ru\": \"Готовка\",\n        \"ko\": \"요리 중\"\n      }\n    },\n    {\n      \"id\": \"5\",\n      \"title\": {\n        \"en\": \"Preheat\",\n        \"nl\": \"Voorverwarmen\",\n        \"da\": \"Forvarm\",\n        \"de\": \"Vorheizen\",\n        \"es\": \"Precalentar\",\n        \"fr\": \"Préchauffage\",\n        \"it\": \"Preriscalda\",\n        \"no\": \"Forvarme\",\n        \"sv\": \"Förvärm\",\n        \"pl\": \"Rozgrzewanie\",\n        \"ru\": \"Предварительный нагрев\",\n        \"ko\": \"예열\"\n      }\n    },\n    {\n      \"id\": \"6\",\n      \"title\": {\n        \"en\": \"Cooked\",\n        \"nl\": \"Gebakken\",\n        \"da\": \"Tilberedt\",\n        \"de\": \"Gekocht\",\n        \"es\": \"Cocido\",\n        \"fr\": \"Cuit\",\n        \"it\": \"Cotto\",\n        \"no\": \"Kokt\",\n        \"sv\": \"Tillagad\",\n        \"pl\": \"Ugotowane\",\n        \"ru\": \"Приготовлено\",\n        \"ko\": \"조리 완료\"\n      }\n    },\n    {\n      \"id\": \"7\",\n      \"title\": {\n        \"en\": \"Preheat finished\",\n        \"nl\": \"Voorverwarmen klaar\",\n        \"da\": \"Forvarm færdig\",\n        \"de\": \"Vorheizen abgeschlossen\",\n        \"es\": \"Precalentamiento terminado\",\n        \"fr\": \"Préchauffage terminé\",\n        \"it\": \"Preriscaldamento finito\",\n        \"no\": \"Forvarming ferdig\",\n        \"sv\": \"Förvärmning klart\",\n        \"pl\": \"Rozgrzewanie zakończone\",\n        \"ru\": \"Предварительный нагрев завершен\",\n        \"ko\": \"예열 완료\"\n      }\n    },\n    {\n      \"id\": \"8\",\n      \"title\": {\n        \"en\": \"Preheat paused\",\n        \"nl\": \"Voorverwarmen gepauzeerd\",\n        \"da\": \"Forvarm sat på pause\",\n        \"de\": \"Vorheizen pausiert\",\n        \"es\": \"Precalentamiento en pausa\",\n        \"fr\": \"Préchauffage en pause\",\n        \"it\": \"Preriscaldamento in pausa\",\n        \"no\": \"Forvarming satt på pause\",\n        \"sv\": \"Förvärmning pausad\",\n        \"pl\": \"Rozgrzewanie wstrzymane\",\n        \"ru\": \"Предварительный нагрев приостановлен\",\n        \"ko\": \"예열 일시 중지\"\n      }\n    },\n    {\n      \"id\": \"9\",\n      \"title\": {\n        \"en\": \"Pause2\",\n        \"nl\": \"Pause2\",\n        \"da\": \"Pause2\",\n        \"de\": \"Pause2\",\n        \"es\": \"Pause2\",\n        \"fr\": \"Pause2\",\n        \"it\": \"Pause2\",\n        \"no\": \"Pause2\",\n        \"sv\": \"Pause2\",\n        \"pl\": \"Pause2\",\n        \"ru\": \"Pause2\",\n        \"ko\": \"Pause2\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": false,\n  \"icon\": \"/assets/icons/airfryer-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/airfryer_careli_target_temperature.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Target Temperature\",\n    \"nl\": \"Target Temperature\",\n    \"da\": \"Måltemperatur\",\n    \"de\": \"Zieltemperatur\",\n    \"es\": \"Temperatura Objetivo\",\n    \"fr\": \"Température Cible\",\n    \"it\": \"Temperatura Obiettivo\",\n    \"no\": \"Måltemperatur\",\n    \"sv\": \"Måltemperatur\",\n    \"pl\": \"Temperatura Docelowa\",\n    \"ru\": \"Целевая Температура\",\n    \"ko\": \"목표 온도\"\n  },\n  \"icon\": \"/assets/icons/target_temperature.svg\",\n  \"getable\": true,\n  \"setable\": true,\n  \"units\": {\n    \"en\": \"°C\",\n    \"nl\": \"°C\",\n    \"da\": \"°C\",\n    \"de\": \"°C\",\n    \"es\": \"°C\",\n    \"fr\": \"°C\",\n    \"it\": \"°C\",\n    \"no\": \"°C\",\n    \"sv\": \"°C\",\n    \"pl\": \"°C\",\n    \"ru\": \"°C\",\n    \"ko\": \"°C\"\n  },\n  \"min\": 40,\n  \"max\": 200,\n  \"decimals\": 0,\n  \"insights\": false\n}"
  },
  {
    "path": ".homeycompose/capabilities/airfryer_careli_target_time.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Target time\",\n    \"nl\": \"Target time\",\n    \"da\": \"Måletid\",\n    \"de\": \"Zielzeit\",\n    \"es\": \"Tiempo objetivo\",\n    \"fr\": \"Temps cible\",\n    \"it\": \"Tempo target\",\n    \"no\": \"Måletid\",\n    \"sv\": \"Måltid\",\n    \"pl\": \"Czas docelowy\",\n    \"ru\": \"Целевое время\",\n    \"ko\": \"목표 시간\"\n  },\n  \"icon\": \"/assets/icons/target_time.svg\",\n  \"getable\": true,\n  \"setable\": true,\n  \"units\": {\n    \"en\": \"minutes\",\n    \"nl\": \"minuten\",\n    \"da\": \"minutter\",\n    \"de\": \"Minuten\",\n    \"es\": \"minutos\",\n    \"fr\": \"minutes\",\n    \"it\": \"minuti\",\n    \"no\": \"minutter\",\n    \"sv\": \"minuter\",\n    \"pl\": \"minuty\",\n    \"ru\": \"минуты\",\n    \"ko\": \"분\"\n  },\n  \"min\": 0,\n  \"max\": 1440,\n  \"decimals\": 0,\n  \"insights\": false\n}"
  },
  {
    "path": ".homeycompose/capabilities/airpurifier_heater_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Air Purifier Heating Mode\",\n    \"nl\": \"Air Purifier verwarming modus\",\n    \"da\": \"Luftrenser opvarmningsfunktion\",\n    \"de\": \"Luftreiniger-Heizmodus\",\n    \"es\": \"Modo de calefacción del purificador de aire\",\n    \"fr\": \"Mode chauffage purificateur d'air\",\n    \"it\": \"Modalità riscaldamento purificatore d'aria\",\n    \"no\": \"Luftrenser oppvarmningsmodus\",\n    \"sv\": \"Luftrenare värmeläge\",\n    \"pl\": \"Tryb ogrzewania oczyszczacza powietrza\",\n    \"ru\": \"Режим обогрева воздухоочистителя\",\n    \"ko\": \"공기 청정기 난방 모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"off\",\n      \"title\": {\n        \"en\": \"Off\",\n        \"nl\": \"Uit\",\n        \"da\": \"Slukket\",\n        \"de\": \"Aus\",\n        \"es\": \"Apagado\",\n        \"fr\": \"Éteint\",\n        \"it\": \"Spento\",\n        \"no\": \"Av\",\n        \"sv\": \"Av\",\n        \"pl\": \"Wył.\",\n        \"ru\": \"Выкл.\",\n        \"ko\": \"끄기\"\n      }\n    },\n    {\n      \"id\": \"low\",\n      \"title\": {\n        \"en\": \"Low\",\n        \"nl\": \"Laag\",\n        \"da\": \"Lav\",\n        \"de\": \"Niedrig\",\n        \"es\": \"Bajo\",\n        \"fr\": \"Faible\",\n        \"it\": \"Basso\",\n        \"no\": \"Lav\",\n        \"sv\": \"Låg\",\n        \"pl\": \"Niski\",\n        \"ru\": \"Низкий\",\n        \"ko\": \"낮음\"\n      }\n    },\n    {\n      \"id\": \"medium\",\n      \"title\": {\n        \"en\": \"Medium\",\n        \"nl\": \"Medium\",\n        \"da\": \"Mellem\",\n        \"de\": \"Mittel\",\n        \"es\": \"Medio\",\n        \"fr\": \"Moyen\",\n        \"it\": \"Medio\",\n        \"no\": \"Middels\",\n        \"sv\": \"Mellan\",\n        \"pl\": \"Średni\",\n        \"ru\": \"Средний\",\n        \"ko\": \"중간\"\n      }\n    },\n    {\n      \"id\": \"high\",\n      \"title\": {\n        \"en\": \"High\",\n        \"nl\": \"Hoog\",\n        \"da\": \"Høj\",\n        \"de\": \"Hoch\",\n        \"es\": \"Alto\",\n        \"fr\": \"Élevé\",\n        \"it\": \"Alto\",\n        \"no\": \"Høy\",\n        \"sv\": \"Hög\",\n        \"pl\": \"Wysoki\",\n        \"ru\": \"Высокий\",\n        \"ko\": \"높음\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/heater-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/airpurifier_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalità\",\n    \"no\": \"Modus\",\n    \"sv\": \"Läge\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\"\n  },\n  \"getable\": true,\n  \"setable\": true,\n  \"values\": [\n    {\n      \"id\": \"auto\",\n      \"title\": {\n        \"en\": \"Auto\",\n        \"nl\": \"Auto\",\n        \"da\": \"Auto\",\n        \"de\": \"Auto\",\n        \"es\": \"Automático\",\n        \"fr\": \"Auto\",\n        \"it\": \"Automatico\",\n        \"no\": \"Auto\",\n        \"sv\": \"Auto\",\n        \"pl\": \"Auto\",\n        \"ru\": \"Авто\",\n        \"ko\": \"자동\"\n      }\n    },\n    {\n      \"id\": \"silent\",\n      \"title\": {\n        \"en\": \"Silent\",\n        \"nl\": \"Stil\",\n        \"da\": \"Stille\",\n        \"de\": \"Leise\",\n        \"es\": \"Silencioso\",\n        \"fr\": \"Silencieux\",\n        \"it\": \"Silenzioso\",\n        \"no\": \"Stille\",\n        \"sv\": \"Tyst\",\n        \"pl\": \"Cichy\",\n        \"ru\": \"Тихий\",\n        \"ko\": \"무음\"\n      }\n    },\n    {\n      \"id\": \"favorite\",\n      \"title\": {\n        \"en\": \"Favorite\",\n        \"nl\": \"Favoriet\",\n        \"da\": \"Favorit\",\n        \"de\": \"Favorit\",\n        \"es\": \"Favorito\",\n        \"fr\": \"Favori\",\n        \"it\": \"Preferito\",\n        \"no\": \"Favoritt\",\n        \"sv\": \"Favorit\",\n        \"pl\": \"Ulubiony\",\n        \"ru\": \"Любимый\",\n        \"ko\": \"즐겨찾기\"\n      }\n    },\n    {\n      \"id\": \"idle\",\n      \"title\": {\n        \"en\": \"Idle\",\n        \"nl\": \"Standby\",\n        \"da\": \"Inaktiv\",\n        \"de\": \"Leerlauf\",\n        \"es\": \"Inactivo\",\n        \"fr\": \"Inactif\",\n        \"it\": \"Inattivo\",\n        \"no\": \"Inaktiv\",\n        \"sv\": \"Inaktiv\",\n        \"pl\": \"Bezczynność\",\n        \"ru\": \"Ожидание\",\n        \"ko\": \"유휴\"\n      }\n    },\n    {\n      \"id\": \"low\",\n      \"title\": {\n        \"en\": \"Low\",\n        \"nl\": \"Laag\",\n        \"da\": \"Lav\",\n        \"de\": \"Niedrig\",\n        \"es\": \"Bajo\",\n        \"fr\": \"Bas\",\n        \"it\": \"Basso\",\n        \"no\": \"Lav\",\n        \"sv\": \"Låg\",\n        \"pl\": \"Niski\",\n        \"ru\": \"Низкий\",\n        \"ko\": \"낮은\"\n      }\n    },\n    {\n      \"id\": \"medium\",\n      \"title\": {\n        \"en\": \"Medium\",\n        \"nl\": \"Medium\",\n        \"da\": \"Medium\",\n        \"de\": \"Mittel\",\n        \"es\": \"Medio\",\n        \"fr\": \"Moyen\",\n        \"it\": \"Medio\",\n        \"no\": \"Middels\",\n        \"sv\": \"Medium\",\n        \"pl\": \"Średni\",\n        \"ru\": \"Средний\",\n        \"ko\": \"중간\"\n      }\n    },\n    {\n      \"id\": \"high\",\n      \"title\": {\n        \"en\": \"High\",\n        \"nl\": \"Hoog\",\n        \"da\": \"Høj\",\n        \"de\": \"Hoch\",\n        \"es\": \"Alto\",\n        \"fr\": \"Haut\",\n        \"it\": \"Alto\",\n        \"no\": \"Høy\",\n        \"sv\": \"Hög\",\n        \"pl\": \"Wysoki\",\n        \"ru\": \"Высокий\",\n        \"ko\": \"높은\"\n      }\n    },\n    {\n      \"id\": \"strong\",\n      \"title\": {\n        \"en\": \"Strong\",\n        \"nl\": \"Sterk\",\n        \"da\": \"Stærk\",\n        \"de\": \"Stark\",\n        \"es\": \"Fuerte\",\n        \"fr\": \"Fort\",\n        \"it\": \"Forte\",\n        \"no\": \"Sterk\",\n        \"sv\": \"Stark\",\n        \"pl\": \"Silny\",\n        \"ru\": \"Сильный\",\n        \"ko\": \"강한\"\n      }\n    }\n  ],\n  \"icon\": \"/assets/icons/airpurifier-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/airpurifier_xiaomi_fanlevel.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Fan Level\",\n    \"nl\": \"Fan Level\",\n    \"da\": \"Ventilatorniveau\",\n    \"de\": \"Lüfterstufe\",\n    \"es\": \"Nivel del ventilador\",\n    \"fr\": \"Niveau du ventilateur\",\n    \"it\": \"Livello della ventola\",\n    \"no\": \"Viftenivå\",\n    \"sv\": \"Fläktnivå\",\n    \"pl\": \"Poziom wentylatora\",\n    \"ru\": \"Уровень вентилятора\",\n    \"ko\": \"팬 레벨\"\n  },\n  \"getable\": true,\n  \"setable\": true,\n  \"min\": 0,\n  \"max\": 14,\n  \"step\": 1,\n  \"icon\": \"/assets/icons/fanlevel.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/airpurifier_zhimi_airfresh_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Air Fresh Mode\",\n    \"nl\": \"Air Fresh Mode\",\n    \"da\": \"Luftfriskningstilstand\",\n    \"de\": \"Luftfrisch-Modus\",\n    \"es\": \"Modo Aire Fresco\",\n    \"fr\": \"Mode Air Fresh\",\n    \"it\": \"Modalità Aria Fresca\",\n    \"no\": \"Luftfriskmodus\",\n    \"sv\": \"Luftfräschläget\",\n    \"pl\": \"Tryb Odświeżania Powietrza\",\n    \"ru\": \"Режим Очистки Воздуха\",\n    \"ko\": \"에어 프레시 모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"auto\",\n      \"title\": {\n        \"en\": \"Auto\",\n        \"nl\": \"Auto\",\n        \"da\": \"Auto\",\n        \"de\": \"Automatisch\",\n        \"es\": \"Automático\",\n        \"fr\": \"Auto\",\n        \"it\": \"Auto\",\n        \"no\": \"Auto\",\n        \"sv\": \"Auto\",\n        \"pl\": \"Auto\",\n        \"ru\": \"Авто\",\n        \"ko\": \"자동\"\n      }\n    },\n    {\n      \"id\": \"silent\",\n      \"title\": {\n        \"en\": \"Silent\",\n        \"nl\": \"Stil\",\n        \"da\": \"Stille\",\n        \"de\": \"Leise\",\n        \"es\": \"Silencioso\",\n        \"fr\": \"Silencieux\",\n        \"it\": \"Silenzioso\",\n        \"no\": \"Stille\",\n        \"sv\": \"Tyst\",\n        \"pl\": \"Cichy\",\n        \"ru\": \"Тихий\",\n        \"ko\": \"무음\"\n      }\n    },\n    {\n      \"id\": \"interval\",\n      \"title\": {\n        \"en\": \"Interval\",\n        \"nl\": \"Interval\",\n        \"da\": \"Interval\",\n        \"de\": \"Intervall\",\n        \"es\": \"Intervalo\",\n        \"fr\": \"Intervalle\",\n        \"it\": \"Intervallo\",\n        \"no\": \"Intervall\",\n        \"sv\": \"Intervall\",\n        \"pl\": \"Interwał\",\n        \"ru\": \"Интервал\",\n        \"ko\": \"간격\"\n      }\n    },\n    {\n      \"id\": \"low\",\n      \"title\": {\n        \"en\": \"Low\",\n        \"nl\": \"Laag\",\n        \"da\": \"Lav\",\n        \"de\": \"Niedrig\",\n        \"es\": \"Bajo\",\n        \"fr\": \"Bas\",\n        \"it\": \"Basso\",\n        \"no\": \"Lav\",\n        \"sv\": \"Låg\",\n        \"pl\": \"Niski\",\n        \"ru\": \"Низкий\",\n        \"ko\": \"낮음\"\n      }\n    },\n    {\n      \"id\": \"middle\",\n      \"title\": {\n        \"en\": \"Medium\",\n        \"nl\": \"Medium\",\n        \"da\": \"Mellem\",\n        \"de\": \"Mittel\",\n        \"es\": \"Medio\",\n        \"fr\": \"Moyen\",\n        \"it\": \"Medio\",\n        \"no\": \"Middels\",\n        \"sv\": \"Medium\",\n        \"pl\": \"Średni\",\n        \"ru\": \"Средний\",\n        \"ko\": \"중간\"\n      }\n    },\n    {\n      \"id\": \"strong\",\n      \"title\": {\n        \"en\": \"High\",\n        \"nl\": \"Hoog\",\n        \"da\": \"Høj\",\n        \"de\": \"Hoch\",\n        \"es\": \"Alto\",\n        \"fr\": \"Haut\",\n        \"it\": \"Alto\",\n        \"no\": \"Høy\",\n        \"sv\": \"Hög\",\n        \"pl\": \"Wysoki\",\n        \"ru\": \"Высокий\",\n        \"ko\": \"높음\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/airpurifier-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/airpurifier_zhimi_airpurifier_mb3_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"de\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalità\",\n    \"no\": \"Modus\",\n    \"sv\": \"Läge\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\",\n    \"pt\": \"Modo\",\n    \"ja\": \"モード\",\n    \"zh\": \"模式\"\n  },\n  \"getable\": true,\n  \"setable\": true,\n  \"values\": [\n    {\n      \"id\": \"auto\",\n      \"title\": {\n        \"en\": \"Auto\",\n        \"nl\": \"Auto\",\n        \"de\": \"Auto\",\n        \"da\": \"Auto\",\n        \"es\": \"Auto\",\n        \"fr\": \"Auto\",\n        \"it\": \"Auto\",\n        \"no\": \"Auto\",\n        \"sv\": \"Auto\",\n        \"pl\": \"Auto\",\n        \"ru\": \"Авто\",\n        \"ko\": \"자동\",\n        \"pt\": \"Automático\",\n        \"ja\": \"オート\",\n        \"zh\": \"自动\"\n      }\n    },\n    {\n      \"id\": \"night\",\n      \"title\": {\n        \"en\": \"Night\",\n        \"nl\": \"Nacht\",\n        \"de\": \"Nacht\",\n        \"da\": \"Nat\",\n        \"es\": \"Noche\",\n        \"fr\": \"Nuit\",\n        \"it\": \"Notte\",\n        \"no\": \"Natt\",\n        \"sv\": \"Natt\",\n        \"pl\": \"Noc\",\n        \"ru\": \"Ночь\",\n        \"ko\": \"밤\",\n        \"pt\": \"Noite\",\n        \"ja\": \"夜\",\n        \"zh\": \"夜晚\"\n      }\n    },\n    {\n      \"id\": \"favorite\",\n      \"title\": {\n        \"en\": \"Favorite\",\n        \"nl\": \"Favoriet\",\n        \"de\": \"Favorit\",\n        \"da\": \"Favorit\",\n        \"es\": \"Favorito\",\n        \"fr\": \"Préféré\",\n        \"it\": \"Preferito\",\n        \"no\": \"Favoritt\",\n        \"sv\": \"Favorit\",\n        \"pl\": \"Ulubiony\",\n        \"ru\": \"Избранное\",\n        \"ko\": \"즐겨찾기\",\n        \"pt\": \"Favorito\",\n        \"ja\": \"お気に入り\",\n        \"zh\": \"最爱\"\n      }\n    },\n    {\n      \"id\": \"idle\",\n      \"title\": {\n        \"en\": \"Idle\",\n        \"nl\": \"Inactief\",\n        \"de\": \"Inaktiv\",\n        \"da\": \"Inaktiv\",\n        \"es\": \"Inactivo\",\n        \"fr\": \"Inactif\",\n        \"it\": \"Inattivo\",\n        \"no\": \"Inaktiv\",\n        \"sv\": \"Inaktiv\",\n        \"pl\": \"Bezczynny\",\n        \"ru\": \"Бездействие\",\n        \"ko\": \"대기 중\",\n        \"pt\": \"Inativo\",\n        \"ja\": \"アイドル\",\n        \"zh\": \"闲置\"\n      }\n    }\n  ],\n  \"icon\": \"/assets/icons/airpurifier-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/airpurifier_zhimi_fanlevel.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Fan Level\",\n    \"nl\": \"Fan Level\",\n    \"da\": \"Ventilatorniveau\",\n    \"de\": \"Lüfterstufe\",\n    \"es\": \"Nivel del ventilador\",\n    \"fr\": \"Niveau du ventilateur\",\n    \"it\": \"Livello della ventola\",\n    \"no\": \"Viftenivå\",\n    \"sv\": \"Fläktnivå\",\n    \"pl\": \"Poziom wentylatora\",\n    \"ru\": \"Уровень вентилятора\",\n    \"ko\": \"팬 레벨\"\n  },\n  \"getable\": true,\n  \"setable\": true,\n  \"values\": [\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Level 1\",\n        \"nl\": \"Level 1\",\n        \"da\": \"Niveau 1\",\n        \"de\": \"Stufe 1\",\n        \"es\": \"Nivel 1\",\n        \"fr\": \"Niveau 1\",\n        \"it\": \"Livello 1\",\n        \"no\": \"Nivå 1\",\n        \"sv\": \"Nivå 1\",\n        \"pl\": \"Poziom 1\",\n        \"ru\": \"Уровень 1\",\n        \"ko\": \"레벨 1\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Level 2\",\n        \"nl\": \"Level 2\",\n        \"da\": \"Niveau 2\",\n        \"de\": \"Stufe 2\",\n        \"es\": \"Nivel 2\",\n        \"fr\": \"Niveau 2\",\n        \"it\": \"Livello 2\",\n        \"no\": \"Nivå 2\",\n        \"sv\": \"Nivå 2\",\n        \"pl\": \"Poziom 2\",\n        \"ru\": \"Уровень 2\",\n        \"ko\": \"레벨 2\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Level 3\",\n        \"nl\": \"Level 3\",\n        \"da\": \"Niveau 3\",\n        \"de\": \"Stufe 3\",\n        \"es\": \"Nivel 3\",\n        \"fr\": \"Niveau 3\",\n        \"it\": \"Livello 3\",\n        \"no\": \"Nivå 3\",\n        \"sv\": \"Nivå 3\",\n        \"pl\": \"Poziom 3\",\n        \"ru\": \"Уровень 3\",\n        \"ko\": \"레벨 3\"\n      }\n    }\n  ],\n  \"icon\": \"/assets/icons/fanlevel.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/airpurifier_zhimi_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalità\",\n    \"no\": \"Modus\",\n    \"sv\": \"Läge\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\"\n  },\n  \"getable\": true,\n  \"setable\": true,\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Auto\",\n        \"nl\": \"Auto\",\n        \"da\": \"Auto\",\n        \"de\": \"Auto\",\n        \"es\": \"Auto\",\n        \"fr\": \"Auto\",\n        \"it\": \"Auto\",\n        \"no\": \"Auto\",\n        \"sv\": \"Auto\",\n        \"pl\": \"Auto\",\n        \"ru\": \"Авто\",\n        \"ko\": \"자동\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Night\",\n        \"nl\": \"Nacht\",\n        \"da\": \"Nat\",\n        \"de\": \"Nacht\",\n        \"es\": \"Noche\",\n        \"fr\": \"Nuit\",\n        \"it\": \"Notte\",\n        \"no\": \"Natt\",\n        \"sv\": \"Natt\",\n        \"pl\": \"Noc\",\n        \"ru\": \"Ночь\",\n        \"ko\": \"야간\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Favorite\",\n        \"nl\": \"Favoriet\",\n        \"da\": \"Favorit\",\n        \"de\": \"Favorit\",\n        \"es\": \"Favorito\",\n        \"fr\": \"Favori\",\n        \"it\": \"Preferito\",\n        \"no\": \"Favoritt\",\n        \"sv\": \"Favorit\",\n        \"pl\": \"Ulubiony\",\n        \"ru\": \"Избранное\",\n        \"ko\": \"선호\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Idle\",\n        \"nl\": \"Inactief\",\n        \"da\": \"Inaktiv\",\n        \"de\": \"Inaktiv\",\n        \"es\": \"Inactivo\",\n        \"fr\": \"Inactif\",\n        \"it\": \"Inattivo\",\n        \"no\": \"Inaktiv\",\n        \"sv\": \"Inaktiv\",\n        \"pl\": \"Bezczynny\",\n        \"ru\": \"Бездействие\",\n        \"ko\": \"대기\"\n      }\n    }\n  ],\n  \"icon\": \"/assets/icons/airpurifier-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/alarm_desiccant_low.json",
    "content": "{\n  \"type\": \"boolean\",\n  \"title\": { \"en\": \"Desiccant Low\" },\n  \"getable\": true,\n  \"setable\": false,\n  \"uiComponent\": \"sensor\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/alarm_filter_work_time.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Filter Alert\",\n    \"nl\": \"Filter waarschuwing\",\n    \"da\": \"Filteralarm\",\n    \"de\": \"Filteralarm\",\n    \"es\": \"Alerta de Filtro\",\n    \"fr\": \"Alerte Filtre\",\n    \"it\": \"Allarme Filtro\",\n    \"no\": \"Filtervarsling\",\n    \"sv\": \"Filtervarning\",\n    \"pl\": \"Alarm filtra\",\n    \"ru\": \"Сигнал фильтра\",\n    \"ko\": \"필터 알림\"\n  },\n  \"type\": \"boolean\",\n  \"getable\": true,\n  \"setable\": false,\n  \"icon\": \"/assets/icons/vacuum_hepa_filter.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/alarm_main_brush_work_time.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Main Brush Alert\",\n    \"nl\": \"Hoofdborstel waarschuwing\",\n    \"da\": \"Hovedbørstealarm\",\n    \"de\": \"Hauptbürstenalarm\",\n    \"es\": \"Alerta de cepillo principal\",\n    \"fr\": \"Alerte brosse principale\",\n    \"it\": \"Allarme spazzola principale\",\n    \"no\": \"Hovedbørstevarsel\",\n    \"sv\": \"Huvudborstevarning\",\n    \"pl\": \"Alarm głównej szczotki\",\n    \"ru\": \"Предупреждение о главной щетке\",\n    \"ko\": \"메인 브러쉬 경고\"\n  },\n  \"type\": \"boolean\",\n  \"getable\": true,\n  \"setable\": false,\n  \"icon\": \"/assets/icons/vacuum_main_brush.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/alarm_sensor_dirty_time.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Sensor Alert\",\n    \"nl\": \"Sensor waarschuwing\",\n    \"da\": \"Sensoralarm\",\n    \"de\": \"Sensoralarm\",\n    \"es\": \"Alerta de sensor\",\n    \"fr\": \"Alerte de capteur\",\n    \"it\": \"Allarme sensore\",\n    \"no\": \"Sensorvarsel\",\n    \"sv\": \"Sensorlarm\",\n    \"pl\": \"Alarm czujnika\",\n    \"ru\": \"Оповещение датчика\",\n    \"ko\": \"센서 경고\"\n  },\n  \"type\": \"boolean\",\n  \"getable\": true,\n  \"setable\": false,\n  \"icon\": \"/assets/icons/vacuum_sensor_dirty.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/alarm_side_brush_work_time.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Side Brush Alert\",\n    \"nl\": \"Zijborstel waarschuwing\",\n    \"da\": \"Sidebørste Advarsel\",\n    \"de\": \"Seitenbürstenalarm\",\n    \"es\": \"Alerta de Cepillo Lateral\",\n    \"fr\": \"Alerte de Brosse Latérale\",\n    \"it\": \"Allarme Spazzola Laterale\",\n    \"no\": \"Sidebørste Varsel\",\n    \"sv\": \"Sidoborste Varning\",\n    \"pl\": \"Ostrzeżenie o Szczotce Boczne\",\n    \"ru\": \"Предупреждение о Боковой Щетке\",\n    \"ko\": \"옆 브러시 알림\"\n  },\n  \"type\": \"boolean\",\n  \"getable\": true,\n  \"setable\": false,\n  \"icon\": \"/assets/icons/vacuum_side_brush.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/alarm_water_shortage.json",
    "content": "{\n  \"type\": \"boolean\",\n  \"title\": {\n    \"en\": \"Water Shortage Alarm\",\n    \"nl\": \"Watertekort Alarm\",\n    \"da\": \"Vandmangel Alarm\",\n    \"de\": \"Wassermangel Alarm\",\n    \"es\": \"Alarma de falta de agua\",\n    \"fr\": \"Alarme manque d'eau\",\n    \"it\": \"Allarme carenza acqua\",\n    \"no\": \"Vannmangel Alarm\",\n    \"sv\": \"Vattenbristlarm\",\n    \"pl\": \"Alarm braku wody\",\n    \"ru\": \"Сигнализация нехватки воды\",\n    \"ko\": \"물 부족 알림\"\n  },\n  \"desc\": {\n    \"en\": \"Indicates when there is a water shortage\"\n  },\n  \"getable\": true,\n  \"setable\": false,\n  \"icon\": \"/assets/icons/water-shortage.svg\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/dehumidifier_dmaker_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalità\",\n    \"no\": \"Modus\",\n    \"sv\": \"Läge\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Smart\",\n        \"nl\": \"Slim\",\n        \"da\": \"Smart\",\n        \"de\": \"Intelligent\",\n        \"es\": \"Inteligente\",\n        \"fr\": \"Intelligent\",\n        \"it\": \"Intelligente\",\n        \"no\": \"Smart\",\n        \"sv\": \"Smart\",\n        \"pl\": \"Inteligentny\",\n        \"ru\": \"Умный\",\n        \"ko\": \"스마트\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Sleep\",\n        \"nl\": \"Slaap\",\n        \"da\": \"Søvn\",\n        \"de\": \"Schlaf\",\n        \"es\": \"Dormir\",\n        \"fr\": \"Sommeil\",\n        \"it\": \"Sonno\",\n        \"no\": \"Søvn\",\n        \"sv\": \"Sömn\",\n        \"pl\": \"Sen\",\n        \"ru\": \"Сон\",\n        \"ko\": \"수면\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Clothes Drying\",\n        \"nl\": \"Kleding drogen\",\n        \"da\": \"Tørring af tøj\",\n        \"de\": \"Kleidung trocknen\",\n        \"es\": \"Secado de ropa\",\n        \"fr\": \"Séchage des vêtements\",\n        \"it\": \"Asciugatura dei vestiti\",\n        \"no\": \"Klær tørking\",\n        \"sv\": \"Klädtorkning\",\n        \"pl\": \"Suszenie ubrań\",\n        \"ru\": \"Сушка одежды\",\n        \"ko\": \"의류 건조\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/humidifier-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/diffuser_xwhzp_fragrance_out_time.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Fragrance Out Time\",\n    \"nl\": \"Geurafgifte tijd\",\n    \"da\": \"Duftudslipstid\",\n    \"de\": \"Duftabgabezeit\",\n    \"es\": \"Tiempo de salida de fragancia\",\n    \"fr\": \"Duree de diffusion\",\n    \"it\": \"Durata erogazione fragranza\",\n    \"no\": \"Duftutslippstid\",\n    \"sv\": \"Doftutslappstid\",\n    \"pl\": \"Czas emisji zapachu\",\n    \"ru\": \"Vremya vydeleniya aromata\",\n    \"ko\": \"fragrance out time\"\n  },\n  \"icon\": \"/assets/icons/target_time.svg\",\n  \"getable\": true,\n  \"setable\": true,\n  \"uiComponent\": \"slider\",\n  \"units\": {\n    \"en\": \"s\",\n    \"nl\": \"s\",\n    \"da\": \"s\",\n    \"de\": \"s\",\n    \"es\": \"s\",\n    \"fr\": \"s\",\n    \"it\": \"s\",\n    \"no\": \"s\",\n    \"sv\": \"s\",\n    \"pl\": \"s\",\n    \"ru\": \"s\",\n    \"ko\": \"s\"\n  },\n  \"insights\": true\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/diffuser_xwhzp_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalita\",\n    \"no\": \"Modus\",\n    \"sv\": \"Lage\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Rezhim\",\n    \"ko\": \"mode\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": { \"en\": \"Sleep\" }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": { \"en\": \"Reading\" }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": { \"en\": \"Exercise\" }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": { \"en\": \"Wakeup\" }\n    },\n    {\n      \"id\": \"4\",\n      \"title\": { \"en\": \"Custom Mode 1\" }\n    },\n    {\n      \"id\": \"5\",\n      \"title\": { \"en\": \"Custom Mode 2\" }\n    },\n    {\n      \"id\": \"6\",\n      \"title\": { \"en\": \"Custom Mode 3\" }\n    },\n    {\n      \"id\": \"7\",\n      \"title\": { \"en\": \"Custom Mode 4\" }\n    },\n    {\n      \"id\": \"8\",\n      \"title\": { \"en\": \"Try It\" }\n    },\n    {\n      \"id\": \"9\",\n      \"title\": { \"en\": \"Idle Mode\" }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/humidifier-mode.svg\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/fan_dmaker_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalità\",\n    \"no\": \"Modus\",\n    \"sv\": \"Läge\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\",\n    \"ja\": \"モード\",\n    \"zh\": \"模式\",\n    \"pt\": \"Modo\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Straight Wind\",\n        \"nl\": \"Rechte wind\",\n        \"da\": \"Lige vind\",\n        \"de\": \"Gerader Wind\",\n        \"es\": \"Viento Recto\",\n        \"fr\": \"Vent Droit\",\n        \"it\": \"Vento Diretto\",\n        \"no\": \"Rett vind\",\n        \"sv\": \"Rak vind\",\n        \"pl\": \"Prosty wiatr\",\n        \"ru\": \"Прямой ветер\",\n        \"ko\": \"직진 바람\",\n        \"ja\": \"真っ直ぐな風\",\n        \"zh\": \"直风\",\n        \"pt\": \"Vento Reto\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Natural Wind\",\n        \"nl\": \"Natuurlijke Wind\",\n        \"da\": \"Naturlig vind\",\n        \"de\": \"Natürlicher Wind\",\n        \"es\": \"Viento Natural\",\n        \"fr\": \"Vent Naturel\",\n        \"it\": \"Vento Naturale\",\n        \"no\": \"Naturlig vind\",\n        \"sv\": \"Naturlig vind\",\n        \"pl\": \"Naturalny wiatr\",\n        \"ru\": \"Естественный ветер\",\n        \"ko\": \"자연 바람\",\n        \"ja\": \"自然な風\",\n        \"zh\": \"自然风\",\n        \"pt\": \"Vento Natural\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Sleep\",\n        \"nl\": \"Slaap\",\n        \"da\": \"Søvn\",\n        \"de\": \"Schlaf\",\n        \"es\": \"Dormir\",\n        \"fr\": \"Sommeil\",\n        \"it\": \"Sonno\",\n        \"no\": \"Søvn\",\n        \"sv\": \"Sömn\",\n        \"pl\": \"Sen\",\n        \"ru\": \"Сон\",\n        \"ko\": \"수면\",\n        \"ja\": \"睡眠\",\n        \"zh\": \"睡觉\",\n        \"pt\": \"Sono\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Cold Air\",\n        \"nl\": \"Koude Lucht\",\n        \"da\": \"Kold Luft\",\n        \"de\": \"Kalte Luft\",\n        \"es\": \"Aire Frío\",\n        \"fr\": \"Air Froid\",\n        \"it\": \"Aria Fredda\",\n        \"no\": \"Kald Luft\",\n        \"sv\": \"Kall Luft\",\n        \"pl\": \"Zimne Powietrze\",\n        \"ru\": \"Холодный воздух\",\n        \"ko\": \"찬 공기\",\n        \"ja\": \"冷たい空気\",\n        \"zh\": \"冷空气\",\n        \"pt\": \"Ar Frio\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/fanlevel.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/fan_zhimi_angle.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Swing Angle\",\n    \"nl\": \"Draaihoek\",\n    \"da\": \"Svingvinkel\",\n    \"de\": \"Schwenkwinkel\",\n    \"es\": \"Ángulo de giro\",\n    \"fr\": \"Angle de balancement\",\n    \"it\": \"Angolo di oscillazione\",\n    \"no\": \"Svingvinkel\",\n    \"sv\": \"Svängvinkel\",\n    \"pl\": \"Kąt huśtania\",\n    \"ru\": \"Угол поворота\",\n    \"ko\": \"스윙 각도\"\n  },\n  \"values\": [\n    {\n      \"id\": \"30\",\n      \"title\": {\n        \"en\": \"30°\",\n        \"nl\": \"30°\",\n        \"da\": \"30°\",\n        \"de\": \"30°\",\n        \"es\": \"30°\",\n        \"fr\": \"30°\",\n        \"it\": \"30°\",\n        \"no\": \"30°\",\n        \"sv\": \"30°\",\n        \"pl\": \"30°\",\n        \"ru\": \"30°\",\n        \"ko\": \"30°\"\n      }\n    },\n    {\n      \"id\": \"60\",\n      \"title\": {\n        \"en\": \"60°\",\n        \"nl\": \"60°\",\n        \"da\": \"60°\",\n        \"de\": \"60°\",\n        \"es\": \"60°\",\n        \"fr\": \"60°\",\n        \"it\": \"60°\",\n        \"no\": \"60°\",\n        \"sv\": \"60°\",\n        \"pl\": \"60°\",\n        \"ru\": \"60°\",\n        \"ko\": \"60°\"\n      }\n    },\n    {\n      \"id\": \"90\",\n      \"title\": {\n        \"en\": \"90°\",\n        \"nl\": \"90°\",\n        \"da\": \"90°\",\n        \"de\": \"90°\",\n        \"es\": \"90°\",\n        \"fr\": \"90°\",\n        \"it\": \"90°\",\n        \"no\": \"90°\",\n        \"sv\": \"90°\",\n        \"pl\": \"90°\",\n        \"ru\": \"90°\",\n        \"ko\": \"90°\"\n      }\n    },\n    {\n      \"id\": \"120\",\n      \"title\": {\n        \"en\": \"120°\",\n        \"nl\": \"120°\",\n        \"da\": \"120°\",\n        \"de\": \"120°\",\n        \"es\": \"120°\",\n        \"fr\": \"120°\",\n        \"it\": \"120°\",\n        \"no\": \"120°\",\n        \"sv\": \"120°\",\n        \"pl\": \"120°\",\n        \"ru\": \"120°\",\n        \"ko\": \"120°\"\n      }\n    },\n    {\n      \"id\": \"140\",\n      \"title\": {\n        \"en\": \"140°\",\n        \"nl\": \"140°\",\n        \"da\": \"140°\",\n        \"de\": \"140°\",\n        \"es\": \"140°\",\n        \"fr\": \"140°\",\n        \"it\": \"140°\",\n        \"no\": \"140°\",\n        \"sv\": \"140°\",\n        \"pl\": \"140°\",\n        \"ru\": \"140°\",\n        \"ko\": \"140°\"\n      }\n    },\n    {\n      \"id\": \"150\",\n      \"title\": {\n        \"en\": \"150°\",\n        \"nl\": \"150°\",\n        \"da\": \"150°\",\n        \"de\": \"150°\",\n        \"es\": \"150°\",\n        \"fr\": \"150°\",\n        \"it\": \"150°\",\n        \"no\": \"150°\",\n        \"sv\": \"150°\",\n        \"pl\": \"150°\",\n        \"ru\": \"150°\",\n        \"ko\": \"150°\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/oscillation.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/fan_zhimi_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalità\",\n    \"no\": \"Modus\",\n    \"sv\": \"Läge\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Natural Wind\",\n        \"nl\": \"Natuur wind\",\n        \"da\": \"Naturlig vind\",\n        \"de\": \"Natürlicher Wind\",\n        \"es\": \"Viento Natural\",\n        \"fr\": \"Vent Naturel\",\n        \"it\": \"Vento Naturale\",\n        \"no\": \"Naturlig Vind\",\n        \"sv\": \"Naturlig Vind\",\n        \"pl\": \"Naturalny Wiatr\",\n        \"ru\": \"Естественный ветер\",\n        \"ko\": \"자연풍\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Straight Wind\",\n        \"nl\": \"Rechte wind\",\n        \"da\": \"Lige Vind\",\n        \"de\": \"Gerader Wind\",\n        \"es\": \"Viento Recto\",\n        \"fr\": \"Vent Direct\",\n        \"it\": \"Vento Diretto\",\n        \"no\": \"Rett Vind\",\n        \"sv\": \"Rakt Vind\",\n        \"pl\": \"Prosty Wiatr\",\n        \"ru\": \"Прямой ветер\",\n        \"ko\": \"직풍\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/fanlevel.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/heater_zhimi_heater_target_temperature.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Target Temperature\",\n    \"nl\": \"Target Temperature\",\n    \"da\": \"Mål Temperatur\",\n    \"de\": \"Zieltemperatur\",\n    \"es\": \"Temperatura objetivo\",\n    \"fr\": \"Température cible\",\n    \"it\": \"Temperatura target\",\n    \"no\": \"Måltemperatur\",\n    \"sv\": \"Måltemperatur\",\n    \"pl\": \"Temperatura docelowa\",\n    \"ru\": \"Целевая температура\",\n    \"ko\": \"목표 온도\"\n  },\n  \"icon\": \"/assets/icons/target_temperature.svg\",\n  \"getable\": true,\n  \"setable\": true,\n  \"units\": {\n    \"en\": \"°C\",\n    \"nl\": \"°C\",\n    \"da\": \"°C\",\n    \"de\": \"°C\",\n    \"es\": \"°C\",\n    \"fr\": \"°C\",\n    \"it\": \"°C\",\n    \"no\": \"°C\",\n    \"sv\": \"°C\",\n    \"pl\": \"°C\",\n    \"ru\": \"°C\",\n    \"ko\": \"°C\"\n  },\n  \"uiComponent\": \"thermostat\",\n  \"min\": 16,\n  \"max\": 30,\n  \"step\": 1,\n  \"decimals\": 0,\n  \"insights\": false\n}"
  },
  {
    "path": ".homeycompose/capabilities/heater_zhimi_heatlevel.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Heatlevel\",\n    \"nl\": \"Hitte stand\",\n    \"da\": \"Varmeniveau\",\n    \"de\": \"Heizstufe\",\n    \"es\": \"Nivel de calor\",\n    \"fr\": \"Niveau de chaleur\",\n    \"it\": \"Livello di calore\",\n    \"no\": \"Varmenivå\",\n    \"sv\": \"Värmenivå\",\n    \"pl\": \"Poziom ciepła\",\n    \"ru\": \"Уровень тепла\",\n    \"ko\": \"난방 레벨\"\n  },\n  \"values\": [\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"High\",\n        \"nl\": \"Hoog\",\n        \"da\": \"Høj\",\n        \"de\": \"Hoch\",\n        \"es\": \"Alto\",\n        \"fr\": \"Élevé\",\n        \"it\": \"Alto\",\n        \"no\": \"Høy\",\n        \"sv\": \"Hög\",\n        \"pl\": \"Wysoki\",\n        \"ru\": \"Высоко\",\n        \"ko\": \"높음\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Low\",\n        \"nl\": \"Laag\",\n        \"da\": \"Lav\",\n        \"de\": \"Niedrig\",\n        \"es\": \"Bajo\",\n        \"fr\": \"Bas\",\n        \"it\": \"Basso\",\n        \"no\": \"Lav\",\n        \"sv\": \"Låg\",\n        \"pl\": \"Niski\",\n        \"ru\": \"Низко\",\n        \"ko\": \"낮음\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/heatlevel.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/heater_zhimi_oscillation.json",
    "content": "{\n  \"type\": \"boolean\",\n  \"title\": {\n    \"en\": \"Oscillation\",\n    \"nl\": \"Oscillatie\",\n    \"da\": \"Oscillation\",\n    \"de\": \"Oszillation\",\n    \"es\": \"Oscilación\",\n    \"fr\": \"Oscillation\",\n    \"it\": \"Oscillazione\",\n    \"no\": \"Oscillasjon\",\n    \"sv\": \"Oscillation\",\n    \"pl\": \"Oscylacja\",\n    \"ru\": \"Колебание\",\n    \"ko\": \"진동\"\n  },\n  \"getable\": true,\n  \"setable\": true,\n  \"uiComponent\": \"toggle\",\n  \"insights\": false,\n  \"icon\": \"/assets/icons/oscillation.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/humidifier2_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalità\",\n    \"no\": \"Modus\",\n    \"sv\": \"Läge\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\"\n  },\n  \"getable\": true,\n  \"setable\": true,\n  \"values\": [\n    {\n      \"id\": \"idle\",\n      \"title\": {\n        \"en\": \"Off\",\n        \"nl\": \"Uit\",\n        \"de\": \"Aus\",\n        \"da\": \"Fra\",\n        \"es\": \"Apagado\",\n        \"fr\": \"Éteint\",\n        \"it\": \"Spento\",\n        \"no\": \"Av\",\n        \"sv\": \"Av\",\n        \"pl\": \"Wyłączony\",\n        \"ru\": \"Выкл\",\n        \"ko\": \"끄기\"\n      }\n    },\n    {\n      \"id\": \"silent\",\n      \"title\": {\n        \"en\": \"Silent\",\n        \"nl\": \"Stil\",\n        \"de\": \"Leise\",\n        \"da\": \"Stille\",\n        \"es\": \"Silencioso\",\n        \"fr\": \"Silencieux\",\n        \"it\": \"Silenzioso\",\n        \"no\": \"Stille\",\n        \"sv\": \"Tyst\",\n        \"pl\": \"Cichy\",\n        \"ru\": \"Тихий\",\n        \"ko\": \"조용\"\n      }\n    },\n    {\n      \"id\": \"medium\",\n      \"title\": {\n        \"en\": \"Medium\",\n        \"nl\": \"Middel\",\n        \"de\": \"Mittel\",\n        \"da\": \"Mellem\",\n        \"es\": \"Medio\",\n        \"fr\": \"Moyen\",\n        \"it\": \"Medio\",\n        \"no\": \"Middels\",\n        \"sv\": \"Mellan\",\n        \"pl\": \"Średni\",\n        \"ru\": \"Средний\",\n        \"ko\": \"중간\"\n      }\n    },\n    {\n      \"id\": \"high\",\n      \"title\": {\n        \"en\": \"High\",\n        \"nl\": \"Hoog\",\n        \"de\": \"Hoch\",\n        \"da\": \"Høj\",\n        \"es\": \"Alto\",\n        \"fr\": \"Haut\",\n        \"it\": \"Alto\",\n        \"no\": \"Høy\",\n        \"sv\": \"Hög\",\n        \"pl\": \"Wysoki\",\n        \"ru\": \"Высокий\",\n        \"ko\": \"높음\"\n      }\n    },\n    {\n      \"id\": \"auto\",\n      \"title\": {\n        \"en\": \"Auto\",\n        \"nl\": \"Auto\",\n        \"de\": \"Auto\",\n        \"da\": \"Auto\",\n        \"es\": \"Automático\",\n        \"fr\": \"Auto\",\n        \"it\": \"Automatico\",\n        \"no\": \"Auto\",\n        \"sv\": \"Auto\",\n        \"pl\": \"Auto\",\n        \"ru\": \"Авто\",\n        \"ko\": \"자동\"\n      }\n    },\n    {\n      \"id\": \"strong\",\n      \"title\": {\n        \"en\": \"Strong\",\n        \"nl\": \"Sterk\",\n        \"de\": \"Stark\",\n        \"da\": \"Stærk\",\n        \"es\": \"Fuerte\",\n        \"fr\": \"Fort\",\n        \"it\": \"Forte\",\n        \"no\": \"Sterk\",\n        \"sv\": \"Stark\",\n        \"pl\": \"Mocny\",\n        \"ru\": \"Сильный\",\n        \"ko\": \"강한\"\n      }\n    }\n  ],\n  \"icon\": \"/assets/icons/humidifier-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/humidifier_deerma_jsq_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalità\",\n    \"no\": \"Modus\",\n    \"sv\": \"Läge\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\",\n    \"ja\": \"モード\",\n    \"zh\": \"模式\",\n    \"pt\": \"Modo\"\n  },\n  \"values\": [\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Low\",\n        \"nl\": \"Laag\",\n        \"da\": \"Lav\",\n        \"de\": \"Niedrig\",\n        \"es\": \"Bajo\",\n        \"fr\": \"Faible\",\n        \"it\": \"Basso\",\n        \"no\": \"Lav\",\n        \"sv\": \"Låg\",\n        \"pl\": \"Niski\",\n        \"ru\": \"Низкий\",\n        \"ko\": \"낮은\",\n        \"ja\": \"低い\",\n        \"zh\": \"低\",\n        \"pt\": \"Baixo\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Medium\",\n        \"nl\": \"Medium\",\n        \"da\": \"Mellem\",\n        \"de\": \"Mittel\",\n        \"es\": \"Medio\",\n        \"fr\": \"Moyen\",\n        \"it\": \"Medio\",\n        \"no\": \"Middels\",\n        \"sv\": \"Medel\",\n        \"pl\": \"Średni\",\n        \"ru\": \"Средний\",\n        \"ko\": \"중간\",\n        \"ja\": \"中\",\n        \"zh\": \"中\",\n        \"pt\": \"Médio\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"High\",\n        \"nl\": \"Hoog\",\n        \"da\": \"Høj\",\n        \"de\": \"Hoch\",\n        \"es\": \"Alto\",\n        \"fr\": \"Élevé\",\n        \"it\": \"Alto\",\n        \"no\": \"Høy\",\n        \"sv\": \"Hög\",\n        \"pl\": \"Wysoki\",\n        \"ru\": \"Высокий\",\n        \"ko\": \"높은\",\n        \"ja\": \"高い\",\n        \"zh\": \"高\",\n        \"pt\": \"Alto\"\n      }\n    },\n    {\n      \"id\": \"4\",\n      \"title\": {\n        \"en\": \"Humidity\",\n        \"nl\": \"Luchtvochtigheid\",\n        \"da\": \"Fugtighed\",\n        \"de\": \"Feuchtigkeit\",\n        \"es\": \"Humedad\",\n        \"fr\": \"Humidité\",\n        \"it\": \"Umidità\",\n        \"no\": \"Fuktighet\",\n        \"sv\": \"Fuktighet\",\n        \"pl\": \"Wilgotność\",\n        \"ru\": \"Влажность\",\n        \"ko\": \"습도\",\n        \"ja\": \"湿度\",\n        \"zh\": \"湿度\",\n        \"pt\": \"Umidade\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/humidifier-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/humidifier_leshow_jsq1_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalità\",\n    \"no\": \"Modus\",\n    \"sv\": \"Läge\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Constant Humidity\",\n        \"nl\": \"Constante luchtvochtigheid\",\n        \"da\": \"Konstant fugtighed\",\n        \"de\": \"Konstante Luftfeuchtigkeit\",\n        \"es\": \"Humedad constante\",\n        \"fr\": \"Humidité constante\",\n        \"it\": \"Umidità costante\",\n        \"no\": \"Konstant fuktighet\",\n        \"sv\": \"Konstant fuktighet\",\n        \"pl\": \"Stała wilgotność\",\n        \"ru\": \"Постоянная влажность\",\n        \"ko\": \"일정 습도\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"High\",\n        \"nl\": \"Hoog\",\n        \"da\": \"Høj\",\n        \"de\": \"Hoch\",\n        \"es\": \"Alto\",\n        \"fr\": \"Élevé\",\n        \"it\": \"Alto\",\n        \"no\": \"Høy\",\n        \"sv\": \"Hög\",\n        \"pl\": \"Wysoki\",\n        \"ru\": \"Высокий\",\n        \"ko\": \"높음\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Sleep\",\n        \"n;\": \"Slaapstand\",\n        \"da\": \"Søvn\",\n        \"de\": \"Schlafmodus\",\n        \"es\": \"Sueño\",\n        \"fr\": \"Veille\",\n        \"it\": \"Sonno\",\n        \"no\": \"Søvn\",\n        \"sv\": \"Sömn\",\n        \"pl\": \"Sen\",\n        \"ru\": \"Сон\",\n        \"ko\": \"수면\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/humidifier-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/humidifier_water_level_state.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Water level state\"\n  },\n  \"desc\": {\n    \"en\": \"Indicates the current water level state in the tank\"\n  },\n  \"getable\": true,\n  \"setable\": false,\n  \"values\": [\n    {\n      \"id\": \"empty\",\n      \"title\": {\n        \"en\": \"Empty\"\n      }\n    },\n    {\n      \"id\": \"normal\",\n      \"title\": {\n        \"en\": \"Normal\"\n      }\n    },\n    {\n      \"id\": \"full\",\n      \"title\": {\n        \"en\": \"Full\"\n      }\n    }\n  ],\n  \"icon\": \"/assets/icons/water-level.svg\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/humidifier_xiaomi_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Mode\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalità\",\n    \"no\": \"Modus\",\n    \"sv\": \"Läge\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Constant Humidity\",\n        \"nl\": \"Constante luchtvochtigheid\",\n        \"da\": \"Konstant fugtighed\",\n        \"de\": \"Konstante Luftfeuchtigkeit\",\n        \"es\": \"Humedad constante\",\n        \"fr\": \"Humidité constante\",\n        \"it\": \"Umidità costante\",\n        \"no\": \"Konstant fuktighet\",\n        \"sv\": \"Konstant fuktighet\",\n        \"pl\": \"Stała wilgotność\",\n        \"ru\": \"Постоянная влажность\",\n        \"ko\": \"항상 습도\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Strong\",\n        \"nl\": \"Sterk\",\n        \"da\": \"Stærk\",\n        \"de\": \"Stark\",\n        \"es\": \"Fuerte\",\n        \"fr\": \"Fort\",\n        \"it\": \"Forte\",\n        \"no\": \"Sterk\",\n        \"sv\": \"Stark\",\n        \"pl\": \"Mocny\",\n        \"ru\": \"Сильный\",\n        \"ko\": \"강한\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Sleep\",\n        \"nl\": \"Slaapstand\",\n        \"da\": \"Søvn\",\n        \"de\": \"Schlaf\",\n        \"es\": \"Sueño\",\n        \"fr\": \"Sommeil\",\n        \"it\": \"Sonno\",\n        \"no\": \"Søvn\",\n        \"sv\": \"Sömn\",\n        \"pl\": \"Sen\",\n        \"ru\": \"Сон\",\n        \"ko\": \"수면\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Air-dry\",\n        \"nl\": \"Air-dry\",\n        \"da\": \"Lufttørre\",\n        \"de\": \"Lufttrocknen\",\n        \"es\": \"Secado al aire\",\n        \"fr\": \"Sécher à l'air\",\n        \"it\": \"Asciuga all'aria\",\n        \"no\": \"Lufttørk\",\n        \"sv\": \"Lufttorka\",\n        \"pl\": \"Suszenie powietrzem\",\n        \"ru\": \"Воздушная сушка\",\n        \"ko\": \"공기 건조\"\n      }\n    },\n    {\n      \"id\": \"4\",\n      \"title\": {\n        \"en\": \"Clean\",\n        \"nl\": \"Schonen\",\n        \"da\": \"Rengør\",\n        \"de\": \"Reinigen\",\n        \"es\": \"Limpiar\",\n        \"fr\": \"Nettoyer\",\n        \"it\": \"Pulito\",\n        \"no\": \"Rengjør\",\n        \"sv\": \"Rengöra\",\n        \"pl\": \"Czystość\",\n        \"ru\": \"Чистка\",\n        \"ko\": \"청소\"\n      }\n    },\n    {\n      \"id\": \"5\",\n      \"title\": {\n        \"en\": \"Descale\",\n        \"nl\": \"Descale\",\n        \"da\": \"Afkalkning\",\n        \"de\": \"Entkalken\",\n        \"es\": \"Desincrustar\",\n        \"fr\": \"Détartrage\",\n        \"it\": \"Decalcificare\",\n        \"no\": \"Avkalking\",\n        \"sv\": \"Avkalka\",\n        \"pl\": \"Odkamienianie\",\n        \"ru\": \"Удаление накипи\",\n        \"ko\": \"제거\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/humidifier-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/humidifier_zhimi_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalità\",\n    \"no\": \"Modus\",\n    \"sv\": \"Läge\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\"\n  },\n  \"getable\": true,\n  \"setable\": true,\n  \"values\": [\n    {\n      \"id\": \"idle\",\n      \"title\": {\n        \"en\": \"Off\",\n        \"nl\": \"Uit\",\n        \"de\": \"Aus\",\n        \"da\": \"Slukket\",\n        \"es\": \"Apagado\",\n        \"fr\": \"Éteint\",\n        \"it\": \"Spento\",\n        \"no\": \"Av\",\n        \"sv\": \"Av\",\n        \"pl\": \"Wył.\",\n        \"ru\": \"Выкл.\",\n        \"ko\": \"낌\"\n      }\n    },\n    {\n      \"id\": \"silent\",\n      \"title\": {\n        \"en\": \"Silent\",\n        \"nl\": \"Stil\",\n        \"de\": \"Leise\",\n        \"da\": \"Stille\",\n        \"es\": \"Silencioso\",\n        \"fr\": \"Silencieux\",\n        \"it\": \"Silenzioso\",\n        \"no\": \"Stille\",\n        \"sv\": \"Tyst\",\n        \"pl\": \"Cichy\",\n        \"ru\": \"Тихий\",\n        \"ko\": \"조용히\"\n      }\n    },\n    {\n      \"id\": \"medium\",\n      \"title\": {\n        \"en\": \"Medium\",\n        \"nl\": \"Middel\",\n        \"de\": \"Mittel\",\n        \"da\": \"Mellem\",\n        \"es\": \"Medio\",\n        \"fr\": \"Moyen\",\n        \"it\": \"Medio\",\n        \"no\": \"Middels\",\n        \"sv\": \"Medium\",\n        \"pl\": \"Średni\",\n        \"ru\": \"Средний\",\n        \"ko\": \"중간\"\n      }\n    },\n    {\n      \"id\": \"high\",\n      \"title\": {\n        \"en\": \"High\",\n        \"nl\": \"Hoog\",\n        \"de\": \"Hoch\",\n        \"da\": \"Høj\",\n        \"es\": \"Alto\",\n        \"fr\": \"Élevé\",\n        \"it\": \"Alto\",\n        \"no\": \"Høy\",\n        \"sv\": \"Hög\",\n        \"pl\": \"Wysoki\",\n        \"ru\": \"Высокий\",\n        \"ko\": \"높은\"\n      }\n    },\n    {\n      \"id\": \"auto\",\n      \"title\": {\n        \"en\": \"Auto\",\n        \"nl\": \"Auto\",\n        \"de\": \"Auto\",\n        \"da\": \"Auto\",\n        \"es\": \"Auto\",\n        \"fr\": \"Auto\",\n        \"it\": \"Auto\",\n        \"no\": \"Auto\",\n        \"sv\": \"Auto\",\n        \"pl\": \"Auto\",\n        \"ru\": \"Авто\",\n        \"ko\": \"자동\"\n      }\n    },\n    {\n      \"id\": \"strong\",\n      \"title\": {\n        \"en\": \"Strong\",\n        \"nl\": \"Sterk\",\n        \"de\": \"Stark\",\n        \"da\": \"Stærk\",\n        \"es\": \"Fuerte\",\n        \"fr\": \"Fort\",\n        \"it\": \"Forte\",\n        \"no\": \"Sterk\",\n        \"sv\": \"Stark\",\n        \"pl\": \"Mocny\",\n        \"ru\": \"Сильный\",\n        \"ko\": \"강한\"\n      }\n    }\n  ],\n  \"icon\": \"/assets/icons/humidifier-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/humidifier_zhimi_mode_miot.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalità\",\n    \"no\": \"Modus\",\n    \"sv\": \"Läge\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Auto\",\n        \"nl\": \"Auto\",\n        \"da\": \"Auto\",\n        \"de\": \"Auto\",\n        \"es\": \"Auto\",\n        \"fr\": \"Auto\",\n        \"it\": \"Auto\",\n        \"no\": \"Auto\",\n        \"sv\": \"Auto\",\n        \"pl\": \"Auto\",\n        \"ru\": \"Авто\",\n        \"ko\": \"자동\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Level 1\",\n        \"nl\": \"Level 1\",\n        \"da\": \"Niveau 1\",\n        \"de\": \"Stufe 1\",\n        \"es\": \"Nivel 1\",\n        \"fr\": \"Niveau 1\",\n        \"it\": \"Livello 1\",\n        \"no\": \"Nivå 1\",\n        \"sv\": \"Nivå 1\",\n        \"pl\": \"Poziom 1\",\n        \"ru\": \"Уровень 1\",\n        \"ko\": \"레벨 1\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Level 2\",\n        \"nl\": \"Level 2\",\n        \"da\": \"Niveau 2\",\n        \"de\": \"Stufe 2\",\n        \"es\": \"Nivel 2\",\n        \"fr\": \"Niveau 2\",\n        \"it\": \"Livello 2\",\n        \"no\": \"Nivå 2\",\n        \"sv\": \"Nivå 2\",\n        \"pl\": \"Poziom 2\",\n        \"ru\": \"Уровень 2\",\n        \"ko\": \"레벨 2\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Level 3\",\n        \"nl\": \"Level 3\",\n        \"da\": \"Niveau 3\",\n        \"de\": \"Stufe 3\",\n        \"es\": \"Nivel 3\",\n        \"fr\": \"Niveau 3\",\n        \"it\": \"Livello 3\",\n        \"no\": \"Nivå 3\",\n        \"sv\": \"Nivå 3\",\n        \"pl\": \"Poziom 3\",\n        \"ru\": \"Уровень 3\",\n        \"ko\": \"레벨 3\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/humidifier-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/measure_desiccant.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": { \"en\": \"Desiccant Left\" },\n  \"getable\": true,\n  \"setable\": false,\n  \"units\": { \"en\": \"%\" },\n  \"decimals\": 0,\n  \"min\": 0,\n  \"max\": 100,\n  \"uiComponent\": \"sensor\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/measure_desiccant_time.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": { \"en\": \"Desiccant Time Left\" },\n  \"getable\": true,\n  \"setable\": false,\n  \"units\": { \"en\": \"days\" },\n  \"decimals\": 0,\n  \"min\": 0,\n  \"uiComponent\": \"sensor\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/measure_filter_days_left.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Filter Days Left\",\n    \"nl\": \"Filterdagen resterend\",\n    \"da\": \"Filtrets resterende dage\",\n    \"de\": \"Verbleibende Filtertage\",\n    \"es\": \"Días restantes del filtro\",\n    \"fr\": \"Jours de filtre restants\",\n    \"it\": \"Giorni filtro rimasti\",\n    \"no\": \"Filterdager igjen\",\n    \"sv\": \"Filterdagar kvar\",\n    \"pl\": \"Pozostało dni filtra\",\n    \"ru\": \"Осталось дней фильтра\",\n    \"ko\": \"필터 남은 일수\"\n  },\n  \"desc\": {\n    \"en\": \"Number of days the filter is expected to last\"\n  },\n  \"getable\": true,\n  \"setable\": false,\n  \"units\": {\n    \"en\": \"days\"\n  },\n  \"icon\": \"/assets/icons/filter_left.svg\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/measure_filter_life.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Filter Life (%)\",\n    \"nl\": \"Filter Levensduur (%)\",\n    \"da\": \"Filterlevetid (%)\",\n    \"de\": \"Filterlebensdauer (%)\",\n    \"es\": \"Vida útil del filtro (%)\",\n    \"fr\": \"Durée de vie du filtre (%)\",\n    \"it\": \"Durata del filtro (%)\",\n    \"no\": \"Filterlevetid (%)\",\n    \"sv\": \"Filterlivslängd (%)\",\n    \"pl\": \"Żywotność filtra (%)\",\n    \"ru\": \"Срок службы фильтра (%)\",\n    \"ko\": \"필터 수명 (%)\"\n  },\n  \"desc\": {\n    \"en\": \"Shows the remaining filter life in percent\"\n  },\n  \"getable\": true,\n  \"setable\": false,\n  \"units\": {\n    \"en\": \"%\"\n  },\n  \"icon\": \"/assets/icons/filter.svg\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/measure_gas_density.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Gas Density\",\n    \"nl\": \"Gas dichtheid\",\n    \"da\": \"Gasdensitet\",\n    \"de\": \"Gasdichte\",\n    \"es\": \"Densidad del gas\",\n    \"fr\": \"Densité de gaz\",\n    \"it\": \"Densità del gas\",\n    \"no\": \"Gassdensitet\",\n    \"sv\": \"Gasdensitet\",\n    \"pl\": \"Gęstość gazu\",\n    \"ru\": \"Плотность газа\",\n    \"ko\": \"가스 밀도\"\n  },\n  \"type\": \"number\",\n  \"units\": {\n    \"en\": \"kg/m3\",\n    \"nl\": \"kg/m3\",\n    \"da\": \"kg/m3\",\n    \"de\": \"kg/m3\",\n    \"es\": \"kg/m3\",\n    \"fr\": \"kg/m3\",\n    \"it\": \"kg/m3\",\n    \"no\": \"kg/m3\",\n    \"sv\": \"kg/m3\",\n    \"pl\": \"kg/m3\",\n    \"ru\": \"kg/m3\",\n    \"ko\": \"kg/m3\"\n  },\n  \"getable\": true,\n  \"setable\": false,\n  \"icon\": \"/assets/icons/measure_gas_density.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/measure_smoke_density.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Smoke Density\",\n    \"nl\": \"Rook dichtheid\",\n    \"da\": \"Røgtæthed\",\n    \"de\": \"Rauchdichte\",\n    \"es\": \"Densidad de humo\",\n    \"fr\": \"Densité de fumée\",\n    \"it\": \"Densità del fumo\",\n    \"no\": \"Røykdensitet\",\n    \"sv\": \"Röktäthet\",\n    \"pl\": \"Gęstość dymu\",\n    \"ru\": \"Плотность дыма\",\n    \"ko\": \"연기 밀도\"\n  },\n  \"type\": \"number\",\n  \"units\": {\n    \"en\": \"kg/m3\",\n    \"da\": \"kg/m3\",\n    \"de\": \"kg/m3\",\n    \"es\": \"kg/m3\",\n    \"fr\": \"kg/m3\",\n    \"it\": \"kg/m3\",\n    \"no\": \"kg/m3\",\n    \"sv\": \"kg/m3\",\n    \"pl\": \"kg/m3\",\n    \"ru\": \"кг/м³\",\n    \"ko\": \"kg/m3\"\n  },\n  \"getable\": true,\n  \"setable\": false,\n  \"icon\": \"/assets/icons/measure_smoke_density.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/measure_target_humidity.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Target humidity\"\n  },\n  \"desc\": {\n    \"en\": \"Target humidity for Insights\"\n  },\n  \"getable\": true,\n  \"setable\": false,\n  \"uiComponent\": null,\n  \"units\": {\n    \"en\": \"%\"\n  },\n  \"decimals\": 0,\n  \"insights\": true\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/measure_tvoc.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"TVOC\",\n    \"nl\": \"TVOC\",\n    \"da\": \"TVOC\",\n    \"de\": \"TVOC\",\n    \"es\": \"TVOC\",\n    \"fr\": \"TVOC\",\n    \"it\": \"TVOC\",\n    \"no\": \"TVOC\",\n    \"sv\": \"TVOC\",\n    \"pl\": \"TVOC\",\n    \"ru\": \"TVOC\",\n    \"ko\": \"TVOC\"\n  },\n  \"icon\": \"/assets/icons/measure_tvoc.svg\",\n  \"getable\": true,\n  \"setable\": false,\n  \"units\": {\n    \"en\": \"µg/m³\",\n    \"nl\": \"µg/m³\",\n    \"da\": \"µg/m³\",\n    \"de\": \"µg/m³\",\n    \"es\": \"µg/m³\",\n    \"fr\": \"µg/m³\",\n    \"it\": \"µg/m³\",\n    \"no\": \"µg/m³\",\n    \"sv\": \"µg/m³\",\n    \"pl\": \"µg/m³\",\n    \"ru\": \"µg/m³\",\n    \"ko\": \"µg/m³\"\n  },\n  \"min\": 0,\n  \"max\": 10,\n  \"decimals\": 3,\n  \"insights\": true\n}"
  },
  {
    "path": ".homeycompose/capabilities/measure_waterlevel.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Waterlevel\",\n    \"nl\": \"Waterniveau\",\n    \"da\": \"Vandstand\",\n    \"de\": \"Wasserstand\",\n    \"es\": \"Nivel del agua\",\n    \"fr\": \"Niveau d'eau\",\n    \"it\": \"Livello dell'acqua\",\n    \"no\": \"Vannstand\",\n    \"sv\": \"Vattennivå\",\n    \"pl\": \"Poziom wody\",\n    \"ru\": \"Уровень воды\",\n    \"ko\": \"수위\"\n  },\n  \"icon\": \"/assets/icons/measure_waterlevel.svg\",\n  \"getable\": true,\n  \"setable\": false,\n  \"uiComponent\": \"sensor\",\n  \"units\": {\n    \"en\": \"%\",\n    \"nl\": \"%\",\n    \"da\": \"%\",\n    \"de\": \"%\",\n    \"es\": \"%\",\n    \"fr\": \"%\",\n    \"it\": \"%\",\n    \"no\": \"%\",\n    \"sv\": \"%\",\n    \"pl\": \"%\",\n    \"ru\": \"%\",\n    \"ko\": \"%\"\n  },\n  \"insights\": true\n}"
  },
  {
    "path": ".homeycompose/capabilities/petfeeder_busy.json",
    "content": "{\n  \"type\": \"boolean\",\n  \"title\": {\n    \"en\": \"Feeder busy\"\n  },\n  \"getable\": true,\n  \"setable\": false,\n  \"uiComponent\": \"toggle\",\n  \"insights\": true,\n  \"insightsTitleTrue\": {\n    \"en\": \"Feeding\"\n  },\n  \"insightsTitleFalse\": {\n    \"en\": \"Idle\"\n  }\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/petfeeder_eaten_food_today.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Eaten Food Today\"\n  },\n  \"desc\": {\n    \"en\": \"Food eaten since midnight\"\n  },\n  \"getable\": true,\n  \"setable\": false,\n  \"units\": {\n    \"en\": \"g\"\n  },\n  \"decimals\": 0,\n  \"min\": 0,\n  \"uiComponent\": \"sensor\",\n  \"insights\": true,\n  \"insightsTitle\": {\n    \"en\": \"Food eaten today\"\n  }\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/petfeeder_eaten_food_total.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": { \"en\": \"Eaten Food Total\" },\n  \"desc\": { \"en\": \"Cumulative eaten food reported by device\" },\n  \"getable\": true,\n  \"setable\": false,\n  \"units\": { \"en\": \"g\" },\n  \"decimals\": 0,\n  \"min\": 0,\n  \"uiComponent\": \"sensor\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/petfeeder_food_in_bowl.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Food left in bowl\"\n  },\n  \"units\": {\n    \"en\": \"g\"\n  },\n  \"decimals\": 1,\n  \"min\": 0,\n  \"getable\": true,\n  \"setable\": false,\n  \"insights\": true,\n  \"insightsTitle\": {\n    \"en\": \"Food in bowl\"\n  },\n  \"uiComponent\": \"sensor\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/petfeeder_food_out_progress.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Food out progress\"\n  },\n  \"getable\": true,\n  \"setable\": false,\n  \"units\": {\n    \"en\": \"%\"\n  },\n  \"min\": 0,\n  \"max\": 100,\n  \"decimals\": 0,\n  \"uiComponent\": \"sensor\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/petfeeder_food_out_status.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": { \"en\": \"Food Out Status\" },\n  \"getable\": true,\n  \"setable\": false,\n  \"values\": [\n    { \"id\": \"ok\", \"title\": { \"en\": \"OK\" } },\n    { \"id\": \"food_out\", \"title\": { \"en\": \"Food Out\" } }\n  ],\n  \"uiComponent\": \"picker\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/petfeeder_foodlevel.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Foodlevel\",\n    \"nl\": \"Voedselniveau\",\n    \"da\": \"Madniveau\",\n    \"de\": \"Futterstand\",\n    \"es\": \"Nivel de comida\",\n    \"fr\": \"Niveau de nourriture\",\n    \"it\": \"Livello di cibo\",\n    \"no\": \"Matenivå\",\n    \"sv\": \"Matnivå\",\n    \"pl\": \"Poziom jedzenia\",\n    \"ru\": \"Уровень еды\",\n    \"ko\": \"음식 수준\"\n  },\n  \"values\": [\n    {\n      \"title\": {\n        \"en\": \"Normal\"\n      },\n      \"id\": \"normal\"\n    },\n    {\n      \"title\": {\n        \"en\": \"Low\"\n      },\n      \"id\": \"low\"\n    },\n    {\n      \"title\": {\n        \"en\": \"Unknown\"\n      },\n      \"id\": \"unknown\"\n    }\n  ],\n  \"getable\": true,\n  \"setable\": false,\n  \"icon\": \"/assets/icons/petfeeder_foodlevel.svg\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/petfeeder_heap_status.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": { \"en\": \"Heap Status\" },\n  \"getable\": true,\n  \"setable\": false,\n  \"values\": [\n    { \"id\": \"ok\", \"title\": { \"en\": \"OK\" } },\n    { \"id\": \"heap_detected\", \"title\": { \"en\": \"Heap Detected\" } }\n  ],\n  \"uiComponent\": \"picker\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/petfeeder_schedule_progress.json",
    "content": "{\n  \"type\": \"number\",\n  \"title\": {\n    \"en\": \"Schedule progress\"\n  },\n  \"units\": {\n    \"en\": \"%\"\n  },\n  \"decimals\": 0,\n  \"min\": 0,\n  \"max\": 100,\n  \"getable\": true,\n  \"setable\": false,\n  \"uiComponent\": \"sensor\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/petfeeder_status_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": { \"en\": \"Feeder Status\" },\n  \"getable\": true,\n  \"setable\": false,\n  \"values\": [\n    { \"id\": \"unknown\", \"title\": { \"en\": \"Unknown\" } },\n    { \"id\": \"idle\", \"title\": { \"en\": \"Idle\" } },\n    { \"id\": \"feeding\", \"title\": { \"en\": \"Feeding\" } },\n    { \"id\": \"paused\", \"title\": { \"en\": \"Paused\" } },\n    { \"id\": \"fault\", \"title\": { \"en\": \"Fault\" } }\n  ],\n  \"uiComponent\": \"picker\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/petwaterdispenser_mmgg_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Pet Waterdispenser Mode\",\n    \"nl\": \"Pet Waterdispenser Mode\",\n    \"da\": \"Kæledyrsvanddispenser Mode\",\n    \"de\": \"Haustier Wasserspender Modus\",\n    \"es\": \"Modo dispensador de agua para mascotas\",\n    \"fr\": \"Mode distributeur d'eau pour animaux\",\n    \"it\": \"Modalità dispenser d'acqua per animali\",\n    \"no\": \"Kjæledyr vannedispensermodus\",\n    \"sv\": \"Husdjur vattendispenserläge\",\n    \"pl\": \"Tryb dozownika wody dla zwierząt\",\n    \"ru\": \"Режим поилки для питомцев\",\n    \"ko\": \"애완동물 물 디스펜서 모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Common\",\n        \"nl\": \"Normaal\",\n        \"da\": \"Almindelig\",\n        \"de\": \"Allgemein\",\n        \"es\": \"Común\",\n        \"fr\": \"Commun\",\n        \"it\": \"Comune\",\n        \"no\": \"Vanlig\",\n        \"sv\": \"Vanlig\",\n        \"pl\": \"Zwykły\",\n        \"ru\": \"Обычный\",\n        \"ko\": \"일반\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Smart\",\n        \"nl\": \"Slim\",\n        \"da\": \"Smart\",\n        \"de\": \"Intelligent\",\n        \"es\": \"Inteligente\",\n        \"fr\": \"Intelligent\",\n        \"it\": \"Intelligente\",\n        \"no\": \"Smart\",\n        \"sv\": \"Smart\",\n        \"pl\": \"Inteligentny\",\n        \"ru\": \"Умный\",\n        \"ko\": \"스마트\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/waterdispenser-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/petwaterdispenser_mmgg_mode_3.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Pet Fountain Mode\",\n    \"nl\": \"Huisdier Fontein Modus\",\n    \"da\": \"Kæledyr Fountain Mode\",\n    \"de\": \"Haustierbrunnen-Modus\",\n    \"es\": \"Modo Fuente para Mascotas\",\n    \"fr\": \"Mode Fontaine à Animaux\",\n    \"it\": \"Modalità Fontana per Animali\",\n    \"no\": \"Kjæledyr Fontenemodus\",\n    \"sv\": \"Husdjur Fontänläge\",\n    \"pl\": \"Tryb Fontanny dla Zwierząt\",\n    \"ru\": \"Режим поилки для питомцев\",\n    \"ko\": \"애완동물 분수 모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Auto\",\n        \"nl\": \"Auto\",\n        \"da\": \"Auto\",\n        \"de\": \"Auto\",\n        \"es\": \"Auto\",\n        \"fr\": \"Auto\",\n        \"it\": \"Auto\",\n        \"no\": \"Auto\",\n        \"sv\": \"Auto\",\n        \"pl\": \"Auto\",\n        \"ru\": \"Авто\",\n        \"ko\": \"자동\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Interval\",\n        \"nl\": \"Interval\",\n        \"da\": \"Interval\",\n        \"de\": \"Intervall\",\n        \"es\": \"Intervalo\",\n        \"fr\": \"Intervalle\",\n        \"it\": \"Intervallo\",\n        \"no\": \"Intervall\",\n        \"sv\": \"Intervall\",\n        \"pl\": \"Interwał\",\n        \"ru\": \"Интервал\",\n        \"ko\": \"간격\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Constant\",\n        \"nl\": \"Constant\",\n        \"da\": \"Konstant\",\n        \"de\": \"Konstant\",\n        \"es\": \"Constante\",\n        \"fr\": \"Constant\",\n        \"it\": \"Costante\",\n        \"no\": \"Konstant\",\n        \"sv\": \"Konstant\",\n        \"pl\": \"Ciągły\",\n        \"ru\": \"Постоянный\",\n        \"ko\": \"지속\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/waterdispenser-mode.svg\"\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_dreame_fanspeed.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Fanspeed\",\n    \"nl\": \"Fanspeed\",\n    \"da\": \"Blæserhastighed\",\n    \"de\": \"Lüftergeschwindigkeit\",\n    \"es\": \"Velocidad del ventilador\",\n    \"fr\": \"Vitesse du ventilateur\",\n    \"it\": \"Velocità della ventola\",\n    \"no\": \"Viftehastighet\",\n    \"sv\": \"Fläkthastighet\",\n    \"pl\": \"Prędkość wentylatora\",\n    \"ru\": \"Скорость вентилятора\",\n    \"ko\": \"팬 속도\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Silent\",\n        \"nl\": \"Stil\",\n        \"da\": \"Stille\",\n        \"de\": \"Leise\",\n        \"es\": \"Silencioso\",\n        \"fr\": \"Silencieux\",\n        \"it\": \"Silenzioso\",\n        \"no\": \"Stille\",\n        \"sv\": \"Tyst\",\n        \"pl\": \"Cichy\",\n        \"ru\": \"Бесшумный\",\n        \"ko\": \"조용한\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Basic\",\n        \"nl\": \"Basis\",\n        \"da\": \"Basis\",\n        \"de\": \"Basis\",\n        \"es\": \"Básico\",\n        \"fr\": \"De base\",\n        \"it\": \"Di base\",\n        \"no\": \"Grunnleggende\",\n        \"sv\": \"Grundläggande\",\n        \"pl\": \"Podstawowy\",\n        \"ru\": \"Базовый\",\n        \"ko\": \"기본\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Strong\",\n        \"nl\": \"Sterk\",\n        \"da\": \"Stærk\",\n        \"de\": \"Stark\",\n        \"es\": \"Fuerte\",\n        \"fr\": \"Fort\",\n        \"it\": \"Forte\",\n        \"no\": \"Sterk\",\n        \"sv\": \"Stark\",\n        \"pl\": \"Silny\",\n        \"ru\": \"Сильный\",\n        \"ko\": \"강한\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Full speed\",\n        \"nl\": \"Volle snelheid\",\n        \"da\": \"Fuld hastighed\",\n        \"de\": \"Volle Geschwindigkeit\",\n        \"es\": \"Velocidad máxima\",\n        \"fr\": \"Vitesse maximale\",\n        \"it\": \"Velocità massima\",\n        \"no\": \"Full fart\",\n        \"sv\": \"Full hastighet\",\n        \"pl\": \"Pełna prędkość\",\n        \"ru\": \"Полная скорость\",\n        \"ko\": \"최고 속도\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/fanlevel.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_dreame_mop_intensity.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mop Intensity\",\n    \"nl\": \"Dweil intensiteit\",\n    \"da\": \"Mop Intensity\",\n    \"de\": \"Wischintensität\",\n    \"es\": \"Intensidad de fregado\",\n    \"fr\": \"Intensité de la serpillière\",\n    \"it\": \"Intensità del mop\",\n    \"no\": \"Mop Intensity\",\n    \"sv\": \"Mop Intensity\",\n    \"pl\": \"Intensywność mopa\",\n    \"ru\": \"Интенсивность швабры\",\n    \"ko\": \"물걸레 강도\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Low\",\n        \"nl\": \"Laag\",\n        \"da\": \"Lav\",\n        \"de\": \"Niedrig\",\n        \"es\": \"Bajo\",\n        \"fr\": \"Faible\",\n        \"it\": \"Basso\",\n        \"no\": \"Lav\",\n        \"sv\": \"Låg\",\n        \"pl\": \"Niski\",\n        \"ru\": \"Низкий\",\n        \"ko\": \"낮음\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Medium\",\n        \"nl\": \"Medium\",\n        \"da\": \"Middel\",\n        \"de\": \"Mittel\",\n        \"es\": \"Medio\",\n        \"fr\": \"Moyen\",\n        \"it\": \"Medio\",\n        \"no\": \"Medium\",\n        \"sv\": \"Medium\",\n        \"pl\": \"Średni\",\n        \"ru\": \"Средний\",\n        \"ko\": \"중간\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"High\",\n        \"nl\": \"Hoog\",\n        \"da\": \"Høj\",\n        \"de\": \"Hoch\",\n        \"es\": \"Alto\",\n        \"fr\": \"Élevé\",\n        \"it\": \"Alto\",\n        \"no\": \"Høy\",\n        \"sv\": \"Hög\",\n        \"pl\": \"Wysoki\",\n        \"ru\": \"Высокий\",\n        \"ko\": \"높음\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"High (specific models)\",\n        \"nl\": \"Hoog (specifieke modellen)\",\n        \"da\": \"Høj (specifikke modeller)\",\n        \"de\": \"Hoch (spezifische Modelle)\",\n        \"es\": \"Alto (modelos específicos)\",\n        \"fr\": \"Élevé (modèles spécifiques)\",\n        \"it\": \"Alto (modelli specifici)\",\n        \"no\": \"Høy (spesifikke modeller)\",\n        \"sv\": \"Hög (specifika modeller)\",\n        \"pl\": \"Wysoki (specyficzne modele)\",\n        \"ru\": \"Высокий (определённые модели)\",\n        \"ko\": \"높음 (특정 모델)\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/mopintensity.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_roborock_fanspeed.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Fanspeed\",\n    \"nl\": \"Fanspeed\",\n    \"da\": \"Blæserhastighed\",\n    \"de\": \"Lüftergeschwindigkeit\",\n    \"es\": \"Velocidad del ventilador\",\n    \"fr\": \"Vitesse du ventilateur\",\n    \"it\": \"Velocità della ventola\",\n    \"no\": \"Viftehastighet\",\n    \"sv\": \"Fläkthastighet\",\n    \"pl\": \"Prędkość wentylatora\",\n    \"ru\": \"Скорость вентилятора\",\n    \"ko\": \"팬 속도\"\n  },\n  \"values\": [\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Quiet\",\n        \"nl\": \"Stil\",\n        \"da\": \"Rolig\",\n        \"de\": \"Leise\",\n        \"es\": \"Silencioso\",\n        \"fr\": \"Silencieux\",\n        \"it\": \"Silenzioso\",\n        \"no\": \"Stille\",\n        \"sv\": \"Tyst\",\n        \"pl\": \"Cichy\",\n        \"ru\": \"Тихий\",\n        \"ko\": \"조용하게\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Standard\",\n        \"nl\": \"Standaard\",\n        \"da\": \"Standard\",\n        \"de\": \"Standard\",\n        \"es\": \"Estándar\",\n        \"fr\": \"Standard\",\n        \"it\": \"Standard\",\n        \"no\": \"Standard\",\n        \"sv\": \"Standard\",\n        \"pl\": \"Standardowy\",\n        \"ru\": \"Стандартный\",\n        \"ko\": \"표준\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Medium\",\n        \"nl\": \"Medium\",\n        \"da\": \"Mellem\",\n        \"de\": \"Mittel\",\n        \"es\": \"Medio\",\n        \"fr\": \"Moyen\",\n        \"it\": \"Medio\",\n        \"no\": \"Middels\",\n        \"sv\": \"Mellan\",\n        \"pl\": \"Średni\",\n        \"ru\": \"Средний\",\n        \"ko\": \"중간\"\n      }\n    },\n    {\n      \"id\": \"4\",\n      \"title\": {\n        \"en\": \"Turbo\",\n        \"nl\": \"Turbo\",\n        \"da\": \"Turbo\",\n        \"de\": \"Turbo\",\n        \"es\": \"Turbo\",\n        \"fr\": \"Turbo\",\n        \"it\": \"Turbo\",\n        \"no\": \"Turbo\",\n        \"sv\": \"Turbo\",\n        \"pl\": \"Turbo\",\n        \"ru\": \"Турбо\",\n        \"ko\": \"터보\"\n      }\n    },\n    {\n      \"id\": \"5\",\n      \"title\": {\n        \"en\": \"Max\",\n        \"nl\": \"Max\",\n        \"da\": \"Maks\",\n        \"de\": \"Max\",\n        \"es\": \"Máximo\",\n        \"fr\": \"Max\",\n        \"it\": \"Massimo\",\n        \"no\": \"Maks\",\n        \"sv\": \"Max\",\n        \"pl\": \"Maks\",\n        \"ru\": \"Макс\",\n        \"ko\": \"최대\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/fanlevel.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_roborock_mop_intensity.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mop Intensity\",\n    \"nl\": \"Dweil intensiteit\",\n    \"da\": \"Mop intensitet\",\n    \"de\": \"Wischintensität\",\n    \"es\": \"Intensidad de fregado\",\n    \"fr\": \"Intensité du nettoyage\",\n    \"it\": \"Intensità di pulizia\",\n    \"no\": \"Mop intesitet\",\n    \"sv\": \"Moppens intensitet\",\n    \"pl\": \"Intensywność mopowania\",\n    \"ru\": \"Интенсивность мытья\",\n    \"ko\": \"걸레질 강도\"\n  },\n  \"values\": [\n    {\n      \"id\": \"200\",\n      \"title\": {\n        \"en\": \"Off\",\n        \"nl\": \"Uit\",\n        \"da\": \"Slukket\",\n        \"de\": \"Aus\",\n        \"es\": \"Apagado\",\n        \"fr\": \"Éteint\",\n        \"it\": \"Spento\",\n        \"no\": \"Av\",\n        \"sv\": \"Av\",\n        \"pl\": \"Wyłączone\",\n        \"ru\": \"Выкл\",\n        \"ko\": \"꺼짐\"\n      }\n    },\n    {\n      \"id\": \"201\",\n      \"title\": {\n        \"en\": \"Mild\",\n        \"nl\": \"Mild\",\n        \"da\": \"Let\",\n        \"de\": \"Mild\",\n        \"es\": \"Suave\",\n        \"fr\": \"Doux\",\n        \"it\": \"Leggero\",\n        \"no\": \"Mild\",\n        \"sv\": \"Mild\",\n        \"pl\": \"Łagodny\",\n        \"ru\": \"Слабый\",\n        \"ko\": \"약한\"\n      }\n    },\n    {\n      \"id\": \"202\",\n      \"title\": {\n        \"en\": \"Moderate\",\n        \"nl\": \"Gemiddeld\",\n        \"da\": \"Moderat\",\n        \"de\": \"Mittel\",\n        \"es\": \"Moderado\",\n        \"fr\": \"Modéré\",\n        \"it\": \"Moderato\",\n        \"no\": \"Moderat\",\n        \"sv\": \"Medel\",\n        \"pl\": \"Umiarkowany\",\n        \"ru\": \"Средний\",\n        \"ko\": \"보통\"\n      }\n    },\n    {\n      \"id\": \"203\",\n      \"title\": {\n        \"en\": \"Intense\",\n        \"nl\": \"Intens\",\n        \"da\": \"Intens\",\n        \"de\": \"Intensiv\",\n        \"es\": \"Intenso\",\n        \"fr\": \"Intense\",\n        \"it\": \"Intenso\",\n        \"no\": \"Intens\",\n        \"sv\": \"Intensiv\",\n        \"pl\": \"Intensywny\",\n        \"ru\": \"Сильный\",\n        \"ko\": \"강한\"\n      }\n    },\n    {\n      \"id\": \"204\",\n      \"title\": {\n        \"en\": \"Unknown mop intensity\",\n        \"nl\": \"Unknown mop intensity\",\n        \"da\": \"Ukendt mop intensitet\",\n        \"de\": \"Unbekannte Wischintensität\",\n        \"es\": \"Intensidad de fregado desconocida\",\n        \"fr\": \"Intensité de nettoyage inconnue\",\n        \"it\": \"Intensità di pulizia sconosciuta\",\n        \"no\": \"Ukjent mop intesitet\",\n        \"sv\": \"Okänd moppens intensitet\",\n        \"pl\": \"Nieznana intensywność mopowania\",\n        \"ru\": \"Неизвестная интенсивность мытья\",\n        \"ko\": \"알 수 없는 걸레질 강도\"\n      }\n    },\n    {\n      \"id\": \"207\",\n      \"title\": {\n        \"en\": \"Unknown mop intensity\",\n        \"nl\": \"Unknown mop intensity\",\n        \"da\": \"Ukendt mop intensitet\",\n        \"de\": \"Unbekannte Wischintensität\",\n        \"es\": \"Intensidad de fregado desconocida\",\n        \"fr\": \"Intensité de nettoyage inconnue\",\n        \"it\": \"Intensità di pulizia sconosciuta\",\n        \"no\": \"Ukjent mop intesitet\",\n        \"sv\": \"Okänd moppens intensitet\",\n        \"pl\": \"Nieznana intensywność mopowania\",\n        \"ru\": \"Неизвестная интенсивность мытья\",\n        \"ko\": \"알 수 없는 걸레질 강도\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/mopintensity.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_roidmi_fanspeed.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Fanspeed\",\n    \"nl\": \"Fanspeed\",\n    \"da\": \"Blæserhastighed\",\n    \"de\": \"Lüftergeschwindigkeit\",\n    \"es\": \"Velocidad del ventilador\",\n    \"fr\": \"Vitesse du ventilateur\",\n    \"it\": \"Velocità della ventola\",\n    \"no\": \"Viftehastighet\",\n    \"sv\": \"Fläkthastighet\",\n    \"pl\": \"Prędkość wentylatora\",\n    \"ru\": \"Скорость вентилятора\",\n    \"ko\": \"팬 속도\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Sweep\",\n        \"nl\": \"Sweep\",\n        \"da\": \"Sweep\",\n        \"de\": \"Sweep\",\n        \"es\": \"Sweep\",\n        \"fr\": \"Sweep\",\n        \"it\": \"Sweep\",\n        \"no\": \"Sweep\",\n        \"sv\": \"Sweep\",\n        \"pl\": \"Sweep\",\n        \"ru\": \"Sweep\",\n        \"ko\": \"Sweep\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Silent\",\n        \"nl\": \"Stil\",\n        \"da\": \"Stille\",\n        \"de\": \"Leise\",\n        \"es\": \"Silencioso\",\n        \"fr\": \"Silencieux\",\n        \"it\": \"Silenzioso\",\n        \"no\": \"Stille\",\n        \"sv\": \"Tyst\",\n        \"pl\": \"Cichy\",\n        \"ru\": \"Тихий\",\n        \"ko\": \"조용한\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Basic\",\n        \"nl\": \"Basis\",\n        \"da\": \"Grundlæggende\",\n        \"de\": \"Basis\",\n        \"es\": \"Básico\",\n        \"fr\": \"De base\",\n        \"it\": \"Base\",\n        \"no\": \"Grunnleggende\",\n        \"sv\": \"Grundläggande\",\n        \"pl\": \"Podstawowe\",\n        \"ru\": \"Основной\",\n        \"ko\": \"기본\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Strong\",\n        \"nl\": \"Sterk\",\n        \"da\": \"Stærk\",\n        \"de\": \"Stark\",\n        \"es\": \"Fuerte\",\n        \"fr\": \"Fort\",\n        \"it\": \"Forte\",\n        \"no\": \"Sterk\",\n        \"sv\": \"Stark\",\n        \"pl\": \"Silny\",\n        \"ru\": \"Сильный\",\n        \"ko\": \"강한\"\n      }\n    },\n    {\n      \"id\": \"4\",\n      \"title\": {\n        \"en\": \"Full speed\",\n        \"nl\": \"Volle snelheid\",\n        \"da\": \"Fuld fart\",\n        \"de\": \"Volle Geschwindigkeit\",\n        \"es\": \"Velocidad máxima\",\n        \"fr\": \"Pleine vitesse\",\n        \"it\": \"Piena velocità\",\n        \"no\": \"Full fart\",\n        \"sv\": \"Full fart\",\n        \"pl\": \"Pełna prędkość\",\n        \"ru\": \"Полная скорость\",\n        \"ko\": \"최고 속도\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/fanlevel.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_roidmi_mop_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Sweep and Mop Mode\",\n    \"nl\": \"Sweep and Mop modus\",\n    \"da\": \"Feje- og mopningstilstand\",\n    \"de\": \"Kehr- und Wischmodus\",\n    \"es\": \"Modo de barrido y fregado\",\n    \"fr\": \"Mode balayage et vadrouille\",\n    \"it\": \"Modalità spazzare e pulire\",\n    \"no\": \"Feie- og moppemodus\",\n    \"sv\": \"Sop- och moppningsläge\",\n    \"pl\": \"Tryb zamiatania i mopowania\",\n    \"ru\": \"Режим подметания и мытья полов\",\n    \"ko\": \"쓸기 및 물기 모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Sweep\",\n        \"nl\": \"Sweep\",\n        \"da\": \"Feje\",\n        \"de\": \"Kehren\",\n        \"es\": \"Barrer\",\n        \"fr\": \"Balayer\",\n        \"it\": \"Spazzare\",\n        \"no\": \"Feie\",\n        \"sv\": \"Sopa\",\n        \"pl\": \"Zamiatanie\",\n        \"ru\": \"Подметание\",\n        \"ko\": \"쓸기\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Mop\",\n        \"nl\": \"Mop\",\n        \"da\": \"Moppe\",\n        \"de\": \"Wischen\",\n        \"es\": \"Fregar\",\n        \"fr\": \"Passer la serpillière\",\n        \"it\": \"Pulire\",\n        \"no\": \"Moppe\",\n        \"sv\": \"Moppa\",\n        \"pl\": \"Mopowanie\",\n        \"ru\": \"Мытьё полов\",\n        \"ko\": \"물기\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Mop & Sweep\",\n        \"nl\": \"Mop & Sweep\",\n        \"da\": \"Moppe & Feje\",\n        \"de\": \"Wischen & Kehren\",\n        \"es\": \"Fregar y Barrer\",\n        \"fr\": \"Vadrouille et Balayage\",\n        \"it\": \"Pulire e Spazzare\",\n        \"no\": \"Moppe og Feie\",\n        \"sv\": \"Moppa & Sopa\",\n        \"pl\": \"Mopowanie i zamiatanie\",\n        \"ru\": \"Мытьё полов и подметание\",\n        \"ko\": \"물기 및 쓸기\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/vacuum-mop.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_roidmi_waterlevel.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Fanspeed\",\n    \"nl\": \"Fanspeed\",\n    \"da\": \"Blæserhastighed\",\n    \"de\": \"Lüftergeschwindigkeit\",\n    \"es\": \"Velocidad del ventilador\",\n    \"fr\": \"Vitesse du ventilateur\",\n    \"it\": \"Velocità della ventola\",\n    \"no\": \"Viftehastighet\",\n    \"sv\": \"Fläkthastighet\",\n    \"pl\": \"Prędkość wentylatora\",\n    \"ru\": \"Скорость вентилятора\",\n    \"ko\": \"팬 속도\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Mop\",\n        \"nl\": \"Mop\",\n        \"da\": \"Mop\",\n        \"de\": \"Mop\",\n        \"es\": \"Mopa\",\n        \"fr\": \"Serpillère\",\n        \"it\": \"Mop\",\n        \"no\": \"Mopp\",\n        \"sv\": \"Mopp\",\n        \"pl\": \"Mop\",\n        \"ru\": \"Швабра\",\n        \"ko\": \"걸레\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"First\",\n        \"nl\": \"Eerste\",\n        \"da\": \"Første\",\n        \"de\": \"Erste\",\n        \"es\": \"Primero\",\n        \"fr\": \"Premier\",\n        \"it\": \"Primo\",\n        \"no\": \"Første\",\n        \"sv\": \"Första\",\n        \"pl\": \"Pierwszy\",\n        \"ru\": \"Первый\",\n        \"ko\": \"첫번째\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Second\",\n        \"nl\": \"Tweede\",\n        \"da\": \"Anden\",\n        \"de\": \"Zweite\",\n        \"es\": \"Segundo\",\n        \"fr\": \"Deuxième\",\n        \"it\": \"Secondo\",\n        \"no\": \"Andre\",\n        \"sv\": \"Andra\",\n        \"pl\": \"Drugi\",\n        \"ru\": \"Второй\",\n        \"ko\": \"두번째\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Third\",\n        \"nl\": \"Derde\",\n        \"da\": \"Tredje\",\n        \"de\": \"Dritte\",\n        \"es\": \"Tercero\",\n        \"fr\": \"Troisième\",\n        \"it\": \"Terzo\",\n        \"no\": \"Tredje\",\n        \"sv\": \"Tredje\",\n        \"pl\": \"Trzeci\",\n        \"ru\": \"Третий\",\n        \"ko\": \"세번째\"\n      }\n    },\n    {\n      \"id\": \"4\",\n      \"title\": {\n        \"en\": \"Fourth\",\n        \"nl\": \"Vierde\",\n        \"da\": \"Fjerde\",\n        \"de\": \"Vierte\",\n        \"es\": \"Cuarto\",\n        \"fr\": \"Quatrième\",\n        \"it\": \"Quarto\",\n        \"no\": \"Fjerde\",\n        \"sv\": \"Fjärde\",\n        \"pl\": \"Czwarty\",\n        \"ru\": \"Четвертый\",\n        \"ko\": \"네번째\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": false,\n  \"icon\": \"/assets/icons/measure_waterlevel.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_viomi_mop_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Vacuum Mode\",\n    \"nl\": \"Stofzuiger modus\",\n    \"da\": \"Støvsugermodus\",\n    \"de\": \"Staubsaugermodus\",\n    \"es\": \"Modo de aspiradora\",\n    \"fr\": \"Mode aspirateur\",\n    \"it\": \"Modalità aspirapolvere\",\n    \"no\": \"Støvsugermodus\",\n    \"sv\": \"Dammsugarläge\",\n    \"pl\": \"Tryb odkurzacza\",\n    \"ru\": \"Режим пылесоса\",\n    \"ko\": \"진공 모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Vacuum\",\n        \"nl\": \"Stofzuigen\",\n        \"da\": \"Støvsuge\",\n        \"de\": \"Staubsaugen\",\n        \"es\": \"Aspirar\",\n        \"fr\": \"Aspirer\",\n        \"it\": \"Aspirare\",\n        \"no\": \"Støvsuge\",\n        \"sv\": \"Dammsuga\",\n        \"pl\": \"Odkurzać\",\n        \"ru\": \"Пылесосить\",\n        \"ko\": \"진공\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Vacuum + Mop\",\n        \"nl\": \"Stofzuigen + moppen\",\n        \"da\": \"Støvsuge + moppe\",\n        \"de\": \"Staubsaugen + Wischen\",\n        \"es\": \"Aspirar + Trapear\",\n        \"fr\": \"Aspirer + Passer la serpillière\",\n        \"it\": \"Aspirare + Lavare\",\n        \"no\": \"Støvsuge + moppe\",\n        \"sv\": \"Dammsuga + moppa\",\n        \"pl\": \"Odkurzać + Mopować\",\n        \"ru\": \"Пылесосить + Мыть\",\n        \"ko\": \"진공 + 걸레질\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Mop\",\n        \"nl\": \"Moppen\",\n        \"da\": \"Moppe\",\n        \"de\": \"Wischen\",\n        \"es\": \"Trapear\",\n        \"fr\": \"Passer la serpillière\",\n        \"it\": \"Lavare\",\n        \"no\": \"Moppe\",\n        \"sv\": \"Moppa\",\n        \"pl\": \"Mopować\",\n        \"ru\": \"Мыть\",\n        \"ko\": \"걸레질\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/vacuum-mop.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_xiaomi_carpet_mode_max.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Carpet avoidance\",\n    \"nl\": \"Tapijt vermijden\",\n    \"de\": \"Teppichvermeidung\",\n    \"da\": \"Undgå tæpper\",\n    \"es\": \"Evitar alfombras\",\n    \"fr\": \"Éviter les tapis\",\n    \"it\": \"Evitamento tappeti\",\n    \"no\": \"Unngå tepper\",\n    \"sv\": \"Undvik mattor\",\n    \"pl\": \"Unikanie dywanów\",\n    \"ru\": \"Избегание ковров\",\n    \"ko\": \"카펫 회피\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Self Adaptation\",\n        \"nl\": \"Zelfaanpassing\",\n        \"de\": \"Selbstanpassung\",\n        \"da\": \"Selvtilpasning\",\n        \"es\": \"Auto adaptación\",\n        \"fr\": \"Auto-adaptation\",\n        \"it\": \"Auto adattamento\",\n        \"no\": \"Selvtilpasning\",\n        \"sv\": \"Självanpassning\",\n        \"pl\": \"Samodopasowanie\",\n        \"ru\": \"Самоадаптация\",\n        \"ko\": \"자동 적응\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Avoid\",\n        \"nl\": \"Vermijden\",\n        \"de\": \"Vermeiden\",\n        \"da\": \"Undgå\",\n        \"es\": \"Evitar\",\n        \"fr\": \"Éviter\",\n        \"it\": \"Evita\",\n        \"no\": \"Unngå\",\n        \"sv\": \"Undvik\",\n        \"pl\": \"Unikaj\",\n        \"ru\": \"Избегать\",\n        \"ko\": \"회피\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Ignore\",\n        \"nl\": \"Negeren\",\n        \"de\": \"Ignorieren\",\n        \"da\": \"Ignorer\",\n        \"es\": \"Ignorar\",\n        \"fr\": \"Ignorer\",\n        \"it\": \"Ignora\",\n        \"no\": \"Ignorer\",\n        \"sv\": \"Ignorera\",\n        \"pl\": \"Ignoruj\",\n        \"ru\": \"Игнорировать\",\n        \"ko\": \"무시\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Span\",\n        \"nl\": \"Span\",\n        \"de\": \"Span\",\n        \"da\": \"Span\",\n        \"es\": \"Span\",\n        \"fr\": \"Span\",\n        \"it\": \"Span\",\n        \"no\": \"Span\",\n        \"sv\": \"Span\",\n        \"pl\": \"Span\",\n        \"ru\": \"Span\",\n        \"ko\": \"Span\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true\n}\n"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_xiaomi_cleaning_mode_max.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Cleaning Power\",\n    \"nl\": \"Reinigingskracht\",\n    \"de\": \"Reinigungsleistung\",\n    \"da\": \"Rengøringskraft\",\n    \"es\": \"Potencia de limpieza\",\n    \"fr\": \"Pouvoir de nettoyage\",\n    \"it\": \"Potenza di pulizia\",\n    \"no\": \"Rengjøringskraft\",\n    \"sv\": \"Rengöringskraft\",\n    \"pl\": \"Moc czyszczenia\",\n    \"ru\": \"Сила очистки\",\n    \"ko\": \"청소 능력\"\n  },\n  \"values\": [\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Silent\",\n        \"nl\": \"Stil\",\n        \"de\": \"Leise\",\n        \"da\": \"Stille\",\n        \"es\": \"Silencioso\",\n        \"fr\": \"Silencieux\",\n        \"it\": \"Silenzioso\",\n        \"no\": \"Stille\",\n        \"sv\": \"Tyst\",\n        \"pl\": \"Cichy\",\n        \"ru\": \"Тихий\",\n        \"ko\": \"조용한\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Standard\",\n        \"nl\": \"Standaard\",\n        \"de\": \"Standard\",\n        \"da\": \"Standard\",\n        \"es\": \"Estándar\",\n        \"fr\": \"Standard\",\n        \"it\": \"Standard\",\n        \"no\": \"Standard\",\n        \"sv\": \"Standard\",\n        \"pl\": \"Standardowy\",\n        \"ru\": \"Стандартный\",\n        \"ko\": \"표준\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Strong\",\n        \"nl\": \"Sterk\",\n        \"de\": \"Stark\",\n        \"da\": \"Stærk\",\n        \"es\": \"Fuerte\",\n        \"fr\": \"Fort\",\n        \"it\": \"Forte\",\n        \"no\": \"Sterk\",\n        \"sv\": \"Stark\",\n        \"pl\": \"Silny\",\n        \"ru\": \"Сильный\",\n        \"ko\": \"강한\"\n      }\n    },\n    {\n      \"id\": \"4\",\n      \"title\": {\n        \"en\": \"Turbo\",\n        \"nl\": \"Turbo\",\n        \"de\": \"Turbo\",\n        \"da\": \"Turbo\",\n        \"es\": \"Turbo\",\n        \"fr\": \"Turbo\",\n        \"it\": \"Turbo\",\n        \"no\": \"Turbo\",\n        \"sv\": \"Turbo\",\n        \"pl\": \"Turbo\",\n        \"ru\": \"Турбо\",\n        \"ko\": \"터보\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/fanlevel.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_xiaomi_detergent_left_level.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Water left (%)\",\n    \"nl\": \"Overgebleven water (%)\",\n    \"da\": \"Resterende vand (%)\",\n    \"de\": \"Verbleibendes Wasser (%)\",\n    \"es\": \"Agua restante (%)\",\n    \"fr\": \"Eau restante (%)\",\n    \"it\": \"Acqua rimasta (%)\",\n    \"no\": \"Vann igjen (%)\",\n    \"sv\": \"Vatten kvar (%)\",\n    \"pl\": \"Pozostała woda (%)\",\n    \"ru\": \"Остаток воды (%)\",\n    \"ko\": \"남은 물 (%)\"\n  },\n  \"type\": \"number\",\n  \"getable\": true,\n  \"setable\": false,\n  \"units\": {\n    \"en\": \"%\",\n    \"nl\": \"%\",\n    \"da\": \"%\",\n    \"de\": \"%\",\n    \"es\": \"%\",\n    \"fr\": \"%\",\n    \"it\": \"%\",\n    \"no\": \"%\",\n    \"sv\": \"%\",\n    \"pl\": \"%\",\n    \"ru\": \"%\",\n    \"ko\": \"%\"\n  },\n  \"uiComponent\": \"sensor\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_xiaomi_dust_bag_left_level.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Dust bag left (%)\",\n    \"nl\": \"Stofzak over (%)\",\n    \"da\": \"Støvsugerpose tilbage (%)\",\n    \"de\": \"Staubbeutel verbleibend (%)\",\n    \"es\": \"Bolsa de polvo restante (%)\",\n    \"fr\": \"Sac à poussière restant (%)\",\n    \"it\": \"Sacchetto della polvere rimasto (%)\",\n    \"no\": \"Støvsekk igjen (%)\",\n    \"sv\": \"Dammsugarpåse kvar (%)\",\n    \"pl\": \"Pozostało worka na kurz (%)\",\n    \"ru\": \"Осталось пылесборника (%)\",\n    \"ko\": \"먼지 봉투 남음 (%)\"\n  },\n  \"type\": \"number\",\n  \"getable\": true,\n  \"setable\": false,\n  \"units\": {\n    \"en\": \"%\",\n    \"nl\": \"%\",\n    \"da\": \"%\",\n    \"de\": \"%\",\n    \"es\": \"%\",\n    \"fr\": \"%\",\n    \"it\": \"%\",\n    \"no\": \"%\",\n    \"sv\": \"%\",\n    \"pl\": \"%\",\n    \"ru\": \"%\",\n    \"ko\": \"%\"\n  },\n  \"uiComponent\": \"sensor\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_xiaomi_mop_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Sweep and Mop Mode\",\n    \"nl\": \"Sweep and Mop modus\",\n    \"da\": \"Feje og Moppe Tilstand\",\n    \"de\": \"Kehr- und Wischmodus\",\n    \"es\": \"Modo Barrer y Trapear\",\n    \"fr\": \"Mode Balayage et Lavage\",\n    \"it\": \"Modalità Spazza e Passa\",\n    \"no\": \"Feie- og Moppemodus\",\n    \"sv\": \"Sopa och Mopp-läge\",\n    \"pl\": \"Tryb zamiatania i mopowania\",\n    \"ru\": \"Режим подметания и мытья\",\n    \"ko\": \"청소 및 물걸레 모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Sweep\",\n        \"nl\": \"Sweep\",\n        \"da\": \"Feje\",\n        \"de\": \"Kehren\",\n        \"es\": \"Barrer\",\n        \"fr\": \"Balayer\",\n        \"it\": \"Spazza\",\n        \"no\": \"Feie\",\n        \"sv\": \"Sopa\",\n        \"pl\": \"Zamiatać\",\n        \"ru\": \"Подметать\",\n        \"ko\": \"청소\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Sweep & Mop\",\n        \"nl\": \"Sweep & Mop\",\n        \"da\": \"Feje & Moppe\",\n        \"de\": \"Kehren & Wischen\",\n        \"es\": \"Barrer y Trapear\",\n        \"fr\": \"Balayer & Laver\",\n        \"it\": \"Spazza & Passa\",\n        \"no\": \"Feie & Moppe\",\n        \"sv\": \"Sopa & Mopp\",\n        \"pl\": \"Zamiatać i mopować\",\n        \"ru\": \"Подметать и мыть\",\n        \"ko\": \"청소 및 물걸레질\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Mop\",\n        \"nl\": \"Mop\",\n        \"da\": \"Moppe\",\n        \"de\": \"Wischen\",\n        \"es\": \"Trapear\",\n        \"fr\": \"Laver\",\n        \"it\": \"Passa\",\n        \"no\": \"Moppe\",\n        \"sv\": \"Mopp\",\n        \"pl\": \"Mopować\",\n        \"ru\": \"Мыть\",\n        \"ko\": \"물걸레질\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/vacuum-mop.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_xiaomi_mop_mode_max.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Sweep & Mop Mode\",\n    \"it\": \"Modalità Spazza e Passa\",\n    \"no\": \"Feie- og Moppemodus\",\n    \"sv\": \"Sopa och Mopp-läge\",\n    \"pl\": \"Tryb zamiatania i mopowania\",\n    \"ru\": \"Режим подметания и мытья\",\n    \"ko\": \"청소 및 물걸레 모드\",\n    \"nl\": \"Vegen en Dweilen modus\",\n    \"da\": \"Fej & Moppe tilstand\",\n    \"de\": \"Kehren & Wischen Modus\",\n    \"es\": \"Modo Barrer y Trapear\",\n    \"fr\": \"Mode Balayer & Laver\"\n  },\n  \"values\": [\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Sweep\",\n        \"nl\": \"Sweep\",\n        \"da\": \"Feje\",\n        \"de\": \"Kehren\",\n        \"es\": \"Barrer\",\n        \"fr\": \"Balayer\",\n        \"it\": \"Spazza\",\n        \"no\": \"Feie\",\n        \"sv\": \"Sopa\",\n        \"pl\": \"Zamiatać\",\n        \"ru\": \"Подметать\",\n        \"ko\": \"청소\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Mop\",\n        \"nl\": \"Mop\",\n        \"da\": \"Moppe\",\n        \"de\": \"Wischen\",\n        \"es\": \"Trapear\",\n        \"fr\": \"Laver\",\n        \"it\": \"Passa\",\n        \"no\": \"Moppe\",\n        \"sv\": \"Mopp\",\n        \"pl\": \"Mopować\",\n        \"ru\": \"Мыть\",\n        \"ko\": \"물걸레질\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Sweep & Mop\",\n        \"nl\": \"Sweep & Mop\",\n        \"da\": \"Feje & Moppe\",\n        \"de\": \"Kehren & Wischen\",\n        \"es\": \"Barrer y Trapear\",\n        \"fr\": \"Balayer & Laver\",\n        \"it\": \"Spazza & Passa\",\n        \"no\": \"Feie & Moppe\",\n        \"sv\": \"Sopa & Mopp\",\n        \"pl\": \"Zamiatać i mopować\",\n        \"ru\": \"Подметать и мыть\",\n        \"ko\": \"청소 및 물걸레질\"\n      }\n    },\n    {\n      \"id\": \"4\",\n      \"title\": {\n        \"en\": \"Sweep Before Mopping\",\n        \"nl\": \"Vegen voor Dweilen\",\n        \"da\": \"Fej før mopning\",\n        \"de\": \"Kehren vor dem Wischen\",\n        \"es\": \"Barrer antes de trapear\",\n        \"fr\": \"Balayer avant de laver\",\n        \"it\": \"Spazza prima di passare\",\n        \"no\": \"Feie før mopping\",\n        \"sv\": \"Sopa före moppning\",\n        \"pl\": \"Zamiataj przed mopowaniem\",\n        \"ru\": \"Подметать перед мытьём\",\n        \"ko\": \"물걸레질 전 청소\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/vacuum-mop.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_xiaomi_path_mode_max.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Path Mode\",\n    \"nl\": \"Padmodus\",\n    \"de\": \"Pfadmodus\",\n    \"da\": \"Sti mode\",\n    \"es\": \"Modo de ruta\",\n    \"fr\": \"Mode chemin\",\n    \"it\": \"Modalità percorso\",\n    \"no\": \"Bane modus\",\n    \"sv\": \"Sätt för väg\",\n    \"pl\": \"Tryb ścieżki\",\n    \"ru\": \"Режим пути\",\n    \"ko\": \"경로 모드\"\n  },\n  \"values\": [\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Quick\",\n        \"nl\": \"Snel\",\n        \"de\": \"Schnell\",\n        \"da\": \"Hurtig\",\n        \"es\": \"Rápido\",\n        \"fr\": \"Rapide\",\n        \"it\": \"Veloce\",\n        \"no\": \"Rask\",\n        \"sv\": \"Snabb\",\n        \"pl\": \"Szybki\",\n        \"ru\": \"Быстрый\",\n        \"ko\": \"빠른\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Standard\",\n        \"nl\": \"Standaard\",\n        \"de\": \"Standard\",\n        \"da\": \"Standard\",\n        \"es\": \"Estándar\",\n        \"fr\": \"Standard\",\n        \"it\": \"Standard\",\n        \"no\": \"Standard\",\n        \"sv\": \"Standard\",\n        \"pl\": \"Standard\",\n        \"ru\": \"Стандарт\",\n        \"ko\": \"표준\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Deep\",\n        \"nl\": \"Diep\",\n        \"de\": \"Tief\",\n        \"da\": \"Dyb\",\n        \"es\": \"Profundo\",\n        \"fr\": \"Profond\",\n        \"it\": \"Profondo\",\n        \"no\": \"Dyp\",\n        \"sv\": \"Djupt\",\n        \"pl\": \"Głęboki\",\n        \"ru\": \"Глубокий\",\n        \"ko\": \"깊은\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/vacuum-path-mode.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_xiaomi_status.json",
    "content": "{\n  \"type\": \"string\",\n  \"title\": {\n    \"en\": \"Status / error\",\n    \"nl\": \"Status / fout\",\n    \"da\": \"Status / fejl\",\n    \"de\": \"Status / Fehler\",\n    \"es\": \"Estado / error\",\n    \"fr\": \"Statut / erreur\",\n    \"it\": \"Stato / errore\",\n    \"no\": \"Status / feil\",\n    \"sv\": \"Status / fel\",\n    \"pl\": \"Status / błąd\",\n    \"ru\": \"Статус / ошибка\",\n    \"ko\": \"상태 / 오류\"\n  },\n  \"getable\": true,\n  \"setable\": false,\n  \"insights\": false,\n  \"icon\": \"/assets/icons/alarm_generic.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/vacuum_xiaomi_water_level_max.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Water Output\",\n    \"nl\": \"Wateroutput\",\n    \"de\": \"Wasserausgabe\",\n    \"es\": \"Salida de Agua\",\n    \"fr\": \"Sortie d'Eau\",\n    \"it\": \"Uscita dell'Acqua\",\n    \"da\": \"Vandoutput\",\n    \"no\": \"Vannutgang\",\n    \"sv\": \"Vattenutgång\",\n    \"pl\": \"Wydajność wody\",\n    \"ru\": \"Вывод воды\",\n    \"ko\": \"물 출력\"\n  },\n  \"values\": [\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Level 1\",\n        \"nl\": \"Niveau 1\",\n        \"de\": \"Stufe 1\",\n        \"es\": \"Nivel 1\",\n        \"fr\": \"Niveau 1\",\n        \"it\": \"Livello 1\",\n        \"da\": \"Niveau 1\",\n        \"no\": \"Nivå 1\",\n        \"sv\": \"Nivå 1\",\n        \"pl\": \"Poziom 1\",\n        \"ru\": \"Уровень 1\",\n        \"ko\": \"레벨 1\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Level 2\",\n        \"nl\": \"Niveau 2\",\n        \"de\": \"Stufe 2\",\n        \"es\": \"Nivel 2\",\n        \"fr\": \"Niveau 2\",\n        \"it\": \"Livello 2\",\n        \"da\": \"Niveau 2\",\n        \"no\": \"Nivå 2\",\n        \"sv\": \"Nivå 2\",\n        \"pl\": \"Poziom 2\",\n        \"ru\": \"Уровень 2\",\n        \"ko\": \"레벨 2\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Level 3\",\n        \"nl\": \"Niveau 3\",\n        \"de\": \"Stufe 3\",\n        \"es\": \"Nivel 3\",\n        \"fr\": \"Niveau 3\",\n        \"it\": \"Livello 3\",\n        \"da\": \"Niveau 3\",\n        \"no\": \"Nivå 3\",\n        \"sv\": \"Nivå 3\",\n        \"pl\": \"Poziom 3\",\n        \"ru\": \"Уровень 3\",\n        \"ko\": \"레벨 3\"\n      }\n    }\n  ],\n  \"getable\": true,\n  \"setable\": true,\n  \"icon\": \"/assets/icons/water-level.svg\"\n}"
  },
  {
    "path": ".homeycompose/capabilities/yeelight_ceil43_mode.json",
    "content": "{\n  \"type\": \"enum\",\n  \"title\": {\n    \"en\": \"Mode\",\n    \"nl\": \"Modus\",\n    \"da\": \"Tilstand\",\n    \"de\": \"Modus\",\n    \"es\": \"Modo\",\n    \"fr\": \"Mode\",\n    \"it\": \"Modalita\",\n    \"no\": \"Modus\",\n    \"sv\": \"Lage\",\n    \"pl\": \"Tryb\",\n    \"ru\": \"Режим\",\n    \"ko\": \"모드\"\n  },\n  \"getable\": true,\n  \"setable\": true,\n  \"uiComponent\": \"picker\",\n  \"values\": [\n    {\n      \"id\": \"0\",\n      \"title\": {\n        \"en\": \"Day\",\n        \"nl\": \"Dag\",\n        \"da\": \"Dag\",\n        \"de\": \"Tag\",\n        \"es\": \"Dia\",\n        \"fr\": \"Jour\",\n        \"it\": \"Giorno\",\n        \"no\": \"Dag\",\n        \"sv\": \"Dag\",\n        \"pl\": \"Dzien\",\n        \"ru\": \"День\",\n        \"ko\": \"주간\"\n      }\n    },\n    {\n      \"id\": \"1\",\n      \"title\": {\n        \"en\": \"Night\",\n        \"nl\": \"Nacht\",\n        \"da\": \"Nat\",\n        \"de\": \"Nacht\",\n        \"es\": \"Noche\",\n        \"fr\": \"Nuit\",\n        \"it\": \"Notte\",\n        \"no\": \"Natt\",\n        \"sv\": \"Natt\",\n        \"pl\": \"Noc\",\n        \"ru\": \"Ночь\",\n        \"ko\": \"야간\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"title\": {\n        \"en\": \"Color\",\n        \"nl\": \"Kleur\",\n        \"da\": \"Farve\",\n        \"de\": \"Farbe\",\n        \"es\": \"Color\",\n        \"fr\": \"Couleur\",\n        \"it\": \"Colore\",\n        \"no\": \"Farge\",\n        \"sv\": \"Farg\",\n        \"pl\": \"Kolor\",\n        \"ru\": \"Цвет\",\n        \"ko\": \"색상\"\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"title\": {\n        \"en\": \"Flow\",\n        \"nl\": \"Flow\",\n        \"da\": \"Flow\",\n        \"de\": \"Flow\",\n        \"es\": \"Flujo\",\n        \"fr\": \"Flux\",\n        \"it\": \"Flusso\",\n        \"no\": \"Flyt\",\n        \"sv\": \"Flode\",\n        \"pl\": \"Przeplyw\",\n        \"ru\": \"Поток\",\n        \"ko\": \"흐름\"\n      }\n    }\n  ],\n  \"icon\": \"/assets/icons/airpurifier-mode.svg\"\n}\n"
  },
  {
    "path": ".homeycompose/drivers/pair/add_device/index.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": ".homeycompose/drivers/pair/pair/index.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": ".homeycompose/drivers/pair/start/index.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": ".homeycompose/drivers/settings/address.json",
    "content": "{\n  \"id\": \"address\",\n  \"type\": \"text\",\n  \"value\": \"0.0.0.0\",\n  \"label\": {\n    \"en\": \"IP Address\",\n    \"nl\": \"IP adres\",\n    \"da\": \"IP-adresse\",\n    \"de\": \"IP-Adresse\",\n    \"es\": \"Dirección IP\",\n    \"fr\": \"Adresse IP\",\n    \"it\": \"Indirizzo IP\",\n    \"no\": \"IP-adresse\",\n    \"sv\": \"IP-adress\",\n    \"pl\": \"Adres IP\",\n    \"ru\": \"IP-адрес\",\n    \"ko\": \"IP 주소\"\n  }\n}"
  },
  {
    "path": ".homeycompose/drivers/settings/deviceSid.json",
    "content": "{\n  \"id\": \"deviceSid\",\n  \"type\": \"label\",\n  \"value\": \"0123456789abcd\",\n  \"label\": {\n    \"en\": \"Device SID\",\n    \"nl\": \"Apparaat SID\",\n    \"da\": \"Enhed SID\",\n    \"de\": \"Gerät SID\",\n    \"es\": \"Dispositivo SID\",\n    \"fr\": \"Appareil SID\",\n    \"it\": \"Dispositivo SID\",\n    \"no\": \"Enhet SID\",\n    \"sv\": \"Enhet SID\",\n    \"pl\": \"Urządzenie SID\",\n    \"ru\": \"Устройство SID\",\n    \"ko\": \"장치 SID\"\n  }\n}"
  },
  {
    "path": ".homeycompose/drivers/settings/gatewaySid.json",
    "content": "{\n  \"id\": \"gatewaySid\",\n  \"type\": \"label\",\n  \"value\": \"0123456789ab\",\n  \"label\": {\n    \"en\": \"Gateway SID\",\n    \"nl\": \"Gateway SID\",\n    \"da\": \"Gateway SID\",\n    \"de\": \"Gateway SID\",\n    \"es\": \"Gateway SID\",\n    \"fr\": \"Gateway SID\",\n    \"it\": \"Gateway SID\",\n    \"no\": \"Gateway SID\",\n    \"sv\": \"Gateway SID\",\n    \"pl\": \"Gateway SID\",\n    \"ru\": \"Gateway SID\",\n    \"ko\": \"Gateway SID\"\n  }\n}"
  },
  {
    "path": ".homeycompose/drivers/settings/model.json",
    "content": "{\n  \"id\": \"model\",\n  \"type\": \"label\",\n  \"value\": \"lumi.device\",\n  \"label\": {\n    \"en\": \"Model\",\n    \"nl\": \"Model\",\n    \"da\": \"Model\",\n    \"de\": \"Modell\",\n    \"es\": \"Modelo\",\n    \"fr\": \"Modèle\",\n    \"it\": \"Modello\",\n    \"no\": \"Modell\",\n    \"sv\": \"Modell\",\n    \"pl\": \"Model\",\n    \"ru\": \"Модель\",\n    \"ko\": \"모델\"\n  }\n}"
  },
  {
    "path": ".homeycompose/drivers/settings/modelCode.json",
    "content": "{\n  \"id\": \"modelCode\",\n  \"type\": \"label\",\n  \"value\": \"AABBCC01LM\",\n  \"label\": {\n    \"en\": \"Device Model Code\",\n    \"nl\": \"Apparaat modelcode\",\n    \"da\": \"Enhedsmodelkode\",\n    \"de\": \"Gerätemodellcode\",\n    \"es\": \"Código de modelo del dispositivo\",\n    \"fr\": \"Code modèle de l'appareil\",\n    \"it\": \"Codice modello del dispositivo\",\n    \"no\": \"Enhetsmodellkode\",\n    \"sv\": \"Enhetsmodellkod\",\n    \"pl\": \"Kod modelu urządzenia\",\n    \"ru\": \"Код модели устройства\",\n    \"ko\": \"장치 모델 코드\"\n  }\n}"
  },
  {
    "path": ".homeycompose/drivers/settings/polling.json",
    "content": "{\n  \"id\": \"polling\",\n  \"type\": \"number\",\n  \"value\": 60,\n  \"attr\": {\n    \"min\": 5,\n    \"max\": 3600\n  },\n  \"label\": {\n    \"en\": \"Polling Frequency\",\n    \"nl\": \"Polling frequentie\",\n    \"da\": \"Polling Frekvens\",\n    \"de\": \"Abfragefrequenz\",\n    \"es\": \"Frecuencia de sondeo\",\n    \"fr\": \"Fréquence de sondage\",\n    \"it\": \"Frequenza di polling\",\n    \"no\": \"Polling Frekvens\",\n    \"sv\": \"Pollingfrekvens\",\n    \"pl\": \"Częstotliwość odpytywania\",\n    \"ru\": \"Частота опроса\",\n    \"ko\": \"폴링 빈도\"\n  }\n}"
  },
  {
    "path": ".homeycompose/drivers/settings/token.json",
    "content": "{\n  \"id\": \"token\",\n  \"type\": \"text\",\n  \"value\": \"\",\n  \"label\": {\n    \"en\": \"Mi Device Token\",\n    \"nl\": \"Mi Apparaat Token\",\n    \"da\": \"Mi Enheds Token\",\n    \"de\": \"Mi Gerätetoken\",\n    \"es\": \"Token del Dispositivo Mi\",\n    \"fr\": \"Jeton de l'Appareil Mi\",\n    \"it\": \"Token Dispositivo Mi\",\n    \"no\": \"Mi Enhet Token\",\n    \"sv\": \"Mi Enhetstoken\",\n    \"pl\": \"Token Urządzenia Mi\",\n    \"ru\": \"Токен Устройства Mi\",\n    \"ko\": \"Mi 기기 토큰\"\n  }\n}"
  },
  {
    "path": ".homeycompose/drivers/templates/defaults.json",
    "content": "{\n  \"icon\": \"{{driverAssetsPath}}/icon.svg\",\n  \"pair\": [\n    {\n      \"id\": \"start\",\n      \"$template\": \"start\",\n      \"navigation\": {\n        \"next\": \"pair\"\n      }\n    },\n    {\n      \"id\": \"pair\",\n      \"$template\": \"pair\"\n    },\n    {\n      \"id\": \"add_device\",\n      \"$template\": \"add_device\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ],\n  \"connectivity\": [\n    \"lan\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/drivers/templates/defaults_subdevice.json",
    "content": "{\n  \"icon\": \"{{driverAssetsPath}}/icon.svg\",\n  \"pair\": [\n    {\n      \"id\": \"list_devices\",\n      \"template\": \"list_devices\",\n      \"navigation\": {\n        \"next\": \"add_devices\"\n      },\n      \"options\": {\n        \"singular\": false\n      }\n    },\n    {\n      \"id\": \"add_devices\",\n      \"template\": \"add_devices\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ],\n  \"connectivity\": [\n    \"lan\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/airpurifierSetFavorite.json",
    "content": "{\n  \"id\": \"airpurifierSetFavorite\",\n  \"title\": {\n    \"en\": \"Set Favorite Speed\",\n    \"nl\": \"Favoriete snelheid instellen\",\n    \"da\": \"Indstil favorit hastighed\",\n    \"de\": \"Lieblingsgeschwindigkeit einstellen\",\n    \"es\": \"Establecer velocidad favorita\",\n    \"fr\": \"Définir la vitesse favorite\",\n    \"it\": \"Imposta velocità preferita\",\n    \"no\": \"Sett favoritt hastighet\",\n    \"sv\": \"Ställ in favorit hastighet\",\n    \"pl\": \"Ustaw ulubioną prędkość\",\n    \"ru\": \"Установить любимую скорость\",\n    \"ko\": \"즐겨찾기 속도 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set favorite speed to [[favorite]]\",\n    \"nl\": \"Favoriete snelheid instellen op [[favorite]]\",\n    \"da\": \"Indstil favorit hastighed til [[favorite]]\",\n    \"de\": \"Lieblingsgeschwindigkeit auf [[favorite]] einstellen\",\n    \"es\": \"Establecer velocidad favorita a [[favorite]]\",\n    \"fr\": \"Définir la vitesse favorite à [[favorite]]\",\n    \"it\": \"Imposta velocità preferita a [[favorite]]\",\n    \"no\": \"Sett favoritt hastighet til [[favorite]]\",\n    \"sv\": \"Ställ in favorit hastighet till [[favorite]]\",\n    \"pl\": \"Ustaw ulubioną prędkość na [[favorite]]\",\n    \"ru\": \"Установить любимую скорость на [[favorite]]\",\n    \"ko\": \"[[favorite]]로 즐겨찾기 속도 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"favorite\",\n      \"title\": {\n        \"en\": \"Favorite\",\n        \"nl\": \"Favoriet\",\n        \"da\": \"Favorit\",\n        \"de\": \"Favorit\",\n        \"es\": \"Favorito\",\n        \"fr\": \"Favori\",\n        \"it\": \"Preferito\",\n        \"no\": \"Favoritt\",\n        \"sv\": \"Favorit\",\n        \"pl\": \"Ulubiony\",\n        \"ru\": \"Любимый\",\n        \"ko\": \"즐겨찾기\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"label\": {\n            \"en\": \"1\",\n            \"nl\": \"1\",\n            \"da\": \"1\",\n            \"de\": \"1\",\n            \"es\": \"1\",\n            \"fr\": \"1\",\n            \"it\": \"1\",\n            \"no\": \"1\",\n            \"sv\": \"1\",\n            \"pl\": \"1\",\n            \"ru\": \"1\",\n            \"ko\": \"1\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"label\": {\n            \"en\": \"2\",\n            \"nl\": \"2\",\n            \"da\": \"2\",\n            \"de\": \"2\",\n            \"es\": \"2\",\n            \"fr\": \"2\",\n            \"it\": \"2\",\n            \"no\": \"2\",\n            \"sv\": \"2\",\n            \"pl\": \"2\",\n            \"ru\": \"2\",\n            \"ko\": \"2\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"label\": {\n            \"en\": \"3\",\n            \"nl\": \"3\",\n            \"da\": \"3\",\n            \"de\": \"3\",\n            \"es\": \"3\",\n            \"fr\": \"3\",\n            \"it\": \"3\",\n            \"no\": \"3\",\n            \"sv\": \"3\",\n            \"pl\": \"3\",\n            \"ru\": \"3\",\n            \"ko\": \"3\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"label\": {\n            \"en\": \"4\",\n            \"nl\": \"4\",\n            \"da\": \"4\",\n            \"de\": \"4\",\n            \"es\": \"4\",\n            \"fr\": \"4\",\n            \"it\": \"4\",\n            \"no\": \"4\",\n            \"sv\": \"4\",\n            \"pl\": \"4\",\n            \"ru\": \"4\",\n            \"ko\": \"4\"\n          }\n        },\n        {\n          \"id\": \"5\",\n          \"label\": {\n            \"en\": \"5\",\n            \"nl\": \"5\",\n            \"da\": \"5\",\n            \"de\": \"5\",\n            \"es\": \"5\",\n            \"fr\": \"5\",\n            \"it\": \"5\",\n            \"no\": \"5\",\n            \"sv\": \"5\",\n            \"pl\": \"5\",\n            \"ru\": \"5\",\n            \"ko\": \"5\"\n          }\n        },\n        {\n          \"id\": \"6\",\n          \"label\": {\n            \"en\": \"6\",\n            \"nl\": \"6\",\n            \"da\": \"6\",\n            \"de\": \"6\",\n            \"es\": \"6\",\n            \"fr\": \"6\",\n            \"it\": \"6\",\n            \"no\": \"6\",\n            \"sv\": \"6\",\n            \"pl\": \"6\",\n            \"ru\": \"6\",\n            \"ko\": \"6\"\n          }\n        },\n        {\n          \"id\": \"7\",\n          \"label\": {\n            \"en\": \"7\",\n            \"nl\": \"7\",\n            \"da\": \"7\",\n            \"de\": \"7\",\n            \"es\": \"7\",\n            \"fr\": \"7\",\n            \"it\": \"7\",\n            \"no\": \"7\",\n            \"sv\": \"7\",\n            \"pl\": \"7\",\n            \"ru\": \"7\",\n            \"ko\": \"7\"\n          }\n        },\n        {\n          \"id\": \"8\",\n          \"label\": {\n            \"en\": \"8\",\n            \"nl\": \"8\",\n            \"da\": \"8\",\n            \"de\": \"8\",\n            \"es\": \"8\",\n            \"fr\": \"8\",\n            \"it\": \"8\",\n            \"no\": \"8\",\n            \"sv\": \"8\",\n            \"pl\": \"8\",\n            \"ru\": \"8\",\n            \"ko\": \"8\"\n          }\n        },\n        {\n          \"id\": \"9\",\n          \"label\": {\n            \"en\": \"9\",\n            \"nl\": \"9\",\n            \"da\": \"9\",\n            \"de\": \"9\",\n            \"es\": \"9\",\n            \"fr\": \"9\",\n            \"it\": \"9\",\n            \"no\": \"9\",\n            \"sv\": \"9\",\n            \"pl\": \"9\",\n            \"ru\": \"9\",\n            \"ko\": \"9\"\n          }\n        },\n        {\n          \"id\": \"10\",\n          \"label\": {\n            \"en\": \"10\",\n            \"nl\": \"10\",\n            \"da\": \"10\",\n            \"de\": \"10\",\n            \"es\": \"10\",\n            \"fr\": \"10\",\n            \"it\": \"10\",\n            \"no\": \"10\",\n            \"sv\": \"10\",\n            \"pl\": \"10\",\n            \"ru\": \"10\",\n            \"ko\": \"10\"\n          }\n        },\n        {\n          \"id\": \"11\",\n          \"label\": {\n            \"en\": \"11\",\n            \"nl\": \"11\",\n            \"da\": \"11\",\n            \"de\": \"11\",\n            \"es\": \"11\",\n            \"fr\": \"11\",\n            \"it\": \"11\",\n            \"no\": \"11\",\n            \"sv\": \"11\",\n            \"pl\": \"11\",\n            \"ru\": \"11\",\n            \"ko\": \"11\"\n          }\n        },\n        {\n          \"id\": \"12\",\n          \"label\": {\n            \"en\": \"12\",\n            \"nl\": \"12\",\n            \"da\": \"12\",\n            \"de\": \"12\",\n            \"es\": \"12\",\n            \"fr\": \"12\",\n            \"it\": \"12\",\n            \"no\": \"12\",\n            \"sv\": \"12\",\n            \"pl\": \"12\",\n            \"ru\": \"12\",\n            \"ko\": \"12\"\n          }\n        },\n        {\n          \"id\": \"13\",\n          \"label\": {\n            \"en\": \"13\",\n            \"nl\": \"13\",\n            \"da\": \"13\",\n            \"de\": \"13\",\n            \"es\": \"13\",\n            \"fr\": \"13\",\n            \"it\": \"13\",\n            \"no\": \"13\",\n            \"sv\": \"13\",\n            \"pl\": \"13\",\n            \"ru\": \"13\",\n            \"ko\": \"13\"\n          }\n        },\n        {\n          \"id\": \"14\",\n          \"label\": {\n            \"en\": \"14\",\n            \"nl\": \"14\",\n            \"da\": \"14\",\n            \"de\": \"14\",\n            \"es\": \"14\",\n            \"fr\": \"14\",\n            \"it\": \"14\",\n            \"no\": \"14\",\n            \"sv\": \"14\",\n            \"pl\": \"14\",\n            \"ru\": \"14\",\n            \"ko\": \"14\"\n          }\n        },\n        {\n          \"id\": \"15\",\n          \"label\": {\n            \"en\": \"15\",\n            \"nl\": \"15\",\n            \"da\": \"15\",\n            \"de\": \"15\",\n            \"es\": \"15\",\n            \"fr\": \"15\",\n            \"it\": \"15\",\n            \"no\": \"15\",\n            \"sv\": \"15\",\n            \"pl\": \"15\",\n            \"ru\": \"15\",\n            \"ko\": \"15\"\n          }\n        },\n        {\n          \"id\": \"16\",\n          \"label\": {\n            \"en\": \"16\",\n            \"nl\": \"16\",\n            \"da\": \"16\",\n            \"de\": \"16\",\n            \"es\": \"16\",\n            \"fr\": \"16\",\n            \"it\": \"16\",\n            \"no\": \"16\",\n            \"sv\": \"16\",\n            \"pl\": \"16\",\n            \"ru\": \"16\",\n            \"ko\": \"16\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Air Purifier\",\n        \"nl\": \"Selecteer Mi Luchtreiniger\",\n        \"da\": \"Vælg Mi luftrenser\",\n        \"de\": \"Wählen Sie Mi Luftreiniger\",\n        \"es\": \"Seleccione Mi Purificador de aire\",\n        \"fr\": \"Sélectionnez Mi Purificateur d'air\",\n        \"it\": \"Seleziona Mi Purificatore d'aria\",\n        \"no\": \"Velg Mi luftrenser\",\n        \"sv\": \"Välj Mi luftrenare\",\n        \"pl\": \"Wybierz Mi oczyszczacz powietrza\",\n        \"ru\": \"Выберите Mi Очиститель воздуха\",\n        \"ko\": \"Mi 공기청정기 선택\"\n      },\n      \"filter\": \"driver_id=mi-airpurifier|airpurifier_zhimi_advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/airpurifierXiaomiFanlevel.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set fan level\",\n    \"nl\": \"Ventilatieniveau instellen\",\n    \"da\": \"Indstil ventilatorniveau\",\n    \"de\": \"Lüfterstufe einstellen\",\n    \"es\": \"Establecer nivel de ventilador\",\n    \"fr\": \"Définir le niveau du ventilateur\",\n    \"it\": \"Imposta livello ventola\",\n    \"no\": \"Still inn viftetrinn\",\n    \"sv\": \"Ställ in fläkthastighet\",\n    \"pl\": \"Ustaw poziom wentylatora\",\n    \"ru\": \"Установить уровень вентилятора\",\n    \"ko\": \"팬 레벨 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set fan level to [[fanlevel]]\",\n    \"nl\": \"Stel fan level in op [[fanlevel]]\",\n    \"da\": \"Indstil blæserniveau til [[fanlevel]]\",\n    \"de\": \"Lüfterstufe auf [[fanlevel]] einstellen\",\n    \"es\": \"Establecer el nivel del ventilador a [[fanlevel]]\",\n    \"fr\": \"Définir le niveau du ventilateur à [[fanlevel]]\",\n    \"it\": \"Imposta il livello della ventola a [[fanlevel]]\",\n    \"no\": \"Still inn viftenivå til [[fanlevel]]\",\n    \"sv\": \"Ställ in fläkthastighet till [[fanlevel]]\",\n    \"pl\": \"Ustaw poziom wentylatora na [[fanlevel]]\",\n    \"ru\": \"Установите уровень вентилятора на [[fanlevel]]\",\n    \"ko\": \"팬 레벨 [[fanlevel]]로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"fanlevel\",\n      \"title\": {\n        \"en\": \"Fan Level\",\n        \"nl\": \"Fan Level\",\n        \"da\": \"Blæserniveau\",\n        \"de\": \"Lüfterstufe\",\n        \"es\": \"Nivel del ventilador\",\n        \"fr\": \"Niveau de ventilateur\",\n        \"it\": \"Livello ventola\",\n        \"no\": \"Viftenivå\",\n        \"sv\": \"Fläkthastighet\",\n        \"pl\": \"Poziom wentylatora\",\n        \"ru\": \"Уровень вентилятора\",\n        \"ko\": \"팬 레벨\"\n      },\n      \"type\": \"number\",\n      \"min\": 0,\n      \"max\": 14,\n      \"step\": 1\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Airpurifier\",\n        \"nl\": \"Selecteer Airpurifier\",\n        \"da\": \"Vælg luftrenser\",\n        \"de\": \"Luftreiniger auswählen\",\n        \"es\": \"Seleccionar purificador de aire\",\n        \"fr\": \"Sélectionner le purificateur d'air\",\n        \"it\": \"Seleziona purificatore d'aria\",\n        \"no\": \"Velg luftrenser\",\n        \"sv\": \"Välj luftrenare\",\n        \"pl\": \"Wybierz oczyszczacz powietrza\",\n        \"ru\": \"Выберите очиститель воздуха\",\n        \"ko\": \"공기청정기 선택\"\n      },\n      \"filter\": \"driver_id=airpurifier_zhimi_advanced_miot&capabilities=airpurifier_xiaomi_fanlevel\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/airpurifierZhimiFanlevel.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set fan level\",\n    \"nl\": \"Ventilatieniveau instellen\",\n    \"da\": \"Indstil ventilatorniveau\",\n    \"de\": \"Lüfterstufe einstellen\",\n    \"es\": \"Establecer nivel de ventilador\",\n    \"fr\": \"Définir le niveau du ventilateur\",\n    \"it\": \"Imposta livello ventola\",\n    \"no\": \"Still inn viftetrinn\",\n    \"sv\": \"Ställ in fläkthastighet\",\n    \"pl\": \"Ustaw poziom wentylatora\",\n    \"ru\": \"Установить уровень вентилятора\",\n    \"ko\": \"팬 레벨 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set fan level to [[fanlevel]]\",\n    \"nl\": \"Stel fan level in op [[fanlevel]]\",\n    \"da\": \"Indstil blæserniveau til [[fanlevel]]\",\n    \"de\": \"Lüfterstufe auf [[fanlevel]] einstellen\",\n    \"es\": \"Establecer el nivel del ventilador a [[fanlevel]]\",\n    \"fr\": \"Définir le niveau du ventilateur à [[fanlevel]]\",\n    \"it\": \"Imposta il livello della ventola a [[fanlevel]]\",\n    \"no\": \"Still inn viftenivå til [[fanlevel]]\",\n    \"sv\": \"Ställ in fläkthastighet till [[fanlevel]]\",\n    \"pl\": \"Ustaw poziom wentylatora na [[fanlevel]]\",\n    \"ru\": \"Установите уровень вентилятора на [[fanlevel]]\",\n    \"ko\": \"팬 레벨 [[fanlevel]]로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"fanlevel\",\n      \"title\": {\n        \"en\": \"Fan Level\",\n        \"nl\": \"Fan Level\",\n        \"da\": \"Blæserniveau\",\n        \"de\": \"Lüfterstufe\",\n        \"es\": \"Nivel del ventilador\",\n        \"fr\": \"Niveau de ventilateur\",\n        \"it\": \"Livello ventola\",\n        \"no\": \"Viftenivå\",\n        \"sv\": \"Fläkthastighet\",\n        \"pl\": \"Poziom wentylatora\",\n        \"ru\": \"Уровень вентилятора\",\n        \"ko\": \"팬 레벨\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Level 1\",\n            \"nl\": \"Level 1\",\n            \"da\": \"Niveau 1\",\n            \"de\": \"Stufe 1\",\n            \"es\": \"Nivel 1\",\n            \"fr\": \"Niveau 1\",\n            \"it\": \"Livello 1\",\n            \"no\": \"Nivå 1\",\n            \"sv\": \"Nivå 1\",\n            \"pl\": \"Poziom 1\",\n            \"ru\": \"Уровень 1\",\n            \"ko\": \"레벨 1\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Level 2\",\n            \"nl\": \"Level 2\",\n            \"da\": \"Niveau 2\",\n            \"de\": \"Stufe 2\",\n            \"es\": \"Nivel 2\",\n            \"fr\": \"Niveau 2\",\n            \"it\": \"Livello 2\",\n            \"no\": \"Nivå 2\",\n            \"sv\": \"Nivå 2\",\n            \"pl\": \"Poziom 2\",\n            \"ru\": \"Уровень 2\",\n            \"ko\": \"레벨 2\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Level 3\",\n            \"nl\": \"Level 3\",\n            \"da\": \"Niveau 3\",\n            \"de\": \"Stufe 3\",\n            \"es\": \"Nivel 3\",\n            \"fr\": \"Niveau 3\",\n            \"it\": \"Livello 3\",\n            \"no\": \"Nivå 3\",\n            \"sv\": \"Nivå 3\",\n            \"pl\": \"Poziom 3\",\n            \"ru\": \"Уровень 3\",\n            \"ko\": \"레벨 3\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Airpurifier\",\n        \"nl\": \"Selecteer Airpurifier\",\n        \"da\": \"Vælg luftrenser\",\n        \"de\": \"Luftreiniger auswählen\",\n        \"es\": \"Seleccionar purificador de aire\",\n        \"fr\": \"Sélectionner le purificateur d'air\",\n        \"it\": \"Seleziona purificatore d'aria\",\n        \"no\": \"Velg luftrenser\",\n        \"sv\": \"Välj luftrenare\",\n        \"pl\": \"Wybierz oczyszczacz powietrza\",\n        \"ru\": \"Выберите очиститель воздуха\",\n        \"ko\": \"공기청정기 선택\"\n      },\n      \"filter\": \"driver_id=airpurifier_zhimi_advanced_miot&capabilities=airpurifier_zhimi_fanlevel\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/airpurifierZhimiMode.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Indstil tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Configurar modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Angi modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus einstellen auf [[mode]]\",\n    \"es\": \"Configurar modo a [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Angi modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]]로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"da\": \"Auto\",\n            \"de\": \"Auto\",\n            \"es\": \"Auto\",\n            \"fr\": \"Auto\",\n            \"it\": \"Auto\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Автоматический\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Night\",\n            \"nl\": \"Nacht\",\n            \"da\": \"Nat\",\n            \"de\": \"Nacht\",\n            \"es\": \"Noche\",\n            \"fr\": \"Nuit\",\n            \"it\": \"Notte\",\n            \"no\": \"Natt\",\n            \"sv\": \"Natt\",\n            \"pl\": \"Noc\",\n            \"ru\": \"Ночной\",\n            \"ko\": \"야간\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Favorite\",\n            \"nl\": \"Favoriet\",\n            \"da\": \"Favorit\",\n            \"de\": \"Favorit\",\n            \"es\": \"Favorito\",\n            \"fr\": \"Favori\",\n            \"it\": \"Preferito\",\n            \"no\": \"Favoritt\",\n            \"sv\": \"Favorit\",\n            \"pl\": \"Ulubiony\",\n            \"ru\": \"Избранное\",\n            \"ko\": \"즐겨찾기\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Idle / Manual\",\n            \"nl\": \"Inactief / Handmatig\",\n            \"da\": \"Inaktiv / Manuel\",\n            \"de\": \"Leerlauf / Manuell\",\n            \"es\": \"Inactivo / Manual\",\n            \"fr\": \"Inactif / Manuel\",\n            \"it\": \"Inattivo / Manuale\",\n            \"no\": \"Inaktiv / Manuell\",\n            \"sv\": \"Inaktiv / Manuell\",\n            \"pl\": \"Bezczynny / Ręczny\",\n            \"ru\": \"Ожидание / Ручной\",\n            \"ko\": \"대기 / 수동\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Airpurifier\",\n        \"nl\": \"Selecteer Airpurifier\",\n        \"da\": \"Vælg luftrenser\",\n        \"de\": \"Luftreiniger auswählen\",\n        \"es\": \"Selecciona purificador\",\n        \"fr\": \"Sélectionnez l'purificateur\",\n        \"it\": \"Seleziona purificatore\",\n        \"no\": \"Velg luftrenser\",\n        \"sv\": \"Välj luftrenare\",\n        \"pl\": \"Wybierz oczyszczacz powietrza\",\n        \"ru\": \"Выбрать очиститель воздуха\",\n        \"ko\": \"공기 청정기 선택\"\n      },\n      \"filter\": \"driver_id=airpurifier_zhimi_advanced_miot|airpurifier_dmaker_airfresh_t2017\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/changeSpeed.json",
    "content": "{\n  \"id\": \"changeSpeed\",\n  \"title\": {\n    \"en\": \"Set Speed\",\n    \"nl\": \"Stel snelheid in\",\n    \"da\": \"Indstil hastighed\",\n    \"de\": \"Geschwindigkeit einstellen\",\n    \"es\": \"Ajustar velocidad\",\n    \"fr\": \"Régler la vitesse\",\n    \"it\": \"Imposta velocità\",\n    \"no\": \"Sett hastighet\",\n    \"sv\": \"Ställ in hastighet\",\n    \"pl\": \"Ustaw prędkość\",\n    \"ru\": \"Установить скорость\",\n    \"ko\": \"속도 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set speed to [[speed]]\",\n    \"nl\": \"Stel snelheid in op [[speed]]\",\n    \"da\": \"Indstil hastighed til [[speed]]\",\n    \"de\": \"Geschwindigkeit auf [[speed]] einstellen\",\n    \"es\": \"Ajustar velocidad a [[speed]]\",\n    \"fr\": \"Régler la vitesse à [[speed]]\",\n    \"it\": \"Imposta velocità a [[speed]]\",\n    \"no\": \"Sett hastighet til [[speed]]\",\n    \"sv\": \"Ställ in hastighet till [[speed]]\",\n    \"pl\": \"Ustaw prędkość na [[speed]]\",\n    \"ru\": \"Установить скорость на [[speed]]\",\n    \"ko\": \"[[speed]]으로 속도 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"speed\",\n      \"title\": {\n        \"en\": \"Speed\",\n        \"nl\": \"Snelheid\",\n        \"da\": \"Hastighed\",\n        \"de\": \"Geschwindigkeit\",\n        \"es\": \"Velocidad\",\n        \"fr\": \"Vitesse\",\n        \"it\": \"Velocità\",\n        \"no\": \"Hastighet\",\n        \"sv\": \"Hastighet\",\n        \"pl\": \"Prędkość\",\n        \"ru\": \"Скорость\",\n        \"ko\": \"속도\"\n      },\n      \"type\": \"range\",\n      \"min\": 0,\n      \"max\": 100,\n      \"step\": 1,\n      \"label\": \"%\",\n      \"labelDecimals\": 0\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=zhimi-fan|dmaker-fan\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/cleanZoneVacuum.json",
    "content": "{\n  \"id\": \"cleanZoneVacuum\",\n  \"title\": {\n    \"en\": \"Start zone cleaning\",\n    \"nl\": \"Start zone schoonmaken\",\n    \"da\": \"Start zone rengøring\",\n    \"de\": \"Zonenreinigung starten\",\n    \"es\": \"Iniciar limpieza de zonas\",\n    \"fr\": \"Démarrer le nettoyage de zone\",\n    \"it\": \"Avvia pulizia della zona\",\n    \"no\": \"Start sone rengjøring\",\n    \"sv\": \"Starta zonstädning\",\n    \"pl\": \"Rozpocznij czyszczenie strefy\",\n    \"ru\": \"Начать уборку зоны\",\n    \"ko\": \"영역 청소 시작\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Start zone cleaning [[zones]]\",\n    \"nl\": \"Start zone schoonmaken [[zones]]\",\n    \"da\": \"Start zone rengøring [[zones]]\",\n    \"de\": \"Zonenreinigung starten [[zones]]\",\n    \"es\": \"Iniciar limpieza de zonas [[zones]]\",\n    \"fr\": \"Démarrer le nettoyage de zone [[zones]]\",\n    \"it\": \"Avvia pulizia della zona [[zones]]\",\n    \"no\": \"Start sone rengjøring [[zones]]\",\n    \"sv\": \"Starta zonstädning [[zones]]\",\n    \"pl\": \"Rozpocznij czyszczenie strefy [[zones]]\",\n    \"ru\": \"Начать уборку зоны [[zones]]\",\n    \"ko\": \"영역 청소 시작 [[zones]]\"\n  },\n  \"hint\": {\n    \"en\": \"Takes in an a list of zones and the number of times to clean. Each zone contains an array of 5 values: bottom-left-x, bottom-left-y, top-right-x, top-right-y, number of clean times. Zones example: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n    \"nl\": \"Voer een lijst met zones in en het aantal keren om schoon te maken. Elke zone bevat een array met 5 waarden: bottom-left-x, bottom-left-y, top-right-x, top-right-y, number of clean times. Zones voorbeeld: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n    \"da\": \"Indtast en liste over zoner og antallet af gange, der skal rengøres. Hver zone indeholder en række af 5 værdier: nederste venstre x, nederste venstre y, øverste højre x, øverste højre y, antal rengøringstider. Zoner eksempel: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n    \"de\": \"Geben Sie eine Liste der Zonen und die Anzahl der Reinigungsvorgänge ein. Jede Zone enthält ein Array von 5 Werten: unten-links-x, unten-links-y, oben-rechts-x, oben-rechts-y, Anzahl der Reinigungszeiten. Zonenbeispiel: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n    \"es\": \"Ingrese una lista de zonas y el número de veces para limpiar. Cada zona contiene una matriz de 5 valores: abajo-izquierda-x, abajo-izquierda-y, arriba-derecha-x, arriba-derecha-y, número de veces de limpieza. Ejemplo de zonas: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n    \"fr\": \"Saisissez une liste de zones et le nombre de fois à nettoyer. Chaque zone contient un tableau de 5 valeurs : en bas à gauche-x, en bas à gauche-y, en haut à droite-x, en haut à droite-y, nombre de fois à nettoyer. Exemple de zones : [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n    \"it\": \"Inserisci un elenco di zone e il numero di volte da pulire. Ogni zona contiene una matrice di 5 valori: in basso a sinistra x, in basso a sinistra y, in alto a destra x, in alto a destra y, numero di volte di pulizia. Esempio di zone: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n    \"no\": \"Skriv inn en liste over soner og antall ganger å rengjøre. Hver sone inneholder en rekke med 5 verdier: nederst-venstre-x, nederst-venstre-y, øverst-høyre-x, øverst-høyre-y, antall rengjøringstider. Soneeksempel: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n    \"sv\": \"Ange en lista över zoner och antalet gånger att städa. Varje zon innehåller en matris med 5 värden: nedre vänster-x, nedre vänster-y, övre höger-x, övre höger-y, antal rengöringstider. Exempel på zoner: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n    \"pl\": \"Wprowadź listę stref i liczbę razy do czyszczenia. Każda strefa zawiera tablicę z 5 wartościami: dolna-lewa-x, dolna-lewa-y, górna-prawa-x, górna-prawa-y, liczba razy do czyszczenia. Przykład stref: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n    \"ru\": \"Введите список зон и количество раз для уборки. Каждая зона содержит массив из 5 значений: слева внизу-x, слева внизу-y, справа вверху-x, справа вверху-y, количество уборок. Пример зон: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n    \"ko\": \"청소할 횟수와 목록을 입력합니다. 각 영역은 5가지 값의 배열을 포함합니다: 좌하단 x, 좌하단 y, 우상단 x, 우상단 y, 청소 횟수. 영역 예시: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"zones\",\n      \"title\": {\n        \"en\": \"Zones\",\n        \"nl\": \"Zones\",\n        \"da\": \"Zoner\",\n        \"de\": \"Zonen\",\n        \"es\": \"Zonas\",\n        \"fr\": \"Zones\",\n        \"it\": \"Zone\",\n        \"no\": \"Soner\",\n        \"sv\": \"Zoner\",\n        \"pl\": \"Strefy\",\n        \"ru\": \"Зоны\",\n        \"ko\": \"영역\"\n      },\n      \"type\": \"text\",\n      \"placeholder\": {\n        \"en\": \"Zones\",\n        \"nl\": \"Zones\",\n        \"da\": \"Zoner\",\n        \"de\": \"Zonen\",\n        \"es\": \"Zonas\",\n        \"fr\": \"Zones\",\n        \"it\": \"Zone\",\n        \"no\": \"Soner\",\n        \"sv\": \"Zoner\",\n        \"pl\": \"Strefy\",\n        \"ru\": \"Зоны\",\n        \"ko\": \"영역\"\n      }\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer Stofzuiger\",\n        \"da\": \"Vælg Støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccionar aspiradora\",\n        \"fr\": \"Sélectionner l'aspirateur\",\n        \"it\": \"Seleziona aspirapolvere\",\n        \"no\": \"Velg Støvsuger\",\n        \"sv\": \"Välj Dammsugare\",\n        \"pl\": \"Wybierz Odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"진공 청소기 선택\"\n      },\n      \"filter\": \"driver_id=mi-robot|vacuum_mi_rockrobo_vacuum_advanced|vacuum_mi_rockrobo_vacuum_t6\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/enableAngle.json",
    "content": "{\n  \"id\": \"enableAngle\",\n  \"title\": {\n    \"en\": \"Enable Oscillation\",\n    \"nl\": \"Inschakelen oscillatie\",\n    \"da\": \"Aktivér oscillation\",\n    \"de\": \"Oszillation aktivieren\",\n    \"es\": \"Activar oscilación\",\n    \"fr\": \"Activer l'oscillation\",\n    \"it\": \"Abilita oscillazione\",\n    \"no\": \"Aktiver svinging\",\n    \"sv\": \"Aktivera oscillator\",\n    \"pl\": \"Włącz oscylację\",\n    \"ru\": \"Включить осцилляцию\",\n    \"ko\": \"진동 활성화\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Oscillation [[oscillation]]\",\n    \"nl\": \"Oscillatie [[oscillation]]\",\n    \"da\": \"Oscillation [[oscillation]]\",\n    \"de\": \"Oszillation [[oscillation]]\",\n    \"es\": \"Oscilación [[oscillation]]\",\n    \"fr\": \"Oscillation [[oscillation]]\",\n    \"it\": \"Oscillazione [[oscillation]]\",\n    \"no\": \"Oscillation [[oscillation]]\",\n    \"sv\": \"Oscillation [[oscillation]]\",\n    \"pl\": \"Oscylacja [[oscillation]]\",\n    \"ru\": \"Осцилляция [[oscillation]]\",\n    \"ko\": \"진동 [[oscillation]]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"oscillation\",\n      \"title\": {\n        \"en\": \"Angle\",\n        \"nl\": \"Hoek\",\n        \"da\": \"Vinkel\",\n        \"de\": \"Winkel\",\n        \"es\": \"Ángulo\",\n        \"fr\": \"Angle\",\n        \"it\": \"Angolo\",\n        \"no\": \"Vinkel\",\n        \"sv\": \"Vinkel\",\n        \"pl\": \"Kąt\",\n        \"ru\": \"Угол\",\n        \"ko\": \"각도\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"on\",\n          \"label\": {\n            \"en\": \"Enable\",\n            \"nl\": \"Inschakelen\",\n            \"da\": \"Aktiver\",\n            \"de\": \"Aktivieren\",\n            \"es\": \"Habilitar\",\n            \"fr\": \"Activer\",\n            \"it\": \"Abilita\",\n            \"no\": \"Aktiver\",\n            \"sv\": \"Aktivera\",\n            \"pl\": \"Włącz\",\n            \"ru\": \"Включить\",\n            \"ko\": \"사용\"\n          }\n        },\n        {\n          \"id\": \"off\",\n          \"label\": {\n            \"en\": \"Disable\",\n            \"nl\": \"Uitschakelen\",\n            \"da\": \"Deaktiver\",\n            \"de\": \"Deaktivieren\",\n            \"es\": \"Deshabilitar\",\n            \"fr\": \"Désactiver\",\n            \"it\": \"Disabilita\",\n            \"no\": \"Deaktiver\",\n            \"sv\": \"Inaktivera\",\n            \"pl\": \"Wyłącz\",\n            \"ru\": \"Выключить\",\n            \"ko\": \"비활성화\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Choisir l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=zhimi-fan|dmaker-fan|fan_zhimi_advanced|fan_zhimi_fan_za5|fan_dmaker_advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/enableBuzzer.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Enable notification sound\",\n    \"nl\": \"Instellen notificatie geluid\",\n    \"da\": \"Aktiver notifikationslyd\",\n    \"de\": \"Benachrichtigungston aktivieren\",\n    \"es\": \"Activar sonido de notificaciones\",\n    \"fr\": \"Activer le son de notification\",\n    \"it\": \"Abilita suono di notifica\",\n    \"no\": \"Aktiver varslingslyd\",\n    \"sv\": \"Aktivera notifikationsljud\",\n    \"pl\": \"Włącz dźwięk powiadomień\",\n    \"ru\": \"Включить звуковое уведомление\",\n    \"ko\": \"알림 소리 사용\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set notification sound [[sound]]\",\n    \"nl\": \"Wijzig notificatie geluid naar [[sound]]\",\n    \"da\": \"Indstil notifikationslyd [[sound]]\",\n    \"de\": \"Benachrichtigungston einstellen [[sound]]\",\n    \"es\": \"Configurar sonido de notificación [[sound]]\",\n    \"fr\": \"Définir le son de notification [[sound]]\",\n    \"it\": \"Imposta suono di notifica [[sound]]\",\n    \"no\": \"Angi varslingslyd [[sound]]\",\n    \"sv\": \"Ställ in notifikationsljud [[sound]]\",\n    \"pl\": \"Ustaw dźwięk powiadomień [[sound]]\",\n    \"ru\": \"Установить звуковое уведомление [[sound]]\",\n    \"ko\": \"알림 소리 설정 [[sound]]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"sound\",\n      \"title\": {\n        \"en\": \"Sound\",\n        \"nl\": \"Geluid\",\n        \"da\": \"Lyd\",\n        \"de\": \"Klang\",\n        \"es\": \"Sonido\",\n        \"fr\": \"Son\",\n        \"it\": \"Suono\",\n        \"no\": \"Lyd\",\n        \"sv\": \"Ljud\",\n        \"pl\": \"Dźwięk\",\n        \"ru\": \"Звук\",\n        \"ko\": \"소리\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"label\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"da\": \"Fra\",\n            \"de\": \"Aus\",\n            \"es\": \"Apagado\",\n            \"fr\": \"Désactivé\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wyłączone\",\n            \"ru\": \"Выкл.\",\n            \"ko\": \"끔\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"label\": {\n            \"en\": \"On\",\n            \"nl\": \"Aan\",\n            \"da\": \"Til\",\n            \"de\": \"Ein\",\n            \"es\": \"Encendido\",\n            \"fr\": \"Activé\",\n            \"it\": \"Acceso\",\n            \"no\": \"På\",\n            \"sv\": \"På\",\n            \"pl\": \"Włączone\",\n            \"ru\": \"Вкл.\",\n            \"ko\": \"켬\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=airpurifier_zhimi_advanced_miot|fan_dmaker_advanced|heater_zhimi_heater_miot|humidifier_xiaomi_humidifier|petwaterdispenser_mmgg_miot|humidifier_deerma_humidifier_miot|humidifier_zhimi_humidifier_miot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/actions/enableChildLock.json",
    "content": "{\n  \"id\": \"enableChildLock\",\n  \"title\": {\n    \"en\": \"Enable Child Lock\",\n    \"nl\": \"Instellen kindbeveiliging\",\n    \"da\": \"Aktivér børnelås\",\n    \"de\": \"Kindersicherung aktivieren\",\n    \"es\": \"Activar bloqueo infantil\",\n    \"fr\": \"Activer le verrouillage enfant\",\n    \"it\": \"Abilita blocco bambini\",\n    \"no\": \"Aktiver barnelås\",\n    \"sv\": \"Aktivera barnlås\",\n    \"pl\": \"Włącz blokadę rodzicielską\",\n    \"ru\": \"Включить детский замок\",\n    \"ko\": \"어린이 잠금 장치를 활성화\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set child lock [[childlock]]\",\n    \"nl\": \"Wijzig kindbeveiliging naar [[childlock]]\",\n    \"da\": \"Indstil børnelås [[childlock]]\",\n    \"de\": \"Kindersicherung setzen [[childlock]]\",\n    \"es\": \"Configurar bloqueo infantil [[childlock]]\",\n    \"fr\": \"Définir le verrouillage enfant [[childlock]]\",\n    \"it\": \"Imposta blocco bambini [[childlock]]\",\n    \"no\": \"Sett barnelås [[childlock]]\",\n    \"sv\": \"Ställ in barnlåset [[childlock]]\",\n    \"pl\": \"Ustaw blokadę rodzicielską [[childlock]]\",\n    \"ru\": \"Установить детский замок [[childlock]]\",\n    \"ko\": \"어린이 잠금 설정 [[childlock]]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"childlock\",\n      \"title\": {\n        \"en\": \"Childlock\",\n        \"nl\": \"Kinderslot\",\n        \"da\": \"Børnelås\",\n        \"de\": \"Kindersicherung\",\n        \"es\": \"Bloqueo infantil\",\n        \"fr\": \"Verrouillage enfant\",\n        \"it\": \"Blocco bambini\",\n        \"no\": \"Barnelås\",\n        \"sv\": \"Barnlås\",\n        \"pl\": \"Blokada rodzicielska\",\n        \"ru\": \"Детский замок\",\n        \"ko\": \"어린이 잠금 장치\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"on\",\n          \"label\": {\n            \"en\": \"On\",\n            \"nl\": \"Aan\",\n            \"da\": \"Til\",\n            \"de\": \"Ein\",\n            \"es\": \"Encendido\",\n            \"fr\": \"Activé\",\n            \"it\": \"Acceso\",\n            \"no\": \"På\",\n            \"sv\": \"På\",\n            \"pl\": \"Włączone\",\n            \"ru\": \"Вкл\",\n            \"ko\": \"켜기\"\n          }\n        },\n        {\n          \"id\": \"off\",\n          \"label\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"da\": \"Fra\",\n            \"de\": \"Aus\",\n            \"es\": \"Apagado\",\n            \"fr\": \"Désactivé\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wyłączone\",\n            \"ru\": \"Выкл\",\n            \"ko\": \"끄기\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=zhimi-fan|dmaker-fan|fan_zhimi_advanced|fan_zhimi_fan_za5\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/enableEyecare.json",
    "content": "{\n  \"id\": \"enableEyecare\",\n  \"title\": {\n    \"en\": \"Switch Eyecare\",\n    \"nl\": \"Eyecare schakelen\",\n    \"da\": \"Skift Eyecare\",\n    \"de\": \"Eyecare einschalten\",\n    \"es\": \"Cambiar Eyecare\",\n    \"fr\": \"Changer Eyecare\",\n    \"it\": \"Cambia Eyecare\",\n    \"no\": \"Bytt Eyecare\",\n    \"sv\": \"Byt Eyecare\",\n    \"pl\": \"Przełącz Eyecare\",\n    \"ru\": \"Переключить Eyecare\",\n    \"ko\": \"아이케어 전환\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Eyecare [[eyecare]]\",\n    \"nl\": \"Eyecare [[eyecare]]\",\n    \"da\": \"Eyecare [[eyecare]]\",\n    \"de\": \"Eyecare [[eyecare]]\",\n    \"es\": \"Eyecare [[eyecare]]\",\n    \"fr\": \"Eyecare [[eyecare]]\",\n    \"it\": \"Eyecare [[eyecare]]\",\n    \"no\": \"Eyecare [[eyecare]]\",\n    \"sv\": \"Eyecare [[eyecare]]\",\n    \"pl\": \"Eyecare [[eyecare]]\",\n    \"ru\": \"Eyecare [[eyecare]]\",\n    \"ko\": \"Eyecare [[eyecare]]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"eyecare\",\n      \"title\": {\n        \"en\": \"Eyecare\",\n        \"nl\": \"Eyecare\",\n        \"da\": \"Eyecare\",\n        \"de\": \"Eyecare\",\n        \"es\": \"Eyecare\",\n        \"fr\": \"Eyecare\",\n        \"it\": \"Eyecare\",\n        \"no\": \"Eyecare\",\n        \"sv\": \"Eyecare\",\n        \"pl\": \"Eyecare\",\n        \"ru\": \"Eyecare\",\n        \"ko\": \"Eyecare\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"on\",\n          \"label\": {\n            \"en\": \"On\",\n            \"nl\": \"Aan\",\n            \"da\": \"Tænd\",\n            \"de\": \"An\",\n            \"es\": \"Encendido\",\n            \"fr\": \"Allumé\",\n            \"it\": \"Acceso\",\n            \"no\": \"På\",\n            \"sv\": \"På\",\n            \"pl\": \"Włącz\",\n            \"ru\": \"Вкл\",\n            \"ko\": \"켜짐\"\n          }\n        },\n        {\n          \"id\": \"off\",\n          \"label\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"da\": \"Slukket\",\n            \"de\": \"Aus\",\n            \"es\": \"Apagado\",\n            \"fr\": \"Éteint\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wyłącz\",\n            \"ru\": \"Выкл\",\n            \"ko\": \"꺼짐\"\n          }\n        },\n        {\n          \"id\": \"phone\",\n          \"label\": {\n            \"en\": \"Phone\",\n            \"nl\": \"Telefoon\",\n            \"da\": \"Telefon\",\n            \"de\": \"Telefon\",\n            \"es\": \"Teléfono\",\n            \"fr\": \"Téléphone\",\n            \"it\": \"Telefono\",\n            \"no\": \"Telefon\",\n            \"sv\": \"Telefon\",\n            \"pl\": \"Telefon\",\n            \"ru\": \"Телефон\",\n            \"ko\": \"전화기\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Philips Eyecare Lamp\",\n        \"nl\": \"Selecteer Philips Eyecare Lamp\",\n        \"da\": \"Vælg Philips Eyecare Lampe\",\n        \"de\": \"Wählen Sie Philips Eyecare Lampe\",\n        \"es\": \"Seleccione Philips Eyecare Lamp\",\n        \"fr\": \"Sélectionnez Philips Eyecare Lamp\",\n        \"it\": \"Seleziona Philips Eyecare Lamp\",\n        \"no\": \"Velg Philips Eyecare Lamp\",\n        \"sv\": \"Välj Philips Eyecare Lamp\",\n        \"pl\": \"Wybierz lampę Philips Eyecare\",\n        \"ru\": \"Выберите лампу Philips Eyecare\",\n        \"ko\": \"필립스 아이케어 램프 선택\"\n      },\n      \"filter\": \"driver_id=philips-eyecare\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/enableLED.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Enable LED\",\n    \"nl\": \"Instellen LED\",\n    \"da\": \"Aktiver LED\",\n    \"de\": \"LED aktivieren\",\n    \"es\": \"Activar LED\",\n    \"fr\": \"Activer LED\",\n    \"it\": \"Abilita LED\",\n    \"no\": \"Aktiver LED\",\n    \"sv\": \"Aktivera LED\",\n    \"pl\": \"Włącz LED\",\n    \"ru\": \"Включить светодиод\",\n    \"ko\": \"LED 켜기\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set LED [[led]]\",\n    \"nl\": \"Wijzig LED naar [[led]]\",\n    \"da\": \"Indstil LED [[led]]\",\n    \"de\": \"LED einstellen [[led]]\",\n    \"es\": \"Configurar LED [[led]]\",\n    \"fr\": \"Définir la LED [[led]]\",\n    \"it\": \"Imposta LED [[led]]\",\n    \"no\": \"Still inn LED [[led]]\",\n    \"sv\": \"Ställ in LED [[led]]\",\n    \"pl\": \"Ustaw LED [[led]]\",\n    \"ru\": \"Установить светодиод [[led]]\",\n    \"ko\": \"LED 설정 [[led]]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"led\",\n      \"title\": {\n        \"en\": \"LED\",\n        \"nl\": \"LED\",\n        \"da\": \"LED\",\n        \"de\": \"LED\",\n        \"es\": \"LED\",\n        \"fr\": \"LED\",\n        \"it\": \"LED\",\n        \"no\": \"LED\",\n        \"sv\": \"LED\",\n        \"pl\": \"LED\",\n        \"ru\": \"LED\",\n        \"ko\": \"LED\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"label\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"da\": \"Slukket\",\n            \"de\": \"Aus\",\n            \"es\": \"Apagado\",\n            \"fr\": \"Éteint\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wyłączony\",\n            \"ru\": \"Выкл\",\n            \"ko\": \"끄기\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"label\": {\n            \"en\": \"On\",\n            \"nl\": \"Aan\",\n            \"da\": \"Tændt\",\n            \"de\": \"Ein\",\n            \"es\": \"Encendido\",\n            \"fr\": \"Allumé\",\n            \"it\": \"Acceso\",\n            \"no\": \"På\",\n            \"sv\": \"På\",\n            \"pl\": \"Włączony\",\n            \"ru\": \"Вкл\",\n            \"ko\": \"켜기\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"기기 선택\"\n      },\n      \"filter\": \"driver_id=airpurifier_zhimi_advanced_miot|fan_dmaker_advanced|heater_zhimi_heater_miot|humidifier_xiaomi_humidifier|petwaterdispenser_mmgg_miot|humidifier_deerma_humidifier_miot|humidifier_zhimi_humidifier_miot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/actions/fanDmakerMode.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Indstil tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Configurar modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Sett modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus auf [[mode]] einstellen\",\n    \"es\": \"Configurar modo en [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Sett modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]]으로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"label\": {\n            \"en\": \"Straigth Wind\",\n            \"nl\": \"Rechte wind\",\n            \"da\": \"Lige Vind\",\n            \"de\": \"Gerader Wind\",\n            \"es\": \"Viento recto\",\n            \"fr\": \"Vent droit\",\n            \"it\": \"Vento dritto\",\n            \"no\": \"Rett vind\",\n            \"sv\": \"Rak vind\",\n            \"pl\": \"Prosty wiatr\",\n            \"ru\": \"Прямой ветер\",\n            \"ko\": \"직선 바람\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"label\": {\n            \"en\": \"Natural Wind\",\n            \"nl\": \"Natuurlijke wind\",\n            \"da\": \"Naturlig Vind\",\n            \"de\": \"Natürlicher Wind\",\n            \"es\": \"Viento natural\",\n            \"fr\": \"Vent naturel\",\n            \"it\": \"Vento naturale\",\n            \"no\": \"Naturlig vind\",\n            \"sv\": \"Naturlig vind\",\n            \"pl\": \"Naturalny wiatr\",\n            \"ru\": \"Естественный ветер\",\n            \"ko\": \"자연풍\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Dmaker Fan\",\n        \"nl\": \"Selecteer Dmaker Fan\",\n        \"da\": \"Vælg Dmaker Ventilator\",\n        \"de\": \"Wählen Sie Dmaker Ventilator\",\n        \"es\": \"Seleccione Dmaker Fan\",\n        \"fr\": \"Sélectionnez Dmaker Ventilateur\",\n        \"it\": \"Seleziona Dmaker Ventilatore\",\n        \"no\": \"Velg Dmaker Vifte\",\n        \"sv\": \"Välj Dmaker Fläkt\",\n        \"pl\": \"Wybierz wentylator Dmaker\",\n        \"ru\": \"Выберите вентилятор Dmaker\",\n        \"ko\": \"Dmaker 팬 선택\"\n      },\n      \"filter\": \"driver_id=fan_dmaker_advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/fanPowerVacuum.json",
    "content": "{\n  \"id\": \"fanPowerVacuum\",\n  \"title\": {\n    \"en\": \"Set Fanspeed\",\n    \"nl\": \"Stel ventilator in\",\n    \"da\": \"Indstil ventilatorhastighed\",\n    \"de\": \"Lüftergeschwindigkeit einstellen\",\n    \"es\": \"Ajustar la velocidad del ventilador\",\n    \"fr\": \"Régler la vitesse du ventilateur\",\n    \"it\": \"Imposta velocità ventola\",\n    \"no\": \"Sett viftespeed\",\n    \"sv\": \"Ställ in fläkthastigheten\",\n    \"pl\": \"Ustaw prędkość wentylatora\",\n    \"ru\": \"Установить скорость вентилятора\",\n    \"ko\": \"팬 속도 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set Fanspeed [[fanspeed]]\",\n    \"nl\": \"Stel ventilator in op [[fanspeed]]\",\n    \"da\": \"Indstil ventilatorhastighed [[fanspeed]]\",\n    \"de\": \"Lüftergeschwindigkeit einstellen [[fanspeed]]\",\n    \"es\": \"Ajustar la velocidad del ventilador [[fanspeed]]\",\n    \"fr\": \"Régler la vitesse du ventilateur [[fanspeed]]\",\n    \"it\": \"Imposta velocità ventola [[fanspeed]]\",\n    \"no\": \"Sett viftespeed [[fanspeed]]\",\n    \"sv\": \"Ställ in fläkthastigheten [[fanspeed]]\",\n    \"pl\": \"Ustaw prędkość wentylatora [[fanspeed]]\",\n    \"ru\": \"Установить скорость вентилятора [[fanspeed]]\",\n    \"ko\": \"팬 속도 설정 [[fanspeed]]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"fanspeed\",\n      \"title\": {\n        \"en\": \"Fanspeed\",\n        \"nl\": \"Fan snelheid\",\n        \"da\": \"Ventilatorhastighed\",\n        \"de\": \"Lüftergeschwindigkeit\",\n        \"es\": \"Velocidad del ventilador\",\n        \"fr\": \"Vitesse du ventilateur\",\n        \"it\": \"Velocità della ventola\",\n        \"no\": \"Viftespeed\",\n        \"sv\": \"Fläkthastighet\",\n        \"pl\": \"Prędkość wentylatora\",\n        \"ru\": \"Скорость вентилятора\",\n        \"ko\": \"팬 속도\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"38\",\n          \"label\": {\n            \"en\": \"Quiet\",\n            \"nl\": \"Stil\",\n            \"da\": \"Stille\",\n            \"de\": \"Leise\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"조용한\"\n          }\n        },\n        {\n          \"id\": \"66\",\n          \"label\": {\n            \"en\": \"Balanced\",\n            \"nl\": \"Gebalanceerd\",\n            \"da\": \"Balanceret\",\n            \"de\": \"Ausgewogen\",\n            \"es\": \"Equilibrado\",\n            \"fr\": \"Équilibré\",\n            \"it\": \"Bilanciato\",\n            \"no\": \"Balansert\",\n            \"sv\": \"Balanserad\",\n            \"pl\": \"Zrównoważony\",\n            \"ru\": \"Сбалансированный\",\n            \"ko\": \"균형 잡힌\"\n          }\n        },\n        {\n          \"id\": \"77\",\n          \"label\": {\n            \"en\": \"Turbo\",\n            \"nl\": \"Turbo\",\n            \"da\": \"Turbo\",\n            \"de\": \"Turbo\",\n            \"es\": \"Turbo\",\n            \"fr\": \"Turbo\",\n            \"it\": \"Turbo\",\n            \"no\": \"Turbo\",\n            \"sv\": \"Turbo\",\n            \"pl\": \"Turbo\",\n            \"ru\": \"Турбо\",\n            \"ko\": \"터보\"\n          }\n        },\n        {\n          \"id\": \"90\",\n          \"label\": {\n            \"en\": \"Max\",\n            \"nl\": \"Maximum\",\n            \"da\": \"Maks\",\n            \"de\": \"Max\",\n            \"es\": \"Max\",\n            \"fr\": \"Max\",\n            \"it\": \"Max\",\n            \"no\": \"Maks\",\n            \"sv\": \"Maks\",\n            \"pl\": \"Maks\",\n            \"ru\": \"Макс\",\n            \"ko\": \"맥스\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Robot\",\n        \"nl\": \"Selecteer Mi Robot\",\n        \"da\": \"Vælg Mi Robot\",\n        \"de\": \"Mi Roboter auswählen\",\n        \"es\": \"Selecciona Mi Robot\",\n        \"fr\": \"Sélectionnez Mi Robot\",\n        \"it\": \"Seleziona Mi Robot\",\n        \"no\": \"Velg Mi Robot\",\n        \"sv\": \"Välj Mi Robot\",\n        \"pl\": \"Wybierz Mi Robot\",\n        \"ru\": \"Выберите Mi Robot\",\n        \"ko\": \"Mi 로봇 선택\"\n      },\n      \"filter\": \"driver_id=mi-robot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/fanZhimiMode.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Sæt tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Establecer modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Sett modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Sæt modus til [[mode]]\",\n    \"de\": \"Modus auf [[mode]] einstellen\",\n    \"es\": \"Establecer modo a [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Sett modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Natural Wind\",\n            \"nl\": \"Natuur wind\",\n            \"da\": \"Naturlig vind\",\n            \"de\": \"Natürlicher Wind\",\n            \"es\": \"Viento Natural\",\n            \"fr\": \"Vent Naturel\",\n            \"it\": \"Vento Naturale\",\n            \"no\": \"Naturlig vind\",\n            \"sv\": \"Naturlig vind\",\n            \"pl\": \"Naturalny wiatr\",\n            \"ru\": \"Естественный ветер\",\n            \"ko\": \"자연풍\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Straight Wind\",\n            \"nl\": \"Rechte wind\",\n            \"da\": \"Lige vind\",\n            \"de\": \"Gerader Wind\",\n            \"es\": \"Viento Directo\",\n            \"fr\": \"Vent Droit\",\n            \"it\": \"Vento Dritto\",\n            \"no\": \"Rett vind\",\n            \"sv\": \"Rakt vind\",\n            \"pl\": \"Prosty wiatr\",\n            \"ru\": \"Прямой ветер\",\n            \"ko\": \"직선풍\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Fan\",\n        \"nl\": \"Selecteer Fan\",\n        \"da\": \"Vælg ventilator\",\n        \"de\": \"Lüfter auswählen\",\n        \"es\": \"Seleccionar Ventilador\",\n        \"fr\": \"Sélectionner le Ventilateur\",\n        \"it\": \"Seleziona Ventilatore\",\n        \"no\": \"Velg vifte\",\n        \"sv\": \"Välj fläkt\",\n        \"pl\": \"Wybierz Wentylator\",\n        \"ru\": \"Выбрать вентилятор\",\n        \"ko\": \"팬 선택\"\n      },\n      \"filter\": \"driver_id=fan_zhimi_advanced|fan_zhimi_fan_za5\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/findVacuum.json",
    "content": "{\n  \"id\": \"findVacuum\",\n  \"title\": {\n    \"en\": \"Find vacuum cleaner\",\n    \"nl\": \"Vind stofzuiger\",\n    \"da\": \"Find støvsuger\",\n    \"de\": \"Staubsauger finden\",\n    \"es\": \"Encontrar aspiradora\",\n    \"fr\": \"Trouver l'aspirateur\",\n    \"it\": \"Trova l'aspirapolvere\",\n    \"no\": \"Finn støvsugeren\",\n    \"sv\": \"Hitta dammsugare\",\n    \"pl\": \"Znajdź odkurzacz\",\n    \"ru\": \"Найти пылесос\",\n    \"ko\": \"진공 청소기 찾기\"\n  },\n  \"hint\": {\n    \"en\": \"Let the vacuum cleaner tell you where it's at\",\n    \"nl\": \"Laat de stofzuiger vertellen waar hij is\",\n    \"da\": \"Lad støvsugeren fortælle dig, hvor den er\",\n    \"de\": \"Lass den Staubsauger dir sagen, wo er ist\",\n    \"es\": \"Deja que la aspiradora te diga dónde está\",\n    \"fr\": \"Laisse l'aspirateur te dire où il est\",\n    \"it\": \"Lascia che l'aspirapolvere ti dica dove si trova\",\n    \"no\": \"La støvsugeren fortelle deg hvor den er\",\n    \"sv\": \"Låt dammsugaren berätta var den är\",\n    \"pl\": \"Pozwól odkuraczowi powiedzieć, gdzie się znajduje\",\n    \"ru\": \"Пусть пылесос скажет, где он\",\n    \"ko\": \"진공 청소기가 어디에 있는지 알려주세요\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Robot\",\n        \"nl\": \"Selecteer Mi Robot\",\n        \"da\": \"Vælg Mi Robot\",\n        \"de\": \"Wählen Sie Mi Robot\",\n        \"es\": \"Seleccionar Mi Robot\",\n        \"fr\": \"Sélectionner Mi Robot\",\n        \"it\": \"Seleziona Mi Robot\",\n        \"no\": \"Velg Mi Robot\",\n        \"sv\": \"Välj Mi Robot\",\n        \"pl\": \"Wybierz Mi Robot\",\n        \"ru\": \"Выберите Mi Robot\",\n        \"ko\": \"Mi Robot 선택\"\n      },\n      \"filter\": \"driver_id=mi-robot|vacuum_mi_rockrobo_vacuum_advanced|vacuum_mi_rockrobo_vacuum_t6\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/gateway_custom_radio.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Play custom radio station\",\n    \"nl\": \"Afspelen custom radio station\",\n    \"da\": \"Afspil tilpasset radiostation\",\n    \"de\": \"Spiele benutzerdefinierten Radiosender\",\n    \"es\": \"Reproduce emisora de radio personalizada\",\n    \"fr\": \"Lire station de radio personnalisée\",\n    \"it\": \"Riproduci stazione radio personalizzata\",\n    \"no\": \"Spill tilpasset radiostasjon\",\n    \"sv\": \"Spela anpassad radiostation\",\n    \"pl\": \"Odtwórz dostosowaną stację radiową\",\n    \"ru\": \"Воспроизвести пользовательскую радиостанцию\",\n    \"ko\": \"맞춤형 라디오 방송국 재생\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Play custom radio station [[id]] on url [[url]] with volume [[volume]]\",\n    \"nl\": \"Afspelen custom radio station [[id]] op [[url]] met volume [[volume]]\",\n    \"da\": \"Afspil tilpasset radiostation [[id]] på url [[url]] med lydstyrke [[volume]]\",\n    \"de\": \"Spiele benutzerdefinierten Radiosender [[id]] auf URL [[url]] mit Lautstärke [[volume]]\",\n    \"es\": \"Reproduce emisora de radio personalizada [[id]] en url [[url]] con volumen [[volume]]\",\n    \"fr\": \"Lire station de radio personnalisée [[id]] sur url [[url]] avec volume [[volume]]\",\n    \"it\": \"Riproduci stazione radio personalizzata [[id]] su url [[url]] con volume [[volume]]\",\n    \"no\": \"Spill tilpasset radiostasjon [[id]] på url [[url]] med volum [[volume]]\",\n    \"sv\": \"Spela anpassad radiostation [[id]] på url [[url]] med volym [[volume]]\",\n    \"pl\": \"Odtwórz dostosowaną stację radiową [[id]] na url [[url]] z głośnością [[volume]]\",\n    \"ru\": \"Воспроизведите пользовательскую радиостанцию [[id]] на url [[url]] с громкостью [[volume]]\",\n    \"ko\": \"맞춤형 라디오 방송국 [[id]]의 url [[url]]에서 볼륨 [[volume]]으로 재생\"\n  },\n  \"args\": [\n    {\n      \"name\": \"id\",\n      \"title\": {\n        \"en\": \"Station ID\",\n        \"nl\": \"Station ID\",\n        \"da\": \"Station ID\",\n        \"de\": \"Sender-ID\",\n        \"es\": \"ID de estación\",\n        \"fr\": \"ID de la station\",\n        \"it\": \"ID stazione\",\n        \"no\": \"Stasjons-ID\",\n        \"sv\": \"Stations-ID\",\n        \"pl\": \"ID stacji\",\n        \"ru\": \"ID станции\",\n        \"ko\": \"방송국 ID\"\n      },\n      \"type\": \"text\",\n      \"placeholder\": {\n        \"en\": \"ID\",\n        \"nl\": \"ID\",\n        \"da\": \"ID\",\n        \"de\": \"ID\",\n        \"es\": \"ID\",\n        \"fr\": \"ID\",\n        \"it\": \"ID\",\n        \"no\": \"ID\",\n        \"sv\": \"ID\",\n        \"pl\": \"ID\",\n        \"ru\": \"ID\",\n        \"ko\": \"ID\"\n      }\n    },\n    {\n      \"name\": \"url\",\n      \"title\": {\n        \"en\": \"URL\",\n        \"nl\": \"URL\",\n        \"da\": \"URL\",\n        \"de\": \"URL\",\n        \"es\": \"URL\",\n        \"fr\": \"URL\",\n        \"it\": \"URL\",\n        \"no\": \"URL\",\n        \"sv\": \"URL\",\n        \"pl\": \"URL\",\n        \"ru\": \"URL\",\n        \"ko\": \"URL\"\n      },\n      \"type\": \"text\",\n      \"placeholder\": {\n        \"en\": \"URL\",\n        \"nl\": \"URL\",\n        \"da\": \"URL\",\n        \"de\": \"URL\",\n        \"es\": \"URL\",\n        \"fr\": \"URL\",\n        \"it\": \"URL\",\n        \"no\": \"URL\",\n        \"sv\": \"URL\",\n        \"pl\": \"URL\",\n        \"ru\": \"URL\",\n        \"ko\": \"URL\"\n      }\n    },\n    {\n      \"type\": \"range\",\n      \"title\": {\n        \"en\": \"Volume\",\n        \"nl\": \"Volume\",\n        \"da\": \"Volumen\",\n        \"de\": \"Lautstärke\",\n        \"es\": \"Volumen\",\n        \"fr\": \"Volume\",\n        \"it\": \"Volume\",\n        \"no\": \"Volum\",\n        \"sv\": \"Volym\",\n        \"pl\": \"Głośność\",\n        \"ru\": \"Громкость\",\n        \"ko\": \"볼륨\"\n      },\n      \"name\": \"volume\",\n      \"min\": 0,\n      \"max\": 1,\n      \"step\": 0.01,\n      \"label\": \"%\",\n      \"labelMultiplier\": 100,\n      \"labelDecimals\": 0\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Gateway\",\n        \"nl\": \"Selecteer Gateway\",\n        \"da\": \"Vælg Gateway\",\n        \"de\": \"Gateway auswählen\",\n        \"es\": \"Seleccionar Gateway\",\n        \"fr\": \"Sélectionner la passerelle\",\n        \"it\": \"Seleziona Gateway\",\n        \"no\": \"Velg Gateway\",\n        \"sv\": \"Välj Gateway\",\n        \"pl\": \"Wybierz bramę\",\n        \"ru\": \"Выберите шлюз\",\n        \"ko\": \"게이트웨이 선택\"\n      },\n      \"filter\": \"driver_id=gateway\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/gateway_play_effect.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Play effect\",\n    \"nl\": \"Speel effect\",\n    \"da\": \"Afspil effekt\",\n    \"de\": \"Effekt abspielen\",\n    \"es\": \"Reproducir efecto\",\n    \"fr\": \"Jouer l'effet\",\n    \"it\": \"Riproduci effetto\",\n    \"no\": \"Spill av effekt\",\n    \"sv\": \"Spela effekt\",\n    \"pl\": \"Odtwórz efekt\",\n    \"ru\": \"Воспроизвести эффект\",\n    \"ko\": \"효과 재생\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Play effect [[toneID]]\",\n    \"nl\": \"Speel effect [[toneID]]\",\n    \"da\": \"Afspil effekt [[toneID]]\",\n    \"de\": \"Effekt abspielen [[toneID]]\",\n    \"es\": \"Reproducir efecto [[toneID]]\",\n    \"fr\": \"Jouer l'effet [[toneID]]\",\n    \"it\": \"Riproduci effetto [[toneID]]\",\n    \"no\": \"Spill av effekt [[toneID]]\",\n    \"sv\": \"Spela effekt [[toneID]]\",\n    \"pl\": \"Odtwórz efekt [[toneID]]\",\n    \"ru\": \"Воспроизвести эффект [[toneID]]\",\n    \"ko\": \"효과 재생 [[toneID]]\"\n  },\n  \"args\": [\n    {\n      \"type\": \"dropdown\",\n      \"title\": {\n        \"en\": \"Effect ID\",\n        \"nl\": \"Effect ID\",\n        \"da\": \"Effekt-ID\",\n        \"de\": \"Effekt-ID\",\n        \"es\": \"ID de efecto\",\n        \"fr\": \"ID d'effet\",\n        \"it\": \"ID effetto\",\n        \"no\": \"Effekt-ID\",\n        \"sv\": \"Effekt-ID\",\n        \"pl\": \"ID efektu\",\n        \"ru\": \"ID эффекта\",\n        \"ko\": \"효과 ID\"\n      },\n      \"name\": \"toneID\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"label\": {\n            \"en\": \"Police car 1\",\n            \"da\": \"Politibil 1\",\n            \"de\": \"Polizeiauto 1\",\n            \"es\": \"Coche de policía 1\",\n            \"fr\": \"Voiture de police 1\",\n            \"it\": \"Auto della polizia 1\",\n            \"no\": \"Politibil 1\",\n            \"sv\": \"Polisbil 1\",\n            \"pl\": \"Radiowóz 1\",\n            \"ru\": \"Полицейская машина 1\",\n            \"ko\": \"경찰차 1\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"label\": {\n            \"en\": \"Police car 2\",\n            \"da\": \"Politibil 2\",\n            \"de\": \"Polizeiauto 2\",\n            \"es\": \"Coche de policía 2\",\n            \"fr\": \"Voiture de police 2\",\n            \"it\": \"Auto della polizia 2\",\n            \"no\": \"Politibil 2\",\n            \"sv\": \"Polisbil 2\",\n            \"pl\": \"Radiowóz 2\",\n            \"ru\": \"Полицейская машина 2\",\n            \"ko\": \"경찰차 2\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"label\": {\n            \"en\": \"Accident\",\n            \"da\": \"Uheld\",\n            \"de\": \"Unfall\",\n            \"es\": \"Accidente\",\n            \"fr\": \"Accident\",\n            \"it\": \"Incidente\",\n            \"no\": \"Ulykke\",\n            \"sv\": \"Olycka\",\n            \"pl\": \"Wypadek\",\n            \"ru\": \"Авария\",\n            \"ko\": \"사고\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"label\": {\n            \"en\": \"Countdown\",\n            \"da\": \"Nedtælling\",\n            \"de\": \"Countdown\",\n            \"es\": \"Cuenta regresiva\",\n            \"fr\": \"Compte à rebours\",\n            \"it\": \"Conto alla rovescia\",\n            \"no\": \"Nedtelling\",\n            \"sv\": \"Nedräkning\",\n            \"pl\": \"Odliczanie\",\n            \"ru\": \"Обратный отсчет\",\n            \"ko\": \"카운트다운\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"label\": {\n            \"en\": \"Ghost\",\n            \"da\": \"Spøgelse\",\n            \"de\": \"Gespenst\",\n            \"es\": \"Fantasma\",\n            \"fr\": \"Fantôme\",\n            \"it\": \"Fantasma\",\n            \"no\": \"Spøkelse\",\n            \"sv\": \"Spöke\",\n            \"pl\": \"Duch\",\n            \"ru\": \"Призрак\",\n            \"ko\": \"유령\"\n          }\n        },\n        {\n          \"id\": \"5\",\n          \"label\": {\n            \"en\": \"Sniper rifle\",\n            \"da\": \"Snigskytteriffel\",\n            \"de\": \"Scharfschützengewehr\",\n            \"es\": \"Rifle de francotirador\",\n            \"fr\": \"Fusil de sniper\",\n            \"it\": \"Fucile da cecchino\",\n            \"no\": \"Snikskytterifle\",\n            \"sv\": \"Krypskyttegevär\",\n            \"pl\": \"Karabin snajperski\",\n            \"ru\": \"Снайперская винтовка\",\n            \"ko\": \"저격 소총\"\n          }\n        },\n        {\n          \"id\": \"6\",\n          \"label\": {\n            \"en\": \"Battle\",\n            \"da\": \"Kamp\",\n            \"de\": \"Schlacht\",\n            \"es\": \"Batalla\",\n            \"fr\": \"Bataille\",\n            \"it\": \"Battaglia\",\n            \"no\": \"Kamp\",\n            \"sv\": \"Strid\",\n            \"pl\": \"Bitwa\",\n            \"ru\": \"Битва\",\n            \"ko\": \"전투\"\n          }\n        },\n        {\n          \"id\": \"7\",\n          \"label\": {\n            \"en\": \"Air raid\",\n            \"da\": \"Luftangreb\",\n            \"de\": \"Luftangriff\",\n            \"es\": \"Ataque aéreo\",\n            \"fr\": \"Raid aérien\",\n            \"it\": \"Incursione aerea\",\n            \"no\": \"Luftangrep\",\n            \"sv\": \"Flyganfall\",\n            \"pl\": \"Nalot\",\n            \"ru\": \"Воздушный налет\",\n            \"ko\": \"공습\"\n          }\n        },\n        {\n          \"id\": \"8\",\n          \"label\": {\n            \"en\": \"Bark\",\n            \"da\": \"Gøen\",\n            \"de\": \"Bellen\",\n            \"es\": \"Ladrido\",\n            \"fr\": \"Aboiement\",\n            \"it\": \"Abbaiare\",\n            \"no\": \"Bjeffing\",\n            \"sv\": \"Skall\",\n            \"pl\": \"Szczekanie\",\n            \"ru\": \"Лай\",\n            \"ko\": \"짖다\"\n          }\n        },\n        {\n          \"id\": \"10\",\n          \"label\": {\n            \"en\": \"Doorbell\",\n            \"da\": \"Dørklokke\",\n            \"de\": \"Türklingel\",\n            \"es\": \"Timbre\",\n            \"fr\": \"Sonnette\",\n            \"it\": \"Campanello\",\n            \"no\": \"Ringeklokke\",\n            \"sv\": \"Dörrklocka\",\n            \"pl\": \"Dzwonek do drzwi\",\n            \"ru\": \"Дверной звонок\",\n            \"ko\": \"문 벨\"\n          }\n        },\n        {\n          \"id\": \"11\",\n          \"label\": {\n            \"en\": \"Knock at a door\",\n            \"da\": \"Banke på en dør\",\n            \"de\": \"Klopfen an der Tür\",\n            \"es\": \"Llamar a la puerta\",\n            \"fr\": \"Frapper à une porte\",\n            \"it\": \"Bussare alla porta\",\n            \"no\": \"Banke på en dør\",\n            \"sv\": \"Knacka på en dörr\",\n            \"pl\": \"Pukanie do drzwi\",\n            \"ru\": \"стучать в дверь\",\n            \"ko\": \"문을 두드리다\"\n          }\n        },\n        {\n          \"id\": \"12\",\n          \"label\": {\n            \"en\": \"Amuse\",\n            \"da\": \"Underholde\",\n            \"de\": \"Unterhalten\",\n            \"es\": \"Divertir\",\n            \"fr\": \"Amuser\",\n            \"it\": \"Divertire\",\n            \"no\": \"Underholde\",\n            \"sv\": \"Underhålla\",\n            \"pl\": \"Bawić\",\n            \"ru\": \"развлекать\",\n            \"ko\": \"즐겁게 하다\"\n          }\n        },\n        {\n          \"id\": \"13\",\n          \"label\": {\n            \"en\": \"Alarm clock\",\n            \"da\": \"Vækkeur\",\n            \"de\": \"Wecker\",\n            \"es\": \"Reloj despertador\",\n            \"fr\": \"Réveil\",\n            \"it\": \"Sveglia\",\n            \"no\": \"Vekkerklokke\",\n            \"sv\": \"Väckarklocka\",\n            \"pl\": \"Budzik\",\n            \"ru\": \"Будильник\",\n            \"ko\": \"알람 시계\"\n          }\n        },\n        {\n          \"id\": \"20\",\n          \"label\": {\n            \"en\": \"MiMix\",\n            \"da\": \"MiMix\",\n            \"de\": \"MiMix\",\n            \"es\": \"MiMix\",\n            \"fr\": \"MiMix\",\n            \"it\": \"MiMix\",\n            \"no\": \"MiMix\",\n            \"sv\": \"MiMix\",\n            \"pl\": \"MiMix\",\n            \"ru\": \"MiMix\",\n            \"ko\": \"MiMix\"\n          }\n        },\n        {\n          \"id\": \"21\",\n          \"label\": {\n            \"en\": \"Enthusiastic\",\n            \"da\": \"Entusiastisk\",\n            \"de\": \"Enthusiastisch\",\n            \"es\": \"Entusiasta\",\n            \"fr\": \"Enthousiaste\",\n            \"it\": \"Entusiasta\",\n            \"no\": \"Entusiastisk\",\n            \"sv\": \"Entusiastisk\",\n            \"pl\": \"Entuzjastyczny\",\n            \"ru\": \"Восторженный\",\n            \"ko\": \"열렬한\"\n          }\n        },\n        {\n          \"id\": \"22\",\n          \"label\": {\n            \"en\": \"GuitarClassic\",\n            \"da\": \"GuitarClassic\",\n            \"de\": \"GuitarClassic\",\n            \"es\": \"GuitarClassic\",\n            \"fr\": \"GuitarClassic\",\n            \"it\": \"GuitarClassic\",\n            \"no\": \"GuitarClassic\",\n            \"sv\": \"GuitarClassic\",\n            \"pl\": \"GuitarClassic\",\n            \"ru\": \"GuitarClassic\",\n            \"ko\": \"GuitarClassic\"\n          }\n        },\n        {\n          \"id\": \"23\",\n          \"label\": {\n            \"en\": \"IceWorldPiano\",\n            \"da\": \"IceWorldPiano\",\n            \"de\": \"IceWorldPiano\",\n            \"es\": \"IceWorldPiano\",\n            \"fr\": \"IceWorldPiano\",\n            \"it\": \"IceWorldPiano\",\n            \"no\": \"IceWorldPiano\",\n            \"sv\": \"IceWorldPiano\",\n            \"pl\": \"IceWorldPiano\",\n            \"ru\": \"IceWorldPiano\",\n            \"ko\": \"IceWorldPiano\"\n          }\n        },\n        {\n          \"id\": \"24\",\n          \"label\": {\n            \"en\": \"LeisureTime\",\n            \"da\": \"LeisureTime\",\n            \"de\": \"LeisureTime\",\n            \"es\": \"LeisureTime\",\n            \"fr\": \"LeisureTime\",\n            \"it\": \"LeisureTime\",\n            \"no\": \"LeisureTime\",\n            \"sv\": \"LeisureTime\",\n            \"pl\": \"LeisureTime\",\n            \"ru\": \"LeisureTime\",\n            \"ko\": \"LeisureTime\"\n          }\n        },\n        {\n          \"id\": \"25\",\n          \"label\": {\n            \"en\": \"ChildHood\",\n            \"da\": \"ChildHood\",\n            \"de\": \"ChildHood\",\n            \"es\": \"ChildHood\",\n            \"fr\": \"ChildHood\",\n            \"it\": \"ChildHood\",\n            \"no\": \"ChildHood\",\n            \"sv\": \"ChildHood\",\n            \"pl\": \"ChildHood\",\n            \"ru\": \"ChildHood\",\n            \"ko\": \"ChildHood\"\n          }\n        },\n        {\n          \"id\": \"26\",\n          \"label\": {\n            \"en\": \"MorningStreamLiet\",\n            \"da\": \"MorningStreamLiet\",\n            \"de\": \"MorningStreamLiet\",\n            \"es\": \"MorningStreamLiet\",\n            \"fr\": \"MorningStreamLiet\",\n            \"it\": \"MorningStreamLiet\",\n            \"no\": \"MorningStreamLiet\",\n            \"sv\": \"MorningStreamLiet\",\n            \"pl\": \"MorningStreamLiet\",\n            \"ru\": \"MorningStreamLiet\",\n            \"ko\": \"MorningStreamLiet\"\n          }\n        },\n        {\n          \"id\": \"27\",\n          \"label\": {\n            \"en\": \"MusicBox\",\n            \"da\": \"MusicBox\",\n            \"de\": \"MusicBox\",\n            \"es\": \"MusicBox\",\n            \"fr\": \"MusicBox\",\n            \"it\": \"MusicBox\",\n            \"no\": \"MusicBox\",\n            \"sv\": \"MusicBox\",\n            \"pl\": \"MusicBox\",\n            \"ru\": \"MusicBox\",\n            \"ko\": \"MusicBox\"\n          }\n        },\n        {\n          \"id\": \"28\",\n          \"label\": {\n            \"en\": \"Orange\",\n            \"da\": \"Orange\",\n            \"de\": \"Orange\",\n            \"es\": \"Naranja\",\n            \"fr\": \"Orange\",\n            \"it\": \"Arancio\",\n            \"no\": \"Oransje\",\n            \"sv\": \"Orange\",\n            \"pl\": \"Pomarańczowy\",\n            \"ru\": \"Оранжевый\",\n            \"ko\": \"오렌지\"\n          }\n        },\n        {\n          \"id\": \"29\",\n          \"label\": {\n            \"en\": \"Thinker\",\n            \"da\": \"Tænker\",\n            \"de\": \"Denker\",\n            \"es\": \"Pensador\",\n            \"fr\": \"Penseur\",\n            \"it\": \"Pensatore\",\n            \"no\": \"Tenker\",\n            \"sv\": \"Tänker\",\n            \"pl\": \"Myśliciel\",\n            \"ru\": \"Мыслитель\",\n            \"ko\": \"사색가\"\n          }\n        },\n        {\n          \"id\": \"10000\",\n          \"label\": {\n            \"en\": \"MUTE\",\n            \"da\": \"STUM\",\n            \"de\": \"STUMM\",\n            \"es\": \"MUDO\",\n            \"fr\": \"SILENCE\",\n            \"it\": \"MUTO\",\n            \"no\": \"STILLE\",\n            \"sv\": \"TYST\",\n            \"pl\": \"WYŁĄCZONY\",\n            \"ru\": \"БЕСШУМНЫЙ\",\n            \"ko\": \"무음\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Gateway\",\n        \"nl\": \"Selecteer Gateway\",\n        \"da\": \"Vælg Gateway\",\n        \"de\": \"Gateway auswählen\",\n        \"es\": \"Seleccionar Gateway\",\n        \"fr\": \"Sélectionner la passerelle\",\n        \"it\": \"Seleziona Gateway\",\n        \"no\": \"Velg Gateway\",\n        \"sv\": \"Välj Gateway\",\n        \"pl\": \"Wybierz Gateway\",\n        \"ru\": \"Выберите шлюз\",\n        \"ko\": \"게이트웨이 선택\"\n      },\n      \"filter\": \"driver_id=gateway\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/gateway_play_radio.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Play favorite radio station\",\n    \"nl\": \"Afspelen favoriete radio station\",\n    \"da\": \"Afspil favorit radiostation\",\n    \"de\": \"Favoriten-Radiosender abspielen\",\n    \"es\": \"Reproducir emisora de radio favorita\",\n    \"fr\": \"Jouer la station de radio favorite\",\n    \"it\": \"Riproduci stazione radio preferita\",\n    \"no\": \"Spill favoritt radiostasjon\",\n    \"sv\": \"Spela favorit radiostation\",\n    \"pl\": \"Odtwórz ulubioną stację radiową\",\n    \"ru\": \"Воспроизвести любимую радиостанцию\",\n    \"ko\": \"좋아하는 라디오 방송 재생\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Play favorite radio station [[favoriteID]] with volume [[volume]]\",\n    \"nl\": \"Afspelen favoriete radio station [[favoriteID]] met volume [[volume]]\",\n    \"da\": \"Afspil favorit radiostation [[favoriteID]] med lydstyrke [[volume]]\",\n    \"de\": \"Favoriten-Radiosender [[favoriteID]] mit Lautstärke [[volume]] abspielen\",\n    \"es\": \"Reproducir emisora de radio favorita [[favoriteID]] con volumen [[volume]]\",\n    \"fr\": \"Jouer la station de radio favorite [[favoriteID]] avec le volume [[volume]]\",\n    \"it\": \"Riproduci stazione radio preferita [[favoriteID]] con volume [[volume]]\",\n    \"no\": \"Spill favoritt radiostasjon [[favoriteID]] med volum [[volume]]\",\n    \"sv\": \"Spela favorit radiostation [[favoriteID]] med volym [[volume]]\",\n    \"pl\": \"Odtwórz ulubioną stację radiową [[favoriteID]] z głośnością [[volume]]\",\n    \"ru\": \"Воспроизвести любимую радиостанцию [[favoriteID]] с громкостью [[volume]]\",\n    \"ko\": \"좋아하는 라디오 방송 [[favoriteID]] 볼륨 [[volume]]으로 재생\"\n  },\n  \"args\": [\n    {\n      \"type\": \"dropdown\",\n      \"title\": {\n        \"en\": \"Station ID\",\n        \"nl\": \"Station ID\",\n        \"da\": \"Station ID\",\n        \"de\": \"Stations-ID\",\n        \"es\": \"ID de estación\",\n        \"fr\": \"ID de la station\",\n        \"it\": \"ID stazione\",\n        \"no\": \"Stasjons-ID\",\n        \"sv\": \"Stations-ID\",\n        \"pl\": \"ID stacji\",\n        \"ru\": \"Идентификатор станции\",\n        \"ko\": \"스테이션 ID\"\n      },\n      \"name\": \"favoriteID\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"label\": {\n            \"en\": \"1 - favorite radio\",\n            \"nl\": \"1 - favoriete station\",\n            \"da\": \"1 - favorit radio\",\n            \"de\": \"1 - Lieblingsradio\",\n            \"es\": \"1 - radio favorita\",\n            \"fr\": \"1 - radio favorite\",\n            \"it\": \"1 - radio preferita\",\n            \"no\": \"1 - favoritt radio\",\n            \"sv\": \"1 - favorit radio\",\n            \"pl\": \"1 - ulubione radio\",\n            \"ru\": \"1 - любимое радио\",\n            \"ko\": \"1 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"label\": {\n            \"en\": \"2 - favorite radio\",\n            \"nl\": \"2 - favoriete station\",\n            \"da\": \"2 - favorit radio\",\n            \"de\": \"2 - Lieblingsradio\",\n            \"es\": \"2 - radio favorita\",\n            \"fr\": \"2 - radio favorite\",\n            \"it\": \"2 - radio preferita\",\n            \"no\": \"2 - favoritt radio\",\n            \"sv\": \"2 - favorit radio\",\n            \"pl\": \"2 - ulubione radio\",\n            \"ru\": \"2 - любимое радио\",\n            \"ko\": \"2 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"label\": {\n            \"en\": \"3 - favorite radio\",\n            \"nl\": \"3 - favoriete station\",\n            \"da\": \"3 - favorit radio\",\n            \"de\": \"3 - Lieblingsradio\",\n            \"es\": \"3 - radio favorita\",\n            \"fr\": \"3 - radio favorite\",\n            \"it\": \"3 - radio preferita\",\n            \"no\": \"3 - favoritt radio\",\n            \"sv\": \"3 - favorit radio\",\n            \"pl\": \"3 - ulubione radio\",\n            \"ru\": \"3 - любимое радио\",\n            \"ko\": \"3 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"label\": {\n            \"en\": \"4 - favorite radio\",\n            \"nl\": \"4 - favoriete station\",\n            \"da\": \"4 - favorit radio\",\n            \"de\": \"4 - Lieblingsradio\",\n            \"es\": \"4 - radio favorita\",\n            \"fr\": \"4 - radio favorite\",\n            \"it\": \"4 - radio preferita\",\n            \"no\": \"4 - favoritt radio\",\n            \"sv\": \"4 - favorit radio\",\n            \"pl\": \"4 - ulubione radio\",\n            \"ru\": \"4 - любимое радио\",\n            \"ko\": \"4 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"label\": {\n            \"en\": \"5 - favorite radio\",\n            \"nl\": \"5 - favoriete station\",\n            \"da\": \"5 - favorit radio\",\n            \"de\": \"5 - Lieblingsradio\",\n            \"es\": \"5 - radio favorita\",\n            \"fr\": \"5 - radio favorite\",\n            \"it\": \"5 - radio preferita\",\n            \"no\": \"5 - favoritt radio\",\n            \"sv\": \"5 - favorit radio\",\n            \"pl\": \"5 - ulubione radio\",\n            \"ru\": \"5 - любимое радио\",\n            \"ko\": \"5 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"5\",\n          \"label\": {\n            \"en\": \"6 - favorite radio\",\n            \"nl\": \"6 - favoriete station\",\n            \"da\": \"6 - favorit radio\",\n            \"de\": \"6 - Lieblingsradio\",\n            \"es\": \"6 - radio favorita\",\n            \"fr\": \"6 - radio favorite\",\n            \"it\": \"6 - radio preferita\",\n            \"no\": \"6 - favoritt radio\",\n            \"sv\": \"6 - favorit radio\",\n            \"pl\": \"6 - ulubione radio\",\n            \"ru\": \"6 - любимое радио\",\n            \"ko\": \"6 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"6\",\n          \"label\": {\n            \"en\": \"7 - favorite radio\",\n            \"nl\": \"7 - favoriete station\",\n            \"da\": \"7 - favorit radio\",\n            \"de\": \"7 - Lieblingsradio\",\n            \"es\": \"7 - radio favorita\",\n            \"fr\": \"7 - radio favorite\",\n            \"it\": \"7 - radio preferita\",\n            \"no\": \"7 - favoritt radio\",\n            \"sv\": \"7 - favorit radio\",\n            \"pl\": \"7 - ulubione radio\",\n            \"ru\": \"7 - любимое радио\",\n            \"ko\": \"7 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"7\",\n          \"label\": {\n            \"en\": \"8 - favorite radio\",\n            \"nl\": \"8 - favoriete station\",\n            \"da\": \"8 - favorit radio\",\n            \"de\": \"8 - Lieblingsradio\",\n            \"es\": \"8 - radio favorita\",\n            \"fr\": \"8 - radio favorite\",\n            \"it\": \"8 - radio preferita\",\n            \"no\": \"8 - favoritt radio\",\n            \"sv\": \"8 - favorit radio\",\n            \"pl\": \"8 - ulubione radio\",\n            \"ru\": \"8 - любимое радио\",\n            \"ko\": \"8 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"8\",\n          \"label\": {\n            \"en\": \"9 - favorite radio\",\n            \"nl\": \"9 - favoriete station\",\n            \"da\": \"9 - favorit radio\",\n            \"de\": \"9 - Lieblingsradio\",\n            \"es\": \"9 - radio favorita\",\n            \"fr\": \"9 - radio favorite\",\n            \"it\": \"9 - radio preferita\",\n            \"no\": \"9 - favoritt radio\",\n            \"sv\": \"9 - favorit radio\",\n            \"pl\": \"9 - ulubione radio\",\n            \"ru\": \"9 - любимое радио\",\n            \"ko\": \"9 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"9\",\n          \"label\": {\n            \"en\": \"10 - favorite radio\",\n            \"nl\": \"10 - favoriete station\",\n            \"da\": \"10 - favorit radio\",\n            \"de\": \"10 - Lieblingsradio\",\n            \"es\": \"10 - radio favorita\",\n            \"fr\": \"10 - radio favorite\",\n            \"it\": \"10 - radio preferita\",\n            \"no\": \"10 - favoritt radio\",\n            \"sv\": \"10 - favorit radio\",\n            \"pl\": \"10 - ulubione radio\",\n            \"ru\": \"10 - любимое радио\",\n            \"ko\": \"10 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"10\",\n          \"label\": {\n            \"en\": \"11 - favorite radio\",\n            \"nl\": \"11 - favoriete station\",\n            \"da\": \"11 - favorit radio\",\n            \"de\": \"11 - Lieblingsradio\",\n            \"es\": \"11 - radio favorita\",\n            \"fr\": \"11 - radio favorite\",\n            \"it\": \"11 - radio preferita\",\n            \"no\": \"11 - favoritt radio\",\n            \"sv\": \"11 - favorit radio\",\n            \"pl\": \"11 - ulubione radio\",\n            \"ru\": \"11 - любимое радио\",\n            \"ko\": \"11 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"11\",\n          \"label\": {\n            \"en\": \"12 - favorite radio\",\n            \"nl\": \"12 - favoriete station\",\n            \"da\": \"12 - favorit radio\",\n            \"de\": \"12 - Lieblingsradio\",\n            \"es\": \"12 - radio favorita\",\n            \"fr\": \"12 - radio favorite\",\n            \"it\": \"12 - radio preferita\",\n            \"no\": \"12 - favoritt radio\",\n            \"sv\": \"12 - favorit radio\",\n            \"pl\": \"12 - ulubione radio\",\n            \"ru\": \"12 - любимое радио\",\n            \"ko\": \"12 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"12\",\n          \"label\": {\n            \"en\": \"13 - favorite radio\",\n            \"nl\": \"13 - favoriete station\",\n            \"da\": \"13 - favorit radio\",\n            \"de\": \"13 - Lieblingsradio\",\n            \"es\": \"13 - radio favorita\",\n            \"fr\": \"13 - radio favorite\",\n            \"it\": \"13 - radio preferita\",\n            \"no\": \"13 - favoritt radio\",\n            \"sv\": \"13 - favorit radio\",\n            \"pl\": \"13 - ulubione radio\",\n            \"ru\": \"13 - любимое радио\",\n            \"ko\": \"13 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"13\",\n          \"label\": {\n            \"en\": \"14 - favorite radio\",\n            \"nl\": \"14 - favoriete station\",\n            \"da\": \"14 - favorit radio\",\n            \"de\": \"14 - Lieblingsradio\",\n            \"es\": \"14 - radio favorita\",\n            \"fr\": \"14 - radio favorite\",\n            \"it\": \"14 - radio preferita\",\n            \"no\": \"14 - favoritt radio\",\n            \"sv\": \"14 - favorit radio\",\n            \"pl\": \"14 - ulubione radio\",\n            \"ru\": \"14 - любимое радио\",\n            \"ko\": \"14 - 좋아하는 라디오\"\n          }\n        },\n        {\n          \"id\": \"13\",\n          \"label\": {\n            \"en\": \"15 - favorite radio\",\n            \"nl\": \"15 - favoriete station\",\n            \"da\": \"15 - favorit radio\",\n            \"de\": \"15 - Lieblingsradio\",\n            \"es\": \"15 - radio favorita\",\n            \"fr\": \"15 - radio favorite\",\n            \"it\": \"15 - radio preferita\",\n            \"no\": \"15 - favoritt radio\",\n            \"sv\": \"15 - favorit radio\",\n            \"pl\": \"15 - ulubione radio\",\n            \"ru\": \"15 - любимое радио\",\n            \"ko\": \"15 - 좋아하는 라디오\"\n          }\n        }\n      ]\n    },\n    {\n      \"type\": \"range\",\n      \"title\": {\n        \"en\": \"Volume\",\n        \"nl\": \"Volume\",\n        \"da\": \"Lydstyrke\",\n        \"de\": \"Lautstärke\",\n        \"es\": \"Volumen\",\n        \"fr\": \"Volume\",\n        \"it\": \"Volume\",\n        \"no\": \"Volum\",\n        \"sv\": \"Volym\",\n        \"pl\": \"Głośność\",\n        \"ru\": \"Громкость\",\n        \"ko\": \"볼륨\"\n      },\n      \"name\": \"volume\",\n      \"min\": 0,\n      \"max\": 1,\n      \"step\": 0.01,\n      \"label\": \"%\",\n      \"labelMultiplier\": 100,\n      \"labelDecimals\": 0\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Robot\",\n        \"nl\": \"Selecteer Mi Robot\",\n        \"da\": \"Vælg Mi Robot\",\n        \"de\": \"Wählen Sie Mi Robot\",\n        \"es\": \"Selecciona Mi Robot\",\n        \"fr\": \"Sélectionnez Mi Robot\",\n        \"it\": \"Seleziona Mi Robot\",\n        \"no\": \"Velg Mi Robot\",\n        \"sv\": \"Välj Mi Robot\",\n        \"pl\": \"Wybierz Mi Robot\",\n        \"ru\": \"Выберите Mi Robot\",\n        \"ko\": \"Mi Robot 선택\"\n      },\n      \"filter\": \"driver_id=gateway\"\n    }\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/gateway_set_volume.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set volume for\",\n    \"nl\": \"Set volume voor\",\n    \"da\": \"Indstil lydstyrke for\",\n    \"de\": \"Lautstärke einstellen für\",\n    \"es\": \"Establecer volumen para\",\n    \"fr\": \"Régler le volume pour\",\n    \"it\": \"Imposta il volume per\",\n    \"no\": \"Sett volum for\",\n    \"sv\": \"Ställ in volymen för\",\n    \"pl\": \"Ustaw głośność dla\",\n    \"ru\": \"Установить громкость для\",\n    \"ko\": \"볼륨 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set volume to [[volume]] for [[target]]\",\n    \"nl\": \"Zet volume naar [[volume]] voor [[target]]\",\n    \"da\": \"Indstil lydstyrke til [[volume]] for [[target]]\",\n    \"de\": \"Lautstärke auf [[volume]] einstellen für [[target]]\",\n    \"es\": \"Establecer volumen a [[volume]] para [[target]]\",\n    \"fr\": \"Régler le volume à [[volume]] pour [[target]]\",\n    \"it\": \"Imposta il volume a [[volume]] per [[target]]\",\n    \"no\": \"Sett volum til [[volume]] for [[target]]\",\n    \"sv\": \"Ställ in volymen till [[volume]] för [[target]]\",\n    \"pl\": \"Ustaw głośność na [[volume]] dla [[target]]\",\n    \"ru\": \"Установить громкость на [[volume]] для [[target]]\",\n    \"ko\": \"[[target]]의 [[volume]]로 볼륨 설정\"\n  },\n  \"args\": [\n    {\n      \"type\": \"dropdown\",\n      \"title\": {\n        \"en\": \"Target\",\n        \"nl\": \"Doel\",\n        \"da\": \"Mål\",\n        \"de\": \"Ziel\",\n        \"es\": \"Objetivo\",\n        \"fr\": \"Cible\",\n        \"it\": \"Obiettivo\",\n        \"no\": \"Mål\",\n        \"sv\": \"Mål\",\n        \"pl\": \"Cel\",\n        \"ru\": \"Цель\",\n        \"ko\": \"대상\"\n      },\n      \"name\": \"target\",\n      \"values\": [\n        {\n          \"id\": \"alarm\",\n          \"label\": {\n            \"en\": \"Alarm\",\n            \"nl\": \"Alarm\",\n            \"da\": \"Alarm\",\n            \"de\": \"Alarm\",\n            \"es\": \"Alarma\",\n            \"fr\": \"Alarme\",\n            \"it\": \"Allarme\",\n            \"no\": \"Alarm\",\n            \"sv\": \"Larm\",\n            \"pl\": \"Alarm\",\n            \"ru\": \"Тревога\",\n            \"ko\": \"알람\"\n          }\n        },\n        {\n          \"id\": \"doorbell\",\n          \"label\": {\n            \"en\": \"Doorbell\",\n            \"nl\": \"Deurbel\",\n            \"da\": \"Dørklokke\",\n            \"de\": \"Türklingel\",\n            \"es\": \"Timbre\",\n            \"fr\": \"Sonnette\",\n            \"it\": \"Campanello\",\n            \"no\": \"Ringeklokke\",\n            \"sv\": \"Dörrklocka\",\n            \"pl\": \"Dzwonek do drzwi\",\n            \"ru\": \"Дверной звонок\",\n            \"ko\": \"초인종\"\n          }\n        },\n        {\n          \"id\": \"prompt\",\n          \"label\": {\n            \"en\": \"Prompt\",\n            \"nl\": \"Waarschuwing\",\n            \"da\": \"Påmindelse\",\n            \"de\": \"Eingabeaufforderung\",\n            \"es\": \"Mensaje\",\n            \"fr\": \"Message\",\n            \"it\": \"Richiesta\",\n            \"no\": \"Spørsmål\",\n            \"sv\": \"Uppmaning\",\n            \"pl\": \"Komunikat\",\n            \"ru\": \"Подсказка\",\n            \"ko\": \"프롬프트\"\n          }\n        },\n        {\n          \"id\": \"radio\",\n          \"label\": {\n            \"en\": \"Radio\",\n            \"nl\": \"Radio\",\n            \"da\": \"Radio\",\n            \"de\": \"Radio\",\n            \"es\": \"Radio\",\n            \"fr\": \"Radio\",\n            \"it\": \"Radio\",\n            \"no\": \"Radio\",\n            \"sv\": \"Radio\",\n            \"pl\": \"Radio\",\n            \"ru\": \"Радио\",\n            \"ko\": \"라디오\"\n          }\n        }\n      ]\n    },\n    {\n      \"type\": \"range\",\n      \"title\": {\n        \"en\": \"Volume\",\n        \"nl\": \"Volume\",\n        \"da\": \"Lydstyrke\",\n        \"de\": \"Lautstärke\",\n        \"es\": \"Volumen\",\n        \"fr\": \"Volume\",\n        \"it\": \"Volume\",\n        \"no\": \"Volum\",\n        \"sv\": \"Volym\",\n        \"pl\": \"Głośność\",\n        \"ru\": \"Громкость\",\n        \"ko\": \"볼륨\"\n      },\n      \"name\": \"volume\",\n      \"min\": 0,\n      \"max\": 1,\n      \"step\": 0.01,\n      \"label\": \"%\",\n      \"labelMultiplier\": 100,\n      \"labelDecimals\": 0\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Gateway\",\n        \"nl\": \"Selecteer Gateway\",\n        \"da\": \"Vælg Gateway\",\n        \"de\": \"Gateway auswählen\",\n        \"es\": \"Seleccionar Gateway\",\n        \"fr\": \"Sélectionner Gateway\",\n        \"it\": \"Seleziona Gateway\",\n        \"no\": \"Velg Gateway\",\n        \"sv\": \"Välj Gateway\",\n        \"pl\": \"Wybierz Gateway\",\n        \"ru\": \"Выберите Gateway\",\n        \"ko\": \"게이트웨이 선택\"\n      },\n      \"filter\": \"driver_id=gateway\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/goToTargetVacuum.json",
    "content": "{\n  \"id\": \"goToTargetVacuum\",\n  \"title\": {\n    \"en\": \"Send vacuum cleaner to target\",\n    \"nl\": \"Stuur stofzuiger naar doel\",\n    \"da\": \"Send støvsuger til mål\",\n    \"de\": \"Sende Staubsauger zum Ziel\",\n    \"es\": \"Enviar aspiradora al objetivo\",\n    \"fr\": \"Envoyer l'aspirateur à la cible\",\n    \"it\": \"Invia aspirapolvere al bersaglio\",\n    \"no\": \"Send støvsuger til mål\",\n    \"sv\": \"Skicka dammsugare till mål\",\n    \"pl\": \"Wyślij odkurzacz do celu\",\n    \"ru\": \"Отправить пылесос к цели\",\n    \"ko\": \"진공 청소기를 목표 지점으로 보내기\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Send vacuum cleaner to coordinates X [[xcoordinate]] and Y [[ycoordinate]]\",\n    \"nl\": \"Stuur stofzuiger naar coördinaten X [[xcoordinate]] en Y [[ycoordinate]]\",\n    \"da\": \"Send støvsuger til koordinaterne X [[xcoordinate]] og Y [[ycoordinate]]\",\n    \"de\": \"Senden Sie den Staubsauger zu den Koordinaten X [[xcoordinate]] und Y [[ycoordinate]]\",\n    \"es\": \"Enviar aspiradora a las coordenadas X [[xcoordinate]] e Y [[ycoordinate]]\",\n    \"fr\": \"Envoyer l'aspirateur aux coordonnées X [[xcoordinate]] et Y [[ycoordinate]]\",\n    \"it\": \"Invia l'aspirapolvere alle coordinate X [[xcoordinate]] e Y [[ycoordinate]]\",\n    \"no\": \"Send støvsuger til koordinater X [[xcoordinate]] og Y [[ycoordinate]]\",\n    \"sv\": \"Skicka dammsugare till koordinaterna X [[xcoordinate]] och Y [[ycoordinate]]\",\n    \"pl\": \"Wyślij odkurzacz na współrzędne X [[xcoordinate]] i Y [[ycoordinate]]\",\n    \"ru\": \"Отправить пылесос на координаты X [[xcoordinate]] и Y [[ycoordinate]]\",\n    \"ko\": \"진공 청소기를 X [[xcoordinate]] 및 Y [[ycoordinate]] 좌표로 보내기\"\n  },\n  \"hint\": {\n    \"en\": \"Enter the x and y coordinates of the target: ex. 25000 and 28000\",\n    \"nl\": \"Voer de x en y coördinaten van het doel in: bv. 25000 en 28000\",\n    \"da\": \"Indtast x- og y-koordinaterne for målet: f.eks. 25000 og 28000\",\n    \"de\": \"Geben Sie die x- und y-Koordinaten des Ziels ein: z.B. 25000 und 28000\",\n    \"es\": \"Introduzca las coordenadas x e y del objetivo: ej. 25000 y 28000\",\n    \"fr\": \"Entrez les coordonnées x et y de la cible : ex. 25000 et 28000\",\n    \"it\": \"Inserisci le coordinate x e y del bersaglio: es. 25000 e 28000\",\n    \"no\": \"Skriv inn x- og y-koordinatene til målet: f.eks. 25000 og 28000\",\n    \"sv\": \"Ange x- och y-koordinaterna för målet: ex. 25000 och 28000\",\n    \"pl\": \"Wpisz współrzędne x i y celu: np. 25000 i 28000\",\n    \"ru\": \"Введите координаты x и y цели: например, 25000 и 28000\",\n    \"ko\": \"목표의 x 및 y 좌표를 입력하세요: 예. 25000 및 28000\"\n  },\n  \"args\": [\n    {\n      \"name\": \"xcoordinate\",\n      \"title\": {\n        \"en\": \"X Coordinate\",\n        \"nl\": \"X coördinaat\",\n        \"da\": \"X-koordinat\",\n        \"de\": \"X-Koordinate\",\n        \"es\": \"Coordenada X\",\n        \"fr\": \"Coordonnée X\",\n        \"it\": \"Coordinata X\",\n        \"no\": \"X-koordinat\",\n        \"sv\": \"X-koordinat\",\n        \"pl\": \"Współrzędna X\",\n        \"ru\": \"Координата X\",\n        \"ko\": \"X 좌표\"\n      },\n      \"type\": \"number\",\n      \"placeholder\": {\n        \"en\": \"X Coordinate\",\n        \"nl\": \"X coördinaat\",\n        \"da\": \"X-koordinat\",\n        \"de\": \"X-Koordinate\",\n        \"es\": \"Coordenada X\",\n        \"fr\": \"Coordonnée X\",\n        \"it\": \"Coordinata X\",\n        \"no\": \"X-koordinat\",\n        \"sv\": \"X-koordinat\",\n        \"pl\": \"Współrzędna X\",\n        \"ru\": \"Координата X\",\n        \"ko\": \"X 좌표\"\n      }\n    },\n    {\n      \"name\": \"ycoordinate\",\n      \"title\": {\n        \"en\": \"Y Coordinate\",\n        \"nl\": \"Y coördinaat\",\n        \"da\": \"Y-koordinat\",\n        \"de\": \"Y-Koordinate\",\n        \"es\": \"Coordenada Y\",\n        \"fr\": \"Coordonnée Y\",\n        \"it\": \"Coordinata Y\",\n        \"no\": \"Y-koordinat\",\n        \"sv\": \"Y-koordinat\",\n        \"pl\": \"Współrzędna Y\",\n        \"ru\": \"Координата Y\",\n        \"ko\": \"Y 좌표\"\n      },\n      \"type\": \"number\",\n      \"placeholder\": {\n        \"en\": \"Y Coordinate\",\n        \"nl\": \"Y coördinaat\",\n        \"da\": \"Y-koordinat\",\n        \"de\": \"Y-Koordinate\",\n        \"es\": \"Coordenada Y\",\n        \"fr\": \"Coordonnée Y\",\n        \"it\": \"Coordinata Y\",\n        \"no\": \"Y-koordinat\",\n        \"sv\": \"Y-koordinat\",\n        \"pl\": \"Współrzędna Y\",\n        \"ru\": \"Координата Y\",\n        \"ko\": \"Y 좌표\"\n      }\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer Stofzuiger\",\n        \"da\": \"Vælg støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccionar aspiradora\",\n        \"fr\": \"Choisir l'aspirateur\",\n        \"it\": \"Seleziona aspirapolvere\",\n        \"no\": \"Velg støvsuger\",\n        \"sv\": \"Välj dammsugare\",\n        \"pl\": \"Wybierz odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"진공 청소기 선택\"\n      },\n      \"filter\": \"driver_id=mi-robot|vacuum_mi_rockrobo_vacuum_advanced|vacuum_mi_rockrobo_vacuum_t6|vacuum_mi_roborock_vacuum_a08|vacuum_dreame_vacuum_p2029_p2041|vacuum_dreame_vacuum_mc1808|vacuum_viomi_vacuum_v7\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/heaterZhimiHeatlevel.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set heatlevel\",\n    \"nl\": \"Stel hitte in\",\n    \"da\": \"Indstil varme niveau\",\n    \"de\": \"Heizstufe einstellen\",\n    \"es\": \"Establecer nivel de calor\",\n    \"fr\": \"Régler le niveau de chaleur\",\n    \"it\": \"Imposta livello di calore\",\n    \"no\": \"Sett varme nivå\",\n    \"sv\": \"Ställ in värmenivå\",\n    \"pl\": \"Ustaw poziom ciepła\",\n    \"ru\": \"Установить уровень нагрева\",\n    \"ko\": \"난방 수준 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set heatlevel to [[heatlevel]]\",\n    \"nl\": \"Stel hitte in op [[heatlevel]]\",\n    \"da\": \"Indstil varme niveau til [[heatlevel]]\",\n    \"de\": \"Heizstufe einstellen auf [[heatlevel]]\",\n    \"es\": \"Establecer nivel de calor en [[heatlevel]]\",\n    \"fr\": \"Régler le niveau de chaleur à [[heatlevel]]\",\n    \"it\": \"Imposta livello di calore a [[heatlevel]]\",\n    \"no\": \"Sett varme nivå til [[heatlevel]]\",\n    \"sv\": \"Ställ in värmenivå till [[heatlevel]]\",\n    \"pl\": \"Ustaw poziom ciepła na [[heatlevel]]\",\n    \"ru\": \"Установить уровень нагрева до [[heatlevel]]\",\n    \"ko\": \"[[heatlevel]]로 난방 수준 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"heatlevel\",\n      \"title\": {\n        \"en\": \"Heatlevel\",\n        \"nl\": \"Hitte\",\n        \"da\": \"Varme niveau\",\n        \"de\": \"Heizstufe\",\n        \"es\": \"Nivel de calor\",\n        \"fr\": \"Niveau de chaleur\",\n        \"it\": \"Livello di calore\",\n        \"no\": \"Varme nivå\",\n        \"sv\": \"Värmenivå\",\n        \"pl\": \"Poziom ciepła\",\n        \"ru\": \"Уровень нагрева\",\n        \"ko\": \"난방 수준\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Élevé\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높음\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Low\",\n            \"nl\": \"Laag\",\n            \"da\": \"Lav\",\n            \"de\": \"Niedrig\",\n            \"es\": \"Bajo\",\n            \"fr\": \"Faible\",\n            \"it\": \"Basso\",\n            \"no\": \"Lav\",\n            \"sv\": \"Låg\",\n            \"pl\": \"Niski\",\n            \"ru\": \"Низкий\",\n            \"ko\": \"낮음\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Heater\",\n        \"nl\": \"Selecteer Heater\",\n        \"da\": \"Vælg varmelegeme\",\n        \"de\": \"Heizung auswählen\",\n        \"es\": \"Seleccionar calentador\",\n        \"fr\": \"Sélectionner le chauffage\",\n        \"it\": \"Seleziona riscaldatore\",\n        \"no\": \"Velg varmeovn\",\n        \"sv\": \"Välj värmare\",\n        \"pl\": \"Wybierz grzejnik\",\n        \"ru\": \"Выберите обогреватель\",\n        \"ko\": \"히터 선택\"\n      },\n      \"filter\": \"driver_id=heater_zhimi_heater_miot&capabilities=heater_zhimi_heatlevel\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/heaterZhimiOscillation.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set oscillation\",\n    \"nl\": \"Stel oscillatie in\",\n    \"da\": \"Indstil oscillation\",\n    \"de\": \"Oszillation einstellen\",\n    \"es\": \"Configurar oscilación\",\n    \"fr\": \"Régler l'oscillation\",\n    \"it\": \"Imposta oscillazione\",\n    \"no\": \"Sett svingning\",\n    \"sv\": \"Ställ in oscillation\",\n    \"pl\": \"Ustaw oscylację\",\n    \"ru\": \"Установить колебание\",\n    \"ko\": \"진동 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set oscillation to [[oscillation]]\",\n    \"nl\": \"Stel oscillatie in op [[oscillation]]\",\n    \"da\": \"Indstil oscillation til [[oscillation]]\",\n    \"de\": \"Oszillation einstellen auf [[oscillation]]\",\n    \"es\": \"Configurar oscilación a [[oscillation]]\",\n    \"fr\": \"Régler l'oscillation sur [[oscillation]]\",\n    \"it\": \"Imposta oscillazione su [[oscillation]]\",\n    \"no\": \"Sett svingning til [[oscillation]]\",\n    \"sv\": \"Ställ in oscillation till [[oscillation]]\",\n    \"pl\": \"Ustaw oscylację na [[oscillation]]\",\n    \"ru\": \"Установить колебание на [[oscillation]]\",\n    \"ko\": \"[[oscillation]]으로 진동 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"oscillation\",\n      \"title\": {\n        \"en\": \"Oscillation\",\n        \"nl\": \"Oscillatie\",\n        \"da\": \"Oscillation\",\n        \"de\": \"Oszillation\",\n        \"es\": \"Oscilación\",\n        \"fr\": \"Oscillation\",\n        \"it\": \"Oscillazione\",\n        \"no\": \"Svingning\",\n        \"sv\": \"Oscillation\",\n        \"pl\": \"Oscylacja\",\n        \"ru\": \"Колебание\",\n        \"ko\": \"진동\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"da\": \"Fra\",\n            \"de\": \"Aus\",\n            \"es\": \"Apagar\",\n            \"fr\": \"Éteindre\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wyłącz\",\n            \"ru\": \"Выкл\",\n            \"ko\": \"꺼짐\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"On\",\n            \"nl\": \"Aan\",\n            \"da\": \"Til\",\n            \"de\": \"An\",\n            \"es\": \"Encender\",\n            \"fr\": \"Allumer\",\n            \"it\": \"Acceso\",\n            \"no\": \"På\",\n            \"sv\": \"På\",\n            \"pl\": \"Włącz\",\n            \"ru\": \"Вкл\",\n            \"ko\": \"켜짐\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Heater\",\n        \"nl\": \"Selecteer Heater\",\n        \"da\": \"Vælg varmer\",\n        \"de\": \"Heizung auswählen\",\n        \"es\": \"Seleccionar calentador\",\n        \"fr\": \"Sélectionner le chauffage\",\n        \"it\": \"Seleziona riscaldatore\",\n        \"no\": \"Velg varmeovn\",\n        \"sv\": \"Välj värmare\",\n        \"pl\": \"Wybierz grzejnik\",\n        \"ru\": \"Выберите обогреватель\",\n        \"ko\": \"히터 선택\"\n      },\n      \"filter\": \"driver_id=heater_zhimi_heater_miot&capabilities=heater_zhimi_oscillation\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/heaterZhimiTargetTemperature.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set target temperature\",\n    \"nl\": \"Stel doel temperatuur in\",\n    \"da\": \"Indstil måletemperatur\",\n    \"de\": \"Zieltemperatur einstellen\",\n    \"es\": \"Establecer temperatura objetivo\",\n    \"fr\": \"Régler la température cible\",\n    \"it\": \"Imposta la temperatura target\",\n    \"no\": \"Sett måltemperatur\",\n    \"sv\": \"Ställ in måttemperaturen\",\n    \"pl\": \"Ustaw temperaturę docelową\",\n    \"ru\": \"Установить целевую температуру\",\n    \"ko\": \"목표 온도 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set target temperature to [[temperature]]\",\n    \"nl\": \"Stel doel temperatuur in op [[temperature]]\",\n    \"da\": \"Indstil måletemperatur til [[temperature]]\",\n    \"de\": \"Zieltemperatur auf [[temperature]] einstellen\",\n    \"es\": \"Establecer temperatura objetivo a [[temperature]]\",\n    \"fr\": \"Régler la température cible sur [[temperature]]\",\n    \"it\": \"Imposta la temperatura target a [[temperature]]\",\n    \"no\": \"Sett måltemperaturen til [[temperature]]\",\n    \"sv\": \"Ställ in måttemperaturen till [[temperature]]\",\n    \"pl\": \"Ustaw temperaturę docelową na [[temperature]]\",\n    \"ru\": \"Установить целевую температуру на [[temperature]]\",\n    \"ko\": \"[[temperature]]도로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"temperature\",\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Target Temperature\",\n        \"nl\": \"Doel temperatuur\",\n        \"da\": \"Måletemperatur\",\n        \"de\": \"Zieltemperatur\",\n        \"es\": \"Temperatura objetivo\",\n        \"fr\": \"Température cible\",\n        \"it\": \"Temperatura target\",\n        \"no\": \"Måltemperatur\",\n        \"sv\": \"Måttemperatur\",\n        \"pl\": \"Temperatura docelowa\",\n        \"ru\": \"Целевая температура\",\n        \"ko\": \"목표 온도\"\n      },\n      \"min\": 16,\n      \"max\": 30,\n      \"step\": 1\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Heater\",\n        \"nl\": \"Selecteer Heater\",\n        \"da\": \"Vælg varmeapparat\",\n        \"de\": \"Heizung auswählen\",\n        \"es\": \"Seleccionar calentador\",\n        \"fr\": \"Sélectionner le radiateur\",\n        \"it\": \"Seleziona riscaldatore\",\n        \"no\": \"Velg varmeovn\",\n        \"sv\": \"Välj värmare\",\n        \"pl\": \"Wybierz grzejnik\",\n        \"ru\": \"Выбрать обогреватель\",\n        \"ko\": \"히터 선택\"\n      },\n      \"filter\": \"driver_id=heater_zhimi_heater_miot&capabilities=heater_zhimi_heater_target_temperature\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/humidifierXiaomiMode.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Sæt tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Configurar modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Angi modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus auf [[mode]] einstellen\",\n    \"es\": \"Configurar modo a [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Sett modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Constant Humidity\",\n            \"nl\": \"Constante luchtvochtigheid\",\n            \"da\": \"Konstant fugtighed\",\n            \"de\": \"Konstante Luftfeuchtigkeit\",\n            \"es\": \"Humedad constante\",\n            \"fr\": \"Humidité constante\",\n            \"it\": \"Umidità costante\",\n            \"no\": \"Konstant fuktighet\",\n            \"sv\": \"Konstant luftfuktighet\",\n            \"pl\": \"Stała wilgotność\",\n            \"ru\": \"Постоянная влажность\",\n            \"ko\": \"일정 습도\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Strong\",\n            \"nl\": \"Sterk\",\n            \"da\": \"Stærk\",\n            \"de\": \"Stark\",\n            \"es\": \"Fuerte\",\n            \"fr\": \"Fort\",\n            \"it\": \"Intenso\",\n            \"no\": \"Sterk\",\n            \"sv\": \"Stark\",\n            \"pl\": \"Silny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강하게\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Sleep\",\n            \"nl\": \"Slaapstand\",\n            \"da\": \"Sovefunktion\",\n            \"de\": \"Schlafmodus\",\n            \"es\": \"Modo de dormir\",\n            \"fr\": \"Sommeil\",\n            \"it\": \"Modalità notte\",\n            \"no\": \"Søvn\",\n            \"sv\": \"Sovläge\",\n            \"pl\": \"Tryb snu\",\n            \"ru\": \"Спящий режим\",\n            \"ko\": \"수면 모드\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Air-dry\",\n            \"nl\": \"Air-dry\",\n            \"da\": \"Lufttørre\",\n            \"de\": \"Lufttrocknen\",\n            \"es\": \"Secar al aire\",\n            \"fr\": \"Sécher à l'air\",\n            \"it\": \"Asciugare all'aria\",\n            \"no\": \"Lufttørk\",\n            \"sv\": \"Lufttorka\",\n            \"pl\": \"Suszenie powietrzem\",\n            \"ru\": \"Воздушная сушка\",\n            \"ko\": \"에어 드라이\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Clean\",\n            \"nl\": \"Schonen\",\n            \"da\": \"Rengør\",\n            \"de\": \"Reinigen\",\n            \"es\": \"Limpiar\",\n            \"fr\": \"Nettoyer\",\n            \"it\": \"Pulire\",\n            \"no\": \"Rengjør\",\n            \"sv\": \"Rena\",\n            \"pl\": \"Czyszczenie\",\n            \"ru\": \"Чистка\",\n            \"ko\": \"세척\"\n          }\n        },\n        {\n          \"id\": \"5\",\n          \"title\": {\n            \"en\": \"Descale\",\n            \"nl\": \"Descale\",\n            \"da\": \"Afkalkning\",\n            \"de\": \"Entkalken\",\n            \"es\": \"Descalcificar\",\n            \"fr\": \"Détartrer\",\n            \"it\": \"Decalcificare\",\n            \"no\": \"Avkalking\",\n            \"sv\": \"Avkalka\",\n            \"pl\": \"Odkamienianie\",\n            \"ru\": \"Удаление накипи\",\n            \"ko\": \"석회 제거\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Humidifier\",\n        \"nl\": \"Selecteer Mi Humidifier\",\n        \"da\": \"Vælg Mi Luftfugter\",\n        \"de\": \"Wählen Sie Mi Luftbefeuchter\",\n        \"es\": \"Selecciona Mi Humidificador\",\n        \"fr\": \"Sélectionnez Mi Humidificateur\",\n        \"it\": \"Seleziona Mi Umidificatore\",\n        \"no\": \"Velg Mi Luftfukter\",\n        \"sv\": \"Välj Mi Luftfuktare\",\n        \"pl\": \"Wybierz Mi Nawilżacz\",\n        \"ru\": \"Выбрать Mi Увлажнитель\",\n        \"ko\": \"Mi 가습기 선택\"\n      },\n      \"filter\": \"driver_id=humidifier_xiaomi_humidifier\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/humidifierZhimiMode.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Indstil tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Establecer modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Angi modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus einstellen auf [[mode]]\",\n    \"es\": \"Establecer modo a [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Angi modus til [[mode]]\",\n    \"sv\": \"Ställ in läge på [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"idle\",\n          \"title\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"de\": \"Aus\",\n            \"da\": \"Fra\",\n            \"es\": \"Apagado\",\n            \"fr\": \"Éteint\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wył.\",\n            \"ru\": \"Выкл.\",\n            \"ko\": \"끔\"\n          }\n        },\n        {\n          \"id\": \"silent\",\n          \"title\": {\n            \"en\": \"Silent\",\n            \"nl\": \"Stil\",\n            \"de\": \"Leise\",\n            \"da\": \"Stille\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Беззвучный\",\n            \"ko\": \"무음\"\n          }\n        },\n        {\n          \"id\": \"medium\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Middel\",\n            \"de\": \"Mittel\",\n            \"da\": \"Medium\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Medium\",\n            \"sv\": \"Medium\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"high\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"de\": \"Hoch\",\n            \"da\": \"Høj\",\n            \"es\": \"Alto\",\n            \"fr\": \"Haut\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높음\"\n          }\n        },\n        {\n          \"id\": \"auto\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"de\": \"Auto\",\n            \"da\": \"Auto\",\n            \"es\": \"Auto\",\n            \"fr\": \"Auto\",\n            \"it\": \"Auto\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"strong\",\n          \"title\": {\n            \"en\": \"Strong\",\n            \"nl\": \"Sterk\",\n            \"de\": \"Stark\",\n            \"da\": \"Stærk\",\n            \"es\": \"Fuerte\",\n            \"fr\": \"Fort\",\n            \"it\": \"Forte\",\n            \"no\": \"Sterk\",\n            \"sv\": \"Stark\",\n            \"pl\": \"Silny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강한\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Humidifier\",\n        \"nl\": \"Selecteer Mi Humidifier\",\n        \"da\": \"Vælg Mi Humidifier\",\n        \"de\": \"Wählen Sie Mi Luftbefeuchter aus\",\n        \"es\": \"Selecciona Mi Humidificador\",\n        \"fr\": \"Sélectionnez Mi Humidificateur\",\n        \"it\": \"Seleziona Mi Umidificatore\",\n        \"no\": \"Velg Mi Humidifier\",\n        \"sv\": \"Välj Mi Humidifier\",\n        \"pl\": \"Wybierz Mi Humidifier\",\n        \"ru\": \"Выберите Mi Humidifier\",\n        \"ko\": \"Mi Humidifier 선택\"\n      },\n      \"filter\": \"driver_id=humidifier_zhimi_humidifier\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/humidifierZhimiModeMIoT.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Sæt tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Establecer modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Sett modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus auf [[mode]] einstellen\",\n    \"es\": \"Establecer modo a [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Sett modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"da\": \"Auto\",\n            \"de\": \"Auto\",\n            \"es\": \"Auto\",\n            \"fr\": \"Auto\",\n            \"it\": \"Auto\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Level 1\",\n            \"nl\": \"Level 1\",\n            \"da\": \"Niveau 1\",\n            \"de\": \"Stufe 1\",\n            \"es\": \"Nivel 1\",\n            \"fr\": \"Niveau 1\",\n            \"it\": \"Livello 1\",\n            \"no\": \"Nivå 1\",\n            \"sv\": \"Nivå 1\",\n            \"pl\": \"Poziom 1\",\n            \"ru\": \"Уровень 1\",\n            \"ko\": \"레벨 1\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Level 2\",\n            \"nl\": \"Level 2\",\n            \"da\": \"Niveau 2\",\n            \"de\": \"Stufe 2\",\n            \"es\": \"Nivel 2\",\n            \"fr\": \"Niveau 2\",\n            \"it\": \"Livello 2\",\n            \"no\": \"Nivå 2\",\n            \"sv\": \"Nivå 2\",\n            \"pl\": \"Poziom 2\",\n            \"ru\": \"Уровень 2\",\n            \"ko\": \"레벨 2\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Level 3\",\n            \"nl\": \"Level 3\",\n            \"da\": \"Niveau 3\",\n            \"de\": \"Stufe 3\",\n            \"es\": \"Nivel 3\",\n            \"fr\": \"Niveau 3\",\n            \"it\": \"Livello 3\",\n            \"no\": \"Nivå 3\",\n            \"sv\": \"Nivå 3\",\n            \"pl\": \"Poziom 3\",\n            \"ru\": \"Уровень 3\",\n            \"ko\": \"레벨 3\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Humidifier\",\n        \"nl\": \"Selecteer Mi Humidifier\",\n        \"da\": \"Vælg Mi Luftfugter\",\n        \"de\": \"Wählen Sie Mi Luftbefeuchter\",\n        \"es\": \"Seleccionar Mi Humidificador\",\n        \"fr\": \"Sélectionnez Humidificateur Mi\",\n        \"it\": \"Seleziona Mi Umidificatore\",\n        \"no\": \"Velg Mi Luftfukter\",\n        \"sv\": \"Välj Mi Luftfuktare\",\n        \"pl\": \"Wybierz Mi Nawilżacz\",\n        \"ru\": \"Выберите Mi Увлажнитель\",\n        \"ko\": \"Mi 가습기 선택\"\n      },\n      \"filter\": \"driver_id=humidifier_zhimi_humidifier_miot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/ledAirpurifierHumidifier.json",
    "content": "{\n  \"title\": {\n    \"en\": \"LED display brightness\",\n    \"nl\": \"LED display helderheid\",\n    \"da\": \"LED skærm lysstyrke\",\n    \"de\": \"LED-Display-Helligkeit\",\n    \"es\": \"Brillo de la pantalla LED\",\n    \"fr\": \"Luminosité de l'affichage LED\",\n    \"it\": \"Luminosità del display LED\",\n    \"no\": \"LED-skjermens lysstyrke\",\n    \"sv\": \"LED-skärmens ljusstyrka\",\n    \"pl\": \"Jasność wyświetlacza LED\",\n    \"ru\": \"Яркость светодиодного дисплея\",\n    \"ko\": \"LED 디스플레이 밝기\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set LED display brightness to [[brightness]]\",\n    \"nl\": \"Stel LED display helderheid in op [[brightness]]\",\n    \"da\": \"Indstil LED skærm lysstyrke til [[brightness]]\",\n    \"de\": \"LED-Display-Helligkeit auf [[brightness]] einstellen\",\n    \"es\": \"Establecer el brillo de la pantalla LED a [[brightness]]\",\n    \"fr\": \"Régler la luminosité de l'affichage LED sur [[brightness]]\",\n    \"it\": \"Imposta la luminosità del display LED a [[brightness]]\",\n    \"no\": \"Sett LED-skjermens lysstyrke til [[brightness]]\",\n    \"sv\": \"Ställ in LED-skärmens ljusstyrka till [[brightness]]\",\n    \"pl\": \"Ustaw jasność wyświetlacza LED na [[brightness]]\",\n    \"ru\": \"Установить яркость светодиодного дисплея на [[brightness]]\",\n    \"ko\": \"LED 디스플레이 밝기를 [[brightness]]로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"brightness\",\n      \"title\": {\n        \"en\": \"Brightness\",\n        \"nl\": \"Helderheid\",\n        \"da\": \"Lysstyrke\",\n        \"de\": \"Helligkeit\",\n        \"es\": \"Brillo\",\n        \"fr\": \"Luminosité\",\n        \"it\": \"Luminosità\",\n        \"no\": \"Lysstyrke\",\n        \"sv\": \"Ljusstyrka\",\n        \"pl\": \"Jasność\",\n        \"ru\": \"Яркость\",\n        \"ko\": \"밝기\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"label\": {\n            \"en\": \"Bright\",\n            \"nl\": \"Helder\",\n            \"da\": \"Lys\",\n            \"de\": \"Hell\",\n            \"es\": \"Brillante\",\n            \"fr\": \"Éclatant\",\n            \"it\": \"Luminoso\",\n            \"no\": \"Lyst\",\n            \"sv\": \"Ljus\",\n            \"pl\": \"Jasny\",\n            \"ru\": \"Яркий\",\n            \"ko\": \"밝게\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"label\": {\n            \"en\": \"Dim\",\n            \"nl\": \"Gedimd\",\n            \"da\": \"Dæmpet\",\n            \"de\": \"Gedimmt\",\n            \"es\": \"Atenuado\",\n            \"fr\": \"Tamiser\",\n            \"it\": \"Fioco\",\n            \"no\": \"Dempet\",\n            \"sv\": \"Dämpad\",\n            \"pl\": \"Ściemnić\",\n            \"ru\": \"Тусклый\",\n            \"ko\": \"어둡게\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"label\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"da\": \"Slukket\",\n            \"de\": \"Aus\",\n            \"es\": \"Apagado\",\n            \"fr\": \"Éteindre\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wyłączony\",\n            \"ru\": \"Выкл\",\n            \"ko\": \"끄기\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer Apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-airpurifier|humidifier_zhimi_humidifier|zhimi-fan\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/leftSwitchOff.json",
    "content": "{\n  \"id\": \"leftSwitchOff\",\n  \"title\": {\n    \"en\": \"Turn Left Switch Off\",\n    \"nl\": \"Schakel linkerschakelaar uit\",\n    \"da\": \"Sluk venstre kontakt\",\n    \"de\": \"Schalten Sie den linken Schalter aus\",\n    \"es\": \"Apaga el interruptor izquierdo\",\n    \"fr\": \"Éteindre l'interrupteur de gauche\",\n    \"it\": \"Spegni l'interruttore sinistro\",\n    \"no\": \"Slå av venstre bryter\",\n    \"sv\": \"Stäng av vänstra brytaren\",\n    \"pl\": \"Wyłącz lewy przełącznik\",\n    \"ru\": \"Выключить левый переключатель\",\n    \"ko\": \"왼쪽 스위치 끄기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/leftSwitchOn.json",
    "content": "{\n  \"id\": \"leftSwitchOn\",\n  \"title\": {\n    \"en\": \"Turn Left Switch On\",\n    \"nl\": \"Schakel linkerschakelaar aan\",\n    \"da\": \"Tænd Venstre Afbryder\",\n    \"de\": \"Schalten Sie den linken Schalter ein\",\n    \"es\": \"Enciende el interruptor izquierdo\",\n    \"fr\": \"Allumer l'interrupteur de gauche\",\n    \"it\": \"Accendi l'interruttore sinistro\",\n    \"no\": \"Slå på venstre bryter\",\n    \"sv\": \"Slå på vänster brytare\",\n    \"pl\": \"Włącz lewy przełącznik\",\n    \"ru\": \"Включите левый выключатель\",\n    \"ko\": \"왼쪽 스위치 켜기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionnez l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/leftSwitchToggle.json",
    "content": "{\n  \"id\": \"leftSwitchToggle\",\n  \"title\": {\n    \"en\": \"Toggle Left Switch\",\n    \"nl\": \"Schakel linkerschakelaar\",\n    \"da\": \"Skift venstre kontakt\",\n    \"de\": \"Linken Schalter umlegen\",\n    \"es\": \"Alternar interruptor izquierdo\",\n    \"fr\": \"Basculer l'interrupteur gauche\",\n    \"it\": \"Attiva/disattiva l'interruttore sinistro\",\n    \"no\": \"Veksle venstre bryter\",\n    \"sv\": \"Växla vänster brytare\",\n    \"pl\": \"Przełącz lewy włącznik\",\n    \"ru\": \"Переключить левый выключатель\",\n    \"ko\": \"왼쪽 스위치 전환\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"기기 선택\"\n      },\n      \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/modeAirpurifier.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Indstil tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Configurar modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Sett modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus einstellen auf [[mode]]\",\n    \"es\": \"Configurar modo a [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Sett modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"auto\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"da\": \"Auto\",\n            \"de\": \"Auto\",\n            \"es\": \"Auto\",\n            \"fr\": \"Auto\",\n            \"it\": \"Auto\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"silent\",\n          \"title\": {\n            \"en\": \"Silent\",\n            \"nl\": \"Stil\",\n            \"da\": \"Stille\",\n            \"de\": \"Leise\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"조용한\"\n          }\n        },\n        {\n          \"id\": \"favorite\",\n          \"title\": {\n            \"en\": \"Favorite\",\n            \"nl\": \"Favoriet\",\n            \"da\": \"Favorit\",\n            \"de\": \"Favorit\",\n            \"es\": \"Favorito\",\n            \"fr\": \"Favori\",\n            \"it\": \"Preferito\",\n            \"no\": \"Favoritt\",\n            \"sv\": \"Favorit\",\n            \"pl\": \"Ulubiony\",\n            \"ru\": \"Любимый\",\n            \"ko\": \"즐겨 찾기\"\n          }\n        },\n        {\n          \"id\": \"idle\",\n          \"title\": {\n            \"en\": \"Idle\",\n            \"nl\": \"Standby\",\n            \"da\": \"I dvale\",\n            \"de\": \"Leerlauf\",\n            \"es\": \"Inactivo\",\n            \"fr\": \"Inactif\",\n            \"it\": \"Inattivo\",\n            \"no\": \"Inaktiv\",\n            \"sv\": \"Inaktiv\",\n            \"pl\": \"Bezczynny\",\n            \"ru\": \"Ожидание\",\n            \"ko\": \"대기모드\"\n          }\n        },\n        {\n          \"id\": \"low\",\n          \"title\": {\n            \"en\": \"Low\",\n            \"nl\": \"Laag\",\n            \"da\": \"Lav\",\n            \"de\": \"Niedrig\",\n            \"es\": \"Bajo\",\n            \"fr\": \"Bas\",\n            \"it\": \"Basso\",\n            \"no\": \"Lav\",\n            \"sv\": \"Låg\",\n            \"pl\": \"Niski\",\n            \"ru\": \"Низкий\",\n            \"ko\": \"낮음\"\n          }\n        },\n        {\n          \"id\": \"medium\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Medium\",\n            \"da\": \"Mellem\",\n            \"de\": \"Mittel\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Middels\",\n            \"sv\": \"Mellan\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"high\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Élevé\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높음\"\n          }\n        },\n        {\n          \"id\": \"strong\",\n          \"title\": {\n            \"en\": \"Strong\",\n            \"nl\": \"Sterk\",\n            \"da\": \"Stærk\",\n            \"de\": \"Stark\",\n            \"es\": \"Fuerte\",\n            \"fr\": \"Fort\",\n            \"it\": \"Forte\",\n            \"no\": \"Sterk\",\n            \"sv\": \"Stark\",\n            \"pl\": \"Silny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강한\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Air Purifier\",\n        \"nl\": \"Selecteer Mi Luchtreiniger\",\n        \"da\": \"Vælg Mi Luftrenser\",\n        \"de\": \"Wählen Sie Mi Luftreiniger\",\n        \"es\": \"Seleccionar Mi Purificador de Aire\",\n        \"fr\": \"Sélectionner Mi Purificateur d'air\",\n        \"it\": \"Seleziona Mi Purificatore d'aria\",\n        \"no\": \"Velg Mi Luftrenser\",\n        \"sv\": \"Välj Mi Luftrenare\",\n        \"pl\": \"Wybierz Mi Oczyszczacz Powietrza\",\n        \"ru\": \"Выбрать Mi Очиститель Воздуха\",\n        \"ko\": \"Mi 공기청정기 선택\"\n      },\n      \"filter\": \"driver_id=mi-airpurifier|airpurifier_zhimi_advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/actions/modeAirpurifierV7.json",
    "content": "{\n  \"id\": \"modeAirpurifierV7\",\n  \"title\": {\n    \"en\": \"Set mode (v7)\",\n    \"nl\": \"Stel modus in (v7)\",\n    \"da\": \"Indstil tilstand (v7)\",\n    \"de\": \"Modus einstellen (v7)\",\n    \"es\": \"Configurar modo (v7)\",\n    \"fr\": \"Définir le mode (v7)\",\n    \"it\": \"Imposta modalità (v7)\",\n    \"no\": \"Sett modus (v7)\",\n    \"sv\": \"Ställ in läge (v7)\",\n    \"pl\": \"Ustaw tryb (v7)\",\n    \"ru\": \"Установить режим (v7)\",\n    \"ko\": \"모드 설정 (v7)\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set v7 mode to [[mode]]\",\n    \"nl\": \"Stel v7-modus in op [[mode]]\",\n    \"da\": \"Indstil v7-tilstand til [[mode]]\",\n    \"de\": \"V7-Modus einstellen auf [[mode]]\",\n    \"es\": \"Configurar modo v7 a [[mode]]\",\n    \"fr\": \"Définir le mode v7 sur [[mode]]\",\n    \"it\": \"Imposta modalità v7 su [[mode]]\",\n    \"no\": \"Sett v7-modus til [[mode]]\",\n    \"sv\": \"Ställ in v7-läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb v7 na [[mode]]\",\n    \"ru\": \"Установить режим v7 на [[mode]]\",\n    \"ko\": \"v7 모드를 [[mode]](으)로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"auto\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"da\": \"Auto\",\n            \"de\": \"Auto\",\n            \"es\": \"Auto\",\n            \"fr\": \"Auto\",\n            \"it\": \"Auto\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"silent\",\n          \"title\": {\n            \"en\": \"Night\",\n            \"nl\": \"Nacht\",\n            \"da\": \"Nat\",\n            \"de\": \"Nacht\",\n            \"es\": \"Noche\",\n            \"fr\": \"Nuit\",\n            \"it\": \"Notte\",\n            \"no\": \"Natt\",\n            \"sv\": \"Natt\",\n            \"pl\": \"Noc\",\n            \"ru\": \"Ночь\",\n            \"ko\": \"야간\"\n          }\n        },\n        {\n          \"id\": \"favorite\",\n          \"title\": {\n            \"en\": \"Favorite\",\n            \"nl\": \"Favoriet\",\n            \"da\": \"Favorit\",\n            \"de\": \"Favorit\",\n            \"es\": \"Favorito\",\n            \"fr\": \"Favori\",\n            \"it\": \"Preferito\",\n            \"no\": \"Favoritt\",\n            \"sv\": \"Favorit\",\n            \"pl\": \"Ulubiony\",\n            \"ru\": \"Любимый\",\n            \"ko\": \"즐겨찾기\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Air Purifier v7\",\n        \"nl\": \"Selecteer Mi Luchtreiniger v7\",\n        \"da\": \"Vælg Mi Luftrenser v7\",\n        \"de\": \"Wählen Sie Mi Luftreiniger v7\",\n        \"es\": \"Seleccionar Mi Purificador de Aire v7\",\n        \"fr\": \"Sélectionner Mi Purificateur d'air v7\",\n        \"it\": \"Seleziona Mi Purificatore d'aria v7\",\n        \"no\": \"Velg Mi Luftrenser v7\",\n        \"sv\": \"Välj Mi Luftrenare v7\",\n        \"pl\": \"Wybierz Mi Oczyszczacz Powietrza v7\",\n        \"ru\": \"Выбрать Mi Очиститель Воздуха v7\",\n        \"ko\": \"Mi 공기청정기 v7 선택\"\n      },\n      \"filter\": \"driver_id=airpurifier_zhimi_advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/actions/modeDehumidifierDmaker.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Sæt tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Establecer modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Sett modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus auf [[mode]] einstellen\",\n    \"es\": \"Establecer modo en [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Sett modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Smart\",\n            \"nl\": \"Slim\",\n            \"da\": \"Smart\",\n            \"de\": \"Intelligent\",\n            \"es\": \"Inteligente\",\n            \"fr\": \"Intelligent\",\n            \"it\": \"Intelligente\",\n            \"no\": \"Smart\",\n            \"sv\": \"Smart\",\n            \"pl\": \"Inteligentny\",\n            \"ru\": \"Умный\",\n            \"ko\": \"스마트\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Sleep\",\n            \"nl\": \"Slaap\",\n            \"da\": \"Søvn\",\n            \"de\": \"Schlaf\",\n            \"es\": \"Dormir\",\n            \"fr\": \"Sommeil\",\n            \"it\": \"Sonno\",\n            \"no\": \"Søvn\",\n            \"sv\": \"Sömn\",\n            \"pl\": \"Sen\",\n            \"ru\": \"Сон\",\n            \"ko\": \"수면\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Clothes Drying\",\n            \"nl\": \"Kleding drogen\",\n            \"da\": \"Tørring af tøj\",\n            \"de\": \"Kleidung trocknen\",\n            \"es\": \"Secado de ropa\",\n            \"fr\": \"Séchage des vêtements\",\n            \"it\": \"Asciugatura dei vestiti\",\n            \"no\": \"Klær tørking\",\n            \"sv\": \"Klädtorkning\",\n            \"pl\": \"Suszenie ubrań\",\n            \"ru\": \"Сушка одежды\",\n            \"ko\": \"의류 건조\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Humidifier\",\n        \"nl\": \"Selecteer Mi Luchtbevochtiger\",\n        \"da\": \"Vælg Mi Luftfugter\",\n        \"de\": \"Wählen Sie Mi Luftbefeuchter\",\n        \"es\": \"Seleccione Mi Humidificador\",\n        \"fr\": \"Sélectionnez Mi Humidificateur\",\n        \"it\": \"Seleziona Mi Umidificatore\",\n        \"no\": \"Velg Mi Luftfukter\",\n        \"sv\": \"Välj Mi Luftfuktare\",\n        \"pl\": \"Wybierz Mi Nawilżacz\",\n        \"ru\": \"Выберите Mi Увлажнитель\",\n        \"ko\": \"Mi 가습기 선택\"\n      },\n      \"filter\": \"driver_id=dehumidifier_dmaker_derh_miot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/modeDiffuserXwhzp.json",
    "content": "{\n  \"id\": \"modeDiffuserXwhzp\",\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Saet tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Establecer modo\",\n    \"fr\": \"Definir le mode\",\n    \"it\": \"Imposta modalita\",\n    \"no\": \"Sett modus\",\n    \"sv\": \"Stall in lage\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Ustanovit rezhim\",\n    \"ko\": \"mode set\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        { \"id\": \"0\", \"title\": { \"en\": \"Sleep\" } },\n        { \"id\": \"1\", \"title\": { \"en\": \"Reading\" } },\n        { \"id\": \"2\", \"title\": { \"en\": \"Exercise\" } },\n        { \"id\": \"3\", \"title\": { \"en\": \"Wakeup\" } },\n        { \"id\": \"4\", \"title\": { \"en\": \"Custom Mode 1\" } },\n        { \"id\": \"5\", \"title\": { \"en\": \"Custom Mode 2\" } },\n        { \"id\": \"6\", \"title\": { \"en\": \"Custom Mode 3\" } },\n        { \"id\": \"7\", \"title\": { \"en\": \"Custom Mode 4\" } },\n        { \"id\": \"8\", \"title\": { \"en\": \"Try It\" } },\n        { \"id\": \"9\", \"title\": { \"en\": \"Idle Mode\" } }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mijia Smart Scent Diffuser\"\n      },\n      \"filter\": \"driver_id=diffuser_xwhzp_diffuser_xwxfj\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/actions/modeDmakerFan.json",
    "content": "{\n  \"id\": \"modeDmakerFan\",\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Indstil tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Establecer modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Sett modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus einstellen auf [[mode]]\",\n    \"es\": \"Establecer modo a [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Sett modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"normal\",\n          \"label\": {\n            \"en\": \"Normal\",\n            \"nl\": \"Normaal\",\n            \"da\": \"Normal\",\n            \"de\": \"Normal\",\n            \"es\": \"Normal\",\n            \"fr\": \"Normal\",\n            \"it\": \"Normale\",\n            \"no\": \"Normal\",\n            \"sv\": \"Normal\",\n            \"pl\": \"Normalny\",\n            \"ru\": \"Нормальный\",\n            \"ko\": \"일반\"\n          }\n        },\n        {\n          \"id\": \"nature\",\n          \"label\": {\n            \"en\": \"Nature\",\n            \"nl\": \"Natuur\",\n            \"da\": \"Natur\",\n            \"de\": \"Natur\",\n            \"es\": \"Naturaleza\",\n            \"fr\": \"Nature\",\n            \"it\": \"Natura\",\n            \"no\": \"Natur\",\n            \"sv\": \"Natur\",\n            \"pl\": \"Natura\",\n            \"ru\": \"Природный\",\n            \"ko\": \"자연\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Dmaker Fan\",\n        \"nl\": \"Selecteer Dmaker Ventilator\",\n        \"da\": \"Vælg Dmaker Fan\",\n        \"de\": \"Wählen Sie Dmaker Fan\",\n        \"es\": \"Seleccione Dmaker Fan\",\n        \"fr\": \"Sélectionnez Dmaker Fan\",\n        \"it\": \"Seleziona Dmaker Fan\",\n        \"no\": \"Velg Dmaker-vifte\",\n        \"sv\": \"Välj Dmaker-fläkt\",\n        \"pl\": \"Wybierz wentylator Dmaker\",\n        \"ru\": \"Выбрать вентилятор Dmaker\",\n        \"ko\": \"Dmaker 선풍기 선택\"\n      },\n      \"filter\": \"driver_id=dmaker-fan\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/modeEyecare.json",
    "content": "{\n  \"id\": \"modeEyecare\",\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Indstil tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Establecer modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Sett modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus einstellen auf [[mode]]\",\n    \"es\": \"Establecer modo a [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Sett modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"study\",\n          \"label\": {\n            \"en\": \"Study\",\n            \"nl\": \"Studeer\",\n            \"da\": \"Studie\",\n            \"de\": \"Studium\",\n            \"es\": \"Estudio\",\n            \"fr\": \"Étude\",\n            \"it\": \"Studio\",\n            \"no\": \"Studier\",\n            \"sv\": \"Studera\",\n            \"pl\": \"Studia\",\n            \"ru\": \"Учеба\",\n            \"ko\": \"공부\"\n          }\n        },\n        {\n          \"id\": \"reading\",\n          \"label\": {\n            \"en\": \"Reading\",\n            \"nl\": \"Lezen\",\n            \"da\": \"Læsning\",\n            \"de\": \"Lesen\",\n            \"es\": \"Lectura\",\n            \"fr\": \"Lecture\",\n            \"it\": \"Lettura\",\n            \"no\": \"Lesing\",\n            \"sv\": \"Läsa\",\n            \"pl\": \"Czytanie\",\n            \"ru\": \"Чтение\",\n            \"ko\": \"독서\"\n          }\n        },\n        {\n          \"id\": \"phone\",\n          \"label\": {\n            \"en\": \"Phone\",\n            \"nl\": \"Telefoon\",\n            \"da\": \"Telefon\",\n            \"de\": \"Telefon\",\n            \"es\": \"Teléfono\",\n            \"fr\": \"Téléphone\",\n            \"it\": \"Telefono\",\n            \"no\": \"Telefon\",\n            \"sv\": \"Telefon\",\n            \"pl\": \"Telefon\",\n            \"ru\": \"Телефон\",\n            \"ko\": \"전화\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Philips Eyecare Lamp\",\n        \"nl\": \"Selecteer Philips Eyecare Lamp\",\n        \"da\": \"Vælg Philips Eyecare Lamp\",\n        \"de\": \"Wählen Sie Philips Eyecare Lampe\",\n        \"es\": \"Seleccionar lámpara Philips Eyecare\",\n        \"fr\": \"Sélectionnez la lampe Philips Eyecare\",\n        \"it\": \"Seleziona lampada Philips Eyecare\",\n        \"no\": \"Velg Philips Eyecare Lampe\",\n        \"sv\": \"Välj Philips Eyecare Lampa\",\n        \"pl\": \"Wybierz lampę Philips Eyecare\",\n        \"ru\": \"Выберите лампу Philips Eyecare\",\n        \"ko\": \"필립스 아이케어 램프 선택\"\n      },\n      \"filter\": \"driver_id=philips-eyecare\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/modeHumidifierDeerma.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Indstil tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Ajustar modo\",\n    \"fr\": \"Régler le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Angi modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus auf [[mode]] einstellen\",\n    \"es\": \"Ajustar modo a [[mode]]\",\n    \"fr\": \"Régler le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Angi modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"label\": {\n            \"en\": \"Low\",\n            \"nl\": \"Laag\",\n            \"da\": \"Lav\",\n            \"de\": \"Niedrig\",\n            \"es\": \"Bajo\",\n            \"fr\": \"Faible\",\n            \"it\": \"Basso\",\n            \"no\": \"Lav\",\n            \"sv\": \"Låg\",\n            \"pl\": \"Niski\",\n            \"ru\": \"Низкий\",\n            \"ko\": \"낮음\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"label\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Medium\",\n            \"da\": \"Mellem\",\n            \"de\": \"Mittel\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Middels\",\n            \"sv\": \"Medium\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"label\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Élevé\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높음\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"label\": {\n            \"en\": \"Humidity\",\n            \"nl\": \"Luchtvochtigheid\",\n            \"da\": \"Fugtighed\",\n            \"de\": \"Feuchtigkeit\",\n            \"es\": \"Humedad\",\n            \"fr\": \"Humidité\",\n            \"it\": \"Umidità\",\n            \"no\": \"Fuktighet\",\n            \"sv\": \"Luftfuktighet\",\n            \"pl\": \"Wilgotność\",\n            \"ru\": \"Влажность\",\n            \"ko\": \"습도\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Humidifier\",\n        \"nl\": \"Selecteer Mi Luchtbevochtiger\",\n        \"da\": \"Vælg Mi Luftfugter\",\n        \"de\": \"Wählen Sie Mi Luftbefeuchter\",\n        \"es\": \"Selecciona Mi Humidificador\",\n        \"fr\": \"Sélectionnez Mi Humidificateur\",\n        \"it\": \"Seleziona Mi Umidificatore\",\n        \"no\": \"Velg Mi Luftfukter\",\n        \"sv\": \"Välj Mi Luftfuktare\",\n        \"pl\": \"Wybierz Mi Nawilżacz\",\n        \"ru\": \"Выберите Mi Увлажнитель\",\n        \"ko\": \"Mi 가습기 선택\"\n      },\n      \"filter\": \"driver_id=humidifier_deerma_humidifier_jsq||humidifier_deerma_humidifier_miot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/modeHumidifierLeshowJSQ1.json",
    "content": "{\n  \"id\": \"modeHumidifierLeshowJSQ1\",\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Sæt tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Establecer modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Sett modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus auf [[mode]] einstellen\",\n    \"es\": \"Establecer modo en [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Sett modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Constant Humidity\",\n            \"nl\": \"Constante luchtvochtigheid\",\n            \"da\": \"Konstant fugtighed\",\n            \"de\": \"Konstante Luftfeuchtigkeit\",\n            \"es\": \"Humedad constante\",\n            \"fr\": \"Humidité constante\",\n            \"it\": \"Umidità costante\",\n            \"no\": \"Konstant fuktighet\",\n            \"sv\": \"Konstant fuktighet\",\n            \"pl\": \"Stała wilgotność\",\n            \"ru\": \"Постоянная влажность\",\n            \"ko\": \"일정한 습도\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Élevé\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높음\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Sleep\",\n            \"nl\": \"Slaapstand\",\n            \"da\": \"Søvn\",\n            \"de\": \"Schlafmodus\",\n            \"es\": \"Dormir\",\n            \"fr\": \"Sommeil\",\n            \"it\": \"Sonno\",\n            \"no\": \"Søvn\",\n            \"sv\": \"Sömn\",\n            \"pl\": \"Sen\",\n            \"ru\": \"Сон\",\n            \"ko\": \"수면\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Humidifier\",\n        \"nl\": \"Selecteer Mi Luchtbevochtiger\",\n        \"da\": \"Vælg Mi Luftfugter\",\n        \"de\": \"Wählen Sie Mi Luftbefeuchter\",\n        \"es\": \"Seleccione Mi Humidificador\",\n        \"fr\": \"Sélectionnez Mi Humidificateur\",\n        \"it\": \"Seleziona Mi Umidificatore\",\n        \"no\": \"Velg Mi Luftfukter\",\n        \"sv\": \"Välj Mi Luftfuktare\",\n        \"pl\": \"Wybierz Mi Nawilżacz\",\n        \"ru\": \"Выберите Mi Увлажнитель\",\n        \"ko\": \"Mi 가습기 선택\"\n      },\n      \"filter\": \"driver_id=humidifier_leshow_humidifier_jsq1\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/modeVacuumMop.json",
    "content": "{\n  \"id\": \"modeVacuumMop\",\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Indstil tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Establecer modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Sett modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus einstellen auf [[mode]]\",\n    \"es\": \"Establecer modo en [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Sett modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Vacuum\",\n            \"nl\": \"Stofzuigen\",\n            \"da\": \"Støvsug\",\n            \"de\": \"Staubsaugen\",\n            \"es\": \"Aspirar\",\n            \"fr\": \"Aspirer\",\n            \"it\": \"Aspirazione\",\n            \"no\": \"Støvsuging\",\n            \"sv\": \"Dammsug\",\n            \"pl\": \"Odkurzanie\",\n            \"ru\": \"Пылесос\",\n            \"ko\": \"청소\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Vacuum + Mop\",\n            \"nl\": \"Stofzuigen + moppen\",\n            \"da\": \"Støvsug + Mop\",\n            \"de\": \"Staubsaugen + Wischen\",\n            \"es\": \"Aspirar + Fregar\",\n            \"fr\": \"Aspirer + Nettoyer\",\n            \"it\": \"Aspirazione + Passaggio del mop\",\n            \"no\": \"Støvsuging + Mopping\",\n            \"sv\": \"Dammsug + Moppa\",\n            \"pl\": \"Odkurzanie + Mop\",\n            \"ru\": \"Пылесос + Мытье\",\n            \"ko\": \"청소 + 물걸레질\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Mop\",\n            \"nl\": \"Moppen\",\n            \"da\": \"Mop\",\n            \"de\": \"Wischen\",\n            \"es\": \"Fregar\",\n            \"fr\": \"Nettoyer\",\n            \"it\": \"Passaggio del mop\",\n            \"no\": \"Mopping\",\n            \"sv\": \"Moppa\",\n            \"pl\": \"Mop\",\n            \"ru\": \"Мытье\",\n            \"ko\": \"물걸레질\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer Stofzuiger\",\n        \"da\": \"Vælg Støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccionar Aspiradora\",\n        \"fr\": \"Sélectionnez l'aspirateur\",\n        \"it\": \"Seleziona Aspirapolvere\",\n        \"no\": \"Velg Støvsuger\",\n        \"sv\": \"Välj Dammsugare\",\n        \"pl\": \"Wybierz Odkurzacz\",\n        \"ru\": \"Выберите Пылесос\",\n        \"ko\": \"청소기 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_viomi_vacuum_v7\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/modeZhimiAirfresh.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set Mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Indstil tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Configurar modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Angi modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Indstil tilstand til [[mode]]\",\n    \"de\": \"Modus einstellen auf [[mode]]\",\n    \"es\": \"Configurar modo a [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta la modalità su [[mode]]\",\n    \"no\": \"Angi modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"auto\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"da\": \"Auto\",\n            \"de\": \"Auto\",\n            \"es\": \"Automático\",\n            \"fr\": \"Auto\",\n            \"it\": \"Auto\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"silent\",\n          \"title\": {\n            \"en\": \"Silent\",\n            \"nl\": \"Stil\",\n            \"da\": \"Silent\",\n            \"de\": \"Leise\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Silent\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"무음\"\n          }\n        },\n        {\n          \"id\": \"interval\",\n          \"title\": {\n            \"en\": \"Interval\",\n            \"nl\": \"Interval\",\n            \"da\": \"Interval\",\n            \"de\": \"Intervall\",\n            \"es\": \"Intervalo\",\n            \"fr\": \"Intervalle\",\n            \"it\": \"Intervallo\",\n            \"no\": \"Intervall\",\n            \"sv\": \"Intervall\",\n            \"pl\": \"Interwał\",\n            \"ru\": \"Интервал\",\n            \"ko\": \"간격\"\n          }\n        },\n        {\n          \"id\": \"low\",\n          \"title\": {\n            \"en\": \"Low\",\n            \"nl\": \"Laag\",\n            \"da\": \"Lav\",\n            \"de\": \"Niedrig\",\n            \"es\": \"Bajo\",\n            \"fr\": \"Bas\",\n            \"it\": \"Basso\",\n            \"no\": \"Lav\",\n            \"sv\": \"Låg\",\n            \"pl\": \"Niski\",\n            \"ru\": \"Низкий\",\n            \"ko\": \"낮음\"\n          }\n        },\n        {\n          \"id\": \"middle\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Medium\",\n            \"da\": \"Middel\",\n            \"de\": \"Mittel\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Middels\",\n            \"sv\": \"Medium\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"strong\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Élevé\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높음\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Smartmi Fresh Air System \",\n        \"nl\": \"Selecteer Smartmi Fresh Air System\",\n        \"da\": \"Vælg Smartmi Fresh Air System \",\n        \"de\": \"Smartmi-Frischluftsystem auswählen\",\n        \"es\": \"Seleccione Smartmi Fresh Air System \",\n        \"fr\": \"Sélectionnez Smartmi Fresh Air System \",\n        \"it\": \"Seleziona Smartmi Fresh Air System \",\n        \"no\": \"Velg Smartmi Fresh Air System\",\n        \"sv\": \"Välj Smartmi Fresh Air System \",\n        \"pl\": \"Wybierz Smartmi Fresh Air System \",\n        \"ru\": \"Выберите систему свежего воздуха Smartmi\",\n        \"ko\": \"Smartmi Fresh Air System 선택\"\n      },\n      \"filter\": \"driver_id=airfresh_zhimi_airfresh\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/petfeederCalibrate.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Calibrate feeder scale\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\"\n      },\n      \"filter\": \"driver_id=petfeeder_mmgg_miot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/actions/petfeederDisplaySchedule.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set display schedule progress\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Display progress [[enabled]]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"enabled\",\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"true\",\n          \"label\": {\n            \"en\": \"On\"\n          }\n        },\n        {\n          \"id\": \"false\",\n          \"label\": {\n            \"en\": \"Off\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\"\n      },\n      \"filter\": \"driver_id=petfeeder_mmgg_miot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/actions/petfeederServeFood.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Serve food\",\n    \"nl\": \"Voedsel serveren\",\n    \"da\": \"Server mad\",\n    \"de\": \"Essen servieren\",\n    \"es\": \"Servir comida\",\n    \"fr\": \"Servir la nourriture\",\n    \"it\": \"Servire cibo\",\n    \"no\": \"Server mat\",\n    \"sv\": \"Servera mat\",\n    \"pl\": \"Podawaj jedzenie\",\n    \"ru\": \"Подавать еду\",\n    \"ko\": \"음식 제공\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Serve [[servings]] servings\",\n    \"nl\": \"Serveer [[servings]] porties\",\n    \"da\": \"Server [[servings]] portioner\",\n    \"de\": \"Serviere [[servings]] Portionen\",\n    \"es\": \"Servir [[servings]] raciones\",\n    \"fr\": \"Servir [[servings]] portions\",\n    \"it\": \"Servi [[servings]] porzioni\",\n    \"no\": \"Server [[servings]] porsjoner\",\n    \"sv\": \"Servera [[servings]] portioner\",\n    \"pl\": \"Podaj [[servings]] porcje\",\n    \"ru\": \"Подать [[servings]] порций\",\n    \"ko\": \"[[servings]] 서빙 제공\"\n  },\n  \"args\": [\n    {\n      \"name\": \"servings\",\n      \"title\": {\n        \"en\": \"Servings\",\n        \"nl\": \"Porties\",\n        \"da\": \"Portioner\",\n        \"de\": \"Portionen\",\n        \"es\": \"Raciones\",\n        \"fr\": \"Portions\",\n        \"it\": \"Porzioni\",\n        \"no\": \"Porsjoner\",\n        \"sv\": \"Portioner\",\n        \"pl\": \"Porcje\",\n        \"ru\": \"Порции\",\n        \"ko\": \"서빙\"\n      },\n      \"type\": \"number\",\n      \"placeholder\": {\n        \"en\": \"Servings\",\n        \"nl\": \"Porties\",\n        \"da\": \"Portioner\",\n        \"de\": \"Portionen\",\n        \"es\": \"Raciones\",\n        \"fr\": \"Portions\",\n        \"it\": \"Porzioni\",\n        \"no\": \"Porsjoner\",\n        \"sv\": \"Portioner\",\n        \"pl\": \"Porcje\",\n        \"ru\": \"Порции\",\n        \"ko\": \"서빙\"\n      },\n      \"min\": 1,\n      \"max\": 30,\n      \"step\": 1\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=petfeeder_mmgg_miot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/petwaterdispenserMmggMode.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set mode\",\n    \"nl\": \"Stel modus in\",\n    \"da\": \"Sæt tilstand\",\n    \"de\": \"Modus einstellen\",\n    \"es\": \"Establecer modo\",\n    \"fr\": \"Définir le mode\",\n    \"it\": \"Imposta modalità\",\n    \"no\": \"Sett modus\",\n    \"sv\": \"Ställ in läge\",\n    \"pl\": \"Ustaw tryb\",\n    \"ru\": \"Установить режим\",\n    \"ko\": \"모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]]\",\n    \"nl\": \"Stel modus in op [[mode]]\",\n    \"da\": \"Sæt tilstand til [[mode]]\",\n    \"de\": \"Modus auf [[mode]] setzen\",\n    \"es\": \"Establecer modo en [[mode]]\",\n    \"fr\": \"Définir le mode sur [[mode]]\",\n    \"it\": \"Imposta modalità su [[mode]]\",\n    \"no\": \"Sett modus til [[mode]]\",\n    \"sv\": \"Ställ in läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb na [[mode]]\",\n    \"ru\": \"Установить режим на [[mode]]\",\n    \"ko\": \"[[mode]] 모드로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Common\",\n            \"nl\": \"Normaal\",\n            \"da\": \"Almindelig\",\n            \"de\": \"Normal\",\n            \"es\": \"Común\",\n            \"fr\": \"Commun\",\n            \"it\": \"Comune\",\n            \"no\": \"Vanlig\",\n            \"sv\": \"Vanlig\",\n            \"pl\": \"Zwykły\",\n            \"ru\": \"Обычный\",\n            \"ko\": \"일반\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Smart\",\n            \"nl\": \"Slim\",\n            \"da\": \"Smart\",\n            \"de\": \"Klug\",\n            \"es\": \"Inteligente\",\n            \"fr\": \"Intelligent\",\n            \"it\": \"Intelligente\",\n            \"no\": \"Smart\",\n            \"sv\": \"Smart\",\n            \"pl\": \"Inteligentny\",\n            \"ru\": \"Умный\",\n            \"ko\": \"스마트\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Pet Waterdispenser\",\n        \"nl\": \"Selecteer Pet Waterdispenser\",\n        \"da\": \"Vælg Pet Waterdispenser\",\n        \"de\": \"Wählen Sie Pet Waterdispenser\",\n        \"es\": \"Seleccione el dispensador de agua para mascotas\",\n        \"fr\": \"Sélectionnez Pet Waterdispenser\",\n        \"it\": \"Seleziona Pet Waterdispenser\",\n        \"no\": \"Velg Pet Waterdispenser\",\n        \"sv\": \"Välj Pet Waterdispenser\",\n        \"pl\": \"Wybierz Pet Waterdispenser\",\n        \"ru\": \"Выберите Pet Waterdispenser\",\n        \"ko\": \"펫 워터 디스펜서를 선택하세요\"\n      },\n      \"filter\": \"driver_id=petwaterdispenser_mmgg_miot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/petwaterdispenserMmggMode_Xiaomi.json",
    "content": "{\n    \"title\": {\n      \"en\": \"Set mode\",\n      \"nl\": \"Stel modus in\",\n      \"da\": \"Sæt tilstand\",\n      \"de\": \"Modus einstellen\",\n      \"es\": \"Establecer modo\",\n      \"fr\": \"Définir le mode\",\n      \"it\": \"Imposta modalità\",\n      \"no\": \"Sett modus\",\n      \"sv\": \"Ställ in läge\",\n      \"pl\": \"Ustaw tryb\",\n      \"ru\": \"Установить режим\",\n      \"ko\": \"모드 설정\"\n    },\n    \"titleFormatted\": {\n      \"en\": \"Set mode to [[mode]]\",\n      \"nl\": \"Stel modus in op [[mode]]\",\n      \"da\": \"Sæt tilstand til [[mode]]\",\n      \"de\": \"Modus auf [[mode]] setzen\",\n      \"es\": \"Establecer modo en [[mode]]\",\n      \"fr\": \"Définir le mode sur [[mode]]\",\n      \"it\": \"Imposta modalità su [[mode]]\",\n      \"no\": \"Sett modus til [[mode]]\",\n      \"sv\": \"Ställ in läge till [[mode]]\",\n      \"pl\": \"Ustaw tryb na [[mode]]\",\n      \"ru\": \"Установить режим на [[mode]]\",\n      \"ko\": \"[[mode]] 모드로 설정\"\n    },\n    \"args\": [\n      {\n        \"name\": \"mode\",\n        \"title\": {\n          \"en\": \"Mode\",\n          \"nl\": \"Modus\",\n          \"da\": \"Tilstand\",\n          \"de\": \"Modus\",\n          \"es\": \"Modo\",\n          \"fr\": \"Mode\",\n          \"it\": \"Modalità\",\n          \"no\": \"Modus\",\n          \"sv\": \"Läge\",\n          \"pl\": \"Tryb\",\n          \"ru\": \"Режим\",\n          \"ko\": \"모드\"\n        },\n        \"type\": \"dropdown\",\n        \"values\": [\n          {\n            \"id\": \"0\",\n            \"title\": {\n              \"en\": \"Auto\",\n              \"nl\": \"Auto\",\n              \"da\": \"Auto\",\n              \"de\": \"Auto\",\n              \"es\": \"Auto\",\n              \"fr\": \"Auto\",\n              \"it\": \"Auto\",\n              \"no\": \"Auto\",\n              \"sv\": \"Auto\",\n              \"pl\": \"Auto\",\n              \"ru\": \"Авто\",\n              \"ko\": \"자동\"\n            }\n          },\n          {\n            \"id\": \"1\",\n            \"title\": {\n              \"en\": \"Interval\",\n              \"nl\": \"Interval\",\n              \"da\": \"Interval\",\n              \"de\": \"Intervall\",\n              \"es\": \"Intervalo\",\n              \"fr\": \"Intervalle\",\n              \"it\": \"Intervallo\",\n              \"no\": \"Intervall\",\n              \"sv\": \"Intervall\",\n              \"pl\": \"Interwał\",\n              \"ru\": \"Интервал\",\n              \"ko\": \"간격\"\n            }\n          },\n          {\n            \"id\": \"2\",\n            \"title\": {\n              \"en\": \"Constant\",\n              \"nl\": \"Constant\",\n              \"da\": \"Konstant\",\n              \"de\": \"Konstant\",\n              \"es\": \"Constante\",\n              \"fr\": \"Constant\",\n              \"it\": \"Costante\",\n              \"no\": \"Konstant\",\n              \"sv\": \"Konstant\",\n              \"pl\": \"Stały\",\n              \"ru\": \"Постоянный\",\n              \"ko\": \"지속\"\n            }\n          }\n        ]\n      },\n      {\n        \"name\": \"device\",\n        \"type\": \"device\",\n        \"placeholder\": {\n          \"en\": \"Select Pet Fountain\",\n          \"nl\": \"Selecteer Huisdierfontein\",\n          \"da\": \"Vælg Kæledyrsfountain\",\n          \"de\": \"Wählen Sie Haustierbrunnen\",\n          \"es\": \"Seleccione Fuente para Mascotas\",\n          \"fr\": \"Sélectionnez Fontaine pour Animaux\",\n          \"it\": \"Seleziona Fontana per Animali\",\n          \"no\": \"Velg Kjæledyrfontene\",\n          \"sv\": \"Välj Husdjursfontän\",\n          \"pl\": \"Wybierz Fontannę dla Zwierząt\",\n          \"ru\": \"Выберите Фонтан для животных\",\n          \"ko\": \"펫 분수대 선택\"\n        },\n        \"filter\": \"driver_id=pet_waterer_xiaomi\"\n      }\n    ],\n    \"platforms\": [\n      \"local\"\n    ]\n  }\n  "
  },
  {
    "path": ".homeycompose/flow/actions/remote_send_ir_code.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Send IR code\",\n    \"nl\": \"IR code versturen\",\n    \"da\": \"Send IR-kode\",\n    \"de\": \"IR-Code senden\",\n    \"es\": \"Enviar código IR\",\n    \"fr\": \"Envoyer le code IR\",\n    \"it\": \"Invia codice IR\",\n    \"no\": \"Send IR-kode\",\n    \"sv\": \"Skicka IR-kod\",\n    \"pl\": \"Wyślij kod IR\",\n    \"ru\": \"Отправить код IR\",\n    \"ko\": \"IR 코드 보내기\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Send code [[code]]\",\n    \"nl\": \"Verstuur code [[code]]\",\n    \"da\": \"Send kode [[code]]\",\n    \"de\": \"Code [[code]] senden\",\n    \"es\": \"Enviar código [[code]]\",\n    \"fr\": \"Envoyer le code [[code]]\",\n    \"it\": \"Invia codice [[code]]\",\n    \"no\": \"Send kode [[code]]\",\n    \"sv\": \"Skicka kod [[code]]\",\n    \"pl\": \"Wyślij kod [[code]]\",\n    \"ru\": \"Отправить код [[code]]\",\n    \"ko\": \"코드 [[code]] 보내기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"code\",\n      \"title\": {\n        \"en\": \"Code\",\n        \"nl\": \"Code\",\n        \"da\": \"Kode\",\n        \"de\": \"Code\",\n        \"es\": \"Código\",\n        \"fr\": \"Code\",\n        \"it\": \"Codice\",\n        \"no\": \"Kode\",\n        \"sv\": \"Kod\",\n        \"pl\": \"Kod\",\n        \"ru\": \"Код\",\n        \"ko\": \"코드\"\n      },\n      \"type\": \"text\",\n      \"placeholder\": {\n        \"en\": \"code\",\n        \"nl\": \"code\",\n        \"da\": \"kode\",\n        \"de\": \"Code\",\n        \"es\": \"código\",\n        \"fr\": \"code\",\n        \"it\": \"codice\",\n        \"no\": \"kode\",\n        \"sv\": \"kod\",\n        \"pl\": \"kod\",\n        \"ru\": \"код\",\n        \"ko\": \"코드\"\n      }\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select IR Remote\",\n        \"nl\": \"Selecteer IR Remote\",\n        \"da\": \"Vælg IR-fjernbetjening\",\n        \"de\": \"Wähle IR-Fernbedienung\",\n        \"es\": \"Selecciona Control Remoto IR\",\n        \"fr\": \"Sélectionnez la télécommande IR\",\n        \"it\": \"Seleziona telecomando IR\",\n        \"no\": \"Velg IR-fjernkontroll\",\n        \"sv\": \"Välj IR-fjärrkontroll\",\n        \"pl\": \"Wybierz pilot IR\",\n        \"ru\": \"Выберите ИК-пульт\",\n        \"ko\": \"IR 리모컨 선택\"\n      },\n      \"filter\": \"driver_id=remote_chuangmi_remote_v2\"\n    }\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/rightSwitchOff.json",
    "content": "{\n  \"id\": \"rightSwitchOff\",\n  \"title\": {\n    \"en\": \"Turn Right Switch Off\",\n    \"nl\": \"Schakel rechterschakelaar uit\",\n    \"da\": \"Sluk højre kontakt\",\n    \"de\": \"Rechten Schalter ausschalten\",\n    \"es\": \"Apagar interruptor derecho\",\n    \"fr\": \"Éteindre l'interrupteur de droite\",\n    \"it\": \"Spegni interruttore destro\",\n    \"no\": \"Slå av høyre bryter\",\n    \"sv\": \"Stäng av höger strömbrytare\",\n    \"pl\": \"Wyłącz prawy przełącznik\",\n    \"ru\": \"Выключить правый выключатель\",\n    \"ko\": \"오른쪽 스위치 끄기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/rightSwitchOn.json",
    "content": "{\n  \"id\": \"rightSwitchOn\",\n  \"title\": {\n    \"en\": \"Turn Right Switch On\",\n    \"nl\": \"Schakel rechterschakelaar aan\",\n    \"da\": \"Tænd højre kontakt\",\n    \"de\": \"Rechten Schalter einschalten\",\n    \"es\": \"Encender interruptor derecho\",\n    \"fr\": \"Allumer l'interrupteur droit\",\n    \"it\": \"Accendi l'interruttore destro\",\n    \"no\": \"Slå på høyre bryter\",\n    \"sv\": \"Slå på höger strömbrytare\",\n    \"pl\": \"Włącz prawy przełącznik\",\n    \"ru\": \"Включить правый переключатель\",\n    \"ko\": \"오른쪽 스위치 켜기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/rightSwitchToggle.json",
    "content": "{\n  \"id\": \"rightSwitchToggle\",\n  \"title\": {\n    \"en\": \"Toggle Right Switch\",\n    \"nl\": \"Schakel rechterschakelaar\",\n    \"da\": \"Skift højre kontakt\",\n    \"de\": \"Rechten Schalter umschalten\",\n    \"es\": \"Cambiar interruptor derecho\",\n    \"fr\": \"Basculer l'interrupteur droit\",\n    \"it\": \"Attiva/disattiva l'interruttore destro\",\n    \"no\": \"Slå av/på høyre bryter\",\n    \"sv\": \"Växla höger strömbrytare\",\n    \"pl\": \"Przełącz prawy przełącznik\",\n    \"ru\": \"Переключить правый переключатель\",\n    \"ko\": \"오른쪽 스위치 전환\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/rotateLeftStep.json",
    "content": "{\n  \"title\": { \"en\": \"Rotate fan to the left\", \"de\": \"Lüfter nach links drehen\" },\n  \"titleFormatted\": { \"en\": \"Rotate fan to the left\", \"de\": \"Lüfter nach links drehen\" },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": { \"en\": \"Select Device\" },\n      \"filter\": \"driver_id=fan_dmaker_advanced\"\n    }\n  ],\n  \"platforms\": [\"local\"]\n}\n"
  },
  {
    "path": ".homeycompose/flow/actions/rotateRightStep.json",
    "content": "{\n  \"title\": { \"en\": \"Rotate fan to the right\", \"de\": \"Lüfter nach rechts drehen\" },\n  \"titleFormatted\": { \"en\": \"Rotate fan to the right\", \"de\": \"Lüfter nach rechts drehen\" },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": { \"en\": \"Select Device\" },\n      \"filter\": \"driver_id=fan_dmaker_advanced\"\n    }\n  ],\n  \"platforms\": [\"local\"]\n}\n"
  },
  {
    "path": ".homeycompose/flow/actions/setAngle.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Change Oscillating Angle\",\n    \"nl\": \"Wijzig oscillatie hoek\",\n    \"da\": \"Skift oscillerende vinkel\",\n    \"de\": \"Oszillationswinkel ändern\",\n    \"es\": \"Cambiar ángulo de oscilación\",\n    \"fr\": \"Changer l'angle d'oscillation\",\n    \"it\": \"Cambia angolo di oscillazione\",\n    \"no\": \"Endre oscillerende vinkel\",\n    \"sv\": \"Ändra oscillatorvinkel\",\n    \"pl\": \"Zmień kąt oscylacji\",\n    \"ru\": \"Изменить угол колебания\",\n    \"ko\": \"진동 각도 변경\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Change oscillating angle to [[angle]]\",\n    \"nl\": \"Wijzig oscillatie hoek naar [[angle]]\",\n    \"da\": \"Skift oscillerende vinkel til [[angle]]\",\n    \"de\": \"Oszillationswinkel ändern zu [[angle]]\",\n    \"es\": \"Cambiar ángulo de oscilación a [[angle]]\",\n    \"fr\": \"Changer l'angle d'oscillation en [[angle]]\",\n    \"it\": \"Cambia angolo di oscillazione a [[angle]]\",\n    \"no\": \"Endre oscillerende vinkel til [[angle]]\",\n    \"sv\": \"Ändra oscillatorvinkel till [[angle]]\",\n    \"pl\": \"Zmień kąt oscylacji na [[angle]]\",\n    \"ru\": \"Изменить угол колебания на [[angle]]\",\n    \"ko\": \"진동 각도 [[angle]]로 변경\"\n  },\n  \"args\": [\n    {\n      \"name\": \"angle\",\n      \"title\": {\n        \"en\": \"Angle\",\n        \"nl\": \"Hoek\",\n        \"da\": \"Vinkel\",\n        \"de\": \"Winkel\",\n        \"es\": \"Ángulo\",\n        \"fr\": \"Angle\",\n        \"it\": \"Angolo\",\n        \"no\": \"Vinkel\",\n        \"sv\": \"Vinkel\",\n        \"pl\": \"Kąt\",\n        \"ru\": \"Угол\",\n        \"ko\": \"각도\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"30\",\n          \"title\": {\n            \"en\": \"30°\",\n            \"nl\": \"30°\",\n            \"da\": \"30°\",\n            \"de\": \"30°\",\n            \"es\": \"30°\",\n            \"fr\": \"30°\",\n            \"it\": \"30°\",\n            \"no\": \"30°\",\n            \"sv\": \"30°\",\n            \"pl\": \"30°\",\n            \"ru\": \"30°\",\n            \"ko\": \"30°\"\n          }\n        },\n        {\n          \"id\": \"60\",\n          \"title\": {\n            \"en\": \"60°\",\n            \"nl\": \"60°\",\n            \"da\": \"60°\",\n            \"de\": \"60°\",\n            \"es\": \"60°\",\n            \"fr\": \"60°\",\n            \"it\": \"60°\",\n            \"no\": \"60°\",\n            \"sv\": \"60°\",\n            \"pl\": \"60°\",\n            \"ru\": \"60°\",\n            \"ko\": \"60°\"\n          }\n        },\n        {\n          \"id\": \"90\",\n          \"title\": {\n            \"en\": \"90°\",\n            \"nl\": \"90°\",\n            \"da\": \"90°\",\n            \"de\": \"90°\",\n            \"es\": \"90°\",\n            \"fr\": \"90°\",\n            \"it\": \"90°\",\n            \"no\": \"90°\",\n            \"sv\": \"90°\",\n            \"pl\": \"90°\",\n            \"ru\": \"90°\",\n            \"ko\": \"90°\"\n          }\n        },\n        {\n          \"id\": \"120\",\n          \"title\": {\n            \"en\": \"120°\",\n            \"nl\": \"120°\",\n            \"da\": \"120°\",\n            \"de\": \"120°\",\n            \"es\": \"120°\",\n            \"fr\": \"120°\",\n            \"it\": \"120°\",\n            \"no\": \"120°\",\n            \"sv\": \"120°\",\n            \"pl\": \"120°\",\n            \"ru\": \"120°\",\n            \"ko\": \"120°\"\n          }\n        },\n        {\n          \"id\": \"140\",\n          \"title\": {\n            \"en\": \"140°\",\n            \"nl\": \"140°\",\n            \"da\": \"140°\",\n            \"de\": \"140°\",\n            \"es\": \"140°\",\n            \"fr\": \"140°\",\n            \"it\": \"140°\",\n            \"no\": \"140°\",\n            \"sv\": \"140°\",\n            \"pl\": \"140°\",\n            \"ru\": \"140°\",\n            \"ko\": \"140°\"\n          }\n        },\n        {\n          \"id\": \"150\",\n          \"title\": {\n            \"en\": \"150°\",\n            \"nl\": \"150°\",\n            \"da\": \"150°\",\n            \"de\": \"150°\",\n            \"es\": \"150°\",\n            \"fr\": \"150°\",\n            \"it\": \"150°\",\n            \"no\": \"150°\",\n            \"sv\": \"150°\",\n            \"pl\": \"150°\",\n            \"ru\": \"150°\",\n            \"ko\": \"150°\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=zhimi-fan|dmaker-fan|fan_zhimi_advanced|fan_zhimi_fan_za5|fan_dmaker_advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/vacuumDreameFanspeed.json",
    "content": "{\n  \"id\": \"vacuumDreameFanspeed\",\n  \"title\": {\n    \"en\": \"Set Fanspeed\",\n    \"nl\": \"Stel ventilator in\",\n    \"da\": \"Indstil blæserhastighed\",\n    \"de\": \"Lüftergeschwindigkeit einstellen\",\n    \"es\": \"Establecer velocidad del ventilador\",\n    \"fr\": \"Régler la vitesse du ventilateur\",\n    \"it\": \"Imposta velocità della ventola\",\n    \"no\": \"Set viftehastighet\",\n    \"sv\": \"Ställ in fläkthastighet\",\n    \"pl\": \"Ustaw prędkość wentylatora\",\n    \"ru\": \"Установить скорость вентилятора\",\n    \"ko\": \"팬 속도 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set Fanspeed [[fanspeed]]\",\n    \"nl\": \"Stel ventilator in op [[fanspeed]]\",\n    \"da\": \"Indstil blæserhastighed [[fanspeed]]\",\n    \"de\": \"Lüftergeschwindigkeit einstellen [[fanspeed]]\",\n    \"es\": \"Establecer velocidad del ventilador [[fanspeed]]\",\n    \"fr\": \"Régler la vitesse du ventilateur [[fanspeed]]\",\n    \"it\": \"Imposta velocità della ventola [[fanspeed]]\",\n    \"no\": \"Set viftehastighet [[fanspeed]]\",\n    \"sv\": \"Ställ in fläkthastighet [[fanspeed]]\",\n    \"pl\": \"Ustaw prędkość wentylatora [[fanspeed]]\",\n    \"ru\": \"Установить скорость вентилятора [[fanspeed]]\",\n    \"ko\": \"팬 속도 설정 [[fanspeed]]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"fanspeed\",\n      \"title\": {\n        \"en\": \"Fanspeed\",\n        \"nl\": \"Fan snelheid\",\n        \"da\": \"Blæserhastighed\",\n        \"de\": \"Lüftergeschwindigkeit\",\n        \"es\": \"Velocidad del ventilador\",\n        \"fr\": \"Vitesse du ventilateur\",\n        \"it\": \"Velocità della ventola\",\n        \"no\": \"Viftehastighet\",\n        \"sv\": \"Fläkhastighet\",\n        \"pl\": \"Prędkość wentylatora\",\n        \"ru\": \"Скорость вентилятора\",\n        \"ko\": \"팬 속도\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Silent\",\n            \"nl\": \"Stil\",\n            \"da\": \"Silent\",\n            \"de\": \"Leise\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"조용한\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Basic\",\n            \"nl\": \"Basis\",\n            \"da\": \"Grundlæggende\",\n            \"de\": \"Einfach\",\n            \"es\": \"Básico\",\n            \"fr\": \"De base\",\n            \"it\": \"Base\",\n            \"no\": \"Grunnleggende\",\n            \"sv\": \"Grundläggande\",\n            \"pl\": \"Podstawowy\",\n            \"ru\": \"Основной\",\n            \"ko\": \"기본\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Strong\",\n            \"nl\": \"Sterk\",\n            \"da\": \"Stærk\",\n            \"de\": \"Stark\",\n            \"es\": \"Fuerte\",\n            \"fr\": \"Fort\",\n            \"it\": \"Forte\",\n            \"no\": \"Sterk\",\n            \"sv\": \"Stark\",\n            \"pl\": \"Mocny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강한\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Full speed\",\n            \"nl\": \"Volle snelheid\",\n            \"da\": \"Fuld hastighed\",\n            \"de\": \"Volle Geschwindigkeit\",\n            \"es\": \"Velocidad completa\",\n            \"fr\": \"Vitesse maximale\",\n            \"it\": \"Velocità massima\",\n            \"no\": \"Full hastighet\",\n            \"sv\": \"Full hastighet\",\n            \"pl\": \"Pełna prędkość\",\n            \"ru\": \"Полная скорость\",\n            \"ko\": \"최고 속도\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer stofzuiger\",\n        \"da\": \"Vælg støvsuger\",\n        \"de\": \"Vakuum auswählen\",\n        \"es\": \"Seleccionar aspiradora\",\n        \"fr\": \"Sélectionner l'aspirateur\",\n        \"it\": \"Seleziona aspirapolvere\",\n        \"no\": \"Velg vakuum\",\n        \"sv\": \"Välj dammsugare\",\n        \"pl\": \"Wybierz odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"진공 청소기 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_dreame_vacuum\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/vacuumDreameMopIntensity.json",
    "content": "{\n  \"id\": \"vacuumDreameMopIntensity\",\n  \"title\": {\n    \"en\": \"Set Mop Intesity\",\n    \"nl\": \"Stel dweil intensiteit in\",\n    \"da\": \"Indstil moppe intensitet\",\n    \"de\": \"Wischeintensität einstellen\",\n    \"es\": \"Establecer intensidad de fregado\",\n    \"fr\": \"Définir l'intensité de la serpillière\",\n    \"it\": \"Imposta l'intensità della mocio\",\n    \"no\": \"Sett moppens intensitet\",\n    \"sv\": \"Ställ in moppintensitet\",\n    \"pl\": \"Ustaw intensywność mopa\",\n    \"ru\": \"Установить интенсивность швабры\",\n    \"ko\": \"걸레 강도 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mop intensity to [[intensity]]\",\n    \"nl\": \"Stel dweil intensiteit in op [[intensity]]\",\n    \"da\": \"Indstil moppe intensitet til [[intensity]]\",\n    \"de\": \"Wischeintensität auf [[intensity]] einstellen\",\n    \"es\": \"Establecer intensidad de fregado a [[intensity]]\",\n    \"fr\": \"Définir l'intensité de la serpillière à [[intensity]]\",\n    \"it\": \"Imposta l'intensità della mocio su [[intensity]]\",\n    \"no\": \"Sett moppens intensitet til [[intensity]]\",\n    \"sv\": \"Ställ in moppintensitet till [[intensity]]\",\n    \"pl\": \"Ustaw intensywność mopa na [[intensity]]\",\n    \"ru\": \"Установить интенсивность швабры на [[intensity]]\",\n    \"ko\": \"걸레 강도를 [[intensity]]로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"intensity\",\n      \"title\": {\n        \"en\": \"Mop Intensity\",\n        \"nl\": \"Dweil intensiteit\",\n        \"da\": \"Moppe intensitet\",\n        \"de\": \"Wischeintensität\",\n        \"es\": \"Intensidad de fregado\",\n        \"fr\": \"Intensité de la serpillière\",\n        \"it\": \"Intensità della mocio\",\n        \"no\": \"Moppens intensitet\",\n        \"sv\": \"Moppintensitet\",\n        \"pl\": \"Intensywność mopa\",\n        \"ru\": \"Интенсивность швабры\",\n        \"ko\": \"걸레 강도\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Low\",\n            \"nl\": \"Laag\",\n            \"da\": \"Lav\",\n            \"de\": \"Niedrig\",\n            \"es\": \"Bajo\",\n            \"fr\": \"Bas\",\n            \"it\": \"Bassa\",\n            \"no\": \"Lav\",\n            \"sv\": \"Låg\",\n            \"pl\": \"Niski\",\n            \"ru\": \"Низкий\",\n            \"ko\": \"낮음\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Medium\",\n            \"da\": \"Mellem\",\n            \"de\": \"Mittel\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Media\",\n            \"no\": \"Middels\",\n            \"sv\": \"Medium\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Élevé\",\n            \"it\": \"Alta\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높음\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer stofzuiger\",\n        \"da\": \"Vælg støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccionar aspiradora\",\n        \"fr\": \"Sélectionnez l'aspirateur\",\n        \"it\": \"Seleziona aspirapolvere\",\n        \"no\": \"Velg støvsuger\",\n        \"sv\": \"Välj dammsugare\",\n        \"pl\": \"Wybierz odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"청소기 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_dreame_vacuum&capabilities=vacuum_dreame_mop_intensity\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/vacuumRoborockFanspeed.json",
    "content": "{\n  \"id\": \"vacuumRoborockFanspeed\",\n  \"title\": {\n    \"en\": \"Set Fanspeed\",\n    \"nl\": \"Stel ventilator in\",\n    \"da\": \"Indstil blæserhastighed\",\n    \"de\": \"Lüftergeschwindigkeit einstellen\",\n    \"es\": \"Ajustar velocidad del ventilador\",\n    \"fr\": \"Régler la vitesse du ventilateur\",\n    \"it\": \"Imposta velocità ventola\",\n    \"no\": \"Sett vifthastighet\",\n    \"sv\": \"Ställ in fläkthastighet\",\n    \"pl\": \"Ustaw prędkość wentylatora\",\n    \"ru\": \"Установить скорость вентилятора\",\n    \"ko\": \"팬 속도 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set Fanspeed [[fanspeed]]\",\n    \"nl\": \"Stel ventilator in op [[fanspeed]]\",\n    \"da\": \"Indstil blæserhastighed [[fanspeed]]\",\n    \"de\": \"Lüftergeschwindigkeit einstellen [[fanspeed]]\",\n    \"es\": \"Ajustar velocidad del ventilador [[fanspeed]]\",\n    \"fr\": \"Régler la vitesse du ventilateur [[fanspeed]]\",\n    \"it\": \"Imposta velocità ventola [[fanspeed]]\",\n    \"no\": \"Sett vifthastighet [[fanspeed]]\",\n    \"sv\": \"Ställ in fläkthastighet [[fanspeed]]\",\n    \"pl\": \"Ustaw prędkość wentylatora [[fanspeed]]\",\n    \"ru\": \"Установить скорость вентилятора [[fanspeed]]\",\n    \"ko\": \"팬 속도 설정 [[fanspeed]]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"fanspeed\",\n      \"title\": {\n        \"en\": \"Fanspeed\",\n        \"nl\": \"Fan snelheid\",\n        \"da\": \"Blæserhastighed\",\n        \"de\": \"Lüftergeschwindigkeit\",\n        \"es\": \"Velocidad del ventilador\",\n        \"fr\": \"Vitesse du ventilateur\",\n        \"it\": \"Velocità ventola\",\n        \"no\": \"Vifthastighet\",\n        \"sv\": \"Fläkthastighet\",\n        \"pl\": \"Prędkość wentylatora\",\n        \"ru\": \"Скорость вентилятора\",\n        \"ko\": \"팬 속도\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Quiet\",\n            \"nl\": \"Stil\",\n            \"da\": \"Stille\",\n            \"de\": \"Leise\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"조용히\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Standard\",\n            \"nl\": \"Standaard\",\n            \"da\": \"Standard\",\n            \"de\": \"Standard\",\n            \"es\": \"Estándar\",\n            \"fr\": \"Standard\",\n            \"it\": \"Standard\",\n            \"no\": \"Standard\",\n            \"sv\": \"Standard\",\n            \"pl\": \"Standardowy\",\n            \"ru\": \"Стандарт\",\n            \"ko\": \"표준\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Medium\",\n            \"da\": \"Medium\",\n            \"de\": \"Mittel\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Medium\",\n            \"sv\": \"Medium\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Turbo\",\n            \"nl\": \"Turbo\",\n            \"da\": \"Turbo\",\n            \"de\": \"Turbo\",\n            \"es\": \"Turbo\",\n            \"fr\": \"Turbo\",\n            \"it\": \"Turbo\",\n            \"no\": \"Turbo\",\n            \"sv\": \"Turbo\",\n            \"pl\": \"Turbo\",\n            \"ru\": \"Турбо\",\n            \"ko\": \"터보\"\n          }\n        },\n        {\n          \"id\": \"5\",\n          \"title\": {\n            \"en\": \"Max\",\n            \"nl\": \"Max\",\n            \"da\": \"Maks.\",\n            \"de\": \"Max\",\n            \"es\": \"Máximo\",\n            \"fr\": \"Max\",\n            \"it\": \"Max\",\n            \"no\": \"Max\",\n            \"sv\": \"Max\",\n            \"pl\": \"Maks.\",\n            \"ru\": \"Макс.\",\n            \"ko\": \"최대\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer stofzuiger\",\n        \"da\": \"Vælg støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccionar aspiradora\",\n        \"fr\": \"Sélectionner un aspirateur\",\n        \"it\": \"Seleziona aspirapolvere\",\n        \"no\": \"Velg støvsuger\",\n        \"sv\": \"Välj dammsugare\",\n        \"pl\": \"Wybierz odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"진공 청소기 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/vacuumRoborockMopIntensity.json",
    "content": "{\n  \"id\": \"vacuumRoborockMopIntensity\",\n  \"title\": {\n    \"en\": \"Set Mop Intensity\",\n    \"nl\": \"Stel dweil intensiteit in\",\n    \"da\": \"Indstil Mop Intensitet\",\n    \"de\": \"Mop-Intensität einstellen\",\n    \"es\": \"Establecer intensidad de fregado\",\n    \"fr\": \"Régler l'intensité de la serpillière\",\n    \"it\": \"Imposta l'intensità della mop\",\n    \"no\": \"Sett moppintensitet\",\n    \"sv\": \"Ställ in moppintensitet\",\n    \"pl\": \"Ustaw intensywność mopa\",\n    \"ru\": \"Установить интенсивность швабры\",\n    \"ko\": \"걸레 강도 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set scrub intensity [[intensity]]\",\n    \"nl\": \"Stel mop intensiteit in op [[intensity]]\",\n    \"da\": \"Indstil skrubbeintensitet [[intensity]]\",\n    \"de\": \"Schrubbintensität einstellen [[intensity]]\",\n    \"es\": \"Establecer intensidad de fregado [[intensity]]\",\n    \"fr\": \"Régler l'intensité de la serpillière [[intensity]]\",\n    \"it\": \"Regola l'intensità di pulizia [[intensity]]\",\n    \"no\": \"Sett skrubbeintensitet [[intensity]]\",\n    \"sv\": \"Ställ in skrubbeintensitet [[intensity]]\",\n    \"pl\": \"Ustaw intensywność szorowania [[intensity]]\",\n    \"ru\": \"Установить интенсивность чистки [[intensity]]\",\n    \"ko\": \"스크럽 강도 설정 [[intensity]]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"intensity\",\n      \"title\": {\n        \"en\": \"Mop Intensity\",\n        \"nl\": \"Dweil intensiteit\",\n        \"da\": \"Mop Intensitet\",\n        \"de\": \"Mop-Intensität\",\n        \"es\": \"Intensidad de fregado\",\n        \"fr\": \"Intensité de la serpillière\",\n        \"it\": \"Intensità della mop\",\n        \"no\": \"Moppintensitet\",\n        \"sv\": \"Moppintensitet\",\n        \"pl\": \"Intensywność mopa\",\n        \"ru\": \"Интенсивность швабры\",\n        \"ko\": \"걸레 강도\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"200\",\n          \"label\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"da\": \"Slukket\",\n            \"de\": \"Aus\",\n            \"es\": \"Apagado\",\n            \"fr\": \"Éteint\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wyłączone\",\n            \"ru\": \"Выкл\",\n            \"ko\": \"끄기\"\n          }\n        },\n        {\n          \"id\": \"201\",\n          \"label\": {\n            \"en\": \"Mild\",\n            \"nl\": \"Mild\",\n            \"da\": \"Mild\",\n            \"de\": \"Mild\",\n            \"es\": \"Suave\",\n            \"fr\": \"Doux\",\n            \"it\": \"Leggera\",\n            \"no\": \"Mild\",\n            \"sv\": \"Mild\",\n            \"pl\": \"Łagodny\",\n            \"ru\": \"Мягкий\",\n            \"ko\": \"약하게\"\n          }\n        },\n        {\n          \"id\": \"202\",\n          \"label\": {\n            \"en\": \"Moderate\",\n            \"nl\": \"Gemiddeld\",\n            \"da\": \"Moderat\",\n            \"de\": \"Mittel\",\n            \"es\": \"Moderada\",\n            \"fr\": \"Modérée\",\n            \"it\": \"Moderata\",\n            \"no\": \"Moderat\",\n            \"sv\": \"Måttlig\",\n            \"pl\": \"Średnia\",\n            \"ru\": \"Умеренный\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"203\",\n          \"label\": {\n            \"en\": \"Intense\",\n            \"nl\": \"Intens\",\n            \"da\": \"Intens\",\n            \"de\": \"Intensiv\",\n            \"es\": \"Intensa\",\n            \"fr\": \"Intense\",\n            \"it\": \"Intensa\",\n            \"no\": \"Intens\",\n            \"sv\": \"Intensiv\",\n            \"pl\": \"Intensywny\",\n            \"ru\": \"Интенсивный\",\n            \"ko\": \"강하게\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer stofzuiger\",\n        \"da\": \"Vælg Støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccione Aspiradora\",\n        \"fr\": \"Sélectionnez Aspirateur\",\n        \"it\": \"Seleziona Aspirapolvere\",\n        \"no\": \"Velg Støvsuger\",\n        \"sv\": \"Välj Dammsugare\",\n        \"pl\": \"Wybierz Odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"진공 청소기를 선택하세요\"\n      },\n      \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced&capabilities=vacuum_roborock_mop_intensity\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/vacuumRoborockMopVacuumMode.json",
    "content": "{\n  \"id\": \"vacuumRoborockMopVacuumMode\",\n  \"title\": {\n    \"en\": \"Set mop/vacuummode and intensity\",\n    \"nl\": \"Stel mop/stofzuig modus en intensiteit in\",\n    \"da\": \"Indstil mop/suge tilstand og intensitet\",\n    \"de\": \"Stellen Sie den Mopp/Saugmodus und die Intensität ein\",\n    \"es\": \"Configura el modo de trapeado/aspirado y la intensidad\",\n    \"fr\": \"Réglez le mode mop/aspiration et l'intensité\",\n    \"it\": \"Imposta la modalità mop/aspirapolvere e l'intensità\",\n    \"no\": \"Still inn mopp/støvsugermodus og intensitet\",\n    \"sv\": \"Ställ in mopp/dammsugarläge och intensitet\",\n    \"pl\": \"Ustaw tryb mopowania/odkurzania i intensywność\",\n    \"ru\": \"Установите режим мытья/пылесоса и интенсивность\",\n    \"ko\": \"닦기/흡입 모드와 강도를 설정하세요\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set mode to [[mode]] with fan speed [[fanspeed]] and mop intensity [[mop]]\",\n    \"nl\": \"Stel mode in op [[mode]] met stofzuigkracht [[fanspeed]] en mop intensiteit [[mop]]\",\n    \"da\": \"Indstil tilstand til [[mode]] med blæserhastighed [[fanspeed]] og moppeintensitet [[mop]]\",\n    \"de\": \"Stellen Sie den Modus auf [[mode]] mit Gebläsegeschwindigkeit [[fanspeed]] und Mop-Intensität [[mop]] ein\",\n    \"es\": \"Configura el modo en [[mode]] con la velocidad del ventilador [[fanspeed]] y la intensidad del trapeado [[mop]]\",\n    \"fr\": \"Réglez le mode sur [[mode]] avec une vitesse de ventilateur de [[fanspeed]] et une intensité de mop [[mop]]\",\n    \"it\": \"Imposta la modalità su [[mode]] con velocità di ventilazione [[fanspeed]] e intensità del mop [[mop]]\",\n    \"no\": \"Sett modus til [[mode]] med viftehastighet [[fanspeed]] og moppintensitet [[mop]]\",\n    \"sv\": \"Ställ in läge till [[mode]] med fläkthastighet [[fanspeed]] och moppintensitet [[mop]]\",\n    \"pl\": \"Ustaw tryb na [[mode]] z prędkością wentylatora [[fanspeed]] i intensywnością mopowania [[mop]]\",\n    \"ru\": \"Установите режим на [[mode]] с скоростью вентилятора [[fanspeed]] и интенсивностью мытья [[mop]]\",\n    \"ko\": \"[[mode]] 모드로 설정하고 팬 속도 [[fanspeed]]와 걸레 세정 강도 [[mop]]를 조절하세요\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"sweep\",\n          \"title\": {\n            \"en\": \"Vacuum\",\n            \"nl\": \"Stofzuigen\",\n            \"da\": \"Suge\",\n            \"de\": \"Saugen\",\n            \"es\": \"Aspirar\",\n            \"fr\": \"Aspirateur\",\n            \"it\": \"Aspirapolvere\",\n            \"no\": \"Støvsuge\",\n            \"sv\": \"Dammsug\",\n            \"pl\": \"Odkurzanie\",\n            \"ru\": \"Пылесос\",\n            \"ko\": \"진공 청소\"\n          }\n        },\n        {\n          \"id\": \"mop\",\n          \"title\": {\n            \"en\": \"Mop\",\n            \"nl\": \"Moppen\",\n            \"da\": \"Moppe\",\n            \"de\": \"Wischen\",\n            \"es\": \"Trapeado\",\n            \"fr\": \"Mop\",\n            \"it\": \"Mocio\",\n            \"no\": \"Moppe\",\n            \"sv\": \"Moppa\",\n            \"pl\": \"Mopowanie\",\n            \"ru\": \"Моп\",\n            \"ko\": \"걸레질\"\n          }\n        },\n        {\n          \"id\": \"sweep-mop\",\n          \"title\": {\n            \"en\": \"Vacuum + Mop\",\n            \"nl\": \"Stofzuigen + moppen\",\n            \"da\": \"Suge + Moppe\",\n            \"de\": \"Saugen + Wischen\",\n            \"es\": \"Aspirar + Trapeado\",\n            \"fr\": \"Aspirateur + Mop\",\n            \"it\": \"Aspirapolvere + Mocio\",\n            \"no\": \"Støvsuge + Moppe\",\n            \"sv\": \"Dammsug + Moppa\",\n            \"pl\": \"Odkurzanie + Mopowanie\",\n            \"ru\": \"Пылесос + Моп\",\n            \"ko\": \"진공 청소 + 걸레질\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"fanspeed\",\n      \"title\": {\n        \"en\": \"Fanspeed\",\n        \"nl\": \"Fan snelheid\",\n        \"da\": \"Blæserhastighed\",\n        \"de\": \"Gebläsegeschwindigkeit\",\n        \"es\": \"Velocidad del ventilador\",\n        \"fr\": \"Vitesse du ventilateur\",\n        \"it\": \"Velocità della ventola\",\n        \"no\": \"Viftehastighet\",\n        \"sv\": \"Fläkthastighet\",\n        \"pl\": \"Prędkość wentylatora\",\n        \"ru\": \"Скорость вентилятора\",\n        \"ko\": \"팬 속도\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Quiet\",\n            \"nl\": \"Stil\",\n            \"da\": \"Stille\",\n            \"de\": \"Leise\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"조용한\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Standard\",\n            \"nl\": \"Standaard\",\n            \"da\": \"Standard\",\n            \"de\": \"Standard\",\n            \"es\": \"Estándar\",\n            \"fr\": \"Standard\",\n            \"it\": \"Standard\",\n            \"no\": \"Standard\",\n            \"sv\": \"Standard\",\n            \"pl\": \"Standard\",\n            \"ru\": \"Стандартный\",\n            \"ko\": \"표준\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Medium\",\n            \"da\": \"Medium\",\n            \"de\": \"Mittel\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Medium\",\n            \"sv\": \"Medium\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Turbo\",\n            \"nl\": \"Turbo\",\n            \"da\": \"Turbo\",\n            \"de\": \"Turbo\",\n            \"es\": \"Turbo\",\n            \"fr\": \"Turbo\",\n            \"it\": \"Turbo\",\n            \"no\": \"Turbo\",\n            \"sv\": \"Turbo\",\n            \"pl\": \"Turbo\",\n            \"ru\": \"Турбо\",\n            \"ko\": \"터보\"\n          }\n        },\n        {\n          \"id\": \"5\",\n          \"title\": {\n            \"en\": \"Max\",\n            \"nl\": \"Max\",\n            \"da\": \"Maks\",\n            \"de\": \"Max\",\n            \"es\": \"Máximo\",\n            \"fr\": \"Max\",\n            \"it\": \"Massimo\",\n            \"no\": \"Maksimum\",\n            \"sv\": \"Max\",\n            \"pl\": \"Maksymalny\",\n            \"ru\": \"Макс.\",\n            \"ko\": \"최대\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"mop\",\n      \"title\": {\n        \"en\": \"Mop Intensity\",\n        \"nl\": \"Dweil intensiteit\",\n        \"da\": \"Moppe Intensitet\",\n        \"de\": \"Mop-Intensität\",\n        \"es\": \"Intensidad del trapeado\",\n        \"fr\": \"Intensité de la mop\",\n        \"it\": \"Intensità del mocio\",\n        \"no\": \"Moppintensitet\",\n        \"sv\": \"Moppintensitet\",\n        \"pl\": \"Intensywność mopowania\",\n        \"ru\": \"Интенсивность мытья\",\n        \"ko\": \"걸레질 강도\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"200\",\n          \"label\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"da\": \"Fra\",\n            \"de\": \"Aus\",\n            \"es\": \"Apagar\",\n            \"fr\": \"Éteint\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wył.\",\n            \"ru\": \"Выключено\",\n            \"ko\": \"끔\"\n          }\n        },\n        {\n          \"id\": \"201\",\n          \"label\": {\n            \"en\": \"Mild\",\n            \"nl\": \"Mild\",\n            \"da\": \"Mild\",\n            \"de\": \"Sanft\",\n            \"es\": \"Suave\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Lieve\",\n            \"no\": \"Mild\",\n            \"sv\": \"Mild\",\n            \"pl\": \"Łagodny\",\n            \"ru\": \"Низкая\",\n            \"ko\": \"약하게\"\n          }\n        },\n        {\n          \"id\": \"202\",\n          \"label\": {\n            \"en\": \"Moderate\",\n            \"nl\": \"Gemiddeld\",\n            \"da\": \"Moderat\",\n            \"de\": \"Mäßig\",\n            \"es\": \"Moderado\",\n            \"fr\": \"Modéré\",\n            \"it\": \"Moderato\",\n            \"no\": \"Moderat\",\n            \"sv\": \"Moderat\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средняя\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"203\",\n          \"label\": {\n            \"en\": \"Intense\",\n            \"nl\": \"Intens\",\n            \"da\": \"Intens\",\n            \"de\": \"Intensiv\",\n            \"es\": \"Intenso\",\n            \"fr\": \"Intense\",\n            \"it\": \"Intenso\",\n            \"no\": \"Intens\",\n            \"sv\": \"Intensiv\",\n            \"pl\": \"Intensywny\",\n            \"ru\": \"Высокая\",\n            \"ko\": \"강하게\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer stofzuiger\",\n        \"da\": \"Vælg støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccionar aspiradora\",\n        \"fr\": \"Sélectionnez l'aspirateur\",\n        \"it\": \"Seleziona l'aspirapolvere\",\n        \"no\": \"Velg støvsuger\",\n        \"sv\": \"Välj dammsugare\",\n        \"pl\": \"Wybierz odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"청소기 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced&capabilities=vacuum_roborock_mop_intensity\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/vacuumRoborockPause.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Pause cleaning\",\n    \"nl\": \"Schoonmaken pauzeren\",\n    \"da\": \"Pause rengøring\",\n    \"de\": \"Reinigung pausieren\",\n    \"es\": \"Pausar la limpieza\",\n    \"fr\": \"Mettre en pause le nettoyage\",\n    \"it\": \"Metti in pausa la pulizia\",\n    \"no\": \"Pause rengjøring\",\n    \"sv\": \"Pausa städningen\",\n    \"pl\": \"Wstrzymaj sprzątanie\",\n    \"ru\": \"Приостановить уборку\",\n    \"ko\": \"청소 일시중지\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer stofzuiger\",\n        \"da\": \"Vælg støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccionar aspiradora\",\n        \"fr\": \"Sélectionner l'aspirateur\",\n        \"it\": \"Selezionare l'aspirapolvere\",\n        \"no\": \"Velg støvsuger\",\n        \"sv\": \"Välj dammsugare\",\n        \"pl\": \"Wybierz odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"진공 청소기 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/vacuumRoidmiFanspeed.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set Fanspeed\",\n    \"nl\": \"Stel ventilator in\",\n    \"da\": \"Indstil blæserhastigheden\",\n    \"de\": \"Stelle die Lüftergeschwindigkeit ein\",\n    \"es\": \"Configurar la velocidad del ventilador\",\n    \"fr\": \"Ajuster la vitesse du ventilateur\",\n    \"it\": \"Regola la velocità della ventola\",\n    \"no\": \"Juster viftehastigheten\",\n    \"sv\": \"Justera fläkthastigheten\",\n    \"pl\": \"Ustaw prędkość wentylatora\",\n    \"ru\": \"Настройка скорости вентилятора\",\n    \"ko\": \"팬 속도 조정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set Fanspeed [[fanspeed]]\",\n    \"nl\": \"Stel ventilator in op [[fanspeed]]\",\n    \"da\": \"Indstil blæserhastigheden [[fanspeed]]\",\n    \"de\": \"Stelle die Lüftergeschwindigkeit ein [[fanspeed]]\",\n    \"es\": \"Configurar la velocidad del ventilador [[fanspeed]]\",\n    \"fr\": \"Ajuster la vitesse du ventilateur [[fanspeed]]\",\n    \"it\": \"Regola la velocità della ventola [[fanspeed]]\",\n    \"no\": \"Juster viftehastigheten [[fanspeed]]\",\n    \"sv\": \"Justera fläkthastigheten [[fanspeed]]\",\n    \"pl\": \"Ustaw prędkość wentylatora [[fanspeed]]\",\n    \"ru\": \"Настройка скорости вентилятора [[fanspeed]]\",\n    \"ko\": \"팬 속도 조정 [[fanspeed]]\"\n  },\n  \"args\": [\n    {\n      \"name\": \"fanspeed\",\n      \"title\": {\n        \"en\": \"Fanspeed\",\n        \"nl\": \"Fan snelheid\",\n        \"da\": \"Blæserhastighed\",\n        \"de\": \"Lüftergeschwindigkeit\",\n        \"es\": \"Velocidad del soplador\",\n        \"fr\": \"Vitesse du ventilateur\",\n        \"it\": \"Velocità del ventilatore\",\n        \"no\": \"Blæserhastighet\",\n        \"sv\": \"Fläkt hastighet\",\n        \"pl\": \"Prędkość wentylacji\",\n        \"ru\": \"Скорость вентиляции\",\n        \"ko\": \"팬 속도\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Sweep\",\n            \"nl\": \"Sweep\",\n            \"da\": \"Sweep\",\n            \"de\": \"Sweep\",\n            \"es\": \"Sweep\",\n            \"fr\": \"Sweep\",\n            \"it\": \"Sweep\",\n            \"no\": \"Sweep\",\n            \"sv\": \"Sweep\",\n            \"pl\": \"Sweep\",\n            \"ru\": \"Sweep\",\n            \"ko\": \"Sweep\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Silent\",\n            \"nl\": \"Stil\",\n            \"da\": \"Lydløs\",\n            \"de\": \"Geräuschlos\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"조용한\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Basic\",\n            \"nl\": \"Basis\",\n            \"da\": \"Basis\",\n            \"de\": \"Basis\",\n            \"es\": \"Base\",\n            \"fr\": \"Base\",\n            \"it\": \"Base\",\n            \"no\": \"Grunnleggende\",\n            \"sv\": \"Grundläggande\",\n            \"pl\": \"Podstawowy\",\n            \"ru\": \"Основной\",\n            \"ko\": \"기본\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Strong\",\n            \"nl\": \"Sterk\",\n            \"da\": \"Stærk\",\n            \"de\": \"Stark\",\n            \"es\": \"Fuerte\",\n            \"fr\": \"Fort\",\n            \"it\": \"Forte\",\n            \"no\": \"Sterk\",\n            \"sv\": \"Stark\",\n            \"pl\": \"Mocny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강한\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Full speed\",\n            \"nl\": \"Volle snelheid\",\n            \"da\": \"Fuld hastighed\",\n            \"de\": \"Vollgas\",\n            \"es\": \"Máxima velocidad\",\n            \"fr\": \"Vitesse maximale\",\n            \"it\": \"Velocità massima\",\n            \"no\": \"Fullt hastighet\",\n            \"sv\": \"Hastighet\",\n            \"pl\": \"Maksymalna prędkość\",\n            \"ru\": \"Максимальная скорость\",\n            \"ko\": \"최고 속도\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer stofzuiger\",\n        \"da\": \"Vælg støvsuger\",\n        \"de\": \"Wählen Sie den Staubsauger aus\",\n        \"es\": \"Seleccionar aspiradora\",\n        \"fr\": \"Choisissez le modèle d'aspirateur\",\n        \"it\": \"Seleziona il modello di aspirapolvere\",\n        \"no\": \"Velg støvsuger\",\n        \"sv\": \"Välj dammsugare\",\n        \"pl\": \"Wybierz odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"청소기 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_roidmi_vacuum_miot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/vacuumRoidmiMopMode.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set Sweep and Mop Mode\",\n    \"nl\": \"Stel Sweep and Mop modus in\",\n    \"da\": \"Indstil Sweep og Mop-tilstand\",\n    \"de\": \"Sweep und Mop Modus einstellen\",\n    \"es\": \"Configurar modo Barrer y Fregar\",\n    \"fr\": \"Définir le mode Balayage et Nettoyage\",\n    \"it\": \"Imposta modalità Spazza e Pulisci\",\n    \"no\": \"Angi Sweep og Mop-modus\",\n    \"sv\": \"Ställ in Sop- och Moppläge\",\n    \"pl\": \"Ustaw tryb Zamiatanie i Mopowanie\",\n    \"ru\": \"Установить режим Подметания и Мытья\",\n    \"ko\": \"청소 및 물걸레 모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set Sweep and Mop Mode to [[mode]]\",\n    \"nl\": \"Stel Sweep and Mop modus in op [[mode]]\",\n    \"da\": \"Indstil Sweep og Mop-tilstand til [[mode]]\",\n    \"de\": \"Sweep und Mop Modus auf [[mode]] einstellen\",\n    \"es\": \"Configurar modo Barrer y Fregar a [[mode]]\",\n    \"fr\": \"Définir le mode Balayage et Nettoyage sur [[mode]]\",\n    \"it\": \"Imposta la modalità Spazza e Pulisci su [[mode]]\",\n    \"no\": \"Angi Sweep og Mop-modus til [[mode]]\",\n    \"sv\": \"Ställ in Sop- och Moppläge till [[mode]]\",\n    \"pl\": \"Ustaw tryb Zamiatanie i Mopowanie na [[mode]]\",\n    \"ru\": \"Установить режим Подметания и Мытья на [[mode]]\",\n    \"ko\": \"청소 및 물걸레 모드를 [[mode]]로 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Sweep and Mop Mode\",\n        \"nl\": \"Sweep and Mop modus\",\n        \"da\": \"Sweep og Mop-tilstand\",\n        \"de\": \"Sweep und Mop Modus\",\n        \"es\": \"Modo Barrer y Fregar\",\n        \"fr\": \"Mode Balayage et Nettoyage\",\n        \"it\": \"Modalità Spazza e Pulisci\",\n        \"no\": \"Sweep og Mop-modus\",\n        \"sv\": \"Sop- och Moppläge\",\n        \"pl\": \"Tryb Zamiatanie i Mopowanie\",\n        \"ru\": \"Режим Подметания и Мытья\",\n        \"ko\": \"청소 및 물걸레 모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Sweep\",\n            \"nl\": \"Sweep\",\n            \"da\": \"Sweep\",\n            \"de\": \"Sweep\",\n            \"es\": \"Barrer\",\n            \"fr\": \"Balayer\",\n            \"it\": \"Spazza\",\n            \"no\": \"Sweep\",\n            \"sv\": \"Sweep\",\n            \"pl\": \"Zamiatanie\",\n            \"ru\": \"Подметание\",\n            \"ko\": \"청소\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Mop\",\n            \"nl\": \"Mop\",\n            \"da\": \"Mop\",\n            \"de\": \"Mop\",\n            \"es\": \"Fregar\",\n            \"fr\": \"Nettoyer\",\n            \"it\": \"Pulisci\",\n            \"no\": \"Mop\",\n            \"sv\": \"Mop\",\n            \"pl\": \"Mopowanie\",\n            \"ru\": \"Мытьё\",\n            \"ko\": \"물걸레\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Mop & Sweep\",\n            \"nl\": \"Mop & Sweep\",\n            \"da\": \"Mop & Sweep\",\n            \"de\": \"Mop & Sweep\",\n            \"es\": \"Fregar y Barrer\",\n            \"fr\": \"Nettoyer et Balayer\",\n            \"it\": \"Pulisci & Spazza\",\n            \"no\": \"Mop & Sweep\",\n            \"sv\": \"Mop & Sweep\",\n            \"pl\": \"Mopowanie i Zamiatanie\",\n            \"ru\": \"Мытьё и Подметание\",\n            \"ko\": \"청소 및 물걸레\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer stofzuiger\",\n        \"da\": \"Vælg støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccionar aspiradora\",\n        \"fr\": \"Sélectionner l'aspirateur\",\n        \"it\": \"Seleziona aspirapolvere\",\n        \"no\": \"Velg støvsuger\",\n        \"sv\": \"Välj dammsugare\",\n        \"pl\": \"Wybierz odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"진공 청소기 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_roidmi_vacuum_miot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/vacuumRoomCleaning.json",
    "content": "{\n  \"id\": \"vacuumRoomCleaning\",\n  \"title\": {\n    \"en\": \"Start room cleaning\",\n    \"nl\": \"Start kamer stofzuigen\",\n    \"da\": \"Start rengøring af rum\",\n    \"de\": \"Raumreinigung starten\",\n    \"es\": \"Iniciar limpieza de habitación\",\n    \"fr\": \"Commencer le nettoyage de la pièce\",\n    \"it\": \"Inizia la pulizia della stanza\",\n    \"no\": \"Start romrensingen\",\n    \"sv\": \"Starta rumsstädning\",\n    \"pl\": \"Rozpocznij sprzątanie pokoju\",\n    \"ru\": \"Начать уборку комнаты\",\n    \"ko\": \"방 청소 시작\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Send vacuum cleaner to clean room [[rooms]]\",\n    \"nl\": \"Stuur stofzuiger naar kamer [[rooms]]\",\n    \"da\": \"Send støvsugeren til at rengøre rum [[rooms]]\",\n    \"de\": \"Schicke Staubsauger zur Reinigung von Raum [[rooms]]\",\n    \"es\": \"Enviar aspiradora a limpiar habitación [[rooms]]\",\n    \"fr\": \"Envoyez l'aspirateur nettoyer la pièce [[rooms]]\",\n    \"it\": \"Invia l'aspirapolvere per pulire la stanza [[rooms]]\",\n    \"no\": \"Send støvsugeren for å rengjøre rom [[rooms]]\",\n    \"sv\": \"Skicka dammsugaren för att rengöra rummet [[rooms]]\",\n    \"pl\": \"Wyślij odkurzacz do sprzątania pokoju [[rooms]]\",\n    \"ru\": \"Отправить пылесос для уборки комнаты [[rooms]]\",\n    \"ko\": \"[[rooms]] 방 청소를 위해 진공 청소기를 보내세요\"\n  },\n  \"hint\": {\n    \"en\": \"Enter the room ID's (comma seperated)\",\n    \"nl\": \"Voer kamer ID's in (gescheiden door een komma)\",\n    \"da\": \"Indtast rum-ID'er (kommasepareret)\",\n    \"de\": \"Geben Sie die Raum-IDs ein (kommasepariert)\",\n    \"es\": \"Ingrese las IDs de las habitaciones (separadas por comas)\",\n    \"fr\": \"Entrez les ID des pièces (séparés par des virgules)\",\n    \"it\": \"Inserisci gli ID delle stanze (separati da virgole)\",\n    \"no\": \"Skriv inn rom-ID-er (kommaseparert)\",\n    \"sv\": \"Ange rums-ID:n (kommaseparerade)\",\n    \"pl\": \"Wprowadź identyfikatory pokoi (oddzielone przecinkami)\",\n    \"ru\": \"Введите ID комнат (через запятую)\",\n    \"ko\": \"방 ID를 입력하세요 (쉼표로 구분)\"\n  },\n  \"args\": [\n    {\n      \"name\": \"rooms\",\n      \"title\": {\n        \"en\": \"Room(s)\",\n        \"nl\": \"Kamer(s)\",\n        \"da\": \"Rum\",\n        \"de\": \"Raum/Räume\",\n        \"es\": \"Habitación(es)\",\n        \"fr\": \"Pièce(s)\",\n        \"it\": \"Stanza/e\",\n        \"no\": \"Rom\",\n        \"sv\": \"Rum\",\n        \"pl\": \"Pokój/e\",\n        \"ru\": \"Комната/ы\",\n        \"ko\": \"방\"\n      },\n      \"type\": \"text\",\n      \"placeholder\": {\n        \"en\": \"Room(s)\",\n        \"nl\": \"Kamer(s)\",\n        \"da\": \"Rum\",\n        \"de\": \"Raum/Räume\",\n        \"es\": \"Habitación(es)\",\n        \"fr\": \"Pièce(s)\",\n        \"it\": \"Stanza/e\",\n        \"no\": \"Rom\",\n        \"sv\": \"Rum\",\n        \"pl\": \"Pokój/e\",\n        \"ru\": \"Комната/ы\",\n        \"ko\": \"방\"\n      }\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer stofzuiger\",\n        \"da\": \"Vælg støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccionar aspiradora\",\n        \"fr\": \"Sélectionner l'aspirateur\",\n        \"it\": \"Seleziona l'aspirapolvere\",\n        \"no\": \"Velg støvsuger\",\n        \"sv\": \"Välj dammsugare\",\n        \"pl\": \"Wybierz odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"진공 청소기 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced|vacuum_dreame_vacuum\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/vacuumRoomCleaningRepeats.json",
    "content": "{\n  \"id\": \"vacuumRoomCleaningRepeats\",\n  \"title\": {\n    \"en\": \"Start repeated room cleaning\",\n    \"nl\": \"Start herhaald kamer stofzuigen\",\n    \"da\": \"Start gentagne rum rengøring\",\n    \"de\": \"Beginne wiederholte Raumreinigung\",\n    \"es\": \"Iniciar limpieza repetida de habitaciones\",\n    \"fr\": \"Commencer le nettoyage répété de la pièce\",\n    \"it\": \"Inizia la pulizia ripetuta della stanza\",\n    \"no\": \"Start gjentatt romrengjøring\",\n    \"sv\": \"Start upprepad rumstädning\",\n    \"pl\": \"Rozpocznij powtarzane sprzątanie pokoju\",\n    \"ru\": \"Начать повторяющуюся уборку комнаты\",\n    \"ko\": \"반복 방 청소 시작\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Send vacuum cleaner to clean room [[rooms]] and repeat [[repeats]] times\",\n    \"nl\": \"Stuur stofzuiger naar kamer [[rooms]] en herhaal [[repeats]] keer\",\n    \"da\": \"Send støvsuger til at rengøre rum [[rooms]] og gentag [[repeats]] gange\",\n    \"de\": \"Schicke Staubsauger, um Raum [[rooms]] zu reinigen und [[repeats]] mal zu wiederholen\",\n    \"es\": \"Enviar aspiradora para limpiar la habitación [[rooms]] y repetir [[repeats]] veces\",\n    \"fr\": \"Envoyer l'aspirateur pour nettoyer la pièce [[rooms]] et répéter [[repeats]] fois\",\n    \"it\": \"Invia l'aspirapolvere a pulire la stanza [[rooms]] e ripeti [[repeats]] volte\",\n    \"no\": \"Send støvsuger for å rengjøre rommet [[rooms]] og gjenta [[repeats]] ganger\",\n    \"sv\": \"Skicka dammsugare för att städa rum [[rooms]] och upprepa [[repeats]] gånger\",\n    \"pl\": \"Wyślij odkurzacz, aby posprzątał pokój [[rooms]] i powtórz [[repeats]] razy\",\n    \"ru\": \"Отправить пылесос для уборки комнаты [[rooms]] и повторить [[repeats]] раз\",\n    \"ko\": \"방 [[rooms]]을 청소하도록 청소기를 보내고 [[repeats]]번 반복\"\n  },\n  \"hint\": {\n    \"en\": \"Enter the room ID's (comma seperated)\",\n    \"nl\": \"Voer kamer ID's in (gescheiden door een komma)\",\n    \"da\": \"Indtast rum ID'erne (kommasepareret)\",\n    \"de\": \"Geben Sie die Raum-IDs ein (durch Kommas getrennt)\",\n    \"es\": \"Ingrese los ID de las habitaciones (separados por comas)\",\n    \"fr\": \"Entrez les ID des pièces (séparés par des virgules)\",\n    \"it\": \"Inserisci gli ID delle stanze (separati da virgole)\",\n    \"no\": \"Skriv inn rom-ID-er (kommaseparert)\",\n    \"sv\": \"Ange rums-ID:n (kommaseparerade)\",\n    \"pl\": \"Wprowadź identyfikatory pokoi (oddzielone przecinkami)\",\n    \"ru\": \"Введите идентификаторы комнат (через запятую)\",\n    \"ko\": \"방 ID 입력(쉼표로 구분)\"\n  },\n  \"args\": [\n    {\n      \"name\": \"rooms\",\n      \"title\": {\n        \"en\": \"Room(s)\",\n        \"nl\": \"Kamer(s)\",\n        \"da\": \"Rum\",\n        \"de\": \"Raum/Räume\",\n        \"es\": \"Habitación(es)\",\n        \"fr\": \"Pièce(s)\",\n        \"it\": \"Stanza/e\",\n        \"no\": \"Rom\",\n        \"sv\": \"Rum\",\n        \"pl\": \"Pokój(e)\",\n        \"ru\": \"Комната(ы)\",\n        \"ko\": \"방\"\n      },\n      \"type\": \"text\",\n      \"placeholder\": {\n        \"en\": \"Room(s)\",\n        \"nl\": \"Kamer(s)\",\n        \"da\": \"Rum\",\n        \"de\": \"Raum/Räume\",\n        \"es\": \"Habitación(es)\",\n        \"fr\": \"Pièce(s)\",\n        \"it\": \"Stanza/e\",\n        \"no\": \"Rom\",\n        \"sv\": \"Rum\",\n        \"pl\": \"Pokój(e)\",\n        \"ru\": \"Комната(ы)\",\n        \"ko\": \"방\"\n      }\n    },\n    {\n      \"name\": \"repeats\",\n      \"title\": {\n        \"en\": \"Repeat\",\n        \"nl\": \"Herhaal\",\n        \"da\": \"Gentag\",\n        \"de\": \"Wiederholen\",\n        \"es\": \"Repetir\",\n        \"fr\": \"Répéter\",\n        \"it\": \"Ripeti\",\n        \"no\": \"Gjenta\",\n        \"sv\": \"Upprepa\",\n        \"pl\": \"Powtórz\",\n        \"ru\": \"Повторить\",\n        \"ko\": \"반복\"\n      },\n      \"type\": \"number\",\n      \"min\": 1,\n      \"max\": 3,\n      \"step\": 1\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer stofzuiger\",\n        \"da\": \"Vælg støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccione aspiradora\",\n        \"fr\": \"Sélectionnez l'aspirateur\",\n        \"it\": \"Seleziona l'aspirapolvere\",\n        \"no\": \"Velg støvsuger\",\n        \"sv\": \"Välj dammsugare\",\n        \"pl\": \"Wybierz odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"청소기 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/actions/vacuumXiaomiMopMode.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Set Sweep and Mop Mode\",\n    \"nl\": \"Stel Sweep and Mop modus in\",\n    \"da\": \"Indstil Sweep og Mop-tilstand\",\n    \"de\": \"Sweep- und Mop-Modus einstellen\",\n    \"es\": \"Establecer modo Sweep y Mop\",\n    \"fr\": \"Définir le mode Sweep et Mop\",\n    \"it\": \"Imposta modalità Sweep e Mop\",\n    \"no\": \"Sett Sweep og Mop-modus\",\n    \"sv\": \"Ställ in Sweep och Mop-läge\",\n    \"pl\": \"Ustaw tryb Sweep i Mop\",\n    \"ru\": \"Установите режим Sweep и Mop\",\n    \"ko\": \"쓸기 및 물걸레 모드 설정\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Set Sweep and Mop Mode to [[mode]]\",\n    \"nl\": \"Stel Sweep and Mop modus in op [[mode]]\",\n    \"da\": \"Indstil Sweep og Mop-tilstand til [[mode]]\",\n    \"de\": \"Sweep- und Mop-Modus auf [[mode]] einstellen\",\n    \"es\": \"Establecer modo Sweep y Mop a [[mode]]\",\n    \"fr\": \"Définir le mode Sweep et Mop sur [[mode]]\",\n    \"it\": \"Imposta modalità Sweep e Mop su [[mode]]\",\n    \"no\": \"Sett Sweep og Mop-modus til [[mode]]\",\n    \"sv\": \"Ställ in Sweep och Mop-läge till [[mode]]\",\n    \"pl\": \"Ustaw tryb Sweep i Mop na [[mode]]\",\n    \"ru\": \"Установите режим Sweep и Mop на [[mode]]\",\n    \"ko\": \"[[mode]]로 쓸기 및 물걸레 모드 설정\"\n  },\n  \"args\": [\n    {\n      \"name\": \"mode\",\n      \"title\": {\n        \"en\": \"Sweep and Mop Mode\",\n        \"nl\": \"Sweep and Mop modus\",\n        \"da\": \"Sweep og Mop-tilstand\",\n        \"de\": \"Sweep- und Mop-Modus\",\n        \"es\": \"Modo Sweep y Mop\",\n        \"fr\": \"Mode Sweep et Mop\",\n        \"it\": \"Modalità Sweep e Mop\",\n        \"no\": \"Sweep og Mop-modus\",\n        \"sv\": \"Sweep och Mop-läge\",\n        \"pl\": \"Tryb Sweep i Mop\",\n        \"ru\": \"Режим Sweep и Mop\",\n        \"ko\": \"쓸기 및 물걸레 모드\"\n      },\n      \"type\": \"dropdown\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Sweep\",\n            \"nl\": \"Sweep\",\n            \"da\": \"Sweep\",\n            \"de\": \"Sweep\",\n            \"es\": \"Sweep\",\n            \"fr\": \"Sweep\",\n            \"it\": \"Sweep\",\n            \"no\": \"Sweep\",\n            \"sv\": \"Sweep\",\n            \"pl\": \"Sweep\",\n            \"ru\": \"Sweep\",\n            \"ko\": \"쓸기\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Sweep & Mop\",\n            \"nl\": \"Sweep & Mop\",\n            \"da\": \"Sweep & Mop\",\n            \"de\": \"Sweep & Mop\",\n            \"es\": \"Sweep & Mop\",\n            \"fr\": \"Sweep & Mop\",\n            \"it\": \"Sweep & Mop\",\n            \"no\": \"Sweep & Mop\",\n            \"sv\": \"Sweep & Mop\",\n            \"pl\": \"Sweep & Mop\",\n            \"ru\": \"Sweep & Mop\",\n            \"ko\": \"쓸기 & 물걸레\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Mop\",\n            \"nl\": \"Mop\",\n            \"da\": \"Mop\",\n            \"de\": \"Mop\",\n            \"es\": \"Mop\",\n            \"fr\": \"Mop\",\n            \"it\": \"Mop\",\n            \"no\": \"Mop\",\n            \"sv\": \"Mop\",\n            \"pl\": \"Mop\",\n            \"ru\": \"Mop\",\n            \"ko\": \"물걸레\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer stofzuiger\",\n        \"da\": \"Vælg støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccionar aspiradora\",\n        \"fr\": \"Sélectionner un aspirateur\",\n        \"it\": \"Seleziona l'aspirapolvere\",\n        \"no\": \"Velg støvsuger\",\n        \"sv\": \"Välj dammsugare\",\n        \"pl\": \"Wybierz odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"진공청소기 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_xiaomi_vacuum_miot\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/conditions/leftSwitch.json",
    "content": "{\n  \"id\": \"leftSwitch\",\n  \"title\": {\n    \"en\": \"Left switch !{{on|off}}\",\n    \"nl\": \"Linkerschakelaar !{{aan|uit}}\",\n    \"da\": \"Venstre switch !{{on|off}}\",\n    \"de\": \"Linker Schalter !{{on|off}}\",\n    \"es\": \"Interruptor izquierdo !{{on|off}}\",\n    \"fr\": \"Interrupteur gauche !{{on|off}}\",\n    \"it\": \"Interruttore sinistro !{{on|off}}\",\n    \"no\": \"Venstre bryter !{{on|off}}\",\n    \"sv\": \"Vänster switch !{{on|off}}\",\n    \"pl\": \"Lewy przełącznik !{{on|off}}\",\n    \"ru\": \"Левый переключатель !{{on|off}}\",\n    \"ko\": \"왼쪽 스위치 !{{on|off}}\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Selecciona dispositivo\",\n        \"fr\": \"Sélectionnez l'appareil\",\n        \"it\": \"Seleziona il dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/conditions/measure_humidity_between.json",
    "content": "{\n  \"id\": \"measure_humidity_between\",\n  \"title\": {\n    \"en\": \"Humidity !{{is between|is not between}}\",\n    \"nl\": \"Luchtvochtigheid !{{ligt tussen|ligt niet tussen}}\",\n    \"da\": \"Fugtighed !{{er mellem|er ikke mellem}}\",\n    \"de\": \"Feuchtigkeit !{{liegt zwischen|liegt nicht zwischen}}\",\n    \"es\": \"Humedad !{{está entre|no está entre}}\",\n    \"fr\": \"Humidité !{{est entre|n'est pas entre}}\",\n    \"it\": \"Umidità !{{è tra|non è tra}}\",\n    \"no\": \"Fuktighet !{{er mellom|er ikke mellom}}\",\n    \"sv\": \"Fuktighet !{{är mellan|är inte mellan}}\",\n    \"pl\": \"Wilgotność !{{jest między|nie jest między}}\",\n    \"ru\": \"Влажность !{{между|не между}}\",\n    \"ko\": \"습도 !{{사이에 있음|사이에 없음}}\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Humidity !{{is between|is not between}} [[value1]] and [[value2]]\",\n    \"nl\": \"Luchtvochtigheid !{{ligt tussen|ligt niet tussen}} [[value1]] en [[value2]]\",\n    \"da\": \"Fugtighed !{{er mellem|er ikke mellem}} [[value1]] og [[value2]]\",\n    \"de\": \"Feuchtigkeit !{{liegt zwischen|liegt nicht zwischen}} [[value1]] und [[value2]]\",\n    \"es\": \"Humedad !{{está entre|no está entre}} [[value1]] y [[value2]]\",\n    \"fr\": \"Humidité !{{est entre|n'est pas entre}} [[value1]] et [[value2]]\",\n    \"it\": \"Umidità !{{è tra|non è tra}} [[value1]] e [[value2]]\",\n    \"no\": \"Fuktighet !{{er mellom|er ikke mellom}} [[value1]] og [[value2]]\",\n    \"sv\": \"Fuktighet !{{är mellan|är inte mellan}} [[value1]] och [[value2]]\",\n    \"pl\": \"Wilgotność !{{jest między|nie jest między}} [[value1]] i [[value2]]\",\n    \"ru\": \"Влажность !{{между|не между}} [[value1]] и [[value2]]\",\n    \"ko\": \"습도 !{{사이에 있음|사이에 없음}} [[value1]] 과 [[value2]]\"\n  },\n  \"hint\": {\n    \"en\": \"Use this card to determine whether or not the humidity for the zone is between two values. The specified values are also valid.\",\n    \"nl\": \"Gebruik dit kaartje om te bepalen of de luchtvochtigheid voor de zone tussen twee waarden ligt. De opgegeven waarden zijn ook geldig.\",\n    \"da\": \"Brug dette kort til at afgøre, om fugtigheden i zonen er mellem to værdier. De angivne værdier er også gyldige.\",\n    \"de\": \"Verwenden Sie diese Karte, um festzustellen, ob die Feuchtigkeit in der Zone zwischen zwei Werten liegt. Die angegebenen Werte sind ebenfalls gültig.\",\n    \"es\": \"Utilice esta tarjeta para determinar si la humedad de la zona está entre dos valores. Los valores especificados también son válidos.\",\n    \"fr\": \"Utilisez cette carte pour déterminer si l'humidité de la zone est entre deux valeurs. Les valeurs spécifiées sont également valides.\",\n    \"it\": \"Usa questa scheda per determinare se l'umidità della zona è tra due valori. Anche i valori specificati sono validi.\",\n    \"no\": \"Bruk dette kortet for å avgjøre om fuktigheten for sonen er mellom to verdier. De spesifiserte verdiene er også gyldige.\",\n    \"sv\": \"Använd detta kort för att avgöra om fuktigheten för zonen är mellan två värden. De angivna värdena är också giltiga.\",\n    \"pl\": \"Użyj tej karty, aby sprawdzić, czy wilgotność w strefie mieści się między dwiema wartościami. Podane wartości są również ważne.\",\n    \"ru\": \"Используйте эту карту, чтобы определить, находится ли влажность в зоне между двумя значениями. Указанные значения также действительны.\",\n    \"ko\": \"이 카드를 사용하여 구역의 습도가 두 값 사이에 있는지 여부를 결정하세요. 지정된 값도 유효합니다.\"\n  },\n  \"args\": [\n    {\n      \"type\": \"number\",\n      \"name\": \"value1\",\n      \"min\": 0,\n      \"max\": 100,\n      \"step\": 1,\n      \"title\": {\n        \"en\": \"Above\",\n        \"nl\": \"Boven\",\n        \"da\": \"Over\",\n        \"de\": \"Über\",\n        \"es\": \"Por encima de\",\n        \"fr\": \"Au dessus de\",\n        \"it\": \"Sopra\",\n        \"no\": \"Over\",\n        \"sv\": \"Över\",\n        \"pl\": \"Powyżej\",\n        \"ru\": \"Над\",\n        \"ko\": \"이상\"\n      },\n      \"placeholder\": {\n        \"en\": \"%\",\n        \"nl\": \"%\",\n        \"da\": \"%\",\n        \"de\": \"%\",\n        \"es\": \"%\",\n        \"fr\": \"%\",\n        \"it\": \"%\",\n        \"no\": \"%\",\n        \"sv\": \"%\",\n        \"pl\": \"%\",\n        \"ru\": \"%\",\n        \"ko\": \"%\"\n      }\n    },\n    {\n      \"type\": \"number\",\n      \"name\": \"value2\",\n      \"min\": 0,\n      \"max\": 100,\n      \"step\": 1,\n      \"title\": {\n        \"en\": \"Below\",\n        \"nl\": \"Onder\",\n        \"da\": \"Under\",\n        \"de\": \"Unter\",\n        \"es\": \"Por debajo de\",\n        \"fr\": \"En dessous de\",\n        \"it\": \"Sotto\",\n        \"no\": \"Under\",\n        \"sv\": \"Under\",\n        \"pl\": \"Poniżej\",\n        \"ru\": \"Под\",\n        \"ko\": \"이하\"\n      },\n      \"placeholder\": {\n        \"en\": \"%\",\n        \"nl\": \"%\",\n        \"da\": \"%\",\n        \"de\": \"%\",\n        \"es\": \"%\",\n        \"fr\": \"%\",\n        \"it\": \"%\",\n        \"no\": \"%\",\n        \"sv\": \"%\",\n        \"pl\": \"%\",\n        \"ru\": \"%\",\n        \"ko\": \"%\"\n      }\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-temperature-humidity-sensor|aqara-temperature-humidity-sensor\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/conditions/measure_temperature_between.json",
    "content": "{\n  \"id\": \"measure_temperature_between\",\n  \"title\": {\n    \"en\": \"Temperature !{{is between|is not between}}\",\n    \"nl\": \"Temperatuur !{{ligt tussen|ligt niet tussen}}\",\n    \"da\": \"Temperatur !{{er mellem|er ikke mellem}}\",\n    \"de\": \"Temperatur !{{liegt zwischen|liegt nicht zwischen}}\",\n    \"es\": \"Temperatura !{{está entre|no está entre}}\",\n    \"fr\": \"Température !{{est entre|n'est pas entre}}\",\n    \"it\": \"Temperatura !{{è tra|non è tra}}\",\n    \"no\": \"Temperatur !{{er mellom|er ikke mellom}}\",\n    \"sv\": \"Temperatur !{{är mellan|är inte mellan}}\",\n    \"pl\": \"Temperatura !{{jest między|nie jest między}}\",\n    \"ru\": \"Температура !{{между|не между}}\",\n    \"ko\": \"온도 !{{사이에 있음|사이에 없음}}\"\n  },\n  \"titleFormatted\": {\n    \"en\": \"Temperature !{{is between|is not between}} [[value1]] and [[value2]]\",\n    \"nl\": \"Temperatuur !{{ligt tussen|ligt niet tussen}} [[value1]] en [[value2]]\",\n    \"da\": \"Temperatur !{{er mellem|er ikke mellem}} [[value1]] og [[value2]]\",\n    \"de\": \"Temperatur !{{liegt zwischen|liegt nicht zwischen}} [[value1]] und [[value2]]\",\n    \"es\": \"Temperatura !{{está entre|no está entre}} [[value1]] y [[value2]]\",\n    \"fr\": \"Température !{{est entre|n'est pas entre}} [[value1]] et [[value2]]\",\n    \"it\": \"Temperatura !{{è tra|non è tra}} [[value1]] e [[value2]]\",\n    \"no\": \"Temperatur !{{er mellom|er ikke mellom}} [[value1]] og [[value2]]\",\n    \"sv\": \"Temperatur !{{är mellan|är inte mellan}} [[value1]] och [[value2]]\",\n    \"pl\": \"Temperatura !{{jest między|nie jest między}} [[value1]] i [[value2]]\",\n    \"ru\": \"Температура !{{между|не между}} [[value1]] и [[value2]]\",\n    \"ko\": \"온도 !{{사이에 있음|사이에 없음}} [[value1]]와 [[value2]] 사이\"\n  },\n  \"hint\": {\n    \"en\": \"Use this card to determine whether or not the zone temperature is between two values. The specified values are also valid.\",\n    \"nl\": \"Gebruik dit kaartje om te bepalen of de zone temperatuur tussen twee waarden ligt. De opgegeven waarden zijn ook geldig.\",\n    \"da\": \"Brug dette kort til at bestemme, om zonens temperatur er mellem to værdier. De angivne værdier er også gyldige.\",\n    \"de\": \"Verwenden Sie diese Karte, um festzustellen, ob die Zonentemperatur zwischen zwei Werten liegt. Die angegebenen Werte sind ebenfalls gültig.\",\n    \"es\": \"Usa esta tarjeta para determinar si la temperatura de la zona está entre dos valores. Los valores especificados también son válidos.\",\n    \"fr\": \"Utilisez cette carte pour déterminer si la température de la zone est comprise entre deux valeurs. Les valeurs spécifiées sont également valables.\",\n    \"it\": \"Usa questa scheda per determinare se la temperatura della zona è compresa tra due valori. Anche i valori specificati sono validi.\",\n    \"no\": \"Bruk dette kortet for å bestemme om sone-temperaturen er mellom to verdier. De spesifiserte verdiene er også gyldige.\",\n    \"sv\": \"Använd detta kort för att avgöra om zonens temperatur är mellan två värden. De specificerade värdena är också giltiga.\",\n    \"pl\": \"Użyj tej karty, aby określić, czy temperatura strefy mieści się pomiędzy dwoma wartościami. Podane wartości są również ważne.\",\n    \"ru\": \"Используйте эту карту, чтобы определить, находится ли температура в зоне между двумя значениями. Указанные значения также действительны.\",\n    \"ko\": \"이 카드를 사용하여 구역 온도가 두 값 사이에 있는지 여부를 결정하세요. 지정된 값도 유효합니다.\"\n  },\n  \"args\": [\n    {\n      \"type\": \"number\",\n      \"name\": \"value1\",\n      \"min\": -50,\n      \"max\": 100,\n      \"step\": 1,\n      \"title\": {\n        \"en\": \"Above\",\n        \"nl\": \"Boven\",\n        \"da\": \"Over\",\n        \"de\": \"Über\",\n        \"es\": \"Por encima\",\n        \"fr\": \"Au-dessus\",\n        \"it\": \"Sopra\",\n        \"no\": \"Over\",\n        \"sv\": \"Över\",\n        \"pl\": \"Powyżej\",\n        \"ru\": \"Выше\",\n        \"ko\": \"위\"\n      },\n      \"placeholder\": {\n        \"en\": \"°C\",\n        \"nl\": \"°C\",\n        \"da\": \"°C\",\n        \"de\": \"°C\",\n        \"es\": \"°C\",\n        \"fr\": \"°C\",\n        \"it\": \"°C\",\n        \"no\": \"°C\",\n        \"sv\": \"°C\",\n        \"pl\": \"°C\",\n        \"ru\": \"°C\",\n        \"ko\": \"°C\"\n      }\n    },\n    {\n      \"type\": \"number\",\n      \"name\": \"value2\",\n      \"min\": -50,\n      \"max\": 100,\n      \"step\": 1,\n      \"title\": {\n        \"en\": \"Below\",\n        \"nl\": \"Onder\",\n        \"da\": \"Under\",\n        \"de\": \"Unter\",\n        \"es\": \"Por debajo\",\n        \"fr\": \"En dessous\",\n        \"it\": \"Sotto\",\n        \"no\": \"Under\",\n        \"sv\": \"Under\",\n        \"pl\": \"Poniżej\",\n        \"ru\": \"Ниже\",\n        \"ko\": \"아래\"\n      },\n      \"placeholder\": {\n        \"en\": \"°C\",\n        \"nl\": \"°C\",\n        \"da\": \"°C\",\n        \"de\": \"°C\",\n        \"es\": \"°C\",\n        \"fr\": \"°C\",\n        \"it\": \"°C\",\n        \"no\": \"°C\",\n        \"sv\": \"°C\",\n        \"pl\": \"°C\",\n        \"ru\": \"°C\",\n        \"ko\": \"°C\"\n      }\n    },\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-temperature-humidity-sensor|aqara-temperature-humidity-sensor\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/conditions/rightSwitch.json",
    "content": "{\n  \"id\": \"rightSwitch\",\n  \"title\": {\n    \"en\": \"Right switch !{{on|off}}\",\n    \"nl\": \"Rechterschakelaar !{{aan|uit}}\",\n    \"da\": \"Højre switch !{{til|fra}}\",\n    \"de\": \"Rechter Schalter !{{an|aus}}\",\n    \"es\": \"Interruptor derecho !{{encendido|apagado}}\",\n    \"fr\": \"Interrupteur droit !{{allumé|éteint}}\",\n    \"it\": \"Interruttore destro !{{acceso|spento}}\",\n    \"no\": \"Høyre bryter !{{på|av}}\",\n    \"sv\": \"Höger strömbrytare !{{på|av}}\",\n    \"pl\": \"Prawy przełącznik !{{włączone|wyłączone}}\",\n    \"ru\": \"Правый переключатель !{{включено|выключено}}\",\n    \"ko\": \"오른쪽 스위치 !{{켜짐|꺼짐}}\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/alertVacuum.json",
    "content": "{\n  \"id\": \"alertVacuum\",\n  \"title\": {\n    \"en\": \"Consumable Alert\",\n    \"nl\": \"Verbruiksartikel waarschuwing\",\n    \"da\": \"Forbrugsalarm\",\n    \"de\": \"Verbrauchsmaterial-Warnung\",\n    \"es\": \"Alerta de consumibles\",\n    \"fr\": \"Alerte de consommable\",\n    \"it\": \"Allarme consumabile\",\n    \"no\": \"Forbruksvarsel\",\n    \"sv\": \"Förbrukningsalarm\",\n    \"pl\": \"Alert materiałów eksploatacyjnych\",\n    \"ru\": \"Оповещение о расходных материалах\",\n    \"ko\": \"소모품 경고\"\n  },\n  \"tokens\": [\n    {\n      \"name\": \"consumable\",\n      \"type\": \"string\",\n      \"title\": {\n        \"en\": \"consumable\",\n        \"nl\": \"verbruiksartikel\",\n        \"da\": \"forbrugbar\",\n        \"de\": \"Verbrauchsmaterial\",\n        \"es\": \"consumible\",\n        \"fr\": \"consommable\",\n        \"it\": \"consumabile\",\n        \"no\": \"forbrukbar\",\n        \"sv\": \"förbrukningsvara\",\n        \"pl\": \"materiał eksploatacyjny\",\n        \"ru\": \"расходный материал\",\n        \"ko\": \"소모품\"\n      },\n      \"example\": \"filter\"\n    },\n    {\n      \"name\": \"value\",\n      \"type\": \"string\",\n      \"title\": {\n        \"en\": \"value\",\n        \"nl\": \"waarde\",\n        \"da\": \"værdi\",\n        \"de\": \"Wert\",\n        \"es\": \"valor\",\n        \"fr\": \"valeur\",\n        \"it\": \"valore\",\n        \"no\": \"verdi\",\n        \"sv\": \"värde\",\n        \"pl\": \"wartość\",\n        \"ru\": \"значение\",\n        \"ko\": \"값\"\n      },\n      \"example\": \"10%\"\n    }\n  ],\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Vacuum\",\n        \"nl\": \"Selecteer stofzuiger\",\n        \"da\": \"Vælg støvsuger\",\n        \"de\": \"Staubsauger auswählen\",\n        \"es\": \"Seleccionar aspiradora\",\n        \"fr\": \"Sélectionner l'aspirateur\",\n        \"it\": \"Selezionare aspirapolvere\",\n        \"no\": \"Velg støvsuger\",\n        \"sv\": \"Välj dammsugare\",\n        \"pl\": \"Wybierz odkurzacz\",\n        \"ru\": \"Выберите пылесос\",\n        \"ko\": \"진공청소기 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced|vacuum_dreame_vacuum|vacuum_viomi_vacuum_v7|vacuum_mija_vacuum_miot|vacuum_roidmi_vacuum_miot|vacuum_xiaomi_vacuum_max\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/triggers/alert_cube.json",
    "content": "{\n  \"id\": \"alert_cube\",\n  \"title\": {\n    \"en\": \"Alert\",\n    \"nl\": \"Waarschuwing\",\n    \"da\": \"Alarm\",\n    \"de\": \"Alarm\",\n    \"es\": \"Alerta\",\n    \"fr\": \"Alerte\",\n    \"it\": \"Allarme\",\n    \"no\": \"Varsel\",\n    \"sv\": \"Varning\",\n    \"pl\": \"Alarm\",\n    \"ru\": \"Оповещение\",\n    \"ko\": \"경고\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionnez l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-aqara-cube\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/click_double.json",
    "content": "{\n  \"id\": \"click_double\",\n  \"title\": {\n    \"en\": \"Double Click\",\n    \"nl\": \"Dubbelklik\",\n    \"da\": \"Dobbeltklik\",\n    \"de\": \"Doppelklick\",\n    \"es\": \"Doble clic\",\n    \"fr\": \"Double-clic\",\n    \"it\": \"Doppio clic\",\n    \"no\": \"Dobbeltklikk\",\n    \"sv\": \"Dubbelklick\",\n    \"pl\": \"Podwójne kliknięcie\",\n    \"ru\": \"Двойной щелчок\",\n    \"ko\": \"더블 클릭\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-button|aqara-button|aqara-button-advanced|aqara-86sw1-advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/click_double_left.json",
    "content": "{\n  \"id\": \"click_double_left\",\n  \"title\": {\n    \"en\": \"Left Double Click\",\n    \"nl\": \"Dubbel klik links\",\n    \"da\": \"Dobbeltklik til venstre\",\n    \"de\": \"Doppelklick links\",\n    \"es\": \"Doble clic izquierdo\",\n    \"fr\": \"Double clic gauche\",\n    \"it\": \"Doppio clic sinistro\",\n    \"no\": \"Dobbeltklikk venstre\",\n    \"sv\": \"Dubbelklick vänster\",\n    \"pl\": \"Podwójne kliknięcie lewym\",\n    \"ru\": \"Двойной клик левой кнопкой\",\n    \"ko\": \"왼쪽 더블 클릭\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Selecciona dispositivo\",\n        \"fr\": \"Sélectionner le périphérique\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-86sw2-advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/click_double_right.json",
    "content": "{\n  \"id\": \"click_double_right\",\n  \"title\": {\n    \"en\": \"Right Double Click\",\n    \"nl\": \"Dubbel klik rechts\",\n    \"da\": \"Højre Dobbeltklik\",\n    \"de\": \"Rechts Doppelklick\",\n    \"es\": \"Doble Clic Derecho\",\n    \"fr\": \"Double Clic Droit\",\n    \"it\": \"Doppio Clic Destro\",\n    \"no\": \"Høyre Dobbeltklikk\",\n    \"sv\": \"Höger Dubbelklick\",\n    \"pl\": \"Podwójne Kliknięcie Prawym\",\n    \"ru\": \"Правый Двойной Щелчок\",\n    \"ko\": \"오른쪽 더블 클릭\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-86sw2-advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/click_long.json",
    "content": "{\n  \"id\": \"click_long\",\n  \"title\": {\n    \"en\": \"Long Click\",\n    \"nl\": \"Lange klik\",\n    \"da\": \"Langt Klik\",\n    \"de\": \"Langer Klick\",\n    \"es\": \"Click Largo\",\n    \"fr\": \"Clic Long\",\n    \"it\": \"Clic Lungo\",\n    \"no\": \"Langt Trykk\",\n    \"sv\": \"Långt Tryck\",\n    \"pl\": \"Długie Kliknięcie\",\n    \"ru\": \"Долгое Нажатие\",\n    \"ko\": \"오래 클릭\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-button|aqara-button|aqara-button-advanced|aqara-86sw1-advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/click_long_left.json",
    "content": "{\n  \"id\": \"click_long_left\",\n  \"title\": {\n    \"en\": \"Left Long Click\",\n    \"nl\": \"Lange klik links\",\n    \"da\": \"Langt klik til venstre\",\n    \"de\": \"Langer Klick links\",\n    \"es\": \"Clic largo a la izquierda\",\n    \"fr\": \"Long clic gauche\",\n    \"it\": \"Clic lungo a sinistra\",\n    \"no\": \"Langt klikk til venstre\",\n    \"sv\": \"Långt klick till vänster\",\n    \"pl\": \"Długie kliknięcie w lewo\",\n    \"ru\": \"Долгое нажатие слева\",\n    \"ko\": \"왼쪽 긴 클릭\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-86sw2-advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/click_long_release.json",
    "content": "{\n  \"id\": \"click_long_release\",\n  \"title\": {\n    \"en\": \"Long Click Release\",\n    \"nl\": \"Lange klik loslaten\",\n    \"da\": \"Langt Klik Udgivelse\",\n    \"de\": \"Langer Klick Freigabe\",\n    \"es\": \"Liberación de clic largo\",\n    \"fr\": \"Relâchement de long clic\",\n    \"it\": \"Rilascio del clic lungo\",\n    \"no\": \"Langt Klikk Utløsning\",\n    \"sv\": \"Långt Klick Släpp\",\n    \"pl\": \"Długie Kliknięcie Zwolnienie\",\n    \"ru\": \"Долгое Нажатие Отпустить\",\n    \"ko\": \"길게 클릭 해제\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner le périphérique\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-button-advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/click_long_right.json",
    "content": "{\n  \"id\": \"click_long_right\",\n  \"title\": {\n    \"en\": \"Right Long Click\",\n    \"nl\": \"Lange klik rechts\",\n    \"da\": \"Højre Lang Klik\",\n    \"de\": \"Rechter Langer Klick\",\n    \"es\": \"Clic Largo Derecho\",\n    \"fr\": \"Clic Long Droit\",\n    \"it\": \"Clic Lungo Destro\",\n    \"no\": \"Høyre Langt Klikk\",\n    \"sv\": \"Höger Lång Klick\",\n    \"pl\": \"Długie kliknięcie prawe\",\n    \"ru\": \"Длинный клик правой кнопкой\",\n    \"ko\": \"오른쪽 길게 클릭\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-86sw2-advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/click_single.json",
    "content": "{\n  \"id\": \"click_single\",\n  \"title\": {\n    \"en\": \"Click\",\n    \"nl\": \"Klik\",\n    \"da\": \"Klik\",\n    \"de\": \"Klick\",\n    \"es\": \"Clic\",\n    \"fr\": \"Clic\",\n    \"it\": \"Clic\",\n    \"no\": \"Klikk\",\n    \"sv\": \"Klick\",\n    \"pl\": \"Kliknij\",\n    \"ru\": \"Клик\",\n    \"ko\": \"클릭\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner le dispositif\",\n        \"it\": \"Seleziona il dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-button|aqara-button|aqara-button-advanced|aqara-86sw1-advanced|aqara_86sw1_switch\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/click_single_left.json",
    "content": "{\n  \"id\": \"click_single_left\",\n  \"title\": {\n    \"en\": \"Left Click\",\n    \"nl\": \"Klik links\",\n    \"da\": \"Venstre klik\",\n    \"de\": \"Links Klick\",\n    \"es\": \"Clic izquierdo\",\n    \"fr\": \"Clic gauche\",\n    \"it\": \"Clic sinistro\",\n    \"no\": \"Venstre klikk\",\n    \"sv\": \"Vänsterklick\",\n    \"pl\": \"Kliknij lewy\",\n    \"ru\": \"Левый клик\",\n    \"ko\": \"왼쪽 클릭\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccione el dispositivo\",\n        \"fr\": \"Sélectionnez un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara_86sw2_switch|aqara-86sw2-advanced|db86_switch\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/click_single_left_right.json",
    "content": "{\n  \"id\": \"click_single_left_right\",\n  \"title\": {\n    \"en\": \"Left and Right Click Together\",\n    \"nl\": \"Klik rechts en links tegelijk\",\n    \"da\": \"Venstre og højre klik sammen\",\n    \"de\": \"Links- und Rechtsklick zusammen\",\n    \"es\": \"Clic izquierdo y derecho juntos\",\n    \"fr\": \"Cliquez gauche et droit ensemble\",\n    \"it\": \"Clic sinistro e destro insieme\",\n    \"no\": \"Venstre og høyre klikk sammen\",\n    \"sv\": \"Vänster och höger klick tillsammans\",\n    \"pl\": \"Lewy i prawy klik razem\",\n    \"ru\": \"Левый и правый клик вместе\",\n    \"ko\": \"왼쪽 및 오른쪽 클릭 같이\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionnez l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara_86sw2_switch|aqara-86sw2-advanced|db86_switch\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/click_single_right.json",
    "content": "{\n  \"id\": \"click_single_right\",\n  \"title\": {\n    \"en\": \"Right Click\",\n    \"nl\": \"Klik rechts\",\n    \"da\": \"Højreklik\",\n    \"de\": \"Rechtsklick\",\n    \"es\": \"Clic derecho\",\n    \"fr\": \"Clic droit\",\n    \"it\": \"Clic destro\",\n    \"no\": \"Høyreklikk\",\n    \"sv\": \"Högerklick\",\n    \"pl\": \"Kliknij prawym przyciskiem\",\n    \"ru\": \"Щелчок правой кнопкой мыши\",\n    \"ko\": \"오른쪽 클릭\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara_86sw2_switch|aqara-86sw2-advanced|db86_switch\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/cubeRotated.json",
    "content": "{\n  \"id\": \"cubeRotated\",\n  \"title\": {\n    \"en\": \"Rotated\",\n    \"nl\": \"Gedraaid\",\n    \"da\": \"Drejet\",\n    \"de\": \"Gedreht\",\n    \"es\": \"Girado\",\n    \"fr\": \"Tourné\",\n    \"it\": \"Ruotato\",\n    \"no\": \"Dreid\",\n    \"sv\": \"Vriden\",\n    \"pl\": \"Obrócony\",\n    \"ru\": \"Повернутый\",\n    \"ko\": \"회전된\"\n  },\n  \"tokens\": [\n    {\n      \"name\": \"cube_rotated\",\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"rotation\",\n        \"nl\": \"rotatie\",\n        \"da\": \"rotation\",\n        \"de\": \"Drehung\",\n        \"es\": \"rotación\",\n        \"fr\": \"rotation\",\n        \"it\": \"rotazione\",\n        \"no\": \"rotasjon\",\n        \"sv\": \"rotation\",\n        \"pl\": \"obrót\",\n        \"ru\": \"вращение\",\n        \"ko\": \"회전\"\n      },\n      \"example\": 0\n    }\n  ],\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-aqara-cube\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/desiccant_low.json",
    "content": "{\n  \"title\": { \"en\": \"Desiccant low\" },\n  \"hint\":  { \"en\": \"Triggers when desiccant level falls below the threshold.\" },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"filter\": \"driver_id=petfeeder_mmgg_miot\"\n    }\n  ],\n  \"tokens\": [\n    { \"name\": \"level_percent\", \"type\": \"number\", \"title\": { \"en\": \"Level (%)\" } }\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/triggers/eaten_food_changed.json",
    "content": "{\n  \"title\": { \"en\": \"Eaten food changed\" },\n  \"hint\":  { \"en\": \"Triggers when eaten food telemetry changes.\" },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"filter\": \"driver_id=petfeeder_mmgg_miot\"\n    }\n  ],\n  \"tokens\": [\n    { \"name\": \"today_g\", \"type\": \"number\", \"title\": { \"en\": \"Today (g)\" } },\n    { \"name\": \"total_g\", \"type\": \"number\", \"title\": { \"en\": \"Total (g)\" } },\n    { \"name\": \"delta_g\", \"type\": \"number\", \"title\": { \"en\": \"Delta (g)\" } }\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/triggers/feeder_status_changed.json",
    "content": "{\n  \"title\": { \"en\": \"Feeder status changed\" },\n  \"hint\":  { \"en\": \"Triggers when the feeder status (mode) changes.\" },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"filter\": \"driver_id=petfeeder_mmgg_miot\"\n    }\n  ],\n  \"tokens\": [\n    { \"name\": \"new_status\",      \"type\": \"string\", \"title\": { \"en\": \"New status\" } },\n    { \"name\": \"previous_status\", \"type\": \"string\", \"title\": { \"en\": \"Previous status\" } }\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/triggers/flip180_cube.json",
    "content": "{\n  \"id\": \"flip180_cube\",\n  \"title\": {\n    \"en\": \"Flip 180°\",\n    \"nl\": \"180° keren\",\n    \"da\": \"Vend 180°\",\n    \"de\": \"180° drehen\",\n    \"es\": \"Girar 180°\",\n    \"fr\": \"Retourner 180°\",\n    \"it\": \"Capovolgere 180°\",\n    \"no\": \"Snur 180°\",\n    \"sv\": \"Vänd 180°\",\n    \"pl\": \"Odwróć 180°\",\n    \"ru\": \"Повернуть на 180°\",\n    \"ko\": \"180° 뒤집기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-aqara-cube\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/flip90_cube.json",
    "content": "{\n  \"id\": \"flip90_cube\",\n  \"title\": {\n    \"en\": \"Flip 90°\",\n    \"nl\": \"90° keren\",\n    \"da\": \"Flip 90°\",\n    \"de\": \"90° drehen\",\n    \"es\": \"Girar 90°\",\n    \"fr\": \"Retourner à 90°\",\n    \"it\": \"Capovolgi di 90°\",\n    \"no\": \"Flipp 90°\",\n    \"sv\": \"Vänd 90°\",\n    \"pl\": \"Obróć o 90°\",\n    \"ru\": \"Повернуть на 90°\",\n    \"ko\": \"90° 뒤집기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-aqara-cube\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/free_fall_cube.json",
    "content": "{\n  \"id\": \"free_fall_cube\",\n  \"title\": {\n    \"en\": \"Free Fall\",\n    \"nl\": \"Vrije val\",\n    \"da\": \"Frit fald\",\n    \"de\": \"Freier Fall\",\n    \"es\": \"Caída libre\",\n    \"fr\": \"Chute libre\",\n    \"it\": \"Caduta libera\",\n    \"no\": \"Fritt fall\",\n    \"sv\": \"Fritt fall\",\n    \"pl\": \"Swobodny spadek\",\n    \"ru\": \"Свободное падение\",\n    \"ko\": \"자유낙하\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-aqara-cube\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/gatewayLuminance.json",
    "content": "{\n  \"id\": \"gatewayLuminance\",\n  \"title\": {\n    \"en\": \"Luminance has changed\",\n    \"nl\": \"De helderheid is veranderd\",\n    \"da\": \"Luminansen er ændret\",\n    \"de\": \"Die Helligkeit hat sich geändert\",\n    \"es\": \"La luminancia ha cambiado\",\n    \"fr\": \"La luminance a changé\",\n    \"it\": \"La luminanza è cambiata\",\n    \"no\": \"Luminansen har endret seg\",\n    \"sv\": \"Luminansen har ändrats\",\n    \"pl\": \"Jasność została zmieniona\",\n    \"ru\": \"Яркость изменилась\",\n    \"ko\": \"조도가 변경되었습니다\"\n  },\n  \"tokens\": [\n    {\n      \"name\": \"luminance\",\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"luminance\",\n        \"nl\": \"helderheid\",\n        \"da\": \"luminans\",\n        \"de\": \"Helligkeit\",\n        \"es\": \"luminancia\",\n        \"fr\": \"luminance\",\n        \"it\": \"luminanza\",\n        \"no\": \"luminans\",\n        \"sv\": \"luminans\",\n        \"pl\": \"jasność\",\n        \"ru\": \"яркость\",\n        \"ko\": \"휘도\"\n      },\n      \"example\": 0\n    }\n  ],\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Gateway\",\n        \"nl\": \"Selecteer Gateway\",\n        \"da\": \"Vælg Gateway\",\n        \"de\": \"Gateway auswählen\",\n        \"es\": \"Selecciona Gateway\",\n        \"fr\": \"Sélectionnez Gateway\",\n        \"it\": \"Seleziona Gateway\",\n        \"no\": \"Velg Gateway\",\n        \"sv\": \"Välj Gateway\",\n        \"pl\": \"Wybierz Gateway\",\n        \"ru\": \"Выберите шлюз\",\n        \"ko\": \"게이트웨이를 선택하세요\"\n      },\n      \"filter\": \"driver_id=gateway\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ],\n  \"deprecated\": true\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/humidifier2Waterlevel.json",
    "content": "{\n  \"id\": \"humidifier2Waterlevel\",\n  \"title\": {\n    \"en\": \"Waterlevel has changed\",\n    \"nl\": \"Waterniveau is veranderd\",\n    \"de\": \"Der Wasserstand hat sich geändert\",\n    \"da\": \"Vandniveauet er ændret\",\n    \"es\": \"El nivel de agua ha cambiado\",\n    \"fr\": \"Le niveau de l'eau a changé\",\n    \"it\": \"Il livello dell'acqua è cambiato\",\n    \"no\": \"Vannstanden har endret seg\",\n    \"sv\": \"Vattennivån har ändrats\",\n    \"pl\": \"Poziom wody się zmienił\",\n    \"ru\": \"Уровень воды изменился\",\n    \"ko\": \"수위가 변경되었습니다\"\n  },\n  \"tokens\": [\n    {\n      \"name\": \"waterlevel\",\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"current waterlevel\",\n        \"nl\": \"actueel waterniveau\",\n        \"de\": \"aktueller Wasserstand\",\n        \"da\": \"nuværende vandniveau\",\n        \"es\": \"nivel de agua actual\",\n        \"fr\": \"niveau d'eau actuel\",\n        \"it\": \"livello dell'acqua attuale\",\n        \"no\": \"nåværende vannstand\",\n        \"sv\": \"nuvarande vattennivå\",\n        \"pl\": \"aktualny poziom wody\",\n        \"ru\": \"текущий уровень воды\",\n        \"ko\": \"현재 수위\"\n      },\n      \"example\": 88\n    },\n    {\n      \"name\": \"previous_waterlevel\",\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"previous waterlevel\",\n        \"nl\": \"vorige waterniveau\",\n        \"de\": \"bisheriger Wasserstand\",\n        \"da\": \"tidligere vandniveau\",\n        \"es\": \"nivel de agua anterior\",\n        \"fr\": \"niveau d'eau précédent\",\n        \"it\": \"livello dell'acqua precedente\",\n        \"no\": \"forrige vannstand\",\n        \"sv\": \"tidigare vattennivå\",\n        \"pl\": \"wcześniejszy poziom wody\",\n        \"ru\": \"предыдущий уровень воды\",\n        \"ko\": \"이전 수위\"\n      },\n      \"example\": 90\n    }\n  ],\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Humidifier 2\",\n        \"nl\": \"Selecteer Humidifier 2\",\n        \"da\": \"Vælg Humidifier 2\",\n        \"es\": \"Selecciona Humidifier 2\",\n        \"fr\": \"Sélectionnez Humidifier 2\",\n        \"it\": \"Seleziona Humidifier 2\",\n        \"no\": \"Velg Humidifier 2\",\n        \"sv\": \"Välj Humidifier 2\",\n        \"pl\": \"Wybierz Humidifier 2\",\n        \"ru\": \"Выберите Humidifier 2\",\n        \"ko\": \"Humidifier 2 선택\"\n      },\n      \"filter\": \"driver_id=humidifier_zhimi_humidifier|humidifier_zhimi_humidifier_miot|humidifier_xiaomi_humidifier\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/leftSwitchOff.json",
    "content": "{\n  \"id\": \"leftSwitchOff\",\n  \"title\": {\n    \"en\": \"Left Switch Off\",\n    \"nl\": \"Linkerschakelaar uit\",\n    \"da\": \"Venstre kontakt slukket\",\n    \"de\": \"Linker Schalter aus\",\n    \"es\": \"Interruptor izquierdo apagado\",\n    \"fr\": \"Interrupteur gauche éteint\",\n    \"it\": \"Interruttore sinistro spento\",\n    \"no\": \"Venstre bryter av\",\n    \"sv\": \"Vänstra brytaren av\",\n    \"pl\": \"Lewy przełącznik wyłączony\",\n    \"ru\": \"Выключатель слева выключен\",\n    \"ko\": \"왼쪽 스위치 끄기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/leftSwitchOn.json",
    "content": "{\n  \"id\": \"leftSwitchOn\",\n  \"title\": {\n    \"en\": \"Left Switch On\",\n    \"nl\": \"Linkerschakelaar aan\",\n    \"da\": \"Venstre kontakt tændt\",\n    \"de\": \"Linker Schalter an\",\n    \"es\": \"Interruptor izquierdo encendido\",\n    \"fr\": \"Interrupteur gauche allumé\",\n    \"it\": \"Interruttore sinistro acceso\",\n    \"no\": \"Venstre bryter på\",\n    \"sv\": \"Vänstra strömbrytaren på\",\n    \"pl\": \"Lewy przełącznik włączony\",\n    \"ru\": \"Левый переключатель включен\",\n    \"ko\": \"왼쪽 스위치 켜기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/lockEvent.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Lock Event\",\n    \"nl\": \"Lock event\",\n    \"da\": \"Låsebegivenhed\",\n    \"de\": \"Schlossereignis\",\n    \"es\": \"Evento de Bloqueo\",\n    \"fr\": \"Événement de Verrouillage\",\n    \"it\": \"Evento di Blocco\",\n    \"no\": \"Låshendelse\",\n    \"sv\": \"Låshändelse\",\n    \"pl\": \"Wydarzenie Blokady\",\n    \"ru\": \"Событие Блокировки\",\n    \"ko\": \"잠금 이벤트\"\n  },\n  \"tokens\": [\n    {\n      \"name\": \"finger_id\",\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"fingerprint id\",\n        \"nl\": \"vingerafdruk id\",\n        \"da\": \"fingeraftryk id\",\n        \"de\": \"Fingerabdruck ID\",\n        \"es\": \"ID de huella digital\",\n        \"fr\": \"ID d'empreinte digitale\",\n        \"it\": \"ID dell'impronta digitale\",\n        \"no\": \"fingeravtrykk id\",\n        \"sv\": \"fingeravtryck id\",\n        \"pl\": \"ID odcisku palca\",\n        \"ru\": \"ID отпечатка пальца\",\n        \"ko\": \"지문 ID\"\n      },\n      \"example\": 0\n    },\n    {\n      \"name\": \"code_id\",\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"code id\",\n        \"nl\": \"code id\",\n        \"da\": \"kode id\",\n        \"de\": \"Code ID\",\n        \"es\": \"ID de código\",\n        \"fr\": \"ID de code\",\n        \"it\": \"ID del codice\",\n        \"no\": \"kode id\",\n        \"sv\": \"kod id\",\n        \"pl\": \"ID kodu\",\n        \"ru\": \"ID кода\",\n        \"ko\": \"코드 ID\"\n      },\n      \"example\": 0\n    },\n    {\n      \"name\": \"card_id\",\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"card id\",\n        \"nl\": \"kaart id\",\n        \"da\": \"kort id\",\n        \"de\": \"Karten ID\",\n        \"es\": \"ID de tarjeta\",\n        \"fr\": \"ID de carte\",\n        \"it\": \"ID della carta\",\n        \"no\": \"kort id\",\n        \"sv\": \"kort id\",\n        \"pl\": \"ID karty\",\n        \"ru\": \"ID карты\",\n        \"ko\": \"카드 ID\"\n      },\n      \"example\": 0\n    },\n    {\n      \"name\": \"userName\",\n      \"type\": \"string\",\n      \"title\": {\n        \"en\": \"User\",\n        \"nl\": \"Gebruiker\",\n        \"da\": \"Bruger\",\n        \"de\": \"Benutzer\",\n        \"es\": \"Usuario\",\n        \"fr\": \"Utilisateur\",\n        \"it\": \"Utente\",\n        \"no\": \"Bruker\",\n        \"sv\": \"Användare\",\n        \"pl\": \"Użytkownik\",\n        \"ru\": \"Пользователь\",\n        \"ko\": \"사용자\"\n      },\n      \"example\": {\n        \"en\": \"John Doe\"\n      }\n    },\n    {\n      \"name\": \"wrong_id\",\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"wrong id\",\n        \"nl\": \"verkeerd id\",\n        \"da\": \"forkert id\",\n        \"de\": \"falsche ID\",\n        \"es\": \"ID incorrecta\",\n        \"fr\": \"ID incorrecte\",\n        \"it\": \"ID errato\",\n        \"no\": \"feil id\",\n        \"sv\": \"fel id\",\n        \"pl\": \"błędne ID\",\n        \"ru\": \"неверный ID\",\n        \"ko\": \"잘못된 ID\"\n      },\n      \"example\": 3\n    }\n  ],\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"filter\": \"driver_id=lock.aq1\"\n    }\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/motionSensorNoMotion120.json",
    "content": "{\n  \"id\": \"motionSensorNoMotion120\",\n  \"title\": {\n    \"en\": \"No motion detected in 2 minutes\",\n    \"nl\": \"Geen beweging gedetecteerd in 2 minuten\",\n    \"da\": \"Ingen bevægelse registreret i 2 minutter\",\n    \"de\": \"Keine Bewegung in 2 Minuten erkannt\",\n    \"es\": \"No se detectó movimiento en 2 minutos\",\n    \"fr\": \"Aucun mouvement détecté en 2 minutes\",\n    \"it\": \"Nessun movimento rilevato in 2 minuti\",\n    \"no\": \"Ingen bevegelse oppdaget på 2 minutter\",\n    \"sv\": \"Ingen rörelse upptäckt på 2 minuter\",\n    \"pl\": \"Nie wykryto ruchu przez 2 minuty\",\n    \"ru\": \"Движение не обнаружено в течение 2 минут\",\n    \"ko\": \"2분 동안 움직임이 감지되지 않음\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-motion-sensor|aqara-motion-sensor\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/motionSensorNoMotion1200.json",
    "content": "{\n  \"id\": \"motionSensorNoMotion1200\",\n  \"title\": {\n    \"en\": \"No motion detected in 20 minutes\",\n    \"nl\": \"Geen beweging gedetecteerd in 20 minuten\",\n    \"da\": \"Ingen bevægelse registreret i 20 minutter\",\n    \"de\": \"Keine Bewegung in 20 Minuten erkannt\",\n    \"es\": \"No se ha detectado movimiento en 20 minutos\",\n    \"fr\": \"Aucun mouvement détecté en 20 minutes\",\n    \"it\": \"Nessun movimento rilevato in 20 minuti\",\n    \"no\": \"Ingen bevegelse oppdaget på 20 minutter\",\n    \"sv\": \"Ingen rörelse upptäckt på 20 minuter\",\n    \"pl\": \"Brak ruchu wykrytego w ciągu 20 minut\",\n    \"ru\": \"Движение не обнаружено в течение 20 минут\",\n    \"ko\": \"20분 동안 움직임 감지되지 않음\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-motion-sensor|aqara-motion-sensor\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/motionSensorNoMotion180.json",
    "content": "{\n  \"id\": \"motionSensorNoMotion180\",\n  \"title\": {\n    \"en\": \"No motion detected in 3 minutes\",\n    \"nl\": \"Geen beweging gedetecteerd in 3 minuten\",\n    \"da\": \"Ingen bevægelse registreret i 3 minutter\",\n    \"de\": \"Keine Bewegung in 3 Minuten erkannt\",\n    \"es\": \"No se detectó movimiento en 3 minutos\",\n    \"fr\": \"Aucun mouvement détecté en 3 minutes\",\n    \"it\": \"Nessun movimento rilevato in 3 minuti\",\n    \"no\": \"Ingen bevegelse oppdaget på 3 minutter\",\n    \"sv\": \"Ingen rörelse upptäckt på 3 minuter\",\n    \"pl\": \"Brak wykrycia ruchu przez 3 minuty\",\n    \"ru\": \"Нет движения в течение 3 минут\",\n    \"ko\": \"3분 동안 움직임이 감지되지 않음\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona il dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-motion-sensor|aqara-motion-sensor\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/motionSensorNoMotion1800.json",
    "content": "{\n  \"id\": \"motionSensorNoMotion1800\",\n  \"title\": {\n    \"en\": \"No motion detected in 30 minutes\",\n    \"nl\": \"Geen beweging gedetecteerd in 30 minuten\",\n    \"da\": \"Ingen bevægelse registreret i 30 minutter\",\n    \"de\": \"Keine Bewegung in 30 Minuten erkannt\",\n    \"es\": \"No se detectó movimiento en 30 minutos\",\n    \"fr\": \"Aucun mouvement détecté en 30 minutes\",\n    \"it\": \"Nessun movimento rilevato in 30 minuti\",\n    \"no\": \"Ingen bevegelse oppdaget på 30 minutter\",\n    \"sv\": \"Ingen rörelse upptäckt på 30 minuter\",\n    \"pl\": \"Brak ruchu przez 30 minut\",\n    \"ru\": \"Движение не обнаружено в течение 30 минут\",\n    \"ko\": \"30분 동안 움직임이 감지되지 않았습니다.\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner le dispositif\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치를 선택하세요\"\n      },\n      \"filter\": \"driver_id=mi-motion-sensor|aqara-motion-sensor\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/motionSensorNoMotion300.json",
    "content": "{\n  \"id\": \"motionSensorNoMotion300\",\n  \"title\": {\n    \"en\": \"No motion detected in 5 minutes\",\n    \"nl\": \"Geen beweging gedetecteerd in 5 minuten\",\n    \"da\": \"Ingen bevægelse registreret i 5 minutter\",\n    \"de\": \"Keine Bewegung in 5 Minuten erkannt\",\n    \"es\": \"No se detectó movimiento en 5 minutos\",\n    \"fr\": \"Aucun mouvement détecté en 5 minutes\",\n    \"it\": \"Nessun movimento rilevato in 5 minuti\",\n    \"no\": \"Ingen bevegelse oppdaget på 5 minutter\",\n    \"sv\": \"Ingen rörelse upptäckt på 5 minuter\",\n    \"pl\": \"Brak ruchu przez 5 minut\",\n    \"ru\": \"Нет движения в течение 5 минут\",\n    \"ko\": \"5분 동안 감지된 움직임 없음\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-motion-sensor|aqara-motion-sensor\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/motionSensorNoMotion600.json",
    "content": "{\n  \"id\": \"motionSensorNoMotion600\",\n  \"title\": {\n    \"en\": \"No motion detected in 10 minutes\",\n    \"nl\": \"Geen beweging gedetecteerd in 10 minuten\",\n    \"da\": \"Ingen bevægelse registreret i 10 minutter\",\n    \"de\": \"Keine Bewegung in 10 Minuten erkannt\",\n    \"es\": \"No se detectó movimiento en 10 minutos\",\n    \"fr\": \"Aucun mouvement détecté en 10 minutes\",\n    \"it\": \"Nessun movimento rilevato in 10 minuti\",\n    \"no\": \"Ingen bevegelse oppdaget på 10 minutter\",\n    \"sv\": \"Ingen rörelse upptäckt på 10 minuter\",\n    \"pl\": \"Nie wykryto ruchu przez 10 minut\",\n    \"ru\": \"Движение не обнаружено в течение 10 минут\",\n    \"ko\": \"10분 동안 움직임이 감지되지 않음\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un périphérique\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"기기 선택\"\n      },\n      \"filter\": \"driver_id=mi-motion-sensor|aqara-motion-sensor\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/move_cube.json",
    "content": "{\n  \"id\": \"move_cube\",\n  \"title\": {\n    \"en\": \"Move\",\n    \"nl\": \"Verplaatsen\",\n    \"da\": \"Flyt\",\n    \"de\": \"Bewegen\",\n    \"es\": \"Mover\",\n    \"fr\": \"Déplacer\",\n    \"it\": \"Muovi\",\n    \"no\": \"Flytt\",\n    \"sv\": \"Flytta\",\n    \"pl\": \"Przenieś\",\n    \"ru\": \"Двигать\",\n    \"ko\": \"이동\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-aqara-cube\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/rightSwitchOff.json",
    "content": "{\n  \"id\": \"rightSwitchOff\",\n  \"title\": {\n    \"en\": \"Right Switch Off\",\n    \"nl\": \"Rechterschakelaar uit\",\n    \"da\": \"Højre kontakt slukket\",\n    \"de\": \"Rechter Schalter aus\",\n    \"es\": \"Interruptor derecho apagado\",\n    \"fr\": \"Interrupteur droit éteint\",\n    \"it\": \"Interruttore destro spento\",\n    \"no\": \"Høyre bryter av\",\n    \"sv\": \"Högra strömställaren av\",\n    \"pl\": \"Przełącznik prawy wyłączony\",\n    \"ru\": \"Правый выключатель выключен\",\n    \"ko\": \"오른쪽 스위치 끄기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/rightSwitchOn.json",
    "content": "{\n  \"id\": \"rightSwitchOn\",\n  \"title\": {\n    \"en\": \"Right Switch On\",\n    \"nl\": \"Rechterschakelaar aan\",\n    \"da\": \"Højre kontakt er tændt\",\n    \"de\": \"Rechter Schalter an\",\n    \"es\": \"Interruptor derecho encendido\",\n    \"fr\": \"Interrupteur droit allumé\",\n    \"it\": \"Interruttore destro acceso\",\n    \"no\": \"Høyre bryter på\",\n    \"sv\": \"Högra brytaren på\",\n    \"pl\": \"Prawy włącznik włączony\",\n    \"ru\": \"Правый выключатель включён\",\n    \"ko\": \"오른쪽 스위치 켜기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionnez un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/rotate_negative_cube.json",
    "content": "{\n  \"id\": \"rotate_negative_cube\",\n  \"title\": {\n    \"en\": \"Rotated Anti Clockwise\",\n    \"nl\": \"Rotatie tegen de klok in\",\n    \"da\": \"Drejet mod uret\",\n    \"de\": \"Gegen den Uhrzeigersinn gedreht\",\n    \"es\": \"Girado en sentido antihorario\",\n    \"fr\": \"Tourné dans le sens antihoraire\",\n    \"it\": \"Ruotato in senso antiorario\",\n    \"no\": \"Dreid mot klokka\",\n    \"sv\": \"Vriden moturs\",\n    \"pl\": \"Obrócony przeciwnie do ruchu wskazówek zegara\",\n    \"ru\": \"Повернуто против часовой стрелки\",\n    \"ko\": \"반시계 방향으로 회전\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-aqara-cube\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/rotate_positive_cube.json",
    "content": "{\n  \"id\": \"rotate_positive_cube\",\n  \"title\": {\n    \"en\": \"Rotated Clockwise\",\n    \"nl\": \"Rotatie met de klok mee\",\n    \"da\": \"Drejet med uret\",\n    \"de\": \"Im Uhrzeigersinn gedreht\",\n    \"es\": \"Girado en el sentido de las agujas del reloj\",\n    \"fr\": \"Tourné dans le sens des aiguilles d'une montre\",\n    \"it\": \"Ruotato in senso orario\",\n    \"no\": \"Roterte med klokken\",\n    \"sv\": \"Roterad medurs\",\n    \"pl\": \"Obrócony zgodnie z ruchem wskazówek zegara\",\n    \"ru\": \"Повернут по часовой стрелке\",\n    \"ko\": \"시계 방향으로 회전\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionnez l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-aqara-cube\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/shake.json",
    "content": "{\n  \"id\": \"shake\",\n  \"title\": {\n    \"en\": \"Shake\",\n    \"nl\": \"Schudden\",\n    \"da\": \"Ryst\",\n    \"de\": \"Schütteln\",\n    \"es\": \"Agitar\",\n    \"fr\": \"Secouer\",\n    \"it\": \"Scuoti\",\n    \"no\": \"Rist\",\n    \"sv\": \"Skaka\",\n    \"pl\": \"Potrząśnij\",\n    \"ru\": \"Встряхнуть\",\n    \"ko\": \"흔들기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выбрать устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=aqara-button-advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/shake_air_cube.json",
    "content": "{\n  \"id\": \"shake_air_cube\",\n  \"title\": {\n    \"en\": \"Shake in air\",\n    \"nl\": \"Schudden in de lucht\",\n    \"da\": \"Ryst i luften\",\n    \"de\": \"Schütteln in der Luft\",\n    \"es\": \"Agitar en el aire\",\n    \"fr\": \"Secouer dans les airs\",\n    \"it\": \"Sbattere in aria\",\n    \"no\": \"Rist i lufta\",\n    \"sv\": \"Skaka i luften\",\n    \"pl\": \"Potrząśnij w powietrzu\",\n    \"ru\": \"Встряхнуть в воздухе\",\n    \"ko\": \"공중에서 흔들기\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-aqara-cube\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/statusVacuum.json",
    "content": "{\n  \"id\": \"statusVacuum\",\n  \"title\": {\n    \"en\": \"Status has changed\",\n    \"nl\": \"Status is gewijzigd\",\n    \"da\": \"Status er ændret\",\n    \"de\": \"Status hat sich geändert\",\n    \"es\": \"El estado ha cambiado\",\n    \"fr\": \"Le statut a changé\",\n    \"it\": \"Lo stato è cambiato\",\n    \"no\": \"Status har endret seg\",\n    \"sv\": \"Status har ändrats\",\n    \"pl\": \"Status zmienił się\",\n    \"ru\": \"Статус изменился\",\n    \"ko\": \"상태가 변경되었습니다\"\n  },\n  \"tokens\": [\n    {\n      \"name\": \"status\",\n      \"type\": \"string\",\n      \"title\": {\n        \"en\": \"status\",\n        \"nl\": \"status\",\n        \"da\": \"status\",\n        \"de\": \"Status\",\n        \"es\": \"estado\",\n        \"fr\": \"statut\",\n        \"it\": \"stato\",\n        \"no\": \"status\",\n        \"sv\": \"status\",\n        \"pl\": \"status\",\n        \"ru\": \"статус\",\n        \"ko\": \"상태\"\n      },\n      \"example\": \"stopped\"\n    }\n  ],\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Robot\",\n        \"nl\": \"Selecteer Mi Robot\",\n        \"da\": \"Vælg Mi Robot\",\n        \"de\": \"Mi-Roboter auswählen\",\n        \"es\": \"Selecciona Mi Robot\",\n        \"fr\": \"Sélectionnez Mi Robot\",\n        \"it\": \"Seleziona Mi Robot\",\n        \"no\": \"Velg Mi Robot\",\n        \"sv\": \"Välj Mi Robot\",\n        \"pl\": \"Wybierz Mi Robot\",\n        \"ru\": \"Выберите Mi Robot\",\n        \"ko\": \"Mi 로봇 선택\"\n      },\n      \"filter\": \"driver_id=mi-robot|vacuum_mi_rockrobo_vacuum_advanced|vacuum_dreame_vacuum|vacuum_viomi_vacuum_v7|vacuum_mija_vacuum_miot|vacuum_roidmi_vacuum_miot|vacuum_xiaomi_vacuum_max\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/triggers/tap_twice_cube.json",
    "content": "{\n  \"id\": \"tap_twice_cube\",\n  \"title\": {\n    \"en\": \"Tap twice\",\n    \"nl\": \"2x tikken\",\n    \"da\": \"Tryk to gange\",\n    \"de\": \"Zweimal tippen\",\n    \"es\": \"Toca dos veces\",\n    \"fr\": \"Tapez deux fois\",\n    \"it\": \"Tocca due volte\",\n    \"no\": \"Trykk to ganger\",\n    \"sv\": \"Tryck två gånger\",\n    \"pl\": \"Dotknij dwa razy\",\n    \"ru\": \"Нажмите дважды\",\n    \"ko\": \"두 번 탭하세요\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionnez un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-aqara-cube\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/triggerModeChanged.json",
    "content": "{\n  \"title\": {\n    \"en\": \"Mode has changed\",\n    \"nl\": \"Modus gewijzigd\",\n    \"de\": \"Modus hat sich geändert\",\n    \"da\": \"Tilstand er ændret\",\n    \"es\": \"El modo ha cambiado\",\n    \"fr\": \"Le mode a changé\",\n    \"it\": \"La modalità è cambiata\",\n    \"no\": \"Modus er endret\",\n    \"sv\": \"Läget har ändrats\",\n    \"pl\": \"Tryb został zmieniony\",\n    \"ru\": \"Режим изменился\",\n    \"ko\": \"모드가 변경되었습니다\"\n  },\n  \"tokens\": [\n    {\n      \"name\": \"new_mode\",\n      \"type\": \"string\",\n      \"title\": {\n        \"en\": \"new mode\",\n        \"nl\": \"nieuwe modus\",\n        \"de\": \"neue modus\",\n        \"da\": \"ny tilstand\",\n        \"es\": \"nuevo modo\",\n        \"fr\": \"nouveau mode\",\n        \"it\": \"nuova modalità\",\n        \"no\": \"ny modus\",\n        \"sv\": \"nytt läge\",\n        \"pl\": \"nowy tryb\",\n        \"ru\": \"новый режим\",\n        \"ko\": \"새로운 모드\"\n      },\n      \"example\": \"medium\"\n    },\n    {\n      \"name\": \"previous_mode\",\n      \"type\": \"string\",\n      \"title\": {\n        \"en\": \"previous mode\",\n        \"nl\": \"vorige modus\",\n        \"de\": \"bisherige modus\",\n        \"da\": \"forrige tilstand\",\n        \"es\": \"modo anterior\",\n        \"fr\": \"mode précédent\",\n        \"it\": \"modalità precedente\",\n        \"no\": \"forrige modus\",\n        \"sv\": \"föregående läge\",\n        \"pl\": \"poprzedni tryb\",\n        \"ru\": \"предыдущий режим\",\n        \"ko\": \"이전 모드\"\n      },\n      \"example\": \"silent\"\n    }\n  ],\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"es\": \"Seleccione dispositivo\",\n        \"fr\": \"Sélectionnez l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"디바이스 선택\"\n      },\n      \"filter\": \"driver_id=mi-airpurifier|airpurifier_zhimi_advanced|airpurifier_zhimi_advanced_miot|airpurifier_zhimi_airpurifier_ma2|airpurifier_dmaker_airfresh_t2017|airfresh_zhimi_airfresh|humidifier_zhimi_humidifier|humidifier_zhimi_humidifier_miot|humidifier_deerma_humidifier_jsq|humidifier_deerma_humidifier_miot|dmaker_fan_1c|fan_zhimi_advanced|zhimi_fan_za5|airfryer_careli_miot|petwaterdispenser_mmgg_miot|pet_waterer_xiaomi|petfeeder_mmgg_miot|humidifier_xiaomi_humidifier|dehumidifier_dmaker_derh_miot|humidifier_leshow_humidifier_jsq1|diffuser_xwhzp_diffuser_xwxfj\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}\n"
  },
  {
    "path": ".homeycompose/flow/triggers/triggerPlugInUse.json",
    "content": "{\n  \"id\": \"triggerPlugInUse\",\n  \"title\": {\n    \"en\": \"In use\",\n    \"nl\": \"In gebruik\",\n    \"da\": \"I brug\",\n    \"de\": \"In Benutzung\",\n    \"es\": \"En uso\",\n    \"fr\": \"En cours d'utilisation\",\n    \"it\": \"In uso\",\n    \"no\": \"I bruk\",\n    \"sv\": \"I bruk\",\n    \"pl\": \"W użyciu\",\n    \"ru\": \"В использовании\",\n    \"ko\": \"사용 중\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccione el dispositivo\",\n        \"fr\": \"Sélectionner l'appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=mi-plug\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/triggerVacuumRoomSegments.json",
    "content": "{\n  \"id\": \"triggerVacuumRoomSegments\",\n  \"title\": {\n    \"en\": \"Room segments has changed\",\n    \"nl\": \"Kamer segmenten is gewijzigd\",\n    \"da\": \"Rumsegmenter er ændret\",\n    \"de\": \"Raumsegmente wurden geändert\",\n    \"es\": \"Los segmentos de la habitación han cambiado\",\n    \"fr\": \"Les segments de la pièce ont changé\",\n    \"it\": \"I segmenti della stanza sono cambiati\",\n    \"no\": \"Romsegmenter har blitt endret\",\n    \"sv\": \"Rumssegment har ändrats\",\n    \"pl\": \"Segmenty pokoju zostały zmienione\",\n    \"ru\": \"Сегменты комнаты изменились\",\n    \"ko\": \"룸 세그먼트가 변경되었습니다\"\n  },\n  \"tokens\": [\n    {\n      \"name\": \"segments\",\n      \"type\": \"string\",\n      \"title\": {\n        \"en\": \"Segments\",\n        \"nl\": \"Segmenten\",\n        \"da\": \"Segmenter\",\n        \"de\": \"Segmente\",\n        \"es\": \"Segmentos\",\n        \"fr\": \"Segments\",\n        \"it\": \"Segmenti\",\n        \"no\": \"Segmenter\",\n        \"sv\": \"Segment\",\n        \"pl\": \"Segmenty\",\n        \"ru\": \"Сегменты\",\n        \"ko\": \"세그먼트\"\n      },\n      \"example\": \"[16,17]\"\n    }\n  ],\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select Mi Robot\",\n        \"nl\": \"Selecteer Mi Robot\",\n        \"da\": \"Vælg Mi Robot\",\n        \"de\": \"Wählen Sie Mi Robot\",\n        \"es\": \"Seleccionar Mi Robot\",\n        \"fr\": \"Sélectionner Mi Robot\",\n        \"it\": \"Seleziona Mi Robot\",\n        \"no\": \"Velg Mi Robot\",\n        \"sv\": \"Välj Mi Robot\",\n        \"pl\": \"Wybierz Mi Robot\",\n        \"ru\": \"Выберите Mi Robot\",\n        \"ko\": \"Mi 로봇 선택\"\n      },\n      \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/triggerVibrationFreeFallAlarm.json",
    "content": "{\n  \"id\": \"triggerVibrationFreeFallAlarm\",\n  \"title\": {\n    \"en\": \"Free Fall\",\n    \"nl\": \"Vrije val\",\n    \"da\": \"Frit fald\",\n    \"de\": \"Freier Fall\",\n    \"es\": \"Caída libre\",\n    \"fr\": \"Chute libre\",\n    \"it\": \"Caduta libera\",\n    \"no\": \"Fritt fall\",\n    \"sv\": \"Fritt fall\",\n    \"pl\": \"Swobodny spadek\",\n    \"ru\": \"Свободное падение\",\n    \"ko\": \"자유 낙하\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionner un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"장치 선택\"\n      },\n      \"filter\": \"driver_id=vibration_sensor\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeycompose/flow/triggers/triggerVibrationTiltAlarm.json",
    "content": "{\n  \"id\": \"triggerVibrationTiltAlarm\",\n  \"title\": {\n    \"en\": \"Tilted\",\n    \"nl\": \"Tilted\",\n    \"da\": \"Vippet\",\n    \"de\": \"Geneigt\",\n    \"es\": \"Inclinado\",\n    \"fr\": \"Incliné\",\n    \"it\": \"Inclinato\",\n    \"no\": \"Vippet\",\n    \"sv\": \"Vinklad\",\n    \"pl\": \"Przechylony\",\n    \"ru\": \"Наклонено\",\n    \"ko\": \"기울어진\"\n  },\n  \"args\": [\n    {\n      \"name\": \"device\",\n      \"type\": \"device\",\n      \"placeholder\": {\n        \"en\": \"Select device\",\n        \"nl\": \"Selecteer apparaat\",\n        \"da\": \"Vælg enhed\",\n        \"de\": \"Gerät auswählen\",\n        \"es\": \"Seleccionar dispositivo\",\n        \"fr\": \"Sélectionnez un appareil\",\n        \"it\": \"Seleziona dispositivo\",\n        \"no\": \"Velg enhet\",\n        \"sv\": \"Välj enhet\",\n        \"pl\": \"Wybierz urządzenie\",\n        \"ru\": \"Выберите устройство\",\n        \"ko\": \"기기 선택\"\n      },\n      \"filter\": \"driver_id=vibration_sensor\"\n    }\n  ],\n  \"platforms\": [\n    \"local\"\n  ]\n}"
  },
  {
    "path": ".homeyignore",
    "content": "docs/*\nappdirectory.zip\nappdirectory_working.zip"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"overrides\": [\n    {\n      \"files\": [\"*.html\", \"**/*.js\"],\n      \"options\": {\n        \"semi\": true,\n        \"singleQuote\": true,\n        \"tabWidth\": 4,\n        \"printWidth\": 500,\n        \"trailingComma\": \"none\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, gender identity and expression, level of experience,\neducation, socio-economic status, nationality, personal appearance, race,\nreligion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at support@athom.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Athom and Homey\n\nFirst off all, thank you for taking the time to contribute!\n\nThe following is a set of guidelines for contributing to Athom and its packages, which are hosted in the [Athom Organization](https://github.com/athombv) on GitHub. These are just guidelines, not rules. Use your best judgment, and feel free to contact us if you have any questions.\n\nPlease join our [community slack](https://slack.athom.com), if you have not done so already.\nWe also have a [community forum](https://community.homey.app) for general discussions.\n\n\n## Before submitting a bug or feature request\n\n* **Have you actually read the error message**?\n* Have you searched for similar issues?\n* Have you updated homey, all apps, and the development tools (if applicable)?\n* Have you checked that it's not a problem with one of the apps you're using, rather than Homey itself?\n* Have you looked at what's involved in fixing/implementing this?\n \nCapable programmers should always attempt to investigate and fix problems themselves before asking for others to help. Submit a pull request instead of an issue!\n\n## A great bug report contains\n\n* Context – what were you trying to achieve?\n* Detailed steps to reproduce the error from scratch. Try isolating the minimal amount of code needed to reproduce the error.\n* Any applicable log files or ID's.\n* Evidence you've looked into solving the problem and ideally, a theory on the cause and a possible solution.\n\n## A great feature request contains\n\n* The current situation.\n* How and why the current situation is problematic.\n* A detailed proposal or pull request that demonstrates how the problem could be solved.\n* A use case – who needs this feature and why?\n* Any caveats.\n\n## A great pull request contains\n\n* Minimal changes. Only submit code relevant to the current issue. Other changes should go in new pull requests.\n* Minimal commits. Please squash to a single commit before sending your pull request.\n* No conflicts. Please rebase off the latest master before submitting.\n* Code conforming to the existing conventions and formats. i.e. Please don't reformat whitespace.\n* Passing tests in the test folder (if applicable). Use existing tests as a reference.\n* Relevant documentation.\n\n## Speeding up your pull request\nMerging pull requests takes time. While we always try to merge your pull request as soon as possible, there are certain things you can do to speed up this process.\n\n* Ask developers to review your code changes and post their feedback.\n* Ask users to test your changes and post their feedback.\n* Keep your changes to the minimal required amount, and dedicated to one issue/feature only."
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    {one line to give the program's name and a brief idea of what it does.}\n    Copyright (C) {year}  {name of author}\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    {project}  Copyright (C) {year}  {fullname}\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "README.da.txt",
    "content": "Brug Homey til at styre WiFi-enheder, der forbinder via Xiaomi Mi Home-appen. Du kan også bruge denne app til at styre Xiaomi / Aqara Zigbee-enheder, som er forbundet til en Xiaomi-gateway. Der er ingen begrænsninger for antallet af tilkoblede Zigbee-enheder, da du kan have flere Mi Gateway-enheder og fordele alle Zigbee-enheder mellem dem.\n\nXiaomi understøtter officielt ikke styring af enheder uden for Mi Home-appen. Yderligere trin er nødvendige for at parre disse enheder med Homey, hvilket kræver noget teknisk viden. Det betyder også, at ikke alle tilgængelige enheder er understøttet. Vær også opmærksom på, at Xiaomi kan foretage ændringer i deres økosystem til enhver tid, hvilket kan resultere i, at Homey ikke længere kan styre disse enheder.\n\nBesøg venligst supportsiden for understøttede enheder, installationsvejledninger og yderligere detaljer."
  },
  {
    "path": "README.de.txt",
    "content": "Nutze Homey, um WLAN-Geräte zu steuern, die sich mit der Xiaomi Mi Home-App verbinden. Du kannst diese App auch verwenden, um Xiaomi / Aqara Zigbee-Geräte zu steuern, die mit einem Xiaomi-Gateway verbunden sind. Es gibt keine Einschränkungen hinsichtlich der Anzahl der verbundenen Zigbee-Geräte, da du mehrere Mi Gateway-Geräte haben und alle Zigbee-Geräte zwischen ihnen verteilen kannst.\n\nXiaomi unterstützt offiziell nicht die Steuerung von Geräten außerhalb der Mi Home-App. Zusätzliche Schritte sind erforderlich, um diese Geräte mit Homey zu koppeln, die einige technische Kenntnisse erfordern. Das bedeutet auch, dass nicht alle verfügbaren Geräte unterstützt werden. Sei dir auch bewusst, dass Xiaomi jederzeit Änderungen an seinem Ökosystem vornehmen kann, wodurch Homey diese Geräte möglicherweise nicht mehr steuern kann.\n\nBitte besuche das Support-Thema für unterstützte Geräte, Installationsanweisungen und weitere Details."
  },
  {
    "path": "README.es.txt",
    "content": "Usa Homey para controlar dispositivos WiFi que se conectan a través de la aplicación Xiaomi Mi Home. También puedes usar esta app para controlar dispositivos Zigbee de Xiaomi / Aqara que estén conectados a una puerta de enlace Xiaomi. No hay restricciones en el número de dispositivos Zigbee conectados, ya que puedes tener múltiples dispositivos Mi Gateway y distribuir todos los dispositivos Zigbee entre ellos.\n\nXiaomi no admite oficialmente el control de dispositivos fuera de la aplicación Mi Home. Se requieren pasos adicionales para emparejar estos dispositivos con Homey que requieren algún conocimiento técnico. Esto también significa que no todos los dispositivos disponibles son compatibles. Además, debes tener en cuenta que Xiaomi puede hacer cambios en su ecosistema en cualquier momento, lo que podría resultar en que Homey no pueda controlar estos dispositivos.\n\nPor favor, visita el tema de soporte para conocer los dispositivos compatibles, las instrucciones de instalación y más detalles."
  },
  {
    "path": "README.fr.txt",
    "content": "Utilisez Homey pour contrôler des appareils WiFi qui se connectent via l'application Xiaomi Mi Home. Vous pouvez également utiliser cette application pour contrôler des appareils Zigbee Xiaomi / Aqara connectés à une passerelle Xiaomi. Il n'y a pas de restrictions sur le nombre d'appareils Zigbee connectés, car vous pouvez avoir plusieurs passerelles Mi et répartir tous les appareils Zigbee entre elles.\n\nXiaomi ne prend pas officiellement en charge le contrôle des appareils en dehors de l'application Mi Home. Des étapes supplémentaires sont nécessaires pour jumeler ces appareils avec Homey, ce qui requiert quelques connaissances techniques. Cela signifie également que tous les appareils disponibles ne sont pas pris en charge. Soyez également conscient que Xiaomi peut apporter des modifications à son écosystème à tout moment, ce qui pourrait empêcher Homey de contrôler ces appareils.\n\nVeuillez consulter le sujet de support pour les appareils pris en charge, les instructions d'installation et plus de détails."
  },
  {
    "path": "README.it.txt",
    "content": "Usa Homey per controllare i dispositivi WiFi che si connettono tramite l'app Xiaomi Mi Home. Puoi anche usare questa app per controllare i dispositivi Zigbee Xiaomi / Aqara che sono collegati a un gateway Xiaomi. Non ci sono restrizioni sul numero di dispositivi Zigbee collegati, poiché puoi avere più dispositivi Mi Gateway e distribuire tutti i dispositivi Zigbee tra di loro.\n\nXiaomi non supporta ufficialmente il controllo dei dispositivi al di fuori dell'app Mi Home. Sono necessari passaggi aggiuntivi per collegare questi dispositivi a Homey che richiedono alcune conoscenze tecniche. Significa anche che non tutti i dispositivi disponibili sono supportati. Fai attenzione che Xiaomi può apportare modifiche al suo ecosistema in qualsiasi momento, il che potrebbe impedire a Homey di controllare questi dispositivi.\n\nVisita l'argomento di supporto per i dispositivi supportati, le istruzioni di installazione e ulteriori dettagli."
  },
  {
    "path": "README.ko.txt",
    "content": "Homey를 사용하여 Xiaomi Mi Home 앱에 연결된 WiFi 기기를 제어하세요. 또한 Xiaomi 게이트웨이에 연결된 Xiaomi / Aqara Zigbee 기기를 제어할 수도 있습니다. 여러 Mi 게이트웨이 기기를 사용하여 모든 Zigbee 기기를 분배할 수 있으므로 연결된 Zigbee 기기의 수에 제한이 없습니다.\n\nXiaomi는 공식적으로 Mi Home 앱 외부에서 기기를 제어하는 것을 지원하지 않습니다. 이러한 기기를 Homey와 페어링하는 추가 단계가 필요하며, 이는 약간의 기술 지식이 필요합니다. 또한 모든 기기가 지원되는 것은 아닙니다. Xiaomi는 언제든지 자사 생태계에 변경을 가할 수 있으며, 그 결과 Homey가 이러한 기기를 더 이상 제어할 수 없게 될 수 있습니다.\n\n지원되는 기기, 설치 설명서 및 자세한 내용은 지원 주제를 방문하세요."
  },
  {
    "path": "README.md",
    "content": "# Homey app for Xiaomi Mi Home devices\nUse [Homey](https://www.athom.com/) to control WiFi devices which connect trough the Xiaomi Mi Home app. You can also use this app to control Xiaomi / Aqara Zigbee devices which are connected to a Xiaomi gateway. There are no restrictions to the number of connected Zigbee devices, since you can have multiple Mi Gateway devices and distribute all Zigbee devices between them.\n\n## Important\nXiaomi does not officially support controlling devices from outside the Mi Home app. Additional steps are required for pairing these devices with Homey that require some technical knowledge. It also means not all available devices are supported. Also be aware that Xiaomi can make changes to it's eco system at any time resulting in Homey not being able to control these devices anymore.\n\n## Adding miIO devices\nFor Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. In some cases technical knowledge is needed for retrieving these tokens. See the instructions [here](https://github.com/shaarkys/com.xiaomi-miio/wiki/Obtain-token) on retrieving device tokens.\n\n## (Un)supported devices\nAs mentioned not all available devices are supported. [Here](https://github.com/shaarkys/com.xiaomi-miio/wiki/Supported-Devices) is a list of identified devices that should work. If you want support for a specific device please read [this](https://github.com/jghaanstra/com.xiaomi-miio/wiki/Adding-new-devices).\n\n## Support\nGithub is for bugs and features. If you need support, please use the community support forum and visit the [support topic](https://community.homey.app/t/app-pro-xiaomi-mi-home-app-for-wifi-devices/118) for further details.\n\n## Donations\nI enjoy creating apps for Homey and try to support them as best as I can. If you enjoy using my apps a [donation](https://www.paypal.me/bkubesa) in return for the time I put into this is much appreciated.\n"
  },
  {
    "path": "README.nl.txt",
    "content": "Gebruik Homey om WiFi apparaten te bedienen die verbonden zijn via de Xiaomi Mi Home app. Je kunt deze app ook gebruiken om Xiaomi / Aqara Zigbee apparaten te bedienen die verbonden zijn met een Xiaomi gateway. Er zijn geen beperkingen aan het aantal verbonden Zigbee apparaten, aangezien je meerdere Mi Gateway apparaten kunt hebben en alle Zigbee apparaten tussen hen kunt verdelen.\n\nXiaomi ondersteunt officieel niet het bedienen van apparaten buiten de Mi Home app. Er zijn extra stappen nodig voor het koppelen van deze apparaten met Homey, wat enige technische kennis vereist. Dit betekent ook dat niet alle beschikbare apparaten worden ondersteund. Houd er ook rekening mee dat Xiaomi veranderingen kan doorvoeren in zijn ecosysteem, waardoor Homey deze apparaten mogelijk niet meer kan bedienen.\n\nBezoek het supporttopic voor ondersteunde apparaten, installatie instructies en meer details."
  },
  {
    "path": "README.no.txt",
    "content": "Bruk Homey for å kontrollere WiFi-enheter som kobler seg til via Xiaomi Mi Home-appen. Du kan også bruke denne appen til å kontrollere Xiaomi / Aqara Zigbee-enheter som er koblet til en Xiaomi-gateway. Det er ingen begrensninger på antall tilkoblede Zigbee-enheter, siden du kan ha flere Mi Gateway-enheter og fordele alle Zigbee-enheter mellom dem.\n\nXiaomi støtter ikke offisielt kontroll av enheter utenfor Mi Home-appen. Ekstra trinn er nødvendig for å pare disse enhetene med Homey, noe som krever teknisk innsikt. Det betyr også at ikke alle tilgjengelige enheter støttes. Vær også oppmerksom på at Xiaomi kan endre sitt økosystem når som helst, noe som kan resultere i at Homey ikke lenger kan kontrollere disse enhetene.\n\nBesøk støttesiden for informasjon om støttede enheter, installasjonsinstruksjoner og ytterligere detaljer."
  },
  {
    "path": "README.pl.txt",
    "content": "Użyj Homey do sterowania urządzeniami WiFi, które łączą się przez aplikację Xiaomi Mi Home. Możesz także używać tej aplikacji do sterowania urządzeniami Xiaomi / Aqara Zigbee, które są podłączone do bramki Xiaomi. Nie ma żadnych ograniczeń co do liczby podłączonych urządzeń Zigbee, ponieważ możesz mieć wiele urządzeń Mi Gateway i rozdzielić między nimi wszystkie urządzenia Zigbee.\n\nXiaomi nie wspiera oficjalnie sterowania urządzeniami spoza aplikacji Mi Home. Do sparowania tych urządzeń z Homey wymagane są dodatkowe kroki, które wymagają pewnej wiedzy technicznej. Oznacza to również, że nie wszystkie dostępne urządzenia są obsługiwane. Pamiętaj też, że Xiaomi może w każdej chwili wprowadzić zmiany w swoim ekosystemie, co może skutkować tym, że Homey nie będzie już w stanie sterować tymi urządzeniami.\n\nOdwiedź temat wsparcia, aby uzyskać informacje o obsługiwanych urządzeniach, instrukcjach instalacji i dalszych szczegółach."
  },
  {
    "path": "README.ru.txt",
    "content": "Используйте Homey для управления WiFi устройствами, которые подключаются через приложение Xiaomi Mi Home. Вы также можете использовать это приложение для управления Zigbee устройствами Xiaomi / Aqara, которые подключены к Xiaomi шлюзу. Ограничений на количество подключенных Zigbee устройств нет, так как вы можете использовать несколько Mi шлюзов и распределять все Zigbee устройства между ними.\n\nXiaomi официально не поддерживает управление устройствами вне приложения Mi Home. Для сопряжения этих устройств с Homey требуются дополнительные шаги, которые требуют некоторого технического знания. Это также означает, что не все доступные устройства поддерживаются. Кроме того, имейте в виду, что Xiaomi может внести изменения в свою экосистему в любое время, что может привести к невозможности управления этими устройствами с помощью Homey.\n\nПожалуйста, посетите тему поддержки для получения информации о поддерживаемых устройствах, инструкций по установке и дальнейших деталей."
  },
  {
    "path": "README.sv.txt",
    "content": "Använd Homey för att styra WiFi-enheter som ansluter via Xiaomi Mi Home-appen. Du kan också använda denna app för att styra Xiaomi / Aqara Zigbee-enheter som är anslutna till en Xiaomi-gateway. Det finns inga begränsningar för antalet anslutna Zigbee-enheter, eftersom du kan ha flera Mi Gateway-enheter och distribuera alla Zigbee-enheter mellan dem.\n\nXiaomi stöder inte officiellt att styra enheter utanför Mi Home-appen. Ytterligare steg krävs för att para ihop dessa enheter med Homey som kräver viss teknisk kunskap. Det innebär också att inte alla tillgängliga enheter stöds. Var också medveten om att Xiaomi kan göra förändringar i sitt ekosystem när som helst, vilket kan resultera i att Homey inte längre kan styra dessa enheter.\n\nBesök supportämnet för stödda enheter, installationsinstruktioner och ytterligare detaljer."
  },
  {
    "path": "README.txt",
    "content": "Use Homey to control WiFi devices which connect trough the Xiaomi Mi Home app. You can also use this app to control Xiaomi / Aqara Zigbee devices which are connected to a Xiaomi gateway. There are no restrictions to the number of connected Zigbee devices, since you can have multiple Mi Gateway devices and distribute all Zigbee devices between them.\n\nXiaomi does not officially support controlling devices from outside the Mi Home app. Additional steps are required for pairing these devices with Homey that require some technical knowledge. It also means not all available devices are supported. Also be aware that Xiaomi can make changes to it's eco system at any time resulting in Homey not being able to control these devices anymore.\n\nPlease visit the support topic for supported devices, installation instructions and further details."
  },
  {
    "path": "api.js",
    "content": "'use strict';\n\nmodule.exports = {\n  async generate({homey, body}) {\n    const result = await homey.app.generate(body);\n    return result;\n  },\n  async testConnection({homey, body}) {\n    const result = await homey.app.testConnection(body);\n    return result;\n  },\n  async getGateways({homey, body}) {\n    const result = await homey.app.getGateways();\n    return result;\n  }\n}"
  },
  {
    "path": "app.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst miio = require(\"miio\");\nconst MiHub = require(\"./lib/MiHub\");\n\nclass XiaomiMiioApp extends Homey.App {\n\n  async onInit() {\n    this.log(\"Initializing Xiaomi Mi Home app ...\");\n\n    this.homey.setTimeout(() => {\n      const browser = miio.browse({ cacheTime: 10  }); // little trick in an attempt to avoid command caching\n      browser.on('available', device => {\n        this.log('Discovered device on '+ device.address +' with device id '+ device.id);\n      });\n    }, 2000);\n\n    // INITIALIZE GATEWAY MODULE\n    this.mihub = new MiHub({log: this.log, homey: this.homey});\n    this.onSettingsChanged = this.onSettingsChanged.bind(this);\n    this.homey.settings.on('set', this.onSettingsChanged);\n    this.homey.settings.on('unset', this.onSettingsChanged);\n\n    // GENERIC CARDS\n    this.homey.flow.getActionCard('enableLED')\n      .registerRunListener(async (args) => {\n        try {\n          if (args.device.deviceProperties.hasOwnProperty('device_properties')) {\n            if (args.device.deviceProperties.device_properties.hasOwnProperty('light')) {\n              return await args.device.miio.call(\"set_properties\", [{ siid: args.device.deviceProperties.set_properties.light.siid, piid: args.device.deviceProperties.set_properties.light.piid, value: Number(args.led) === 1 ? args.device.deviceProperties.device_properties.light.max : args.device.deviceProperties.device_properties.light.min }], { retries: 1 });\n            }\n          } else {\n            return await args.device.miio.call(\"set_properties\", [{ siid: args.device.deviceProperties.set_properties.light.siid, piid: args.device.deviceProperties.set_properties.light.piid, value: Number(args.led) === 1 ? true : false }], { retries: 1 });\n          }\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('enableBuzzer')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.miio.call(\"set_properties\", [{ siid: args.device.deviceProperties.set_properties.buzzer.siid, piid: args.device.deviceProperties.set_properties.buzzer.piid, value: Number(args.sound) === 1 ? true : false }], { retries: 1 });\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    // VACUUMS\n    this.homey.flow.getActionCard('findVacuum')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.miio.find();\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('vacuumRoborockPause')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.miio.pause();\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('fanPowerVacuum')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.miio.changeFanSpeed(Number(args.fanspeed));\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('vacuumRoborockFanspeed')\n      .registerRunListener(async (args) => {\n        try {\n          if (args.device.hasCapability('vacuum_roborock_fanspeed')) {\n            return await args.device.triggerCapabilityListener('vacuum_roborock_fanspeed', args.fanspeed);\n          } else {\n            return await args.device.miio.changeFanSpeed(Number(args.fanspeed));\n          }\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('vacuumRoborockMopIntensity')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.miio.setWaterBoxMode(Number(args.intensity));\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n    \n    this.homey.flow.getActionCard('vacuumRoborockMopVacuumMode')\n      .registerRunListener(async (args) => {\n        try {\n          if (args.device.hasCapability('vacuum_roborock_fanspeed')) {\n            await args.device.triggerCapabilityListener('vacuum_roborock_fanspeed', args.fanspeed);\n          } else {\n            await args.device.miio.changeFanSpeed(Number(args.fanspeed));\n          }\n          await args.device.miio.setWaterBoxMode(Number(args.mop));\n          switch (args.mode) {\n            case \"sweep\":\n              return await args.device.miio.call(\"action\", { siid: 2, aiid: 1, did: \"call-2-1\", in: [] }, { retries: 1 });\n            case \"mop\":\n              return await args.device.miio.call(\"action\", { siid: 2, aiid: 4, did: \"call-2-4\", in: [] }, { retries: 1 });\n            case \"sweep-mop\":\n              return await args.device.miio.call(\"action\", { siid: 2, aiid: 5, did: \"call-2-5\", in: [] }, { retries: 1 });\n            default:\n              break;\n          }\n\n          return await args.device.miio.setWaterBoxMode(Number(args.intensity));\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('vacuumDreameFanspeed')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('vacuum_dreame_fanspeed', args.fanspeed);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('vacuumRoidmiFanspeed')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('vacuum_roidmi_fanspeed', args.fanspeed);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('vacuumRoidmiMopMode')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('vacuum_roidmi_mop_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('vacuumXiaomiMopMode')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('vacuum_xiaomi_mop_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('vacuumDreameMopIntensity')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('vacuum_dreame_mop_intensity', args.intensity);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('goToTargetVacuum')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.miio.sendToLocation(args.xcoordinate, args.ycoordinate);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('cleanZoneVacuum')\n      .registerRunListener(async (args) => {\n        try {\n          const zones = JSON.parse(\"[\" + args.zones + \"]\");\n          return await args.device.miio.cleanZones(zones);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('vacuumRoomCleaning')\n      .registerRunListener(async (args) => {\n        try {\n          if (args.device.getStoreValue('model').startsWith('dreame.vacuum')) {\n            const rooms = JSON.stringify([{\"piid\":1,\"value\":18},{\"piid\":10,\"value\":\"{\\\"selects\\\":[[\"+ args.rooms +\"]]}\"}]).replace(/\\\\\"/g, '\"'); // doesnt work\n            return await args.device.miio.call(\"action\", { siid: 2, aiid: 3, did: \"call-2-3\", in: rooms }, { retries: 1 });\n          } else {\n            const rooms = JSON.parse(\"[\" + args.rooms + \"]\");\n            return await args.device.miio.cleanRooms(rooms);\n            //return await args.device.miio.call(\"app_segment_clean\",  [{\"segments\": rooms, \"repeat\": repeats}], { retries: 1 });\n          }\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('vacuumRoomCleaningRepeats')\n      .registerRunListener(async (args) => {\n        try {\n          const rooms = JSON.parse(\"[\" + args.rooms + \"]\");\n          return await args.device.miio.call(\"app_segment_clean\",  [{\"segments\": rooms, \"repeat\": args.repeats}], { retries: 1 });\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('modeVacuumMop')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('vacuum_mop_mode',args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });    \n\n    // AIR PURIFIER\n    this.homey.flow.getActionCard('modeAirpurifier')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('airpurifier_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('modeAirpurifierV7')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('airpurifier_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('airpurifierSetFavorite')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.miio.setFavoriteLevel(Number(args.favorite));\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('airpurifierZhimiMode')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('airpurifier_zhimi_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('airpurifierZhimiFanlevel')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('airpurifier_zhimi_fanlevel', args.fanlevel);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('airpurifierXiaomiFanlevel')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('airpurifier_xiaomi_fanlevel', args.fanlevel);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    // AIR PURIFIER, HUMIDIFIER, DEHUMIDIFIER\n    this.homey.flow.getActionCard('humidifierZhimiMode')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('humidifier_zhimi_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('humidifierZhimiModeMIoT')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('humidifier_zhimi_mode_miot', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('humidifierXiaomiMode')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('humidifier_xiaomi_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n    \n    this.homey.flow.getActionCard('modeHumidifierDeerma')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('humidifier_deerma_jsq_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('modeZhimiAirfresh')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('airpurifier_zhimi_airfresh_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('modeHumidifierLeshowJSQ1')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('humidifier_leshow_jsq1_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('modeDiffuserXwhzp')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('diffuser_xwhzp_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('modeDehumidifierDmaker')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('dehumidifier_dmaker_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    // PET WATERDISPENSER & FEEDER\n\n    this.homey.flow.getActionCard('petwaterdispenserMmggMode')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('petwaterdispenser_mmgg_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('petfeederServeFood')\n      .registerRunListener(async (args) => {\n        try {\n          const servingsArg = args.servings ?? args.portions;\n          const portions = Math.max(1, Math.min(30, Math.round(Number(servingsArg) || 0)));\n          if (typeof args.device?.servePortions === 'function') {\n            return await args.device.servePortions(portions);\n          }\n          const legacyAction = args.device?.deviceProperties?.set_properties?.serve_food;\n          if (legacyAction) {\n            return await args.device.miio.call('action', legacyAction, { retries: 1 });\n          }\n          throw new Error('Manual feeding not supported by this device');\n        } catch (error) {\n          return Promise.reject(error.message || error);\n        }\n      });\n\n    this.homey.flow.getActionCard('petfeederDisplaySchedule')\n      .registerRunListener(async (args) => {\n        try {\n          if (typeof args.device?.setDisplaySchedule !== 'function') {\n            throw new Error('Display control not supported by this device');\n          }\n          const enabled =\n            args.enabled === true ||\n            args.enabled === 'true' ||\n            args.enabled === 1 ||\n            args.enabled === '1';\n          await args.device.setDisplaySchedule(enabled);\n          return true;\n        } catch (error) {\n          return Promise.reject(error.message || error);\n        }\n      });\n\n    this.homey.flow.getActionCard('petfeederCalibrate')\n      .registerRunListener(async (args) => {\n        try {\n          if (typeof args.device?.calibrateScale !== 'function') {\n            throw new Error('Calibration not supported by this device');\n          }\n          await args.device.calibrateScale();\n          return true;\n        } catch (error) {\n          return Promise.reject(error.message || error);\n        }\n      });\n\n    // AIR PURIFIER, ZHIMI FAN\n    this.homey.flow.getActionCard('ledAirpurifierHumidifier')\n      .registerRunListener(async (args) => {\n        try {\n          if (args.device.hasCapability('airpurifier_mode')) {\n            return await args.device.miio.call('set_led', [args.brightness === \"3\" ? \"off\" : \"on\"], { retries: 1 });\n          } else {\n            return await args.device.miio.call('set_led_b', [Number(args.brightness)], { retries: 1 });\n          }     \n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    // HEATERS\n    this.homey.flow.getActionCard('heaterZhimiTargetTemperature')\n      .registerRunListener(async (args) => {\n        try {\n          if (args.device.hasCapability('heater_zhimi_heater_target_temperature')) {\n            return await args.device.triggerCapabilityListener('heater_zhimi_heater_target_temperature', Number(args.temperature));\n          }          \n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('heaterZhimiOscillation')\n      .registerRunListener(async (args) => {\n        try {\n          if (args.device.hasCapability('heater_zhimi_oscillation')) {\n            return await args.device.triggerCapabilityListener('heater_zhimi_oscillation', Number(args.oscillation));\n          }          \n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('heaterZhimiHeatlevel')\n      .registerRunListener(async (args) => {\n        try {\n          if (args.device.hasCapability('heater_zhimi_heatlevel')) {\n            return await args.device.triggerCapabilityListener('heater_zhimi_heatlevel', Number(args.heatlevel));\n          }          \n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    // FANS\n    this.homey.flow.getActionCard('modeDmakerFan')\n      .registerRunListener(async (args) => {\n        try {\n          await args.device.miio.changeMode(args.mode);\n          return await args.device.setStoreValue(\"mode\", args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('changeSpeed')\n      .registerRunListener(async (args) => {\n        try {\n          await args.device.miio.changeSpeed(args.speed);\n          return await args.device.setStoreValue(\"speed\", args.speed);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('enableAngle')\n      .registerRunListener(async (args) => {\n        try {\n          if (args.device.hasCapability('onoff.swing')) {\n            return await args.device.triggerCapabilityListener('onoff.swing', args.oscillation == 'on');\n          } else {\n            return await args.device.miio.enableAngle(args.oscillation);\n          }\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('setAngle')\n      .registerRunListener(async (args) => {\n        try {\n          if (args.device.hasCapability('fan_zhimi_angle')) {\n            return await args.device.triggerCapabilityListener('fan_zhimi_angle', args.angle);\n          } else {\n            return await args.device.miio.changeAngle(Number(args.angle));\n          }\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('enableChildLock')\n      .registerRunListener(async (args) => {\n        try {\n          if (args.device.getStoreValue('model') === 'zhimi.fan.za5') {\n            return await args.device.miio.call(\"set_properties\", [{ siid: 3, piid: 1, value: args.childlock == \"on\" }], { retries: 1 });\n          } else {\n            return await args.device.miio.changeChildLock(args.childlock);\n          }\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('fanDmakerMode')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('fan_dmaker_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('fanZhimiMode')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.triggerCapabilityListener('fan_zhimi_mode', args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    // PHILIPS EYECARE\n    this.homey.flow.getActionCard('enableEyecare')\n      .registerRunListener(async (args) => {\n        try {\n          const eyecare = args.eyecare == \"on\" ? true : false;\n          return await args.device.triggerCapabilityListener('onoff.eyecare', eyecare);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('modeEyecare')\n      .registerRunListener(async (args) => {\n        try {\n          await args.device.miio.mode(args.mode);\n          return await args.device.setStoreValue(\"mode\", args.mode);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    /* aqara-ctrl-ln2, aqara-ctrl-neutral2 & relay_c2acn01  */\n    this.homey.flow.getConditionCard('rightSwitch')\n      .registerRunListener(async (args) => {\n        if (args.device) {\n          return args.device.getCapabilityValue(\"onoff.1\");\n        } else {\n          return false;\n        }\n      })\n\n    this.homey.flow.getActionCard('rightSwitchOn')\n      .registerRunListener(async (args) => {\n        try {\n          return await this.mihub.sendWrite(args.device.data.sid, { channel_1: \"on\" });\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('rightSwitchOff')\n      .registerRunListener(async (args) => {\n        try {\n          return await this.mihub.sendWrite(args.device.data.sid, { channel_1: \"off\" });\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('rightSwitchToggle')\n      .registerRunListener(async (args) => {\n        try {\n          return await this.mihub.sendWrite(args.device.data.sid, { channel_1: \"toggle\" });\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n    \n    this.homey.flow.getConditionCard('leftSwitch')\n      .registerRunListener(async (args) => {\n        if (args.device) {\n          return args.device.getCapabilityValue(\"onoff.0\");\n        } else {\n          return false;\n        }\n      })\n\n    this.homey.flow.getActionCard('leftSwitchOn')\n      .registerRunListener(async (args) => {\n        try {\n          return await this.mihub.sendWrite(args.device.data.sid, { channel_0: \"on\" });\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('leftSwitchOff')\n      .registerRunListener(async (args) => {\n        try {\n          return await this.mihub.sendWrite(args.device.data.sid, { channel_0: \"off\" });\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('leftSwitchToggle')\n      .registerRunListener(async (args) => {\n        try {\n          return await this.mihub.sendWrite(args.device.data.sid, { channel_0: \"toggle\" });\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    /* Mi / Aqara Humidity & Temperature sensor */\n    this.homey.flow.getConditionCard('measure_humidity_between')\n      .registerRunListener(async (args) => {\n        if (args.device) {\n          let value1, value2;\n          if (args.value1 < args.value2) {\n            value1 = args.value1;\n            value2 = args.value2;\n          } else {\n            value1 = args.value2;\n            value2 = args.value1;\n          }\n          return await args.device.getCapabilityValue('measure_humidity') >= value1 && args.device.getCapabilityValue('measure_humidity') <= value2;\n        } else {\n          return false;\n        }\n      })\n\n    this.homey.flow.getConditionCard('measure_temperature_between')\n      .registerRunListener(async (args) => {\n        if (args.device) {\n          let value1, value2;\n          if (args.value1 < args.value2) {\n            value1 = args.value1;\n            value2 = args.value2;\n          } else {\n            value1 = args.value2;\n            value2 = args.value1;\n          }\n          return await args.device.getCapabilityValue('measure_temperature') >= value1 && args.device.getCapabilityValue('measure_temperature') <= value2;\n        } else {\n          return false;\n        }\n      })\n\n    // GATEWAY\n    this.homey.flow.getActionCard('gateway_play_radio')\n      .registerRunListener(async (args) => {\n        try {\n          const settings = args.device.getSettings();\n          let volume = parseInt(args.volume * 100);\n          let favoriteListsID = settings[`favorite${args.favoriteID}ID`];\n          let favoriteListsIDArray = favoriteListsID.split(\",\");\n\n          if (favoriteListsIDArray[0] !== undefined && favoriteListsIDArray[0] !== null && favoriteListsIDArray[1] !== undefined && favoriteListsIDArray[1] !== null) {\n            let ids = favoriteListsIDArray[0];\n            ids = ids.replace(/\\s/g, \"\");\n            let id = parseInt(ids);\n            let urls = favoriteListsIDArray[1];\n            urls = urls.replace(/\\s/g, \"\");\n            let url = urls.toString();\n\n            await args.device.miio.call(\"play_specify_fm\", { id: id, type: 0, url: url }, { retries: 1 });\n            await args.device.miio.call(\"volume_ctrl_fm\", [volume.toString()], { retries: 1 });\n\n          }\n          return Promise.resolve(true);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('gateway_custom_radio')\n      .registerRunListener(async (args) => {\n        try {\n          let volume = parseInt(args.volume * 100);\n          await args.device.miio.call(\"play_specify_fm\", { id: parseInt(args.id), type: 0, url: args.url }, { retries: 1 });\n          await args.device.miio.call(\"volume_ctrl_fm\", [volume.toString()], { retries: 1 });\n          return Promise.resolve(true);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('gateway_play_effect')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.miio.call(\"welcome\", [parseInt(args.toneID)], { retries: 1 });\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n    this.homey.flow.getActionCard('gateway_set_volume')\n      .registerRunListener(async (args) => {\n        try {\n          let volume = parseInt(args.volume * 100);\n          switch (args.target) {\n            case \"alarm\":\n              return await args.device.miio.call(\"set_alarming_volume\", [volume], { retries: 1 });\n            case \"doorbell\":\n              return await args.device.miio.call(\"set_doorbell_volume\", [volume], { retries: 1 });\n            case \"prompt\":\n              return await args.device.miio.call(\"set_gateway_volume\", [volume], { retries: 1 });\n            case \"radio\":\n              return await args.device.miio.call(\"volume_ctrl_fm\", [volume.toString()], { retries: 1 });\n          }\n          return Promise.resolve(true);\n        } catch (error) {\n          return Promise.reject(error);\n        }\n      });\n\n    // REMOTE\n    this.homey.flow.getActionCard('remote_send_ir_code')\n      .registerRunListener(async (args) => {\n        try {\n          return await args.device.sendIrCode(args.code);\n        } catch (error) {\n          return Promise.reject(error.message);\n        }\n      });\n\n  }\n\n  /* update settings (gatewaysList) */\n  async onSettingsChanged(key) {\n    switch (key) {\n      case \"gatewaysList\":\n        this.mihub.updateGateways(this.homey.settings.get(\"gatewaysList\"));\n        break;\n      default:\n        break;\n    }\n  }\n\n  /* generate a gateway developer key */\n  async generate(args) {\n    try {\n      const key = await this.generateKey();\n      const device = await miio.device({ address: args.ip, token: args.token });\n      const info = await device.call(\"miIO.info\");\n      const returnKey = await device.call(\"set_lumi_dpf_aes_key\", [key]); \n      return Promise.resolve({ status: \"OK\", mac: info.mac.replace(/\\:/g, \"\").toLowerCase(), password: key });\n    } catch (error) {\n      this.error(error);\n      return Promise.reject(error);\n    }\n  }\n\n  /* helper for generating a key */\n  async generateKey() {\n    const chars = \"0123456789ABCDEF\";\n    let result = \"\";\n    for (let i = 0; i < 16; i++) {\n      let idx = Math.floor(Math.random() * chars.length);\n      result += chars[idx];\n    }\n    return result;\n  }\n\n  /* test the connection to a device */\n  async testConnection(args) {\n    try {\n      const device = await miio.device({ address: args.ip, token: args.token });\n      const info = await device.call(\"miIO.info\");\n      return Promise.resolve({status: \"OK\", info});\n    } catch (error) {\n      return Promise.reject(error);\n    }\n  }\n\n  /* return the gateways */\n  async getGateways() {\n    return Promise.resolve(this.mihub.gateways);\n  }\n\n}\n\nmodule.exports = XiaomiMiioApp;\n"
  },
  {
    "path": "app.json",
    "content": "{\n  \"_comment\": \"This file is generated. Please edit .homeycompose/app.json instead.\",\n  \"id\": \"com.xiaomi-miio\",\n  \"sdk\": 3,\n  \"brandColor\": \"#FF6801\",\n  \"name\": {\n    \"en\": \"Xiaomi Mi Home\",\n    \"nl\": \"Xiaomi Mi Home\",\n    \"da\": \"Xiaomi Mi Home\",\n    \"de\": \"Xiaomi Mi Home\",\n    \"es\": \"Xiaomi Mi Home\",\n    \"fr\": \"Xiaomi Mi Home\",\n    \"it\": \"Xiaomi Mi Home\",\n    \"no\": \"Xiaomi Mi Home\",\n    \"sv\": \"Xiaomi Mi Home\",\n    \"pl\": \"Xiaomi Mi Home\",\n    \"ru\": \"Xiaomi Mi Home\",\n    \"ko\": \"Xiaomi Mi Home\"\n  },\n  \"tags\": {\n    \"en\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"vacuumcleaner\",\n      \"robot\",\n      \"purifier\",\n      \"humidifier\",\n      \"philips\",\n      \"eyecare\",\n      \"powerplug\",\n      \"gateway\"\n    ],\n    \"nl\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi home\",\n      \"miio\",\n      \"stofzuiger\",\n      \"robot\",\n      \"luchtreiniger\",\n      \"luchtbevochtiger\",\n      \"philips\",\n      \"eyecare\",\n      \"powerplug\",\n      \"gateway\"\n    ],\n    \"da\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"støvsuger\",\n      \"robot\",\n      \"luftrenser\",\n      \"luftfugter\",\n      \"philips\",\n      \"eyecare\",\n      \"stikdåse\",\n      \"gateway\"\n    ],\n    \"de\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"Staubsauger\",\n      \"Roboter\",\n      \"Luftreiniger\",\n      \"Luftbefeuchter\",\n      \"Philips\",\n      \"eyecare\",\n      \"Steckdose\",\n      \"Gateway\"\n    ],\n    \"es\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"aspiradora\",\n      \"robot\",\n      \"purificador\",\n      \"humidificador\",\n      \"philips\",\n      \"eyecare\",\n      \"enchufe\",\n      \"portal\"\n    ],\n    \"fr\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"aspirateur\",\n      \"robot\",\n      \"purificateur\",\n      \"humidificateur\",\n      \"philips\",\n      \"eyecare\",\n      \"prise\",\n      \"passerelle\"\n    ],\n    \"it\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"aspirapolvere\",\n      \"robot\",\n      \"purificatore\",\n      \"umidificatore\",\n      \"philips\",\n      \"eyecare\",\n      \"presa\",\n      \"gateway\"\n    ],\n    \"no\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"støvsuger\",\n      \"robot\",\n      \"luftrenser\",\n      \"luftfukter\",\n      \"philips\",\n      \"eyecare\",\n      \"strømplugg\",\n      \"gateway\"\n    ],\n    \"sv\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"dammsugare\",\n      \"robot\",\n      \"luftrenare\",\n      \"luftfuktare\",\n      \"philips\",\n      \"eyecare\",\n      \"strömuttag\",\n      \"gateway\"\n    ],\n    \"pl\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"odkurzacz\",\n      \"robot\",\n      \"oczyszczacz\",\n      \"nawilżacz\",\n      \"philips\",\n      \"eyecare\",\n      \"gniazdko\",\n      \"bramka\"\n    ],\n    \"ru\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"пылесос\",\n      \"робот\",\n      \"очиститель\",\n      \"увлажнитель\",\n      \"philips\",\n      \"eyecare\",\n      \"разъем питания\",\n      \"шлюз\"\n    ],\n    \"ko\": [\n      \"Xiaomi\",\n      \"Mi\",\n      \"Mi Home\",\n      \"miio\",\n      \"진공청소기\",\n      \"로봇\",\n      \"공기청정기\",\n      \"가습기\",\n      \"philips\",\n      \"eyecare\",\n      \"전원플러그\",\n      \"게이트웨이\"\n    ]\n  },\n  \"version\": \"3.4.72\",\n  \"compatibility\": \">=12.2.0\",\n  \"platforms\": [\n    \"local\"\n  ],\n  \"author\": {\n    \"name\": \"Bretislav Kubesa\"\n  },\n  \"contributing\": {\n    \"donate\": {\n      \"paypal\": {\n        \"username\": \"bkubesa\"\n      }\n    }\n  },\n  \"contributors\": {\n    \"developers\": [\n      {\n        \"name\": \"Maxmudjon\"\n      },\n      {\n        \"name\": \"Jelger Haanstra\"\n      }\n    ]\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/shaarkys/com.xiaomi-miio/issues\"\n  },\n  \"homeyCommunityTopicId\": 118,\n  \"source\": \"https://github.com/shaarkys/com.xiaomi-miio\",\n  \"homepage\": \"https://community.athom.com/t/118\",\n  \"support\": \"https://community.homey.app/t/app-pro-xiaomi-mi-home-app/118/1770?u=sharkys\",\n  \"images\": {\n    \"large\": \"./assets/images/large.jpg\",\n    \"small\": \"./assets/images/small.jpg\"\n  },\n  \"category\": \"appliances\",\n  \"description\": {\n    \"en\": \"Control Xiaomi Mi Home devices using Homey\",\n    \"nl\": \"Bedien Xiaomi Mi Home apparaten via Homey\",\n    \"da\": \"Styr Xiaomi Mi Home enheder med Homey\",\n    \"de\": \"Steuere Xiaomi Mi Home Geräte mit Homey\",\n    \"es\": \"Controla dispositivos Xiaomi Mi Home con Homey\",\n    \"fr\": \"Contrôlez les appareils Xiaomi Mi Home avec Homey\",\n    \"it\": \"Controlla i dispositivi Xiaomi Mi Home con Homey\",\n    \"no\": \"Kontroller Xiaomi Mi Home-enheter med Homey\",\n    \"sv\": \"Styr Xiaomi Mi Home-enheter med Homey\",\n    \"pl\": \"Steruj urządzeniami Xiaomi Mi Home za pomocą Homey\",\n    \"ru\": \"Управляйте устройствами Xiaomi Mi Home с Homey\",\n    \"ko\": \"Homey를 사용하여 Xiaomi Mi Home 장치를 제어하세요\"\n  },\n  \"dependencies\": {\n    \"net\": \"*\"\n  },\n  \"api\": {\n    \"generate\": {\n      \"method\": \"post\",\n      \"path\": \"/generate\",\n      \"public\": false\n    },\n    \"testConnection\": {\n      \"method\": \"post\",\n      \"path\": \"/testConnection\",\n      \"public\": false\n    },\n    \"getGateways\": {\n      \"method\": \"get\",\n      \"path\": \"/getGateways\",\n      \"public\": false\n    },\n    \"removeChildDevice\": {\n      \"method\": \"post\",\n      \"path\": \"/removeChildDevice\",\n      \"public\": false\n    }\n  },\n  \"flow\": {\n    \"triggers\": [\n      {\n        \"id\": \"alert_cube\",\n        \"title\": {\n          \"en\": \"Alert\",\n          \"nl\": \"Waarschuwing\",\n          \"da\": \"Alarm\",\n          \"de\": \"Alarm\",\n          \"es\": \"Alerta\",\n          \"fr\": \"Alerte\",\n          \"it\": \"Allarme\",\n          \"no\": \"Varsel\",\n          \"sv\": \"Varning\",\n          \"pl\": \"Alarm\",\n          \"ru\": \"Оповещение\",\n          \"ko\": \"경고\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionnez l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-aqara-cube\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"alertVacuum\",\n        \"title\": {\n          \"en\": \"Consumable Alert\",\n          \"nl\": \"Verbruiksartikel waarschuwing\",\n          \"da\": \"Forbrugsalarm\",\n          \"de\": \"Verbrauchsmaterial-Warnung\",\n          \"es\": \"Alerta de consumibles\",\n          \"fr\": \"Alerte de consommable\",\n          \"it\": \"Allarme consumabile\",\n          \"no\": \"Forbruksvarsel\",\n          \"sv\": \"Förbrukningsalarm\",\n          \"pl\": \"Alert materiałów eksploatacyjnych\",\n          \"ru\": \"Оповещение о расходных материалах\",\n          \"ko\": \"소모품 경고\"\n        },\n        \"tokens\": [\n          {\n            \"name\": \"consumable\",\n            \"type\": \"string\",\n            \"title\": {\n              \"en\": \"consumable\",\n              \"nl\": \"verbruiksartikel\",\n              \"da\": \"forbrugbar\",\n              \"de\": \"Verbrauchsmaterial\",\n              \"es\": \"consumible\",\n              \"fr\": \"consommable\",\n              \"it\": \"consumabile\",\n              \"no\": \"forbrukbar\",\n              \"sv\": \"förbrukningsvara\",\n              \"pl\": \"materiał eksploatacyjny\",\n              \"ru\": \"расходный материал\",\n              \"ko\": \"소모품\"\n            },\n            \"example\": \"filter\"\n          },\n          {\n            \"name\": \"value\",\n            \"type\": \"string\",\n            \"title\": {\n              \"en\": \"value\",\n              \"nl\": \"waarde\",\n              \"da\": \"værdi\",\n              \"de\": \"Wert\",\n              \"es\": \"valor\",\n              \"fr\": \"valeur\",\n              \"it\": \"valore\",\n              \"no\": \"verdi\",\n              \"sv\": \"värde\",\n              \"pl\": \"wartość\",\n              \"ru\": \"значение\",\n              \"ko\": \"값\"\n            },\n            \"example\": \"10%\"\n          }\n        ],\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer stofzuiger\",\n              \"da\": \"Vælg støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccionar aspiradora\",\n              \"fr\": \"Sélectionner l'aspirateur\",\n              \"it\": \"Selezionare aspirapolvere\",\n              \"no\": \"Velg støvsuger\",\n              \"sv\": \"Välj dammsugare\",\n              \"pl\": \"Wybierz odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"진공청소기 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced|vacuum_dreame_vacuum|vacuum_viomi_vacuum_v7|vacuum_mija_vacuum_miot|vacuum_roidmi_vacuum_miot|vacuum_xiaomi_vacuum_max\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"click_double\",\n        \"title\": {\n          \"en\": \"Double Click\",\n          \"nl\": \"Dubbelklik\",\n          \"da\": \"Dobbeltklik\",\n          \"de\": \"Doppelklick\",\n          \"es\": \"Doble clic\",\n          \"fr\": \"Double-clic\",\n          \"it\": \"Doppio clic\",\n          \"no\": \"Dobbeltklikk\",\n          \"sv\": \"Dubbelklick\",\n          \"pl\": \"Podwójne kliknięcie\",\n          \"ru\": \"Двойной щелчок\",\n          \"ko\": \"더블 클릭\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-button|aqara-button|aqara-button-advanced|aqara-86sw1-advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"click_double_left\",\n        \"title\": {\n          \"en\": \"Left Double Click\",\n          \"nl\": \"Dubbel klik links\",\n          \"da\": \"Dobbeltklik til venstre\",\n          \"de\": \"Doppelklick links\",\n          \"es\": \"Doble clic izquierdo\",\n          \"fr\": \"Double clic gauche\",\n          \"it\": \"Doppio clic sinistro\",\n          \"no\": \"Dobbeltklikk venstre\",\n          \"sv\": \"Dubbelklick vänster\",\n          \"pl\": \"Podwójne kliknięcie lewym\",\n          \"ru\": \"Двойной клик левой кнопкой\",\n          \"ko\": \"왼쪽 더블 클릭\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Selecciona dispositivo\",\n              \"fr\": \"Sélectionner le périphérique\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-86sw2-advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"click_double_right\",\n        \"title\": {\n          \"en\": \"Right Double Click\",\n          \"nl\": \"Dubbel klik rechts\",\n          \"da\": \"Højre Dobbeltklik\",\n          \"de\": \"Rechts Doppelklick\",\n          \"es\": \"Doble Clic Derecho\",\n          \"fr\": \"Double Clic Droit\",\n          \"it\": \"Doppio Clic Destro\",\n          \"no\": \"Høyre Dobbeltklikk\",\n          \"sv\": \"Höger Dubbelklick\",\n          \"pl\": \"Podwójne Kliknięcie Prawym\",\n          \"ru\": \"Правый Двойной Щелчок\",\n          \"ko\": \"오른쪽 더블 클릭\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-86sw2-advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"click_long\",\n        \"title\": {\n          \"en\": \"Long Click\",\n          \"nl\": \"Lange klik\",\n          \"da\": \"Langt Klik\",\n          \"de\": \"Langer Klick\",\n          \"es\": \"Click Largo\",\n          \"fr\": \"Clic Long\",\n          \"it\": \"Clic Lungo\",\n          \"no\": \"Langt Trykk\",\n          \"sv\": \"Långt Tryck\",\n          \"pl\": \"Długie Kliknięcie\",\n          \"ru\": \"Долгое Нажатие\",\n          \"ko\": \"오래 클릭\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-button|aqara-button|aqara-button-advanced|aqara-86sw1-advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"click_long_left\",\n        \"title\": {\n          \"en\": \"Left Long Click\",\n          \"nl\": \"Lange klik links\",\n          \"da\": \"Langt klik til venstre\",\n          \"de\": \"Langer Klick links\",\n          \"es\": \"Clic largo a la izquierda\",\n          \"fr\": \"Long clic gauche\",\n          \"it\": \"Clic lungo a sinistra\",\n          \"no\": \"Langt klikk til venstre\",\n          \"sv\": \"Långt klick till vänster\",\n          \"pl\": \"Długie kliknięcie w lewo\",\n          \"ru\": \"Долгое нажатие слева\",\n          \"ko\": \"왼쪽 긴 클릭\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-86sw2-advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"click_long_release\",\n        \"title\": {\n          \"en\": \"Long Click Release\",\n          \"nl\": \"Lange klik loslaten\",\n          \"da\": \"Langt Klik Udgivelse\",\n          \"de\": \"Langer Klick Freigabe\",\n          \"es\": \"Liberación de clic largo\",\n          \"fr\": \"Relâchement de long clic\",\n          \"it\": \"Rilascio del clic lungo\",\n          \"no\": \"Langt Klikk Utløsning\",\n          \"sv\": \"Långt Klick Släpp\",\n          \"pl\": \"Długie Kliknięcie Zwolnienie\",\n          \"ru\": \"Долгое Нажатие Отпустить\",\n          \"ko\": \"길게 클릭 해제\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner le périphérique\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-button-advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"click_long_right\",\n        \"title\": {\n          \"en\": \"Right Long Click\",\n          \"nl\": \"Lange klik rechts\",\n          \"da\": \"Højre Lang Klik\",\n          \"de\": \"Rechter Langer Klick\",\n          \"es\": \"Clic Largo Derecho\",\n          \"fr\": \"Clic Long Droit\",\n          \"it\": \"Clic Lungo Destro\",\n          \"no\": \"Høyre Langt Klikk\",\n          \"sv\": \"Höger Lång Klick\",\n          \"pl\": \"Długie kliknięcie prawe\",\n          \"ru\": \"Длинный клик правой кнопкой\",\n          \"ko\": \"오른쪽 길게 클릭\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-86sw2-advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"click_single\",\n        \"title\": {\n          \"en\": \"Click\",\n          \"nl\": \"Klik\",\n          \"da\": \"Klik\",\n          \"de\": \"Klick\",\n          \"es\": \"Clic\",\n          \"fr\": \"Clic\",\n          \"it\": \"Clic\",\n          \"no\": \"Klikk\",\n          \"sv\": \"Klick\",\n          \"pl\": \"Kliknij\",\n          \"ru\": \"Клик\",\n          \"ko\": \"클릭\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner le dispositif\",\n              \"it\": \"Seleziona il dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-button|aqara-button|aqara-button-advanced|aqara-86sw1-advanced|aqara_86sw1_switch\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"click_single_left\",\n        \"title\": {\n          \"en\": \"Left Click\",\n          \"nl\": \"Klik links\",\n          \"da\": \"Venstre klik\",\n          \"de\": \"Links Klick\",\n          \"es\": \"Clic izquierdo\",\n          \"fr\": \"Clic gauche\",\n          \"it\": \"Clic sinistro\",\n          \"no\": \"Venstre klikk\",\n          \"sv\": \"Vänsterklick\",\n          \"pl\": \"Kliknij lewy\",\n          \"ru\": \"Левый клик\",\n          \"ko\": \"왼쪽 클릭\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccione el dispositivo\",\n              \"fr\": \"Sélectionnez un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara_86sw2_switch|aqara-86sw2-advanced|db86_switch\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"click_single_left_right\",\n        \"title\": {\n          \"en\": \"Left and Right Click Together\",\n          \"nl\": \"Klik rechts en links tegelijk\",\n          \"da\": \"Venstre og højre klik sammen\",\n          \"de\": \"Links- und Rechtsklick zusammen\",\n          \"es\": \"Clic izquierdo y derecho juntos\",\n          \"fr\": \"Cliquez gauche et droit ensemble\",\n          \"it\": \"Clic sinistro e destro insieme\",\n          \"no\": \"Venstre og høyre klikk sammen\",\n          \"sv\": \"Vänster och höger klick tillsammans\",\n          \"pl\": \"Lewy i prawy klik razem\",\n          \"ru\": \"Левый и правый клик вместе\",\n          \"ko\": \"왼쪽 및 오른쪽 클릭 같이\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionnez l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara_86sw2_switch|aqara-86sw2-advanced|db86_switch\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"click_single_right\",\n        \"title\": {\n          \"en\": \"Right Click\",\n          \"nl\": \"Klik rechts\",\n          \"da\": \"Højreklik\",\n          \"de\": \"Rechtsklick\",\n          \"es\": \"Clic derecho\",\n          \"fr\": \"Clic droit\",\n          \"it\": \"Clic destro\",\n          \"no\": \"Høyreklikk\",\n          \"sv\": \"Högerklick\",\n          \"pl\": \"Kliknij prawym przyciskiem\",\n          \"ru\": \"Щелчок правой кнопкой мыши\",\n          \"ko\": \"오른쪽 클릭\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara_86sw2_switch|aqara-86sw2-advanced|db86_switch\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"cubeRotated\",\n        \"title\": {\n          \"en\": \"Rotated\",\n          \"nl\": \"Gedraaid\",\n          \"da\": \"Drejet\",\n          \"de\": \"Gedreht\",\n          \"es\": \"Girado\",\n          \"fr\": \"Tourné\",\n          \"it\": \"Ruotato\",\n          \"no\": \"Dreid\",\n          \"sv\": \"Vriden\",\n          \"pl\": \"Obrócony\",\n          \"ru\": \"Повернутый\",\n          \"ko\": \"회전된\"\n        },\n        \"tokens\": [\n          {\n            \"name\": \"cube_rotated\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"rotation\",\n              \"nl\": \"rotatie\",\n              \"da\": \"rotation\",\n              \"de\": \"Drehung\",\n              \"es\": \"rotación\",\n              \"fr\": \"rotation\",\n              \"it\": \"rotazione\",\n              \"no\": \"rotasjon\",\n              \"sv\": \"rotation\",\n              \"pl\": \"obrót\",\n              \"ru\": \"вращение\",\n              \"ko\": \"회전\"\n            },\n            \"example\": 0\n          }\n        ],\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-aqara-cube\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Desiccant low\"\n        },\n        \"hint\": {\n          \"en\": \"Triggers when desiccant level falls below the threshold.\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"filter\": \"driver_id=petfeeder_mmgg_miot\"\n          }\n        ],\n        \"tokens\": [\n          {\n            \"name\": \"level_percent\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"Level (%)\"\n            }\n          }\n        ],\n        \"id\": \"desiccant_low\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Eaten food changed\"\n        },\n        \"hint\": {\n          \"en\": \"Triggers when eaten food telemetry changes.\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"filter\": \"driver_id=petfeeder_mmgg_miot\"\n          }\n        ],\n        \"tokens\": [\n          {\n            \"name\": \"today_g\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"Today (g)\"\n            }\n          },\n          {\n            \"name\": \"total_g\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"Total (g)\"\n            }\n          },\n          {\n            \"name\": \"delta_g\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"Delta (g)\"\n            }\n          }\n        ],\n        \"id\": \"eaten_food_changed\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Feeder status changed\"\n        },\n        \"hint\": {\n          \"en\": \"Triggers when the feeder status (mode) changes.\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"filter\": \"driver_id=petfeeder_mmgg_miot\"\n          }\n        ],\n        \"tokens\": [\n          {\n            \"name\": \"new_status\",\n            \"type\": \"string\",\n            \"title\": {\n              \"en\": \"New status\"\n            }\n          },\n          {\n            \"name\": \"previous_status\",\n            \"type\": \"string\",\n            \"title\": {\n              \"en\": \"Previous status\"\n            }\n          }\n        ],\n        \"id\": \"feeder_status_changed\"\n      },\n      {\n        \"id\": \"flip180_cube\",\n        \"title\": {\n          \"en\": \"Flip 180°\",\n          \"nl\": \"180° keren\",\n          \"da\": \"Vend 180°\",\n          \"de\": \"180° drehen\",\n          \"es\": \"Girar 180°\",\n          \"fr\": \"Retourner 180°\",\n          \"it\": \"Capovolgere 180°\",\n          \"no\": \"Snur 180°\",\n          \"sv\": \"Vänd 180°\",\n          \"pl\": \"Odwróć 180°\",\n          \"ru\": \"Повернуть на 180°\",\n          \"ko\": \"180° 뒤집기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-aqara-cube\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"flip90_cube\",\n        \"title\": {\n          \"en\": \"Flip 90°\",\n          \"nl\": \"90° keren\",\n          \"da\": \"Flip 90°\",\n          \"de\": \"90° drehen\",\n          \"es\": \"Girar 90°\",\n          \"fr\": \"Retourner à 90°\",\n          \"it\": \"Capovolgi di 90°\",\n          \"no\": \"Flipp 90°\",\n          \"sv\": \"Vänd 90°\",\n          \"pl\": \"Obróć o 90°\",\n          \"ru\": \"Повернуть на 90°\",\n          \"ko\": \"90° 뒤집기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-aqara-cube\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"free_fall_cube\",\n        \"title\": {\n          \"en\": \"Free Fall\",\n          \"nl\": \"Vrije val\",\n          \"da\": \"Frit fald\",\n          \"de\": \"Freier Fall\",\n          \"es\": \"Caída libre\",\n          \"fr\": \"Chute libre\",\n          \"it\": \"Caduta libera\",\n          \"no\": \"Fritt fall\",\n          \"sv\": \"Fritt fall\",\n          \"pl\": \"Swobodny spadek\",\n          \"ru\": \"Свободное падение\",\n          \"ko\": \"자유낙하\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-aqara-cube\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"gatewayLuminance\",\n        \"title\": {\n          \"en\": \"Luminance has changed\",\n          \"nl\": \"De helderheid is veranderd\",\n          \"da\": \"Luminansen er ændret\",\n          \"de\": \"Die Helligkeit hat sich geändert\",\n          \"es\": \"La luminancia ha cambiado\",\n          \"fr\": \"La luminance a changé\",\n          \"it\": \"La luminanza è cambiata\",\n          \"no\": \"Luminansen har endret seg\",\n          \"sv\": \"Luminansen har ändrats\",\n          \"pl\": \"Jasność została zmieniona\",\n          \"ru\": \"Яркость изменилась\",\n          \"ko\": \"조도가 변경되었습니다\"\n        },\n        \"tokens\": [\n          {\n            \"name\": \"luminance\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"luminance\",\n              \"nl\": \"helderheid\",\n              \"da\": \"luminans\",\n              \"de\": \"Helligkeit\",\n              \"es\": \"luminancia\",\n              \"fr\": \"luminance\",\n              \"it\": \"luminanza\",\n              \"no\": \"luminans\",\n              \"sv\": \"luminans\",\n              \"pl\": \"jasność\",\n              \"ru\": \"яркость\",\n              \"ko\": \"휘도\"\n            },\n            \"example\": 0\n          }\n        ],\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Gateway\",\n              \"nl\": \"Selecteer Gateway\",\n              \"da\": \"Vælg Gateway\",\n              \"de\": \"Gateway auswählen\",\n              \"es\": \"Selecciona Gateway\",\n              \"fr\": \"Sélectionnez Gateway\",\n              \"it\": \"Seleziona Gateway\",\n              \"no\": \"Velg Gateway\",\n              \"sv\": \"Välj Gateway\",\n              \"pl\": \"Wybierz Gateway\",\n              \"ru\": \"Выберите шлюз\",\n              \"ko\": \"게이트웨이를 선택하세요\"\n            },\n            \"filter\": \"driver_id=gateway\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"deprecated\": true\n      },\n      {\n        \"id\": \"humidifier2Waterlevel\",\n        \"title\": {\n          \"en\": \"Waterlevel has changed\",\n          \"nl\": \"Waterniveau is veranderd\",\n          \"de\": \"Der Wasserstand hat sich geändert\",\n          \"da\": \"Vandniveauet er ændret\",\n          \"es\": \"El nivel de agua ha cambiado\",\n          \"fr\": \"Le niveau de l'eau a changé\",\n          \"it\": \"Il livello dell'acqua è cambiato\",\n          \"no\": \"Vannstanden har endret seg\",\n          \"sv\": \"Vattennivån har ändrats\",\n          \"pl\": \"Poziom wody się zmienił\",\n          \"ru\": \"Уровень воды изменился\",\n          \"ko\": \"수위가 변경되었습니다\"\n        },\n        \"tokens\": [\n          {\n            \"name\": \"waterlevel\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"current waterlevel\",\n              \"nl\": \"actueel waterniveau\",\n              \"de\": \"aktueller Wasserstand\",\n              \"da\": \"nuværende vandniveau\",\n              \"es\": \"nivel de agua actual\",\n              \"fr\": \"niveau d'eau actuel\",\n              \"it\": \"livello dell'acqua attuale\",\n              \"no\": \"nåværende vannstand\",\n              \"sv\": \"nuvarande vattennivå\",\n              \"pl\": \"aktualny poziom wody\",\n              \"ru\": \"текущий уровень воды\",\n              \"ko\": \"현재 수위\"\n            },\n            \"example\": 88\n          },\n          {\n            \"name\": \"previous_waterlevel\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"previous waterlevel\",\n              \"nl\": \"vorige waterniveau\",\n              \"de\": \"bisheriger Wasserstand\",\n              \"da\": \"tidligere vandniveau\",\n              \"es\": \"nivel de agua anterior\",\n              \"fr\": \"niveau d'eau précédent\",\n              \"it\": \"livello dell'acqua precedente\",\n              \"no\": \"forrige vannstand\",\n              \"sv\": \"tidigare vattennivå\",\n              \"pl\": \"wcześniejszy poziom wody\",\n              \"ru\": \"предыдущий уровень воды\",\n              \"ko\": \"이전 수위\"\n            },\n            \"example\": 90\n          }\n        ],\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Humidifier 2\",\n              \"nl\": \"Selecteer Humidifier 2\",\n              \"da\": \"Vælg Humidifier 2\",\n              \"es\": \"Selecciona Humidifier 2\",\n              \"fr\": \"Sélectionnez Humidifier 2\",\n              \"it\": \"Seleziona Humidifier 2\",\n              \"no\": \"Velg Humidifier 2\",\n              \"sv\": \"Välj Humidifier 2\",\n              \"pl\": \"Wybierz Humidifier 2\",\n              \"ru\": \"Выберите Humidifier 2\",\n              \"ko\": \"Humidifier 2 선택\"\n            },\n            \"filter\": \"driver_id=humidifier_zhimi_humidifier|humidifier_zhimi_humidifier_miot|humidifier_xiaomi_humidifier\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"leftSwitchOff\",\n        \"title\": {\n          \"en\": \"Left Switch Off\",\n          \"nl\": \"Linkerschakelaar uit\",\n          \"da\": \"Venstre kontakt slukket\",\n          \"de\": \"Linker Schalter aus\",\n          \"es\": \"Interruptor izquierdo apagado\",\n          \"fr\": \"Interrupteur gauche éteint\",\n          \"it\": \"Interruttore sinistro spento\",\n          \"no\": \"Venstre bryter av\",\n          \"sv\": \"Vänstra brytaren av\",\n          \"pl\": \"Lewy przełącznik wyłączony\",\n          \"ru\": \"Выключатель слева выключен\",\n          \"ko\": \"왼쪽 스위치 끄기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"leftSwitchOn\",\n        \"title\": {\n          \"en\": \"Left Switch On\",\n          \"nl\": \"Linkerschakelaar aan\",\n          \"da\": \"Venstre kontakt tændt\",\n          \"de\": \"Linker Schalter an\",\n          \"es\": \"Interruptor izquierdo encendido\",\n          \"fr\": \"Interrupteur gauche allumé\",\n          \"it\": \"Interruttore sinistro acceso\",\n          \"no\": \"Venstre bryter på\",\n          \"sv\": \"Vänstra strömbrytaren på\",\n          \"pl\": \"Lewy przełącznik włączony\",\n          \"ru\": \"Левый переключатель включен\",\n          \"ko\": \"왼쪽 스위치 켜기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Lock Event\",\n          \"nl\": \"Lock event\",\n          \"da\": \"Låsebegivenhed\",\n          \"de\": \"Schlossereignis\",\n          \"es\": \"Evento de Bloqueo\",\n          \"fr\": \"Événement de Verrouillage\",\n          \"it\": \"Evento di Blocco\",\n          \"no\": \"Låshendelse\",\n          \"sv\": \"Låshändelse\",\n          \"pl\": \"Wydarzenie Blokady\",\n          \"ru\": \"Событие Блокировки\",\n          \"ko\": \"잠금 이벤트\"\n        },\n        \"tokens\": [\n          {\n            \"name\": \"finger_id\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"fingerprint id\",\n              \"nl\": \"vingerafdruk id\",\n              \"da\": \"fingeraftryk id\",\n              \"de\": \"Fingerabdruck ID\",\n              \"es\": \"ID de huella digital\",\n              \"fr\": \"ID d'empreinte digitale\",\n              \"it\": \"ID dell'impronta digitale\",\n              \"no\": \"fingeravtrykk id\",\n              \"sv\": \"fingeravtryck id\",\n              \"pl\": \"ID odcisku palca\",\n              \"ru\": \"ID отпечатка пальца\",\n              \"ko\": \"지문 ID\"\n            },\n            \"example\": 0\n          },\n          {\n            \"name\": \"code_id\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"code id\",\n              \"nl\": \"code id\",\n              \"da\": \"kode id\",\n              \"de\": \"Code ID\",\n              \"es\": \"ID de código\",\n              \"fr\": \"ID de code\",\n              \"it\": \"ID del codice\",\n              \"no\": \"kode id\",\n              \"sv\": \"kod id\",\n              \"pl\": \"ID kodu\",\n              \"ru\": \"ID кода\",\n              \"ko\": \"코드 ID\"\n            },\n            \"example\": 0\n          },\n          {\n            \"name\": \"card_id\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"card id\",\n              \"nl\": \"kaart id\",\n              \"da\": \"kort id\",\n              \"de\": \"Karten ID\",\n              \"es\": \"ID de tarjeta\",\n              \"fr\": \"ID de carte\",\n              \"it\": \"ID della carta\",\n              \"no\": \"kort id\",\n              \"sv\": \"kort id\",\n              \"pl\": \"ID karty\",\n              \"ru\": \"ID карты\",\n              \"ko\": \"카드 ID\"\n            },\n            \"example\": 0\n          },\n          {\n            \"name\": \"userName\",\n            \"type\": \"string\",\n            \"title\": {\n              \"en\": \"User\",\n              \"nl\": \"Gebruiker\",\n              \"da\": \"Bruger\",\n              \"de\": \"Benutzer\",\n              \"es\": \"Usuario\",\n              \"fr\": \"Utilisateur\",\n              \"it\": \"Utente\",\n              \"no\": \"Bruker\",\n              \"sv\": \"Användare\",\n              \"pl\": \"Użytkownik\",\n              \"ru\": \"Пользователь\",\n              \"ko\": \"사용자\"\n            },\n            \"example\": {\n              \"en\": \"John Doe\"\n            }\n          },\n          {\n            \"name\": \"wrong_id\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"wrong id\",\n              \"nl\": \"verkeerd id\",\n              \"da\": \"forkert id\",\n              \"de\": \"falsche ID\",\n              \"es\": \"ID incorrecta\",\n              \"fr\": \"ID incorrecte\",\n              \"it\": \"ID errato\",\n              \"no\": \"feil id\",\n              \"sv\": \"fel id\",\n              \"pl\": \"błędne ID\",\n              \"ru\": \"неверный ID\",\n              \"ko\": \"잘못된 ID\"\n            },\n            \"example\": 3\n          }\n        ],\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"filter\": \"driver_id=lock.aq1\"\n          }\n        ],\n        \"id\": \"lockEvent\"\n      },\n      {\n        \"id\": \"motionSensorNoMotion120\",\n        \"title\": {\n          \"en\": \"No motion detected in 2 minutes\",\n          \"nl\": \"Geen beweging gedetecteerd in 2 minuten\",\n          \"da\": \"Ingen bevægelse registreret i 2 minutter\",\n          \"de\": \"Keine Bewegung in 2 Minuten erkannt\",\n          \"es\": \"No se detectó movimiento en 2 minutos\",\n          \"fr\": \"Aucun mouvement détecté en 2 minutes\",\n          \"it\": \"Nessun movimento rilevato in 2 minuti\",\n          \"no\": \"Ingen bevegelse oppdaget på 2 minutter\",\n          \"sv\": \"Ingen rörelse upptäckt på 2 minuter\",\n          \"pl\": \"Nie wykryto ruchu przez 2 minuty\",\n          \"ru\": \"Движение не обнаружено в течение 2 минут\",\n          \"ko\": \"2분 동안 움직임이 감지되지 않음\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-motion-sensor|aqara-motion-sensor\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"motionSensorNoMotion1200\",\n        \"title\": {\n          \"en\": \"No motion detected in 20 minutes\",\n          \"nl\": \"Geen beweging gedetecteerd in 20 minuten\",\n          \"da\": \"Ingen bevægelse registreret i 20 minutter\",\n          \"de\": \"Keine Bewegung in 20 Minuten erkannt\",\n          \"es\": \"No se ha detectado movimiento en 20 minutos\",\n          \"fr\": \"Aucun mouvement détecté en 20 minutes\",\n          \"it\": \"Nessun movimento rilevato in 20 minuti\",\n          \"no\": \"Ingen bevegelse oppdaget på 20 minutter\",\n          \"sv\": \"Ingen rörelse upptäckt på 20 minuter\",\n          \"pl\": \"Brak ruchu wykrytego w ciągu 20 minut\",\n          \"ru\": \"Движение не обнаружено в течение 20 минут\",\n          \"ko\": \"20분 동안 움직임 감지되지 않음\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-motion-sensor|aqara-motion-sensor\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"motionSensorNoMotion180\",\n        \"title\": {\n          \"en\": \"No motion detected in 3 minutes\",\n          \"nl\": \"Geen beweging gedetecteerd in 3 minuten\",\n          \"da\": \"Ingen bevægelse registreret i 3 minutter\",\n          \"de\": \"Keine Bewegung in 3 Minuten erkannt\",\n          \"es\": \"No se detectó movimiento en 3 minutos\",\n          \"fr\": \"Aucun mouvement détecté en 3 minutes\",\n          \"it\": \"Nessun movimento rilevato in 3 minuti\",\n          \"no\": \"Ingen bevegelse oppdaget på 3 minutter\",\n          \"sv\": \"Ingen rörelse upptäckt på 3 minuter\",\n          \"pl\": \"Brak wykrycia ruchu przez 3 minuty\",\n          \"ru\": \"Нет движения в течение 3 минут\",\n          \"ko\": \"3분 동안 움직임이 감지되지 않음\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona il dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-motion-sensor|aqara-motion-sensor\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"motionSensorNoMotion1800\",\n        \"title\": {\n          \"en\": \"No motion detected in 30 minutes\",\n          \"nl\": \"Geen beweging gedetecteerd in 30 minuten\",\n          \"da\": \"Ingen bevægelse registreret i 30 minutter\",\n          \"de\": \"Keine Bewegung in 30 Minuten erkannt\",\n          \"es\": \"No se detectó movimiento en 30 minutos\",\n          \"fr\": \"Aucun mouvement détecté en 30 minutes\",\n          \"it\": \"Nessun movimento rilevato in 30 minuti\",\n          \"no\": \"Ingen bevegelse oppdaget på 30 minutter\",\n          \"sv\": \"Ingen rörelse upptäckt på 30 minuter\",\n          \"pl\": \"Brak ruchu przez 30 minut\",\n          \"ru\": \"Движение не обнаружено в течение 30 минут\",\n          \"ko\": \"30분 동안 움직임이 감지되지 않았습니다.\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner le dispositif\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치를 선택하세요\"\n            },\n            \"filter\": \"driver_id=mi-motion-sensor|aqara-motion-sensor\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"motionSensorNoMotion300\",\n        \"title\": {\n          \"en\": \"No motion detected in 5 minutes\",\n          \"nl\": \"Geen beweging gedetecteerd in 5 minuten\",\n          \"da\": \"Ingen bevægelse registreret i 5 minutter\",\n          \"de\": \"Keine Bewegung in 5 Minuten erkannt\",\n          \"es\": \"No se detectó movimiento en 5 minutos\",\n          \"fr\": \"Aucun mouvement détecté en 5 minutes\",\n          \"it\": \"Nessun movimento rilevato in 5 minuti\",\n          \"no\": \"Ingen bevegelse oppdaget på 5 minutter\",\n          \"sv\": \"Ingen rörelse upptäckt på 5 minuter\",\n          \"pl\": \"Brak ruchu przez 5 minut\",\n          \"ru\": \"Нет движения в течение 5 минут\",\n          \"ko\": \"5분 동안 감지된 움직임 없음\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-motion-sensor|aqara-motion-sensor\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"motionSensorNoMotion600\",\n        \"title\": {\n          \"en\": \"No motion detected in 10 minutes\",\n          \"nl\": \"Geen beweging gedetecteerd in 10 minuten\",\n          \"da\": \"Ingen bevægelse registreret i 10 minutter\",\n          \"de\": \"Keine Bewegung in 10 Minuten erkannt\",\n          \"es\": \"No se detectó movimiento en 10 minutos\",\n          \"fr\": \"Aucun mouvement détecté en 10 minutes\",\n          \"it\": \"Nessun movimento rilevato in 10 minuti\",\n          \"no\": \"Ingen bevegelse oppdaget på 10 minutter\",\n          \"sv\": \"Ingen rörelse upptäckt på 10 minuter\",\n          \"pl\": \"Nie wykryto ruchu przez 10 minut\",\n          \"ru\": \"Движение не обнаружено в течение 10 минут\",\n          \"ko\": \"10분 동안 움직임이 감지되지 않음\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un périphérique\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"기기 선택\"\n            },\n            \"filter\": \"driver_id=mi-motion-sensor|aqara-motion-sensor\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"move_cube\",\n        \"title\": {\n          \"en\": \"Move\",\n          \"nl\": \"Verplaatsen\",\n          \"da\": \"Flyt\",\n          \"de\": \"Bewegen\",\n          \"es\": \"Mover\",\n          \"fr\": \"Déplacer\",\n          \"it\": \"Muovi\",\n          \"no\": \"Flytt\",\n          \"sv\": \"Flytta\",\n          \"pl\": \"Przenieś\",\n          \"ru\": \"Двигать\",\n          \"ko\": \"이동\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-aqara-cube\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"rightSwitchOff\",\n        \"title\": {\n          \"en\": \"Right Switch Off\",\n          \"nl\": \"Rechterschakelaar uit\",\n          \"da\": \"Højre kontakt slukket\",\n          \"de\": \"Rechter Schalter aus\",\n          \"es\": \"Interruptor derecho apagado\",\n          \"fr\": \"Interrupteur droit éteint\",\n          \"it\": \"Interruttore destro spento\",\n          \"no\": \"Høyre bryter av\",\n          \"sv\": \"Högra strömställaren av\",\n          \"pl\": \"Przełącznik prawy wyłączony\",\n          \"ru\": \"Правый выключатель выключен\",\n          \"ko\": \"오른쪽 스위치 끄기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"rightSwitchOn\",\n        \"title\": {\n          \"en\": \"Right Switch On\",\n          \"nl\": \"Rechterschakelaar aan\",\n          \"da\": \"Højre kontakt er tændt\",\n          \"de\": \"Rechter Schalter an\",\n          \"es\": \"Interruptor derecho encendido\",\n          \"fr\": \"Interrupteur droit allumé\",\n          \"it\": \"Interruttore destro acceso\",\n          \"no\": \"Høyre bryter på\",\n          \"sv\": \"Högra brytaren på\",\n          \"pl\": \"Prawy włącznik włączony\",\n          \"ru\": \"Правый выключатель включён\",\n          \"ko\": \"오른쪽 스위치 켜기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionnez un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"rotate_negative_cube\",\n        \"title\": {\n          \"en\": \"Rotated Anti Clockwise\",\n          \"nl\": \"Rotatie tegen de klok in\",\n          \"da\": \"Drejet mod uret\",\n          \"de\": \"Gegen den Uhrzeigersinn gedreht\",\n          \"es\": \"Girado en sentido antihorario\",\n          \"fr\": \"Tourné dans le sens antihoraire\",\n          \"it\": \"Ruotato in senso antiorario\",\n          \"no\": \"Dreid mot klokka\",\n          \"sv\": \"Vriden moturs\",\n          \"pl\": \"Obrócony przeciwnie do ruchu wskazówek zegara\",\n          \"ru\": \"Повернуто против часовой стрелки\",\n          \"ko\": \"반시계 방향으로 회전\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-aqara-cube\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"rotate_positive_cube\",\n        \"title\": {\n          \"en\": \"Rotated Clockwise\",\n          \"nl\": \"Rotatie met de klok mee\",\n          \"da\": \"Drejet med uret\",\n          \"de\": \"Im Uhrzeigersinn gedreht\",\n          \"es\": \"Girado en el sentido de las agujas del reloj\",\n          \"fr\": \"Tourné dans le sens des aiguilles d'une montre\",\n          \"it\": \"Ruotato in senso orario\",\n          \"no\": \"Roterte med klokken\",\n          \"sv\": \"Roterad medurs\",\n          \"pl\": \"Obrócony zgodnie z ruchem wskazówek zegara\",\n          \"ru\": \"Повернут по часовой стрелке\",\n          \"ko\": \"시계 방향으로 회전\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionnez l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-aqara-cube\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"shake\",\n        \"title\": {\n          \"en\": \"Shake\",\n          \"nl\": \"Schudden\",\n          \"da\": \"Ryst\",\n          \"de\": \"Schütteln\",\n          \"es\": \"Agitar\",\n          \"fr\": \"Secouer\",\n          \"it\": \"Scuoti\",\n          \"no\": \"Rist\",\n          \"sv\": \"Skaka\",\n          \"pl\": \"Potrząśnij\",\n          \"ru\": \"Встряхнуть\",\n          \"ko\": \"흔들기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-button-advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"shake_air_cube\",\n        \"title\": {\n          \"en\": \"Shake in air\",\n          \"nl\": \"Schudden in de lucht\",\n          \"da\": \"Ryst i luften\",\n          \"de\": \"Schütteln in der Luft\",\n          \"es\": \"Agitar en el aire\",\n          \"fr\": \"Secouer dans les airs\",\n          \"it\": \"Sbattere in aria\",\n          \"no\": \"Rist i lufta\",\n          \"sv\": \"Skaka i luften\",\n          \"pl\": \"Potrząśnij w powietrzu\",\n          \"ru\": \"Встряхнуть в воздухе\",\n          \"ko\": \"공중에서 흔들기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-aqara-cube\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"statusVacuum\",\n        \"title\": {\n          \"en\": \"Status has changed\",\n          \"nl\": \"Status is gewijzigd\",\n          \"da\": \"Status er ændret\",\n          \"de\": \"Status hat sich geändert\",\n          \"es\": \"El estado ha cambiado\",\n          \"fr\": \"Le statut a changé\",\n          \"it\": \"Lo stato è cambiato\",\n          \"no\": \"Status har endret seg\",\n          \"sv\": \"Status har ändrats\",\n          \"pl\": \"Status zmienił się\",\n          \"ru\": \"Статус изменился\",\n          \"ko\": \"상태가 변경되었습니다\"\n        },\n        \"tokens\": [\n          {\n            \"name\": \"status\",\n            \"type\": \"string\",\n            \"title\": {\n              \"en\": \"status\",\n              \"nl\": \"status\",\n              \"da\": \"status\",\n              \"de\": \"Status\",\n              \"es\": \"estado\",\n              \"fr\": \"statut\",\n              \"it\": \"stato\",\n              \"no\": \"status\",\n              \"sv\": \"status\",\n              \"pl\": \"status\",\n              \"ru\": \"статус\",\n              \"ko\": \"상태\"\n            },\n            \"example\": \"stopped\"\n          }\n        ],\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Robot\",\n              \"nl\": \"Selecteer Mi Robot\",\n              \"da\": \"Vælg Mi Robot\",\n              \"de\": \"Mi-Roboter auswählen\",\n              \"es\": \"Selecciona Mi Robot\",\n              \"fr\": \"Sélectionnez Mi Robot\",\n              \"it\": \"Seleziona Mi Robot\",\n              \"no\": \"Velg Mi Robot\",\n              \"sv\": \"Välj Mi Robot\",\n              \"pl\": \"Wybierz Mi Robot\",\n              \"ru\": \"Выберите Mi Robot\",\n              \"ko\": \"Mi 로봇 선택\"\n            },\n            \"filter\": \"driver_id=mi-robot|vacuum_mi_rockrobo_vacuum_advanced|vacuum_dreame_vacuum|vacuum_viomi_vacuum_v7|vacuum_mija_vacuum_miot|vacuum_roidmi_vacuum_miot|vacuum_xiaomi_vacuum_max\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"tap_twice_cube\",\n        \"title\": {\n          \"en\": \"Tap twice\",\n          \"nl\": \"2x tikken\",\n          \"da\": \"Tryk to gange\",\n          \"de\": \"Zweimal tippen\",\n          \"es\": \"Toca dos veces\",\n          \"fr\": \"Tapez deux fois\",\n          \"it\": \"Tocca due volte\",\n          \"no\": \"Trykk to ganger\",\n          \"sv\": \"Tryck två gånger\",\n          \"pl\": \"Dotknij dwa razy\",\n          \"ru\": \"Нажмите дважды\",\n          \"ko\": \"두 번 탭하세요\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionnez un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-aqara-cube\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Mode has changed\",\n          \"nl\": \"Modus gewijzigd\",\n          \"de\": \"Modus hat sich geändert\",\n          \"da\": \"Tilstand er ændret\",\n          \"es\": \"El modo ha cambiado\",\n          \"fr\": \"Le mode a changé\",\n          \"it\": \"La modalità è cambiata\",\n          \"no\": \"Modus er endret\",\n          \"sv\": \"Läget har ändrats\",\n          \"pl\": \"Tryb został zmieniony\",\n          \"ru\": \"Режим изменился\",\n          \"ko\": \"모드가 변경되었습니다\"\n        },\n        \"tokens\": [\n          {\n            \"name\": \"new_mode\",\n            \"type\": \"string\",\n            \"title\": {\n              \"en\": \"new mode\",\n              \"nl\": \"nieuwe modus\",\n              \"de\": \"neue modus\",\n              \"da\": \"ny tilstand\",\n              \"es\": \"nuevo modo\",\n              \"fr\": \"nouveau mode\",\n              \"it\": \"nuova modalità\",\n              \"no\": \"ny modus\",\n              \"sv\": \"nytt läge\",\n              \"pl\": \"nowy tryb\",\n              \"ru\": \"новый режим\",\n              \"ko\": \"새로운 모드\"\n            },\n            \"example\": \"medium\"\n          },\n          {\n            \"name\": \"previous_mode\",\n            \"type\": \"string\",\n            \"title\": {\n              \"en\": \"previous mode\",\n              \"nl\": \"vorige modus\",\n              \"de\": \"bisherige modus\",\n              \"da\": \"forrige tilstand\",\n              \"es\": \"modo anterior\",\n              \"fr\": \"mode précédent\",\n              \"it\": \"modalità precedente\",\n              \"no\": \"forrige modus\",\n              \"sv\": \"föregående läge\",\n              \"pl\": \"poprzedni tryb\",\n              \"ru\": \"предыдущий режим\",\n              \"ko\": \"이전 모드\"\n            },\n            \"example\": \"silent\"\n          }\n        ],\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"es\": \"Seleccione dispositivo\",\n              \"fr\": \"Sélectionnez l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"디바이스 선택\"\n            },\n            \"filter\": \"driver_id=mi-airpurifier|airpurifier_zhimi_advanced|airpurifier_zhimi_advanced_miot|airpurifier_zhimi_airpurifier_ma2|airpurifier_dmaker_airfresh_t2017|airfresh_zhimi_airfresh|humidifier_zhimi_humidifier|humidifier_zhimi_humidifier_miot|humidifier_deerma_humidifier_jsq|humidifier_deerma_humidifier_miot|dmaker_fan_1c|fan_zhimi_advanced|zhimi_fan_za5|airfryer_careli_miot|petwaterdispenser_mmgg_miot|pet_waterer_xiaomi|petfeeder_mmgg_miot|humidifier_xiaomi_humidifier|dehumidifier_dmaker_derh_miot|humidifier_leshow_humidifier_jsq1|diffuser_xwhzp_diffuser_xwxfj\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"triggerModeChanged\"\n      },\n      {\n        \"id\": \"triggerPlugInUse\",\n        \"title\": {\n          \"en\": \"In use\",\n          \"nl\": \"In gebruik\",\n          \"da\": \"I brug\",\n          \"de\": \"In Benutzung\",\n          \"es\": \"En uso\",\n          \"fr\": \"En cours d'utilisation\",\n          \"it\": \"In uso\",\n          \"no\": \"I bruk\",\n          \"sv\": \"I bruk\",\n          \"pl\": \"W użyciu\",\n          \"ru\": \"В использовании\",\n          \"ko\": \"사용 중\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccione el dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-plug\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"triggerVacuumRoomSegments\",\n        \"title\": {\n          \"en\": \"Room segments has changed\",\n          \"nl\": \"Kamer segmenten is gewijzigd\",\n          \"da\": \"Rumsegmenter er ændret\",\n          \"de\": \"Raumsegmente wurden geändert\",\n          \"es\": \"Los segmentos de la habitación han cambiado\",\n          \"fr\": \"Les segments de la pièce ont changé\",\n          \"it\": \"I segmenti della stanza sono cambiati\",\n          \"no\": \"Romsegmenter har blitt endret\",\n          \"sv\": \"Rumssegment har ändrats\",\n          \"pl\": \"Segmenty pokoju zostały zmienione\",\n          \"ru\": \"Сегменты комнаты изменились\",\n          \"ko\": \"룸 세그먼트가 변경되었습니다\"\n        },\n        \"tokens\": [\n          {\n            \"name\": \"segments\",\n            \"type\": \"string\",\n            \"title\": {\n              \"en\": \"Segments\",\n              \"nl\": \"Segmenten\",\n              \"da\": \"Segmenter\",\n              \"de\": \"Segmente\",\n              \"es\": \"Segmentos\",\n              \"fr\": \"Segments\",\n              \"it\": \"Segmenti\",\n              \"no\": \"Segmenter\",\n              \"sv\": \"Segment\",\n              \"pl\": \"Segmenty\",\n              \"ru\": \"Сегменты\",\n              \"ko\": \"세그먼트\"\n            },\n            \"example\": \"[16,17]\"\n          }\n        ],\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Robot\",\n              \"nl\": \"Selecteer Mi Robot\",\n              \"da\": \"Vælg Mi Robot\",\n              \"de\": \"Wählen Sie Mi Robot\",\n              \"es\": \"Seleccionar Mi Robot\",\n              \"fr\": \"Sélectionner Mi Robot\",\n              \"it\": \"Seleziona Mi Robot\",\n              \"no\": \"Velg Mi Robot\",\n              \"sv\": \"Välj Mi Robot\",\n              \"pl\": \"Wybierz Mi Robot\",\n              \"ru\": \"Выберите Mi Robot\",\n              \"ko\": \"Mi 로봇 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"triggerVibrationFreeFallAlarm\",\n        \"title\": {\n          \"en\": \"Free Fall\",\n          \"nl\": \"Vrije val\",\n          \"da\": \"Frit fald\",\n          \"de\": \"Freier Fall\",\n          \"es\": \"Caída libre\",\n          \"fr\": \"Chute libre\",\n          \"it\": \"Caduta libera\",\n          \"no\": \"Fritt fall\",\n          \"sv\": \"Fritt fall\",\n          \"pl\": \"Swobodny spadek\",\n          \"ru\": \"Свободное падение\",\n          \"ko\": \"자유 낙하\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=vibration_sensor\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"triggerVibrationTiltAlarm\",\n        \"title\": {\n          \"en\": \"Tilted\",\n          \"nl\": \"Tilted\",\n          \"da\": \"Vippet\",\n          \"de\": \"Geneigt\",\n          \"es\": \"Inclinado\",\n          \"fr\": \"Incliné\",\n          \"it\": \"Inclinato\",\n          \"no\": \"Vippet\",\n          \"sv\": \"Vinklad\",\n          \"pl\": \"Przechylony\",\n          \"ru\": \"Наклонено\",\n          \"ko\": \"기울어진\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionnez un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"기기 선택\"\n            },\n            \"filter\": \"driver_id=vibration_sensor\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"vacuum_on_error\",\n        \"title\": {\n          \"en\": \"The vacuum encountered an error\",\n          \"it\": \"Il robot aspirapolvere ha riscontrato un problema.\",\n          \"nl\": \"De robotstofzuiger heeft een foutmelding gegeven. \",\n          \"da\": \"Robotstøvsugeren har givet en fejl\",\n          \"de\": \"Der Saugroboter hat einen Fehler gemeldet\",\n          \"es\": \"El robot aspirador ha dado un error\",\n          \"fr\": \"L'aspirateur robot a rencontré une erreur\",\n          \"no\": \"Robotstøvsugeren har gitt en feil\",\n          \"sv\": \"Robotdammsugaren har rapporterat ett fel\",\n          \"pl\": \"Odkurzacz robot zgłosił błąd\",\n          \"ru\": \"Робот-пылесос сообщил об ошибке\",\n          \"ko\": \"로봇 청소기가 오류를 발생시켰습니다\"\n        },\n        \"description\": {\n          \"en\": \"the vacuum has raised an error. Please check the device for details.\",\n          \"it\": \"il robot aspirapolvere è andato in errore. Per favore controlla il dispositivo per i dettagli.\",\n          \"nl\": \"De robotstofzuiger heeft een foutmelding gegeven. Controleer het apparaat voor meer details.\",\n          \"da\": \"Robotstøvsugeren har givet en fejl. Kontroller enheden for flere detaljer.\",\n          \"de\": \"Der Saugroboter hat einen Fehler gemeldet. Bitte überprüfen Sie das Gerät für weitere Details.\",\n          \"es\": \"El robot aspirador ha dado un error. Por favor, revise el dispositivo para más detalles.\",\n          \"fr\": \"L'aspirateur robot a rencontré une erreur. Veuillez vérifier l'appareil pour plus de détails.\",\n          \"no\": \"Robotstøvsugeren har gitt en feil. Vennligst sjekk enheten for flere detaljer.\",\n          \"sv\": \"Robotdammsugaren har rapporterat ett fel. Kontrollera enheten för mer information.\",\n          \"pl\": \"Odkurzacz robot zgłosił błąd. Proszę sprawdzić urządzenie, aby uzyskać więcej szczegółów.\",\n          \"ru\": \"Робот-пылесос сообщил об ошибке. Пожалуйста, проверьте устройство для получения подробной информации.\",\n          \"ko\": \"로봇 청소기가 오류를 발생시켰습니다. 자세한 내용은 장치를 확인하십시오.\"\n        },\n        \"tokens\": [\n          {\n            \"name\": \"error\",\n            \"type\": \"string\",\n            \"title\": {\n              \"en\": \"vacuum error raised\",\n              \"it\": \"errore segnalato dal robot aspirapolvere\",\n              \"nl\": \"robotstofzuiger foutmelding gegeven\",\n              \"da\": \"robotstøvsuger fejl\",\n              \"de\": \"Saugroboterfehler\",\n              \"es\": \"error del robot aspirador\",\n              \"fr\": \"erreur de l'aspirateur robot\",\n              \"no\": \"robotstøvsugerfeil\",\n              \"sv\": \"robotdammsugarefel\",\n              \"pl\": \"błąd odkurzacza robota\",\n              \"ru\": \"ошибка робота-пылесоса\",\n              \"ko\": \"로봇 청소기 오류\"\n            }\n          }\n        ],\n        \"args\": [\n          {\n            \"type\": \"device\",\n            \"name\": \"device\",\n            \"filter\": \"driver_id=vacuum_xiaomi_vacuum_max\"\n          }\n        ]\n      }\n    ],\n    \"conditions\": [\n      {\n        \"id\": \"leftSwitch\",\n        \"title\": {\n          \"en\": \"Left switch !{{on|off}}\",\n          \"nl\": \"Linkerschakelaar !{{aan|uit}}\",\n          \"da\": \"Venstre switch !{{on|off}}\",\n          \"de\": \"Linker Schalter !{{on|off}}\",\n          \"es\": \"Interruptor izquierdo !{{on|off}}\",\n          \"fr\": \"Interrupteur gauche !{{on|off}}\",\n          \"it\": \"Interruttore sinistro !{{on|off}}\",\n          \"no\": \"Venstre bryter !{{on|off}}\",\n          \"sv\": \"Vänster switch !{{on|off}}\",\n          \"pl\": \"Lewy przełącznik !{{on|off}}\",\n          \"ru\": \"Левый переключатель !{{on|off}}\",\n          \"ko\": \"왼쪽 스위치 !{{on|off}}\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Selecciona dispositivo\",\n              \"fr\": \"Sélectionnez l'appareil\",\n              \"it\": \"Seleziona il dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"measure_humidity_between\",\n        \"title\": {\n          \"en\": \"Humidity !{{is between|is not between}}\",\n          \"nl\": \"Luchtvochtigheid !{{ligt tussen|ligt niet tussen}}\",\n          \"da\": \"Fugtighed !{{er mellem|er ikke mellem}}\",\n          \"de\": \"Feuchtigkeit !{{liegt zwischen|liegt nicht zwischen}}\",\n          \"es\": \"Humedad !{{está entre|no está entre}}\",\n          \"fr\": \"Humidité !{{est entre|n'est pas entre}}\",\n          \"it\": \"Umidità !{{è tra|non è tra}}\",\n          \"no\": \"Fuktighet !{{er mellom|er ikke mellom}}\",\n          \"sv\": \"Fuktighet !{{är mellan|är inte mellan}}\",\n          \"pl\": \"Wilgotność !{{jest między|nie jest między}}\",\n          \"ru\": \"Влажность !{{между|не между}}\",\n          \"ko\": \"습도 !{{사이에 있음|사이에 없음}}\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Humidity !{{is between|is not between}} [[value1]] and [[value2]]\",\n          \"nl\": \"Luchtvochtigheid !{{ligt tussen|ligt niet tussen}} [[value1]] en [[value2]]\",\n          \"da\": \"Fugtighed !{{er mellem|er ikke mellem}} [[value1]] og [[value2]]\",\n          \"de\": \"Feuchtigkeit !{{liegt zwischen|liegt nicht zwischen}} [[value1]] und [[value2]]\",\n          \"es\": \"Humedad !{{está entre|no está entre}} [[value1]] y [[value2]]\",\n          \"fr\": \"Humidité !{{est entre|n'est pas entre}} [[value1]] et [[value2]]\",\n          \"it\": \"Umidità !{{è tra|non è tra}} [[value1]] e [[value2]]\",\n          \"no\": \"Fuktighet !{{er mellom|er ikke mellom}} [[value1]] og [[value2]]\",\n          \"sv\": \"Fuktighet !{{är mellan|är inte mellan}} [[value1]] och [[value2]]\",\n          \"pl\": \"Wilgotność !{{jest między|nie jest między}} [[value1]] i [[value2]]\",\n          \"ru\": \"Влажность !{{между|не между}} [[value1]] и [[value2]]\",\n          \"ko\": \"습도 !{{사이에 있음|사이에 없음}} [[value1]] 과 [[value2]]\"\n        },\n        \"hint\": {\n          \"en\": \"Use this card to determine whether or not the humidity for the zone is between two values. The specified values are also valid.\",\n          \"nl\": \"Gebruik dit kaartje om te bepalen of de luchtvochtigheid voor de zone tussen twee waarden ligt. De opgegeven waarden zijn ook geldig.\",\n          \"da\": \"Brug dette kort til at afgøre, om fugtigheden i zonen er mellem to værdier. De angivne værdier er også gyldige.\",\n          \"de\": \"Verwenden Sie diese Karte, um festzustellen, ob die Feuchtigkeit in der Zone zwischen zwei Werten liegt. Die angegebenen Werte sind ebenfalls gültig.\",\n          \"es\": \"Utilice esta tarjeta para determinar si la humedad de la zona está entre dos valores. Los valores especificados también son válidos.\",\n          \"fr\": \"Utilisez cette carte pour déterminer si l'humidité de la zone est entre deux valeurs. Les valeurs spécifiées sont également valides.\",\n          \"it\": \"Usa questa scheda per determinare se l'umidità della zona è tra due valori. Anche i valori specificati sono validi.\",\n          \"no\": \"Bruk dette kortet for å avgjøre om fuktigheten for sonen er mellom to verdier. De spesifiserte verdiene er også gyldige.\",\n          \"sv\": \"Använd detta kort för att avgöra om fuktigheten för zonen är mellan två värden. De angivna värdena är också giltiga.\",\n          \"pl\": \"Użyj tej karty, aby sprawdzić, czy wilgotność w strefie mieści się między dwiema wartościami. Podane wartości są również ważne.\",\n          \"ru\": \"Используйте эту карту, чтобы определить, находится ли влажность в зоне между двумя значениями. Указанные значения также действительны.\",\n          \"ko\": \"이 카드를 사용하여 구역의 습도가 두 값 사이에 있는지 여부를 결정하세요. 지정된 값도 유효합니다.\"\n        },\n        \"args\": [\n          {\n            \"type\": \"number\",\n            \"name\": \"value1\",\n            \"min\": 0,\n            \"max\": 100,\n            \"step\": 1,\n            \"title\": {\n              \"en\": \"Above\",\n              \"nl\": \"Boven\",\n              \"da\": \"Over\",\n              \"de\": \"Über\",\n              \"es\": \"Por encima de\",\n              \"fr\": \"Au dessus de\",\n              \"it\": \"Sopra\",\n              \"no\": \"Over\",\n              \"sv\": \"Över\",\n              \"pl\": \"Powyżej\",\n              \"ru\": \"Над\",\n              \"ko\": \"이상\"\n            },\n            \"placeholder\": {\n              \"en\": \"%\",\n              \"nl\": \"%\",\n              \"da\": \"%\",\n              \"de\": \"%\",\n              \"es\": \"%\",\n              \"fr\": \"%\",\n              \"it\": \"%\",\n              \"no\": \"%\",\n              \"sv\": \"%\",\n              \"pl\": \"%\",\n              \"ru\": \"%\",\n              \"ko\": \"%\"\n            }\n          },\n          {\n            \"type\": \"number\",\n            \"name\": \"value2\",\n            \"min\": 0,\n            \"max\": 100,\n            \"step\": 1,\n            \"title\": {\n              \"en\": \"Below\",\n              \"nl\": \"Onder\",\n              \"da\": \"Under\",\n              \"de\": \"Unter\",\n              \"es\": \"Por debajo de\",\n              \"fr\": \"En dessous de\",\n              \"it\": \"Sotto\",\n              \"no\": \"Under\",\n              \"sv\": \"Under\",\n              \"pl\": \"Poniżej\",\n              \"ru\": \"Под\",\n              \"ko\": \"이하\"\n            },\n            \"placeholder\": {\n              \"en\": \"%\",\n              \"nl\": \"%\",\n              \"da\": \"%\",\n              \"de\": \"%\",\n              \"es\": \"%\",\n              \"fr\": \"%\",\n              \"it\": \"%\",\n              \"no\": \"%\",\n              \"sv\": \"%\",\n              \"pl\": \"%\",\n              \"ru\": \"%\",\n              \"ko\": \"%\"\n            }\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-temperature-humidity-sensor|aqara-temperature-humidity-sensor\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"measure_temperature_between\",\n        \"title\": {\n          \"en\": \"Temperature !{{is between|is not between}}\",\n          \"nl\": \"Temperatuur !{{ligt tussen|ligt niet tussen}}\",\n          \"da\": \"Temperatur !{{er mellem|er ikke mellem}}\",\n          \"de\": \"Temperatur !{{liegt zwischen|liegt nicht zwischen}}\",\n          \"es\": \"Temperatura !{{está entre|no está entre}}\",\n          \"fr\": \"Température !{{est entre|n'est pas entre}}\",\n          \"it\": \"Temperatura !{{è tra|non è tra}}\",\n          \"no\": \"Temperatur !{{er mellom|er ikke mellom}}\",\n          \"sv\": \"Temperatur !{{är mellan|är inte mellan}}\",\n          \"pl\": \"Temperatura !{{jest między|nie jest między}}\",\n          \"ru\": \"Температура !{{между|не между}}\",\n          \"ko\": \"온도 !{{사이에 있음|사이에 없음}}\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Temperature !{{is between|is not between}} [[value1]] and [[value2]]\",\n          \"nl\": \"Temperatuur !{{ligt tussen|ligt niet tussen}} [[value1]] en [[value2]]\",\n          \"da\": \"Temperatur !{{er mellem|er ikke mellem}} [[value1]] og [[value2]]\",\n          \"de\": \"Temperatur !{{liegt zwischen|liegt nicht zwischen}} [[value1]] und [[value2]]\",\n          \"es\": \"Temperatura !{{está entre|no está entre}} [[value1]] y [[value2]]\",\n          \"fr\": \"Température !{{est entre|n'est pas entre}} [[value1]] et [[value2]]\",\n          \"it\": \"Temperatura !{{è tra|non è tra}} [[value1]] e [[value2]]\",\n          \"no\": \"Temperatur !{{er mellom|er ikke mellom}} [[value1]] og [[value2]]\",\n          \"sv\": \"Temperatur !{{är mellan|är inte mellan}} [[value1]] och [[value2]]\",\n          \"pl\": \"Temperatura !{{jest między|nie jest między}} [[value1]] i [[value2]]\",\n          \"ru\": \"Температура !{{между|не между}} [[value1]] и [[value2]]\",\n          \"ko\": \"온도 !{{사이에 있음|사이에 없음}} [[value1]]와 [[value2]] 사이\"\n        },\n        \"hint\": {\n          \"en\": \"Use this card to determine whether or not the zone temperature is between two values. The specified values are also valid.\",\n          \"nl\": \"Gebruik dit kaartje om te bepalen of de zone temperatuur tussen twee waarden ligt. De opgegeven waarden zijn ook geldig.\",\n          \"da\": \"Brug dette kort til at bestemme, om zonens temperatur er mellem to værdier. De angivne værdier er også gyldige.\",\n          \"de\": \"Verwenden Sie diese Karte, um festzustellen, ob die Zonentemperatur zwischen zwei Werten liegt. Die angegebenen Werte sind ebenfalls gültig.\",\n          \"es\": \"Usa esta tarjeta para determinar si la temperatura de la zona está entre dos valores. Los valores especificados también son válidos.\",\n          \"fr\": \"Utilisez cette carte pour déterminer si la température de la zone est comprise entre deux valeurs. Les valeurs spécifiées sont également valables.\",\n          \"it\": \"Usa questa scheda per determinare se la temperatura della zona è compresa tra due valori. Anche i valori specificati sono validi.\",\n          \"no\": \"Bruk dette kortet for å bestemme om sone-temperaturen er mellom to verdier. De spesifiserte verdiene er også gyldige.\",\n          \"sv\": \"Använd detta kort för att avgöra om zonens temperatur är mellan två värden. De specificerade värdena är också giltiga.\",\n          \"pl\": \"Użyj tej karty, aby określić, czy temperatura strefy mieści się pomiędzy dwoma wartościami. Podane wartości są również ważne.\",\n          \"ru\": \"Используйте эту карту, чтобы определить, находится ли температура в зоне между двумя значениями. Указанные значения также действительны.\",\n          \"ko\": \"이 카드를 사용하여 구역 온도가 두 값 사이에 있는지 여부를 결정하세요. 지정된 값도 유효합니다.\"\n        },\n        \"args\": [\n          {\n            \"type\": \"number\",\n            \"name\": \"value1\",\n            \"min\": -50,\n            \"max\": 100,\n            \"step\": 1,\n            \"title\": {\n              \"en\": \"Above\",\n              \"nl\": \"Boven\",\n              \"da\": \"Over\",\n              \"de\": \"Über\",\n              \"es\": \"Por encima\",\n              \"fr\": \"Au-dessus\",\n              \"it\": \"Sopra\",\n              \"no\": \"Over\",\n              \"sv\": \"Över\",\n              \"pl\": \"Powyżej\",\n              \"ru\": \"Выше\",\n              \"ko\": \"위\"\n            },\n            \"placeholder\": {\n              \"en\": \"°C\",\n              \"nl\": \"°C\",\n              \"da\": \"°C\",\n              \"de\": \"°C\",\n              \"es\": \"°C\",\n              \"fr\": \"°C\",\n              \"it\": \"°C\",\n              \"no\": \"°C\",\n              \"sv\": \"°C\",\n              \"pl\": \"°C\",\n              \"ru\": \"°C\",\n              \"ko\": \"°C\"\n            }\n          },\n          {\n            \"type\": \"number\",\n            \"name\": \"value2\",\n            \"min\": -50,\n            \"max\": 100,\n            \"step\": 1,\n            \"title\": {\n              \"en\": \"Below\",\n              \"nl\": \"Onder\",\n              \"da\": \"Under\",\n              \"de\": \"Unter\",\n              \"es\": \"Por debajo\",\n              \"fr\": \"En dessous\",\n              \"it\": \"Sotto\",\n              \"no\": \"Under\",\n              \"sv\": \"Under\",\n              \"pl\": \"Poniżej\",\n              \"ru\": \"Ниже\",\n              \"ko\": \"아래\"\n            },\n            \"placeholder\": {\n              \"en\": \"°C\",\n              \"nl\": \"°C\",\n              \"da\": \"°C\",\n              \"de\": \"°C\",\n              \"es\": \"°C\",\n              \"fr\": \"°C\",\n              \"it\": \"°C\",\n              \"no\": \"°C\",\n              \"sv\": \"°C\",\n              \"pl\": \"°C\",\n              \"ru\": \"°C\",\n              \"ko\": \"°C\"\n            }\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-temperature-humidity-sensor|aqara-temperature-humidity-sensor\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"rightSwitch\",\n        \"title\": {\n          \"en\": \"Right switch !{{on|off}}\",\n          \"nl\": \"Rechterschakelaar !{{aan|uit}}\",\n          \"da\": \"Højre switch !{{til|fra}}\",\n          \"de\": \"Rechter Schalter !{{an|aus}}\",\n          \"es\": \"Interruptor derecho !{{encendido|apagado}}\",\n          \"fr\": \"Interrupteur droit !{{allumé|éteint}}\",\n          \"it\": \"Interruttore destro !{{acceso|spento}}\",\n          \"no\": \"Høyre bryter !{{på|av}}\",\n          \"sv\": \"Höger strömbrytare !{{på|av}}\",\n          \"pl\": \"Prawy przełącznik !{{włączone|wyłączone}}\",\n          \"ru\": \"Правый переключатель !{{включено|выключено}}\",\n          \"ko\": \"오른쪽 스위치 !{{켜짐|꺼짐}}\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      }\n    ],\n    \"actions\": [\n      {\n        \"id\": \"airpurifierSetFavorite\",\n        \"title\": {\n          \"en\": \"Set Favorite Speed\",\n          \"nl\": \"Favoriete snelheid instellen\",\n          \"da\": \"Indstil favorit hastighed\",\n          \"de\": \"Lieblingsgeschwindigkeit einstellen\",\n          \"es\": \"Establecer velocidad favorita\",\n          \"fr\": \"Définir la vitesse favorite\",\n          \"it\": \"Imposta velocità preferita\",\n          \"no\": \"Sett favoritt hastighet\",\n          \"sv\": \"Ställ in favorit hastighet\",\n          \"pl\": \"Ustaw ulubioną prędkość\",\n          \"ru\": \"Установить любимую скорость\",\n          \"ko\": \"즐겨찾기 속도 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set favorite speed to [[favorite]]\",\n          \"nl\": \"Favoriete snelheid instellen op [[favorite]]\",\n          \"da\": \"Indstil favorit hastighed til [[favorite]]\",\n          \"de\": \"Lieblingsgeschwindigkeit auf [[favorite]] einstellen\",\n          \"es\": \"Establecer velocidad favorita a [[favorite]]\",\n          \"fr\": \"Définir la vitesse favorite à [[favorite]]\",\n          \"it\": \"Imposta velocità preferita a [[favorite]]\",\n          \"no\": \"Sett favoritt hastighet til [[favorite]]\",\n          \"sv\": \"Ställ in favorit hastighet till [[favorite]]\",\n          \"pl\": \"Ustaw ulubioną prędkość na [[favorite]]\",\n          \"ru\": \"Установить любимую скорость на [[favorite]]\",\n          \"ko\": \"[[favorite]]로 즐겨찾기 속도 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"favorite\",\n            \"title\": {\n              \"en\": \"Favorite\",\n              \"nl\": \"Favoriet\",\n              \"da\": \"Favorit\",\n              \"de\": \"Favorit\",\n              \"es\": \"Favorito\",\n              \"fr\": \"Favori\",\n              \"it\": \"Preferito\",\n              \"no\": \"Favoritt\",\n              \"sv\": \"Favorit\",\n              \"pl\": \"Ulubiony\",\n              \"ru\": \"Любимый\",\n              \"ko\": \"즐겨찾기\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"1\",\n                  \"nl\": \"1\",\n                  \"da\": \"1\",\n                  \"de\": \"1\",\n                  \"es\": \"1\",\n                  \"fr\": \"1\",\n                  \"it\": \"1\",\n                  \"no\": \"1\",\n                  \"sv\": \"1\",\n                  \"pl\": \"1\",\n                  \"ru\": \"1\",\n                  \"ko\": \"1\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"2\",\n                  \"nl\": \"2\",\n                  \"da\": \"2\",\n                  \"de\": \"2\",\n                  \"es\": \"2\",\n                  \"fr\": \"2\",\n                  \"it\": \"2\",\n                  \"no\": \"2\",\n                  \"sv\": \"2\",\n                  \"pl\": \"2\",\n                  \"ru\": \"2\",\n                  \"ko\": \"2\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"3\",\n                  \"nl\": \"3\",\n                  \"da\": \"3\",\n                  \"de\": \"3\",\n                  \"es\": \"3\",\n                  \"fr\": \"3\",\n                  \"it\": \"3\",\n                  \"no\": \"3\",\n                  \"sv\": \"3\",\n                  \"pl\": \"3\",\n                  \"ru\": \"3\",\n                  \"ko\": \"3\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"label\": {\n                  \"en\": \"4\",\n                  \"nl\": \"4\",\n                  \"da\": \"4\",\n                  \"de\": \"4\",\n                  \"es\": \"4\",\n                  \"fr\": \"4\",\n                  \"it\": \"4\",\n                  \"no\": \"4\",\n                  \"sv\": \"4\",\n                  \"pl\": \"4\",\n                  \"ru\": \"4\",\n                  \"ko\": \"4\"\n                }\n              },\n              {\n                \"id\": \"5\",\n                \"label\": {\n                  \"en\": \"5\",\n                  \"nl\": \"5\",\n                  \"da\": \"5\",\n                  \"de\": \"5\",\n                  \"es\": \"5\",\n                  \"fr\": \"5\",\n                  \"it\": \"5\",\n                  \"no\": \"5\",\n                  \"sv\": \"5\",\n                  \"pl\": \"5\",\n                  \"ru\": \"5\",\n                  \"ko\": \"5\"\n                }\n              },\n              {\n                \"id\": \"6\",\n                \"label\": {\n                  \"en\": \"6\",\n                  \"nl\": \"6\",\n                  \"da\": \"6\",\n                  \"de\": \"6\",\n                  \"es\": \"6\",\n                  \"fr\": \"6\",\n                  \"it\": \"6\",\n                  \"no\": \"6\",\n                  \"sv\": \"6\",\n                  \"pl\": \"6\",\n                  \"ru\": \"6\",\n                  \"ko\": \"6\"\n                }\n              },\n              {\n                \"id\": \"7\",\n                \"label\": {\n                  \"en\": \"7\",\n                  \"nl\": \"7\",\n                  \"da\": \"7\",\n                  \"de\": \"7\",\n                  \"es\": \"7\",\n                  \"fr\": \"7\",\n                  \"it\": \"7\",\n                  \"no\": \"7\",\n                  \"sv\": \"7\",\n                  \"pl\": \"7\",\n                  \"ru\": \"7\",\n                  \"ko\": \"7\"\n                }\n              },\n              {\n                \"id\": \"8\",\n                \"label\": {\n                  \"en\": \"8\",\n                  \"nl\": \"8\",\n                  \"da\": \"8\",\n                  \"de\": \"8\",\n                  \"es\": \"8\",\n                  \"fr\": \"8\",\n                  \"it\": \"8\",\n                  \"no\": \"8\",\n                  \"sv\": \"8\",\n                  \"pl\": \"8\",\n                  \"ru\": \"8\",\n                  \"ko\": \"8\"\n                }\n              },\n              {\n                \"id\": \"9\",\n                \"label\": {\n                  \"en\": \"9\",\n                  \"nl\": \"9\",\n                  \"da\": \"9\",\n                  \"de\": \"9\",\n                  \"es\": \"9\",\n                  \"fr\": \"9\",\n                  \"it\": \"9\",\n                  \"no\": \"9\",\n                  \"sv\": \"9\",\n                  \"pl\": \"9\",\n                  \"ru\": \"9\",\n                  \"ko\": \"9\"\n                }\n              },\n              {\n                \"id\": \"10\",\n                \"label\": {\n                  \"en\": \"10\",\n                  \"nl\": \"10\",\n                  \"da\": \"10\",\n                  \"de\": \"10\",\n                  \"es\": \"10\",\n                  \"fr\": \"10\",\n                  \"it\": \"10\",\n                  \"no\": \"10\",\n                  \"sv\": \"10\",\n                  \"pl\": \"10\",\n                  \"ru\": \"10\",\n                  \"ko\": \"10\"\n                }\n              },\n              {\n                \"id\": \"11\",\n                \"label\": {\n                  \"en\": \"11\",\n                  \"nl\": \"11\",\n                  \"da\": \"11\",\n                  \"de\": \"11\",\n                  \"es\": \"11\",\n                  \"fr\": \"11\",\n                  \"it\": \"11\",\n                  \"no\": \"11\",\n                  \"sv\": \"11\",\n                  \"pl\": \"11\",\n                  \"ru\": \"11\",\n                  \"ko\": \"11\"\n                }\n              },\n              {\n                \"id\": \"12\",\n                \"label\": {\n                  \"en\": \"12\",\n                  \"nl\": \"12\",\n                  \"da\": \"12\",\n                  \"de\": \"12\",\n                  \"es\": \"12\",\n                  \"fr\": \"12\",\n                  \"it\": \"12\",\n                  \"no\": \"12\",\n                  \"sv\": \"12\",\n                  \"pl\": \"12\",\n                  \"ru\": \"12\",\n                  \"ko\": \"12\"\n                }\n              },\n              {\n                \"id\": \"13\",\n                \"label\": {\n                  \"en\": \"13\",\n                  \"nl\": \"13\",\n                  \"da\": \"13\",\n                  \"de\": \"13\",\n                  \"es\": \"13\",\n                  \"fr\": \"13\",\n                  \"it\": \"13\",\n                  \"no\": \"13\",\n                  \"sv\": \"13\",\n                  \"pl\": \"13\",\n                  \"ru\": \"13\",\n                  \"ko\": \"13\"\n                }\n              },\n              {\n                \"id\": \"14\",\n                \"label\": {\n                  \"en\": \"14\",\n                  \"nl\": \"14\",\n                  \"da\": \"14\",\n                  \"de\": \"14\",\n                  \"es\": \"14\",\n                  \"fr\": \"14\",\n                  \"it\": \"14\",\n                  \"no\": \"14\",\n                  \"sv\": \"14\",\n                  \"pl\": \"14\",\n                  \"ru\": \"14\",\n                  \"ko\": \"14\"\n                }\n              },\n              {\n                \"id\": \"15\",\n                \"label\": {\n                  \"en\": \"15\",\n                  \"nl\": \"15\",\n                  \"da\": \"15\",\n                  \"de\": \"15\",\n                  \"es\": \"15\",\n                  \"fr\": \"15\",\n                  \"it\": \"15\",\n                  \"no\": \"15\",\n                  \"sv\": \"15\",\n                  \"pl\": \"15\",\n                  \"ru\": \"15\",\n                  \"ko\": \"15\"\n                }\n              },\n              {\n                \"id\": \"16\",\n                \"label\": {\n                  \"en\": \"16\",\n                  \"nl\": \"16\",\n                  \"da\": \"16\",\n                  \"de\": \"16\",\n                  \"es\": \"16\",\n                  \"fr\": \"16\",\n                  \"it\": \"16\",\n                  \"no\": \"16\",\n                  \"sv\": \"16\",\n                  \"pl\": \"16\",\n                  \"ru\": \"16\",\n                  \"ko\": \"16\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Air Purifier\",\n              \"nl\": \"Selecteer Mi Luchtreiniger\",\n              \"da\": \"Vælg Mi luftrenser\",\n              \"de\": \"Wählen Sie Mi Luftreiniger\",\n              \"es\": \"Seleccione Mi Purificador de aire\",\n              \"fr\": \"Sélectionnez Mi Purificateur d'air\",\n              \"it\": \"Seleziona Mi Purificatore d'aria\",\n              \"no\": \"Velg Mi luftrenser\",\n              \"sv\": \"Välj Mi luftrenare\",\n              \"pl\": \"Wybierz Mi oczyszczacz powietrza\",\n              \"ru\": \"Выберите Mi Очиститель воздуха\",\n              \"ko\": \"Mi 공기청정기 선택\"\n            },\n            \"filter\": \"driver_id=mi-airpurifier|airpurifier_zhimi_advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Set fan level\",\n          \"nl\": \"Ventilatieniveau instellen\",\n          \"da\": \"Indstil ventilatorniveau\",\n          \"de\": \"Lüfterstufe einstellen\",\n          \"es\": \"Establecer nivel de ventilador\",\n          \"fr\": \"Définir le niveau du ventilateur\",\n          \"it\": \"Imposta livello ventola\",\n          \"no\": \"Still inn viftetrinn\",\n          \"sv\": \"Ställ in fläkthastighet\",\n          \"pl\": \"Ustaw poziom wentylatora\",\n          \"ru\": \"Установить уровень вентилятора\",\n          \"ko\": \"팬 레벨 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set fan level to [[fanlevel]]\",\n          \"nl\": \"Stel fan level in op [[fanlevel]]\",\n          \"da\": \"Indstil blæserniveau til [[fanlevel]]\",\n          \"de\": \"Lüfterstufe auf [[fanlevel]] einstellen\",\n          \"es\": \"Establecer el nivel del ventilador a [[fanlevel]]\",\n          \"fr\": \"Définir le niveau du ventilateur à [[fanlevel]]\",\n          \"it\": \"Imposta il livello della ventola a [[fanlevel]]\",\n          \"no\": \"Still inn viftenivå til [[fanlevel]]\",\n          \"sv\": \"Ställ in fläkthastighet till [[fanlevel]]\",\n          \"pl\": \"Ustaw poziom wentylatora na [[fanlevel]]\",\n          \"ru\": \"Установите уровень вентилятора на [[fanlevel]]\",\n          \"ko\": \"팬 레벨 [[fanlevel]]로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"fanlevel\",\n            \"title\": {\n              \"en\": \"Fan Level\",\n              \"nl\": \"Fan Level\",\n              \"da\": \"Blæserniveau\",\n              \"de\": \"Lüfterstufe\",\n              \"es\": \"Nivel del ventilador\",\n              \"fr\": \"Niveau de ventilateur\",\n              \"it\": \"Livello ventola\",\n              \"no\": \"Viftenivå\",\n              \"sv\": \"Fläkthastighet\",\n              \"pl\": \"Poziom wentylatora\",\n              \"ru\": \"Уровень вентилятора\",\n              \"ko\": \"팬 레벨\"\n            },\n            \"type\": \"number\",\n            \"min\": 0,\n            \"max\": 14,\n            \"step\": 1\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Airpurifier\",\n              \"nl\": \"Selecteer Airpurifier\",\n              \"da\": \"Vælg luftrenser\",\n              \"de\": \"Luftreiniger auswählen\",\n              \"es\": \"Seleccionar purificador de aire\",\n              \"fr\": \"Sélectionner le purificateur d'air\",\n              \"it\": \"Seleziona purificatore d'aria\",\n              \"no\": \"Velg luftrenser\",\n              \"sv\": \"Välj luftrenare\",\n              \"pl\": \"Wybierz oczyszczacz powietrza\",\n              \"ru\": \"Выберите очиститель воздуха\",\n              \"ko\": \"공기청정기 선택\"\n            },\n            \"filter\": \"driver_id=airpurifier_zhimi_advanced_miot&capabilities=airpurifier_xiaomi_fanlevel\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"airpurifierXiaomiFanlevel\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set fan level\",\n          \"nl\": \"Ventilatieniveau instellen\",\n          \"da\": \"Indstil ventilatorniveau\",\n          \"de\": \"Lüfterstufe einstellen\",\n          \"es\": \"Establecer nivel de ventilador\",\n          \"fr\": \"Définir le niveau du ventilateur\",\n          \"it\": \"Imposta livello ventola\",\n          \"no\": \"Still inn viftetrinn\",\n          \"sv\": \"Ställ in fläkthastighet\",\n          \"pl\": \"Ustaw poziom wentylatora\",\n          \"ru\": \"Установить уровень вентилятора\",\n          \"ko\": \"팬 레벨 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set fan level to [[fanlevel]]\",\n          \"nl\": \"Stel fan level in op [[fanlevel]]\",\n          \"da\": \"Indstil blæserniveau til [[fanlevel]]\",\n          \"de\": \"Lüfterstufe auf [[fanlevel]] einstellen\",\n          \"es\": \"Establecer el nivel del ventilador a [[fanlevel]]\",\n          \"fr\": \"Définir le niveau du ventilateur à [[fanlevel]]\",\n          \"it\": \"Imposta il livello della ventola a [[fanlevel]]\",\n          \"no\": \"Still inn viftenivå til [[fanlevel]]\",\n          \"sv\": \"Ställ in fläkthastighet till [[fanlevel]]\",\n          \"pl\": \"Ustaw poziom wentylatora na [[fanlevel]]\",\n          \"ru\": \"Установите уровень вентилятора на [[fanlevel]]\",\n          \"ko\": \"팬 레벨 [[fanlevel]]로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"fanlevel\",\n            \"title\": {\n              \"en\": \"Fan Level\",\n              \"nl\": \"Fan Level\",\n              \"da\": \"Blæserniveau\",\n              \"de\": \"Lüfterstufe\",\n              \"es\": \"Nivel del ventilador\",\n              \"fr\": \"Niveau de ventilateur\",\n              \"it\": \"Livello ventola\",\n              \"no\": \"Viftenivå\",\n              \"sv\": \"Fläkthastighet\",\n              \"pl\": \"Poziom wentylatora\",\n              \"ru\": \"Уровень вентилятора\",\n              \"ko\": \"팬 레벨\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Level 1\",\n                  \"nl\": \"Level 1\",\n                  \"da\": \"Niveau 1\",\n                  \"de\": \"Stufe 1\",\n                  \"es\": \"Nivel 1\",\n                  \"fr\": \"Niveau 1\",\n                  \"it\": \"Livello 1\",\n                  \"no\": \"Nivå 1\",\n                  \"sv\": \"Nivå 1\",\n                  \"pl\": \"Poziom 1\",\n                  \"ru\": \"Уровень 1\",\n                  \"ko\": \"레벨 1\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Level 2\",\n                  \"nl\": \"Level 2\",\n                  \"da\": \"Niveau 2\",\n                  \"de\": \"Stufe 2\",\n                  \"es\": \"Nivel 2\",\n                  \"fr\": \"Niveau 2\",\n                  \"it\": \"Livello 2\",\n                  \"no\": \"Nivå 2\",\n                  \"sv\": \"Nivå 2\",\n                  \"pl\": \"Poziom 2\",\n                  \"ru\": \"Уровень 2\",\n                  \"ko\": \"레벨 2\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"title\": {\n                  \"en\": \"Level 3\",\n                  \"nl\": \"Level 3\",\n                  \"da\": \"Niveau 3\",\n                  \"de\": \"Stufe 3\",\n                  \"es\": \"Nivel 3\",\n                  \"fr\": \"Niveau 3\",\n                  \"it\": \"Livello 3\",\n                  \"no\": \"Nivå 3\",\n                  \"sv\": \"Nivå 3\",\n                  \"pl\": \"Poziom 3\",\n                  \"ru\": \"Уровень 3\",\n                  \"ko\": \"레벨 3\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Airpurifier\",\n              \"nl\": \"Selecteer Airpurifier\",\n              \"da\": \"Vælg luftrenser\",\n              \"de\": \"Luftreiniger auswählen\",\n              \"es\": \"Seleccionar purificador de aire\",\n              \"fr\": \"Sélectionner le purificateur d'air\",\n              \"it\": \"Seleziona purificatore d'aria\",\n              \"no\": \"Velg luftrenser\",\n              \"sv\": \"Välj luftrenare\",\n              \"pl\": \"Wybierz oczyszczacz powietrza\",\n              \"ru\": \"Выберите очиститель воздуха\",\n              \"ko\": \"공기청정기 선택\"\n            },\n            \"filter\": \"driver_id=airpurifier_zhimi_advanced_miot&capabilities=airpurifier_zhimi_fanlevel\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"airpurifierZhimiFanlevel\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Indstil tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Configurar modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Angi modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus einstellen auf [[mode]]\",\n          \"es\": \"Configurar modo a [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Angi modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]]로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Auto\",\n                  \"nl\": \"Auto\",\n                  \"da\": \"Auto\",\n                  \"de\": \"Auto\",\n                  \"es\": \"Auto\",\n                  \"fr\": \"Auto\",\n                  \"it\": \"Auto\",\n                  \"no\": \"Auto\",\n                  \"sv\": \"Auto\",\n                  \"pl\": \"Auto\",\n                  \"ru\": \"Автоматический\",\n                  \"ko\": \"자동\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Night\",\n                  \"nl\": \"Nacht\",\n                  \"da\": \"Nat\",\n                  \"de\": \"Nacht\",\n                  \"es\": \"Noche\",\n                  \"fr\": \"Nuit\",\n                  \"it\": \"Notte\",\n                  \"no\": \"Natt\",\n                  \"sv\": \"Natt\",\n                  \"pl\": \"Noc\",\n                  \"ru\": \"Ночной\",\n                  \"ko\": \"야간\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Favorite\",\n                  \"nl\": \"Favoriet\",\n                  \"da\": \"Favorit\",\n                  \"de\": \"Favorit\",\n                  \"es\": \"Favorito\",\n                  \"fr\": \"Favori\",\n                  \"it\": \"Preferito\",\n                  \"no\": \"Favoritt\",\n                  \"sv\": \"Favorit\",\n                  \"pl\": \"Ulubiony\",\n                  \"ru\": \"Избранное\",\n                  \"ko\": \"즐겨찾기\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"title\": {\n                  \"en\": \"Idle / Manual\",\n                  \"nl\": \"Inactief / Handmatig\",\n                  \"da\": \"Inaktiv / Manuel\",\n                  \"de\": \"Leerlauf / Manuell\",\n                  \"es\": \"Inactivo / Manual\",\n                  \"fr\": \"Inactif / Manuel\",\n                  \"it\": \"Inattivo / Manuale\",\n                  \"no\": \"Inaktiv / Manuell\",\n                  \"sv\": \"Inaktiv / Manuell\",\n                  \"pl\": \"Bezczynny / Ręczny\",\n                  \"ru\": \"Ожидание / Ручной\",\n                  \"ko\": \"대기 / 수동\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Airpurifier\",\n              \"nl\": \"Selecteer Airpurifier\",\n              \"da\": \"Vælg luftrenser\",\n              \"de\": \"Luftreiniger auswählen\",\n              \"es\": \"Selecciona purificador\",\n              \"fr\": \"Sélectionnez l'purificateur\",\n              \"it\": \"Seleziona purificatore\",\n              \"no\": \"Velg luftrenser\",\n              \"sv\": \"Välj luftrenare\",\n              \"pl\": \"Wybierz oczyszczacz powietrza\",\n              \"ru\": \"Выбрать очиститель воздуха\",\n              \"ko\": \"공기 청정기 선택\"\n            },\n            \"filter\": \"driver_id=airpurifier_zhimi_advanced_miot|airpurifier_dmaker_airfresh_t2017\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"airpurifierZhimiMode\"\n      },\n      {\n        \"id\": \"cleanZoneVacuum\",\n        \"title\": {\n          \"en\": \"Start zone cleaning\",\n          \"nl\": \"Start zone schoonmaken\",\n          \"da\": \"Start zone rengøring\",\n          \"de\": \"Zonenreinigung starten\",\n          \"es\": \"Iniciar limpieza de zonas\",\n          \"fr\": \"Démarrer le nettoyage de zone\",\n          \"it\": \"Avvia pulizia della zona\",\n          \"no\": \"Start sone rengjøring\",\n          \"sv\": \"Starta zonstädning\",\n          \"pl\": \"Rozpocznij czyszczenie strefy\",\n          \"ru\": \"Начать уборку зоны\",\n          \"ko\": \"영역 청소 시작\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Start zone cleaning [[zones]]\",\n          \"nl\": \"Start zone schoonmaken [[zones]]\",\n          \"da\": \"Start zone rengøring [[zones]]\",\n          \"de\": \"Zonenreinigung starten [[zones]]\",\n          \"es\": \"Iniciar limpieza de zonas [[zones]]\",\n          \"fr\": \"Démarrer le nettoyage de zone [[zones]]\",\n          \"it\": \"Avvia pulizia della zona [[zones]]\",\n          \"no\": \"Start sone rengjøring [[zones]]\",\n          \"sv\": \"Starta zonstädning [[zones]]\",\n          \"pl\": \"Rozpocznij czyszczenie strefy [[zones]]\",\n          \"ru\": \"Начать уборку зоны [[zones]]\",\n          \"ko\": \"영역 청소 시작 [[zones]]\"\n        },\n        \"hint\": {\n          \"en\": \"Takes in an a list of zones and the number of times to clean. Each zone contains an array of 5 values: bottom-left-x, bottom-left-y, top-right-x, top-right-y, number of clean times. Zones example: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n          \"nl\": \"Voer een lijst met zones in en het aantal keren om schoon te maken. Elke zone bevat een array met 5 waarden: bottom-left-x, bottom-left-y, top-right-x, top-right-y, number of clean times. Zones voorbeeld: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n          \"da\": \"Indtast en liste over zoner og antallet af gange, der skal rengøres. Hver zone indeholder en række af 5 værdier: nederste venstre x, nederste venstre y, øverste højre x, øverste højre y, antal rengøringstider. Zoner eksempel: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n          \"de\": \"Geben Sie eine Liste der Zonen und die Anzahl der Reinigungsvorgänge ein. Jede Zone enthält ein Array von 5 Werten: unten-links-x, unten-links-y, oben-rechts-x, oben-rechts-y, Anzahl der Reinigungszeiten. Zonenbeispiel: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n          \"es\": \"Ingrese una lista de zonas y el número de veces para limpiar. Cada zona contiene una matriz de 5 valores: abajo-izquierda-x, abajo-izquierda-y, arriba-derecha-x, arriba-derecha-y, número de veces de limpieza. Ejemplo de zonas: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n          \"fr\": \"Saisissez une liste de zones et le nombre de fois à nettoyer. Chaque zone contient un tableau de 5 valeurs : en bas à gauche-x, en bas à gauche-y, en haut à droite-x, en haut à droite-y, nombre de fois à nettoyer. Exemple de zones : [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n          \"it\": \"Inserisci un elenco di zone e il numero di volte da pulire. Ogni zona contiene una matrice di 5 valori: in basso a sinistra x, in basso a sinistra y, in alto a destra x, in alto a destra y, numero di volte di pulizia. Esempio di zone: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n          \"no\": \"Skriv inn en liste over soner og antall ganger å rengjøre. Hver sone inneholder en rekke med 5 verdier: nederst-venstre-x, nederst-venstre-y, øverst-høyre-x, øverst-høyre-y, antall rengjøringstider. Soneeksempel: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n          \"sv\": \"Ange en lista över zoner och antalet gånger att städa. Varje zon innehåller en matris med 5 värden: nedre vänster-x, nedre vänster-y, övre höger-x, övre höger-y, antal rengöringstider. Exempel på zoner: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n          \"pl\": \"Wprowadź listę stref i liczbę razy do czyszczenia. Każda strefa zawiera tablicę z 5 wartościami: dolna-lewa-x, dolna-lewa-y, górna-prawa-x, górna-prawa-y, liczba razy do czyszczenia. Przykład stref: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n          \"ru\": \"Введите список зон и количество раз для уборки. Каждая зона содержит массив из 5 значений: слева внизу-x, слева внизу-y, справа вверху-x, справа вверху-y, количество уборок. Пример зон: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\",\n          \"ko\": \"청소할 횟수와 목록을 입력합니다. 각 영역은 5가지 값의 배열을 포함합니다: 좌하단 x, 좌하단 y, 우상단 x, 우상단 y, 청소 횟수. 영역 예시: [26234,26042,26634,26642,1],[26232,25304,27282,25804,2],[26246,24189,27296,25139,2]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"zones\",\n            \"title\": {\n              \"en\": \"Zones\",\n              \"nl\": \"Zones\",\n              \"da\": \"Zoner\",\n              \"de\": \"Zonen\",\n              \"es\": \"Zonas\",\n              \"fr\": \"Zones\",\n              \"it\": \"Zone\",\n              \"no\": \"Soner\",\n              \"sv\": \"Zoner\",\n              \"pl\": \"Strefy\",\n              \"ru\": \"Зоны\",\n              \"ko\": \"영역\"\n            },\n            \"type\": \"text\",\n            \"placeholder\": {\n              \"en\": \"Zones\",\n              \"nl\": \"Zones\",\n              \"da\": \"Zoner\",\n              \"de\": \"Zonen\",\n              \"es\": \"Zonas\",\n              \"fr\": \"Zones\",\n              \"it\": \"Zone\",\n              \"no\": \"Soner\",\n              \"sv\": \"Zoner\",\n              \"pl\": \"Strefy\",\n              \"ru\": \"Зоны\",\n              \"ko\": \"영역\"\n            }\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer Stofzuiger\",\n              \"da\": \"Vælg Støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccionar aspiradora\",\n              \"fr\": \"Sélectionner l'aspirateur\",\n              \"it\": \"Seleziona aspirapolvere\",\n              \"no\": \"Velg Støvsuger\",\n              \"sv\": \"Välj Dammsugare\",\n              \"pl\": \"Wybierz Odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"진공 청소기 선택\"\n            },\n            \"filter\": \"driver_id=mi-robot|vacuum_mi_rockrobo_vacuum_advanced|vacuum_mi_rockrobo_vacuum_t6\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"enableAngle\",\n        \"title\": {\n          \"en\": \"Enable Oscillation\",\n          \"nl\": \"Inschakelen oscillatie\",\n          \"da\": \"Aktivér oscillation\",\n          \"de\": \"Oszillation aktivieren\",\n          \"es\": \"Activar oscilación\",\n          \"fr\": \"Activer l'oscillation\",\n          \"it\": \"Abilita oscillazione\",\n          \"no\": \"Aktiver svinging\",\n          \"sv\": \"Aktivera oscillator\",\n          \"pl\": \"Włącz oscylację\",\n          \"ru\": \"Включить осцилляцию\",\n          \"ko\": \"진동 활성화\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Oscillation [[oscillation]]\",\n          \"nl\": \"Oscillatie [[oscillation]]\",\n          \"da\": \"Oscillation [[oscillation]]\",\n          \"de\": \"Oszillation [[oscillation]]\",\n          \"es\": \"Oscilación [[oscillation]]\",\n          \"fr\": \"Oscillation [[oscillation]]\",\n          \"it\": \"Oscillazione [[oscillation]]\",\n          \"no\": \"Oscillation [[oscillation]]\",\n          \"sv\": \"Oscillation [[oscillation]]\",\n          \"pl\": \"Oscylacja [[oscillation]]\",\n          \"ru\": \"Осцилляция [[oscillation]]\",\n          \"ko\": \"진동 [[oscillation]]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"oscillation\",\n            \"title\": {\n              \"en\": \"Angle\",\n              \"nl\": \"Hoek\",\n              \"da\": \"Vinkel\",\n              \"de\": \"Winkel\",\n              \"es\": \"Ángulo\",\n              \"fr\": \"Angle\",\n              \"it\": \"Angolo\",\n              \"no\": \"Vinkel\",\n              \"sv\": \"Vinkel\",\n              \"pl\": \"Kąt\",\n              \"ru\": \"Угол\",\n              \"ko\": \"각도\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"on\",\n                \"label\": {\n                  \"en\": \"Enable\",\n                  \"nl\": \"Inschakelen\",\n                  \"da\": \"Aktiver\",\n                  \"de\": \"Aktivieren\",\n                  \"es\": \"Habilitar\",\n                  \"fr\": \"Activer\",\n                  \"it\": \"Abilita\",\n                  \"no\": \"Aktiver\",\n                  \"sv\": \"Aktivera\",\n                  \"pl\": \"Włącz\",\n                  \"ru\": \"Включить\",\n                  \"ko\": \"사용\"\n                }\n              },\n              {\n                \"id\": \"off\",\n                \"label\": {\n                  \"en\": \"Disable\",\n                  \"nl\": \"Uitschakelen\",\n                  \"da\": \"Deaktiver\",\n                  \"de\": \"Deaktivieren\",\n                  \"es\": \"Deshabilitar\",\n                  \"fr\": \"Désactiver\",\n                  \"it\": \"Disabilita\",\n                  \"no\": \"Deaktiver\",\n                  \"sv\": \"Inaktivera\",\n                  \"pl\": \"Wyłącz\",\n                  \"ru\": \"Выключить\",\n                  \"ko\": \"비활성화\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Choisir l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=zhimi-fan|dmaker-fan|fan_zhimi_advanced|fan_zhimi_fan_za5|fan_dmaker_advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Enable notification sound\",\n          \"nl\": \"Instellen notificatie geluid\",\n          \"da\": \"Aktiver notifikationslyd\",\n          \"de\": \"Benachrichtigungston aktivieren\",\n          \"es\": \"Activar sonido de notificaciones\",\n          \"fr\": \"Activer le son de notification\",\n          \"it\": \"Abilita suono di notifica\",\n          \"no\": \"Aktiver varslingslyd\",\n          \"sv\": \"Aktivera notifikationsljud\",\n          \"pl\": \"Włącz dźwięk powiadomień\",\n          \"ru\": \"Включить звуковое уведомление\",\n          \"ko\": \"알림 소리 사용\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set notification sound [[sound]]\",\n          \"nl\": \"Wijzig notificatie geluid naar [[sound]]\",\n          \"da\": \"Indstil notifikationslyd [[sound]]\",\n          \"de\": \"Benachrichtigungston einstellen [[sound]]\",\n          \"es\": \"Configurar sonido de notificación [[sound]]\",\n          \"fr\": \"Définir le son de notification [[sound]]\",\n          \"it\": \"Imposta suono di notifica [[sound]]\",\n          \"no\": \"Angi varslingslyd [[sound]]\",\n          \"sv\": \"Ställ in notifikationsljud [[sound]]\",\n          \"pl\": \"Ustaw dźwięk powiadomień [[sound]]\",\n          \"ru\": \"Установить звуковое уведомление [[sound]]\",\n          \"ko\": \"알림 소리 설정 [[sound]]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"sound\",\n            \"title\": {\n              \"en\": \"Sound\",\n              \"nl\": \"Geluid\",\n              \"da\": \"Lyd\",\n              \"de\": \"Klang\",\n              \"es\": \"Sonido\",\n              \"fr\": \"Son\",\n              \"it\": \"Suono\",\n              \"no\": \"Lyd\",\n              \"sv\": \"Ljud\",\n              \"pl\": \"Dźwięk\",\n              \"ru\": \"Звук\",\n              \"ko\": \"소리\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"label\": {\n                  \"en\": \"Off\",\n                  \"nl\": \"Uit\",\n                  \"da\": \"Fra\",\n                  \"de\": \"Aus\",\n                  \"es\": \"Apagado\",\n                  \"fr\": \"Désactivé\",\n                  \"it\": \"Spento\",\n                  \"no\": \"Av\",\n                  \"sv\": \"Av\",\n                  \"pl\": \"Wyłączone\",\n                  \"ru\": \"Выкл.\",\n                  \"ko\": \"끔\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"On\",\n                  \"nl\": \"Aan\",\n                  \"da\": \"Til\",\n                  \"de\": \"Ein\",\n                  \"es\": \"Encendido\",\n                  \"fr\": \"Activé\",\n                  \"it\": \"Acceso\",\n                  \"no\": \"På\",\n                  \"sv\": \"På\",\n                  \"pl\": \"Włączone\",\n                  \"ru\": \"Вкл.\",\n                  \"ko\": \"켬\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=airpurifier_zhimi_advanced_miot|fan_dmaker_advanced|heater_zhimi_heater_miot|humidifier_xiaomi_humidifier|petwaterdispenser_mmgg_miot|humidifier_deerma_humidifier_miot|humidifier_zhimi_humidifier_miot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"enableBuzzer\"\n      },\n      {\n        \"id\": \"enableEyecare\",\n        \"title\": {\n          \"en\": \"Switch Eyecare\",\n          \"nl\": \"Eyecare schakelen\",\n          \"da\": \"Skift Eyecare\",\n          \"de\": \"Eyecare einschalten\",\n          \"es\": \"Cambiar Eyecare\",\n          \"fr\": \"Changer Eyecare\",\n          \"it\": \"Cambia Eyecare\",\n          \"no\": \"Bytt Eyecare\",\n          \"sv\": \"Byt Eyecare\",\n          \"pl\": \"Przełącz Eyecare\",\n          \"ru\": \"Переключить Eyecare\",\n          \"ko\": \"아이케어 전환\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Eyecare [[eyecare]]\",\n          \"nl\": \"Eyecare [[eyecare]]\",\n          \"da\": \"Eyecare [[eyecare]]\",\n          \"de\": \"Eyecare [[eyecare]]\",\n          \"es\": \"Eyecare [[eyecare]]\",\n          \"fr\": \"Eyecare [[eyecare]]\",\n          \"it\": \"Eyecare [[eyecare]]\",\n          \"no\": \"Eyecare [[eyecare]]\",\n          \"sv\": \"Eyecare [[eyecare]]\",\n          \"pl\": \"Eyecare [[eyecare]]\",\n          \"ru\": \"Eyecare [[eyecare]]\",\n          \"ko\": \"Eyecare [[eyecare]]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"eyecare\",\n            \"title\": {\n              \"en\": \"Eyecare\",\n              \"nl\": \"Eyecare\",\n              \"da\": \"Eyecare\",\n              \"de\": \"Eyecare\",\n              \"es\": \"Eyecare\",\n              \"fr\": \"Eyecare\",\n              \"it\": \"Eyecare\",\n              \"no\": \"Eyecare\",\n              \"sv\": \"Eyecare\",\n              \"pl\": \"Eyecare\",\n              \"ru\": \"Eyecare\",\n              \"ko\": \"Eyecare\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"on\",\n                \"label\": {\n                  \"en\": \"On\",\n                  \"nl\": \"Aan\",\n                  \"da\": \"Tænd\",\n                  \"de\": \"An\",\n                  \"es\": \"Encendido\",\n                  \"fr\": \"Allumé\",\n                  \"it\": \"Acceso\",\n                  \"no\": \"På\",\n                  \"sv\": \"På\",\n                  \"pl\": \"Włącz\",\n                  \"ru\": \"Вкл\",\n                  \"ko\": \"켜짐\"\n                }\n              },\n              {\n                \"id\": \"off\",\n                \"label\": {\n                  \"en\": \"Off\",\n                  \"nl\": \"Uit\",\n                  \"da\": \"Slukket\",\n                  \"de\": \"Aus\",\n                  \"es\": \"Apagado\",\n                  \"fr\": \"Éteint\",\n                  \"it\": \"Spento\",\n                  \"no\": \"Av\",\n                  \"sv\": \"Av\",\n                  \"pl\": \"Wyłącz\",\n                  \"ru\": \"Выкл\",\n                  \"ko\": \"꺼짐\"\n                }\n              },\n              {\n                \"id\": \"phone\",\n                \"label\": {\n                  \"en\": \"Phone\",\n                  \"nl\": \"Telefoon\",\n                  \"da\": \"Telefon\",\n                  \"de\": \"Telefon\",\n                  \"es\": \"Teléfono\",\n                  \"fr\": \"Téléphone\",\n                  \"it\": \"Telefono\",\n                  \"no\": \"Telefon\",\n                  \"sv\": \"Telefon\",\n                  \"pl\": \"Telefon\",\n                  \"ru\": \"Телефон\",\n                  \"ko\": \"전화기\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Philips Eyecare Lamp\",\n              \"nl\": \"Selecteer Philips Eyecare Lamp\",\n              \"da\": \"Vælg Philips Eyecare Lampe\",\n              \"de\": \"Wählen Sie Philips Eyecare Lampe\",\n              \"es\": \"Seleccione Philips Eyecare Lamp\",\n              \"fr\": \"Sélectionnez Philips Eyecare Lamp\",\n              \"it\": \"Seleziona Philips Eyecare Lamp\",\n              \"no\": \"Velg Philips Eyecare Lamp\",\n              \"sv\": \"Välj Philips Eyecare Lamp\",\n              \"pl\": \"Wybierz lampę Philips Eyecare\",\n              \"ru\": \"Выберите лампу Philips Eyecare\",\n              \"ko\": \"필립스 아이케어 램프 선택\"\n            },\n            \"filter\": \"driver_id=philips-eyecare\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"enableChildLock\",\n        \"title\": {\n          \"en\": \"Enable Child Lock\",\n          \"nl\": \"Instellen kindbeveiliging\",\n          \"da\": \"Aktivér børnelås\",\n          \"de\": \"Kindersicherung aktivieren\",\n          \"es\": \"Activar bloqueo infantil\",\n          \"fr\": \"Activer le verrouillage enfant\",\n          \"it\": \"Abilita blocco bambini\",\n          \"no\": \"Aktiver barnelås\",\n          \"sv\": \"Aktivera barnlås\",\n          \"pl\": \"Włącz blokadę rodzicielską\",\n          \"ru\": \"Включить детский замок\",\n          \"ko\": \"어린이 잠금 장치를 활성화\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set child lock [[childlock]]\",\n          \"nl\": \"Wijzig kindbeveiliging naar [[childlock]]\",\n          \"da\": \"Indstil børnelås [[childlock]]\",\n          \"de\": \"Kindersicherung setzen [[childlock]]\",\n          \"es\": \"Configurar bloqueo infantil [[childlock]]\",\n          \"fr\": \"Définir le verrouillage enfant [[childlock]]\",\n          \"it\": \"Imposta blocco bambini [[childlock]]\",\n          \"no\": \"Sett barnelås [[childlock]]\",\n          \"sv\": \"Ställ in barnlåset [[childlock]]\",\n          \"pl\": \"Ustaw blokadę rodzicielską [[childlock]]\",\n          \"ru\": \"Установить детский замок [[childlock]]\",\n          \"ko\": \"어린이 잠금 설정 [[childlock]]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"childlock\",\n            \"title\": {\n              \"en\": \"Childlock\",\n              \"nl\": \"Kinderslot\",\n              \"da\": \"Børnelås\",\n              \"de\": \"Kindersicherung\",\n              \"es\": \"Bloqueo infantil\",\n              \"fr\": \"Verrouillage enfant\",\n              \"it\": \"Blocco bambini\",\n              \"no\": \"Barnelås\",\n              \"sv\": \"Barnlås\",\n              \"pl\": \"Blokada rodzicielska\",\n              \"ru\": \"Детский замок\",\n              \"ko\": \"어린이 잠금 장치\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"on\",\n                \"label\": {\n                  \"en\": \"On\",\n                  \"nl\": \"Aan\",\n                  \"da\": \"Til\",\n                  \"de\": \"Ein\",\n                  \"es\": \"Encendido\",\n                  \"fr\": \"Activé\",\n                  \"it\": \"Acceso\",\n                  \"no\": \"På\",\n                  \"sv\": \"På\",\n                  \"pl\": \"Włączone\",\n                  \"ru\": \"Вкл\",\n                  \"ko\": \"켜기\"\n                }\n              },\n              {\n                \"id\": \"off\",\n                \"label\": {\n                  \"en\": \"Off\",\n                  \"nl\": \"Uit\",\n                  \"da\": \"Fra\",\n                  \"de\": \"Aus\",\n                  \"es\": \"Apagado\",\n                  \"fr\": \"Désactivé\",\n                  \"it\": \"Spento\",\n                  \"no\": \"Av\",\n                  \"sv\": \"Av\",\n                  \"pl\": \"Wyłączone\",\n                  \"ru\": \"Выкл\",\n                  \"ko\": \"끄기\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=zhimi-fan|dmaker-fan|fan_zhimi_advanced|fan_zhimi_fan_za5\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Enable LED\",\n          \"nl\": \"Instellen LED\",\n          \"da\": \"Aktiver LED\",\n          \"de\": \"LED aktivieren\",\n          \"es\": \"Activar LED\",\n          \"fr\": \"Activer LED\",\n          \"it\": \"Abilita LED\",\n          \"no\": \"Aktiver LED\",\n          \"sv\": \"Aktivera LED\",\n          \"pl\": \"Włącz LED\",\n          \"ru\": \"Включить светодиод\",\n          \"ko\": \"LED 켜기\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set LED [[led]]\",\n          \"nl\": \"Wijzig LED naar [[led]]\",\n          \"da\": \"Indstil LED [[led]]\",\n          \"de\": \"LED einstellen [[led]]\",\n          \"es\": \"Configurar LED [[led]]\",\n          \"fr\": \"Définir la LED [[led]]\",\n          \"it\": \"Imposta LED [[led]]\",\n          \"no\": \"Still inn LED [[led]]\",\n          \"sv\": \"Ställ in LED [[led]]\",\n          \"pl\": \"Ustaw LED [[led]]\",\n          \"ru\": \"Установить светодиод [[led]]\",\n          \"ko\": \"LED 설정 [[led]]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"led\",\n            \"title\": {\n              \"en\": \"LED\",\n              \"nl\": \"LED\",\n              \"da\": \"LED\",\n              \"de\": \"LED\",\n              \"es\": \"LED\",\n              \"fr\": \"LED\",\n              \"it\": \"LED\",\n              \"no\": \"LED\",\n              \"sv\": \"LED\",\n              \"pl\": \"LED\",\n              \"ru\": \"LED\",\n              \"ko\": \"LED\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"label\": {\n                  \"en\": \"Off\",\n                  \"nl\": \"Uit\",\n                  \"da\": \"Slukket\",\n                  \"de\": \"Aus\",\n                  \"es\": \"Apagado\",\n                  \"fr\": \"Éteint\",\n                  \"it\": \"Spento\",\n                  \"no\": \"Av\",\n                  \"sv\": \"Av\",\n                  \"pl\": \"Wyłączony\",\n                  \"ru\": \"Выкл\",\n                  \"ko\": \"끄기\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"On\",\n                  \"nl\": \"Aan\",\n                  \"da\": \"Tændt\",\n                  \"de\": \"Ein\",\n                  \"es\": \"Encendido\",\n                  \"fr\": \"Allumé\",\n                  \"it\": \"Acceso\",\n                  \"no\": \"På\",\n                  \"sv\": \"På\",\n                  \"pl\": \"Włączony\",\n                  \"ru\": \"Вкл\",\n                  \"ko\": \"켜기\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"기기 선택\"\n            },\n            \"filter\": \"driver_id=airpurifier_zhimi_advanced_miot|fan_dmaker_advanced|heater_zhimi_heater_miot|humidifier_xiaomi_humidifier|petwaterdispenser_mmgg_miot|humidifier_deerma_humidifier_miot|humidifier_zhimi_humidifier_miot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"enableLED\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Indstil tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Configurar modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Sett modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus auf [[mode]] einstellen\",\n          \"es\": \"Configurar modo en [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Sett modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]]으로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"label\": {\n                  \"en\": \"Straigth Wind\",\n                  \"nl\": \"Rechte wind\",\n                  \"da\": \"Lige Vind\",\n                  \"de\": \"Gerader Wind\",\n                  \"es\": \"Viento recto\",\n                  \"fr\": \"Vent droit\",\n                  \"it\": \"Vento dritto\",\n                  \"no\": \"Rett vind\",\n                  \"sv\": \"Rak vind\",\n                  \"pl\": \"Prosty wiatr\",\n                  \"ru\": \"Прямой ветер\",\n                  \"ko\": \"직선 바람\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Natural Wind\",\n                  \"nl\": \"Natuurlijke wind\",\n                  \"da\": \"Naturlig Vind\",\n                  \"de\": \"Natürlicher Wind\",\n                  \"es\": \"Viento natural\",\n                  \"fr\": \"Vent naturel\",\n                  \"it\": \"Vento naturale\",\n                  \"no\": \"Naturlig vind\",\n                  \"sv\": \"Naturlig vind\",\n                  \"pl\": \"Naturalny wiatr\",\n                  \"ru\": \"Естественный ветер\",\n                  \"ko\": \"자연풍\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Dmaker Fan\",\n              \"nl\": \"Selecteer Dmaker Fan\",\n              \"da\": \"Vælg Dmaker Ventilator\",\n              \"de\": \"Wählen Sie Dmaker Ventilator\",\n              \"es\": \"Seleccione Dmaker Fan\",\n              \"fr\": \"Sélectionnez Dmaker Ventilateur\",\n              \"it\": \"Seleziona Dmaker Ventilatore\",\n              \"no\": \"Velg Dmaker Vifte\",\n              \"sv\": \"Välj Dmaker Fläkt\",\n              \"pl\": \"Wybierz wentylator Dmaker\",\n              \"ru\": \"Выберите вентилятор Dmaker\",\n              \"ko\": \"Dmaker 팬 선택\"\n            },\n            \"filter\": \"driver_id=fan_dmaker_advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"fanDmakerMode\"\n      },\n      {\n        \"id\": \"fanPowerVacuum\",\n        \"title\": {\n          \"en\": \"Set Fanspeed\",\n          \"nl\": \"Stel ventilator in\",\n          \"da\": \"Indstil ventilatorhastighed\",\n          \"de\": \"Lüftergeschwindigkeit einstellen\",\n          \"es\": \"Ajustar la velocidad del ventilador\",\n          \"fr\": \"Régler la vitesse du ventilateur\",\n          \"it\": \"Imposta velocità ventola\",\n          \"no\": \"Sett viftespeed\",\n          \"sv\": \"Ställ in fläkthastigheten\",\n          \"pl\": \"Ustaw prędkość wentylatora\",\n          \"ru\": \"Установить скорость вентилятора\",\n          \"ko\": \"팬 속도 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set Fanspeed [[fanspeed]]\",\n          \"nl\": \"Stel ventilator in op [[fanspeed]]\",\n          \"da\": \"Indstil ventilatorhastighed [[fanspeed]]\",\n          \"de\": \"Lüftergeschwindigkeit einstellen [[fanspeed]]\",\n          \"es\": \"Ajustar la velocidad del ventilador [[fanspeed]]\",\n          \"fr\": \"Régler la vitesse du ventilateur [[fanspeed]]\",\n          \"it\": \"Imposta velocità ventola [[fanspeed]]\",\n          \"no\": \"Sett viftespeed [[fanspeed]]\",\n          \"sv\": \"Ställ in fläkthastigheten [[fanspeed]]\",\n          \"pl\": \"Ustaw prędkość wentylatora [[fanspeed]]\",\n          \"ru\": \"Установить скорость вентилятора [[fanspeed]]\",\n          \"ko\": \"팬 속도 설정 [[fanspeed]]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"fanspeed\",\n            \"title\": {\n              \"en\": \"Fanspeed\",\n              \"nl\": \"Fan snelheid\",\n              \"da\": \"Ventilatorhastighed\",\n              \"de\": \"Lüftergeschwindigkeit\",\n              \"es\": \"Velocidad del ventilador\",\n              \"fr\": \"Vitesse du ventilateur\",\n              \"it\": \"Velocità della ventola\",\n              \"no\": \"Viftespeed\",\n              \"sv\": \"Fläkthastighet\",\n              \"pl\": \"Prędkość wentylatora\",\n              \"ru\": \"Скорость вентилятора\",\n              \"ko\": \"팬 속도\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"38\",\n                \"label\": {\n                  \"en\": \"Quiet\",\n                  \"nl\": \"Stil\",\n                  \"da\": \"Stille\",\n                  \"de\": \"Leise\",\n                  \"es\": \"Silencioso\",\n                  \"fr\": \"Silencieux\",\n                  \"it\": \"Silenzioso\",\n                  \"no\": \"Stille\",\n                  \"sv\": \"Tyst\",\n                  \"pl\": \"Cichy\",\n                  \"ru\": \"Тихий\",\n                  \"ko\": \"조용한\"\n                }\n              },\n              {\n                \"id\": \"66\",\n                \"label\": {\n                  \"en\": \"Balanced\",\n                  \"nl\": \"Gebalanceerd\",\n                  \"da\": \"Balanceret\",\n                  \"de\": \"Ausgewogen\",\n                  \"es\": \"Equilibrado\",\n                  \"fr\": \"Équilibré\",\n                  \"it\": \"Bilanciato\",\n                  \"no\": \"Balansert\",\n                  \"sv\": \"Balanserad\",\n                  \"pl\": \"Zrównoważony\",\n                  \"ru\": \"Сбалансированный\",\n                  \"ko\": \"균형 잡힌\"\n                }\n              },\n              {\n                \"id\": \"77\",\n                \"label\": {\n                  \"en\": \"Turbo\",\n                  \"nl\": \"Turbo\",\n                  \"da\": \"Turbo\",\n                  \"de\": \"Turbo\",\n                  \"es\": \"Turbo\",\n                  \"fr\": \"Turbo\",\n                  \"it\": \"Turbo\",\n                  \"no\": \"Turbo\",\n                  \"sv\": \"Turbo\",\n                  \"pl\": \"Turbo\",\n                  \"ru\": \"Турбо\",\n                  \"ko\": \"터보\"\n                }\n              },\n              {\n                \"id\": \"90\",\n                \"label\": {\n                  \"en\": \"Max\",\n                  \"nl\": \"Maximum\",\n                  \"da\": \"Maks\",\n                  \"de\": \"Max\",\n                  \"es\": \"Max\",\n                  \"fr\": \"Max\",\n                  \"it\": \"Max\",\n                  \"no\": \"Maks\",\n                  \"sv\": \"Maks\",\n                  \"pl\": \"Maks\",\n                  \"ru\": \"Макс\",\n                  \"ko\": \"맥스\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Robot\",\n              \"nl\": \"Selecteer Mi Robot\",\n              \"da\": \"Vælg Mi Robot\",\n              \"de\": \"Mi Roboter auswählen\",\n              \"es\": \"Selecciona Mi Robot\",\n              \"fr\": \"Sélectionnez Mi Robot\",\n              \"it\": \"Seleziona Mi Robot\",\n              \"no\": \"Velg Mi Robot\",\n              \"sv\": \"Välj Mi Robot\",\n              \"pl\": \"Wybierz Mi Robot\",\n              \"ru\": \"Выберите Mi Robot\",\n              \"ko\": \"Mi 로봇 선택\"\n            },\n            \"filter\": \"driver_id=mi-robot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Sæt tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Establecer modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Sett modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Sæt modus til [[mode]]\",\n          \"de\": \"Modus auf [[mode]] einstellen\",\n          \"es\": \"Establecer modo a [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Sett modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Natural Wind\",\n                  \"nl\": \"Natuur wind\",\n                  \"da\": \"Naturlig vind\",\n                  \"de\": \"Natürlicher Wind\",\n                  \"es\": \"Viento Natural\",\n                  \"fr\": \"Vent Naturel\",\n                  \"it\": \"Vento Naturale\",\n                  \"no\": \"Naturlig vind\",\n                  \"sv\": \"Naturlig vind\",\n                  \"pl\": \"Naturalny wiatr\",\n                  \"ru\": \"Естественный ветер\",\n                  \"ko\": \"자연풍\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Straight Wind\",\n                  \"nl\": \"Rechte wind\",\n                  \"da\": \"Lige vind\",\n                  \"de\": \"Gerader Wind\",\n                  \"es\": \"Viento Directo\",\n                  \"fr\": \"Vent Droit\",\n                  \"it\": \"Vento Dritto\",\n                  \"no\": \"Rett vind\",\n                  \"sv\": \"Rakt vind\",\n                  \"pl\": \"Prosty wiatr\",\n                  \"ru\": \"Прямой ветер\",\n                  \"ko\": \"직선풍\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Fan\",\n              \"nl\": \"Selecteer Fan\",\n              \"da\": \"Vælg ventilator\",\n              \"de\": \"Lüfter auswählen\",\n              \"es\": \"Seleccionar Ventilador\",\n              \"fr\": \"Sélectionner le Ventilateur\",\n              \"it\": \"Seleziona Ventilatore\",\n              \"no\": \"Velg vifte\",\n              \"sv\": \"Välj fläkt\",\n              \"pl\": \"Wybierz Wentylator\",\n              \"ru\": \"Выбрать вентилятор\",\n              \"ko\": \"팬 선택\"\n            },\n            \"filter\": \"driver_id=fan_zhimi_advanced|fan_zhimi_fan_za5\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"fanZhimiMode\"\n      },\n      {\n        \"id\": \"findVacuum\",\n        \"title\": {\n          \"en\": \"Find vacuum cleaner\",\n          \"nl\": \"Vind stofzuiger\",\n          \"da\": \"Find støvsuger\",\n          \"de\": \"Staubsauger finden\",\n          \"es\": \"Encontrar aspiradora\",\n          \"fr\": \"Trouver l'aspirateur\",\n          \"it\": \"Trova l'aspirapolvere\",\n          \"no\": \"Finn støvsugeren\",\n          \"sv\": \"Hitta dammsugare\",\n          \"pl\": \"Znajdź odkurzacz\",\n          \"ru\": \"Найти пылесос\",\n          \"ko\": \"진공 청소기 찾기\"\n        },\n        \"hint\": {\n          \"en\": \"Let the vacuum cleaner tell you where it's at\",\n          \"nl\": \"Laat de stofzuiger vertellen waar hij is\",\n          \"da\": \"Lad støvsugeren fortælle dig, hvor den er\",\n          \"de\": \"Lass den Staubsauger dir sagen, wo er ist\",\n          \"es\": \"Deja que la aspiradora te diga dónde está\",\n          \"fr\": \"Laisse l'aspirateur te dire où il est\",\n          \"it\": \"Lascia che l'aspirapolvere ti dica dove si trova\",\n          \"no\": \"La støvsugeren fortelle deg hvor den er\",\n          \"sv\": \"Låt dammsugaren berätta var den är\",\n          \"pl\": \"Pozwól odkuraczowi powiedzieć, gdzie się znajduje\",\n          \"ru\": \"Пусть пылесос скажет, где он\",\n          \"ko\": \"진공 청소기가 어디에 있는지 알려주세요\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Robot\",\n              \"nl\": \"Selecteer Mi Robot\",\n              \"da\": \"Vælg Mi Robot\",\n              \"de\": \"Wählen Sie Mi Robot\",\n              \"es\": \"Seleccionar Mi Robot\",\n              \"fr\": \"Sélectionner Mi Robot\",\n              \"it\": \"Seleziona Mi Robot\",\n              \"no\": \"Velg Mi Robot\",\n              \"sv\": \"Välj Mi Robot\",\n              \"pl\": \"Wybierz Mi Robot\",\n              \"ru\": \"Выберите Mi Robot\",\n              \"ko\": \"Mi Robot 선택\"\n            },\n            \"filter\": \"driver_id=mi-robot|vacuum_mi_rockrobo_vacuum_advanced|vacuum_mi_rockrobo_vacuum_t6\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Play custom radio station\",\n          \"nl\": \"Afspelen custom radio station\",\n          \"da\": \"Afspil tilpasset radiostation\",\n          \"de\": \"Spiele benutzerdefinierten Radiosender\",\n          \"es\": \"Reproduce emisora de radio personalizada\",\n          \"fr\": \"Lire station de radio personnalisée\",\n          \"it\": \"Riproduci stazione radio personalizzata\",\n          \"no\": \"Spill tilpasset radiostasjon\",\n          \"sv\": \"Spela anpassad radiostation\",\n          \"pl\": \"Odtwórz dostosowaną stację radiową\",\n          \"ru\": \"Воспроизвести пользовательскую радиостанцию\",\n          \"ko\": \"맞춤형 라디오 방송국 재생\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Play custom radio station [[id]] on url [[url]] with volume [[volume]]\",\n          \"nl\": \"Afspelen custom radio station [[id]] op [[url]] met volume [[volume]]\",\n          \"da\": \"Afspil tilpasset radiostation [[id]] på url [[url]] med lydstyrke [[volume]]\",\n          \"de\": \"Spiele benutzerdefinierten Radiosender [[id]] auf URL [[url]] mit Lautstärke [[volume]]\",\n          \"es\": \"Reproduce emisora de radio personalizada [[id]] en url [[url]] con volumen [[volume]]\",\n          \"fr\": \"Lire station de radio personnalisée [[id]] sur url [[url]] avec volume [[volume]]\",\n          \"it\": \"Riproduci stazione radio personalizzata [[id]] su url [[url]] con volume [[volume]]\",\n          \"no\": \"Spill tilpasset radiostasjon [[id]] på url [[url]] med volum [[volume]]\",\n          \"sv\": \"Spela anpassad radiostation [[id]] på url [[url]] med volym [[volume]]\",\n          \"pl\": \"Odtwórz dostosowaną stację radiową [[id]] na url [[url]] z głośnością [[volume]]\",\n          \"ru\": \"Воспроизведите пользовательскую радиостанцию [[id]] на url [[url]] с громкостью [[volume]]\",\n          \"ko\": \"맞춤형 라디오 방송국 [[id]]의 url [[url]]에서 볼륨 [[volume]]으로 재생\"\n        },\n        \"args\": [\n          {\n            \"name\": \"id\",\n            \"title\": {\n              \"en\": \"Station ID\",\n              \"nl\": \"Station ID\",\n              \"da\": \"Station ID\",\n              \"de\": \"Sender-ID\",\n              \"es\": \"ID de estación\",\n              \"fr\": \"ID de la station\",\n              \"it\": \"ID stazione\",\n              \"no\": \"Stasjons-ID\",\n              \"sv\": \"Stations-ID\",\n              \"pl\": \"ID stacji\",\n              \"ru\": \"ID станции\",\n              \"ko\": \"방송국 ID\"\n            },\n            \"type\": \"text\",\n            \"placeholder\": {\n              \"en\": \"ID\",\n              \"nl\": \"ID\",\n              \"da\": \"ID\",\n              \"de\": \"ID\",\n              \"es\": \"ID\",\n              \"fr\": \"ID\",\n              \"it\": \"ID\",\n              \"no\": \"ID\",\n              \"sv\": \"ID\",\n              \"pl\": \"ID\",\n              \"ru\": \"ID\",\n              \"ko\": \"ID\"\n            }\n          },\n          {\n            \"name\": \"url\",\n            \"title\": {\n              \"en\": \"URL\",\n              \"nl\": \"URL\",\n              \"da\": \"URL\",\n              \"de\": \"URL\",\n              \"es\": \"URL\",\n              \"fr\": \"URL\",\n              \"it\": \"URL\",\n              \"no\": \"URL\",\n              \"sv\": \"URL\",\n              \"pl\": \"URL\",\n              \"ru\": \"URL\",\n              \"ko\": \"URL\"\n            },\n            \"type\": \"text\",\n            \"placeholder\": {\n              \"en\": \"URL\",\n              \"nl\": \"URL\",\n              \"da\": \"URL\",\n              \"de\": \"URL\",\n              \"es\": \"URL\",\n              \"fr\": \"URL\",\n              \"it\": \"URL\",\n              \"no\": \"URL\",\n              \"sv\": \"URL\",\n              \"pl\": \"URL\",\n              \"ru\": \"URL\",\n              \"ko\": \"URL\"\n            }\n          },\n          {\n            \"type\": \"range\",\n            \"title\": {\n              \"en\": \"Volume\",\n              \"nl\": \"Volume\",\n              \"da\": \"Volumen\",\n              \"de\": \"Lautstärke\",\n              \"es\": \"Volumen\",\n              \"fr\": \"Volume\",\n              \"it\": \"Volume\",\n              \"no\": \"Volum\",\n              \"sv\": \"Volym\",\n              \"pl\": \"Głośność\",\n              \"ru\": \"Громкость\",\n              \"ko\": \"볼륨\"\n            },\n            \"name\": \"volume\",\n            \"min\": 0,\n            \"max\": 1,\n            \"step\": 0.01,\n            \"label\": \"%\",\n            \"labelMultiplier\": 100,\n            \"labelDecimals\": 0\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Gateway\",\n              \"nl\": \"Selecteer Gateway\",\n              \"da\": \"Vælg Gateway\",\n              \"de\": \"Gateway auswählen\",\n              \"es\": \"Seleccionar Gateway\",\n              \"fr\": \"Sélectionner la passerelle\",\n              \"it\": \"Seleziona Gateway\",\n              \"no\": \"Velg Gateway\",\n              \"sv\": \"Välj Gateway\",\n              \"pl\": \"Wybierz bramę\",\n              \"ru\": \"Выберите шлюз\",\n              \"ko\": \"게이트웨이 선택\"\n            },\n            \"filter\": \"driver_id=gateway\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"gateway_custom_radio\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Play effect\",\n          \"nl\": \"Speel effect\",\n          \"da\": \"Afspil effekt\",\n          \"de\": \"Effekt abspielen\",\n          \"es\": \"Reproducir efecto\",\n          \"fr\": \"Jouer l'effet\",\n          \"it\": \"Riproduci effetto\",\n          \"no\": \"Spill av effekt\",\n          \"sv\": \"Spela effekt\",\n          \"pl\": \"Odtwórz efekt\",\n          \"ru\": \"Воспроизвести эффект\",\n          \"ko\": \"효과 재생\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Play effect [[toneID]]\",\n          \"nl\": \"Speel effect [[toneID]]\",\n          \"da\": \"Afspil effekt [[toneID]]\",\n          \"de\": \"Effekt abspielen [[toneID]]\",\n          \"es\": \"Reproducir efecto [[toneID]]\",\n          \"fr\": \"Jouer l'effet [[toneID]]\",\n          \"it\": \"Riproduci effetto [[toneID]]\",\n          \"no\": \"Spill av effekt [[toneID]]\",\n          \"sv\": \"Spela effekt [[toneID]]\",\n          \"pl\": \"Odtwórz efekt [[toneID]]\",\n          \"ru\": \"Воспроизвести эффект [[toneID]]\",\n          \"ko\": \"효과 재생 [[toneID]]\"\n        },\n        \"args\": [\n          {\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Effect ID\",\n              \"nl\": \"Effect ID\",\n              \"da\": \"Effekt-ID\",\n              \"de\": \"Effekt-ID\",\n              \"es\": \"ID de efecto\",\n              \"fr\": \"ID d'effet\",\n              \"it\": \"ID effetto\",\n              \"no\": \"Effekt-ID\",\n              \"sv\": \"Effekt-ID\",\n              \"pl\": \"ID efektu\",\n              \"ru\": \"ID эффекта\",\n              \"ko\": \"효과 ID\"\n            },\n            \"name\": \"toneID\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"label\": {\n                  \"en\": \"Police car 1\",\n                  \"da\": \"Politibil 1\",\n                  \"de\": \"Polizeiauto 1\",\n                  \"es\": \"Coche de policía 1\",\n                  \"fr\": \"Voiture de police 1\",\n                  \"it\": \"Auto della polizia 1\",\n                  \"no\": \"Politibil 1\",\n                  \"sv\": \"Polisbil 1\",\n                  \"pl\": \"Radiowóz 1\",\n                  \"ru\": \"Полицейская машина 1\",\n                  \"ko\": \"경찰차 1\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Police car 2\",\n                  \"da\": \"Politibil 2\",\n                  \"de\": \"Polizeiauto 2\",\n                  \"es\": \"Coche de policía 2\",\n                  \"fr\": \"Voiture de police 2\",\n                  \"it\": \"Auto della polizia 2\",\n                  \"no\": \"Politibil 2\",\n                  \"sv\": \"Polisbil 2\",\n                  \"pl\": \"Radiowóz 2\",\n                  \"ru\": \"Полицейская машина 2\",\n                  \"ko\": \"경찰차 2\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Accident\",\n                  \"da\": \"Uheld\",\n                  \"de\": \"Unfall\",\n                  \"es\": \"Accidente\",\n                  \"fr\": \"Accident\",\n                  \"it\": \"Incidente\",\n                  \"no\": \"Ulykke\",\n                  \"sv\": \"Olycka\",\n                  \"pl\": \"Wypadek\",\n                  \"ru\": \"Авария\",\n                  \"ko\": \"사고\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"Countdown\",\n                  \"da\": \"Nedtælling\",\n                  \"de\": \"Countdown\",\n                  \"es\": \"Cuenta regresiva\",\n                  \"fr\": \"Compte à rebours\",\n                  \"it\": \"Conto alla rovescia\",\n                  \"no\": \"Nedtelling\",\n                  \"sv\": \"Nedräkning\",\n                  \"pl\": \"Odliczanie\",\n                  \"ru\": \"Обратный отсчет\",\n                  \"ko\": \"카운트다운\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"label\": {\n                  \"en\": \"Ghost\",\n                  \"da\": \"Spøgelse\",\n                  \"de\": \"Gespenst\",\n                  \"es\": \"Fantasma\",\n                  \"fr\": \"Fantôme\",\n                  \"it\": \"Fantasma\",\n                  \"no\": \"Spøkelse\",\n                  \"sv\": \"Spöke\",\n                  \"pl\": \"Duch\",\n                  \"ru\": \"Призрак\",\n                  \"ko\": \"유령\"\n                }\n              },\n              {\n                \"id\": \"5\",\n                \"label\": {\n                  \"en\": \"Sniper rifle\",\n                  \"da\": \"Snigskytteriffel\",\n                  \"de\": \"Scharfschützengewehr\",\n                  \"es\": \"Rifle de francotirador\",\n                  \"fr\": \"Fusil de sniper\",\n                  \"it\": \"Fucile da cecchino\",\n                  \"no\": \"Snikskytterifle\",\n                  \"sv\": \"Krypskyttegevär\",\n                  \"pl\": \"Karabin snajperski\",\n                  \"ru\": \"Снайперская винтовка\",\n                  \"ko\": \"저격 소총\"\n                }\n              },\n              {\n                \"id\": \"6\",\n                \"label\": {\n                  \"en\": \"Battle\",\n                  \"da\": \"Kamp\",\n                  \"de\": \"Schlacht\",\n                  \"es\": \"Batalla\",\n                  \"fr\": \"Bataille\",\n                  \"it\": \"Battaglia\",\n                  \"no\": \"Kamp\",\n                  \"sv\": \"Strid\",\n                  \"pl\": \"Bitwa\",\n                  \"ru\": \"Битва\",\n                  \"ko\": \"전투\"\n                }\n              },\n              {\n                \"id\": \"7\",\n                \"label\": {\n                  \"en\": \"Air raid\",\n                  \"da\": \"Luftangreb\",\n                  \"de\": \"Luftangriff\",\n                  \"es\": \"Ataque aéreo\",\n                  \"fr\": \"Raid aérien\",\n                  \"it\": \"Incursione aerea\",\n                  \"no\": \"Luftangrep\",\n                  \"sv\": \"Flyganfall\",\n                  \"pl\": \"Nalot\",\n                  \"ru\": \"Воздушный налет\",\n                  \"ko\": \"공습\"\n                }\n              },\n              {\n                \"id\": \"8\",\n                \"label\": {\n                  \"en\": \"Bark\",\n                  \"da\": \"Gøen\",\n                  \"de\": \"Bellen\",\n                  \"es\": \"Ladrido\",\n                  \"fr\": \"Aboiement\",\n                  \"it\": \"Abbaiare\",\n                  \"no\": \"Bjeffing\",\n                  \"sv\": \"Skall\",\n                  \"pl\": \"Szczekanie\",\n                  \"ru\": \"Лай\",\n                  \"ko\": \"짖다\"\n                }\n              },\n              {\n                \"id\": \"10\",\n                \"label\": {\n                  \"en\": \"Doorbell\",\n                  \"da\": \"Dørklokke\",\n                  \"de\": \"Türklingel\",\n                  \"es\": \"Timbre\",\n                  \"fr\": \"Sonnette\",\n                  \"it\": \"Campanello\",\n                  \"no\": \"Ringeklokke\",\n                  \"sv\": \"Dörrklocka\",\n                  \"pl\": \"Dzwonek do drzwi\",\n                  \"ru\": \"Дверной звонок\",\n                  \"ko\": \"문 벨\"\n                }\n              },\n              {\n                \"id\": \"11\",\n                \"label\": {\n                  \"en\": \"Knock at a door\",\n                  \"da\": \"Banke på en dør\",\n                  \"de\": \"Klopfen an der Tür\",\n                  \"es\": \"Llamar a la puerta\",\n                  \"fr\": \"Frapper à une porte\",\n                  \"it\": \"Bussare alla porta\",\n                  \"no\": \"Banke på en dør\",\n                  \"sv\": \"Knacka på en dörr\",\n                  \"pl\": \"Pukanie do drzwi\",\n                  \"ru\": \"стучать в дверь\",\n                  \"ko\": \"문을 두드리다\"\n                }\n              },\n              {\n                \"id\": \"12\",\n                \"label\": {\n                  \"en\": \"Amuse\",\n                  \"da\": \"Underholde\",\n                  \"de\": \"Unterhalten\",\n                  \"es\": \"Divertir\",\n                  \"fr\": \"Amuser\",\n                  \"it\": \"Divertire\",\n                  \"no\": \"Underholde\",\n                  \"sv\": \"Underhålla\",\n                  \"pl\": \"Bawić\",\n                  \"ru\": \"развлекать\",\n                  \"ko\": \"즐겁게 하다\"\n                }\n              },\n              {\n                \"id\": \"13\",\n                \"label\": {\n                  \"en\": \"Alarm clock\",\n                  \"da\": \"Vækkeur\",\n                  \"de\": \"Wecker\",\n                  \"es\": \"Reloj despertador\",\n                  \"fr\": \"Réveil\",\n                  \"it\": \"Sveglia\",\n                  \"no\": \"Vekkerklokke\",\n                  \"sv\": \"Väckarklocka\",\n                  \"pl\": \"Budzik\",\n                  \"ru\": \"Будильник\",\n                  \"ko\": \"알람 시계\"\n                }\n              },\n              {\n                \"id\": \"20\",\n                \"label\": {\n                  \"en\": \"MiMix\",\n                  \"da\": \"MiMix\",\n                  \"de\": \"MiMix\",\n                  \"es\": \"MiMix\",\n                  \"fr\": \"MiMix\",\n                  \"it\": \"MiMix\",\n                  \"no\": \"MiMix\",\n                  \"sv\": \"MiMix\",\n                  \"pl\": \"MiMix\",\n                  \"ru\": \"MiMix\",\n                  \"ko\": \"MiMix\"\n                }\n              },\n              {\n                \"id\": \"21\",\n                \"label\": {\n                  \"en\": \"Enthusiastic\",\n                  \"da\": \"Entusiastisk\",\n                  \"de\": \"Enthusiastisch\",\n                  \"es\": \"Entusiasta\",\n                  \"fr\": \"Enthousiaste\",\n                  \"it\": \"Entusiasta\",\n                  \"no\": \"Entusiastisk\",\n                  \"sv\": \"Entusiastisk\",\n                  \"pl\": \"Entuzjastyczny\",\n                  \"ru\": \"Восторженный\",\n                  \"ko\": \"열렬한\"\n                }\n              },\n              {\n                \"id\": \"22\",\n                \"label\": {\n                  \"en\": \"GuitarClassic\",\n                  \"da\": \"GuitarClassic\",\n                  \"de\": \"GuitarClassic\",\n                  \"es\": \"GuitarClassic\",\n                  \"fr\": \"GuitarClassic\",\n                  \"it\": \"GuitarClassic\",\n                  \"no\": \"GuitarClassic\",\n                  \"sv\": \"GuitarClassic\",\n                  \"pl\": \"GuitarClassic\",\n                  \"ru\": \"GuitarClassic\",\n                  \"ko\": \"GuitarClassic\"\n                }\n              },\n              {\n                \"id\": \"23\",\n                \"label\": {\n                  \"en\": \"IceWorldPiano\",\n                  \"da\": \"IceWorldPiano\",\n                  \"de\": \"IceWorldPiano\",\n                  \"es\": \"IceWorldPiano\",\n                  \"fr\": \"IceWorldPiano\",\n                  \"it\": \"IceWorldPiano\",\n                  \"no\": \"IceWorldPiano\",\n                  \"sv\": \"IceWorldPiano\",\n                  \"pl\": \"IceWorldPiano\",\n                  \"ru\": \"IceWorldPiano\",\n                  \"ko\": \"IceWorldPiano\"\n                }\n              },\n              {\n                \"id\": \"24\",\n                \"label\": {\n                  \"en\": \"LeisureTime\",\n                  \"da\": \"LeisureTime\",\n                  \"de\": \"LeisureTime\",\n                  \"es\": \"LeisureTime\",\n                  \"fr\": \"LeisureTime\",\n                  \"it\": \"LeisureTime\",\n                  \"no\": \"LeisureTime\",\n                  \"sv\": \"LeisureTime\",\n                  \"pl\": \"LeisureTime\",\n                  \"ru\": \"LeisureTime\",\n                  \"ko\": \"LeisureTime\"\n                }\n              },\n              {\n                \"id\": \"25\",\n                \"label\": {\n                  \"en\": \"ChildHood\",\n                  \"da\": \"ChildHood\",\n                  \"de\": \"ChildHood\",\n                  \"es\": \"ChildHood\",\n                  \"fr\": \"ChildHood\",\n                  \"it\": \"ChildHood\",\n                  \"no\": \"ChildHood\",\n                  \"sv\": \"ChildHood\",\n                  \"pl\": \"ChildHood\",\n                  \"ru\": \"ChildHood\",\n                  \"ko\": \"ChildHood\"\n                }\n              },\n              {\n                \"id\": \"26\",\n                \"label\": {\n                  \"en\": \"MorningStreamLiet\",\n                  \"da\": \"MorningStreamLiet\",\n                  \"de\": \"MorningStreamLiet\",\n                  \"es\": \"MorningStreamLiet\",\n                  \"fr\": \"MorningStreamLiet\",\n                  \"it\": \"MorningStreamLiet\",\n                  \"no\": \"MorningStreamLiet\",\n                  \"sv\": \"MorningStreamLiet\",\n                  \"pl\": \"MorningStreamLiet\",\n                  \"ru\": \"MorningStreamLiet\",\n                  \"ko\": \"MorningStreamLiet\"\n                }\n              },\n              {\n                \"id\": \"27\",\n                \"label\": {\n                  \"en\": \"MusicBox\",\n                  \"da\": \"MusicBox\",\n                  \"de\": \"MusicBox\",\n                  \"es\": \"MusicBox\",\n                  \"fr\": \"MusicBox\",\n                  \"it\": \"MusicBox\",\n                  \"no\": \"MusicBox\",\n                  \"sv\": \"MusicBox\",\n                  \"pl\": \"MusicBox\",\n                  \"ru\": \"MusicBox\",\n                  \"ko\": \"MusicBox\"\n                }\n              },\n              {\n                \"id\": \"28\",\n                \"label\": {\n                  \"en\": \"Orange\",\n                  \"da\": \"Orange\",\n                  \"de\": \"Orange\",\n                  \"es\": \"Naranja\",\n                  \"fr\": \"Orange\",\n                  \"it\": \"Arancio\",\n                  \"no\": \"Oransje\",\n                  \"sv\": \"Orange\",\n                  \"pl\": \"Pomarańczowy\",\n                  \"ru\": \"Оранжевый\",\n                  \"ko\": \"오렌지\"\n                }\n              },\n              {\n                \"id\": \"29\",\n                \"label\": {\n                  \"en\": \"Thinker\",\n                  \"da\": \"Tænker\",\n                  \"de\": \"Denker\",\n                  \"es\": \"Pensador\",\n                  \"fr\": \"Penseur\",\n                  \"it\": \"Pensatore\",\n                  \"no\": \"Tenker\",\n                  \"sv\": \"Tänker\",\n                  \"pl\": \"Myśliciel\",\n                  \"ru\": \"Мыслитель\",\n                  \"ko\": \"사색가\"\n                }\n              },\n              {\n                \"id\": \"10000\",\n                \"label\": {\n                  \"en\": \"MUTE\",\n                  \"da\": \"STUM\",\n                  \"de\": \"STUMM\",\n                  \"es\": \"MUDO\",\n                  \"fr\": \"SILENCE\",\n                  \"it\": \"MUTO\",\n                  \"no\": \"STILLE\",\n                  \"sv\": \"TYST\",\n                  \"pl\": \"WYŁĄCZONY\",\n                  \"ru\": \"БЕСШУМНЫЙ\",\n                  \"ko\": \"무음\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Gateway\",\n              \"nl\": \"Selecteer Gateway\",\n              \"da\": \"Vælg Gateway\",\n              \"de\": \"Gateway auswählen\",\n              \"es\": \"Seleccionar Gateway\",\n              \"fr\": \"Sélectionner la passerelle\",\n              \"it\": \"Seleziona Gateway\",\n              \"no\": \"Velg Gateway\",\n              \"sv\": \"Välj Gateway\",\n              \"pl\": \"Wybierz Gateway\",\n              \"ru\": \"Выберите шлюз\",\n              \"ko\": \"게이트웨이 선택\"\n            },\n            \"filter\": \"driver_id=gateway\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"gateway_play_effect\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Play favorite radio station\",\n          \"nl\": \"Afspelen favoriete radio station\",\n          \"da\": \"Afspil favorit radiostation\",\n          \"de\": \"Favoriten-Radiosender abspielen\",\n          \"es\": \"Reproducir emisora de radio favorita\",\n          \"fr\": \"Jouer la station de radio favorite\",\n          \"it\": \"Riproduci stazione radio preferita\",\n          \"no\": \"Spill favoritt radiostasjon\",\n          \"sv\": \"Spela favorit radiostation\",\n          \"pl\": \"Odtwórz ulubioną stację radiową\",\n          \"ru\": \"Воспроизвести любимую радиостанцию\",\n          \"ko\": \"좋아하는 라디오 방송 재생\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Play favorite radio station [[favoriteID]] with volume [[volume]]\",\n          \"nl\": \"Afspelen favoriete radio station [[favoriteID]] met volume [[volume]]\",\n          \"da\": \"Afspil favorit radiostation [[favoriteID]] med lydstyrke [[volume]]\",\n          \"de\": \"Favoriten-Radiosender [[favoriteID]] mit Lautstärke [[volume]] abspielen\",\n          \"es\": \"Reproducir emisora de radio favorita [[favoriteID]] con volumen [[volume]]\",\n          \"fr\": \"Jouer la station de radio favorite [[favoriteID]] avec le volume [[volume]]\",\n          \"it\": \"Riproduci stazione radio preferita [[favoriteID]] con volume [[volume]]\",\n          \"no\": \"Spill favoritt radiostasjon [[favoriteID]] med volum [[volume]]\",\n          \"sv\": \"Spela favorit radiostation [[favoriteID]] med volym [[volume]]\",\n          \"pl\": \"Odtwórz ulubioną stację radiową [[favoriteID]] z głośnością [[volume]]\",\n          \"ru\": \"Воспроизвести любимую радиостанцию [[favoriteID]] с громкостью [[volume]]\",\n          \"ko\": \"좋아하는 라디오 방송 [[favoriteID]] 볼륨 [[volume]]으로 재생\"\n        },\n        \"args\": [\n          {\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Station ID\",\n              \"nl\": \"Station ID\",\n              \"da\": \"Station ID\",\n              \"de\": \"Stations-ID\",\n              \"es\": \"ID de estación\",\n              \"fr\": \"ID de la station\",\n              \"it\": \"ID stazione\",\n              \"no\": \"Stasjons-ID\",\n              \"sv\": \"Stations-ID\",\n              \"pl\": \"ID stacji\",\n              \"ru\": \"Идентификатор станции\",\n              \"ko\": \"스테이션 ID\"\n            },\n            \"name\": \"favoriteID\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"label\": {\n                  \"en\": \"1 - favorite radio\",\n                  \"nl\": \"1 - favoriete station\",\n                  \"da\": \"1 - favorit radio\",\n                  \"de\": \"1 - Lieblingsradio\",\n                  \"es\": \"1 - radio favorita\",\n                  \"fr\": \"1 - radio favorite\",\n                  \"it\": \"1 - radio preferita\",\n                  \"no\": \"1 - favoritt radio\",\n                  \"sv\": \"1 - favorit radio\",\n                  \"pl\": \"1 - ulubione radio\",\n                  \"ru\": \"1 - любимое радио\",\n                  \"ko\": \"1 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"2 - favorite radio\",\n                  \"nl\": \"2 - favoriete station\",\n                  \"da\": \"2 - favorit radio\",\n                  \"de\": \"2 - Lieblingsradio\",\n                  \"es\": \"2 - radio favorita\",\n                  \"fr\": \"2 - radio favorite\",\n                  \"it\": \"2 - radio preferita\",\n                  \"no\": \"2 - favoritt radio\",\n                  \"sv\": \"2 - favorit radio\",\n                  \"pl\": \"2 - ulubione radio\",\n                  \"ru\": \"2 - любимое радио\",\n                  \"ko\": \"2 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"3 - favorite radio\",\n                  \"nl\": \"3 - favoriete station\",\n                  \"da\": \"3 - favorit radio\",\n                  \"de\": \"3 - Lieblingsradio\",\n                  \"es\": \"3 - radio favorita\",\n                  \"fr\": \"3 - radio favorite\",\n                  \"it\": \"3 - radio preferita\",\n                  \"no\": \"3 - favoritt radio\",\n                  \"sv\": \"3 - favorit radio\",\n                  \"pl\": \"3 - ulubione radio\",\n                  \"ru\": \"3 - любимое радио\",\n                  \"ko\": \"3 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"4 - favorite radio\",\n                  \"nl\": \"4 - favoriete station\",\n                  \"da\": \"4 - favorit radio\",\n                  \"de\": \"4 - Lieblingsradio\",\n                  \"es\": \"4 - radio favorita\",\n                  \"fr\": \"4 - radio favorite\",\n                  \"it\": \"4 - radio preferita\",\n                  \"no\": \"4 - favoritt radio\",\n                  \"sv\": \"4 - favorit radio\",\n                  \"pl\": \"4 - ulubione radio\",\n                  \"ru\": \"4 - любимое радио\",\n                  \"ko\": \"4 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"label\": {\n                  \"en\": \"5 - favorite radio\",\n                  \"nl\": \"5 - favoriete station\",\n                  \"da\": \"5 - favorit radio\",\n                  \"de\": \"5 - Lieblingsradio\",\n                  \"es\": \"5 - radio favorita\",\n                  \"fr\": \"5 - radio favorite\",\n                  \"it\": \"5 - radio preferita\",\n                  \"no\": \"5 - favoritt radio\",\n                  \"sv\": \"5 - favorit radio\",\n                  \"pl\": \"5 - ulubione radio\",\n                  \"ru\": \"5 - любимое радио\",\n                  \"ko\": \"5 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"5\",\n                \"label\": {\n                  \"en\": \"6 - favorite radio\",\n                  \"nl\": \"6 - favoriete station\",\n                  \"da\": \"6 - favorit radio\",\n                  \"de\": \"6 - Lieblingsradio\",\n                  \"es\": \"6 - radio favorita\",\n                  \"fr\": \"6 - radio favorite\",\n                  \"it\": \"6 - radio preferita\",\n                  \"no\": \"6 - favoritt radio\",\n                  \"sv\": \"6 - favorit radio\",\n                  \"pl\": \"6 - ulubione radio\",\n                  \"ru\": \"6 - любимое радио\",\n                  \"ko\": \"6 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"6\",\n                \"label\": {\n                  \"en\": \"7 - favorite radio\",\n                  \"nl\": \"7 - favoriete station\",\n                  \"da\": \"7 - favorit radio\",\n                  \"de\": \"7 - Lieblingsradio\",\n                  \"es\": \"7 - radio favorita\",\n                  \"fr\": \"7 - radio favorite\",\n                  \"it\": \"7 - radio preferita\",\n                  \"no\": \"7 - favoritt radio\",\n                  \"sv\": \"7 - favorit radio\",\n                  \"pl\": \"7 - ulubione radio\",\n                  \"ru\": \"7 - любимое радио\",\n                  \"ko\": \"7 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"7\",\n                \"label\": {\n                  \"en\": \"8 - favorite radio\",\n                  \"nl\": \"8 - favoriete station\",\n                  \"da\": \"8 - favorit radio\",\n                  \"de\": \"8 - Lieblingsradio\",\n                  \"es\": \"8 - radio favorita\",\n                  \"fr\": \"8 - radio favorite\",\n                  \"it\": \"8 - radio preferita\",\n                  \"no\": \"8 - favoritt radio\",\n                  \"sv\": \"8 - favorit radio\",\n                  \"pl\": \"8 - ulubione radio\",\n                  \"ru\": \"8 - любимое радио\",\n                  \"ko\": \"8 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"8\",\n                \"label\": {\n                  \"en\": \"9 - favorite radio\",\n                  \"nl\": \"9 - favoriete station\",\n                  \"da\": \"9 - favorit radio\",\n                  \"de\": \"9 - Lieblingsradio\",\n                  \"es\": \"9 - radio favorita\",\n                  \"fr\": \"9 - radio favorite\",\n                  \"it\": \"9 - radio preferita\",\n                  \"no\": \"9 - favoritt radio\",\n                  \"sv\": \"9 - favorit radio\",\n                  \"pl\": \"9 - ulubione radio\",\n                  \"ru\": \"9 - любимое радио\",\n                  \"ko\": \"9 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"9\",\n                \"label\": {\n                  \"en\": \"10 - favorite radio\",\n                  \"nl\": \"10 - favoriete station\",\n                  \"da\": \"10 - favorit radio\",\n                  \"de\": \"10 - Lieblingsradio\",\n                  \"es\": \"10 - radio favorita\",\n                  \"fr\": \"10 - radio favorite\",\n                  \"it\": \"10 - radio preferita\",\n                  \"no\": \"10 - favoritt radio\",\n                  \"sv\": \"10 - favorit radio\",\n                  \"pl\": \"10 - ulubione radio\",\n                  \"ru\": \"10 - любимое радио\",\n                  \"ko\": \"10 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"10\",\n                \"label\": {\n                  \"en\": \"11 - favorite radio\",\n                  \"nl\": \"11 - favoriete station\",\n                  \"da\": \"11 - favorit radio\",\n                  \"de\": \"11 - Lieblingsradio\",\n                  \"es\": \"11 - radio favorita\",\n                  \"fr\": \"11 - radio favorite\",\n                  \"it\": \"11 - radio preferita\",\n                  \"no\": \"11 - favoritt radio\",\n                  \"sv\": \"11 - favorit radio\",\n                  \"pl\": \"11 - ulubione radio\",\n                  \"ru\": \"11 - любимое радио\",\n                  \"ko\": \"11 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"11\",\n                \"label\": {\n                  \"en\": \"12 - favorite radio\",\n                  \"nl\": \"12 - favoriete station\",\n                  \"da\": \"12 - favorit radio\",\n                  \"de\": \"12 - Lieblingsradio\",\n                  \"es\": \"12 - radio favorita\",\n                  \"fr\": \"12 - radio favorite\",\n                  \"it\": \"12 - radio preferita\",\n                  \"no\": \"12 - favoritt radio\",\n                  \"sv\": \"12 - favorit radio\",\n                  \"pl\": \"12 - ulubione radio\",\n                  \"ru\": \"12 - любимое радио\",\n                  \"ko\": \"12 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"12\",\n                \"label\": {\n                  \"en\": \"13 - favorite radio\",\n                  \"nl\": \"13 - favoriete station\",\n                  \"da\": \"13 - favorit radio\",\n                  \"de\": \"13 - Lieblingsradio\",\n                  \"es\": \"13 - radio favorita\",\n                  \"fr\": \"13 - radio favorite\",\n                  \"it\": \"13 - radio preferita\",\n                  \"no\": \"13 - favoritt radio\",\n                  \"sv\": \"13 - favorit radio\",\n                  \"pl\": \"13 - ulubione radio\",\n                  \"ru\": \"13 - любимое радио\",\n                  \"ko\": \"13 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"13\",\n                \"label\": {\n                  \"en\": \"14 - favorite radio\",\n                  \"nl\": \"14 - favoriete station\",\n                  \"da\": \"14 - favorit radio\",\n                  \"de\": \"14 - Lieblingsradio\",\n                  \"es\": \"14 - radio favorita\",\n                  \"fr\": \"14 - radio favorite\",\n                  \"it\": \"14 - radio preferita\",\n                  \"no\": \"14 - favoritt radio\",\n                  \"sv\": \"14 - favorit radio\",\n                  \"pl\": \"14 - ulubione radio\",\n                  \"ru\": \"14 - любимое радио\",\n                  \"ko\": \"14 - 좋아하는 라디오\"\n                }\n              },\n              {\n                \"id\": \"13\",\n                \"label\": {\n                  \"en\": \"15 - favorite radio\",\n                  \"nl\": \"15 - favoriete station\",\n                  \"da\": \"15 - favorit radio\",\n                  \"de\": \"15 - Lieblingsradio\",\n                  \"es\": \"15 - radio favorita\",\n                  \"fr\": \"15 - radio favorite\",\n                  \"it\": \"15 - radio preferita\",\n                  \"no\": \"15 - favoritt radio\",\n                  \"sv\": \"15 - favorit radio\",\n                  \"pl\": \"15 - ulubione radio\",\n                  \"ru\": \"15 - любимое радио\",\n                  \"ko\": \"15 - 좋아하는 라디오\"\n                }\n              }\n            ]\n          },\n          {\n            \"type\": \"range\",\n            \"title\": {\n              \"en\": \"Volume\",\n              \"nl\": \"Volume\",\n              \"da\": \"Lydstyrke\",\n              \"de\": \"Lautstärke\",\n              \"es\": \"Volumen\",\n              \"fr\": \"Volume\",\n              \"it\": \"Volume\",\n              \"no\": \"Volum\",\n              \"sv\": \"Volym\",\n              \"pl\": \"Głośność\",\n              \"ru\": \"Громкость\",\n              \"ko\": \"볼륨\"\n            },\n            \"name\": \"volume\",\n            \"min\": 0,\n            \"max\": 1,\n            \"step\": 0.01,\n            \"label\": \"%\",\n            \"labelMultiplier\": 100,\n            \"labelDecimals\": 0\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Robot\",\n              \"nl\": \"Selecteer Mi Robot\",\n              \"da\": \"Vælg Mi Robot\",\n              \"de\": \"Wählen Sie Mi Robot\",\n              \"es\": \"Selecciona Mi Robot\",\n              \"fr\": \"Sélectionnez Mi Robot\",\n              \"it\": \"Seleziona Mi Robot\",\n              \"no\": \"Velg Mi Robot\",\n              \"sv\": \"Välj Mi Robot\",\n              \"pl\": \"Wybierz Mi Robot\",\n              \"ru\": \"Выберите Mi Robot\",\n              \"ko\": \"Mi Robot 선택\"\n            },\n            \"filter\": \"driver_id=gateway\"\n          }\n        ],\n        \"id\": \"gateway_play_radio\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set volume for\",\n          \"nl\": \"Set volume voor\",\n          \"da\": \"Indstil lydstyrke for\",\n          \"de\": \"Lautstärke einstellen für\",\n          \"es\": \"Establecer volumen para\",\n          \"fr\": \"Régler le volume pour\",\n          \"it\": \"Imposta il volume per\",\n          \"no\": \"Sett volum for\",\n          \"sv\": \"Ställ in volymen för\",\n          \"pl\": \"Ustaw głośność dla\",\n          \"ru\": \"Установить громкость для\",\n          \"ko\": \"볼륨 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set volume to [[volume]] for [[target]]\",\n          \"nl\": \"Zet volume naar [[volume]] voor [[target]]\",\n          \"da\": \"Indstil lydstyrke til [[volume]] for [[target]]\",\n          \"de\": \"Lautstärke auf [[volume]] einstellen für [[target]]\",\n          \"es\": \"Establecer volumen a [[volume]] para [[target]]\",\n          \"fr\": \"Régler le volume à [[volume]] pour [[target]]\",\n          \"it\": \"Imposta il volume a [[volume]] per [[target]]\",\n          \"no\": \"Sett volum til [[volume]] for [[target]]\",\n          \"sv\": \"Ställ in volymen till [[volume]] för [[target]]\",\n          \"pl\": \"Ustaw głośność na [[volume]] dla [[target]]\",\n          \"ru\": \"Установить громкость на [[volume]] для [[target]]\",\n          \"ko\": \"[[target]]의 [[volume]]로 볼륨 설정\"\n        },\n        \"args\": [\n          {\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Target\",\n              \"nl\": \"Doel\",\n              \"da\": \"Mål\",\n              \"de\": \"Ziel\",\n              \"es\": \"Objetivo\",\n              \"fr\": \"Cible\",\n              \"it\": \"Obiettivo\",\n              \"no\": \"Mål\",\n              \"sv\": \"Mål\",\n              \"pl\": \"Cel\",\n              \"ru\": \"Цель\",\n              \"ko\": \"대상\"\n            },\n            \"name\": \"target\",\n            \"values\": [\n              {\n                \"id\": \"alarm\",\n                \"label\": {\n                  \"en\": \"Alarm\",\n                  \"nl\": \"Alarm\",\n                  \"da\": \"Alarm\",\n                  \"de\": \"Alarm\",\n                  \"es\": \"Alarma\",\n                  \"fr\": \"Alarme\",\n                  \"it\": \"Allarme\",\n                  \"no\": \"Alarm\",\n                  \"sv\": \"Larm\",\n                  \"pl\": \"Alarm\",\n                  \"ru\": \"Тревога\",\n                  \"ko\": \"알람\"\n                }\n              },\n              {\n                \"id\": \"doorbell\",\n                \"label\": {\n                  \"en\": \"Doorbell\",\n                  \"nl\": \"Deurbel\",\n                  \"da\": \"Dørklokke\",\n                  \"de\": \"Türklingel\",\n                  \"es\": \"Timbre\",\n                  \"fr\": \"Sonnette\",\n                  \"it\": \"Campanello\",\n                  \"no\": \"Ringeklokke\",\n                  \"sv\": \"Dörrklocka\",\n                  \"pl\": \"Dzwonek do drzwi\",\n                  \"ru\": \"Дверной звонок\",\n                  \"ko\": \"초인종\"\n                }\n              },\n              {\n                \"id\": \"prompt\",\n                \"label\": {\n                  \"en\": \"Prompt\",\n                  \"nl\": \"Waarschuwing\",\n                  \"da\": \"Påmindelse\",\n                  \"de\": \"Eingabeaufforderung\",\n                  \"es\": \"Mensaje\",\n                  \"fr\": \"Message\",\n                  \"it\": \"Richiesta\",\n                  \"no\": \"Spørsmål\",\n                  \"sv\": \"Uppmaning\",\n                  \"pl\": \"Komunikat\",\n                  \"ru\": \"Подсказка\",\n                  \"ko\": \"프롬프트\"\n                }\n              },\n              {\n                \"id\": \"radio\",\n                \"label\": {\n                  \"en\": \"Radio\",\n                  \"nl\": \"Radio\",\n                  \"da\": \"Radio\",\n                  \"de\": \"Radio\",\n                  \"es\": \"Radio\",\n                  \"fr\": \"Radio\",\n                  \"it\": \"Radio\",\n                  \"no\": \"Radio\",\n                  \"sv\": \"Radio\",\n                  \"pl\": \"Radio\",\n                  \"ru\": \"Радио\",\n                  \"ko\": \"라디오\"\n                }\n              }\n            ]\n          },\n          {\n            \"type\": \"range\",\n            \"title\": {\n              \"en\": \"Volume\",\n              \"nl\": \"Volume\",\n              \"da\": \"Lydstyrke\",\n              \"de\": \"Lautstärke\",\n              \"es\": \"Volumen\",\n              \"fr\": \"Volume\",\n              \"it\": \"Volume\",\n              \"no\": \"Volum\",\n              \"sv\": \"Volym\",\n              \"pl\": \"Głośność\",\n              \"ru\": \"Громкость\",\n              \"ko\": \"볼륨\"\n            },\n            \"name\": \"volume\",\n            \"min\": 0,\n            \"max\": 1,\n            \"step\": 0.01,\n            \"label\": \"%\",\n            \"labelMultiplier\": 100,\n            \"labelDecimals\": 0\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Gateway\",\n              \"nl\": \"Selecteer Gateway\",\n              \"da\": \"Vælg Gateway\",\n              \"de\": \"Gateway auswählen\",\n              \"es\": \"Seleccionar Gateway\",\n              \"fr\": \"Sélectionner Gateway\",\n              \"it\": \"Seleziona Gateway\",\n              \"no\": \"Velg Gateway\",\n              \"sv\": \"Välj Gateway\",\n              \"pl\": \"Wybierz Gateway\",\n              \"ru\": \"Выберите Gateway\",\n              \"ko\": \"게이트웨이 선택\"\n            },\n            \"filter\": \"driver_id=gateway\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"gateway_set_volume\"\n      },\n      {\n        \"id\": \"goToTargetVacuum\",\n        \"title\": {\n          \"en\": \"Send vacuum cleaner to target\",\n          \"nl\": \"Stuur stofzuiger naar doel\",\n          \"da\": \"Send støvsuger til mål\",\n          \"de\": \"Sende Staubsauger zum Ziel\",\n          \"es\": \"Enviar aspiradora al objetivo\",\n          \"fr\": \"Envoyer l'aspirateur à la cible\",\n          \"it\": \"Invia aspirapolvere al bersaglio\",\n          \"no\": \"Send støvsuger til mål\",\n          \"sv\": \"Skicka dammsugare till mål\",\n          \"pl\": \"Wyślij odkurzacz do celu\",\n          \"ru\": \"Отправить пылесос к цели\",\n          \"ko\": \"진공 청소기를 목표 지점으로 보내기\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Send vacuum cleaner to coordinates X [[xcoordinate]] and Y [[ycoordinate]]\",\n          \"nl\": \"Stuur stofzuiger naar coördinaten X [[xcoordinate]] en Y [[ycoordinate]]\",\n          \"da\": \"Send støvsuger til koordinaterne X [[xcoordinate]] og Y [[ycoordinate]]\",\n          \"de\": \"Senden Sie den Staubsauger zu den Koordinaten X [[xcoordinate]] und Y [[ycoordinate]]\",\n          \"es\": \"Enviar aspiradora a las coordenadas X [[xcoordinate]] e Y [[ycoordinate]]\",\n          \"fr\": \"Envoyer l'aspirateur aux coordonnées X [[xcoordinate]] et Y [[ycoordinate]]\",\n          \"it\": \"Invia l'aspirapolvere alle coordinate X [[xcoordinate]] e Y [[ycoordinate]]\",\n          \"no\": \"Send støvsuger til koordinater X [[xcoordinate]] og Y [[ycoordinate]]\",\n          \"sv\": \"Skicka dammsugare till koordinaterna X [[xcoordinate]] och Y [[ycoordinate]]\",\n          \"pl\": \"Wyślij odkurzacz na współrzędne X [[xcoordinate]] i Y [[ycoordinate]]\",\n          \"ru\": \"Отправить пылесос на координаты X [[xcoordinate]] и Y [[ycoordinate]]\",\n          \"ko\": \"진공 청소기를 X [[xcoordinate]] 및 Y [[ycoordinate]] 좌표로 보내기\"\n        },\n        \"hint\": {\n          \"en\": \"Enter the x and y coordinates of the target: ex. 25000 and 28000\",\n          \"nl\": \"Voer de x en y coördinaten van het doel in: bv. 25000 en 28000\",\n          \"da\": \"Indtast x- og y-koordinaterne for målet: f.eks. 25000 og 28000\",\n          \"de\": \"Geben Sie die x- und y-Koordinaten des Ziels ein: z.B. 25000 und 28000\",\n          \"es\": \"Introduzca las coordenadas x e y del objetivo: ej. 25000 y 28000\",\n          \"fr\": \"Entrez les coordonnées x et y de la cible : ex. 25000 et 28000\",\n          \"it\": \"Inserisci le coordinate x e y del bersaglio: es. 25000 e 28000\",\n          \"no\": \"Skriv inn x- og y-koordinatene til målet: f.eks. 25000 og 28000\",\n          \"sv\": \"Ange x- och y-koordinaterna för målet: ex. 25000 och 28000\",\n          \"pl\": \"Wpisz współrzędne x i y celu: np. 25000 i 28000\",\n          \"ru\": \"Введите координаты x и y цели: например, 25000 и 28000\",\n          \"ko\": \"목표의 x 및 y 좌표를 입력하세요: 예. 25000 및 28000\"\n        },\n        \"args\": [\n          {\n            \"name\": \"xcoordinate\",\n            \"title\": {\n              \"en\": \"X Coordinate\",\n              \"nl\": \"X coördinaat\",\n              \"da\": \"X-koordinat\",\n              \"de\": \"X-Koordinate\",\n              \"es\": \"Coordenada X\",\n              \"fr\": \"Coordonnée X\",\n              \"it\": \"Coordinata X\",\n              \"no\": \"X-koordinat\",\n              \"sv\": \"X-koordinat\",\n              \"pl\": \"Współrzędna X\",\n              \"ru\": \"Координата X\",\n              \"ko\": \"X 좌표\"\n            },\n            \"type\": \"number\",\n            \"placeholder\": {\n              \"en\": \"X Coordinate\",\n              \"nl\": \"X coördinaat\",\n              \"da\": \"X-koordinat\",\n              \"de\": \"X-Koordinate\",\n              \"es\": \"Coordenada X\",\n              \"fr\": \"Coordonnée X\",\n              \"it\": \"Coordinata X\",\n              \"no\": \"X-koordinat\",\n              \"sv\": \"X-koordinat\",\n              \"pl\": \"Współrzędna X\",\n              \"ru\": \"Координата X\",\n              \"ko\": \"X 좌표\"\n            }\n          },\n          {\n            \"name\": \"ycoordinate\",\n            \"title\": {\n              \"en\": \"Y Coordinate\",\n              \"nl\": \"Y coördinaat\",\n              \"da\": \"Y-koordinat\",\n              \"de\": \"Y-Koordinate\",\n              \"es\": \"Coordenada Y\",\n              \"fr\": \"Coordonnée Y\",\n              \"it\": \"Coordinata Y\",\n              \"no\": \"Y-koordinat\",\n              \"sv\": \"Y-koordinat\",\n              \"pl\": \"Współrzędna Y\",\n              \"ru\": \"Координата Y\",\n              \"ko\": \"Y 좌표\"\n            },\n            \"type\": \"number\",\n            \"placeholder\": {\n              \"en\": \"Y Coordinate\",\n              \"nl\": \"Y coördinaat\",\n              \"da\": \"Y-koordinat\",\n              \"de\": \"Y-Koordinate\",\n              \"es\": \"Coordenada Y\",\n              \"fr\": \"Coordonnée Y\",\n              \"it\": \"Coordinata Y\",\n              \"no\": \"Y-koordinat\",\n              \"sv\": \"Y-koordinat\",\n              \"pl\": \"Współrzędna Y\",\n              \"ru\": \"Координата Y\",\n              \"ko\": \"Y 좌표\"\n            }\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer Stofzuiger\",\n              \"da\": \"Vælg støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccionar aspiradora\",\n              \"fr\": \"Choisir l'aspirateur\",\n              \"it\": \"Seleziona aspirapolvere\",\n              \"no\": \"Velg støvsuger\",\n              \"sv\": \"Välj dammsugare\",\n              \"pl\": \"Wybierz odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"진공 청소기 선택\"\n            },\n            \"filter\": \"driver_id=mi-robot|vacuum_mi_rockrobo_vacuum_advanced|vacuum_mi_rockrobo_vacuum_t6|vacuum_mi_roborock_vacuum_a08|vacuum_dreame_vacuum_p2029_p2041|vacuum_dreame_vacuum_mc1808|vacuum_viomi_vacuum_v7\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Set heatlevel\",\n          \"nl\": \"Stel hitte in\",\n          \"da\": \"Indstil varme niveau\",\n          \"de\": \"Heizstufe einstellen\",\n          \"es\": \"Establecer nivel de calor\",\n          \"fr\": \"Régler le niveau de chaleur\",\n          \"it\": \"Imposta livello di calore\",\n          \"no\": \"Sett varme nivå\",\n          \"sv\": \"Ställ in värmenivå\",\n          \"pl\": \"Ustaw poziom ciepła\",\n          \"ru\": \"Установить уровень нагрева\",\n          \"ko\": \"난방 수준 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set heatlevel to [[heatlevel]]\",\n          \"nl\": \"Stel hitte in op [[heatlevel]]\",\n          \"da\": \"Indstil varme niveau til [[heatlevel]]\",\n          \"de\": \"Heizstufe einstellen auf [[heatlevel]]\",\n          \"es\": \"Establecer nivel de calor en [[heatlevel]]\",\n          \"fr\": \"Régler le niveau de chaleur à [[heatlevel]]\",\n          \"it\": \"Imposta livello di calore a [[heatlevel]]\",\n          \"no\": \"Sett varme nivå til [[heatlevel]]\",\n          \"sv\": \"Ställ in värmenivå till [[heatlevel]]\",\n          \"pl\": \"Ustaw poziom ciepła na [[heatlevel]]\",\n          \"ru\": \"Установить уровень нагрева до [[heatlevel]]\",\n          \"ko\": \"[[heatlevel]]로 난방 수준 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"heatlevel\",\n            \"title\": {\n              \"en\": \"Heatlevel\",\n              \"nl\": \"Hitte\",\n              \"da\": \"Varme niveau\",\n              \"de\": \"Heizstufe\",\n              \"es\": \"Nivel de calor\",\n              \"fr\": \"Niveau de chaleur\",\n              \"it\": \"Livello di calore\",\n              \"no\": \"Varme nivå\",\n              \"sv\": \"Värmenivå\",\n              \"pl\": \"Poziom ciepła\",\n              \"ru\": \"Уровень нагрева\",\n              \"ko\": \"난방 수준\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"High\",\n                  \"nl\": \"Hoog\",\n                  \"da\": \"Høj\",\n                  \"de\": \"Hoch\",\n                  \"es\": \"Alto\",\n                  \"fr\": \"Élevé\",\n                  \"it\": \"Alto\",\n                  \"no\": \"Høy\",\n                  \"sv\": \"Hög\",\n                  \"pl\": \"Wysoki\",\n                  \"ru\": \"Высокий\",\n                  \"ko\": \"높음\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Low\",\n                  \"nl\": \"Laag\",\n                  \"da\": \"Lav\",\n                  \"de\": \"Niedrig\",\n                  \"es\": \"Bajo\",\n                  \"fr\": \"Faible\",\n                  \"it\": \"Basso\",\n                  \"no\": \"Lav\",\n                  \"sv\": \"Låg\",\n                  \"pl\": \"Niski\",\n                  \"ru\": \"Низкий\",\n                  \"ko\": \"낮음\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Heater\",\n              \"nl\": \"Selecteer Heater\",\n              \"da\": \"Vælg varmelegeme\",\n              \"de\": \"Heizung auswählen\",\n              \"es\": \"Seleccionar calentador\",\n              \"fr\": \"Sélectionner le chauffage\",\n              \"it\": \"Seleziona riscaldatore\",\n              \"no\": \"Velg varmeovn\",\n              \"sv\": \"Välj värmare\",\n              \"pl\": \"Wybierz grzejnik\",\n              \"ru\": \"Выберите обогреватель\",\n              \"ko\": \"히터 선택\"\n            },\n            \"filter\": \"driver_id=heater_zhimi_heater_miot&capabilities=heater_zhimi_heatlevel\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"heaterZhimiHeatlevel\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set oscillation\",\n          \"nl\": \"Stel oscillatie in\",\n          \"da\": \"Indstil oscillation\",\n          \"de\": \"Oszillation einstellen\",\n          \"es\": \"Configurar oscilación\",\n          \"fr\": \"Régler l'oscillation\",\n          \"it\": \"Imposta oscillazione\",\n          \"no\": \"Sett svingning\",\n          \"sv\": \"Ställ in oscillation\",\n          \"pl\": \"Ustaw oscylację\",\n          \"ru\": \"Установить колебание\",\n          \"ko\": \"진동 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set oscillation to [[oscillation]]\",\n          \"nl\": \"Stel oscillatie in op [[oscillation]]\",\n          \"da\": \"Indstil oscillation til [[oscillation]]\",\n          \"de\": \"Oszillation einstellen auf [[oscillation]]\",\n          \"es\": \"Configurar oscilación a [[oscillation]]\",\n          \"fr\": \"Régler l'oscillation sur [[oscillation]]\",\n          \"it\": \"Imposta oscillazione su [[oscillation]]\",\n          \"no\": \"Sett svingning til [[oscillation]]\",\n          \"sv\": \"Ställ in oscillation till [[oscillation]]\",\n          \"pl\": \"Ustaw oscylację na [[oscillation]]\",\n          \"ru\": \"Установить колебание на [[oscillation]]\",\n          \"ko\": \"[[oscillation]]으로 진동 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"oscillation\",\n            \"title\": {\n              \"en\": \"Oscillation\",\n              \"nl\": \"Oscillatie\",\n              \"da\": \"Oscillation\",\n              \"de\": \"Oszillation\",\n              \"es\": \"Oscilación\",\n              \"fr\": \"Oscillation\",\n              \"it\": \"Oscillazione\",\n              \"no\": \"Svingning\",\n              \"sv\": \"Oscillation\",\n              \"pl\": \"Oscylacja\",\n              \"ru\": \"Колебание\",\n              \"ko\": \"진동\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Off\",\n                  \"nl\": \"Uit\",\n                  \"da\": \"Fra\",\n                  \"de\": \"Aus\",\n                  \"es\": \"Apagar\",\n                  \"fr\": \"Éteindre\",\n                  \"it\": \"Spento\",\n                  \"no\": \"Av\",\n                  \"sv\": \"Av\",\n                  \"pl\": \"Wyłącz\",\n                  \"ru\": \"Выкл\",\n                  \"ko\": \"꺼짐\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"On\",\n                  \"nl\": \"Aan\",\n                  \"da\": \"Til\",\n                  \"de\": \"An\",\n                  \"es\": \"Encender\",\n                  \"fr\": \"Allumer\",\n                  \"it\": \"Acceso\",\n                  \"no\": \"På\",\n                  \"sv\": \"På\",\n                  \"pl\": \"Włącz\",\n                  \"ru\": \"Вкл\",\n                  \"ko\": \"켜짐\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Heater\",\n              \"nl\": \"Selecteer Heater\",\n              \"da\": \"Vælg varmer\",\n              \"de\": \"Heizung auswählen\",\n              \"es\": \"Seleccionar calentador\",\n              \"fr\": \"Sélectionner le chauffage\",\n              \"it\": \"Seleziona riscaldatore\",\n              \"no\": \"Velg varmeovn\",\n              \"sv\": \"Välj värmare\",\n              \"pl\": \"Wybierz grzejnik\",\n              \"ru\": \"Выберите обогреватель\",\n              \"ko\": \"히터 선택\"\n            },\n            \"filter\": \"driver_id=heater_zhimi_heater_miot&capabilities=heater_zhimi_oscillation\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"heaterZhimiOscillation\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set target temperature\",\n          \"nl\": \"Stel doel temperatuur in\",\n          \"da\": \"Indstil måletemperatur\",\n          \"de\": \"Zieltemperatur einstellen\",\n          \"es\": \"Establecer temperatura objetivo\",\n          \"fr\": \"Régler la température cible\",\n          \"it\": \"Imposta la temperatura target\",\n          \"no\": \"Sett måltemperatur\",\n          \"sv\": \"Ställ in måttemperaturen\",\n          \"pl\": \"Ustaw temperaturę docelową\",\n          \"ru\": \"Установить целевую температуру\",\n          \"ko\": \"목표 온도 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set target temperature to [[temperature]]\",\n          \"nl\": \"Stel doel temperatuur in op [[temperature]]\",\n          \"da\": \"Indstil måletemperatur til [[temperature]]\",\n          \"de\": \"Zieltemperatur auf [[temperature]] einstellen\",\n          \"es\": \"Establecer temperatura objetivo a [[temperature]]\",\n          \"fr\": \"Régler la température cible sur [[temperature]]\",\n          \"it\": \"Imposta la temperatura target a [[temperature]]\",\n          \"no\": \"Sett måltemperaturen til [[temperature]]\",\n          \"sv\": \"Ställ in måttemperaturen till [[temperature]]\",\n          \"pl\": \"Ustaw temperaturę docelową na [[temperature]]\",\n          \"ru\": \"Установить целевую температуру на [[temperature]]\",\n          \"ko\": \"[[temperature]]도로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"temperature\",\n            \"type\": \"number\",\n            \"title\": {\n              \"en\": \"Target Temperature\",\n              \"nl\": \"Doel temperatuur\",\n              \"da\": \"Måletemperatur\",\n              \"de\": \"Zieltemperatur\",\n              \"es\": \"Temperatura objetivo\",\n              \"fr\": \"Température cible\",\n              \"it\": \"Temperatura target\",\n              \"no\": \"Måltemperatur\",\n              \"sv\": \"Måttemperatur\",\n              \"pl\": \"Temperatura docelowa\",\n              \"ru\": \"Целевая температура\",\n              \"ko\": \"목표 온도\"\n            },\n            \"min\": 16,\n            \"max\": 30,\n            \"step\": 1\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Heater\",\n              \"nl\": \"Selecteer Heater\",\n              \"da\": \"Vælg varmeapparat\",\n              \"de\": \"Heizung auswählen\",\n              \"es\": \"Seleccionar calentador\",\n              \"fr\": \"Sélectionner le radiateur\",\n              \"it\": \"Seleziona riscaldatore\",\n              \"no\": \"Velg varmeovn\",\n              \"sv\": \"Välj värmare\",\n              \"pl\": \"Wybierz grzejnik\",\n              \"ru\": \"Выбрать обогреватель\",\n              \"ko\": \"히터 선택\"\n            },\n            \"filter\": \"driver_id=heater_zhimi_heater_miot&capabilities=heater_zhimi_heater_target_temperature\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"heaterZhimiTargetTemperature\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Sæt tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Configurar modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Angi modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus auf [[mode]] einstellen\",\n          \"es\": \"Configurar modo a [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Sett modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Constant Humidity\",\n                  \"nl\": \"Constante luchtvochtigheid\",\n                  \"da\": \"Konstant fugtighed\",\n                  \"de\": \"Konstante Luftfeuchtigkeit\",\n                  \"es\": \"Humedad constante\",\n                  \"fr\": \"Humidité constante\",\n                  \"it\": \"Umidità costante\",\n                  \"no\": \"Konstant fuktighet\",\n                  \"sv\": \"Konstant luftfuktighet\",\n                  \"pl\": \"Stała wilgotność\",\n                  \"ru\": \"Постоянная влажность\",\n                  \"ko\": \"일정 습도\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Strong\",\n                  \"nl\": \"Sterk\",\n                  \"da\": \"Stærk\",\n                  \"de\": \"Stark\",\n                  \"es\": \"Fuerte\",\n                  \"fr\": \"Fort\",\n                  \"it\": \"Intenso\",\n                  \"no\": \"Sterk\",\n                  \"sv\": \"Stark\",\n                  \"pl\": \"Silny\",\n                  \"ru\": \"Сильный\",\n                  \"ko\": \"강하게\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Sleep\",\n                  \"nl\": \"Slaapstand\",\n                  \"da\": \"Sovefunktion\",\n                  \"de\": \"Schlafmodus\",\n                  \"es\": \"Modo de dormir\",\n                  \"fr\": \"Sommeil\",\n                  \"it\": \"Modalità notte\",\n                  \"no\": \"Søvn\",\n                  \"sv\": \"Sovläge\",\n                  \"pl\": \"Tryb snu\",\n                  \"ru\": \"Спящий режим\",\n                  \"ko\": \"수면 모드\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"title\": {\n                  \"en\": \"Air-dry\",\n                  \"nl\": \"Air-dry\",\n                  \"da\": \"Lufttørre\",\n                  \"de\": \"Lufttrocknen\",\n                  \"es\": \"Secar al aire\",\n                  \"fr\": \"Sécher à l'air\",\n                  \"it\": \"Asciugare all'aria\",\n                  \"no\": \"Lufttørk\",\n                  \"sv\": \"Lufttorka\",\n                  \"pl\": \"Suszenie powietrzem\",\n                  \"ru\": \"Воздушная сушка\",\n                  \"ko\": \"에어 드라이\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"title\": {\n                  \"en\": \"Clean\",\n                  \"nl\": \"Schonen\",\n                  \"da\": \"Rengør\",\n                  \"de\": \"Reinigen\",\n                  \"es\": \"Limpiar\",\n                  \"fr\": \"Nettoyer\",\n                  \"it\": \"Pulire\",\n                  \"no\": \"Rengjør\",\n                  \"sv\": \"Rena\",\n                  \"pl\": \"Czyszczenie\",\n                  \"ru\": \"Чистка\",\n                  \"ko\": \"세척\"\n                }\n              },\n              {\n                \"id\": \"5\",\n                \"title\": {\n                  \"en\": \"Descale\",\n                  \"nl\": \"Descale\",\n                  \"da\": \"Afkalkning\",\n                  \"de\": \"Entkalken\",\n                  \"es\": \"Descalcificar\",\n                  \"fr\": \"Détartrer\",\n                  \"it\": \"Decalcificare\",\n                  \"no\": \"Avkalking\",\n                  \"sv\": \"Avkalka\",\n                  \"pl\": \"Odkamienianie\",\n                  \"ru\": \"Удаление накипи\",\n                  \"ko\": \"석회 제거\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Humidifier\",\n              \"nl\": \"Selecteer Mi Humidifier\",\n              \"da\": \"Vælg Mi Luftfugter\",\n              \"de\": \"Wählen Sie Mi Luftbefeuchter\",\n              \"es\": \"Selecciona Mi Humidificador\",\n              \"fr\": \"Sélectionnez Mi Humidificateur\",\n              \"it\": \"Seleziona Mi Umidificatore\",\n              \"no\": \"Velg Mi Luftfukter\",\n              \"sv\": \"Välj Mi Luftfuktare\",\n              \"pl\": \"Wybierz Mi Nawilżacz\",\n              \"ru\": \"Выбрать Mi Увлажнитель\",\n              \"ko\": \"Mi 가습기 선택\"\n            },\n            \"filter\": \"driver_id=humidifier_xiaomi_humidifier\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"humidifierXiaomiMode\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Indstil tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Establecer modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Angi modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus einstellen auf [[mode]]\",\n          \"es\": \"Establecer modo a [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Angi modus til [[mode]]\",\n          \"sv\": \"Ställ in läge på [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"idle\",\n                \"title\": {\n                  \"en\": \"Off\",\n                  \"nl\": \"Uit\",\n                  \"de\": \"Aus\",\n                  \"da\": \"Fra\",\n                  \"es\": \"Apagado\",\n                  \"fr\": \"Éteint\",\n                  \"it\": \"Spento\",\n                  \"no\": \"Av\",\n                  \"sv\": \"Av\",\n                  \"pl\": \"Wył.\",\n                  \"ru\": \"Выкл.\",\n                  \"ko\": \"끔\"\n                }\n              },\n              {\n                \"id\": \"silent\",\n                \"title\": {\n                  \"en\": \"Silent\",\n                  \"nl\": \"Stil\",\n                  \"de\": \"Leise\",\n                  \"da\": \"Stille\",\n                  \"es\": \"Silencioso\",\n                  \"fr\": \"Silencieux\",\n                  \"it\": \"Silenzioso\",\n                  \"no\": \"Stille\",\n                  \"sv\": \"Tyst\",\n                  \"pl\": \"Cichy\",\n                  \"ru\": \"Беззвучный\",\n                  \"ko\": \"무음\"\n                }\n              },\n              {\n                \"id\": \"medium\",\n                \"title\": {\n                  \"en\": \"Medium\",\n                  \"nl\": \"Middel\",\n                  \"de\": \"Mittel\",\n                  \"da\": \"Medium\",\n                  \"es\": \"Medio\",\n                  \"fr\": \"Moyen\",\n                  \"it\": \"Medio\",\n                  \"no\": \"Medium\",\n                  \"sv\": \"Medium\",\n                  \"pl\": \"Średni\",\n                  \"ru\": \"Средний\",\n                  \"ko\": \"중간\"\n                }\n              },\n              {\n                \"id\": \"high\",\n                \"title\": {\n                  \"en\": \"High\",\n                  \"nl\": \"Hoog\",\n                  \"de\": \"Hoch\",\n                  \"da\": \"Høj\",\n                  \"es\": \"Alto\",\n                  \"fr\": \"Haut\",\n                  \"it\": \"Alto\",\n                  \"no\": \"Høy\",\n                  \"sv\": \"Hög\",\n                  \"pl\": \"Wysoki\",\n                  \"ru\": \"Высокий\",\n                  \"ko\": \"높음\"\n                }\n              },\n              {\n                \"id\": \"auto\",\n                \"title\": {\n                  \"en\": \"Auto\",\n                  \"nl\": \"Auto\",\n                  \"de\": \"Auto\",\n                  \"da\": \"Auto\",\n                  \"es\": \"Auto\",\n                  \"fr\": \"Auto\",\n                  \"it\": \"Auto\",\n                  \"no\": \"Auto\",\n                  \"sv\": \"Auto\",\n                  \"pl\": \"Auto\",\n                  \"ru\": \"Авто\",\n                  \"ko\": \"자동\"\n                }\n              },\n              {\n                \"id\": \"strong\",\n                \"title\": {\n                  \"en\": \"Strong\",\n                  \"nl\": \"Sterk\",\n                  \"de\": \"Stark\",\n                  \"da\": \"Stærk\",\n                  \"es\": \"Fuerte\",\n                  \"fr\": \"Fort\",\n                  \"it\": \"Forte\",\n                  \"no\": \"Sterk\",\n                  \"sv\": \"Stark\",\n                  \"pl\": \"Silny\",\n                  \"ru\": \"Сильный\",\n                  \"ko\": \"강한\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Humidifier\",\n              \"nl\": \"Selecteer Mi Humidifier\",\n              \"da\": \"Vælg Mi Humidifier\",\n              \"de\": \"Wählen Sie Mi Luftbefeuchter aus\",\n              \"es\": \"Selecciona Mi Humidificador\",\n              \"fr\": \"Sélectionnez Mi Humidificateur\",\n              \"it\": \"Seleziona Mi Umidificatore\",\n              \"no\": \"Velg Mi Humidifier\",\n              \"sv\": \"Välj Mi Humidifier\",\n              \"pl\": \"Wybierz Mi Humidifier\",\n              \"ru\": \"Выберите Mi Humidifier\",\n              \"ko\": \"Mi Humidifier 선택\"\n            },\n            \"filter\": \"driver_id=humidifier_zhimi_humidifier\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"humidifierZhimiMode\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Sæt tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Establecer modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Sett modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus auf [[mode]] einstellen\",\n          \"es\": \"Establecer modo a [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Sett modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Auto\",\n                  \"nl\": \"Auto\",\n                  \"da\": \"Auto\",\n                  \"de\": \"Auto\",\n                  \"es\": \"Auto\",\n                  \"fr\": \"Auto\",\n                  \"it\": \"Auto\",\n                  \"no\": \"Auto\",\n                  \"sv\": \"Auto\",\n                  \"pl\": \"Auto\",\n                  \"ru\": \"Авто\",\n                  \"ko\": \"자동\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Level 1\",\n                  \"nl\": \"Level 1\",\n                  \"da\": \"Niveau 1\",\n                  \"de\": \"Stufe 1\",\n                  \"es\": \"Nivel 1\",\n                  \"fr\": \"Niveau 1\",\n                  \"it\": \"Livello 1\",\n                  \"no\": \"Nivå 1\",\n                  \"sv\": \"Nivå 1\",\n                  \"pl\": \"Poziom 1\",\n                  \"ru\": \"Уровень 1\",\n                  \"ko\": \"레벨 1\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Level 2\",\n                  \"nl\": \"Level 2\",\n                  \"da\": \"Niveau 2\",\n                  \"de\": \"Stufe 2\",\n                  \"es\": \"Nivel 2\",\n                  \"fr\": \"Niveau 2\",\n                  \"it\": \"Livello 2\",\n                  \"no\": \"Nivå 2\",\n                  \"sv\": \"Nivå 2\",\n                  \"pl\": \"Poziom 2\",\n                  \"ru\": \"Уровень 2\",\n                  \"ko\": \"레벨 2\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"title\": {\n                  \"en\": \"Level 3\",\n                  \"nl\": \"Level 3\",\n                  \"da\": \"Niveau 3\",\n                  \"de\": \"Stufe 3\",\n                  \"es\": \"Nivel 3\",\n                  \"fr\": \"Niveau 3\",\n                  \"it\": \"Livello 3\",\n                  \"no\": \"Nivå 3\",\n                  \"sv\": \"Nivå 3\",\n                  \"pl\": \"Poziom 3\",\n                  \"ru\": \"Уровень 3\",\n                  \"ko\": \"레벨 3\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Humidifier\",\n              \"nl\": \"Selecteer Mi Humidifier\",\n              \"da\": \"Vælg Mi Luftfugter\",\n              \"de\": \"Wählen Sie Mi Luftbefeuchter\",\n              \"es\": \"Seleccionar Mi Humidificador\",\n              \"fr\": \"Sélectionnez Humidificateur Mi\",\n              \"it\": \"Seleziona Mi Umidificatore\",\n              \"no\": \"Velg Mi Luftfukter\",\n              \"sv\": \"Välj Mi Luftfuktare\",\n              \"pl\": \"Wybierz Mi Nawilżacz\",\n              \"ru\": \"Выберите Mi Увлажнитель\",\n              \"ko\": \"Mi 가습기 선택\"\n            },\n            \"filter\": \"driver_id=humidifier_zhimi_humidifier_miot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"humidifierZhimiModeMIoT\"\n      },\n      {\n        \"id\": \"changeSpeed\",\n        \"title\": {\n          \"en\": \"Set Speed\",\n          \"nl\": \"Stel snelheid in\",\n          \"da\": \"Indstil hastighed\",\n          \"de\": \"Geschwindigkeit einstellen\",\n          \"es\": \"Ajustar velocidad\",\n          \"fr\": \"Régler la vitesse\",\n          \"it\": \"Imposta velocità\",\n          \"no\": \"Sett hastighet\",\n          \"sv\": \"Ställ in hastighet\",\n          \"pl\": \"Ustaw prędkość\",\n          \"ru\": \"Установить скорость\",\n          \"ko\": \"속도 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set speed to [[speed]]\",\n          \"nl\": \"Stel snelheid in op [[speed]]\",\n          \"da\": \"Indstil hastighed til [[speed]]\",\n          \"de\": \"Geschwindigkeit auf [[speed]] einstellen\",\n          \"es\": \"Ajustar velocidad a [[speed]]\",\n          \"fr\": \"Régler la vitesse à [[speed]]\",\n          \"it\": \"Imposta velocità a [[speed]]\",\n          \"no\": \"Sett hastighet til [[speed]]\",\n          \"sv\": \"Ställ in hastighet till [[speed]]\",\n          \"pl\": \"Ustaw prędkość na [[speed]]\",\n          \"ru\": \"Установить скорость на [[speed]]\",\n          \"ko\": \"[[speed]]으로 속도 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"speed\",\n            \"title\": {\n              \"en\": \"Speed\",\n              \"nl\": \"Snelheid\",\n              \"da\": \"Hastighed\",\n              \"de\": \"Geschwindigkeit\",\n              \"es\": \"Velocidad\",\n              \"fr\": \"Vitesse\",\n              \"it\": \"Velocità\",\n              \"no\": \"Hastighet\",\n              \"sv\": \"Hastighet\",\n              \"pl\": \"Prędkość\",\n              \"ru\": \"Скорость\",\n              \"ko\": \"속도\"\n            },\n            \"type\": \"range\",\n            \"min\": 0,\n            \"max\": 100,\n            \"step\": 1,\n            \"label\": \"%\",\n            \"labelDecimals\": 0\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=zhimi-fan|dmaker-fan\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"LED display brightness\",\n          \"nl\": \"LED display helderheid\",\n          \"da\": \"LED skærm lysstyrke\",\n          \"de\": \"LED-Display-Helligkeit\",\n          \"es\": \"Brillo de la pantalla LED\",\n          \"fr\": \"Luminosité de l'affichage LED\",\n          \"it\": \"Luminosità del display LED\",\n          \"no\": \"LED-skjermens lysstyrke\",\n          \"sv\": \"LED-skärmens ljusstyrka\",\n          \"pl\": \"Jasność wyświetlacza LED\",\n          \"ru\": \"Яркость светодиодного дисплея\",\n          \"ko\": \"LED 디스플레이 밝기\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set LED display brightness to [[brightness]]\",\n          \"nl\": \"Stel LED display helderheid in op [[brightness]]\",\n          \"da\": \"Indstil LED skærm lysstyrke til [[brightness]]\",\n          \"de\": \"LED-Display-Helligkeit auf [[brightness]] einstellen\",\n          \"es\": \"Establecer el brillo de la pantalla LED a [[brightness]]\",\n          \"fr\": \"Régler la luminosité de l'affichage LED sur [[brightness]]\",\n          \"it\": \"Imposta la luminosità del display LED a [[brightness]]\",\n          \"no\": \"Sett LED-skjermens lysstyrke til [[brightness]]\",\n          \"sv\": \"Ställ in LED-skärmens ljusstyrka till [[brightness]]\",\n          \"pl\": \"Ustaw jasność wyświetlacza LED na [[brightness]]\",\n          \"ru\": \"Установить яркость светодиодного дисплея на [[brightness]]\",\n          \"ko\": \"LED 디스플레이 밝기를 [[brightness]]로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"brightness\",\n            \"title\": {\n              \"en\": \"Brightness\",\n              \"nl\": \"Helderheid\",\n              \"da\": \"Lysstyrke\",\n              \"de\": \"Helligkeit\",\n              \"es\": \"Brillo\",\n              \"fr\": \"Luminosité\",\n              \"it\": \"Luminosità\",\n              \"no\": \"Lysstyrke\",\n              \"sv\": \"Ljusstyrka\",\n              \"pl\": \"Jasność\",\n              \"ru\": \"Яркость\",\n              \"ko\": \"밝기\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Bright\",\n                  \"nl\": \"Helder\",\n                  \"da\": \"Lys\",\n                  \"de\": \"Hell\",\n                  \"es\": \"Brillante\",\n                  \"fr\": \"Éclatant\",\n                  \"it\": \"Luminoso\",\n                  \"no\": \"Lyst\",\n                  \"sv\": \"Ljus\",\n                  \"pl\": \"Jasny\",\n                  \"ru\": \"Яркий\",\n                  \"ko\": \"밝게\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Dim\",\n                  \"nl\": \"Gedimd\",\n                  \"da\": \"Dæmpet\",\n                  \"de\": \"Gedimmt\",\n                  \"es\": \"Atenuado\",\n                  \"fr\": \"Tamiser\",\n                  \"it\": \"Fioco\",\n                  \"no\": \"Dempet\",\n                  \"sv\": \"Dämpad\",\n                  \"pl\": \"Ściemnić\",\n                  \"ru\": \"Тусклый\",\n                  \"ko\": \"어둡게\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"Off\",\n                  \"nl\": \"Uit\",\n                  \"da\": \"Slukket\",\n                  \"de\": \"Aus\",\n                  \"es\": \"Apagado\",\n                  \"fr\": \"Éteindre\",\n                  \"it\": \"Spento\",\n                  \"no\": \"Av\",\n                  \"sv\": \"Av\",\n                  \"pl\": \"Wyłączony\",\n                  \"ru\": \"Выкл\",\n                  \"ko\": \"끄기\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer Apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=mi-airpurifier|humidifier_zhimi_humidifier|zhimi-fan\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"ledAirpurifierHumidifier\"\n      },\n      {\n        \"id\": \"leftSwitchOff\",\n        \"title\": {\n          \"en\": \"Turn Left Switch Off\",\n          \"nl\": \"Schakel linkerschakelaar uit\",\n          \"da\": \"Sluk venstre kontakt\",\n          \"de\": \"Schalten Sie den linken Schalter aus\",\n          \"es\": \"Apaga el interruptor izquierdo\",\n          \"fr\": \"Éteindre l'interrupteur de gauche\",\n          \"it\": \"Spegni l'interruttore sinistro\",\n          \"no\": \"Slå av venstre bryter\",\n          \"sv\": \"Stäng av vänstra brytaren\",\n          \"pl\": \"Wyłącz lewy przełącznik\",\n          \"ru\": \"Выключить левый переключатель\",\n          \"ko\": \"왼쪽 스위치 끄기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"leftSwitchOn\",\n        \"title\": {\n          \"en\": \"Turn Left Switch On\",\n          \"nl\": \"Schakel linkerschakelaar aan\",\n          \"da\": \"Tænd Venstre Afbryder\",\n          \"de\": \"Schalten Sie den linken Schalter ein\",\n          \"es\": \"Enciende el interruptor izquierdo\",\n          \"fr\": \"Allumer l'interrupteur de gauche\",\n          \"it\": \"Accendi l'interruttore sinistro\",\n          \"no\": \"Slå på venstre bryter\",\n          \"sv\": \"Slå på vänster brytare\",\n          \"pl\": \"Włącz lewy przełącznik\",\n          \"ru\": \"Включите левый выключатель\",\n          \"ko\": \"왼쪽 스위치 켜기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionnez l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"leftSwitchToggle\",\n        \"title\": {\n          \"en\": \"Toggle Left Switch\",\n          \"nl\": \"Schakel linkerschakelaar\",\n          \"da\": \"Skift venstre kontakt\",\n          \"de\": \"Linken Schalter umlegen\",\n          \"es\": \"Alternar interruptor izquierdo\",\n          \"fr\": \"Basculer l'interrupteur gauche\",\n          \"it\": \"Attiva/disattiva l'interruttore sinistro\",\n          \"no\": \"Veksle venstre bryter\",\n          \"sv\": \"Växla vänster brytare\",\n          \"pl\": \"Przełącz lewy włącznik\",\n          \"ru\": \"Переключить левый выключатель\",\n          \"ko\": \"왼쪽 스위치 전환\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"기기 선택\"\n            },\n            \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Set mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Indstil tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Configurar modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Sett modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus einstellen auf [[mode]]\",\n          \"es\": \"Configurar modo a [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Sett modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"auto\",\n                \"title\": {\n                  \"en\": \"Auto\",\n                  \"nl\": \"Auto\",\n                  \"da\": \"Auto\",\n                  \"de\": \"Auto\",\n                  \"es\": \"Auto\",\n                  \"fr\": \"Auto\",\n                  \"it\": \"Auto\",\n                  \"no\": \"Auto\",\n                  \"sv\": \"Auto\",\n                  \"pl\": \"Auto\",\n                  \"ru\": \"Авто\",\n                  \"ko\": \"자동\"\n                }\n              },\n              {\n                \"id\": \"silent\",\n                \"title\": {\n                  \"en\": \"Silent\",\n                  \"nl\": \"Stil\",\n                  \"da\": \"Stille\",\n                  \"de\": \"Leise\",\n                  \"es\": \"Silencioso\",\n                  \"fr\": \"Silencieux\",\n                  \"it\": \"Silenzioso\",\n                  \"no\": \"Stille\",\n                  \"sv\": \"Tyst\",\n                  \"pl\": \"Cichy\",\n                  \"ru\": \"Тихий\",\n                  \"ko\": \"조용한\"\n                }\n              },\n              {\n                \"id\": \"favorite\",\n                \"title\": {\n                  \"en\": \"Favorite\",\n                  \"nl\": \"Favoriet\",\n                  \"da\": \"Favorit\",\n                  \"de\": \"Favorit\",\n                  \"es\": \"Favorito\",\n                  \"fr\": \"Favori\",\n                  \"it\": \"Preferito\",\n                  \"no\": \"Favoritt\",\n                  \"sv\": \"Favorit\",\n                  \"pl\": \"Ulubiony\",\n                  \"ru\": \"Любимый\",\n                  \"ko\": \"즐겨 찾기\"\n                }\n              },\n              {\n                \"id\": \"idle\",\n                \"title\": {\n                  \"en\": \"Idle\",\n                  \"nl\": \"Standby\",\n                  \"da\": \"I dvale\",\n                  \"de\": \"Leerlauf\",\n                  \"es\": \"Inactivo\",\n                  \"fr\": \"Inactif\",\n                  \"it\": \"Inattivo\",\n                  \"no\": \"Inaktiv\",\n                  \"sv\": \"Inaktiv\",\n                  \"pl\": \"Bezczynny\",\n                  \"ru\": \"Ожидание\",\n                  \"ko\": \"대기모드\"\n                }\n              },\n              {\n                \"id\": \"low\",\n                \"title\": {\n                  \"en\": \"Low\",\n                  \"nl\": \"Laag\",\n                  \"da\": \"Lav\",\n                  \"de\": \"Niedrig\",\n                  \"es\": \"Bajo\",\n                  \"fr\": \"Bas\",\n                  \"it\": \"Basso\",\n                  \"no\": \"Lav\",\n                  \"sv\": \"Låg\",\n                  \"pl\": \"Niski\",\n                  \"ru\": \"Низкий\",\n                  \"ko\": \"낮음\"\n                }\n              },\n              {\n                \"id\": \"medium\",\n                \"title\": {\n                  \"en\": \"Medium\",\n                  \"nl\": \"Medium\",\n                  \"da\": \"Mellem\",\n                  \"de\": \"Mittel\",\n                  \"es\": \"Medio\",\n                  \"fr\": \"Moyen\",\n                  \"it\": \"Medio\",\n                  \"no\": \"Middels\",\n                  \"sv\": \"Mellan\",\n                  \"pl\": \"Średni\",\n                  \"ru\": \"Средний\",\n                  \"ko\": \"중간\"\n                }\n              },\n              {\n                \"id\": \"high\",\n                \"title\": {\n                  \"en\": \"High\",\n                  \"nl\": \"Hoog\",\n                  \"da\": \"Høj\",\n                  \"de\": \"Hoch\",\n                  \"es\": \"Alto\",\n                  \"fr\": \"Élevé\",\n                  \"it\": \"Alto\",\n                  \"no\": \"Høy\",\n                  \"sv\": \"Hög\",\n                  \"pl\": \"Wysoki\",\n                  \"ru\": \"Высокий\",\n                  \"ko\": \"높음\"\n                }\n              },\n              {\n                \"id\": \"strong\",\n                \"title\": {\n                  \"en\": \"Strong\",\n                  \"nl\": \"Sterk\",\n                  \"da\": \"Stærk\",\n                  \"de\": \"Stark\",\n                  \"es\": \"Fuerte\",\n                  \"fr\": \"Fort\",\n                  \"it\": \"Forte\",\n                  \"no\": \"Sterk\",\n                  \"sv\": \"Stark\",\n                  \"pl\": \"Silny\",\n                  \"ru\": \"Сильный\",\n                  \"ko\": \"강한\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Air Purifier\",\n              \"nl\": \"Selecteer Mi Luchtreiniger\",\n              \"da\": \"Vælg Mi Luftrenser\",\n              \"de\": \"Wählen Sie Mi Luftreiniger\",\n              \"es\": \"Seleccionar Mi Purificador de Aire\",\n              \"fr\": \"Sélectionner Mi Purificateur d'air\",\n              \"it\": \"Seleziona Mi Purificatore d'aria\",\n              \"no\": \"Velg Mi Luftrenser\",\n              \"sv\": \"Välj Mi Luftrenare\",\n              \"pl\": \"Wybierz Mi Oczyszczacz Powietrza\",\n              \"ru\": \"Выбрать Mi Очиститель Воздуха\",\n              \"ko\": \"Mi 공기청정기 선택\"\n            },\n            \"filter\": \"driver_id=mi-airpurifier|airpurifier_zhimi_advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"modeAirpurifier\"\n      },\n      {\n        \"id\": \"modeAirpurifierV7\",\n        \"title\": {\n          \"en\": \"Set mode (v7)\",\n          \"nl\": \"Stel modus in (v7)\",\n          \"da\": \"Indstil tilstand (v7)\",\n          \"de\": \"Modus einstellen (v7)\",\n          \"es\": \"Configurar modo (v7)\",\n          \"fr\": \"Définir le mode (v7)\",\n          \"it\": \"Imposta modalità (v7)\",\n          \"no\": \"Sett modus (v7)\",\n          \"sv\": \"Ställ in läge (v7)\",\n          \"pl\": \"Ustaw tryb (v7)\",\n          \"ru\": \"Установить режим (v7)\",\n          \"ko\": \"모드 설정 (v7)\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set v7 mode to [[mode]]\",\n          \"nl\": \"Stel v7-modus in op [[mode]]\",\n          \"da\": \"Indstil v7-tilstand til [[mode]]\",\n          \"de\": \"V7-Modus einstellen auf [[mode]]\",\n          \"es\": \"Configurar modo v7 a [[mode]]\",\n          \"fr\": \"Définir le mode v7 sur [[mode]]\",\n          \"it\": \"Imposta modalità v7 su [[mode]]\",\n          \"no\": \"Sett v7-modus til [[mode]]\",\n          \"sv\": \"Ställ in v7-läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb v7 na [[mode]]\",\n          \"ru\": \"Установить режим v7 на [[mode]]\",\n          \"ko\": \"v7 모드를 [[mode]](으)로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"auto\",\n                \"title\": {\n                  \"en\": \"Auto\",\n                  \"nl\": \"Auto\",\n                  \"da\": \"Auto\",\n                  \"de\": \"Auto\",\n                  \"es\": \"Auto\",\n                  \"fr\": \"Auto\",\n                  \"it\": \"Auto\",\n                  \"no\": \"Auto\",\n                  \"sv\": \"Auto\",\n                  \"pl\": \"Auto\",\n                  \"ru\": \"Авто\",\n                  \"ko\": \"자동\"\n                }\n              },\n              {\n                \"id\": \"silent\",\n                \"title\": {\n                  \"en\": \"Night\",\n                  \"nl\": \"Nacht\",\n                  \"da\": \"Nat\",\n                  \"de\": \"Nacht\",\n                  \"es\": \"Noche\",\n                  \"fr\": \"Nuit\",\n                  \"it\": \"Notte\",\n                  \"no\": \"Natt\",\n                  \"sv\": \"Natt\",\n                  \"pl\": \"Noc\",\n                  \"ru\": \"Ночь\",\n                  \"ko\": \"야간\"\n                }\n              },\n              {\n                \"id\": \"favorite\",\n                \"title\": {\n                  \"en\": \"Favorite\",\n                  \"nl\": \"Favoriet\",\n                  \"da\": \"Favorit\",\n                  \"de\": \"Favorit\",\n                  \"es\": \"Favorito\",\n                  \"fr\": \"Favori\",\n                  \"it\": \"Preferito\",\n                  \"no\": \"Favoritt\",\n                  \"sv\": \"Favorit\",\n                  \"pl\": \"Ulubiony\",\n                  \"ru\": \"Любимый\",\n                  \"ko\": \"즐겨찾기\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Air Purifier v7\",\n              \"nl\": \"Selecteer Mi Luchtreiniger v7\",\n              \"da\": \"Vælg Mi Luftrenser v7\",\n              \"de\": \"Wählen Sie Mi Luftreiniger v7\",\n              \"es\": \"Seleccionar Mi Purificador de Aire v7\",\n              \"fr\": \"Sélectionner Mi Purificateur d'air v7\",\n              \"it\": \"Seleziona Mi Purificatore d'aria v7\",\n              \"no\": \"Velg Mi Luftrenser v7\",\n              \"sv\": \"Välj Mi Luftrenare v7\",\n              \"pl\": \"Wybierz Mi Oczyszczacz Powietrza v7\",\n              \"ru\": \"Выбрать Mi Очиститель Воздуха v7\",\n              \"ko\": \"Mi 공기청정기 v7 선택\"\n            },\n            \"filter\": \"driver_id=airpurifier_zhimi_advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Sæt tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Establecer modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Sett modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus auf [[mode]] einstellen\",\n          \"es\": \"Establecer modo en [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Sett modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Smart\",\n                  \"nl\": \"Slim\",\n                  \"da\": \"Smart\",\n                  \"de\": \"Intelligent\",\n                  \"es\": \"Inteligente\",\n                  \"fr\": \"Intelligent\",\n                  \"it\": \"Intelligente\",\n                  \"no\": \"Smart\",\n                  \"sv\": \"Smart\",\n                  \"pl\": \"Inteligentny\",\n                  \"ru\": \"Умный\",\n                  \"ko\": \"스마트\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Sleep\",\n                  \"nl\": \"Slaap\",\n                  \"da\": \"Søvn\",\n                  \"de\": \"Schlaf\",\n                  \"es\": \"Dormir\",\n                  \"fr\": \"Sommeil\",\n                  \"it\": \"Sonno\",\n                  \"no\": \"Søvn\",\n                  \"sv\": \"Sömn\",\n                  \"pl\": \"Sen\",\n                  \"ru\": \"Сон\",\n                  \"ko\": \"수면\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Clothes Drying\",\n                  \"nl\": \"Kleding drogen\",\n                  \"da\": \"Tørring af tøj\",\n                  \"de\": \"Kleidung trocknen\",\n                  \"es\": \"Secado de ropa\",\n                  \"fr\": \"Séchage des vêtements\",\n                  \"it\": \"Asciugatura dei vestiti\",\n                  \"no\": \"Klær tørking\",\n                  \"sv\": \"Klädtorkning\",\n                  \"pl\": \"Suszenie ubrań\",\n                  \"ru\": \"Сушка одежды\",\n                  \"ko\": \"의류 건조\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Humidifier\",\n              \"nl\": \"Selecteer Mi Luchtbevochtiger\",\n              \"da\": \"Vælg Mi Luftfugter\",\n              \"de\": \"Wählen Sie Mi Luftbefeuchter\",\n              \"es\": \"Seleccione Mi Humidificador\",\n              \"fr\": \"Sélectionnez Mi Humidificateur\",\n              \"it\": \"Seleziona Mi Umidificatore\",\n              \"no\": \"Velg Mi Luftfukter\",\n              \"sv\": \"Välj Mi Luftfuktare\",\n              \"pl\": \"Wybierz Mi Nawilżacz\",\n              \"ru\": \"Выберите Mi Увлажнитель\",\n              \"ko\": \"Mi 가습기 선택\"\n            },\n            \"filter\": \"driver_id=dehumidifier_dmaker_derh_miot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"modeDehumidifierDmaker\"\n      },\n      {\n        \"id\": \"modeDiffuserXwhzp\",\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Saet tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Establecer modo\",\n          \"fr\": \"Definir le mode\",\n          \"it\": \"Imposta modalita\",\n          \"no\": \"Sett modus\",\n          \"sv\": \"Stall in lage\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Ustanovit rezhim\",\n          \"ko\": \"mode set\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Sleep\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Reading\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Exercise\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"title\": {\n                  \"en\": \"Wakeup\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"title\": {\n                  \"en\": \"Custom Mode 1\"\n                }\n              },\n              {\n                \"id\": \"5\",\n                \"title\": {\n                  \"en\": \"Custom Mode 2\"\n                }\n              },\n              {\n                \"id\": \"6\",\n                \"title\": {\n                  \"en\": \"Custom Mode 3\"\n                }\n              },\n              {\n                \"id\": \"7\",\n                \"title\": {\n                  \"en\": \"Custom Mode 4\"\n                }\n              },\n              {\n                \"id\": \"8\",\n                \"title\": {\n                  \"en\": \"Try It\"\n                }\n              },\n              {\n                \"id\": \"9\",\n                \"title\": {\n                  \"en\": \"Idle Mode\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mijia Smart Scent Diffuser\"\n            },\n            \"filter\": \"driver_id=diffuser_xwhzp_diffuser_xwxfj\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"modeDmakerFan\",\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Indstil tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Establecer modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Sett modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus einstellen auf [[mode]]\",\n          \"es\": \"Establecer modo a [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Sett modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"normal\",\n                \"label\": {\n                  \"en\": \"Normal\",\n                  \"nl\": \"Normaal\",\n                  \"da\": \"Normal\",\n                  \"de\": \"Normal\",\n                  \"es\": \"Normal\",\n                  \"fr\": \"Normal\",\n                  \"it\": \"Normale\",\n                  \"no\": \"Normal\",\n                  \"sv\": \"Normal\",\n                  \"pl\": \"Normalny\",\n                  \"ru\": \"Нормальный\",\n                  \"ko\": \"일반\"\n                }\n              },\n              {\n                \"id\": \"nature\",\n                \"label\": {\n                  \"en\": \"Nature\",\n                  \"nl\": \"Natuur\",\n                  \"da\": \"Natur\",\n                  \"de\": \"Natur\",\n                  \"es\": \"Naturaleza\",\n                  \"fr\": \"Nature\",\n                  \"it\": \"Natura\",\n                  \"no\": \"Natur\",\n                  \"sv\": \"Natur\",\n                  \"pl\": \"Natura\",\n                  \"ru\": \"Природный\",\n                  \"ko\": \"자연\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Dmaker Fan\",\n              \"nl\": \"Selecteer Dmaker Ventilator\",\n              \"da\": \"Vælg Dmaker Fan\",\n              \"de\": \"Wählen Sie Dmaker Fan\",\n              \"es\": \"Seleccione Dmaker Fan\",\n              \"fr\": \"Sélectionnez Dmaker Fan\",\n              \"it\": \"Seleziona Dmaker Fan\",\n              \"no\": \"Velg Dmaker-vifte\",\n              \"sv\": \"Välj Dmaker-fläkt\",\n              \"pl\": \"Wybierz wentylator Dmaker\",\n              \"ru\": \"Выбрать вентилятор Dmaker\",\n              \"ko\": \"Dmaker 선풍기 선택\"\n            },\n            \"filter\": \"driver_id=dmaker-fan\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"modeEyecare\",\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Indstil tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Establecer modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Sett modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus einstellen auf [[mode]]\",\n          \"es\": \"Establecer modo a [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Sett modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"study\",\n                \"label\": {\n                  \"en\": \"Study\",\n                  \"nl\": \"Studeer\",\n                  \"da\": \"Studie\",\n                  \"de\": \"Studium\",\n                  \"es\": \"Estudio\",\n                  \"fr\": \"Étude\",\n                  \"it\": \"Studio\",\n                  \"no\": \"Studier\",\n                  \"sv\": \"Studera\",\n                  \"pl\": \"Studia\",\n                  \"ru\": \"Учеба\",\n                  \"ko\": \"공부\"\n                }\n              },\n              {\n                \"id\": \"reading\",\n                \"label\": {\n                  \"en\": \"Reading\",\n                  \"nl\": \"Lezen\",\n                  \"da\": \"Læsning\",\n                  \"de\": \"Lesen\",\n                  \"es\": \"Lectura\",\n                  \"fr\": \"Lecture\",\n                  \"it\": \"Lettura\",\n                  \"no\": \"Lesing\",\n                  \"sv\": \"Läsa\",\n                  \"pl\": \"Czytanie\",\n                  \"ru\": \"Чтение\",\n                  \"ko\": \"독서\"\n                }\n              },\n              {\n                \"id\": \"phone\",\n                \"label\": {\n                  \"en\": \"Phone\",\n                  \"nl\": \"Telefoon\",\n                  \"da\": \"Telefon\",\n                  \"de\": \"Telefon\",\n                  \"es\": \"Teléfono\",\n                  \"fr\": \"Téléphone\",\n                  \"it\": \"Telefono\",\n                  \"no\": \"Telefon\",\n                  \"sv\": \"Telefon\",\n                  \"pl\": \"Telefon\",\n                  \"ru\": \"Телефон\",\n                  \"ko\": \"전화\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Philips Eyecare Lamp\",\n              \"nl\": \"Selecteer Philips Eyecare Lamp\",\n              \"da\": \"Vælg Philips Eyecare Lamp\",\n              \"de\": \"Wählen Sie Philips Eyecare Lampe\",\n              \"es\": \"Seleccionar lámpara Philips Eyecare\",\n              \"fr\": \"Sélectionnez la lampe Philips Eyecare\",\n              \"it\": \"Seleziona lampada Philips Eyecare\",\n              \"no\": \"Velg Philips Eyecare Lampe\",\n              \"sv\": \"Välj Philips Eyecare Lampa\",\n              \"pl\": \"Wybierz lampę Philips Eyecare\",\n              \"ru\": \"Выберите лампу Philips Eyecare\",\n              \"ko\": \"필립스 아이케어 램프 선택\"\n            },\n            \"filter\": \"driver_id=philips-eyecare\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Indstil tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Ajustar modo\",\n          \"fr\": \"Régler le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Angi modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus auf [[mode]] einstellen\",\n          \"es\": \"Ajustar modo a [[mode]]\",\n          \"fr\": \"Régler le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Angi modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Low\",\n                  \"nl\": \"Laag\",\n                  \"da\": \"Lav\",\n                  \"de\": \"Niedrig\",\n                  \"es\": \"Bajo\",\n                  \"fr\": \"Faible\",\n                  \"it\": \"Basso\",\n                  \"no\": \"Lav\",\n                  \"sv\": \"Låg\",\n                  \"pl\": \"Niski\",\n                  \"ru\": \"Низкий\",\n                  \"ko\": \"낮음\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Medium\",\n                  \"nl\": \"Medium\",\n                  \"da\": \"Mellem\",\n                  \"de\": \"Mittel\",\n                  \"es\": \"Medio\",\n                  \"fr\": \"Moyen\",\n                  \"it\": \"Medio\",\n                  \"no\": \"Middels\",\n                  \"sv\": \"Medium\",\n                  \"pl\": \"Średni\",\n                  \"ru\": \"Средний\",\n                  \"ko\": \"중간\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"High\",\n                  \"nl\": \"Hoog\",\n                  \"da\": \"Høj\",\n                  \"de\": \"Hoch\",\n                  \"es\": \"Alto\",\n                  \"fr\": \"Élevé\",\n                  \"it\": \"Alto\",\n                  \"no\": \"Høy\",\n                  \"sv\": \"Hög\",\n                  \"pl\": \"Wysoki\",\n                  \"ru\": \"Высокий\",\n                  \"ko\": \"높음\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"label\": {\n                  \"en\": \"Humidity\",\n                  \"nl\": \"Luchtvochtigheid\",\n                  \"da\": \"Fugtighed\",\n                  \"de\": \"Feuchtigkeit\",\n                  \"es\": \"Humedad\",\n                  \"fr\": \"Humidité\",\n                  \"it\": \"Umidità\",\n                  \"no\": \"Fuktighet\",\n                  \"sv\": \"Luftfuktighet\",\n                  \"pl\": \"Wilgotność\",\n                  \"ru\": \"Влажность\",\n                  \"ko\": \"습도\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Humidifier\",\n              \"nl\": \"Selecteer Mi Luchtbevochtiger\",\n              \"da\": \"Vælg Mi Luftfugter\",\n              \"de\": \"Wählen Sie Mi Luftbefeuchter\",\n              \"es\": \"Selecciona Mi Humidificador\",\n              \"fr\": \"Sélectionnez Mi Humidificateur\",\n              \"it\": \"Seleziona Mi Umidificatore\",\n              \"no\": \"Velg Mi Luftfukter\",\n              \"sv\": \"Välj Mi Luftfuktare\",\n              \"pl\": \"Wybierz Mi Nawilżacz\",\n              \"ru\": \"Выберите Mi Увлажнитель\",\n              \"ko\": \"Mi 가습기 선택\"\n            },\n            \"filter\": \"driver_id=humidifier_deerma_humidifier_jsq||humidifier_deerma_humidifier_miot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"modeHumidifierDeerma\"\n      },\n      {\n        \"id\": \"modeHumidifierLeshowJSQ1\",\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Sæt tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Establecer modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Sett modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus auf [[mode]] einstellen\",\n          \"es\": \"Establecer modo en [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Sett modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Constant Humidity\",\n                  \"nl\": \"Constante luchtvochtigheid\",\n                  \"da\": \"Konstant fugtighed\",\n                  \"de\": \"Konstante Luftfeuchtigkeit\",\n                  \"es\": \"Humedad constante\",\n                  \"fr\": \"Humidité constante\",\n                  \"it\": \"Umidità costante\",\n                  \"no\": \"Konstant fuktighet\",\n                  \"sv\": \"Konstant fuktighet\",\n                  \"pl\": \"Stała wilgotność\",\n                  \"ru\": \"Постоянная влажность\",\n                  \"ko\": \"일정한 습도\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"High\",\n                  \"nl\": \"Hoog\",\n                  \"da\": \"Høj\",\n                  \"de\": \"Hoch\",\n                  \"es\": \"Alto\",\n                  \"fr\": \"Élevé\",\n                  \"it\": \"Alto\",\n                  \"no\": \"Høy\",\n                  \"sv\": \"Hög\",\n                  \"pl\": \"Wysoki\",\n                  \"ru\": \"Высокий\",\n                  \"ko\": \"높음\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Sleep\",\n                  \"nl\": \"Slaapstand\",\n                  \"da\": \"Søvn\",\n                  \"de\": \"Schlafmodus\",\n                  \"es\": \"Dormir\",\n                  \"fr\": \"Sommeil\",\n                  \"it\": \"Sonno\",\n                  \"no\": \"Søvn\",\n                  \"sv\": \"Sömn\",\n                  \"pl\": \"Sen\",\n                  \"ru\": \"Сон\",\n                  \"ko\": \"수면\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Mi Humidifier\",\n              \"nl\": \"Selecteer Mi Luchtbevochtiger\",\n              \"da\": \"Vælg Mi Luftfugter\",\n              \"de\": \"Wählen Sie Mi Luftbefeuchter\",\n              \"es\": \"Seleccione Mi Humidificador\",\n              \"fr\": \"Sélectionnez Mi Humidificateur\",\n              \"it\": \"Seleziona Mi Umidificatore\",\n              \"no\": \"Velg Mi Luftfukter\",\n              \"sv\": \"Välj Mi Luftfuktare\",\n              \"pl\": \"Wybierz Mi Nawilżacz\",\n              \"ru\": \"Выберите Mi Увлажнитель\",\n              \"ko\": \"Mi 가습기 선택\"\n            },\n            \"filter\": \"driver_id=humidifier_leshow_humidifier_jsq1\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"modeVacuumMop\",\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Indstil tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Establecer modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Sett modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus einstellen auf [[mode]]\",\n          \"es\": \"Establecer modo en [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Sett modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Vacuum\",\n                  \"nl\": \"Stofzuigen\",\n                  \"da\": \"Støvsug\",\n                  \"de\": \"Staubsaugen\",\n                  \"es\": \"Aspirar\",\n                  \"fr\": \"Aspirer\",\n                  \"it\": \"Aspirazione\",\n                  \"no\": \"Støvsuging\",\n                  \"sv\": \"Dammsug\",\n                  \"pl\": \"Odkurzanie\",\n                  \"ru\": \"Пылесос\",\n                  \"ko\": \"청소\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Vacuum + Mop\",\n                  \"nl\": \"Stofzuigen + moppen\",\n                  \"da\": \"Støvsug + Mop\",\n                  \"de\": \"Staubsaugen + Wischen\",\n                  \"es\": \"Aspirar + Fregar\",\n                  \"fr\": \"Aspirer + Nettoyer\",\n                  \"it\": \"Aspirazione + Passaggio del mop\",\n                  \"no\": \"Støvsuging + Mopping\",\n                  \"sv\": \"Dammsug + Moppa\",\n                  \"pl\": \"Odkurzanie + Mop\",\n                  \"ru\": \"Пылесос + Мытье\",\n                  \"ko\": \"청소 + 물걸레질\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Mop\",\n                  \"nl\": \"Moppen\",\n                  \"da\": \"Mop\",\n                  \"de\": \"Wischen\",\n                  \"es\": \"Fregar\",\n                  \"fr\": \"Nettoyer\",\n                  \"it\": \"Passaggio del mop\",\n                  \"no\": \"Mopping\",\n                  \"sv\": \"Moppa\",\n                  \"pl\": \"Mop\",\n                  \"ru\": \"Мытье\",\n                  \"ko\": \"물걸레질\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer Stofzuiger\",\n              \"da\": \"Vælg Støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccionar Aspiradora\",\n              \"fr\": \"Sélectionnez l'aspirateur\",\n              \"it\": \"Seleziona Aspirapolvere\",\n              \"no\": \"Velg Støvsuger\",\n              \"sv\": \"Välj Dammsugare\",\n              \"pl\": \"Wybierz Odkurzacz\",\n              \"ru\": \"Выберите Пылесос\",\n              \"ko\": \"청소기 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_viomi_vacuum_v7\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Set Mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Indstil tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Configurar modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Angi modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Indstil tilstand til [[mode]]\",\n          \"de\": \"Modus einstellen auf [[mode]]\",\n          \"es\": \"Configurar modo a [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta la modalità su [[mode]]\",\n          \"no\": \"Angi modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"auto\",\n                \"title\": {\n                  \"en\": \"Auto\",\n                  \"nl\": \"Auto\",\n                  \"da\": \"Auto\",\n                  \"de\": \"Auto\",\n                  \"es\": \"Automático\",\n                  \"fr\": \"Auto\",\n                  \"it\": \"Auto\",\n                  \"no\": \"Auto\",\n                  \"sv\": \"Auto\",\n                  \"pl\": \"Auto\",\n                  \"ru\": \"Авто\",\n                  \"ko\": \"자동\"\n                }\n              },\n              {\n                \"id\": \"silent\",\n                \"title\": {\n                  \"en\": \"Silent\",\n                  \"nl\": \"Stil\",\n                  \"da\": \"Silent\",\n                  \"de\": \"Leise\",\n                  \"es\": \"Silencioso\",\n                  \"fr\": \"Silencieux\",\n                  \"it\": \"Silenzioso\",\n                  \"no\": \"Silent\",\n                  \"sv\": \"Tyst\",\n                  \"pl\": \"Cichy\",\n                  \"ru\": \"Тихий\",\n                  \"ko\": \"무음\"\n                }\n              },\n              {\n                \"id\": \"interval\",\n                \"title\": {\n                  \"en\": \"Interval\",\n                  \"nl\": \"Interval\",\n                  \"da\": \"Interval\",\n                  \"de\": \"Intervall\",\n                  \"es\": \"Intervalo\",\n                  \"fr\": \"Intervalle\",\n                  \"it\": \"Intervallo\",\n                  \"no\": \"Intervall\",\n                  \"sv\": \"Intervall\",\n                  \"pl\": \"Interwał\",\n                  \"ru\": \"Интервал\",\n                  \"ko\": \"간격\"\n                }\n              },\n              {\n                \"id\": \"low\",\n                \"title\": {\n                  \"en\": \"Low\",\n                  \"nl\": \"Laag\",\n                  \"da\": \"Lav\",\n                  \"de\": \"Niedrig\",\n                  \"es\": \"Bajo\",\n                  \"fr\": \"Bas\",\n                  \"it\": \"Basso\",\n                  \"no\": \"Lav\",\n                  \"sv\": \"Låg\",\n                  \"pl\": \"Niski\",\n                  \"ru\": \"Низкий\",\n                  \"ko\": \"낮음\"\n                }\n              },\n              {\n                \"id\": \"middle\",\n                \"title\": {\n                  \"en\": \"Medium\",\n                  \"nl\": \"Medium\",\n                  \"da\": \"Middel\",\n                  \"de\": \"Mittel\",\n                  \"es\": \"Medio\",\n                  \"fr\": \"Moyen\",\n                  \"it\": \"Medio\",\n                  \"no\": \"Middels\",\n                  \"sv\": \"Medium\",\n                  \"pl\": \"Średni\",\n                  \"ru\": \"Средний\",\n                  \"ko\": \"중간\"\n                }\n              },\n              {\n                \"id\": \"strong\",\n                \"title\": {\n                  \"en\": \"High\",\n                  \"nl\": \"Hoog\",\n                  \"da\": \"Høj\",\n                  \"de\": \"Hoch\",\n                  \"es\": \"Alto\",\n                  \"fr\": \"Élevé\",\n                  \"it\": \"Alto\",\n                  \"no\": \"Høy\",\n                  \"sv\": \"Hög\",\n                  \"pl\": \"Wysoki\",\n                  \"ru\": \"Высокий\",\n                  \"ko\": \"높음\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Smartmi Fresh Air System \",\n              \"nl\": \"Selecteer Smartmi Fresh Air System\",\n              \"da\": \"Vælg Smartmi Fresh Air System \",\n              \"de\": \"Smartmi-Frischluftsystem auswählen\",\n              \"es\": \"Seleccione Smartmi Fresh Air System \",\n              \"fr\": \"Sélectionnez Smartmi Fresh Air System \",\n              \"it\": \"Seleziona Smartmi Fresh Air System \",\n              \"no\": \"Velg Smartmi Fresh Air System\",\n              \"sv\": \"Välj Smartmi Fresh Air System \",\n              \"pl\": \"Wybierz Smartmi Fresh Air System \",\n              \"ru\": \"Выберите систему свежего воздуха Smartmi\",\n              \"ko\": \"Smartmi Fresh Air System 선택\"\n            },\n            \"filter\": \"driver_id=airfresh_zhimi_airfresh\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"modeZhimiAirfresh\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Calibrate feeder scale\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\"\n            },\n            \"filter\": \"driver_id=petfeeder_mmgg_miot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"petfeederCalibrate\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set display schedule progress\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Display progress [[enabled]]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"enabled\",\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"true\",\n                \"label\": {\n                  \"en\": \"On\"\n                }\n              },\n              {\n                \"id\": \"false\",\n                \"label\": {\n                  \"en\": \"Off\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select device\"\n            },\n            \"filter\": \"driver_id=petfeeder_mmgg_miot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"petfeederDisplaySchedule\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Serve food\",\n          \"nl\": \"Voedsel serveren\",\n          \"da\": \"Server mad\",\n          \"de\": \"Essen servieren\",\n          \"es\": \"Servir comida\",\n          \"fr\": \"Servir la nourriture\",\n          \"it\": \"Servire cibo\",\n          \"no\": \"Server mat\",\n          \"sv\": \"Servera mat\",\n          \"pl\": \"Podawaj jedzenie\",\n          \"ru\": \"Подавать еду\",\n          \"ko\": \"음식 제공\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Serve [[servings]] servings\",\n          \"nl\": \"Serveer [[servings]] porties\",\n          \"da\": \"Server [[servings]] portioner\",\n          \"de\": \"Serviere [[servings]] Portionen\",\n          \"es\": \"Servir [[servings]] raciones\",\n          \"fr\": \"Servir [[servings]] portions\",\n          \"it\": \"Servi [[servings]] porzioni\",\n          \"no\": \"Server [[servings]] porsjoner\",\n          \"sv\": \"Servera [[servings]] portioner\",\n          \"pl\": \"Podaj [[servings]] porcje\",\n          \"ru\": \"Подать [[servings]] порций\",\n          \"ko\": \"[[servings]] 서빙 제공\"\n        },\n        \"args\": [\n          {\n            \"name\": \"servings\",\n            \"title\": {\n              \"en\": \"Servings\",\n              \"nl\": \"Porties\",\n              \"da\": \"Portioner\",\n              \"de\": \"Portionen\",\n              \"es\": \"Raciones\",\n              \"fr\": \"Portions\",\n              \"it\": \"Porzioni\",\n              \"no\": \"Porsjoner\",\n              \"sv\": \"Portioner\",\n              \"pl\": \"Porcje\",\n              \"ru\": \"Порции\",\n              \"ko\": \"서빙\"\n            },\n            \"type\": \"number\",\n            \"placeholder\": {\n              \"en\": \"Servings\",\n              \"nl\": \"Porties\",\n              \"da\": \"Portioner\",\n              \"de\": \"Portionen\",\n              \"es\": \"Raciones\",\n              \"fr\": \"Portions\",\n              \"it\": \"Porzioni\",\n              \"no\": \"Porsjoner\",\n              \"sv\": \"Portioner\",\n              \"pl\": \"Porcje\",\n              \"ru\": \"Порции\",\n              \"ko\": \"서빙\"\n            },\n            \"min\": 1,\n            \"max\": 30,\n            \"step\": 1\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=petfeeder_mmgg_miot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"petfeederServeFood\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Sæt tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Establecer modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Sett modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Sæt tilstand til [[mode]]\",\n          \"de\": \"Modus auf [[mode]] setzen\",\n          \"es\": \"Establecer modo en [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Sett modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Common\",\n                  \"nl\": \"Normaal\",\n                  \"da\": \"Almindelig\",\n                  \"de\": \"Normal\",\n                  \"es\": \"Común\",\n                  \"fr\": \"Commun\",\n                  \"it\": \"Comune\",\n                  \"no\": \"Vanlig\",\n                  \"sv\": \"Vanlig\",\n                  \"pl\": \"Zwykły\",\n                  \"ru\": \"Обычный\",\n                  \"ko\": \"일반\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Smart\",\n                  \"nl\": \"Slim\",\n                  \"da\": \"Smart\",\n                  \"de\": \"Klug\",\n                  \"es\": \"Inteligente\",\n                  \"fr\": \"Intelligent\",\n                  \"it\": \"Intelligente\",\n                  \"no\": \"Smart\",\n                  \"sv\": \"Smart\",\n                  \"pl\": \"Inteligentny\",\n                  \"ru\": \"Умный\",\n                  \"ko\": \"스마트\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Pet Waterdispenser\",\n              \"nl\": \"Selecteer Pet Waterdispenser\",\n              \"da\": \"Vælg Pet Waterdispenser\",\n              \"de\": \"Wählen Sie Pet Waterdispenser\",\n              \"es\": \"Seleccione el dispensador de agua para mascotas\",\n              \"fr\": \"Sélectionnez Pet Waterdispenser\",\n              \"it\": \"Seleziona Pet Waterdispenser\",\n              \"no\": \"Velg Pet Waterdispenser\",\n              \"sv\": \"Välj Pet Waterdispenser\",\n              \"pl\": \"Wybierz Pet Waterdispenser\",\n              \"ru\": \"Выберите Pet Waterdispenser\",\n              \"ko\": \"펫 워터 디스펜서를 선택하세요\"\n            },\n            \"filter\": \"driver_id=petwaterdispenser_mmgg_miot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"petwaterdispenserMmggMode\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set mode\",\n          \"nl\": \"Stel modus in\",\n          \"da\": \"Sæt tilstand\",\n          \"de\": \"Modus einstellen\",\n          \"es\": \"Establecer modo\",\n          \"fr\": \"Définir le mode\",\n          \"it\": \"Imposta modalità\",\n          \"no\": \"Sett modus\",\n          \"sv\": \"Ställ in läge\",\n          \"pl\": \"Ustaw tryb\",\n          \"ru\": \"Установить режим\",\n          \"ko\": \"모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]]\",\n          \"nl\": \"Stel modus in op [[mode]]\",\n          \"da\": \"Sæt tilstand til [[mode]]\",\n          \"de\": \"Modus auf [[mode]] setzen\",\n          \"es\": \"Establecer modo en [[mode]]\",\n          \"fr\": \"Définir le mode sur [[mode]]\",\n          \"it\": \"Imposta modalità su [[mode]]\",\n          \"no\": \"Sett modus til [[mode]]\",\n          \"sv\": \"Ställ in läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb na [[mode]]\",\n          \"ru\": \"Установить режим на [[mode]]\",\n          \"ko\": \"[[mode]] 모드로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Auto\",\n                  \"nl\": \"Auto\",\n                  \"da\": \"Auto\",\n                  \"de\": \"Auto\",\n                  \"es\": \"Auto\",\n                  \"fr\": \"Auto\",\n                  \"it\": \"Auto\",\n                  \"no\": \"Auto\",\n                  \"sv\": \"Auto\",\n                  \"pl\": \"Auto\",\n                  \"ru\": \"Авто\",\n                  \"ko\": \"자동\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Interval\",\n                  \"nl\": \"Interval\",\n                  \"da\": \"Interval\",\n                  \"de\": \"Intervall\",\n                  \"es\": \"Intervalo\",\n                  \"fr\": \"Intervalle\",\n                  \"it\": \"Intervallo\",\n                  \"no\": \"Intervall\",\n                  \"sv\": \"Intervall\",\n                  \"pl\": \"Interwał\",\n                  \"ru\": \"Интервал\",\n                  \"ko\": \"간격\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Constant\",\n                  \"nl\": \"Constant\",\n                  \"da\": \"Konstant\",\n                  \"de\": \"Konstant\",\n                  \"es\": \"Constante\",\n                  \"fr\": \"Constant\",\n                  \"it\": \"Costante\",\n                  \"no\": \"Konstant\",\n                  \"sv\": \"Konstant\",\n                  \"pl\": \"Stały\",\n                  \"ru\": \"Постоянный\",\n                  \"ko\": \"지속\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Pet Fountain\",\n              \"nl\": \"Selecteer Huisdierfontein\",\n              \"da\": \"Vælg Kæledyrsfountain\",\n              \"de\": \"Wählen Sie Haustierbrunnen\",\n              \"es\": \"Seleccione Fuente para Mascotas\",\n              \"fr\": \"Sélectionnez Fontaine pour Animaux\",\n              \"it\": \"Seleziona Fontana per Animali\",\n              \"no\": \"Velg Kjæledyrfontene\",\n              \"sv\": \"Välj Husdjursfontän\",\n              \"pl\": \"Wybierz Fontannę dla Zwierząt\",\n              \"ru\": \"Выберите Фонтан для животных\",\n              \"ko\": \"펫 분수대 선택\"\n            },\n            \"filter\": \"driver_id=pet_waterer_xiaomi\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"petwaterdispenserMmggMode_Xiaomi\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Send IR code\",\n          \"nl\": \"IR code versturen\",\n          \"da\": \"Send IR-kode\",\n          \"de\": \"IR-Code senden\",\n          \"es\": \"Enviar código IR\",\n          \"fr\": \"Envoyer le code IR\",\n          \"it\": \"Invia codice IR\",\n          \"no\": \"Send IR-kode\",\n          \"sv\": \"Skicka IR-kod\",\n          \"pl\": \"Wyślij kod IR\",\n          \"ru\": \"Отправить код IR\",\n          \"ko\": \"IR 코드 보내기\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Send code [[code]]\",\n          \"nl\": \"Verstuur code [[code]]\",\n          \"da\": \"Send kode [[code]]\",\n          \"de\": \"Code [[code]] senden\",\n          \"es\": \"Enviar código [[code]]\",\n          \"fr\": \"Envoyer le code [[code]]\",\n          \"it\": \"Invia codice [[code]]\",\n          \"no\": \"Send kode [[code]]\",\n          \"sv\": \"Skicka kod [[code]]\",\n          \"pl\": \"Wyślij kod [[code]]\",\n          \"ru\": \"Отправить код [[code]]\",\n          \"ko\": \"코드 [[code]] 보내기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"code\",\n            \"title\": {\n              \"en\": \"Code\",\n              \"nl\": \"Code\",\n              \"da\": \"Kode\",\n              \"de\": \"Code\",\n              \"es\": \"Código\",\n              \"fr\": \"Code\",\n              \"it\": \"Codice\",\n              \"no\": \"Kode\",\n              \"sv\": \"Kod\",\n              \"pl\": \"Kod\",\n              \"ru\": \"Код\",\n              \"ko\": \"코드\"\n            },\n            \"type\": \"text\",\n            \"placeholder\": {\n              \"en\": \"code\",\n              \"nl\": \"code\",\n              \"da\": \"kode\",\n              \"de\": \"Code\",\n              \"es\": \"código\",\n              \"fr\": \"code\",\n              \"it\": \"codice\",\n              \"no\": \"kode\",\n              \"sv\": \"kod\",\n              \"pl\": \"kod\",\n              \"ru\": \"код\",\n              \"ko\": \"코드\"\n            }\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select IR Remote\",\n              \"nl\": \"Selecteer IR Remote\",\n              \"da\": \"Vælg IR-fjernbetjening\",\n              \"de\": \"Wähle IR-Fernbedienung\",\n              \"es\": \"Selecciona Control Remoto IR\",\n              \"fr\": \"Sélectionnez la télécommande IR\",\n              \"it\": \"Seleziona telecomando IR\",\n              \"no\": \"Velg IR-fjernkontroll\",\n              \"sv\": \"Välj IR-fjärrkontroll\",\n              \"pl\": \"Wybierz pilot IR\",\n              \"ru\": \"Выберите ИК-пульт\",\n              \"ko\": \"IR 리모컨 선택\"\n            },\n            \"filter\": \"driver_id=remote_chuangmi_remote_v2\"\n          }\n        ],\n        \"id\": \"remote_send_ir_code\"\n      },\n      {\n        \"id\": \"rightSwitchOff\",\n        \"title\": {\n          \"en\": \"Turn Right Switch Off\",\n          \"nl\": \"Schakel rechterschakelaar uit\",\n          \"da\": \"Sluk højre kontakt\",\n          \"de\": \"Rechten Schalter ausschalten\",\n          \"es\": \"Apagar interruptor derecho\",\n          \"fr\": \"Éteindre l'interrupteur de droite\",\n          \"it\": \"Spegni interruttore destro\",\n          \"no\": \"Slå av høyre bryter\",\n          \"sv\": \"Stäng av höger strömbrytare\",\n          \"pl\": \"Wyłącz prawy przełącznik\",\n          \"ru\": \"Выключить правый выключатель\",\n          \"ko\": \"오른쪽 스위치 끄기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"rightSwitchOn\",\n        \"title\": {\n          \"en\": \"Turn Right Switch On\",\n          \"nl\": \"Schakel rechterschakelaar aan\",\n          \"da\": \"Tænd højre kontakt\",\n          \"de\": \"Rechten Schalter einschalten\",\n          \"es\": \"Encender interruptor derecho\",\n          \"fr\": \"Allumer l'interrupteur droit\",\n          \"it\": \"Accendi l'interruttore destro\",\n          \"no\": \"Slå på høyre bryter\",\n          \"sv\": \"Slå på höger strömbrytare\",\n          \"pl\": \"Włącz prawy przełącznik\",\n          \"ru\": \"Включить правый переключатель\",\n          \"ko\": \"오른쪽 스위치 켜기\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner l'appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"rightSwitchToggle\",\n        \"title\": {\n          \"en\": \"Toggle Right Switch\",\n          \"nl\": \"Schakel rechterschakelaar\",\n          \"da\": \"Skift højre kontakt\",\n          \"de\": \"Rechten Schalter umschalten\",\n          \"es\": \"Cambiar interruptor derecho\",\n          \"fr\": \"Basculer l'interrupteur droit\",\n          \"it\": \"Attiva/disattiva l'interruttore destro\",\n          \"no\": \"Slå av/på høyre bryter\",\n          \"sv\": \"Växla höger strömbrytare\",\n          \"pl\": \"Przełącz prawy przełącznik\",\n          \"ru\": \"Переключить правый переключатель\",\n          \"ko\": \"오른쪽 스위치 전환\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выберите устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=aqara-ctrl-neutral2|aqara-ctrl-ln2|relay_c2acn01\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Rotate fan to the left\",\n          \"de\": \"Lüfter nach links drehen\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Rotate fan to the left\",\n          \"de\": \"Lüfter nach links drehen\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\"\n            },\n            \"filter\": \"driver_id=fan_dmaker_advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"rotateLeftStep\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Rotate fan to the right\",\n          \"de\": \"Lüfter nach rechts drehen\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Rotate fan to the right\",\n          \"de\": \"Lüfter nach rechts drehen\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\"\n            },\n            \"filter\": \"driver_id=fan_dmaker_advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"rotateRightStep\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Change Oscillating Angle\",\n          \"nl\": \"Wijzig oscillatie hoek\",\n          \"da\": \"Skift oscillerende vinkel\",\n          \"de\": \"Oszillationswinkel ändern\",\n          \"es\": \"Cambiar ángulo de oscilación\",\n          \"fr\": \"Changer l'angle d'oscillation\",\n          \"it\": \"Cambia angolo di oscillazione\",\n          \"no\": \"Endre oscillerende vinkel\",\n          \"sv\": \"Ändra oscillatorvinkel\",\n          \"pl\": \"Zmień kąt oscylacji\",\n          \"ru\": \"Изменить угол колебания\",\n          \"ko\": \"진동 각도 변경\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Change oscillating angle to [[angle]]\",\n          \"nl\": \"Wijzig oscillatie hoek naar [[angle]]\",\n          \"da\": \"Skift oscillerende vinkel til [[angle]]\",\n          \"de\": \"Oszillationswinkel ändern zu [[angle]]\",\n          \"es\": \"Cambiar ángulo de oscilación a [[angle]]\",\n          \"fr\": \"Changer l'angle d'oscillation en [[angle]]\",\n          \"it\": \"Cambia angolo di oscillazione a [[angle]]\",\n          \"no\": \"Endre oscillerende vinkel til [[angle]]\",\n          \"sv\": \"Ändra oscillatorvinkel till [[angle]]\",\n          \"pl\": \"Zmień kąt oscylacji na [[angle]]\",\n          \"ru\": \"Изменить угол колебания на [[angle]]\",\n          \"ko\": \"진동 각도 [[angle]]로 변경\"\n        },\n        \"args\": [\n          {\n            \"name\": \"angle\",\n            \"title\": {\n              \"en\": \"Angle\",\n              \"nl\": \"Hoek\",\n              \"da\": \"Vinkel\",\n              \"de\": \"Winkel\",\n              \"es\": \"Ángulo\",\n              \"fr\": \"Angle\",\n              \"it\": \"Angolo\",\n              \"no\": \"Vinkel\",\n              \"sv\": \"Vinkel\",\n              \"pl\": \"Kąt\",\n              \"ru\": \"Угол\",\n              \"ko\": \"각도\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"30\",\n                \"title\": {\n                  \"en\": \"30°\",\n                  \"nl\": \"30°\",\n                  \"da\": \"30°\",\n                  \"de\": \"30°\",\n                  \"es\": \"30°\",\n                  \"fr\": \"30°\",\n                  \"it\": \"30°\",\n                  \"no\": \"30°\",\n                  \"sv\": \"30°\",\n                  \"pl\": \"30°\",\n                  \"ru\": \"30°\",\n                  \"ko\": \"30°\"\n                }\n              },\n              {\n                \"id\": \"60\",\n                \"title\": {\n                  \"en\": \"60°\",\n                  \"nl\": \"60°\",\n                  \"da\": \"60°\",\n                  \"de\": \"60°\",\n                  \"es\": \"60°\",\n                  \"fr\": \"60°\",\n                  \"it\": \"60°\",\n                  \"no\": \"60°\",\n                  \"sv\": \"60°\",\n                  \"pl\": \"60°\",\n                  \"ru\": \"60°\",\n                  \"ko\": \"60°\"\n                }\n              },\n              {\n                \"id\": \"90\",\n                \"title\": {\n                  \"en\": \"90°\",\n                  \"nl\": \"90°\",\n                  \"da\": \"90°\",\n                  \"de\": \"90°\",\n                  \"es\": \"90°\",\n                  \"fr\": \"90°\",\n                  \"it\": \"90°\",\n                  \"no\": \"90°\",\n                  \"sv\": \"90°\",\n                  \"pl\": \"90°\",\n                  \"ru\": \"90°\",\n                  \"ko\": \"90°\"\n                }\n              },\n              {\n                \"id\": \"120\",\n                \"title\": {\n                  \"en\": \"120°\",\n                  \"nl\": \"120°\",\n                  \"da\": \"120°\",\n                  \"de\": \"120°\",\n                  \"es\": \"120°\",\n                  \"fr\": \"120°\",\n                  \"it\": \"120°\",\n                  \"no\": \"120°\",\n                  \"sv\": \"120°\",\n                  \"pl\": \"120°\",\n                  \"ru\": \"120°\",\n                  \"ko\": \"120°\"\n                }\n              },\n              {\n                \"id\": \"140\",\n                \"title\": {\n                  \"en\": \"140°\",\n                  \"nl\": \"140°\",\n                  \"da\": \"140°\",\n                  \"de\": \"140°\",\n                  \"es\": \"140°\",\n                  \"fr\": \"140°\",\n                  \"it\": \"140°\",\n                  \"no\": \"140°\",\n                  \"sv\": \"140°\",\n                  \"pl\": \"140°\",\n                  \"ru\": \"140°\",\n                  \"ko\": \"140°\"\n                }\n              },\n              {\n                \"id\": \"150\",\n                \"title\": {\n                  \"en\": \"150°\",\n                  \"nl\": \"150°\",\n                  \"da\": \"150°\",\n                  \"de\": \"150°\",\n                  \"es\": \"150°\",\n                  \"fr\": \"150°\",\n                  \"it\": \"150°\",\n                  \"no\": \"150°\",\n                  \"sv\": \"150°\",\n                  \"pl\": \"150°\",\n                  \"ru\": \"150°\",\n                  \"ko\": \"150°\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Device\",\n              \"nl\": \"Selecteer apparaat\",\n              \"da\": \"Vælg enhed\",\n              \"de\": \"Gerät auswählen\",\n              \"es\": \"Seleccionar dispositivo\",\n              \"fr\": \"Sélectionner un appareil\",\n              \"it\": \"Seleziona dispositivo\",\n              \"no\": \"Velg enhet\",\n              \"sv\": \"Välj enhet\",\n              \"pl\": \"Wybierz urządzenie\",\n              \"ru\": \"Выбрать устройство\",\n              \"ko\": \"장치 선택\"\n            },\n            \"filter\": \"driver_id=zhimi-fan|dmaker-fan|fan_zhimi_advanced|fan_zhimi_fan_za5|fan_dmaker_advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"setAngle\"\n      },\n      {\n        \"id\": \"vacuumDreameFanspeed\",\n        \"title\": {\n          \"en\": \"Set Fanspeed\",\n          \"nl\": \"Stel ventilator in\",\n          \"da\": \"Indstil blæserhastighed\",\n          \"de\": \"Lüftergeschwindigkeit einstellen\",\n          \"es\": \"Establecer velocidad del ventilador\",\n          \"fr\": \"Régler la vitesse du ventilateur\",\n          \"it\": \"Imposta velocità della ventola\",\n          \"no\": \"Set viftehastighet\",\n          \"sv\": \"Ställ in fläkthastighet\",\n          \"pl\": \"Ustaw prędkość wentylatora\",\n          \"ru\": \"Установить скорость вентилятора\",\n          \"ko\": \"팬 속도 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set Fanspeed [[fanspeed]]\",\n          \"nl\": \"Stel ventilator in op [[fanspeed]]\",\n          \"da\": \"Indstil blæserhastighed [[fanspeed]]\",\n          \"de\": \"Lüftergeschwindigkeit einstellen [[fanspeed]]\",\n          \"es\": \"Establecer velocidad del ventilador [[fanspeed]]\",\n          \"fr\": \"Régler la vitesse du ventilateur [[fanspeed]]\",\n          \"it\": \"Imposta velocità della ventola [[fanspeed]]\",\n          \"no\": \"Set viftehastighet [[fanspeed]]\",\n          \"sv\": \"Ställ in fläkthastighet [[fanspeed]]\",\n          \"pl\": \"Ustaw prędkość wentylatora [[fanspeed]]\",\n          \"ru\": \"Установить скорость вентилятора [[fanspeed]]\",\n          \"ko\": \"팬 속도 설정 [[fanspeed]]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"fanspeed\",\n            \"title\": {\n              \"en\": \"Fanspeed\",\n              \"nl\": \"Fan snelheid\",\n              \"da\": \"Blæserhastighed\",\n              \"de\": \"Lüftergeschwindigkeit\",\n              \"es\": \"Velocidad del ventilador\",\n              \"fr\": \"Vitesse du ventilateur\",\n              \"it\": \"Velocità della ventola\",\n              \"no\": \"Viftehastighet\",\n              \"sv\": \"Fläkhastighet\",\n              \"pl\": \"Prędkość wentylatora\",\n              \"ru\": \"Скорость вентилятора\",\n              \"ko\": \"팬 속도\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Silent\",\n                  \"nl\": \"Stil\",\n                  \"da\": \"Silent\",\n                  \"de\": \"Leise\",\n                  \"es\": \"Silencioso\",\n                  \"fr\": \"Silencieux\",\n                  \"it\": \"Silenzioso\",\n                  \"no\": \"Stille\",\n                  \"sv\": \"Tyst\",\n                  \"pl\": \"Cichy\",\n                  \"ru\": \"Тихий\",\n                  \"ko\": \"조용한\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Basic\",\n                  \"nl\": \"Basis\",\n                  \"da\": \"Grundlæggende\",\n                  \"de\": \"Einfach\",\n                  \"es\": \"Básico\",\n                  \"fr\": \"De base\",\n                  \"it\": \"Base\",\n                  \"no\": \"Grunnleggende\",\n                  \"sv\": \"Grundläggande\",\n                  \"pl\": \"Podstawowy\",\n                  \"ru\": \"Основной\",\n                  \"ko\": \"기본\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Strong\",\n                  \"nl\": \"Sterk\",\n                  \"da\": \"Stærk\",\n                  \"de\": \"Stark\",\n                  \"es\": \"Fuerte\",\n                  \"fr\": \"Fort\",\n                  \"it\": \"Forte\",\n                  \"no\": \"Sterk\",\n                  \"sv\": \"Stark\",\n                  \"pl\": \"Mocny\",\n                  \"ru\": \"Сильный\",\n                  \"ko\": \"강한\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"title\": {\n                  \"en\": \"Full speed\",\n                  \"nl\": \"Volle snelheid\",\n                  \"da\": \"Fuld hastighed\",\n                  \"de\": \"Volle Geschwindigkeit\",\n                  \"es\": \"Velocidad completa\",\n                  \"fr\": \"Vitesse maximale\",\n                  \"it\": \"Velocità massima\",\n                  \"no\": \"Full hastighet\",\n                  \"sv\": \"Full hastighet\",\n                  \"pl\": \"Pełna prędkość\",\n                  \"ru\": \"Полная скорость\",\n                  \"ko\": \"최고 속도\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer stofzuiger\",\n              \"da\": \"Vælg støvsuger\",\n              \"de\": \"Vakuum auswählen\",\n              \"es\": \"Seleccionar aspiradora\",\n              \"fr\": \"Sélectionner l'aspirateur\",\n              \"it\": \"Seleziona aspirapolvere\",\n              \"no\": \"Velg vakuum\",\n              \"sv\": \"Välj dammsugare\",\n              \"pl\": \"Wybierz odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"진공 청소기 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_dreame_vacuum\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"vacuumDreameMopIntensity\",\n        \"title\": {\n          \"en\": \"Set Mop Intesity\",\n          \"nl\": \"Stel dweil intensiteit in\",\n          \"da\": \"Indstil moppe intensitet\",\n          \"de\": \"Wischeintensität einstellen\",\n          \"es\": \"Establecer intensidad de fregado\",\n          \"fr\": \"Définir l'intensité de la serpillière\",\n          \"it\": \"Imposta l'intensità della mocio\",\n          \"no\": \"Sett moppens intensitet\",\n          \"sv\": \"Ställ in moppintensitet\",\n          \"pl\": \"Ustaw intensywność mopa\",\n          \"ru\": \"Установить интенсивность швабры\",\n          \"ko\": \"걸레 강도 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mop intensity to [[intensity]]\",\n          \"nl\": \"Stel dweil intensiteit in op [[intensity]]\",\n          \"da\": \"Indstil moppe intensitet til [[intensity]]\",\n          \"de\": \"Wischeintensität auf [[intensity]] einstellen\",\n          \"es\": \"Establecer intensidad de fregado a [[intensity]]\",\n          \"fr\": \"Définir l'intensité de la serpillière à [[intensity]]\",\n          \"it\": \"Imposta l'intensità della mocio su [[intensity]]\",\n          \"no\": \"Sett moppens intensitet til [[intensity]]\",\n          \"sv\": \"Ställ in moppintensitet till [[intensity]]\",\n          \"pl\": \"Ustaw intensywność mopa na [[intensity]]\",\n          \"ru\": \"Установить интенсивность швабры на [[intensity]]\",\n          \"ko\": \"걸레 강도를 [[intensity]]로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"intensity\",\n            \"title\": {\n              \"en\": \"Mop Intensity\",\n              \"nl\": \"Dweil intensiteit\",\n              \"da\": \"Moppe intensitet\",\n              \"de\": \"Wischeintensität\",\n              \"es\": \"Intensidad de fregado\",\n              \"fr\": \"Intensité de la serpillière\",\n              \"it\": \"Intensità della mocio\",\n              \"no\": \"Moppens intensitet\",\n              \"sv\": \"Moppintensitet\",\n              \"pl\": \"Intensywność mopa\",\n              \"ru\": \"Интенсивность швабры\",\n              \"ko\": \"걸레 강도\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Low\",\n                  \"nl\": \"Laag\",\n                  \"da\": \"Lav\",\n                  \"de\": \"Niedrig\",\n                  \"es\": \"Bajo\",\n                  \"fr\": \"Bas\",\n                  \"it\": \"Bassa\",\n                  \"no\": \"Lav\",\n                  \"sv\": \"Låg\",\n                  \"pl\": \"Niski\",\n                  \"ru\": \"Низкий\",\n                  \"ko\": \"낮음\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Medium\",\n                  \"nl\": \"Medium\",\n                  \"da\": \"Mellem\",\n                  \"de\": \"Mittel\",\n                  \"es\": \"Medio\",\n                  \"fr\": \"Moyen\",\n                  \"it\": \"Media\",\n                  \"no\": \"Middels\",\n                  \"sv\": \"Medium\",\n                  \"pl\": \"Średni\",\n                  \"ru\": \"Средний\",\n                  \"ko\": \"중간\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"High\",\n                  \"nl\": \"Hoog\",\n                  \"da\": \"Høj\",\n                  \"de\": \"Hoch\",\n                  \"es\": \"Alto\",\n                  \"fr\": \"Élevé\",\n                  \"it\": \"Alta\",\n                  \"no\": \"Høy\",\n                  \"sv\": \"Hög\",\n                  \"pl\": \"Wysoki\",\n                  \"ru\": \"Высокий\",\n                  \"ko\": \"높음\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer stofzuiger\",\n              \"da\": \"Vælg støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccionar aspiradora\",\n              \"fr\": \"Sélectionnez l'aspirateur\",\n              \"it\": \"Seleziona aspirapolvere\",\n              \"no\": \"Velg støvsuger\",\n              \"sv\": \"Välj dammsugare\",\n              \"pl\": \"Wybierz odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"청소기 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_dreame_vacuum&capabilities=vacuum_dreame_mop_intensity\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"vacuumRoborockFanspeed\",\n        \"title\": {\n          \"en\": \"Set Fanspeed\",\n          \"nl\": \"Stel ventilator in\",\n          \"da\": \"Indstil blæserhastighed\",\n          \"de\": \"Lüftergeschwindigkeit einstellen\",\n          \"es\": \"Ajustar velocidad del ventilador\",\n          \"fr\": \"Régler la vitesse du ventilateur\",\n          \"it\": \"Imposta velocità ventola\",\n          \"no\": \"Sett vifthastighet\",\n          \"sv\": \"Ställ in fläkthastighet\",\n          \"pl\": \"Ustaw prędkość wentylatora\",\n          \"ru\": \"Установить скорость вентилятора\",\n          \"ko\": \"팬 속도 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set Fanspeed [[fanspeed]]\",\n          \"nl\": \"Stel ventilator in op [[fanspeed]]\",\n          \"da\": \"Indstil blæserhastighed [[fanspeed]]\",\n          \"de\": \"Lüftergeschwindigkeit einstellen [[fanspeed]]\",\n          \"es\": \"Ajustar velocidad del ventilador [[fanspeed]]\",\n          \"fr\": \"Régler la vitesse du ventilateur [[fanspeed]]\",\n          \"it\": \"Imposta velocità ventola [[fanspeed]]\",\n          \"no\": \"Sett vifthastighet [[fanspeed]]\",\n          \"sv\": \"Ställ in fläkthastighet [[fanspeed]]\",\n          \"pl\": \"Ustaw prędkość wentylatora [[fanspeed]]\",\n          \"ru\": \"Установить скорость вентилятора [[fanspeed]]\",\n          \"ko\": \"팬 속도 설정 [[fanspeed]]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"fanspeed\",\n            \"title\": {\n              \"en\": \"Fanspeed\",\n              \"nl\": \"Fan snelheid\",\n              \"da\": \"Blæserhastighed\",\n              \"de\": \"Lüftergeschwindigkeit\",\n              \"es\": \"Velocidad del ventilador\",\n              \"fr\": \"Vitesse du ventilateur\",\n              \"it\": \"Velocità ventola\",\n              \"no\": \"Vifthastighet\",\n              \"sv\": \"Fläkthastighet\",\n              \"pl\": \"Prędkość wentylatora\",\n              \"ru\": \"Скорость вентилятора\",\n              \"ko\": \"팬 속도\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Quiet\",\n                  \"nl\": \"Stil\",\n                  \"da\": \"Stille\",\n                  \"de\": \"Leise\",\n                  \"es\": \"Silencioso\",\n                  \"fr\": \"Silencieux\",\n                  \"it\": \"Silenzioso\",\n                  \"no\": \"Stille\",\n                  \"sv\": \"Tyst\",\n                  \"pl\": \"Cichy\",\n                  \"ru\": \"Тихий\",\n                  \"ko\": \"조용히\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Standard\",\n                  \"nl\": \"Standaard\",\n                  \"da\": \"Standard\",\n                  \"de\": \"Standard\",\n                  \"es\": \"Estándar\",\n                  \"fr\": \"Standard\",\n                  \"it\": \"Standard\",\n                  \"no\": \"Standard\",\n                  \"sv\": \"Standard\",\n                  \"pl\": \"Standardowy\",\n                  \"ru\": \"Стандарт\",\n                  \"ko\": \"표준\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"title\": {\n                  \"en\": \"Medium\",\n                  \"nl\": \"Medium\",\n                  \"da\": \"Medium\",\n                  \"de\": \"Mittel\",\n                  \"es\": \"Medio\",\n                  \"fr\": \"Moyen\",\n                  \"it\": \"Medio\",\n                  \"no\": \"Medium\",\n                  \"sv\": \"Medium\",\n                  \"pl\": \"Średni\",\n                  \"ru\": \"Средний\",\n                  \"ko\": \"중간\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"title\": {\n                  \"en\": \"Turbo\",\n                  \"nl\": \"Turbo\",\n                  \"da\": \"Turbo\",\n                  \"de\": \"Turbo\",\n                  \"es\": \"Turbo\",\n                  \"fr\": \"Turbo\",\n                  \"it\": \"Turbo\",\n                  \"no\": \"Turbo\",\n                  \"sv\": \"Turbo\",\n                  \"pl\": \"Turbo\",\n                  \"ru\": \"Турбо\",\n                  \"ko\": \"터보\"\n                }\n              },\n              {\n                \"id\": \"5\",\n                \"title\": {\n                  \"en\": \"Max\",\n                  \"nl\": \"Max\",\n                  \"da\": \"Maks.\",\n                  \"de\": \"Max\",\n                  \"es\": \"Máximo\",\n                  \"fr\": \"Max\",\n                  \"it\": \"Max\",\n                  \"no\": \"Max\",\n                  \"sv\": \"Max\",\n                  \"pl\": \"Maks.\",\n                  \"ru\": \"Макс.\",\n                  \"ko\": \"최대\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer stofzuiger\",\n              \"da\": \"Vælg støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccionar aspiradora\",\n              \"fr\": \"Sélectionner un aspirateur\",\n              \"it\": \"Seleziona aspirapolvere\",\n              \"no\": \"Velg støvsuger\",\n              \"sv\": \"Välj dammsugare\",\n              \"pl\": \"Wybierz odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"진공 청소기 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"vacuumRoborockMopIntensity\",\n        \"title\": {\n          \"en\": \"Set Mop Intensity\",\n          \"nl\": \"Stel dweil intensiteit in\",\n          \"da\": \"Indstil Mop Intensitet\",\n          \"de\": \"Mop-Intensität einstellen\",\n          \"es\": \"Establecer intensidad de fregado\",\n          \"fr\": \"Régler l'intensité de la serpillière\",\n          \"it\": \"Imposta l'intensità della mop\",\n          \"no\": \"Sett moppintensitet\",\n          \"sv\": \"Ställ in moppintensitet\",\n          \"pl\": \"Ustaw intensywność mopa\",\n          \"ru\": \"Установить интенсивность швабры\",\n          \"ko\": \"걸레 강도 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set scrub intensity [[intensity]]\",\n          \"nl\": \"Stel mop intensiteit in op [[intensity]]\",\n          \"da\": \"Indstil skrubbeintensitet [[intensity]]\",\n          \"de\": \"Schrubbintensität einstellen [[intensity]]\",\n          \"es\": \"Establecer intensidad de fregado [[intensity]]\",\n          \"fr\": \"Régler l'intensité de la serpillière [[intensity]]\",\n          \"it\": \"Regola l'intensità di pulizia [[intensity]]\",\n          \"no\": \"Sett skrubbeintensitet [[intensity]]\",\n          \"sv\": \"Ställ in skrubbeintensitet [[intensity]]\",\n          \"pl\": \"Ustaw intensywność szorowania [[intensity]]\",\n          \"ru\": \"Установить интенсивность чистки [[intensity]]\",\n          \"ko\": \"스크럽 강도 설정 [[intensity]]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"intensity\",\n            \"title\": {\n              \"en\": \"Mop Intensity\",\n              \"nl\": \"Dweil intensiteit\",\n              \"da\": \"Mop Intensitet\",\n              \"de\": \"Mop-Intensität\",\n              \"es\": \"Intensidad de fregado\",\n              \"fr\": \"Intensité de la serpillière\",\n              \"it\": \"Intensità della mop\",\n              \"no\": \"Moppintensitet\",\n              \"sv\": \"Moppintensitet\",\n              \"pl\": \"Intensywność mopa\",\n              \"ru\": \"Интенсивность швабры\",\n              \"ko\": \"걸레 강도\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"200\",\n                \"label\": {\n                  \"en\": \"Off\",\n                  \"nl\": \"Uit\",\n                  \"da\": \"Slukket\",\n                  \"de\": \"Aus\",\n                  \"es\": \"Apagado\",\n                  \"fr\": \"Éteint\",\n                  \"it\": \"Spento\",\n                  \"no\": \"Av\",\n                  \"sv\": \"Av\",\n                  \"pl\": \"Wyłączone\",\n                  \"ru\": \"Выкл\",\n                  \"ko\": \"끄기\"\n                }\n              },\n              {\n                \"id\": \"201\",\n                \"label\": {\n                  \"en\": \"Mild\",\n                  \"nl\": \"Mild\",\n                  \"da\": \"Mild\",\n                  \"de\": \"Mild\",\n                  \"es\": \"Suave\",\n                  \"fr\": \"Doux\",\n                  \"it\": \"Leggera\",\n                  \"no\": \"Mild\",\n                  \"sv\": \"Mild\",\n                  \"pl\": \"Łagodny\",\n                  \"ru\": \"Мягкий\",\n                  \"ko\": \"약하게\"\n                }\n              },\n              {\n                \"id\": \"202\",\n                \"label\": {\n                  \"en\": \"Moderate\",\n                  \"nl\": \"Gemiddeld\",\n                  \"da\": \"Moderat\",\n                  \"de\": \"Mittel\",\n                  \"es\": \"Moderada\",\n                  \"fr\": \"Modérée\",\n                  \"it\": \"Moderata\",\n                  \"no\": \"Moderat\",\n                  \"sv\": \"Måttlig\",\n                  \"pl\": \"Średnia\",\n                  \"ru\": \"Умеренный\",\n                  \"ko\": \"중간\"\n                }\n              },\n              {\n                \"id\": \"203\",\n                \"label\": {\n                  \"en\": \"Intense\",\n                  \"nl\": \"Intens\",\n                  \"da\": \"Intens\",\n                  \"de\": \"Intensiv\",\n                  \"es\": \"Intensa\",\n                  \"fr\": \"Intense\",\n                  \"it\": \"Intensa\",\n                  \"no\": \"Intens\",\n                  \"sv\": \"Intensiv\",\n                  \"pl\": \"Intensywny\",\n                  \"ru\": \"Интенсивный\",\n                  \"ko\": \"강하게\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer stofzuiger\",\n              \"da\": \"Vælg Støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccione Aspiradora\",\n              \"fr\": \"Sélectionnez Aspirateur\",\n              \"it\": \"Seleziona Aspirapolvere\",\n              \"no\": \"Velg Støvsuger\",\n              \"sv\": \"Välj Dammsugare\",\n              \"pl\": \"Wybierz Odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"진공 청소기를 선택하세요\"\n            },\n            \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced&capabilities=vacuum_roborock_mop_intensity\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"vacuumRoborockMopVacuumMode\",\n        \"title\": {\n          \"en\": \"Set mop/vacuummode and intensity\",\n          \"nl\": \"Stel mop/stofzuig modus en intensiteit in\",\n          \"da\": \"Indstil mop/suge tilstand og intensitet\",\n          \"de\": \"Stellen Sie den Mopp/Saugmodus und die Intensität ein\",\n          \"es\": \"Configura el modo de trapeado/aspirado y la intensidad\",\n          \"fr\": \"Réglez le mode mop/aspiration et l'intensité\",\n          \"it\": \"Imposta la modalità mop/aspirapolvere e l'intensità\",\n          \"no\": \"Still inn mopp/støvsugermodus og intensitet\",\n          \"sv\": \"Ställ in mopp/dammsugarläge och intensitet\",\n          \"pl\": \"Ustaw tryb mopowania/odkurzania i intensywność\",\n          \"ru\": \"Установите режим мытья/пылесоса и интенсивность\",\n          \"ko\": \"닦기/흡입 모드와 강도를 설정하세요\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set mode to [[mode]] with fan speed [[fanspeed]] and mop intensity [[mop]]\",\n          \"nl\": \"Stel mode in op [[mode]] met stofzuigkracht [[fanspeed]] en mop intensiteit [[mop]]\",\n          \"da\": \"Indstil tilstand til [[mode]] med blæserhastighed [[fanspeed]] og moppeintensitet [[mop]]\",\n          \"de\": \"Stellen Sie den Modus auf [[mode]] mit Gebläsegeschwindigkeit [[fanspeed]] und Mop-Intensität [[mop]] ein\",\n          \"es\": \"Configura el modo en [[mode]] con la velocidad del ventilador [[fanspeed]] y la intensidad del trapeado [[mop]]\",\n          \"fr\": \"Réglez le mode sur [[mode]] avec une vitesse de ventilateur de [[fanspeed]] et une intensité de mop [[mop]]\",\n          \"it\": \"Imposta la modalità su [[mode]] con velocità di ventilazione [[fanspeed]] e intensità del mop [[mop]]\",\n          \"no\": \"Sett modus til [[mode]] med viftehastighet [[fanspeed]] og moppintensitet [[mop]]\",\n          \"sv\": \"Ställ in läge till [[mode]] med fläkthastighet [[fanspeed]] och moppintensitet [[mop]]\",\n          \"pl\": \"Ustaw tryb na [[mode]] z prędkością wentylatora [[fanspeed]] i intensywnością mopowania [[mop]]\",\n          \"ru\": \"Установите режим на [[mode]] с скоростью вентилятора [[fanspeed]] и интенсивностью мытья [[mop]]\",\n          \"ko\": \"[[mode]] 모드로 설정하고 팬 속도 [[fanspeed]]와 걸레 세정 강도 [[mop]]를 조절하세요\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Mode\",\n              \"nl\": \"Modus\",\n              \"da\": \"Tilstand\",\n              \"de\": \"Modus\",\n              \"es\": \"Modo\",\n              \"fr\": \"Mode\",\n              \"it\": \"Modalità\",\n              \"no\": \"Modus\",\n              \"sv\": \"Läge\",\n              \"pl\": \"Tryb\",\n              \"ru\": \"Режим\",\n              \"ko\": \"모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"sweep\",\n                \"title\": {\n                  \"en\": \"Vacuum\",\n                  \"nl\": \"Stofzuigen\",\n                  \"da\": \"Suge\",\n                  \"de\": \"Saugen\",\n                  \"es\": \"Aspirar\",\n                  \"fr\": \"Aspirateur\",\n                  \"it\": \"Aspirapolvere\",\n                  \"no\": \"Støvsuge\",\n                  \"sv\": \"Dammsug\",\n                  \"pl\": \"Odkurzanie\",\n                  \"ru\": \"Пылесос\",\n                  \"ko\": \"진공 청소\"\n                }\n              },\n              {\n                \"id\": \"mop\",\n                \"title\": {\n                  \"en\": \"Mop\",\n                  \"nl\": \"Moppen\",\n                  \"da\": \"Moppe\",\n                  \"de\": \"Wischen\",\n                  \"es\": \"Trapeado\",\n                  \"fr\": \"Mop\",\n                  \"it\": \"Mocio\",\n                  \"no\": \"Moppe\",\n                  \"sv\": \"Moppa\",\n                  \"pl\": \"Mopowanie\",\n                  \"ru\": \"Моп\",\n                  \"ko\": \"걸레질\"\n                }\n              },\n              {\n                \"id\": \"sweep-mop\",\n                \"title\": {\n                  \"en\": \"Vacuum + Mop\",\n                  \"nl\": \"Stofzuigen + moppen\",\n                  \"da\": \"Suge + Moppe\",\n                  \"de\": \"Saugen + Wischen\",\n                  \"es\": \"Aspirar + Trapeado\",\n                  \"fr\": \"Aspirateur + Mop\",\n                  \"it\": \"Aspirapolvere + Mocio\",\n                  \"no\": \"Støvsuge + Moppe\",\n                  \"sv\": \"Dammsug + Moppa\",\n                  \"pl\": \"Odkurzanie + Mopowanie\",\n                  \"ru\": \"Пылесос + Моп\",\n                  \"ko\": \"진공 청소 + 걸레질\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"fanspeed\",\n            \"title\": {\n              \"en\": \"Fanspeed\",\n              \"nl\": \"Fan snelheid\",\n              \"da\": \"Blæserhastighed\",\n              \"de\": \"Gebläsegeschwindigkeit\",\n              \"es\": \"Velocidad del ventilador\",\n              \"fr\": \"Vitesse du ventilateur\",\n              \"it\": \"Velocità della ventola\",\n              \"no\": \"Viftehastighet\",\n              \"sv\": \"Fläkthastighet\",\n              \"pl\": \"Prędkość wentylatora\",\n              \"ru\": \"Скорость вентилятора\",\n              \"ko\": \"팬 속도\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Quiet\",\n                  \"nl\": \"Stil\",\n                  \"da\": \"Stille\",\n                  \"de\": \"Leise\",\n                  \"es\": \"Silencioso\",\n                  \"fr\": \"Silencieux\",\n                  \"it\": \"Silenzioso\",\n                  \"no\": \"Stille\",\n                  \"sv\": \"Tyst\",\n                  \"pl\": \"Cichy\",\n                  \"ru\": \"Тихий\",\n                  \"ko\": \"조용한\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Standard\",\n                  \"nl\": \"Standaard\",\n                  \"da\": \"Standard\",\n                  \"de\": \"Standard\",\n                  \"es\": \"Estándar\",\n                  \"fr\": \"Standard\",\n                  \"it\": \"Standard\",\n                  \"no\": \"Standard\",\n                  \"sv\": \"Standard\",\n                  \"pl\": \"Standard\",\n                  \"ru\": \"Стандартный\",\n                  \"ko\": \"표준\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"title\": {\n                  \"en\": \"Medium\",\n                  \"nl\": \"Medium\",\n                  \"da\": \"Medium\",\n                  \"de\": \"Mittel\",\n                  \"es\": \"Medio\",\n                  \"fr\": \"Moyen\",\n                  \"it\": \"Medio\",\n                  \"no\": \"Medium\",\n                  \"sv\": \"Medium\",\n                  \"pl\": \"Średni\",\n                  \"ru\": \"Средний\",\n                  \"ko\": \"중간\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"title\": {\n                  \"en\": \"Turbo\",\n                  \"nl\": \"Turbo\",\n                  \"da\": \"Turbo\",\n                  \"de\": \"Turbo\",\n                  \"es\": \"Turbo\",\n                  \"fr\": \"Turbo\",\n                  \"it\": \"Turbo\",\n                  \"no\": \"Turbo\",\n                  \"sv\": \"Turbo\",\n                  \"pl\": \"Turbo\",\n                  \"ru\": \"Турбо\",\n                  \"ko\": \"터보\"\n                }\n              },\n              {\n                \"id\": \"5\",\n                \"title\": {\n                  \"en\": \"Max\",\n                  \"nl\": \"Max\",\n                  \"da\": \"Maks\",\n                  \"de\": \"Max\",\n                  \"es\": \"Máximo\",\n                  \"fr\": \"Max\",\n                  \"it\": \"Massimo\",\n                  \"no\": \"Maksimum\",\n                  \"sv\": \"Max\",\n                  \"pl\": \"Maksymalny\",\n                  \"ru\": \"Макс.\",\n                  \"ko\": \"최대\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"mop\",\n            \"title\": {\n              \"en\": \"Mop Intensity\",\n              \"nl\": \"Dweil intensiteit\",\n              \"da\": \"Moppe Intensitet\",\n              \"de\": \"Mop-Intensität\",\n              \"es\": \"Intensidad del trapeado\",\n              \"fr\": \"Intensité de la mop\",\n              \"it\": \"Intensità del mocio\",\n              \"no\": \"Moppintensitet\",\n              \"sv\": \"Moppintensitet\",\n              \"pl\": \"Intensywność mopowania\",\n              \"ru\": \"Интенсивность мытья\",\n              \"ko\": \"걸레질 강도\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"200\",\n                \"label\": {\n                  \"en\": \"Off\",\n                  \"nl\": \"Uit\",\n                  \"da\": \"Fra\",\n                  \"de\": \"Aus\",\n                  \"es\": \"Apagar\",\n                  \"fr\": \"Éteint\",\n                  \"it\": \"Spento\",\n                  \"no\": \"Av\",\n                  \"sv\": \"Av\",\n                  \"pl\": \"Wył.\",\n                  \"ru\": \"Выключено\",\n                  \"ko\": \"끔\"\n                }\n              },\n              {\n                \"id\": \"201\",\n                \"label\": {\n                  \"en\": \"Mild\",\n                  \"nl\": \"Mild\",\n                  \"da\": \"Mild\",\n                  \"de\": \"Sanft\",\n                  \"es\": \"Suave\",\n                  \"fr\": \"Moyen\",\n                  \"it\": \"Lieve\",\n                  \"no\": \"Mild\",\n                  \"sv\": \"Mild\",\n                  \"pl\": \"Łagodny\",\n                  \"ru\": \"Низкая\",\n                  \"ko\": \"약하게\"\n                }\n              },\n              {\n                \"id\": \"202\",\n                \"label\": {\n                  \"en\": \"Moderate\",\n                  \"nl\": \"Gemiddeld\",\n                  \"da\": \"Moderat\",\n                  \"de\": \"Mäßig\",\n                  \"es\": \"Moderado\",\n                  \"fr\": \"Modéré\",\n                  \"it\": \"Moderato\",\n                  \"no\": \"Moderat\",\n                  \"sv\": \"Moderat\",\n                  \"pl\": \"Średni\",\n                  \"ru\": \"Средняя\",\n                  \"ko\": \"중간\"\n                }\n              },\n              {\n                \"id\": \"203\",\n                \"label\": {\n                  \"en\": \"Intense\",\n                  \"nl\": \"Intens\",\n                  \"da\": \"Intens\",\n                  \"de\": \"Intensiv\",\n                  \"es\": \"Intenso\",\n                  \"fr\": \"Intense\",\n                  \"it\": \"Intenso\",\n                  \"no\": \"Intens\",\n                  \"sv\": \"Intensiv\",\n                  \"pl\": \"Intensywny\",\n                  \"ru\": \"Высокая\",\n                  \"ko\": \"강하게\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer stofzuiger\",\n              \"da\": \"Vælg støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccionar aspiradora\",\n              \"fr\": \"Sélectionnez l'aspirateur\",\n              \"it\": \"Seleziona l'aspirapolvere\",\n              \"no\": \"Velg støvsuger\",\n              \"sv\": \"Välj dammsugare\",\n              \"pl\": \"Wybierz odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"청소기 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced&capabilities=vacuum_roborock_mop_intensity\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Pause cleaning\",\n          \"nl\": \"Schoonmaken pauzeren\",\n          \"da\": \"Pause rengøring\",\n          \"de\": \"Reinigung pausieren\",\n          \"es\": \"Pausar la limpieza\",\n          \"fr\": \"Mettre en pause le nettoyage\",\n          \"it\": \"Metti in pausa la pulizia\",\n          \"no\": \"Pause rengjøring\",\n          \"sv\": \"Pausa städningen\",\n          \"pl\": \"Wstrzymaj sprzątanie\",\n          \"ru\": \"Приостановить уборку\",\n          \"ko\": \"청소 일시중지\"\n        },\n        \"args\": [\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer stofzuiger\",\n              \"da\": \"Vælg støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccionar aspiradora\",\n              \"fr\": \"Sélectionner l'aspirateur\",\n              \"it\": \"Selezionare l'aspirapolvere\",\n              \"no\": \"Velg støvsuger\",\n              \"sv\": \"Välj dammsugare\",\n              \"pl\": \"Wybierz odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"진공 청소기 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"vacuumRoborockPause\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set Fanspeed\",\n          \"nl\": \"Stel ventilator in\",\n          \"da\": \"Indstil blæserhastigheden\",\n          \"de\": \"Stelle die Lüftergeschwindigkeit ein\",\n          \"es\": \"Configurar la velocidad del ventilador\",\n          \"fr\": \"Ajuster la vitesse du ventilateur\",\n          \"it\": \"Regola la velocità della ventola\",\n          \"no\": \"Juster viftehastigheten\",\n          \"sv\": \"Justera fläkthastigheten\",\n          \"pl\": \"Ustaw prędkość wentylatora\",\n          \"ru\": \"Настройка скорости вентилятора\",\n          \"ko\": \"팬 속도 조정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set Fanspeed [[fanspeed]]\",\n          \"nl\": \"Stel ventilator in op [[fanspeed]]\",\n          \"da\": \"Indstil blæserhastigheden [[fanspeed]]\",\n          \"de\": \"Stelle die Lüftergeschwindigkeit ein [[fanspeed]]\",\n          \"es\": \"Configurar la velocidad del ventilador [[fanspeed]]\",\n          \"fr\": \"Ajuster la vitesse du ventilateur [[fanspeed]]\",\n          \"it\": \"Regola la velocità della ventola [[fanspeed]]\",\n          \"no\": \"Juster viftehastigheten [[fanspeed]]\",\n          \"sv\": \"Justera fläkthastigheten [[fanspeed]]\",\n          \"pl\": \"Ustaw prędkość wentylatora [[fanspeed]]\",\n          \"ru\": \"Настройка скорости вентилятора [[fanspeed]]\",\n          \"ko\": \"팬 속도 조정 [[fanspeed]]\"\n        },\n        \"args\": [\n          {\n            \"name\": \"fanspeed\",\n            \"title\": {\n              \"en\": \"Fanspeed\",\n              \"nl\": \"Fan snelheid\",\n              \"da\": \"Blæserhastighed\",\n              \"de\": \"Lüftergeschwindigkeit\",\n              \"es\": \"Velocidad del soplador\",\n              \"fr\": \"Vitesse du ventilateur\",\n              \"it\": \"Velocità del ventilatore\",\n              \"no\": \"Blæserhastighet\",\n              \"sv\": \"Fläkt hastighet\",\n              \"pl\": \"Prędkość wentylacji\",\n              \"ru\": \"Скорость вентиляции\",\n              \"ko\": \"팬 속도\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Sweep\",\n                  \"nl\": \"Sweep\",\n                  \"da\": \"Sweep\",\n                  \"de\": \"Sweep\",\n                  \"es\": \"Sweep\",\n                  \"fr\": \"Sweep\",\n                  \"it\": \"Sweep\",\n                  \"no\": \"Sweep\",\n                  \"sv\": \"Sweep\",\n                  \"pl\": \"Sweep\",\n                  \"ru\": \"Sweep\",\n                  \"ko\": \"Sweep\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Silent\",\n                  \"nl\": \"Stil\",\n                  \"da\": \"Lydløs\",\n                  \"de\": \"Geräuschlos\",\n                  \"es\": \"Silencioso\",\n                  \"fr\": \"Silencieux\",\n                  \"it\": \"Silenzioso\",\n                  \"no\": \"Stille\",\n                  \"sv\": \"Tyst\",\n                  \"pl\": \"Cichy\",\n                  \"ru\": \"Тихий\",\n                  \"ko\": \"조용한\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Basic\",\n                  \"nl\": \"Basis\",\n                  \"da\": \"Basis\",\n                  \"de\": \"Basis\",\n                  \"es\": \"Base\",\n                  \"fr\": \"Base\",\n                  \"it\": \"Base\",\n                  \"no\": \"Grunnleggende\",\n                  \"sv\": \"Grundläggande\",\n                  \"pl\": \"Podstawowy\",\n                  \"ru\": \"Основной\",\n                  \"ko\": \"기본\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"title\": {\n                  \"en\": \"Strong\",\n                  \"nl\": \"Sterk\",\n                  \"da\": \"Stærk\",\n                  \"de\": \"Stark\",\n                  \"es\": \"Fuerte\",\n                  \"fr\": \"Fort\",\n                  \"it\": \"Forte\",\n                  \"no\": \"Sterk\",\n                  \"sv\": \"Stark\",\n                  \"pl\": \"Mocny\",\n                  \"ru\": \"Сильный\",\n                  \"ko\": \"강한\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"title\": {\n                  \"en\": \"Full speed\",\n                  \"nl\": \"Volle snelheid\",\n                  \"da\": \"Fuld hastighed\",\n                  \"de\": \"Vollgas\",\n                  \"es\": \"Máxima velocidad\",\n                  \"fr\": \"Vitesse maximale\",\n                  \"it\": \"Velocità massima\",\n                  \"no\": \"Fullt hastighet\",\n                  \"sv\": \"Hastighet\",\n                  \"pl\": \"Maksymalna prędkość\",\n                  \"ru\": \"Максимальная скорость\",\n                  \"ko\": \"최고 속도\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer stofzuiger\",\n              \"da\": \"Vælg støvsuger\",\n              \"de\": \"Wählen Sie den Staubsauger aus\",\n              \"es\": \"Seleccionar aspiradora\",\n              \"fr\": \"Choisissez le modèle d'aspirateur\",\n              \"it\": \"Seleziona il modello di aspirapolvere\",\n              \"no\": \"Velg støvsuger\",\n              \"sv\": \"Välj dammsugare\",\n              \"pl\": \"Wybierz odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"청소기 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_roidmi_vacuum_miot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"vacuumRoidmiFanspeed\"\n      },\n      {\n        \"title\": {\n          \"en\": \"Set Sweep and Mop Mode\",\n          \"nl\": \"Stel Sweep and Mop modus in\",\n          \"da\": \"Indstil Sweep og Mop-tilstand\",\n          \"de\": \"Sweep und Mop Modus einstellen\",\n          \"es\": \"Configurar modo Barrer y Fregar\",\n          \"fr\": \"Définir le mode Balayage et Nettoyage\",\n          \"it\": \"Imposta modalità Spazza e Pulisci\",\n          \"no\": \"Angi Sweep og Mop-modus\",\n          \"sv\": \"Ställ in Sop- och Moppläge\",\n          \"pl\": \"Ustaw tryb Zamiatanie i Mopowanie\",\n          \"ru\": \"Установить режим Подметания и Мытья\",\n          \"ko\": \"청소 및 물걸레 모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set Sweep and Mop Mode to [[mode]]\",\n          \"nl\": \"Stel Sweep and Mop modus in op [[mode]]\",\n          \"da\": \"Indstil Sweep og Mop-tilstand til [[mode]]\",\n          \"de\": \"Sweep und Mop Modus auf [[mode]] einstellen\",\n          \"es\": \"Configurar modo Barrer y Fregar a [[mode]]\",\n          \"fr\": \"Définir le mode Balayage et Nettoyage sur [[mode]]\",\n          \"it\": \"Imposta la modalità Spazza e Pulisci su [[mode]]\",\n          \"no\": \"Angi Sweep og Mop-modus til [[mode]]\",\n          \"sv\": \"Ställ in Sop- och Moppläge till [[mode]]\",\n          \"pl\": \"Ustaw tryb Zamiatanie i Mopowanie na [[mode]]\",\n          \"ru\": \"Установить режим Подметания и Мытья на [[mode]]\",\n          \"ko\": \"청소 및 물걸레 모드를 [[mode]]로 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Sweep and Mop Mode\",\n              \"nl\": \"Sweep and Mop modus\",\n              \"da\": \"Sweep og Mop-tilstand\",\n              \"de\": \"Sweep und Mop Modus\",\n              \"es\": \"Modo Barrer y Fregar\",\n              \"fr\": \"Mode Balayage et Nettoyage\",\n              \"it\": \"Modalità Spazza e Pulisci\",\n              \"no\": \"Sweep og Mop-modus\",\n              \"sv\": \"Sop- och Moppläge\",\n              \"pl\": \"Tryb Zamiatanie i Mopowanie\",\n              \"ru\": \"Режим Подметания и Мытья\",\n              \"ko\": \"청소 및 물걸레 모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Sweep\",\n                  \"nl\": \"Sweep\",\n                  \"da\": \"Sweep\",\n                  \"de\": \"Sweep\",\n                  \"es\": \"Barrer\",\n                  \"fr\": \"Balayer\",\n                  \"it\": \"Spazza\",\n                  \"no\": \"Sweep\",\n                  \"sv\": \"Sweep\",\n                  \"pl\": \"Zamiatanie\",\n                  \"ru\": \"Подметание\",\n                  \"ko\": \"청소\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Mop\",\n                  \"nl\": \"Mop\",\n                  \"da\": \"Mop\",\n                  \"de\": \"Mop\",\n                  \"es\": \"Fregar\",\n                  \"fr\": \"Nettoyer\",\n                  \"it\": \"Pulisci\",\n                  \"no\": \"Mop\",\n                  \"sv\": \"Mop\",\n                  \"pl\": \"Mopowanie\",\n                  \"ru\": \"Мытьё\",\n                  \"ko\": \"물걸레\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Mop & Sweep\",\n                  \"nl\": \"Mop & Sweep\",\n                  \"da\": \"Mop & Sweep\",\n                  \"de\": \"Mop & Sweep\",\n                  \"es\": \"Fregar y Barrer\",\n                  \"fr\": \"Nettoyer et Balayer\",\n                  \"it\": \"Pulisci & Spazza\",\n                  \"no\": \"Mop & Sweep\",\n                  \"sv\": \"Mop & Sweep\",\n                  \"pl\": \"Mopowanie i Zamiatanie\",\n                  \"ru\": \"Мытьё и Подметание\",\n                  \"ko\": \"청소 및 물걸레\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer stofzuiger\",\n              \"da\": \"Vælg støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccionar aspiradora\",\n              \"fr\": \"Sélectionner l'aspirateur\",\n              \"it\": \"Seleziona aspirapolvere\",\n              \"no\": \"Velg støvsuger\",\n              \"sv\": \"Välj dammsugare\",\n              \"pl\": \"Wybierz odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"진공 청소기 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_roidmi_vacuum_miot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"vacuumRoidmiMopMode\"\n      },\n      {\n        \"id\": \"vacuumRoomCleaning\",\n        \"title\": {\n          \"en\": \"Start room cleaning\",\n          \"nl\": \"Start kamer stofzuigen\",\n          \"da\": \"Start rengøring af rum\",\n          \"de\": \"Raumreinigung starten\",\n          \"es\": \"Iniciar limpieza de habitación\",\n          \"fr\": \"Commencer le nettoyage de la pièce\",\n          \"it\": \"Inizia la pulizia della stanza\",\n          \"no\": \"Start romrensingen\",\n          \"sv\": \"Starta rumsstädning\",\n          \"pl\": \"Rozpocznij sprzątanie pokoju\",\n          \"ru\": \"Начать уборку комнаты\",\n          \"ko\": \"방 청소 시작\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Send vacuum cleaner to clean room [[rooms]]\",\n          \"nl\": \"Stuur stofzuiger naar kamer [[rooms]]\",\n          \"da\": \"Send støvsugeren til at rengøre rum [[rooms]]\",\n          \"de\": \"Schicke Staubsauger zur Reinigung von Raum [[rooms]]\",\n          \"es\": \"Enviar aspiradora a limpiar habitación [[rooms]]\",\n          \"fr\": \"Envoyez l'aspirateur nettoyer la pièce [[rooms]]\",\n          \"it\": \"Invia l'aspirapolvere per pulire la stanza [[rooms]]\",\n          \"no\": \"Send støvsugeren for å rengjøre rom [[rooms]]\",\n          \"sv\": \"Skicka dammsugaren för att rengöra rummet [[rooms]]\",\n          \"pl\": \"Wyślij odkurzacz do sprzątania pokoju [[rooms]]\",\n          \"ru\": \"Отправить пылесос для уборки комнаты [[rooms]]\",\n          \"ko\": \"[[rooms]] 방 청소를 위해 진공 청소기를 보내세요\"\n        },\n        \"hint\": {\n          \"en\": \"Enter the room ID's (comma seperated)\",\n          \"nl\": \"Voer kamer ID's in (gescheiden door een komma)\",\n          \"da\": \"Indtast rum-ID'er (kommasepareret)\",\n          \"de\": \"Geben Sie die Raum-IDs ein (kommasepariert)\",\n          \"es\": \"Ingrese las IDs de las habitaciones (separadas por comas)\",\n          \"fr\": \"Entrez les ID des pièces (séparés par des virgules)\",\n          \"it\": \"Inserisci gli ID delle stanze (separati da virgole)\",\n          \"no\": \"Skriv inn rom-ID-er (kommaseparert)\",\n          \"sv\": \"Ange rums-ID:n (kommaseparerade)\",\n          \"pl\": \"Wprowadź identyfikatory pokoi (oddzielone przecinkami)\",\n          \"ru\": \"Введите ID комнат (через запятую)\",\n          \"ko\": \"방 ID를 입력하세요 (쉼표로 구분)\"\n        },\n        \"args\": [\n          {\n            \"name\": \"rooms\",\n            \"title\": {\n              \"en\": \"Room(s)\",\n              \"nl\": \"Kamer(s)\",\n              \"da\": \"Rum\",\n              \"de\": \"Raum/Räume\",\n              \"es\": \"Habitación(es)\",\n              \"fr\": \"Pièce(s)\",\n              \"it\": \"Stanza/e\",\n              \"no\": \"Rom\",\n              \"sv\": \"Rum\",\n              \"pl\": \"Pokój/e\",\n              \"ru\": \"Комната/ы\",\n              \"ko\": \"방\"\n            },\n            \"type\": \"text\",\n            \"placeholder\": {\n              \"en\": \"Room(s)\",\n              \"nl\": \"Kamer(s)\",\n              \"da\": \"Rum\",\n              \"de\": \"Raum/Räume\",\n              \"es\": \"Habitación(es)\",\n              \"fr\": \"Pièce(s)\",\n              \"it\": \"Stanza/e\",\n              \"no\": \"Rom\",\n              \"sv\": \"Rum\",\n              \"pl\": \"Pokój/e\",\n              \"ru\": \"Комната/ы\",\n              \"ko\": \"방\"\n            }\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer stofzuiger\",\n              \"da\": \"Vælg støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccionar aspiradora\",\n              \"fr\": \"Sélectionner l'aspirateur\",\n              \"it\": \"Seleziona l'aspirapolvere\",\n              \"no\": \"Velg støvsuger\",\n              \"sv\": \"Välj dammsugare\",\n              \"pl\": \"Wybierz odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"진공 청소기 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced|vacuum_dreame_vacuum\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"id\": \"vacuumRoomCleaningRepeats\",\n        \"title\": {\n          \"en\": \"Start repeated room cleaning\",\n          \"nl\": \"Start herhaald kamer stofzuigen\",\n          \"da\": \"Start gentagne rum rengøring\",\n          \"de\": \"Beginne wiederholte Raumreinigung\",\n          \"es\": \"Iniciar limpieza repetida de habitaciones\",\n          \"fr\": \"Commencer le nettoyage répété de la pièce\",\n          \"it\": \"Inizia la pulizia ripetuta della stanza\",\n          \"no\": \"Start gjentatt romrengjøring\",\n          \"sv\": \"Start upprepad rumstädning\",\n          \"pl\": \"Rozpocznij powtarzane sprzątanie pokoju\",\n          \"ru\": \"Начать повторяющуюся уборку комнаты\",\n          \"ko\": \"반복 방 청소 시작\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Send vacuum cleaner to clean room [[rooms]] and repeat [[repeats]] times\",\n          \"nl\": \"Stuur stofzuiger naar kamer [[rooms]] en herhaal [[repeats]] keer\",\n          \"da\": \"Send støvsuger til at rengøre rum [[rooms]] og gentag [[repeats]] gange\",\n          \"de\": \"Schicke Staubsauger, um Raum [[rooms]] zu reinigen und [[repeats]] mal zu wiederholen\",\n          \"es\": \"Enviar aspiradora para limpiar la habitación [[rooms]] y repetir [[repeats]] veces\",\n          \"fr\": \"Envoyer l'aspirateur pour nettoyer la pièce [[rooms]] et répéter [[repeats]] fois\",\n          \"it\": \"Invia l'aspirapolvere a pulire la stanza [[rooms]] e ripeti [[repeats]] volte\",\n          \"no\": \"Send støvsuger for å rengjøre rommet [[rooms]] og gjenta [[repeats]] ganger\",\n          \"sv\": \"Skicka dammsugare för att städa rum [[rooms]] och upprepa [[repeats]] gånger\",\n          \"pl\": \"Wyślij odkurzacz, aby posprzątał pokój [[rooms]] i powtórz [[repeats]] razy\",\n          \"ru\": \"Отправить пылесос для уборки комнаты [[rooms]] и повторить [[repeats]] раз\",\n          \"ko\": \"방 [[rooms]]을 청소하도록 청소기를 보내고 [[repeats]]번 반복\"\n        },\n        \"hint\": {\n          \"en\": \"Enter the room ID's (comma seperated)\",\n          \"nl\": \"Voer kamer ID's in (gescheiden door een komma)\",\n          \"da\": \"Indtast rum ID'erne (kommasepareret)\",\n          \"de\": \"Geben Sie die Raum-IDs ein (durch Kommas getrennt)\",\n          \"es\": \"Ingrese los ID de las habitaciones (separados por comas)\",\n          \"fr\": \"Entrez les ID des pièces (séparés par des virgules)\",\n          \"it\": \"Inserisci gli ID delle stanze (separati da virgole)\",\n          \"no\": \"Skriv inn rom-ID-er (kommaseparert)\",\n          \"sv\": \"Ange rums-ID:n (kommaseparerade)\",\n          \"pl\": \"Wprowadź identyfikatory pokoi (oddzielone przecinkami)\",\n          \"ru\": \"Введите идентификаторы комнат (через запятую)\",\n          \"ko\": \"방 ID 입력(쉼표로 구분)\"\n        },\n        \"args\": [\n          {\n            \"name\": \"rooms\",\n            \"title\": {\n              \"en\": \"Room(s)\",\n              \"nl\": \"Kamer(s)\",\n              \"da\": \"Rum\",\n              \"de\": \"Raum/Räume\",\n              \"es\": \"Habitación(es)\",\n              \"fr\": \"Pièce(s)\",\n              \"it\": \"Stanza/e\",\n              \"no\": \"Rom\",\n              \"sv\": \"Rum\",\n              \"pl\": \"Pokój(e)\",\n              \"ru\": \"Комната(ы)\",\n              \"ko\": \"방\"\n            },\n            \"type\": \"text\",\n            \"placeholder\": {\n              \"en\": \"Room(s)\",\n              \"nl\": \"Kamer(s)\",\n              \"da\": \"Rum\",\n              \"de\": \"Raum/Räume\",\n              \"es\": \"Habitación(es)\",\n              \"fr\": \"Pièce(s)\",\n              \"it\": \"Stanza/e\",\n              \"no\": \"Rom\",\n              \"sv\": \"Rum\",\n              \"pl\": \"Pokój(e)\",\n              \"ru\": \"Комната(ы)\",\n              \"ko\": \"방\"\n            }\n          },\n          {\n            \"name\": \"repeats\",\n            \"title\": {\n              \"en\": \"Repeat\",\n              \"nl\": \"Herhaal\",\n              \"da\": \"Gentag\",\n              \"de\": \"Wiederholen\",\n              \"es\": \"Repetir\",\n              \"fr\": \"Répéter\",\n              \"it\": \"Ripeti\",\n              \"no\": \"Gjenta\",\n              \"sv\": \"Upprepa\",\n              \"pl\": \"Powtórz\",\n              \"ru\": \"Повторить\",\n              \"ko\": \"반복\"\n            },\n            \"type\": \"number\",\n            \"min\": 1,\n            \"max\": 3,\n            \"step\": 1\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer stofzuiger\",\n              \"da\": \"Vælg støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccione aspiradora\",\n              \"fr\": \"Sélectionnez l'aspirateur\",\n              \"it\": \"Seleziona l'aspirapolvere\",\n              \"no\": \"Velg støvsuger\",\n              \"sv\": \"Välj dammsugare\",\n              \"pl\": \"Wybierz odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"청소기 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_mi_rockrobo_vacuum_advanced\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ]\n      },\n      {\n        \"title\": {\n          \"en\": \"Set Sweep and Mop Mode\",\n          \"nl\": \"Stel Sweep and Mop modus in\",\n          \"da\": \"Indstil Sweep og Mop-tilstand\",\n          \"de\": \"Sweep- und Mop-Modus einstellen\",\n          \"es\": \"Establecer modo Sweep y Mop\",\n          \"fr\": \"Définir le mode Sweep et Mop\",\n          \"it\": \"Imposta modalità Sweep e Mop\",\n          \"no\": \"Sett Sweep og Mop-modus\",\n          \"sv\": \"Ställ in Sweep och Mop-läge\",\n          \"pl\": \"Ustaw tryb Sweep i Mop\",\n          \"ru\": \"Установите режим Sweep и Mop\",\n          \"ko\": \"쓸기 및 물걸레 모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set Sweep and Mop Mode to [[mode]]\",\n          \"nl\": \"Stel Sweep and Mop modus in op [[mode]]\",\n          \"da\": \"Indstil Sweep og Mop-tilstand til [[mode]]\",\n          \"de\": \"Sweep- und Mop-Modus auf [[mode]] einstellen\",\n          \"es\": \"Establecer modo Sweep y Mop a [[mode]]\",\n          \"fr\": \"Définir le mode Sweep et Mop sur [[mode]]\",\n          \"it\": \"Imposta modalità Sweep e Mop su [[mode]]\",\n          \"no\": \"Sett Sweep og Mop-modus til [[mode]]\",\n          \"sv\": \"Ställ in Sweep och Mop-läge till [[mode]]\",\n          \"pl\": \"Ustaw tryb Sweep i Mop na [[mode]]\",\n          \"ru\": \"Установите режим Sweep и Mop на [[mode]]\",\n          \"ko\": \"[[mode]]로 쓸기 및 물걸레 모드 설정\"\n        },\n        \"args\": [\n          {\n            \"name\": \"mode\",\n            \"title\": {\n              \"en\": \"Sweep and Mop Mode\",\n              \"nl\": \"Sweep and Mop modus\",\n              \"da\": \"Sweep og Mop-tilstand\",\n              \"de\": \"Sweep- und Mop-Modus\",\n              \"es\": \"Modo Sweep y Mop\",\n              \"fr\": \"Mode Sweep et Mop\",\n              \"it\": \"Modalità Sweep e Mop\",\n              \"no\": \"Sweep og Mop-modus\",\n              \"sv\": \"Sweep och Mop-läge\",\n              \"pl\": \"Tryb Sweep i Mop\",\n              \"ru\": \"Режим Sweep и Mop\",\n              \"ko\": \"쓸기 및 물걸레 모드\"\n            },\n            \"type\": \"dropdown\",\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"title\": {\n                  \"en\": \"Sweep\",\n                  \"nl\": \"Sweep\",\n                  \"da\": \"Sweep\",\n                  \"de\": \"Sweep\",\n                  \"es\": \"Sweep\",\n                  \"fr\": \"Sweep\",\n                  \"it\": \"Sweep\",\n                  \"no\": \"Sweep\",\n                  \"sv\": \"Sweep\",\n                  \"pl\": \"Sweep\",\n                  \"ru\": \"Sweep\",\n                  \"ko\": \"쓸기\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"title\": {\n                  \"en\": \"Sweep & Mop\",\n                  \"nl\": \"Sweep & Mop\",\n                  \"da\": \"Sweep & Mop\",\n                  \"de\": \"Sweep & Mop\",\n                  \"es\": \"Sweep & Mop\",\n                  \"fr\": \"Sweep & Mop\",\n                  \"it\": \"Sweep & Mop\",\n                  \"no\": \"Sweep & Mop\",\n                  \"sv\": \"Sweep & Mop\",\n                  \"pl\": \"Sweep & Mop\",\n                  \"ru\": \"Sweep & Mop\",\n                  \"ko\": \"쓸기 & 물걸레\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"title\": {\n                  \"en\": \"Mop\",\n                  \"nl\": \"Mop\",\n                  \"da\": \"Mop\",\n                  \"de\": \"Mop\",\n                  \"es\": \"Mop\",\n                  \"fr\": \"Mop\",\n                  \"it\": \"Mop\",\n                  \"no\": \"Mop\",\n                  \"sv\": \"Mop\",\n                  \"pl\": \"Mop\",\n                  \"ru\": \"Mop\",\n                  \"ko\": \"물걸레\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"device\",\n            \"type\": \"device\",\n            \"placeholder\": {\n              \"en\": \"Select Vacuum\",\n              \"nl\": \"Selecteer stofzuiger\",\n              \"da\": \"Vælg støvsuger\",\n              \"de\": \"Staubsauger auswählen\",\n              \"es\": \"Seleccionar aspiradora\",\n              \"fr\": \"Sélectionner un aspirateur\",\n              \"it\": \"Seleziona l'aspirapolvere\",\n              \"no\": \"Velg støvsuger\",\n              \"sv\": \"Välj dammsugare\",\n              \"pl\": \"Wybierz odkurzacz\",\n              \"ru\": \"Выберите пылесос\",\n              \"ko\": \"진공청소기 선택\"\n            },\n            \"filter\": \"driver_id=vacuum_xiaomi_vacuum_miot\"\n          }\n        ],\n        \"platforms\": [\n          \"local\"\n        ],\n        \"id\": \"vacuumXiaomiMopMode\"\n      },\n      {\n        \"id\": \"advanced_room_cleaning\",\n        \"title\": {\n          \"en\": \"advanced cleaning\",\n          \"it\": \"Pulizia avanzata\",\n          \"nl\": \"Geavanceerde reiniging\",\n          \"da\": \"Avanceret rengøring\",\n          \"de\": \"Erweiterte Reinigung\",\n          \"es\": \"Limpieza avanzada\",\n          \"fr\": \"Nettoyage avancé\",\n          \"no\": \"Avansert rengjøring\",\n          \"sv\": \"Avancerad rengöring\",\n          \"pl\": \"Zaawansowane czyszczenie\",\n          \"ru\": \"Расширенная очистка\",\n          \"ko\": \"고급 청소\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Start [[mode]] with accuracy [[accuracy]]. Sweep [[mode_sweep]] and mop [[mode_mop]] on room [[room]] (carpet-avoid: [[carpet_avoidance]])\",\n          \"it\": \"Attiva [[mode]] con accuratezza percorso [[accuracy]]. Aspirazione [[mode_sweep]] e lavaggio [[mode_mop]] in stanza [[room]] (evita tappeti: [[carpet_avoidance]])\",\n          \"nl\": \"Start [[mode]] met nauwkeurigheid [[accuracy]]. Stofzuigen [[mode_sweep]] en dweilen [[mode_mop]] in kamer [[room]] (tapijt vermijden: [[carpet_avoidance]])\",\n          \"da\": \"Start [[mode]] med nøjagtighed [[accuracy]]. Støvsug [[mode_sweep]] og moppe [[mode_mop]] i rum [[room]] (undgå tæpper: [[carpet_avoidance]])\",\n          \"de\": \"Starte [[mode]] mit Genauigkeit [[accuracy]]. Saugen [[mode_sweep]] und Wischen [[mode_mop]] im Raum [[room]] (Teppich-Vermeidung: [[carpet_avoidance]])\",\n          \"es\": \"Iniciar [[mode]] con precisión [[accuracy]]. Barrer [[mode_sweep]] y fregar [[mode_mop]] en la habitación [[room]] (evitar alfombras: [[carpet_avoidance]])\",\n          \"fr\": \"Démarrer [[mode]] avec précision [[accuracy]]. Balayer [[mode_sweep]] et frotter [[mode_mop]] dans la pièce [[room]] (éviter tapis: [[carpet_avoidance]])\",\n          \"no\": \"Start [[mode]] med nøyaktighet [[accuracy]]. Støvsuge [[mode_sweep]] og moppe [[mode_mop]] i rom [[room]] (unngå tepper: [[carpet_avoidance]])\",\n          \"sv\": \"Starta [[mode]] med noggrannhet [[accuracy]]. Dammsuga [[mode_sweep]] och moppa [[mode_mop]] i rum [[room]] (undvik mattor: [[carpet_avoidance]])\",\n          \"pl\": \"Rozpocznij [[mode]] z dokładnością [[accuracy]]. Odkurzanie [[mode_sweep]] i mycie [[mode_mop]] w pokoju [[room]] (unikaj dywanów: [[carpet_avoidance]])\",\n          \"ru\": \"Запустить [[mode]] с точностью [[accuracy]]. Пылесосить [[mode_sweep]] и мыть [[mode_mop]] в комнате [[room]] (избегать ковров: [[carpet_avoidance]])\",\n          \"ko\": \"[[mode]]를 [[accuracy]] 정확도로 시작합니다. [[mode_sweep]] 청소 및 [[mode_mop]] 방 [[room]] (카펫 회피: [[carpet_avoidance]])\"\n        },\n        \"args\": [\n          {\n            \"type\": \"device\",\n            \"name\": \"device\",\n            \"filter\": \"driver_id=vacuum_xiaomi_vacuum_max\"\n          },\n          {\n            \"name\": \"mode\",\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Select mode\",\n              \"it\": \"Seleziona modalità\",\n              \"nl\": \"Selecteer modus\",\n              \"da\": \"Vælg tilstand\",\n              \"de\": \"Modus auswählen\",\n              \"es\": \"Seleccionar modo\",\n              \"fr\": \"Sélectionner le mode\",\n              \"no\": \"Velg modus\",\n              \"sv\": \"Välj läge\",\n              \"pl\": \"Wybierz tryb\",\n              \"ru\": \"Выберите режим\",\n              \"ko\": \"모드 선택\"\n            },\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Sweep\",\n                  \"it\": \"Aspirazione\",\n                  \"nl\": \"Stofzuigen\",\n                  \"da\": \"Støvsugning\",\n                  \"de\": \"Saugen\",\n                  \"es\": \"Aspirar\",\n                  \"fr\": \"Aspirer\",\n                  \"no\": \"Støvsuging\",\n                  \"sv\": \"Dammsugning\",\n                  \"pl\": \"Odkurzanie\",\n                  \"ru\": \"Пылесосить\",\n                  \"ko\": \"청소하기\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Mop\",\n                  \"it\": \"Lavaggio\",\n                  \"nl\": \"Dweilen\",\n                  \"da\": \"Gulvvask\",\n                  \"de\": \"Wischen\",\n                  \"es\": \"Fregar\",\n                  \"fr\": \"Laver\",\n                  \"no\": \"Vask\",\n                  \"sv\": \"Moppning\",\n                  \"pl\": \"Mycie\",\n                  \"ru\": \"Мытье\",\n                  \"ko\": \"청소하기\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"Sweep and mop\",\n                  \"it\": \"Aspirazione e lavaggio\",\n                  \"nl\": \"Stofzuigen en dweilen\",\n                  \"da\": \"Støvsugning og gulvvask\",\n                  \"de\": \"Saugen und Wischen\",\n                  \"es\": \"Aspirar y fregar\",\n                  \"fr\": \"Aspirer et laver\",\n                  \"no\": \"Støvsuging og vask\",\n                  \"sv\": \"Dammsugning och moppning\",\n                  \"pl\": \"Odkurzanie i mycie\",\n                  \"ru\": \"Пылесосить и мыть\",\n                  \"ko\": \"청소 및 세척\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"label\": {\n                  \"en\": \"Sweep and after mop\",\n                  \"it\": \"Aspirazione e successivamente lavaggio\",\n                  \"nl\": \"Stofzuigen en daarna dweilen\",\n                  \"da\": \"Støvsugning og derefter gulvvask\",\n                  \"de\": \"Saugen und anschließend wischen\",\n                  \"es\": \"Aspirar y luego fregar\",\n                  \"fr\": \"Aspirer puis laver\",\n                  \"no\": \"Støvsuging og deretter vask\",\n                  \"sv\": \"Dammsugning och sedan moppning\",\n                  \"pl\": \"Odkurzanie, a następnie mycie\",\n                  \"ru\": \"Сначала пылесосить, а затем мыть\",\n                  \"ko\": \"먼저 청소한 후 세척\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"accuracy\",\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Select clean accuracy\",\n              \"it\": \"Seleziona accuratezza percorso pulizia\",\n              \"nl\": \"Selecteer reinigingsnauwkeurigheid\",\n              \"da\": \"Vælg rengøringsnøjagtighed\",\n              \"de\": \"Reinigungsgenauigkeit auswählen\",\n              \"es\": \"Seleccionar precisión de limpieza\",\n              \"fr\": \"Sélectionner la précision de nettoyage\",\n              \"no\": \"Velg rengjøringsnøyaktighet\",\n              \"sv\": \"Välj rengöringsnoggrannhet\",\n              \"pl\": \"Wybierz dokładność czyszczenia\",\n              \"ru\": \"Выберите точность очистки\",\n              \"ko\": \"청소 정확도 선택\"\n            },\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Quick\",\n                  \"it\": \"Veloce\",\n                  \"nl\": \"Snel\",\n                  \"da\": \"Hurtig\",\n                  \"de\": \"Schnell\",\n                  \"es\": \"Rápido\",\n                  \"fr\": \"Rapide\",\n                  \"no\": \"Rask\",\n                  \"sv\": \"Snabb\",\n                  \"pl\": \"Szybki\",\n                  \"ru\": \"Быстрый\",\n                  \"ko\": \"빠름\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Standard\",\n                  \"it\": \"Standard\",\n                  \"nl\": \"Standaard\",\n                  \"da\": \"Standard\",\n                  \"de\": \"Standard\",\n                  \"es\": \"Estándar\",\n                  \"fr\": \"Standard\",\n                  \"no\": \"Standard\",\n                  \"sv\": \"Standard\",\n                  \"pl\": \"Standardowy\",\n                  \"ru\": \"Стандартный\",\n                  \"ko\": \"표준\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"Deep\",\n                  \"it\": \"Profondo\",\n                  \"nl\": \"Diep\",\n                  \"da\": \"Dyb\",\n                  \"de\": \"Tief\",\n                  \"es\": \"Profundo\",\n                  \"fr\": \"Profond\",\n                  \"no\": \"Dyp\",\n                  \"sv\": \"Djup\",\n                  \"pl\": \"Głęboki\",\n                  \"ru\": \"Глубокий\",\n                  \"ko\": \"딥\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"mode_sweep\",\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Select sweep power\",\n              \"it\": \"Seleziona potenza aspirazione\",\n              \"nl\": \"Selecteer stofzuigkracht\",\n              \"da\": \"Vælg støvsugerkraft\",\n              \"de\": \"Saugleistung auswählen\",\n              \"es\": \"Seleccionar potencia de succión\",\n              \"fr\": \"Sélectionner la puissance d'aspiration\",\n              \"no\": \"Velg sugekraft\",\n              \"sv\": \"Välj sugkraft\",\n              \"pl\": \"Wybierz moc ssania\",\n              \"ru\": \"Выберите мощность всасывания\",\n              \"ko\": \"흡입력 선택\"\n            },\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Silent\",\n                  \"it\": \"Silenzioso\",\n                  \"nl\": \"Stil\",\n                  \"da\": \"Stille\",\n                  \"de\": \"Leise\",\n                  \"es\": \"Silencioso\",\n                  \"fr\": \"Silencieux\",\n                  \"no\": \"Stille\",\n                  \"sv\": \"Tyst\",\n                  \"pl\": \"Cichy\",\n                  \"ru\": \"Тихий\",\n                  \"ko\": \"조용한\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Basic\",\n                  \"it\": \"Normale\",\n                  \"nl\": \"Basis\",\n                  \"da\": \"Basis\",\n                  \"de\": \"Basis\",\n                  \"es\": \"Básico\",\n                  \"fr\": \"Basique\",\n                  \"no\": \"Grunnleggende\",\n                  \"sv\": \"Grundläggande\",\n                  \"pl\": \"Podstawowy\",\n                  \"ru\": \"Базовый\",\n                  \"ko\": \"기본\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"Strong\",\n                  \"it\": \"Forte\",\n                  \"nl\": \"Sterk\",\n                  \"da\": \"Stærk\",\n                  \"de\": \"Stark\",\n                  \"es\": \"Fuerte\",\n                  \"fr\": \"Forte\",\n                  \"no\": \"Sterk\",\n                  \"sv\": \"Stark\",\n                  \"pl\": \"Mocny\",\n                  \"ru\": \"Сильный\",\n                  \"ko\": \"강한\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"label\": {\n                  \"en\": \"Full Speed\",\n                  \"it\": \"Massima potenza\",\n                  \"nl\": \"Volledige snelheid\",\n                  \"da\": \"Fuld hastighed\",\n                  \"de\": \"Vollgas\",\n                  \"es\": \"A toda velocidad\",\n                  \"fr\": \"Vitesse maximale\",\n                  \"no\": \"Full hastighet\",\n                  \"sv\": \"Full hastighet\",\n                  \"pl\": \"Pełna prędkość\",\n                  \"ru\": \"Максимальная скорость\",\n                  \"ko\": \"최고속\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"mode_mop\",\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Mop mode\",\n              \"it\": \"Modalità lavaggio\",\n              \"nl\": \"Dweilmodus\",\n              \"da\": \"Moppefunktion\",\n              \"de\": \"Wischmodus\",\n              \"es\": \"Modo fregona\",\n              \"fr\": \"Mode serpillère\",\n              \"no\": \"Moppemodus\",\n              \"sv\": \"Moppläge\",\n              \"pl\": \"Tryb mopa\",\n              \"ru\": \"Режим швабры\",\n              \"ko\": \"대걸레 모드\"\n            },\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"label\": {\n                  \"en\": \"Off\",\n                  \"it\": \"Nessuno\",\n                  \"nl\": \"Uit\",\n                  \"da\": \"Fra\",\n                  \"de\": \"Aus\",\n                  \"es\": \"Apagar\",\n                  \"fr\": \"Éteindre\",\n                  \"no\": \"Av\",\n                  \"sv\": \"Av\",\n                  \"pl\": \"Wyłączony\",\n                  \"ru\": \"Выключить\",\n                  \"ko\": \"끔\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Level 1\",\n                  \"it\": \"Livello 1\",\n                  \"nl\": \"Niveau 1\",\n                  \"da\": \"Niveau 1\",\n                  \"de\": \"Stufe 1\",\n                  \"es\": \"Nivel 1\",\n                  \"fr\": \"Niveau 1\",\n                  \"no\": \"Nivå 1\",\n                  \"sv\": \"Nivå 1\",\n                  \"pl\": \"Poziom 1\",\n                  \"ru\": \"Уровень 1\",\n                  \"ko\": \"레벨 1\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Level 2\",\n                  \"it\": \"Livello 2\",\n                  \"nl\": \"Niveau 2\",\n                  \"da\": \"Niveau 2\",\n                  \"de\": \"Stufe 2\",\n                  \"es\": \"Nivel 2\",\n                  \"fr\": \"Niveau 2\",\n                  \"no\": \"Nivå 2\",\n                  \"sv\": \"Nivå 2\",\n                  \"pl\": \"Poziom 2\",\n                  \"ru\": \"Уровень 2\",\n                  \"ko\": \"레벨 2\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"Level 3\",\n                  \"it\": \"Livello 3\",\n                  \"nl\": \"Niveau 3\",\n                  \"da\": \"Niveau 3\",\n                  \"de\": \"Stufe 3\",\n                  \"es\": \"Nivel 3\",\n                  \"fr\": \"Niveau 3\",\n                  \"no\": \"Nivå 3\",\n                  \"sv\": \"Nivå 3\",\n                  \"pl\": \"Poziom 3\",\n                  \"ru\": \"Уровень 3\",\n                  \"ko\": \"레벨 3\"\n                }\n              }\n            ]\n          },\n          {\n            \"name\": \"carpet_avoidance\",\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Carpet avoidance\",\n              \"it\": \"Evitamento tappeti\",\n              \"nl\": \"Tapijt vermijden\",\n              \"da\": \"Undgå tæpper\",\n              \"de\": \"Teppichvermeidung\",\n              \"es\": \"Evitar alfombras\",\n              \"fr\": \"Éviter les tapis\",\n              \"no\": \"Unngå tepper\",\n              \"sv\": \"Undvik mattor\",\n              \"pl\": \"Unikaj dywanów\",\n              \"ru\": \"Избегать ковров\",\n              \"ko\": \"카펫 회피\"\n            },\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"label\": {\n                  \"en\": \"Self Adaptation\",\n                  \"it\": \"Auto adattamento\",\n                  \"nl\": \"Zelfaanpassing\",\n                  \"da\": \"Selvtilpasning\",\n                  \"de\": \"Selbstanpassung\",\n                  \"es\": \"Auto adaptación\",\n                  \"fr\": \"Auto-adaptation\",\n                  \"no\": \"Selvtilpasning\",\n                  \"sv\": \"Självanpassning\",\n                  \"pl\": \"Samodopasowanie\",\n                  \"ru\": \"Самоадаптация\",\n                  \"ko\": \"자동 적응\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Avoid\",\n                  \"it\": \"Evita\",\n                  \"nl\": \"Vermijden\",\n                  \"da\": \"Undgå\",\n                  \"de\": \"Vermeiden\",\n                  \"es\": \"Evitar\",\n                  \"fr\": \"Éviter\",\n                  \"no\": \"Unngå\",\n                  \"sv\": \"Undvik\",\n                  \"pl\": \"Unikaj\",\n                  \"ru\": \"Избегать\",\n                  \"ko\": \"회피\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Ignore\",\n                  \"it\": \"Ignora\",\n                  \"nl\": \"Negeren\",\n                  \"da\": \"Ignorer\",\n                  \"de\": \"Ignorieren\",\n                  \"es\": \"Ignorar\",\n                  \"fr\": \"Ignorer\",\n                  \"no\": \"Ignorer\",\n                  \"sv\": \"Ignorera\",\n                  \"pl\": \"Ignoruj\",\n                  \"ru\": \"Игнорировать\",\n                  \"ko\": \"무시\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"Span\",\n                  \"it\": \"Span\",\n                  \"nl\": \"Span\",\n                  \"da\": \"Span\",\n                  \"de\": \"Span\",\n                  \"es\": \"Span\",\n                  \"fr\": \"Span\",\n                  \"no\": \"Span\",\n                  \"sv\": \"Span\",\n                  \"pl\": \"Span\",\n                  \"ru\": \"Span\",\n                  \"ko\": \"Span\"\n                }\n              }\n            ]\n          },\n          {\n            \"type\": \"text\",\n            \"name\": \"room\",\n            \"title\": {\n              \"en\": \"Select room separated by commas ('all' for all rooms)\",\n              \"it\": \"Seleziona stanze separate da virgole ('all' per tutte le stanze)\",\n              \"nl\": \"Selecteer kamer gescheiden door komma's ('all' voor alle kamers)\",\n              \"da\": \"Vælg rum adskilt af kommaer ('all' for alle rum)\",\n              \"de\": \"Wählen Sie Räume, die durch Kommas getrennt sind ('all' für alle Räume)\",\n              \"es\": \"Seleccionar habitación separada por comas ('all' para todas las habitaciones)\",\n              \"fr\": \"Sélectionner la pièce séparée par des virgules ('all' pour toutes les pièces)\",\n              \"no\": \"Velg rom atskilt med kommaer ('all' for alle rom)\",\n              \"sv\": \"Välj rum åtskilt med kommatecken ('all' för alla rum)\",\n              \"pl\": \"Wybierz pokój oddzielony przecinkami ('all' dla wszystkich pokoi)\",\n              \"ru\": \"Выберите комнату, разделенную запятыми ('all' для всех комнат)\",\n              \"ko\": \"방을 쉼표로 구분하여 선택합니다('all'은 모든 방에 해당)\"\n            },\n            \"placeholder\": {\n              \"en\": \"all\"\n            }\n          }\n        ]\n      },\n      {\n        \"id\": \"set_sweep_mop_type\",\n        \"title\": {\n          \"en\": \"Set vacuum mode\",\n          \"it\": \"Imposta modalità aspirazione\",\n          \"nl\": \"Stel zuigmodus in\",\n          \"da\": \"Indstil støvsugningsmodus\",\n          \"de\": \"Saugmodus einstellen\",\n          \"es\": \"Establecer modo aspiración\",\n          \"fr\": \"Définir le mode aspirateur\",\n          \"no\": \"Angi støvsugmodus\",\n          \"sv\": \"Ställ in dammsägarläge\",\n          \"pl\": \"Ustaw tryb odkurzania\",\n          \"ru\": \"Установить режим уборки\",\n          \"ko\": \"청소 모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set vacuum mode to [[mode]]\",\n          \"it\": \"Imposta modalità aspirazione su [[mode]]\",\n          \"nl\": \"Stel zuigmodus in op [[mode]]\",\n          \"da\": \"Indstil støvsugningsmodus til [[mode]]\",\n          \"de\": \"Saugmodus einstellen auf [[mode]]\",\n          \"es\": \"Establecer modo aspiración en [[mode]]\",\n          \"fr\": \"Définir le mode aspirateur sur [[mode]]\",\n          \"no\": \"Angi støvsugmodus til [[mode]]\",\n          \"sv\": \"Ställ in dammsägarläge på [[mode]]\",\n          \"pl\": \"Ustaw tryb odkurzania na [[mode]]\",\n          \"ru\": \"Установить режим уборки на [[mode]]\",\n          \"ko\": \"청소 모드를 [[mode]]로 설정\"\n        },\n        \"args\": [\n          {\n            \"type\": \"device\",\n            \"name\": \"device\",\n            \"filter\": \"driver_id=vacuum_xiaomi_vacuum_max\"\n          },\n          {\n            \"name\": \"mode\",\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Vacuum mode\",\n              \"it\": \"Modalità aspirazione\",\n              \"nl\": \"Zuigmodus\",\n              \"da\": \"Støvsugningsmodus\",\n              \"de\": \"Saugmodus\",\n              \"es\": \"Modo aspirar\",\n              \"fr\": \"Mode aspiration\",\n              \"no\": \"Støvsugmodus\",\n              \"sv\": \"Dammsägarläge\",\n              \"pl\": \"Tryb odkurzania\",\n              \"ru\": \"Режим уборки\",\n              \"ko\": \"청소 모드\"\n            },\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Sweep only\",\n                  \"it\": \"Solo aspirazione\",\n                  \"nl\": \"Alleen stofzuigen\",\n                  \"da\": \"Kun støvsugning\",\n                  \"de\": \"Nur Saugen\",\n                  \"es\": \"Solo aspirar\",\n                  \"fr\": \"Aspirer seulement\",\n                  \"no\": \"Kun støvsuging\",\n                  \"sv\": \"Endast dammsugning\",\n                  \"pl\": \"Tylko odkurzanie\",\n                  \"ru\": \"Только уборка\",\n                  \"ko\": \"청소만\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Mop only\",\n                  \"it\": \"Solo lavaggio\",\n                  \"nl\": \"Alleen dweilen\",\n                  \"da\": \"Kun gulvvask\",\n                  \"de\": \"Nur Wischen\",\n                  \"es\": \"Solo fregar\",\n                  \"fr\": \"Lavette seulement\",\n                  \"no\": \"Kun vask\",\n                  \"sv\": \"Endast moppning\",\n                  \"pl\": \"Tylko mopowanie\",\n                  \"ru\": \"Только мытье\",\n                  \"ko\": \"물걸레만\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"Sweep & mop\",\n                  \"it\": \"Aspirazione e lavaggio\",\n                  \"nl\": \"Stofzuigen en dweilen\",\n                  \"da\": \"Støvsugning og gulvvask\",\n                  \"de\": \"Saugen und Wischen\",\n                  \"es\": \"Aspirar y fregar\",\n                  \"fr\": \"Aspirer et laver\",\n                  \"no\": \"Støvsuging og vask\",\n                  \"sv\": \"Dammsugning och moppning\",\n                  \"pl\": \"Odkurzanie i mopowanie\",\n                  \"ru\": \"Уборка и мытье\",\n                  \"ko\": \"청소 및 물걸레\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"label\": {\n                  \"en\": \"Sweep then mop\",\n                  \"it\": \"Prima aspirare poi lavare\",\n                  \"nl\": \"Eerst stofzuigen daarna dweilen\",\n                  \"da\": \"Først støvsug, derefter gulvvask\",\n                  \"de\": \"Zuerst saugen, dann wischen\",\n                  \"es\": \"Primero aspirar, luego fregar\",\n                  \"fr\": \"D'abord aspirer, puis laver\",\n                  \"no\": \"Først støvsug, deretter vask\",\n                  \"sv\": \"Först dammsugning, sedan moppning\",\n                  \"pl\": \"Najpierw odkurzanie, potem mopowanie\",\n                  \"ru\": \"Сначала уборка, затем мытье\",\n                  \"ko\": \"먼저 청소 후 물걸레\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      {\n        \"id\": \"set_cleaning_mode\",\n        \"title\": {\n          \"en\": \"Set cleaning power\",\n          \"it\": \"Imposta potenza di pulizia\",\n          \"nl\": \"Stel zuigvermogen in\",\n          \"da\": \"Indstil rengøringseffekt\",\n          \"de\": \"Reinigungsstärke einstellen\",\n          \"es\": \"Establecer potencia de limpieza\",\n          \"fr\": \"Définir la puissance de nettoyage\",\n          \"no\": \"Angi rengjøringsstyrke\",\n          \"sv\": \"Ställ in rengöringsstyrka\",\n          \"pl\": \"Ustaw moc odkurzania\",\n          \"ru\": \"Установить мощность уборки\",\n          \"ko\": \"청소 세기 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set cleaning power to [[power]]\",\n          \"it\": \"Imposta potenza di pulizia su [[power]]\",\n          \"nl\": \"Stel zuigvermogen in op [[power]]\",\n          \"da\": \"Indstil rengøringseffekt til [[power]]\",\n          \"de\": \"Reinigungsstärke einstellen auf [[power]]\",\n          \"es\": \"Establecer potencia de limpieza en [[power]]\",\n          \"fr\": \"Définir la puissance de nettoyage sur [[power]]\",\n          \"no\": \"Angi rengjøringsstyrke til [[power]]\",\n          \"sv\": \"Ställ in rengöringsstyrka på [[power]]\",\n          \"pl\": \"Ustaw moc odkurzania na [[power]]\",\n          \"ru\": \"Установить мощность уборки на [[power]]\",\n          \"ko\": \"청소 세기를 [[power]]로 설정\"\n        },\n        \"args\": [\n          {\n            \"type\": \"device\",\n            \"name\": \"device\",\n            \"filter\": \"driver_id=vacuum_xiaomi_vacuum_max\"\n          },\n          {\n            \"name\": \"power\",\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Cleaning power\",\n              \"it\": \"Potenza di pulizia\",\n              \"nl\": \"Zuigkracht\",\n              \"da\": \"Rengøringseffekt\",\n              \"de\": \"Reinigungsstärke\",\n              \"es\": \"Potencia de limpieza\",\n              \"fr\": \"Puissance de nettoyage\",\n              \"no\": \"Rengjøringsstyrke\",\n              \"sv\": \"Rengöringsstyrka\",\n              \"pl\": \"Moc odkurzania\",\n              \"ru\": \"Мощность уборки\",\n              \"ko\": \"청소 세기\"\n            },\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Silent\",\n                  \"it\": \"Silenzioso\",\n                  \"nl\": \"Stil\",\n                  \"da\": \"Stille\",\n                  \"de\": \"Leise\",\n                  \"es\": \"Silencioso\",\n                  \"fr\": \"Silencieux\",\n                  \"no\": \"Stille\",\n                  \"sv\": \"Tyst\",\n                  \"pl\": \"Cichy\",\n                  \"ru\": \"Тихо\",\n                  \"ko\": \"조용함\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Basic\",\n                  \"it\": \"Normale\",\n                  \"nl\": \"Basis\",\n                  \"da\": \"Basis\",\n                  \"de\": \"Basis\",\n                  \"es\": \"Básico\",\n                  \"fr\": \"Basique\",\n                  \"no\": \"Grunnleggende\",\n                  \"sv\": \"Grundläggande\",\n                  \"pl\": \"Podstawowy\",\n                  \"ru\": \"Базовый\",\n                  \"ko\": \"기본\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"Strong\",\n                  \"it\": \"Forte\",\n                  \"nl\": \"Sterk\",\n                  \"da\": \"Stærk\",\n                  \"de\": \"Stark\",\n                  \"es\": \"Fuerte\",\n                  \"fr\": \"Forte\",\n                  \"no\": \"Sterk\",\n                  \"sv\": \"Stark\",\n                  \"pl\": \"Mocny\",\n                  \"ru\": \"Сильный\",\n                  \"ko\": \"강함\"\n                }\n              },\n              {\n                \"id\": \"4\",\n                \"label\": {\n                  \"en\": \"Full Speed\",\n                  \"it\": \"Massima potenza\",\n                  \"nl\": \"Volledige snelheid\",\n                  \"da\": \"Fuld hastighed\",\n                  \"de\": \"Vollgas\",\n                  \"es\": \"A toda velocidad\",\n                  \"fr\": \"Vitesse maximale\",\n                  \"no\": \"Full hastighet\",\n                  \"sv\": \"Full hastighet\",\n                  \"pl\": \"Pełna prędkość\",\n                  \"ru\": \"Максимальная скорость\",\n                  \"ko\": \"최고속\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      {\n        \"id\": \"set_water_level\",\n        \"title\": {\n          \"en\": \"Set water output level\",\n          \"it\": \"Imposta livello acqua\",\n          \"nl\": \"Stel waterniveau in\",\n          \"da\": \"Indstil vandniveau\",\n          \"de\": \"Wasserstand einstellen\",\n          \"es\": \"Establecer nivel de agua\",\n          \"fr\": \"Définir le niveau d'eau\",\n          \"no\": \"Angi vannivå\",\n          \"sv\": \"Ställ in vattennivå\",\n          \"pl\": \"Ustaw poziom wody\",\n          \"ru\": \"Установить уровень воды\",\n          \"ko\": \"물 세기 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set water level to [[level]]\",\n          \"it\": \"Imposta livello acqua su [[level]]\",\n          \"nl\": \"Stel waterniveau in op [[level]]\",\n          \"da\": \"Indstil vandniveau til [[level]]\",\n          \"de\": \"Wasserstand einstellen auf [[level]]\",\n          \"es\": \"Establecer nivel de agua en [[level]]\",\n          \"fr\": \"Définir le niveau d'eau sur [[level]]\",\n          \"no\": \"Angi vannivå til [[level]]\",\n          \"sv\": \"Ställ in vattennivå på [[level]]\",\n          \"pl\": \"Ustaw poziom wody na [[level]]\",\n          \"ru\": \"Установить уровень воды на [[level]]\",\n          \"ko\": \"물 세기를 [[level]]로 설정\"\n        },\n        \"args\": [\n          {\n            \"type\": \"device\",\n            \"name\": \"device\",\n            \"filter\": \"driver_id=vacuum_xiaomi_vacuum_max\"\n          },\n          {\n            \"name\": \"level\",\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Water level\",\n              \"it\": \"Livello acqua\",\n              \"nl\": \"Waterniveau\",\n              \"da\": \"Vandniveau\",\n              \"de\": \"Wasserstand\",\n              \"es\": \"Nivel de agua\",\n              \"fr\": \"Niveau d'eau\",\n              \"no\": \"Vannivå\",\n              \"sv\": \"Vattennivå\",\n              \"pl\": \"Poziom wody\",\n              \"ru\": \"Уровень воды\",\n              \"ko\": \"물 세기\"\n            },\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"label\": {\n                  \"en\": \"Off\",\n                  \"it\": \"Spento\",\n                  \"nl\": \"Uit\",\n                  \"da\": \"Fra\",\n                  \"de\": \"Aus\",\n                  \"es\": \"Apagado\",\n                  \"fr\": \"Désactivé\",\n                  \"no\": \"Av\",\n                  \"sv\": \"Av\",\n                  \"pl\": \"Wyłączony\",\n                  \"ru\": \"Выключено\",\n                  \"ko\": \"끔\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Level 1\",\n                  \"it\": \"Livello 1\",\n                  \"nl\": \"Niveau 1\",\n                  \"da\": \"Niveau 1\",\n                  \"de\": \"Stufe 1\",\n                  \"es\": \"Nivel 1\",\n                  \"fr\": \"Niveau 1\",\n                  \"no\": \"Nivå 1\",\n                  \"sv\": \"Nivå 1\",\n                  \"pl\": \"Poziom 1\",\n                  \"ru\": \"Уровень 1\",\n                  \"ko\": \"레벨 1\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Level 2\",\n                  \"it\": \"Livello 2\",\n                  \"nl\": \"Niveau 2\",\n                  \"da\": \"Niveau 2\",\n                  \"de\": \"Stufe 2\",\n                  \"es\": \"Nivel 2\",\n                  \"fr\": \"Niveau 2\",\n                  \"no\": \"Nivå 2\",\n                  \"sv\": \"Nivå 2\",\n                  \"pl\": \"Poziom 2\",\n                  \"ru\": \"Уровень 2\",\n                  \"ko\": \"레벨 2\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"Level 3\",\n                  \"it\": \"Livello 3\",\n                  \"nl\": \"Niveau 3\",\n                  \"da\": \"Niveau 3\",\n                  \"de\": \"Stufe 3\",\n                  \"es\": \"Nivel 3\",\n                  \"fr\": \"Niveau 3\",\n                  \"no\": \"Nivå 3\",\n                  \"sv\": \"Nivå 3\",\n                  \"pl\": \"Poziom 3\",\n                  \"ru\": \"Уровень 3\",\n                  \"ko\": \"레벨 3\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      {\n        \"id\": \"set_path_mode\",\n        \"title\": {\n          \"en\": \"Set path mode\",\n          \"it\": \"Imposta modalità percorso\",\n          \"nl\": \"Stel padmodus in\",\n          \"da\": \"Indstil stiemodus\",\n          \"de\": \"Pfadmodus einstellen\",\n          \"es\": \"Establecer modo de recorrido\",\n          \"fr\": \"Définir le mode de chemin\",\n          \"no\": \"Angi sti-modus\",\n          \"sv\": \"Ställ in sökläge\",\n          \"pl\": \"Ustaw tryb trasy\",\n          \"ru\": \"Установить режим траектории\",\n          \"ko\": \"경로 모드 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set path mode to [[mode]]\",\n          \"it\": \"Imposta modalità percorso su [[mode]]\",\n          \"nl\": \"Stel padmodus in op [[mode]]\",\n          \"da\": \"Indstil stiemodus til [[mode]]\",\n          \"de\": \"Pfadmodus einstellen auf [[mode]]\",\n          \"es\": \"Establecer modo de recorrido en [[mode]]\",\n          \"fr\": \"Définir le mode de chemin sur [[mode]]\",\n          \"no\": \"Angi sti-modus til [[mode]]\",\n          \"sv\": \"Ställ in sökläge på [[mode]]\",\n          \"pl\": \"Ustaw tryb trasy na [[mode]]\",\n          \"ru\": \"Установить режим траектории на [[mode]]\",\n          \"ko\": \"경로 모드를 [[mode]]로 설정\"\n        },\n        \"args\": [\n          {\n            \"type\": \"device\",\n            \"name\": \"device\",\n            \"filter\": \"driver_id=vacuum_xiaomi_vacuum_max\"\n          },\n          {\n            \"name\": \"mode\",\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Path mode\",\n              \"it\": \"Modalità percorso\",\n              \"nl\": \"Padmodus\",\n              \"da\": \"Stiemodus\",\n              \"de\": \"Pfadmodus\",\n              \"es\": \"Modo de recorrido\",\n              \"fr\": \"Mode de chemin\",\n              \"no\": \"Sti-modus\",\n              \"sv\": \"Sökläge\",\n              \"pl\": \"Tryb trasy\",\n              \"ru\": \"Режим траектории\",\n              \"ko\": \"경로 모드\"\n            },\n            \"values\": [\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Quick\",\n                  \"it\": \"Veloce\",\n                  \"nl\": \"Snel\",\n                  \"da\": \"Hurtig\",\n                  \"de\": \"Schnell\",\n                  \"es\": \"Rápido\",\n                  \"fr\": \"Rapide\",\n                  \"no\": \"Rask\",\n                  \"sv\": \"Snabb\",\n                  \"pl\": \"Szybki\",\n                  \"ru\": \"Быстрый\",\n                  \"ko\": \"빠름\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Standard\",\n                  \"it\": \"Standard\",\n                  \"nl\": \"Standaard\",\n                  \"da\": \"Standard\",\n                  \"de\": \"Standard\",\n                  \"es\": \"Estándar\",\n                  \"fr\": \"Standard\",\n                  \"no\": \"Standard\",\n                  \"sv\": \"Standard\",\n                  \"pl\": \"Standardowy\",\n                  \"ru\": \"Стандартный\",\n                  \"ko\": \"표준\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"Deep\",\n                  \"it\": \"Profondo\",\n                  \"nl\": \"Diep\",\n                  \"da\": \"Dyb\",\n                  \"de\": \"Tief\",\n                  \"es\": \"Profundo\",\n                  \"fr\": \"Profond\",\n                  \"no\": \"Dyp\",\n                  \"sv\": \"Djup\",\n                  \"pl\": \"Głęboki\",\n                  \"ru\": \"Глубокий\",\n                  \"ko\": \"딥\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      {\n        \"id\": \"set_carpet_avoidance\",\n        \"title\": {\n          \"en\": \"Set carpet avoidance\",\n          \"nl\": \"Stel tapijtvermijding in\",\n          \"de\": \"Teppichvermeidung einstellen\",\n          \"da\": \"Indstil tæppeundgåelse\",\n          \"es\": \"Establecer evasión de alfombras\",\n          \"fr\": \"Définir l’évitement des tapis\",\n          \"it\": \"Imposta evitamento tappeti\",\n          \"no\": \"Sett teppeunngåelse\",\n          \"sv\": \"Ställ in mattundvikande\",\n          \"pl\": \"Ustaw unikanie dywanów\",\n          \"ru\": \"Установить избегание ковров\",\n          \"ko\": \"카펫 회피 설정\"\n        },\n        \"titleFormatted\": {\n          \"en\": \"Set carpet avoidance to [[mode]]\",\n          \"nl\": \"Stel tapijtvermijding in op [[mode]]\",\n          \"de\": \"Teppichvermeidung einstellen auf [[mode]]\",\n          \"da\": \"Indstil tæppeundgåelse til [[mode]]\",\n          \"es\": \"Establecer evasión de alfombras a [[mode]]\",\n          \"fr\": \"Définir l’évitement des tapis sur [[mode]]\",\n          \"it\": \"Imposta evitamento tappeti su [[mode]]\",\n          \"no\": \"Sett teppeunngåelse til [[mode]]\",\n          \"sv\": \"Ställ in mattundvikande till [[mode]]\",\n          \"pl\": \"Ustaw unikanie dywanów na [[mode]]\",\n          \"ru\": \"Установить избегание ковров на [[mode]]\",\n          \"ko\": \"[[mode]]로 카펫 회피 설정\"\n        },\n        \"args\": [\n          {\n            \"type\": \"device\",\n            \"name\": \"device\",\n            \"filter\": \"driver_id=vacuum_xiaomi_vacuum_max\"\n          },\n          {\n            \"name\": \"mode\",\n            \"type\": \"dropdown\",\n            \"title\": {\n              \"en\": \"Carpet avoidance mode\",\n              \"nl\": \"Tapijtvermijdingsmodus\",\n              \"de\": \"Teppichvermeidungsmodus\",\n              \"da\": \"Tæppeundgåelsestilstand\",\n              \"es\": \"Modo de evasión de alfombras\",\n              \"fr\": \"Mode d’évitement des tapis\",\n              \"it\": \"Modalità evitamento tappeti\",\n              \"no\": \"Teppeunngåelsesmodus\",\n              \"sv\": \"Mattundvikandeläge\",\n              \"pl\": \"Tryb unikania dywanów\",\n              \"ru\": \"Режим избегания ковров\",\n              \"ko\": \"카펫 회피 모드\"\n            },\n            \"values\": [\n              {\n                \"id\": \"0\",\n                \"label\": {\n                  \"en\": \"Self Adaptation\",\n                  \"nl\": \"Zelfaanpassing\",\n                  \"de\": \"Selbstanpassung\",\n                  \"da\": \"Selvtilpasning\",\n                  \"es\": \"Auto adaptación\",\n                  \"fr\": \"Auto-adaptation\",\n                  \"it\": \"Auto adattamento\",\n                  \"no\": \"Selvtilpasning\",\n                  \"sv\": \"Självanpassning\",\n                  \"pl\": \"Samodopasowanie\",\n                  \"ru\": \"Самоадаптация\",\n                  \"ko\": \"자동 적응\"\n                }\n              },\n              {\n                \"id\": \"1\",\n                \"label\": {\n                  \"en\": \"Avoid\",\n                  \"nl\": \"Vermijden\",\n                  \"de\": \"Vermeiden\",\n                  \"da\": \"Undgå\",\n                  \"es\": \"Evitar\",\n                  \"fr\": \"Éviter\",\n                  \"it\": \"Evita\",\n                  \"no\": \"Unngå\",\n                  \"sv\": \"Undvik\",\n                  \"pl\": \"Unikaj\",\n                  \"ru\": \"Избегать\",\n                  \"ko\": \"회피\"\n                }\n              },\n              {\n                \"id\": \"2\",\n                \"label\": {\n                  \"en\": \"Ignore\",\n                  \"nl\": \"Negeren\",\n                  \"de\": \"Ignorieren\",\n                  \"da\": \"Ignorer\",\n                  \"es\": \"Ignorar\",\n                  \"fr\": \"Ignorer\",\n                  \"it\": \"Ignora\",\n                  \"no\": \"Ignorer\",\n                  \"sv\": \"Ignorera\",\n                  \"pl\": \"Ignoruj\",\n                  \"ru\": \"Игнорировать\",\n                  \"ko\": \"무시\"\n                }\n              },\n              {\n                \"id\": \"3\",\n                \"label\": {\n                  \"en\": \"Span\",\n                  \"nl\": \"Span\",\n                  \"de\": \"Span\",\n                  \"da\": \"Span\",\n                  \"es\": \"Span\",\n                  \"fr\": \"Span\",\n                  \"it\": \"Span\",\n                  \"no\": \"Span\",\n                  \"sv\": \"Span\",\n                  \"pl\": \"Span\",\n                  \"ru\": \"Span\",\n                  \"ko\": \"Span\"\n                }\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  },\n  \"drivers\": [\n    {\n      \"icon\": \"/drivers/airfresh_zhimi_airfresh/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Smartmi Fresh Air System (WiFi)\",\n        \"nl\": \"Smartmi Fresh Air System (WiFi)\",\n        \"da\": \"Smartmi Friskluftsystem (WiFi)\",\n        \"de\": \"Smartmi Frischluftsystem (WiFi)\",\n        \"es\": \"Sistema de Aire Fresco Smartmi (WiFi)\",\n        \"fr\": \"Système d'air frais Smartmi (WiFi)\",\n        \"it\": \"Sistema di Aria Fresca Smartmi (WiFi)\",\n        \"no\": \"Smartmi Friskluftsystem (WiFi)\",\n        \"sv\": \"Smartmi Friskluftsystem (WiFi)\",\n        \"pl\": \"System świeżego powietrza Smartmi (WiFi)\",\n        \"ru\": \"Система свежего воздуха Smartmi (WiFi)\",\n        \"ko\": \"스마트미 신선한 공기 시스템 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/airfresh_zhimi_airfresh/assets/images/large.jpg\",\n        \"small\": \"drivers/airfresh_zhimi_airfresh/assets/images/small.jpg\"\n      },\n      \"class\": \"airpurifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"airpurifier_zhimi_airfresh_mode\",\n        \"measure_temperature\",\n        \"measure_humidity\",\n        \"measure_pm25\",\n        \"measure_co2\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.ptc\": {\n          \"title\": {\n            \"en\": \"Heat\",\n            \"nl\": \"Verwarmen\",\n            \"da\": \"Varme\",\n            \"de\": \"Heizen\",\n            \"es\": \"Calentar\",\n            \"fr\": \"Chauffer\",\n            \"it\": \"Riscaldare\",\n            \"no\": \"Varme\",\n            \"sv\": \"Värme\",\n            \"pl\": \"Grzanie\",\n            \"ru\": \"Нагрев\",\n            \"ko\": \"열기\"\n          }\n        }\n      },\n      \"id\": \"airfresh_zhimi_airfresh\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuraciones de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\",\n            \"pt\": \"Configurações do usuário\",\n            \"fi\": \"Käyttäjäasetukset\",\n            \"tr\": \"Kullanıcı Ayarları\",\n            \"zh\": \"用户设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"Светодиод\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summer\",\n                \"de\": \"Summer\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Buzzer\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Summer\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Brzęczyk\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"버저\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnelås\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo para niños\",\n                \"fr\": \"Verrouillage enfant\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barnelås\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada rodzicielska\",\n                \"ru\": \"Блокировка от детей\",\n                \"ko\": \"잠금\"\n              }\n            },\n            {\n              \"id\": \"f1_hour_used\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter life\",\n                \"nl\": \"Filter duur\",\n                \"da\": \"Filterliv\",\n                \"de\": \"Filterlebensdauer\",\n                \"es\": \"Vida del filtro\",\n                \"fr\": \"Durée de vie du filtre\",\n                \"it\": \"Vita del filtro\",\n                \"no\": \"Filterlevetid\",\n                \"sv\": \"Filterliv\",\n                \"pl\": \"Żywotność filtra\",\n                \"ru\": \"Срок службы фильтра\",\n                \"ko\": \"필터 수명\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"motor_speed\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Motorspeed\",\n                \"nl\": \"Motorsnelheid\",\n                \"da\": \"Motoreffekt\",\n                \"de\": \"Motorgeschwindigkeit\",\n                \"es\": \"Velocidad del motor\",\n                \"fr\": \"Vitesse du moteur\",\n                \"it\": \"Velocità del motore\",\n                \"no\": \"Motoreffekt\",\n                \"sv\": \"Motoreffekt\",\n                \"pl\": \"Prędkość silnika\",\n                \"ru\": \"Скорость двигателя\",\n                \"ko\": \"모터 속도\"\n              },\n              \"value\": \"400\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"pt\": \"Configurações do dispositivo\",\n            \"fi\": \"Laitteen asetukset\",\n            \"tr\": \"Aygıt Ayarları\",\n            \"zh\": \"设备设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/airfresh_zhimi_airfresh_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n        \"nl\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n        \"da\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n        \"de\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n        \"es\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n        \"fr\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n        \"it\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n        \"no\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n        \"sv\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n        \"pl\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n        \"ru\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n        \"ko\": \"Smartmi Fresh Air System MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/airfresh_zhimi_airfresh_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/airfresh_zhimi_airfresh_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"airpurifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"onoff.ptc\",\n        \"airpurifier_zhimi_fanlevel\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.ptc\": {\n          \"title\": {\n            \"en\": \"Heat\",\n            \"nl\": \"Verwarmen\",\n            \"da\": \"Varme\",\n            \"de\": \"Heizen\",\n            \"es\": \"Calor\",\n            \"fr\": \"Chaleur\",\n            \"it\": \"Calore\",\n            \"no\": \"Varme\",\n            \"sv\": \"Värme\",\n            \"pl\": \"Ciepło\",\n            \"ru\": \"Тепло\",\n            \"ko\": \"난방\"\n          }\n        }\n      },\n      \"id\": \"airfresh_zhimi_airfresh_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"LED\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Sommer\",\n                \"de\": \"Summton\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Buzzer\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Buzzer\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Brzęczyk\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"부저\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnelås\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo infantil\",\n                \"fr\": \"Verrouillage enfant\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barnelås\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada rodzicielska\",\n                \"ru\": \"Родительский контроль\",\n                \"ko\": \"잠금 기능\"\n              }\n            },\n            {\n              \"id\": \"f1_hour_used\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter life\",\n                \"nl\": \"Filter duur\",\n                \"da\": \"Filtreringens liv\",\n                \"de\": \"Filterlebensdauer\",\n                \"es\": \"Vida del filtro\",\n                \"fr\": \"Durée de vie du filtre\",\n                \"it\": \"Durata del filtro\",\n                \"no\": \"Filterliv\",\n                \"sv\": \"Filterlivslängd\",\n                \"pl\": \"Żywotność filtra\",\n                \"ru\": \"Срок службы фильтра\",\n                \"ko\": \"필터 수명\"\n              },\n              \"value\": \"0%\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/airfryer_careli_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Air Fryers MIoT (WiFi)\",\n        \"nl\": \"Air Fryers MIoT (WiFi)\",\n        \"da\": \"Air Fryers MIoT (WiFi)\",\n        \"de\": \"Air Fryers MIoT (WiFi)\",\n        \"es\": \"Air Fryers MIoT (WiFi)\",\n        \"fr\": \"Air Fryers MIoT (WiFi)\",\n        \"it\": \"Air Fryers MIoT (WiFi)\",\n        \"no\": \"Air Fryers MIoT (WiFi)\",\n        \"sv\": \"Air Fryers MIoT (WiFi)\",\n        \"pl\": \"Air Fryers MIoT (WiFi)\",\n        \"ru\": \"Air Fryers MIoT (WiFi)\",\n        \"ko\": \"Air Fryers MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/airfryer_careli_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/airfryer_careli_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"airfryer\",\n      \"capabilities\": [\n        \"onoff\",\n        \"airfryer_careli_mode\",\n        \"airfryer_careli_target_time\",\n        \"airfryer_careli_target_temperature\",\n        \"onoff.preheat\",\n        \"airfryer_careli_food_quantity\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.preheat\": {\n          \"title\": {\n            \"en\": \"Preheat switch\",\n            \"nl\": \"Preheat schakelaar\",\n            \"da\": \"Forvarmingskontakt\",\n            \"de\": \"Vorheizschalter\",\n            \"es\": \"Interruptor de precalentamiento\",\n            \"fr\": \"Interrupteur de préchauffage\",\n            \"it\": \"Interruttore di preriscaldamento\",\n            \"no\": \"Forvarmingsbryter\",\n            \"sv\": \"Förvärmningsbrytare\",\n            \"pl\": \"Przełącznik nagrzewania\",\n            \"ru\": \"Выключатель предварительного нагрева\",\n            \"ko\": \"예열 스위치\"\n          }\n        }\n      },\n      \"id\": \"airfryer_careli_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Consumables\",\n            \"nl\": \"Verbruiksartikelen\",\n            \"da\": \"Forbrugsvarer\",\n            \"de\": \"Verbrauchsmaterialien\",\n            \"es\": \"Consumibles\",\n            \"fr\": \"Consommables\",\n            \"it\": \"Consumi\",\n            \"no\": \"Forbruksartikler\",\n            \"sv\": \"Förbrukningsvaror\",\n            \"pl\": \"Materiały eksploatacyjne\",\n            \"ru\": \"Расходные материалы\",\n            \"ko\": \"소모품\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_threshold\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Alarm threshold\",\n                \"nl\": \"Alarm ondergrens\",\n                \"da\": \"Alarm tærskel\",\n                \"de\": \"Alarmgrenze\",\n                \"es\": \"Umbral de alarma\",\n                \"fr\": \"Seuil d'alarme\",\n                \"it\": \"Soglia di allarme\",\n                \"no\": \"Alarmterskel\",\n                \"sv\": \"Alarmtröskel\",\n                \"pl\": \"Próg alarmowy\",\n                \"ru\": \"Порог тревоги\",\n                \"ko\": \"알람 임계값\"\n              },\n              \"hint\": {\n                \"en\": \"Threshold below which the alarm will be activated.\",\n                \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n                \"da\": \"Tærskel under hvilken alarmen vil blive aktiveret.\",\n                \"de\": \"Schwellenwert, unter dem der Alarm ausgelöst wird.\",\n                \"es\": \"Límite por debajo del cual se activará la alarma.\",\n                \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n                \"it\": \"Soglia al di sotto della quale verrà attivato l'allarme.\",\n                \"no\": \"Terskel under hvilken alarmen vil bli aktivert.\",\n                \"sv\": \"Tröskel under vilken alarmet aktiveras.\",\n                \"pl\": \"Próg poniżej którego alarm zostanie włączony.\",\n                \"ru\": \"Порог, ниже которого будет активирована тревога.\",\n                \"ko\": \"알람이 활성화되는 임계값입니다.\"\n              },\n              \"value\": 20,\n              \"attr\": {\n                \"min\": 1,\n                \"max\": 90\n              }\n            },\n            {\n              \"id\": \"main_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Main brush remaining (%)\",\n                \"nl\": \"Hoofdborstel over (%)\",\n                \"da\": \"Hovedbørste resterende (%)\",\n                \"de\": \"Hauptbürste verbleibend (%)\",\n                \"es\": \"Cepillo principal restante (%)\",\n                \"fr\": \"Brosse principale restante (%)\",\n                \"it\": \"Spazzola principale rimanente (%)\",\n                \"no\": \"Hovedbørste gjenværende (%)\",\n                \"sv\": \"Huvudborste kvar (%)\",\n                \"pl\": \"Pozostało szczotek głównych (%)\",\n                \"ru\": \"Осталось основной щетки (%)\",\n                \"ko\": \"메인 브러시 잔여량 (%)\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"side_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Side brush remaining\",\n                \"nl\": \"Zijborstel over\",\n                \"da\": \"Sidebørste tilbageværende\",\n                \"de\": \"Seitenbürste verbleibend\",\n                \"es\": \"Cepillo lateral restante\",\n                \"fr\": \"Brosse latérale restante\",\n                \"it\": \"Spazzola laterale rimanente\",\n                \"no\": \"Sidebørste gjenværende\",\n                \"sv\": \"Sidoborste kvar\",\n                \"pl\": \"Pozostało szczotek bocznych\",\n                \"ru\": \"Осталось боковой щетки\",\n                \"ko\": \"사이드 브러시 잔여량\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"filter_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter remaining\",\n                \"nl\": \"Filter over\",\n                \"da\": \"Filter tilbageværende\",\n                \"de\": \"Filter verbleibend\",\n                \"es\": \"Filtro restante\",\n                \"fr\": \"Filtre restant\",\n                \"it\": \"Filtro rimanente\",\n                \"no\": \"Filter gjenværende\",\n                \"sv\": \"Filter kvar\",\n                \"pl\": \"Pozostało filtrów\",\n                \"ru\": \"Осталось фильтра\",\n                \"ko\": \"필터 잔여량\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"total_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total work time\",\n                \"nl\": \"Totale gebruikstijd\",\n                \"da\": \"Samlet arbejdstid\",\n                \"de\": \"Gesamte Arbeitszeit\",\n                \"es\": \"Tiempo total de trabajo\",\n                \"fr\": \"Temps de travail total\",\n                \"it\": \"Tempo di lavoro totale\",\n                \"no\": \"Total arbeidstid\",\n                \"sv\": \"Total arbetstid\",\n                \"pl\": \"Całkowity czas pracy\",\n                \"ru\": \"Общее время работы\",\n                \"ko\": \"총 작업 시간\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"total_cleared_area\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total cleaned area\",\n                \"nl\": \"Totaal geschoont\",\n                \"da\": \"Samlet rengjort område\",\n                \"de\": \"Gesamt gereinigte Fläche\",\n                \"es\": \"Área total limpiada\",\n                \"fr\": \"Surface totale nettoyée\",\n                \"it\": \"Area totale pulita\",\n                \"no\": \"Totalt rengjort område\",\n                \"sv\": \"Totalt rengjort område\",\n                \"pl\": \"Łączna powierzchnia sprzątania\",\n                \"ru\": \"Общая убранная площадь\",\n                \"ko\": \"총 청소 면적\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"total_clean_count\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total clean count\",\n                \"nl\": \"Totaal aantal opschoningen\",\n                \"da\": \"Samlet rengøringsantal\",\n                \"de\": \"Gesamtzahl der Reinigungen\",\n                \"es\": \"Recuentos de limpieza totales\",\n                \"fr\": \"Nombre total de nettoyages\",\n                \"it\": \"Conteggio totale delle pulizie\",\n                \"no\": \"Total rengjøringsteller\",\n                \"sv\": \"Total rengöringsantal\",\n                \"pl\": \"Łączna liczba czyszczenia\",\n                \"ru\": \"Общее количество чисток\",\n                \"ko\": \"총 청소 횟수\"\n              },\n              \"value\": \"0\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device data\",\n            \"nl\": \"Apparaat data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"장치 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"error\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Error\",\n                \"nl\": \"Error\",\n                \"da\": \"Fejl\",\n                \"de\": \"Fehler\",\n                \"es\": \"Error\",\n                \"fr\": \"Erreur\",\n                \"it\": \"Errore\",\n                \"no\": \"Feil\",\n                \"sv\": \"Fel\",\n                \"pl\": \"Błąd\",\n                \"ru\": \"Ошибка\",\n                \"ko\": \"오류\"\n              },\n              \"value\": \"No error\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/airmonitor_cgllc_zhimi_airmonitor/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Air Quality Monitor (WiFi)\",\n        \"nl\": \"Mi Air Quality Monitor (WiFi)\",\n        \"da\": \"Mi Luftkvalitetsmonitor (WiFi)\",\n        \"de\": \"Mi Luftqualitätsmonitor (WiFi)\",\n        \"es\": \"Monitor de Calidad del Aire Mi (WiFi)\",\n        \"fr\": \"Moniteur de Qualité de l'Air Mi (WiFi)\",\n        \"it\": \"Monitor della Qualità dell'Aria Mi (WiFi)\",\n        \"no\": \"Mi Luftkvalitetsmonitor (WiFi)\",\n        \"sv\": \"Mi Luftkvalitetsmonitor (WiFi)\",\n        \"pl\": \"Monitor Jakości Powietrza Mi (WiFi)\",\n        \"ru\": \"Монитор качества воздуха Mi (WiFi)\",\n        \"ko\": \"미 에어 퀄리티 모니터 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/airmonitor_cgllc_zhimi_airmonitor/assets/images/large.jpg\",\n        \"small\": \"drivers/airmonitor_cgllc_zhimi_airmonitor/assets/images/small.jpg\"\n      },\n      \"class\": \"airtreatment\",\n      \"capabilities\": [\n        \"measure_pm25\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"INTERNAL\"\n        ]\n      },\n      \"id\": \"airmonitor_cgllc_zhimi_airmonitor\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"ja\": \"デバイス設定\",\n            \"zh\": \"设备设置\",\n            \"pt\": \"Configurações do dispositivo\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/airpurifier_dmaker_airfresh_t2017/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n        \"nl\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n        \"da\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n        \"de\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n        \"es\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n        \"fr\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n        \"it\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n        \"no\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n        \"sv\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n        \"pl\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n        \"ru\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n        \"ko\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/airpurifier_dmaker_airfresh_t2017/assets/images/large.jpg\",\n        \"small\": \"drivers/airpurifier_dmaker_airfresh_t2017/assets/images/small.jpg\"\n      },\n      \"class\": \"airpurifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"dim\",\n        \"airpurifier_zhimi_mode\",\n        \"onoff.ptc\",\n        \"measure_temperature\",\n        \"measure_pm25\",\n        \"measure_co2\"\n      ],\n      \"capabilitiesOptions\": {\n        \"dim\": {\n          \"title\": {\n            \"en\": \"Speedlevel\",\n            \"nl\": \"Snelheid\",\n            \"da\": \"Hastighedsniveau\",\n            \"de\": \"Geschwindigkeitsstufe\",\n            \"es\": \"Nivel de velocidad\",\n            \"fr\": \"Niveau de vitesse\",\n            \"it\": \"Livello di velocità\",\n            \"no\": \"Hastighetsnivå\",\n            \"sv\": \"Hastighetsnivå\",\n            \"pl\": \"Poziom prędkości\",\n            \"ru\": \"Уровень скорости\",\n            \"ko\": \"속도 레벨\"\n          }\n        },\n        \"onoff.ptc\": {\n          \"title\": {\n            \"en\": \"Heat\",\n            \"nl\": \"Verwarmen\",\n            \"da\": \"Varme\",\n            \"de\": \"Heizen\",\n            \"es\": \"Calor\",\n            \"fr\": \"Chaleur\",\n            \"it\": \"Calore\",\n            \"no\": \"Varme\",\n            \"sv\": \"Värme\",\n            \"pl\": \"Ciepło\",\n            \"ru\": \"Тепло\",\n            \"ko\": \"난방\"\n          }\n        }\n      },\n      \"id\": \"airpurifier_dmaker_airfresh_t2017\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de Usuario\",\n            \"fr\": \"Paramètres de l'utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"display\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Display\",\n                \"nl\": \"Display\",\n                \"da\": \"Skærm\",\n                \"de\": \"Anzeige\",\n                \"es\": \"Pantalla\",\n                \"fr\": \"Affichage\",\n                \"it\": \"Schermo\",\n                \"no\": \"Skjerm\",\n                \"sv\": \"Skärm\",\n                \"pl\": \"Wyświetlacz\",\n                \"ru\": \"Дисплей\",\n                \"ko\": \"디스플레이\"\n              }\n            },\n            {\n              \"id\": \"Sound\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Sound\",\n                \"nl\": \"Sound\",\n                \"da\": \"Lyd\",\n                \"de\": \"Ton\",\n                \"es\": \"Sonido\",\n                \"fr\": \"Son\",\n                \"it\": \"Suono\",\n                \"no\": \"Lyd\",\n                \"sv\": \"Ljud\",\n                \"pl\": \"Dźwięk\",\n                \"ru\": \"Звук\",\n                \"ko\": \"소리\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnesikring\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo Infantil\",\n                \"fr\": \"Verrouillage enfant\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barnesikring\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada rodzicielska\",\n                \"ru\": \"Блокировка от детей\",\n                \"ko\": \"차일드 락\"\n              }\n            },\n            {\n              \"id\": \"filter_efficient\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter life\",\n                \"nl\": \"Fil;ter duur\",\n                \"da\": \"Filter levetid\",\n                \"de\": \"Filterlebensdauer\",\n                \"es\": \"Vida del filtro\",\n                \"fr\": \"Durée de vie du filtre\",\n                \"it\": \"Durata del filtro\",\n                \"no\": \"Filterliv\",\n                \"sv\": \"Filterliv\",\n                \"pl\": \"Żywotność filtra\",\n                \"ru\": \"Ресурс фильтра\",\n                \"ko\": \"필터 수명\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"filter_intermediate\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter life 2\",\n                \"da\": \"Filter levetid 2\",\n                \"de\": \"Filterlebensdauer 2\",\n                \"es\": \"Vida del filtro 2\",\n                \"fr\": \"Durée de vie du filtre 2\",\n                \"it\": \"Durata del filtro 2\",\n                \"no\": \"Filterliv 2\",\n                \"sv\": \"Filterliv 2\",\n                \"pl\": \"Żywotność filtra 2\",\n                \"ru\": \"Ресурс фильтра 2\",\n                \"ko\": \"필터 수명 2\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"screen_direction\",\n              \"type\": \"dropdown\",\n              \"value\": \"forward\",\n              \"label\": {\n                \"en\": \"Screen Direction\",\n                \"nl\": \"Scherm orientatie\",\n                \"da\": \"Skærmretning\",\n                \"de\": \"Bildschirmrichtung\",\n                \"es\": \"Dirección de la pantalla\",\n                \"fr\": \"Orientation de l'écran\",\n                \"it\": \"Orientamento schermo\",\n                \"no\": \"Skjermretning\",\n                \"sv\": \"Skärmriktning\",\n                \"pl\": \"Kierunek ekranu\",\n                \"ru\": \"Направление экрана\",\n                \"ko\": \"화면 방향\"\n              },\n              \"values\": [\n                {\n                  \"id\": \"forward\",\n                  \"label\": {\n                    \"en\": \"Normal\",\n                    \"da\": \"Normal\",\n                    \"de\": \"Normal\",\n                    \"es\": \"Normal\",\n                    \"fr\": \"Normal\",\n                    \"it\": \"Normale\",\n                    \"no\": \"Normal\",\n                    \"sv\": \"Normal\",\n                    \"pl\": \"Normalny\",\n                    \"ru\": \"Обычный\",\n                    \"ko\": \"일반\"\n                  }\n                },\n                {\n                  \"id\": \"left\",\n                  \"label\": {\n                    \"en\": \"-90\",\n                    \"da\": \"-90\",\n                    \"de\": \"-90\",\n                    \"es\": \"-90\",\n                    \"fr\": \"-90\",\n                    \"it\": \"-90\",\n                    \"no\": \"-90\",\n                    \"sv\": \"-90\",\n                    \"pl\": \"-90\",\n                    \"ru\": \"-90\",\n                    \"ko\": \"-90\"\n                  }\n                },\n                {\n                  \"id\": \"right\",\n                  \"label\": {\n                    \"en\": \"+90\",\n                    \"da\": \"+90\",\n                    \"de\": \"+90\",\n                    \"es\": \"+90\",\n                    \"fr\": \"+90\",\n                    \"it\": \"+90\",\n                    \"no\": \"+90\",\n                    \"sv\": \"+90\",\n                    \"pl\": \"+90\",\n                    \"ru\": \"+90\",\n                    \"ko\": \"+90\"\n                  }\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/airpurifier_zhimi_advanced/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Advanced Older Mi Air Purifier (WiFi)\",\n        \"nl\": \"Geavanceerde oudere Mi Air Purifier (WiFi)\",\n        \"da\": \"Avanceret Ældre Mi Luft Purifier (WiFi)\",\n        \"de\": \"Erweiterter älterer Mi Luftreiniger (WiFi)\",\n        \"es\": \"Purificador de aire Mi avanzado para mayores (WiFi)\",\n        \"fr\": \"Purificateur d'air Mi ancien avancé (WiFi)\",\n        \"it\": \"Purificatore d'aria Mi avanzato più vecchio (WiFi)\",\n        \"no\": \"Avansert Eldre Mi Luft Purifier (WiFi)\",\n        \"sv\": \"Avancerad Äldre Mi Luft Purifier (WiFi)\",\n        \"pl\": \"Zaawansowany starszy oczyszczacz powietrza Mi (WiFi)\",\n        \"ru\": \"Продвинутый старый Mi Воздухоочиститель (WiFi)\",\n        \"ko\": \"고급 구형 Mi 공기청정기 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/airpurifier_zhimi_advanced/assets/images/large.jpg\",\n        \"small\": \"drivers/airpurifier_zhimi_advanced/assets/images/small.jpg\"\n      },\n      \"class\": \"airpurifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"measure_pm25\",\n        \"measure_humidity\",\n        \"measure_temperature\",\n        \"measure_luminance\",\n        \"airpurifier_mode\",\n        \"fan_speed\"\n      ],\n      \"capabilitiesOptions\": {\n        \"fan_speed\": {\n          \"min\": 0,\n          \"max\": 16,\n          \"step\": 1\n        }\n      },\n      \"id\": \"airpurifier_zhimi_advanced\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de Usuario\",\n            \"fr\": \"Paramètres Utilisateur\",\n            \"it\": \"Impostazioni Utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia Użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"LED\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summer\",\n                \"de\": \"Summer\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Sonnerie\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Buzzer\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Brzęczyk\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"부저\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnesikring\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo infantil\",\n                \"fr\": \"Verrouillage Enfant\",\n                \"it\": \"Blocco Bambini\",\n                \"no\": \"Barnesikring\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada Dziecięca\",\n                \"ru\": \"Блокировка от детей\",\n                \"ko\": \"어린이 잠금\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Data\",\n            \"nl\": \"Apparaat Data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"기기 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"filter1_life\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter life\",\n                \"nl\": \"Filter duur\",\n                \"da\": \"Filterets levetid\",\n                \"de\": \"Filterlebensdauer\",\n                \"es\": \"Vida útil del filtro\",\n                \"fr\": \"Durée de vie du filtre\",\n                \"it\": \"Vita del filtro\",\n                \"no\": \"Filterets levetid\",\n                \"sv\": \"Filterlivslängd\",\n                \"pl\": \"Czas życia filtra\",\n                \"ru\": \"Срок службы фильтра\",\n                \"ko\": \"필터 수명\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"f1_hour_used\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter hours used\",\n                \"nl\": \"Filter uur gebruikt\",\n                \"da\": \"Filtrets brugte timer\",\n                \"de\": \"Verwendete Filterstunden\",\n                \"es\": \"Horas de uso del filtro\",\n                \"fr\": \"Heures de filtre utilisées\",\n                \"it\": \"Ore di utilizzo del filtro\",\n                \"no\": \"Filtertimer brukt\",\n                \"sv\": \"Filteranvändningstimmar\",\n                \"pl\": \"Użyte godziny filtra\",\n                \"ru\": \"Часы использования фильтра\",\n                \"ko\": \"필터 사용 시간\"\n              },\n              \"value\": \"0h\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Réglages de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/airpurifier_zhimi_advanced_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Advanced Mi Air Purifier MIoT (WiFi)\",\n        \"nl\": \"Geavanceerde Mi Air Purifier MIoT (WiFi)\",\n        \"da\": \"Avanceret Mi Air Purifier MIoT (WiFi)\",\n        \"de\": \"Erweiterter Mi Air Purifier MIoT (WiFi)\",\n        \"es\": \"Purificador de aire Mi avanzado MIoT (WiFi)\",\n        \"fr\": \"Purificateur d'air Mi avancé MIoT (WiFi)\",\n        \"it\": \"Purificatore d'aria Mi Avanzato MIoT (WiFi)\",\n        \"no\": \"Avansert Mi Air Purifier MIoT (WiFi)\",\n        \"sv\": \"Avancerad Mi Air Purifier MIoT (WiFi)\",\n        \"pl\": \"Zaawansowany Mi Air Purifier MIoT (WiFi)\",\n        \"ru\": \"Продвинутый воздухоочиститель Mi MIoT (WiFi)\",\n        \"ko\": \"고급 Mi Air Purifier MIoT (WiFi)\",\n        \"ja\": \"高度なMiエア purificador MIoT（WiFi）\",\n        \"zh\": \"高级Mi空气净化器MIoT（WiFi）\"\n      },\n      \"images\": {\n        \"large\": \"drivers/airpurifier_zhimi_advanced_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/airpurifier_zhimi_advanced_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"onoff\",\n        \"measure_pm25\",\n        \"airpurifier_zhimi_mode\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.ion\": {\n          \"title\": {\n            \"en\": \"Enable ions\",\n            \"nl\": \"Inschakelen ionen\",\n            \"da\": \"Aktiver ioner\",\n            \"de\": \"Ionen aktivieren\",\n            \"es\": \"Activar iones\",\n            \"fr\": \"Activer les ions\",\n            \"it\": \"Attiva ioni\",\n            \"no\": \"Aktiver ioner\",\n            \"sv\": \"Aktivera joner\",\n            \"pl\": \"Włącz jony\",\n            \"ru\": \"Включить ионы\",\n            \"ko\": \"이온 활성화\",\n            \"ja\": \"イオンを有効にする\",\n            \"zh\": \"启用离子\"\n          }\n        }\n      },\n      \"id\": \"airpurifier_zhimi_advanced_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"Светодиод\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summer\",\n                \"de\": \"Summton\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Buzzer\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Summer\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Brzęczyk\",\n                \"ru\": \"Звуковой сигнал\",\n                \"ko\": \"버저\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnelås\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo Infantil\",\n                \"fr\": \"Verrouillage enfant\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barnelås\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada rodzicielska\",\n                \"ru\": \"Блокировка от детей\",\n                \"ko\": \"잠금\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Data\",\n            \"nl\": \"Apparaat Data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"기기 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"filter_life_remaining\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter remaining\",\n                \"nl\": \"Filter over\",\n                \"da\": \"Filter tilbage\",\n                \"de\": \"Filter übrig\",\n                \"es\": \"Filtro restante\",\n                \"fr\": \"Filtre restant\",\n                \"it\": \"Filtro rimanente\",\n                \"no\": \"Filter gjenværende\",\n                \"sv\": \"Filter kvar\",\n                \"pl\": \"Pozostało filtra\",\n                \"ru\": \"Остаток фильтра\",\n                \"ko\": \"필터 잔여량\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"filter_hours_used\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter hours used\",\n                \"nl\": \"Filter uur gebruikt\",\n                \"da\": \"Filter timer brugt\",\n                \"de\": \"Filterstunden verwendet\",\n                \"es\": \"Horas de filtro utilizadas\",\n                \"fr\": \"Heures de filtre utilisées\",\n                \"it\": \"Ore di filtro utilizzate\",\n                \"no\": \"Filter timer brukt\",\n                \"sv\": \"Filter timmar användes\",\n                \"pl\": \"Godziny używania filtra\",\n                \"ru\": \"Использованные часы фильтра\",\n                \"ko\": \"필터 사용 시간\"\n              },\n              \"value\": \"0h\"\n            },\n            {\n              \"id\": \"purify_volume\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Air Cleared\",\n                \"nl\": \"Lucht geschoond\",\n                \"da\": \"Luft renset\",\n                \"de\": \"Luft gereinigt\",\n                \"es\": \"Aire purificado\",\n                \"fr\": \"Air purifié\",\n                \"it\": \"Aria ripulita\",\n                \"no\": \"Luft renset\",\n                \"sv\": \"Luft rensad\",\n                \"pl\": \"Oczyszczone powietrze\",\n                \"ru\": \"Воздух очищен\",\n                \"ko\": \"정화된 공기\"\n              },\n              \"value\": \"0m3\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"기기 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-86sw1-advanced/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Wireless Wall Single Switch gen2 (Gateway)\",\n        \"nl\": \"Aqara Wireless Wall Single Switch gen2 (Gateway)\",\n        \"da\": \"Aqara Trådløs Væg Enkel Switch gen2 (Gateway)\",\n        \"de\": \"Aqara Drahtloser Wandschalter Einzeln gen2 (Gateway)\",\n        \"es\": \"Interruptor de Pared Inalámbrico Simple Aqara gen2 (Gateway)\",\n        \"fr\": \"Interrupteur Mural Sans Fil Simple Aqara gen2 (Gateway)\",\n        \"it\": \"Interruttore da Parete Wireless Singolo Aqara gen2 (Gateway)\",\n        \"no\": \"Aqara Trådløs Vegg Enkel Bryter gen2 (Gateway)\",\n        \"sv\": \"Aqara Trådlös Vägg Enkelt Strömbrytare gen2 (Gateway)\",\n        \"pl\": \"Bezprzewodowy Przełącznik Ścienny Aqara gen2 (Gateway)\",\n        \"ru\": \"Беспроводной Настенный Переключатель Aqara gen2 (Шлюз)\",\n        \"ko\": \"Aqara 무선 벽 단일 스위치 gen2 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-86sw1-advanced/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-86sw1-advanced/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2032\"\n        ]\n      },\n      \"id\": \"aqara-86sw1-advanced\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-86sw2-advanced/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Wireless Wall Double Switch gen2 (Gateway)\",\n        \"nl\": \"Aqara Wireless Wall Double Switch gen2 (Gateway)\",\n        \"da\": \"Aqara trådløs væg dobbeltkontakt gen2 (Gateway)\",\n        \"de\": \"Aqara Drahtloser Wandschalter doppelt gen2 (Gateway)\",\n        \"es\": \"Aqara Interruptor de pared inalámbrico doble gen2 (Gateway)\",\n        \"fr\": \"Interrupteur mural sans fil double Aqara gen2 (Gateway)\",\n        \"it\": \"Interruttore da parete wireless doppio Aqara gen2 (Gateway)\",\n        \"no\": \"Aqara trådløs veggbryter dobbel gen2 (Gateway)\",\n        \"sv\": \"Aqara trådlös väggbrytare dubbel gen2 (Gateway)\",\n        \"pl\": \"Aqara bezprzewodowy podwójny przełącznik ścienny gen2 (Gateway)\",\n        \"ru\": \"Aqara Беспроводной настенный двойной выключатель gen2 (Шлюз)\",\n        \"ko\": \"Aqara 무선 벽 2 배 스위치 gen2 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-86sw2-advanced/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-86sw2-advanced/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2032\"\n        ]\n      },\n      \"id\": \"aqara-86sw2-advanced\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"pt\": \"Configurações do dispositivo\",\n            \"fi\": \"Laitteen asetukset\",\n            \"ja\": \"デバイス設定\",\n            \"zh\": \"设备设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-button/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Wireless Button (Gateway)\",\n        \"nl\": \"Aqara Wireless Button (Gateway)\",\n        \"da\": \"Aqara Trådløs Knap (Gateway)\",\n        \"de\": \"Aqara Kabelloser Knopf (Gateway)\",\n        \"es\": \"Botón Inalámbrico Aqara (Gateway)\",\n        \"fr\": \"Bouton Sans Fil Aqara (Gateway)\",\n        \"it\": \"Pulsante Wireless Aqara (Gateway)\",\n        \"no\": \"Aqara Trådløs Knapp (Gateway)\",\n        \"sv\": \"Aqara Trådlös Knapp (Gateway)\",\n        \"pl\": \"Bezprzewodowy Przycisk Aqara (Gateway)\",\n        \"ru\": \"Беспроводная Кнопка Aqara (Gateway)\",\n        \"ko\": \"아카라 무선 버튼 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-button/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-button/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2032\"\n        ]\n      },\n      \"id\": \"aqara-button\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"ja\": \"デバイス設定\",\n            \"zh\": \"设备设置\",\n            \"pt\": \"Configurações do dispositivo\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-button-advanced/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Wireless Button gen2 (Gateway)\",\n        \"nl\": \"Aqara Wireless Button gen2 (Gateway)\",\n        \"da\": \"Aqara trådløs knap gen2 (Gateway)\",\n        \"de\": \"Aqara kabellose Taste gen2 (Gateway)\",\n        \"es\": \"Botón inalámbrico Aqara gen2 (Gateway)\",\n        \"fr\": \"Bouton sans fil Aqara gen2 (Gateway)\",\n        \"it\": \"Pulsante wireless Aqara gen2 (Gateway)\",\n        \"no\": \"Aqara trådløs knapp gen2 (Gateway)\",\n        \"sv\": \"Aqara trådlös knapp gen2 (Gateway)\",\n        \"pl\": \"Bezprzewodowy przycisk Aqara gen2 (Gateway)\",\n        \"ru\": \"Беспроводная кнопка Aqara gen2 (Gateway)\",\n        \"ko\": \"아카라 무선 버튼 2세대 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-button-advanced/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-button-advanced/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2032\"\n        ]\n      },\n      \"id\": \"aqara-button-advanced\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-ctrl-ln1/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Smart Wall Single Switch With Neutral (Gateway)\",\n        \"nl\": \"Aqara Smart Wall Single Switch met nuldraad (Gateway)\",\n        \"da\": \"Aqara Smart Wall Single Switch med neutral (Gateway)\",\n        \"de\": \"Aqara Smart Wall Single Switch mit Neutralleiter (Gateway)\",\n        \"es\": \"Interruptor simple de pared inteligente Aqara con neutro (Gateway)\",\n        \"fr\": \"Interrupteur mural simple intelligent Aqara avec neutre (Gateway)\",\n        \"it\": \"Interruttore singolo da parete Aqara con neutro (Gateway)\",\n        \"no\": \"Aqara Smart veggbryter med nøytral (Gateway)\",\n        \"sv\": \"Aqara Smart Wall enkel brytare med neutral (Gateway)\",\n        \"pl\": \"Pojedynczy włącznik Aqara Smart Wall z neutralnym przewodem (Gateway)\",\n        \"ru\": \"Aqara умный настенный выключатель с нейтральным проводом (Gateway)\",\n        \"ko\": \"Aqara 스마트 벽 단일 스위치 중립선 포함 (Gateway)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-ctrl-ln1/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-ctrl-ln1/assets/images/small.png\"\n      },\n      \"class\": \"light\",\n      \"capabilities\": [\n        \"onoff\"\n      ],\n      \"id\": \"aqara-ctrl-ln1\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-ctrl-ln2/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Smart Wall Double Switch With Neutral (Gateway)\",\n        \"nl\": \"Aqara Smart Wall Double Switch met nuldraad (Gateway)\",\n        \"da\": \"Aqara Smart Wall Dobbeltkontakt med Neutral (Gateway)\",\n        \"de\": \"Aqara Smart Wall Doppelschalter mit Neutralleiter (Gateway)\",\n        \"es\": \"Interruptor Doble de Pared Inteligente Aqara con Neutro (Gateway)\",\n        \"fr\": \"Double Interrupteur Mural Intelligent Aqara avec Neutre (Gateway)\",\n        \"it\": \"Interruttore Doppio da Parete Intelligente Aqara con Neutro (Gateway)\",\n        \"no\": \"Aqara Smart Vegg Dobbelbryter med Nøytral (Gateway)\",\n        \"sv\": \"Aqara Smart Vägg Dubbelbrytare med Neutral (Gateway)\",\n        \"pl\": \"Aqara Inteligentny Podwójny Włącznik Ścienny z Przewodem Neutralnym (Gateway)\",\n        \"ru\": \"Aqara Умный Настенный Двойной Выключатель с Нулевым (Шлюз)\",\n        \"ko\": \"아카라 스마트 벽면 더블 스위치 중성선 포함 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-ctrl-ln2/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-ctrl-ln2/assets/images/small.png\"\n      },\n      \"class\": \"light\",\n      \"capabilities\": [\n        \"onoff.0\",\n        \"onoff.1\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.0\": {\n          \"title\": {\n            \"en\": \"Left button\",\n            \"nl\": \"Linkerknop\",\n            \"da\": \"Venstre knap\",\n            \"de\": \"Linker Knopf\",\n            \"es\": \"Botón izquierdo\",\n            \"fr\": \"Bouton gauche\",\n            \"it\": \"Pulsante sinistro\",\n            \"no\": \"Venstre knapp\",\n            \"sv\": \"Vänster knapp\",\n            \"pl\": \"Lewy przycisk\",\n            \"ru\": \"Левая кнопка\",\n            \"ko\": \"왼쪽 버튼\"\n          }\n        },\n        \"onoff.1\": {\n          \"title\": {\n            \"en\": \"Right button\",\n            \"nl\": \"Rechterknop\",\n            \"da\": \"Højre knap\",\n            \"de\": \"Rechter Knopf\",\n            \"es\": \"Botón derecho\",\n            \"fr\": \"Bouton droit\",\n            \"it\": \"Pulsante destro\",\n            \"no\": \"Høyre knapp\",\n            \"sv\": \"Höger knapp\",\n            \"pl\": \"Prawy przycisk\",\n            \"ru\": \"Правая кнопка\",\n            \"ko\": \"오른쪽 버튼\"\n          }\n        }\n      },\n      \"id\": \"aqara-ctrl-ln2\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-ctrl-neutral1/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Smart Wall Single Switch No Neutral (Gateway)\",\n        \"nl\": \"Aqara Smart Wall Single Switch zonder nuldraad (Gateway)\",\n        \"da\": \"Aqara Smart Wall Enkelt Switch Ingen Neutral (Gateway)\",\n        \"de\": \"Aqara Smart Wall Einzelner Schalter Ohne Neutralleiter (Gateway)\",\n        \"es\": \"Aqara Smart Wall Interruptor Único Sin Neutro (Gateway)\",\n        \"fr\": \"Aqara Smart Wall Interrupteur Simple Sans Neutre (Gateway)\",\n        \"it\": \"Aqara Smart Wall Interruttore Singolo Senza Neutro (Gateway)\",\n        \"no\": \"Aqara Smart Wall Enkel Bryter Ingen Nøytral (Gateway)\",\n        \"sv\": \"Aqara Smart Wall Enkel Switch Ingen Neutral (Gateway)\",\n        \"pl\": \"Aqara Smart Wall Pojedynczy Przełącznik Bez Neutralnego (Gateway)\",\n        \"ru\": \"Aqara Smart Wall Одинарный Выключатель Без Нейтрального Провода (Gateway)\",\n        \"ko\": \"Aqara Smart Wall 단일 스위치 중성선 없음 (Gateway)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-ctrl-neutral1/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-ctrl-neutral1/assets/images/small.png\"\n      },\n      \"class\": \"light\",\n      \"capabilities\": [\n        \"onoff\"\n      ],\n      \"id\": \"aqara-ctrl-neutral1\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuraciones del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-ctrl-neutral2/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Smart Wall Double Switch No Neutral (Gateway)\",\n        \"nl\": \"Aqara Smart Wall Double Switch zonder nuldraad (Gateway)\",\n        \"da\": \"Aqara Smart Væg Dobbeltafbryder Uden Neutral (Gateway)\",\n        \"de\": \"Aqara Smart Wanddoppelschalter Ohne Neutralleiter (Gateway)\",\n        \"es\": \"Interruptor Doble de Pared Inteligente Aqara Sin Neutro (Gateway)\",\n        \"fr\": \"Interrupteur Double Intelligent Aqara Sans Neutre (Gateway)\",\n        \"it\": \"Interruttore Doppio a Parete Intelligente Aqara Senza Neutro (Gateway)\",\n        \"no\": \"Aqara Smart Vegg Dobbel Bryter Uten Nøytral (Gateway)\",\n        \"sv\": \"Aqara Smart Vägg Dubbel Switch Utan Neutral (Gateway)\",\n        \"pl\": \"Aqara Smart Podwójny Włącznik Ścienny Bez N (Gateway)\",\n        \"ru\": \"Умный Настенный Двойной Выключатель Aqara Без Нейтрали (Шлюз)\",\n        \"ko\": \"아카라 스마트 벽 스위치 더블 무중성 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-ctrl-neutral2/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-ctrl-neutral2/assets/images/small.png\"\n      },\n      \"class\": \"light\",\n      \"capabilities\": [\n        \"onoff.0\",\n        \"onoff.1\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.0\": {\n          \"title\": {\n            \"en\": \"Left button\",\n            \"nl\": \"Linkerknop\",\n            \"da\": \"Venstre knap\",\n            \"de\": \"Linker Knopf\",\n            \"es\": \"Botón izquierdo\",\n            \"fr\": \"Bouton gauche\",\n            \"it\": \"Pulsante sinistro\",\n            \"no\": \"Venstre knapp\",\n            \"sv\": \"Vänster knapp\",\n            \"pl\": \"Lewy przycisk\",\n            \"ru\": \"Левая кнопка\",\n            \"ko\": \"왼쪽 버튼\"\n          }\n        },\n        \"onoff.1\": {\n          \"title\": {\n            \"en\": \"Right button\",\n            \"nl\": \"Rechterknop\",\n            \"da\": \"Højre knap\",\n            \"de\": \"Rechter Knopf\",\n            \"es\": \"Botón derecho\",\n            \"fr\": \"Bouton droit\",\n            \"it\": \"Pulsante destro\",\n            \"no\": \"Høyre knapp\",\n            \"sv\": \"Höger knapp\",\n            \"pl\": \"Prawy przycisk\",\n            \"ru\": \"Правая кнопка\",\n            \"ko\": \"오른쪽 버튼\"\n          }\n        }\n      },\n      \"id\": \"aqara-ctrl-neutral2\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-curtain/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Curtain Motor (Gateway)\",\n        \"nl\": \"Aqara gordijnmotor (Gateway)\",\n        \"da\": \"Aqara gardinmotor (Gateway)\",\n        \"de\": \"Aqara Vorhangmotor (Gateway)\",\n        \"es\": \"Motor de cortina Aqara (Gateway)\",\n        \"fr\": \"Moteur de rideau Aqara (Gateway)\",\n        \"it\": \"Motore per tende Aqara (Gateway)\",\n        \"no\": \"Aqara gardinmotor (Gateway)\",\n        \"sv\": \"Aqara gardinmotor (Gateway)\",\n        \"pl\": \"Silnik zasłonowy Aqara (Gateway)\",\n        \"ru\": \"Шторный мотор Aqara (Gateway)\",\n        \"ko\": \"아카라 커튼 모터 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-curtain/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-curtain/assets/images/small.png\"\n      },\n      \"class\": \"windowcoverings\",\n      \"capabilities\": [\n        \"onoff\",\n        \"dim\",\n        \"windowcoverings_state\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff\": {\n          \"title\": {\n            \"en\": \"Open Close\",\n            \"da\": \"Åbn Luk\",\n            \"de\": \"Öffnen Schließen\",\n            \"es\": \"Abrir Cerrar\",\n            \"fr\": \"Ouvrir Fermer\",\n            \"it\": \"Apri Chiudi\",\n            \"no\": \"Åpne Lukke\",\n            \"sv\": \"Öppna Stäng\",\n            \"pl\": \"Otwórz Zamknij\",\n            \"ru\": \"Открыть Закрыть\",\n            \"ko\": \"열기 닫기\"\n          },\n          \"greyout\": false\n        },\n        \"dim\": {\n          \"title\": {\n            \"en\": \"Level\",\n            \"da\": \"Niveau\",\n            \"de\": \"Pegel\",\n            \"es\": \"Nivel\",\n            \"fr\": \"Niveau\",\n            \"it\": \"Livello\",\n            \"no\": \"Nivå\",\n            \"sv\": \"Nivå\",\n            \"pl\": \"Poziom\",\n            \"ru\": \"Уровень\",\n            \"ko\": \"수준\"\n          }\n        }\n      },\n      \"id\": \"aqara-curtain\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User settings\",\n            \"nl\": \"Gebruikersinstellingen\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuraciones de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"inverted_mode\",\n              \"type\": \"checkbox\",\n              \"value\": false,\n              \"label\": {\n                \"en\": \"Inverted operation mode\",\n                \"nl\": \"Omgekeerde operatie modus\",\n                \"da\": \"Omvendt driftsindstilling\",\n                \"de\": \"Umgekehrter Betriebsmodus\",\n                \"es\": \"Modo de operación invertido\",\n                \"fr\": \"Mode de fonctionnement inversé\",\n                \"it\": \"Modalità operativa invertita\",\n                \"no\": \"Omvendt driftsmodus\",\n                \"sv\": \"Omvänd driftläge\",\n                \"pl\": \"Odwrócony tryb pracy\",\n                \"ru\": \"Инверсный режим работы\",\n                \"ko\": \"역운전 모드\"\n              }\n            },\n            {\n              \"id\": \"inverted_state\",\n              \"type\": \"checkbox\",\n              \"value\": false,\n              \"label\": {\n                \"en\": \"Inverted state\",\n                \"nl\": \"Omgekeerde status\",\n                \"da\": \"Omvendt tilstand\",\n                \"de\": \"Umgekehrter Zustand\",\n                \"es\": \"Estado invertido\",\n                \"fr\": \"État inversé\",\n                \"it\": \"Stato invertito\",\n                \"no\": \"Omvendt tilstand\",\n                \"sv\": \"Omvänd tillstånd\",\n                \"pl\": \"Odwrócony stan\",\n                \"ru\": \"Инверсное состояние\",\n                \"ko\": \"역상태\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-curtain-aq2/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Roller Shade Controller (Gateway)\",\n        \"nl\": \"Aqara Roller Shade Controller (Gateway)\",\n        \"da\": \"Aqara Rullegardin Controller (Gateway)\",\n        \"de\": \"Aqara Rollo-Controller (Gateway)\",\n        \"es\": \"Controlador de Persiana Enrollable Aqara (Gateway)\",\n        \"fr\": \"Contrôleur de Store Enrouleur Aqara (Gateway)\",\n        \"it\": \"Controllore Tapparella Aqara (Gateway)\",\n        \"no\": \"Aqara Rullgardin Kontroller (Gateway)\",\n        \"sv\": \"Aqara Rullgardinskontroll (Gateway)\",\n        \"pl\": \"Sterownik Rolet Aqara (Gateway)\",\n        \"ru\": \"Контроллер роликовых штор Aqara (Gateway)\",\n        \"ko\": \"아카라 롤러 셰이드 컨트롤러 (Gateway)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-curtain-aq2/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-curtain-aq2/assets/images/small.png\"\n      },\n      \"class\": \"windowcoverings\",\n      \"capabilities\": [\n        \"onoff\",\n        \"dim\",\n        \"windowcoverings_state\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff\": {\n          \"title\": {\n            \"en\": \"Open Close\",\n            \"da\": \"Åben Luk\",\n            \"de\": \"Öffnen Schließen\",\n            \"es\": \"Abrir Cerrar\",\n            \"fr\": \"Ouvrir Fermer\",\n            \"it\": \"Apri Chiudi\",\n            \"no\": \"Åpne Lukk\",\n            \"sv\": \"Öppna Stäng\",\n            \"pl\": \"Otwórz Zamknij\",\n            \"ru\": \"Открыть Закрыть\",\n            \"ko\": \"열기 닫기\"\n          },\n          \"greyout\": false\n        },\n        \"dim\": {\n          \"title\": {\n            \"en\": \"Level\",\n            \"da\": \"Niveau\",\n            \"de\": \"Niveau\",\n            \"es\": \"Nivel\",\n            \"fr\": \"Niveau\",\n            \"it\": \"Livello\",\n            \"no\": \"Nivå\",\n            \"sv\": \"Nivå\",\n            \"pl\": \"Poziom\",\n            \"ru\": \"Уровень\",\n            \"ko\": \"수준\"\n          }\n        }\n      },\n      \"id\": \"aqara-curtain-aq2\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User settings\",\n            \"nl\": \"Gebruikersinstellingen\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"inverted_mode\",\n              \"type\": \"checkbox\",\n              \"value\": false,\n              \"label\": {\n                \"en\": \"Inverted operation mode\",\n                \"nl\": \"Omgekeerde operatie modus\",\n                \"da\": \"Omvendt driftstilstand\",\n                \"de\": \"Umgekehrter Betriebsmodus\",\n                \"es\": \"Modo de operación inverso\",\n                \"fr\": \"Mode de fonctionnement inversé\",\n                \"it\": \"Modalità di funzionamento invertita\",\n                \"no\": \"Omvendt driftmodus\",\n                \"sv\": \"Inverterat driftläge\",\n                \"pl\": \"Odwrócony tryb pracy\",\n                \"ru\": \"Обратный режим работы\",\n                \"ko\": \"역방향 작동 모드\"\n              }\n            },\n            {\n              \"id\": \"inverted_state\",\n              \"type\": \"checkbox\",\n              \"value\": false,\n              \"label\": {\n                \"en\": \"Inverted state\",\n                \"nl\": \"Omgekeerde status\",\n                \"da\": \"Omvendt tilstand\",\n                \"de\": \"Umgekehrter Zustand\",\n                \"es\": \"Estado invertido\",\n                \"fr\": \"État inversé\",\n                \"it\": \"Stato invertito\",\n                \"no\": \"Omvendt tilstand\",\n                \"sv\": \"Inverterat tillstånd\",\n                \"pl\": \"Odwrócony stan\",\n                \"ru\": \"Обратное состояние\",\n                \"ko\": \"역방향 상태\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-magnet-sensor/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Magnet Sensor (Gateway)\",\n        \"nl\": \"Aqara magneetsensor (Gateway)\",\n        \"da\": \"Aqara Magnet Sensor (Gateway)\",\n        \"de\": \"Aqara Magnetsensor (Gateway)\",\n        \"es\": \"Sensor Magnético Aqara (Gateway)\",\n        \"fr\": \"Capteur Magnétique Aqara (Gateway)\",\n        \"it\": \"Sensore Magnetico Aqara (Gateway)\",\n        \"no\": \"Aqara Magnet Sensor (Gateway)\",\n        \"sv\": \"Aqara Magnet Sensor (Gateway)\",\n        \"pl\": \"Czujnik Magnetyczny Aqara (Gateway)\",\n        \"ru\": \"Магнитный Датчик Aqara (Gateway)\",\n        \"ko\": \"아카라 자석 센서 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-magnet-sensor/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-magnet-sensor/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"alarm_contact\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR1632\"\n        ]\n      },\n      \"id\": \"aqara-magnet-sensor\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User settings\",\n            \"nl\": \"Gebruikersinstellingen\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"inverted\",\n              \"type\": \"checkbox\",\n              \"label\": {\n                \"en\": \"Inverted alarm\",\n                \"nl\": \"Omgekeerd alarm\",\n                \"da\": \"Omvendt alarm\",\n                \"de\": \"Invertierter Alarm\",\n                \"es\": \"Alarma invertida\",\n                \"fr\": \"Alarme inversée\",\n                \"it\": \"Allarme invertito\",\n                \"no\": \"Omvendt alarm\",\n                \"sv\": \"Omvänt larm\",\n                \"pl\": \"Odwrócony alarm\",\n                \"ru\": \"Инвертированная тревога\",\n                \"ko\": \"역방향 알람\"\n              },\n              \"value\": false\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres du dispositif\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-motion-sensor/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Motion Sensor (Gateway)\",\n        \"nl\": \"Aqara bewegingssensor (Gateway)\",\n        \"da\": \"Aqara Bevægelsessensor (Gateway)\",\n        \"de\": \"Aqara Bewegungssensor (Gateway)\",\n        \"es\": \"Sensor de Movimiento Aqara (Gateway)\",\n        \"fr\": \"Capteur de Mouvement Aqara (Gateway)\",\n        \"it\": \"Sensore di Movimento Aqara (Gateway)\",\n        \"no\": \"Aqara Bevegelsessensor (Gateway)\",\n        \"sv\": \"Aqara Rörelsesensor (Gateway)\",\n        \"pl\": \"Czujnik Ruchu Aqara (Gateway)\",\n        \"ru\": \"Датчик движения Aqara (Gateway)\",\n        \"ko\": \"아카라 모션 센서 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-motion-sensor/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-motion-sensor/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"alarm_motion\",\n        \"measure_luminance\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2450\"\n        ]\n      },\n      \"id\": \"aqara-motion-sensor\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Duration of the motion alarm\",\n            \"nl\": \"Duur van het bewegingsalarm\",\n            \"da\": \"Varighed af bevægelsesalarm\",\n            \"de\": \"Dauer des Bewegungsalarms\",\n            \"es\": \"Duración de la alarma de movimiento\",\n            \"fr\": \"Durée de l'alarme de mouvement\",\n            \"it\": \"Durata dell'allarme di movimento\",\n            \"no\": \"Varighet på bevegelsesalarmen\",\n            \"sv\": \"Varaktighet för rörelselarmet\",\n            \"pl\": \"Czas trwania alarmu ruchu\",\n            \"ru\": \"Продолжительность сигнализации движения\",\n            \"ko\": \"움직임 경보 기간\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_duration_number\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Disable after\",\n                \"nl\": \"Uitschakelen na\",\n                \"da\": \"Deaktiver efter\",\n                \"de\": \"Deaktivieren nach\",\n                \"es\": \"Desactivar después de\",\n                \"fr\": \"Désactiver après\",\n                \"it\": \"Disabilita dopo\",\n                \"no\": \"Deaktiver etter\",\n                \"sv\": \"Inaktivera efter\",\n                \"pl\": \"Wyłącz po\",\n                \"ru\": \"Отключить через\",\n                \"ko\": \"다음 후 비활성화\"\n              },\n              \"hint\": {\n                \"en\": \"Here you can specify after what time the alarm signal from the motion sensor will be stopped, if a motion is detected it is not detected. Usually this is for 60 seconds, you can set from 5 to 86400 seconds. \\n \\n Attention! Values less than 60 seconds are relevant only for independently modified sensors that have the ability to transmit information about the movement with a frequency of 5 seconds.\",\n                \"nl\": \"Hier kunt u opgeven hoe laat het alarmsignaal van de bewegingssensor wordt gestopt, als een beweging wordt gedetecteerd, wordt deze niet gedetecteerd. Gewoonlijk is dit 60 seconden, u kunt 5 tot 86400 seconden instellen.  n  n Let op! Waarden minder dan 60 seconden zijn alleen relevant voor onafhankelijk aangepaste sensoren die de mogelijkheid hebben om informatie over de beweging te verzenden met een frequentie van 5 seconden.\",\n                \"da\": \"Her kan du specificere, hvornår alarmsignalet fra bevægelsessensorer vil blive stoppet, hvis en bevægelse detekteres, men ikke bliver detekteret. Normalt er dette 60 sekunder, du kan indstille fra 5 til 86400 sekunder. \\n \\n Opmærksomhed! Værdier mindre end 60 sekunder er kun relevante for uafhængigt modificerede sensorer, der har mulighed for at sende information om bevægelsen med en frekvens på 5 sekunder.\",\n                \"de\": \"Hier können Sie angeben, nach welcher Zeit das Alarmsignal des Bewegungssensors gestoppt wird, wenn eine Bewegung erkannt wird, sie jedoch nicht erkannt wird. Normalerweise liegt dieser Wert bei 60 Sekunden, Sie können von 5 bis 86400 Sekunden einstellen. \\n \\n Achtung! Werte unter 60 Sekunden sind nur für unabhängig modifizierte Sensoren relevant, die die Fähigkeit haben, Informationen über die Bewegung mit einer Frequenz von 5 Sekunden zu übertragen.\",\n                \"es\": \"Aquí puedes especificar después de cuánto tiempo se detendrá la señal de alarma del sensor de movimiento, si se detecta un movimiento no se detecta. Normalmente esto es de 60 segundos, puedes establecer desde 5 hasta 86400 segundos. \\n \\n ¡Atención! Los valores inferiores a 60 segundos solo son relevantes para sensores modificados independientemente que tienen la capacidad de transmitir información sobre el movimiento con una frecuencia de 5 segundos.\",\n                \"fr\": \"Ici, vous pouvez spécifier après combien de temps le signal d'alarme du capteur de mouvement sera arrêté, si un mouvement est détecté, il n'est pas détecté. En général, cela dure 60 secondes, vous pouvez régler de 5 à 86400 secondes. \\n \\n Attention ! Les valeurs inférieures à 60 secondes ne sont pertinentes que pour les capteurs modifiés indépendamment qui ont la capacité de transmettre des informations sur le mouvement avec une fréquence de 5 secondes.\",\n                \"it\": \"Qui puoi specificare dopo quanto tempo il segnale di allarme dal sensore di movimento verrà interrotto, se un movimento viene rilevato non viene rilevato. Di solito questo è per 60 secondi, puoi impostare da 5 a 86400 secondi. \\n \\n Attenzione! I valori inferiori a 60 secondi sono rilevanti solo per i sensori modificati indipendentemente che hanno la capacità di trasmettere informazioni sul movimento con una frequenza di 5 secondi.\",\n                \"no\": \"Her kan du spesifisere etter hvor lang tid alarmsignalet fra bevegelsessensoren vil bli stoppet, dersom en bevegelse er detektert blir det ikke detektert. Vanligvis er dette for 60 sekunder, du kan sette fra 5 til 86400 sekunder. \\n \\n Oppmerksomhet! Verdier mindre enn 60 sekunder er kun relevant for uavhengig modifiserte sensorer som har muligheten til å sende informasjon om bevegelsen med en frekvens på 5 sekunder.\",\n                \"sv\": \"Här kan du specificera efter vilken tid alarmsignalen från rörelsesensorn ska stoppas, om en rörelse detekteras detekteras den inte. Vanligtvis är detta för 60 sekunder, du kan ställa in från 5 till 86400 sekunder. \\n \\n Uppmärksamhet! Värden mindre än 60 sekunder är endast relevanta för oberoende modifierade sensorer som har förmågan att skicka information om rörelsen med en frekvens på 5 sekunder.\",\n                \"pl\": \"Tutaj możesz określić, po jakim czasie sygnał alarmowy z czujnika ruchu zostanie zatrzymany, jeśli ruch jest wykrywany, ale nie jest wykrywany. Zwykle jest to 60 sekund, można ustawić od 5 do 86400 sekund. \\n \\n Uwaga! Wartości mniejsze niż 60 sekund są istotne tylko dla niezależnie zmodyfikowanych czujników, które mają możliwość przesyłania informacji o ruchu z częstotliwością 5 sekund.\",\n                \"ru\": \"Здесь вы можете указать, через какое время будет прекращен сигнал тревоги от датчика движения, если обнаружено движение. Обычно это 60 секунд, вы можете настроить от 5 до 86400 секунд. \\n \\n Внимание! Значения менее 60 секунд имеют значение только для независимо модифицированных датчиков, которые имеют возможность передавать информацию о движении с частотой 5 секунд.\",\n                \"ko\": \"여기에서 움직임이 감지된 후 모션 센서의 경보 신호가 중지되어야 하는 시간을 지정할 수 있습니다. 일반적으로 이것은 60초입니다. 5 ~ 86400초 사이에서 설정할 수 있습니다. \\n \\n 주의! 60초 미만의 값은 5초 간격으로 움직임에 관한 정보를 전송할 수 있는 독립적으로 수정된 센서에만 관련이 있습니다.\"\n              },\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 86400\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuraciones del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-temperature-humidity-sensor/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Temperature & Humidity Sensor (Gateway)\",\n        \"nl\": \"Aqara temperatuur & luchtvochtigheid sensor (Gateway)\",\n        \"da\": \"Aqara Temperatur- og Fugtighedssensor (Gateway)\",\n        \"de\": \"Aqara Temperatur- und Feuchtigkeitssensor (Gateway)\",\n        \"es\": \"Sensor de temperatura y humedad Aqara (Gateway)\",\n        \"fr\": \"Capteur de température et d'humidité Aqara (Gateway)\",\n        \"it\": \"Sensore di temperatura e umidità Aqara (Gateway)\",\n        \"no\": \"Aqara temperatur- og fuktighetssensor (Gateway)\",\n        \"sv\": \"Aqara temperatur- och fuktighetssensor (Gateway)\",\n        \"pl\": \"Czujnik temperatury i wilgotności Aqara (Gateway)\",\n        \"ru\": \"Датчик температуры и влажности Aqara (Gateway)\",\n        \"ko\": \"아카라 온습도 센서 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-temperature-humidity-sensor/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-temperature-humidity-sensor/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"measure_temperature\",\n        \"measure_humidity\",\n        \"measure_pressure\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2032\"\n        ]\n      },\n      \"id\": \"aqara-temperature-humidity-sensor\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Offset settings\",\n            \"nl\": \"Offset instellingen\",\n            \"da\": \"Offset-indstillinger\",\n            \"de\": \"Offset-Einstellungen\",\n            \"es\": \"Configuración de compensación\",\n            \"fr\": \"Paramètres de décalage\",\n            \"it\": \"Impostazioni di offset\",\n            \"no\": \"Offset-innstillinger\",\n            \"sv\": \"Offset-inställningar\",\n            \"pl\": \"Ustawienia przesunięcia\",\n            \"ru\": \"Настройки смещения\",\n            \"ko\": \"오프셋 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"addOrTakeOffset\",\n              \"type\": \"radio\",\n              \"label\": {\n                \"en\": \"Offset\",\n                \"nl\": \"Offset\",\n                \"da\": \"Offset\",\n                \"de\": \"Offset\",\n                \"es\": \"Compensación\",\n                \"fr\": \"Décalage\",\n                \"it\": \"Offset\",\n                \"no\": \"Offset\",\n                \"sv\": \"Offset\",\n                \"pl\": \"Offset\",\n                \"ru\": \"Смещение\",\n                \"ko\": \"오프셋\"\n              },\n              \"value\": \"add\",\n              \"values\": [\n                {\n                  \"id\": \"add\",\n                  \"label\": {\n                    \"en\": \"Add offset\",\n                    \"nl\": \"Offset toevoegen\",\n                    \"da\": \"Tilføj offset\",\n                    \"de\": \"Offset hinzufügen\",\n                    \"es\": \"Añadir compensación\",\n                    \"fr\": \"Ajouter un décalage\",\n                    \"it\": \"Aggiungi offset\",\n                    \"no\": \"Legg til offset\",\n                    \"sv\": \"Lägg till offset\",\n                    \"pl\": \"Dodaj offset\",\n                    \"ru\": \"Добавить смещение\",\n                    \"ko\": \"오프셋 추가\"\n                  }\n                },\n                {\n                  \"id\": \"take\",\n                  \"label\": {\n                    \"en\": \"Minus offset\",\n                    \"nl\": \"Offset verminderen\",\n                    \"da\": \"Minus offset\",\n                    \"de\": \"Offset abziehen\",\n                    \"es\": \"Restar compensación\",\n                    \"fr\": \"Moins offset\",\n                    \"it\": \"Sottrai offset\",\n                    \"no\": \"Minus offset\",\n                    \"sv\": \"Minus offset\",\n                    \"pl\": \"Minus offset\",\n                    \"ru\": \"Минус смещение\",\n                    \"ko\": \"오프셋 빼기\"\n                  }\n                }\n              ]\n            },\n            {\n              \"id\": \"offset\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Offset\",\n                \"nl\": \"Offset\",\n                \"da\": \"Offset\",\n                \"de\": \"Offset\",\n                \"es\": \"Compensación\",\n                \"fr\": \"Décalage\",\n                \"it\": \"Offset\",\n                \"no\": \"Offset\",\n                \"sv\": \"Offset\",\n                \"pl\": \"Offset\",\n                \"ru\": \"Смещение\",\n                \"ko\": \"오프셋\"\n              },\n              \"value\": 0,\n              \"min\": 0,\n              \"max\": 5\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara-wleak-sensor/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Waterleak Sensor (Gateway)\",\n        \"nl\": \"Aqara waterlek sensor (Gateway)\",\n        \"da\": \"Aqara Vandlækagesensor (Gateway)\",\n        \"de\": \"Aqara Wasseraustrittsensor (Gateway)\",\n        \"es\": \"Sensor de fugas de agua Aqara (Gateway)\",\n        \"fr\": \"Capteur de fuite d'eau Aqara (Gateway)\",\n        \"it\": \"Sensore di perdita d'acqua Aqara (Gateway)\",\n        \"no\": \"Aqara Vannlekkasjesensor (Gateway)\",\n        \"sv\": \"Aqara Vattenläckagesensor (Gateway)\",\n        \"pl\": \"Czujnik wycieku wody Aqara (Gateway)\",\n        \"ru\": \"Датчик утечки воды Aqara (Gateway)\",\n        \"ko\": \"아카라 물 누수 센서 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara-wleak-sensor/assets/images/large.png\",\n        \"small\": \"/drivers/aqara-wleak-sensor/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"alarm_water\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2032\"\n        ]\n      },\n      \"id\": \"aqara-wleak-sensor\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"기기 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara_86sw1_switch/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Wireless Wall Single Switch (Gateway)\",\n        \"nl\": \"Aqara Wireless Wall Single Switch (Gateway)\",\n        \"da\": \"Aqara trådløs væg enkeltkontakt (gateway)\",\n        \"de\": \"Aqara kabelloser Wandschalter (Gateway)\",\n        \"es\": \"Interruptor de pared inalámbrico Aqara (Gateway)\",\n        \"fr\": \"Interrupteur mural sans fil Aqara (Gateway)\",\n        \"it\": \"Interruttore singolo a parete wireless Aqara (Gateway)\",\n        \"no\": \"Aqara trådløs vegg enkel bryter (gateway)\",\n        \"sv\": \"Aqara trådlös väggbrytare (gateway)\",\n        \"pl\": \"Aqara bezprzewodowy przełącznik ścienny (bramka)\",\n        \"ru\": \"Беспроводной настенный однокнопочный выключатель Aqara (шлюз)\",\n        \"ko\": \"아카라 무선 벽 단일 스위치 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara_86sw1_switch/assets/images/large.jpg\",\n        \"small\": \"/drivers/aqara_86sw1_switch/assets/images/small.jpg\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2032\"\n        ]\n      },\n      \"id\": \"aqara_86sw1_switch\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/aqara_86sw2_switch/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Wireless Wall Double Switch (Gateway)\",\n        \"nl\": \"Aqara Wireless Wall Double Switch (Gateway)\",\n        \"da\": \"Aqara Trådløs Væg Dobbeltkontakt (Gateway)\",\n        \"de\": \"Aqara Funk-Wandschalter Doppelt (Gateway)\",\n        \"es\": \"Interruptor Doble de Pared Inalámbrico Aqara (Gateway)\",\n        \"fr\": \"Interrupteur Double sans Fil Aqara (Gateway)\",\n        \"it\": \"Interruttore da Parete Wireless Doppio Aqara (Gateway)\",\n        \"no\": \"Aqara Trådløs Vegg Dobbel Bryter (Gateway)\",\n        \"sv\": \"Aqara Trådlös Väggdubbla Strömbrytare (Gateway)\",\n        \"pl\": \"Aqara Bezprzewodowy Podwójny Przełącznik Ścienny (Gateway)\",\n        \"ru\": \"Беспроводной Двойной Настенный Выключатель Aqara (Gateway)\",\n        \"ko\": \"아카라 무선 벽 이중 스위치 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/aqara_86sw2_switch/assets/images/large.jpg\",\n        \"small\": \"/drivers/aqara_86sw2_switch/assets/images/small.jpg\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2032\"\n        ]\n      },\n      \"id\": \"aqara_86sw2_switch\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"pt\": \"Configurações do Dispositivo\",\n            \"zh\": \"设备设置\",\n            \"ja\": \"デバイス設定\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/clothesdryer_hyd_airer_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mijia Smart Clothes Drying Rack MIoT (WiFi)\",\n        \"nl\": \"Slim Mijia Droogrek MIoT (WiFi)\",\n        \"da\": \"Mijia Smart Tørrerist MIoT (WiFi)\",\n        \"de\": \"Mijia Smarter Wäscheständer MIoT (WiFi)\",\n        \"es\": \"Mijia Estante de Secado Inteligente MIoT (WiFi)\",\n        \"fr\": \"Séchoir à vêtements intelligent Mijia MIoT (WiFi)\",\n        \"it\": \"Stendibiancheria Intelligente Mijia MIoT (WiFi)\",\n        \"no\": \"Mijia Smart Tørkestativ MIoT (WiFi)\",\n        \"sv\": \"Mijia Smart Klädtorkställning MIoT (WiFi)\",\n        \"pl\": \"Mijia Inteligentny Wieszaki Suszarki MIoT (WiFi)\",\n        \"ru\": \"Умная сушилка для одежды Mijia MIoT (WiFi)\",\n        \"ko\": \"미지아 스마트 건조대 MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/clothesdryer_hyd_airer_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/clothesdryer_hyd_airer_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"onoff\",\n        \"windowcoverings_state\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff\": {\n          \"title\": {\n            \"en\": \"Light\",\n            \"nl\": \"Licht\",\n            \"da\": \"Lys\",\n            \"de\": \"Licht\",\n            \"es\": \"Luz\",\n            \"fr\": \"Lumière\",\n            \"it\": \"Luce\",\n            \"no\": \"Lys\",\n            \"sv\": \"Ljus\",\n            \"pl\": \"Światło\",\n            \"ru\": \"Свет\",\n            \"ko\": \"빛\"\n          }\n        },\n        \"windowcoverings_state\": {\n          \"title\": {\n            \"en\": \"Position\",\n            \"nl\": \"Positie\",\n            \"da\": \"Position\",\n            \"de\": \"Position\",\n            \"es\": \"Posición\",\n            \"fr\": \"Position\",\n            \"it\": \"Posizione\",\n            \"no\": \"Posisjon\",\n            \"sv\": \"Position\",\n            \"pl\": \"Pozycja\",\n            \"ru\": \"Позиция\",\n            \"ko\": \"위치\"\n          }\n        }\n      },\n      \"id\": \"clothesdryer_hyd_airer_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"Светодиод\",\n                \"ko\": \"LED\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device data\",\n            \"nl\": \"Apparaat data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"장치 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"error\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Error\",\n                \"nl\": \"Error\",\n                \"da\": \"Fejl\",\n                \"de\": \"Fehler\",\n                \"es\": \"Error\",\n                \"fr\": \"Erreur\",\n                \"it\": \"Errore\",\n                \"no\": \"Feil\",\n                \"sv\": \"Fel\",\n                \"pl\": \"Błąd\",\n                \"ru\": \"Ошибка\",\n                \"ko\": \"오류\"\n              },\n              \"value\": \"No error\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"기기 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/ctrl_86plug_aq1/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Wall Outlet (Gateway)\",\n        \"nl\": \"Aqara Wall Outlet (Gateway)\",\n        \"da\": \"Aqara Vægudtag (Gateway)\",\n        \"de\": \"Aqara Wandsteckdose (Gateway)\",\n        \"es\": \"Aqara Toma de Pared (Gateway)\",\n        \"fr\": \"Prise Murale Aqara (Gateway)\",\n        \"it\": \"Presa da Muro Aqara (Gateway)\",\n        \"no\": \"Aqara Veggkontakt (Gateway)\",\n        \"sv\": \"Aqara Vägguttag (Gateway)\",\n        \"pl\": \"Gniazdko Ścienne Aqara (Gateway)\",\n        \"ru\": \"Настенная Розетка Aqara (Gateway)\",\n        \"ko\": \"아카라 벽면 콘센트 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/ctrl_86plug_aq1/assets/images/large.jpg\",\n        \"small\": \"/drivers/ctrl_86plug_aq1/assets/images/small.jpg\"\n      },\n      \"class\": \"light\",\n      \"capabilities\": [\n        \"onoff\",\n        \"meter_power\",\n        \"measure_power\"\n      ],\n      \"id\": \"ctrl_86plug_aq1\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"pt\": \"Configurações do dispositivo\",\n            \"ja\": \"デバイス設定\",\n            \"zh\": \"设备设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/dehumidifier_dmaker_derh_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n        \"nl\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n        \"da\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n        \"de\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n        \"es\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n        \"fr\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n        \"it\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n        \"no\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n        \"sv\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n        \"pl\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n        \"ru\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n        \"ko\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/dehumidifier_dmaker_derh_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/dehumidifier_dmaker_derh_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"dehumidifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"dehumidifier_dmaker_mode\",\n        \"target_humidity\",\n        \"measure_humidity\",\n        \"measure_temperature\",\n        \"alarm_water\"\n      ],\n      \"capabilitiesOptions\": {\n        \"target_humidity\": {\n          \"min\": 0.4,\n          \"max\": 0.8\n        },\n        \"alarm_water\": {\n          \"title\": {\n            \"en\": \"Water Tank Full\",\n            \"nl\": \"Watertank vol\",\n            \"da\": \"Vandtank fuld\",\n            \"de\": \"Wassertank voll\",\n            \"es\": \"Depósito de agua lleno\",\n            \"fr\": \"Réservoir d'eau plein\",\n            \"it\": \"Serbatoio dell'acqua pieno\",\n            \"no\": \"Vanntank full\",\n            \"sv\": \"Vattentank full\",\n            \"pl\": \"Zbiornik wody pełny\",\n            \"ru\": \"Резервуар для воды заполнен\",\n            \"ko\": \"물탱크 가득 참\"\n          }\n        }\n      },\n      \"id\": \"dehumidifier_dmaker_derh_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración del usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"LED\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summer\",\n                \"de\": \"Summer\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Vibreur\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Summerton\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Buzer\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"부저\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnelås\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo infantil\",\n                \"fr\": \"Verrouillage enfants\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barnelås\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada dla dzieci\",\n                \"ru\": \"Блокировка от детей\",\n                \"ko\": \"잠금 기능\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device data\",\n            \"nl\": \"Apparaat data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"장치 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"error\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Error\",\n                \"nl\": \"Error\",\n                \"da\": \"Fejl\",\n                \"de\": \"Fehler\",\n                \"es\": \"Error\",\n                \"fr\": \"Erreur\",\n                \"it\": \"Errore\",\n                \"no\": \"Feil\",\n                \"sv\": \"Fel\",\n                \"pl\": \"Błąd\",\n                \"ru\": \"Ошибка\",\n                \"ko\": \"오류\"\n              },\n              \"value\": \"No error\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/diffuser_xwhzp_diffuser_xwxfj/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mijia Smart Scent Diffuser (WiFi)\",\n        \"nl\": \"Mijia Smart Geurverspreider (WiFi)\",\n        \"da\": \"Mijia Smart Duftdiffuser (WiFi)\",\n        \"de\": \"Mijia Smart Duftdiffusor (WiFi)\",\n        \"es\": \"Difusor Aromatico Inteligente Mijia (WiFi)\",\n        \"fr\": \"Diffuseur de parfum intelligent Mijia (WiFi)\",\n        \"it\": \"Diffusore di fragranze smart Mijia (WiFi)\",\n        \"no\": \"Mijia Smart duftspreder (WiFi)\",\n        \"sv\": \"Mijia Smart doftspridare (WiFi)\",\n        \"pl\": \"Inteligentny dyfuzor zapachu Mijia (WiFi)\",\n        \"ru\": \"Mijia smart aroma-diffuser (WiFi)\",\n        \"ko\": \"Mijia smart scent diffuser (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/diffuser_xwhzp_diffuser_xwxfj/assets/images/large.jpg\",\n        \"small\": \"drivers/diffuser_xwhzp_diffuser_xwxfj/assets/images/small.jpg\"\n      },\n      \"class\": \"humidifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"diffuser_xwhzp_mode\",\n        \"diffuser_xwhzp_fragrance_out_time\",\n        \"dim\",\n        \"light_hue\",\n        \"light_saturation\",\n        \"measure_waterlevel\",\n        \"alarm_tank_empty\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"capabilitiesOptions\": {\n        \"dim\": {\n          \"title\": {\n            \"en\": \"Ambient light brightness\",\n            \"nl\": \"Helderheid sfeerverlichting\",\n            \"da\": \"Lysstyrke for stemningslys\",\n            \"de\": \"Helligkeit des Umgebungslichts\",\n            \"es\": \"Brillo de luz ambiental\",\n            \"fr\": \"Luminosite de la lumiere d'ambiance\",\n            \"it\": \"Luminosita luce ambiente\",\n            \"no\": \"Lysstyrke for stemningslys\",\n            \"sv\": \"Ljusstyrka for omgivningsljus\",\n            \"pl\": \"Jasnosc oswietlenia ambientowego\",\n            \"ru\": \"Yarkost ambientnogo osveshcheniya\",\n            \"ko\": \"ambient light brightness\"\n          }\n        },\n        \"diffuser_xwhzp_fragrance_out_time\": {\n          \"min\": 30,\n          \"max\": 120,\n          \"step\": 10\n        }\n      },\n      \"energy\": {\n        \"batteries\": [\n          \"INTERNAL\"\n        ]\n      },\n      \"id\": \"diffuser_xwhzp_diffuser_xwxfj\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"ja\": \"デバイス設定\",\n            \"zh\": \"设备设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/dmaker-fan/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Basic  Mi Smart Fan Generic (WiFi)\",\n        \"nl\": \"Basic Mi Smart Fan Generic (WiFi)\",\n        \"da\": \"Basis Mi Smart Fan Generic (WiFi)\",\n        \"de\": \"Basis Mi Smart Fan Generic (WiFi)\",\n        \"es\": \"Básico Mi Smart Fan Genérico (WiFi)\",\n        \"fr\": \"Basique Mi Smart Fan Générique (WiFi)\",\n        \"it\": \"Base Mi Smart Fan Generico (WiFi)\",\n        \"no\": \"Grunnleggende Mi Smart Fan Generic (WiFi)\",\n        \"sv\": \"Grundläggande Mi Smart Fan Generic (WiFi)\",\n        \"pl\": \"Podstawowy Mi Smart Fan Generic (WiFi)\",\n        \"ru\": \"Основной Mi Smart Fan Generic (WiFi)\",\n        \"ko\": \"베이직 Mi Smart Fan Generic (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/dmaker-fan/assets/images/large.jpg\",\n        \"small\": \"drivers/dmaker-fan/assets/images/small.jpg\"\n      },\n      \"class\": \"fan\",\n      \"capabilities\": [\n        \"onoff\"\n      ],\n      \"id\": \"dmaker-fan\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/fan_dmaker_advanced/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Advanced Mi Smart Standing Fan MIoT (WiFi)\",\n        \"nl\": \"Geadvanceerde Mi Smart Standing Fan MIoT (WiFi)\",\n        \"da\": \"Avanceret Mi Smart Standing Fan MIoT (WiFi)\",\n        \"de\": \"Erweiterter Mi Smart Standventilator MIoT (WiFi)\",\n        \"es\": \"Ventilador de pie avanzado Mi Smart MIoT (WiFi)\",\n        \"fr\": \"Ventilateur sur pied intelligent Mi avancé MIoT (WiFi)\",\n        \"it\": \"Ventilatore Smart Standing avanzato Mi MIoT (WiFi)\",\n        \"no\": \"Avansert Mi Smart stående vifte MIoT (WiFi)\",\n        \"sv\": \"Avancerad Mi Smart stående fläkt MIoT (WiFi)\",\n        \"pl\": \"Zaawansowany stojący wentylator Mi Smart MIoT (WiFi)\",\n        \"ru\": \"Продвинутый Mi Smart стоячий вентилятор MIoT (WiFi)\",\n        \"ko\": \"고급형 Mi 스마트 스탠딩 팬 MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/fan_dmaker_advanced/assets/images/large.jpg\",\n        \"small\": \"drivers/fan_dmaker_advanced/assets/images/small.jpg\"\n      },\n      \"class\": \"fan\",\n      \"capabilities\": [\n        \"onoff\",\n        \"oscillating\",\n        \"dim\",\n        \"fan_zhimi_angle\",\n        \"fan_speed\",\n        \"fan_dmaker_mode\"\n      ],\n      \"capabilitiesOptions\": {\n        \"dim\": {\n          \"title\": {\n            \"en\": \"Fanlevel\",\n            \"nl\": \"Ventilator niveau\",\n            \"da\": \"Fan niveau\",\n            \"de\": \"Ventilatorebene\",\n            \"es\": \"Nivel de ventilador\",\n            \"fr\": \"Niveau de ventilateur\",\n            \"it\": \"Livello del ventilatore\",\n            \"no\": \"Viftenivå\",\n            \"sv\": \"Fläktnivå\",\n            \"pl\": \"Poziom wentylatora\",\n            \"ru\": \"Уровень вентилятора\",\n            \"ko\": \"팬 레벨\"\n          },\n          \"min\": 1,\n          \"max\": 4,\n          \"step\": 1\n        }\n      },\n      \"id\": \"fan_dmaker_advanced\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de Usuario\",\n            \"fr\": \"Paramètres Utilisateur\",\n            \"it\": \"Impostazioni Utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia Użytkownika\",\n            \"ru\": \"Пользовательские настройки\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"Светодиод\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summer\",\n                \"de\": \"Summer\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Buzzer\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Summer\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Brzęczyk\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"버저\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnelås\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo para Niños\",\n                \"fr\": \"Verrouillage Enfant\",\n                \"it\": \"Blocco Bambino\",\n                \"no\": \"Barnesikring\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada rodzicielska\",\n                \"ru\": \"Блокировка от детей\",\n                \"ko\": \"차일드 락\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del Dispositivo\",\n            \"fr\": \"Paramètres de l'Appareil\",\n            \"it\": \"Impostazioni del Dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia Urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/fan_zhimi_advanced/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Advanced Smartmi/ZhiMi Fan (WiFi)\",\n        \"nl\": \"Geadvanceerde Smartmi/ZhiMi Fan (WiFi)\",\n        \"da\": \"Avanceret Smartmi/ZhiMi Fan (WiFi)\",\n        \"de\": \"Erweiterter Smartmi/ZhiMi Ventilator (WiFi)\",\n        \"es\": \"Ventilador Smartmi/ZhiMi Avanzado (WiFi)\",\n        \"fr\": \"Ventilateur Smartmi/ZhiMi Avancé (WiFi)\",\n        \"it\": \"Ventilatore Smartmi/ZhiMi Avanzato (WiFi)\",\n        \"no\": \"Avansert Smartmi/ZhiMi Vifte (WiFi)\",\n        \"sv\": \"Avancerad Smartmi/ZhiMi Fläkt (WiFi)\",\n        \"pl\": \"Zaawansowany Smartmi/ZhiMi Wentylator (WiFi)\",\n        \"ru\": \"Продвинутый Smartmi/ZhiMi Вентилятор (WiFi)\",\n        \"ko\": \"고급 Smartmi/ZhiMi 팬 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/fan_zhimi_advanced/assets/images/large.jpg\",\n        \"small\": \"drivers/fan_zhimi_advanced/assets/images/small.jpg\"\n      },\n      \"class\": \"fan\",\n      \"capabilities\": [\n        \"onoff\",\n        \"oscillating\",\n        \"fan_speed\",\n        \"measure_wind_angle\",\n        \"fan_zhimi_mode\"\n      ],\n      \"capabilitiesOptions\": {\n        \"measure_wind_angle\": {\n          \"min\": 0,\n          \"max\": 120,\n          \"step\": 1\n        }\n      },\n      \"id\": \"fan_zhimi_advanced\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"LED\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summer\",\n                \"de\": \"Summer\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Sonnerie\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Summelyd\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Brzęczyk\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"버저\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnelås\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo para niños\",\n                \"fr\": \"Verrouillage enfant\",\n                \"it\": \"Blocco per bambini\",\n                \"no\": \"Barnesikring\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada dla dzieci\",\n                \"ru\": \"Детский замок\",\n                \"ko\": \"어린이 잠금 장치\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/fan_zhimi_fan_za5/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Smartmi Standing Fan 3 (WiFi)\",\n        \"nl\": \"Smartmi Standing Fan 3 (WiFi)\",\n        \"da\": \"Smartmi Standing Fan 3 (WiFi)\",\n        \"de\": \"Smartmi Standventilator 3 (WiFi)\",\n        \"es\": \"Ventilador de Pie Smartmi 3 (WiFi)\",\n        \"fr\": \"Ventilateur Debout Smartmi 3 (WiFi)\",\n        \"it\": \"Ventilatore a Piantana Smartmi 3 (WiFi)\",\n        \"no\": \"Smartmi Stående Vifte 3 (WiFi)\",\n        \"sv\": \"Smartmi Golvfläkt 3 (WiFi)\",\n        \"pl\": \"Wentylator stojący Smartmi 3 (WiFi)\",\n        \"ru\": \"Стоящий вентилятор Smartmi 3 (WiFi)\",\n        \"ko\": \"Smartmi 스탠딩 팬 3 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/fan_zhimi_fan_za5/assets/images/large.jpg\",\n        \"small\": \"drivers/fan_zhimi_fan_za5/assets/images/small.jpg\"\n      },\n      \"class\": \"fan\",\n      \"capabilities\": [\n        \"onoff\",\n        \"oscillating\",\n        \"onoff.ion\",\n        \"fan_speed\",\n        \"fan_zhimi_angle\",\n        \"fan_zhimi_mode\",\n        \"measure_humidity\",\n        \"measure_temperature\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.ion\": {\n          \"title\": {\n            \"en\": \"Enable ions\",\n            \"nl\": \"Inschakelen ionen\",\n            \"da\": \"Aktiver ioner\",\n            \"de\": \"Ionen aktivieren\",\n            \"es\": \"Activar iones\",\n            \"fr\": \"Activer les ions\",\n            \"it\": \"Abilita ioni\",\n            \"no\": \"Aktiver ioner\",\n            \"sv\": \"Aktivera joner\",\n            \"pl\": \"Włącz jony\",\n            \"ru\": \"Включить ионы\",\n            \"ko\": \"이온 활성화\"\n          }\n        },\n        \"fan_speed\": {\n          \"min\": 1,\n          \"max\": 4,\n          \"step\": 1,\n          \"units\": \"level\"\n        }\n      },\n      \"id\": \"fan_zhimi_fan_za5\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\",\n            \"pt\": \"Configurações do usuário\",\n            \"zh\": \"用户设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"Светодиод\",\n                \"ko\": \"LED\",\n                \"pt\": \"LED\",\n                \"zh\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summer\",\n                \"de\": \"Summerton\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Sonnerie\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Summer\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Brzęczyk\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"버저\",\n                \"pt\": \"Buzzer\",\n                \"zh\": \"蜂鸣器\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnelås\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo infantil\",\n                \"fr\": \"Verrouillage enfant\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barnesikring\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada dziecięca\",\n                \"ru\": \"Блокировка от детей\",\n                \"ko\": \"자녀 보호\",\n                \"pt\": \"Bloqueio infantil\",\n                \"zh\": \"儿童锁\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"pt\": \"Configurações do dispositivo\",\n            \"zh\": \"设备设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/gateway/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Xiaomi Gateway v2 (WiFi)\",\n        \"nl\": \"Xiaomi Gateway v2 (WiFi)\",\n        \"da\": \"Xiaomi Gateway v2 (WiFi)\",\n        \"de\": \"Xiaomi Gateway v2 (WiFi)\",\n        \"es\": \"Xiaomi Gateway v2 (WiFi)\",\n        \"fr\": \"Xiaomi Gateway v2 (WiFi)\",\n        \"it\": \"Xiaomi Gateway v2 (WiFi)\",\n        \"no\": \"Xiaomi Gateway v2 (WiFi)\",\n        \"sv\": \"Xiaomi Gateway v2 (WiFi)\",\n        \"pl\": \"Xiaomi Gateway v2 (WiFi)\",\n        \"ru\": \"Xiaomi Gateway v2 (WiFi)\",\n        \"ko\": \"Xiaomi Gateway v2 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/gateway/assets/images/large.jpg\",\n        \"small\": \"drivers/gateway/assets/images/small.jpg\"\n      },\n      \"class\": \"light\",\n      \"capabilities\": [\n        \"onoff\",\n        \"dim\",\n        \"light_hue\",\n        \"light_saturation\",\n        \"measure_luminance\",\n        \"homealarm_state\",\n        \"speaker_playing\",\n        \"speaker_next\",\n        \"speaker_prev\",\n        \"speaker_track\",\n        \"volume_set\",\n        \"volume_set.alarm\",\n        \"button\"\n      ],\n      \"capabilitiesOptions\": {\n        \"speaker_playing\": {\n          \"title\": {\n            \"en\": \"Radio\",\n            \"nl\": \"Radio\",\n            \"da\": \"Radio\",\n            \"de\": \"Radio\",\n            \"es\": \"Radio\",\n            \"fr\": \"Radio\",\n            \"it\": \"Radio\",\n            \"no\": \"Radio\",\n            \"sv\": \"Radio\",\n            \"pl\": \"Radio\",\n            \"ru\": \"Радио\",\n            \"ko\": \"라디오\"\n          }\n        },\n        \"speaker_next\": {\n          \"title\": {\n            \"en\": \"Next Station\",\n            \"nl\": \"Volgend station\",\n            \"da\": \"Næste station\",\n            \"de\": \"Nächste Station\",\n            \"es\": \"Siguiente estación\",\n            \"fr\": \"Prochaine station\",\n            \"it\": \"Stazione successiva\",\n            \"no\": \"Neste stasjon\",\n            \"sv\": \"Nästa station\",\n            \"pl\": \"Następna stacja\",\n            \"ru\": \"Следующая станция\",\n            \"ko\": \"다음 방송\"\n          }\n        },\n        \"speaker_prev\": {\n          \"title\": {\n            \"en\": \"Previous Station\",\n            \"nl\": \"Vorig station\",\n            \"da\": \"Forrige station\",\n            \"de\": \"Vorherige Station\",\n            \"es\": \"Estación anterior\",\n            \"fr\": \"Station précédente\",\n            \"it\": \"Stazione precedente\",\n            \"no\": \"Forrige stasjon\",\n            \"sv\": \"Föregående station\",\n            \"pl\": \"Poprzednia stacja\",\n            \"ru\": \"Предыдущая станция\",\n            \"ko\": \"이전 방송\"\n          }\n        },\n        \"volume_set\": {\n          \"title\": {\n            \"en\": \"Radio volume\",\n            \"nl\": \"Radio volume\",\n            \"da\": \"Radiovolumen\",\n            \"de\": \"Radiolautstärke\",\n            \"es\": \"Volumen de la radio\",\n            \"fr\": \"Volume de la radio\",\n            \"it\": \"Volume della radio\",\n            \"no\": \"Radiovolum\",\n            \"sv\": \"Radiovolym\",\n            \"pl\": \"Głośność radia\",\n            \"ru\": \"Громкость радио\",\n            \"ko\": \"라디오 볼륨\"\n          }\n        },\n        \"volume_set.alarm\": {\n          \"title\": {\n            \"en\": \"Alarm volume\",\n            \"nl\": \"Alarm volume\",\n            \"da\": \"Alarmvolumen\",\n            \"de\": \"Alarmlautstärke\",\n            \"es\": \"Volumen de la alarma\",\n            \"fr\": \"Volume de l'alarme\",\n            \"it\": \"Volume dell'allarme\",\n            \"no\": \"Alarmvolum\",\n            \"sv\": \"Alarmvolym\",\n            \"pl\": \"Głośność alarmu\",\n            \"ru\": \"Громкость сигнала тревоги\",\n            \"ko\": \"알람 볼륨\"\n          }\n        },\n        \"button\": {\n          \"title\": {\n            \"en\": \"Join / Pair\",\n            \"nl\": \"Join / Pair\",\n            \"da\": \"Join / Par\",\n            \"de\": \"Verbinden / Koppeln\",\n            \"es\": \"Unir / Emparejar\",\n            \"fr\": \"Joindre / Apparier\",\n            \"it\": \"Unisci / Abbina\",\n            \"no\": \"Koble til / Pare\",\n            \"sv\": \"Anslut / Para\",\n            \"pl\": \"Połącz / Sparuj\",\n            \"ru\": \"Присоединиться / Спарить\",\n            \"ko\": \"연결 / 페어링\"\n          }\n        }\n      },\n      \"id\": \"gateway\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Gateway Favorite Stations\",\n            \"nl\": \"Gateway favoriete stations\",\n            \"da\": \"Gateway favoritradiostationer\",\n            \"de\": \"Gateway Lieblingsstationen\",\n            \"es\": \"Estaciones favoritas de Gateway\",\n            \"fr\": \"Stations favorites de la passerelle\",\n            \"it\": \"Stazioni preferite del gateway\",\n            \"no\": \"Gateway favorittstasjoner\",\n            \"sv\": \"Gateway favoritstationer\",\n            \"pl\": \"Ulubione stacje bramy\",\n            \"ru\": \"Избранные станции шлюза\",\n            \"ko\": \"게이트웨이 즐겨찾기 방송국\"\n          },\n          \"children\": [\n            {\n              \"id\": \"favorite0ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"1 - Favorite Radio\",\n                \"nl\": \"1 - Favoriet station\",\n                \"da\": \"1 - Favoritradiostation\",\n                \"de\": \"1 - Lieblingssender\",\n                \"es\": \"1 - Radio favorita\",\n                \"fr\": \"1 - Radio préférée\",\n                \"it\": \"1 - Radio preferita\",\n                \"no\": \"1 - Favorittradiostasjon\",\n                \"sv\": \"1 - Favoritstation\",\n                \"pl\": \"1 - Ulubiona stacja\",\n                \"ru\": \"1 - Любимая радиостанция\",\n                \"ko\": \"1 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite1ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"2 - Favorite Radio\",\n                \"nl\": \"2 - Favoriet station\",\n                \"da\": \"2 - Favoritradiostation\",\n                \"de\": \"2 - Lieblingssender\",\n                \"es\": \"2 - Radio favorita\",\n                \"fr\": \"2 - Radio préférée\",\n                \"it\": \"2 - Radio preferita\",\n                \"no\": \"2 - Favorittradiostasjon\",\n                \"sv\": \"2 - Favoritstation\",\n                \"pl\": \"2 - Ulubiona stacja\",\n                \"ru\": \"2 - Любимая радиостанция\",\n                \"ko\": \"2 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite2ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"3 - Favorite Radio\",\n                \"nl\": \"3 - Favoriet station\",\n                \"da\": \"3 - Favoritradiostation\",\n                \"de\": \"3 - Lieblingssender\",\n                \"es\": \"3 - Radio favorita\",\n                \"fr\": \"3 - Radio préférée\",\n                \"it\": \"3 - Radio preferita\",\n                \"no\": \"3 - Favorittradiostasjon\",\n                \"sv\": \"3 - Favoritstation\",\n                \"pl\": \"3 - Ulubiona stacja\",\n                \"ru\": \"3 - Любимая радиостанция\",\n                \"ko\": \"3 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite3ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"4 - Favorite Radio\",\n                \"nl\": \"4 - Favoriet station\",\n                \"da\": \"4 - Favoritradiostation\",\n                \"de\": \"4 - Lieblingssender\",\n                \"es\": \"4 - Radio favorita\",\n                \"fr\": \"4 - Radio préférée\",\n                \"it\": \"4 - Radio preferita\",\n                \"no\": \"4 - Favorittradiostasjon\",\n                \"sv\": \"4 - Favoritstation\",\n                \"pl\": \"4 - Ulubiona stacja\",\n                \"ru\": \"4 - Любимая радиостанция\",\n                \"ko\": \"4 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite4ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"5 - Favorite Radio\",\n                \"nl\": \"5 - Favoriet station\",\n                \"da\": \"5 - Favoritradiostation\",\n                \"de\": \"5 - Lieblingssender\",\n                \"es\": \"5 - Radio favorita\",\n                \"fr\": \"5 - Radio préférée\",\n                \"it\": \"5 - Radio preferita\",\n                \"no\": \"5 - Favorittradiostasjon\",\n                \"sv\": \"5 - Favoritstation\",\n                \"pl\": \"5 - Ulubiona stacja\",\n                \"ru\": \"5 - Любимая радиостанция\",\n                \"ko\": \"5 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite5ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"6 - Favorite Radio\",\n                \"nl\": \"6 - Favoriet station\",\n                \"da\": \"6 - Favoritradiostation\",\n                \"de\": \"6 - Lieblingssender\",\n                \"es\": \"6 - Radio favorita\",\n                \"fr\": \"6 - Radio préférée\",\n                \"it\": \"6 - Radio preferita\",\n                \"no\": \"6 - Favorittradiostasjon\",\n                \"sv\": \"6 - Favoritstation\",\n                \"pl\": \"6 - Ulubiona stacja\",\n                \"ru\": \"6 - Любимая радиостанция\",\n                \"ko\": \"6 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite6ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"7 - Favorite Radio\",\n                \"nl\": \"7 - Favoriet station\",\n                \"da\": \"7 - Favoritradiostation\",\n                \"de\": \"7 - Lieblingssender\",\n                \"es\": \"7 - Radio favorita\",\n                \"fr\": \"7 - Radio préférée\",\n                \"it\": \"7 - Radio preferita\",\n                \"no\": \"7 - Favorittradiostasjon\",\n                \"sv\": \"7 - Favoritstation\",\n                \"pl\": \"7 - Ulubiona stacja\",\n                \"ru\": \"7 - Любимая радиостанция\",\n                \"ko\": \"7 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite7ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"8 - Favorite Radio\",\n                \"nl\": \"8 - Favoriet station\",\n                \"da\": \"8 - Favoritradiostation\",\n                \"de\": \"8 - Lieblingssender\",\n                \"es\": \"8 - Radio favorita\",\n                \"fr\": \"8 - Radio préférée\",\n                \"it\": \"8 - Radio preferita\",\n                \"no\": \"8 - Favorittradiostasjon\",\n                \"sv\": \"8 - Favoritstation\",\n                \"pl\": \"8 - Ulubiona stacja\",\n                \"ru\": \"8 - Любимая радиостанция\",\n                \"ko\": \"8 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite8ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"9 - Favorite Radio\",\n                \"nl\": \"9 - Favoriet station\",\n                \"da\": \"9 - Favoritradiostation\",\n                \"de\": \"9 - Lieblingssender\",\n                \"es\": \"9 - Radio favorita\",\n                \"fr\": \"9 - Radio préférée\",\n                \"it\": \"9 - Radio preferita\",\n                \"no\": \"9 - Favorittradiostasjon\",\n                \"sv\": \"9 - Favoritstation\",\n                \"pl\": \"9 - Ulubiona stacja\",\n                \"ru\": \"9 - Любимая радиостанция\",\n                \"ko\": \"9 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite9ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"10 - Favorite Radio\",\n                \"nl\": \"10 - Favoriet station\",\n                \"da\": \"10 - Favoritradiostation\",\n                \"de\": \"10 - Lieblingssender\",\n                \"es\": \"10 - Radio favorita\",\n                \"fr\": \"10 - Radio préférée\",\n                \"it\": \"10 - Radio preferita\",\n                \"no\": \"10 - Favorittradiostasjon\",\n                \"sv\": \"10 - Favoritstation\",\n                \"pl\": \"10 - Ulubiona stacja\",\n                \"ru\": \"10 - Любимая радиостанция\",\n                \"ko\": \"10 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite10ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"11 - Favorite Radio\",\n                \"nl\": \"11 - Favoriet station\",\n                \"da\": \"11 - Favoritradiostation\",\n                \"de\": \"11 - Lieblingssender\",\n                \"es\": \"11 - Radio favorita\",\n                \"fr\": \"11 - Radio préférée\",\n                \"it\": \"11 - Radio preferita\",\n                \"no\": \"11 - Favorittradiostasjon\",\n                \"sv\": \"11 - Favoritstation\",\n                \"pl\": \"11 - Ulubiona stacja\",\n                \"ru\": \"11 - Любимая радиостанция\",\n                \"ko\": \"11 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite11ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"12 - Favorite Radio\",\n                \"nl\": \"12 - Favoriet station\",\n                \"da\": \"12 - Favoritradiostation\",\n                \"de\": \"12 - Lieblingssender\",\n                \"es\": \"12 - Radio favorita\",\n                \"fr\": \"12 - Radio préférée\",\n                \"it\": \"12 - Radio preferita\",\n                \"no\": \"12 - Favorittradiostasjon\",\n                \"sv\": \"12 - Favoritstation\",\n                \"pl\": \"12 - Ulubiona stacja\",\n                \"ru\": \"12 - Любимая радиостанция\",\n                \"ko\": \"12 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite12ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"13 - Favorite Radio\",\n                \"nl\": \"13 - Favoriet station\",\n                \"da\": \"13 - Favoritradiostation\",\n                \"de\": \"13 - Lieblingssender\",\n                \"es\": \"13 - Radio favorita\",\n                \"fr\": \"13 - Radio préférée\",\n                \"it\": \"13 - Radio preferita\",\n                \"no\": \"13 - Favorittradiostasjon\",\n                \"sv\": \"13 - Favoritstation\",\n                \"pl\": \"13 - Ulubiona stacja\",\n                \"ru\": \"13 - Любимая радиостанция\",\n                \"ko\": \"13 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite13ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"14 - Favorite Radio\",\n                \"nl\": \"14 - Favoriet station\",\n                \"da\": \"14 - Favoritradiostation\",\n                \"de\": \"14 - Lieblingssender\",\n                \"es\": \"14 - Radio favorita\",\n                \"fr\": \"14 - Radio préférée\",\n                \"it\": \"14 - Radio preferita\",\n                \"no\": \"14 - Favorittradiostasjon\",\n                \"sv\": \"14 - Favoritstation\",\n                \"pl\": \"14 - Ulubiona stacja\",\n                \"ru\": \"14 - Любимая радиостанция\",\n                \"ko\": \"14 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite14ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"15 - Favorite Radio\",\n                \"nl\": \"15 - Favoriet station\",\n                \"da\": \"15 - Favoritradiostation\",\n                \"de\": \"15 - Lieblingssender\",\n                \"es\": \"15 - Radio favorita\",\n                \"fr\": \"15 - Radio préférée\",\n                \"it\": \"15 - Radio preferita\",\n                \"no\": \"15 - Favorittradiostasjon\",\n                \"sv\": \"15 - Favoritstation\",\n                \"pl\": \"15 - Ulubiona stacja\",\n                \"ru\": \"15 - Любимая радиостанция\",\n                \"ko\": \"15 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite15ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"16 - Favorite Radio\",\n                \"da\": \"16 - Favoritradiostation\",\n                \"de\": \"16 - Lieblingssender\",\n                \"es\": \"16 - Radio favorita\",\n                \"fr\": \"16 - Radio préférée\",\n                \"it\": \"16 - Radio preferita\",\n                \"no\": \"16 - Favorittradiostasjon\",\n                \"sv\": \"16 - Favoritstation\",\n                \"pl\": \"16 - Ulubiona stacja\",\n                \"ru\": \"16 - Любимая радиостанция\",\n                \"ko\": \"16 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite16ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"17 - Favorite Radio\",\n                \"da\": \"17 - Favoritradiostation\",\n                \"de\": \"17 - Lieblingssender\",\n                \"es\": \"17 - Radio favorita\",\n                \"fr\": \"17 - Radio préférée\",\n                \"it\": \"17 - Radio preferita\",\n                \"no\": \"17 - Favorittradiostasjon\",\n                \"sv\": \"17 - Favoritstation\",\n                \"pl\": \"17 - Ulubiona stacja\",\n                \"ru\": \"17 - Любимая радиостанция\",\n                \"ko\": \"17 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite17ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"18 - Favorite Radio\",\n                \"da\": \"18 - Favoritradiostation\",\n                \"de\": \"18 - Lieblingssender\",\n                \"es\": \"18 - Radio favorita\",\n                \"fr\": \"18 - Radio préférée\",\n                \"it\": \"18 - Radio preferita\",\n                \"no\": \"18 - Favorittradiostasjon\",\n                \"sv\": \"18 - Favoritstation\",\n                \"pl\": \"18 - Ulubiona stacja\",\n                \"ru\": \"18 - Любимая радиостанция\",\n                \"ko\": \"18 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite18ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"19 - Favorite Radio\",\n                \"da\": \"19 - Favoritradiostation\",\n                \"de\": \"19 - Lieblingssender\",\n                \"es\": \"19 - Radio favorita\",\n                \"fr\": \"19 - Radio préférée\",\n                \"it\": \"19 - Radio preferita\",\n                \"no\": \"19 - Favorittradiostasjon\",\n                \"sv\": \"19 - Favoritstation\",\n                \"pl\": \"19 - Ulubiona stacja\",\n                \"ru\": \"19 - Любимая радиостанция\",\n                \"ko\": \"19 - 즐겨찾는 라디오\"\n              }\n            },\n            {\n              \"id\": \"favorite19ID\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"20 - Favorite Radio\",\n                \"da\": \"20 - Favoritradiostation\",\n                \"de\": \"20 - Lieblingssender\",\n                \"es\": \"20 - Radio favorita\",\n                \"fr\": \"20 - Radio préférée\",\n                \"it\": \"20 - Radio preferita\",\n                \"no\": \"20 - Favorittradiostasjon\",\n                \"sv\": \"20 - Favoritstation\",\n                \"pl\": \"20 - Ulubiona stacja\",\n                \"ru\": \"20 - Любимая радиостанция\",\n                \"ko\": \"20 - 즐겨찾는 라디오\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/heater_zhimi_heater_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Smart Space/Fan Heater MIoT (WiFi)\",\n        \"nl\": \"Smart Space/Fan Heater MIoT (WiFi)\",\n        \"da\": \"Smart Space/Fan Heater MIoT (WiFi)\",\n        \"de\": \"Smart Space/Fan Heater MIoT (WiFi)\",\n        \"es\": \"Espacio inteligente / Calefactor de ventilador MIoT (WiFi)\",\n        \"fr\": \"Chauffage de ventilateur/espace intelligent MIoT (WiFi)\",\n        \"it\": \"Riscaldatore a ventola / Spazio Intelligente MIoT (WiFi)\",\n        \"no\": \"Smart Space/Viftevarmer MIoT (WiFi)\",\n        \"sv\": \"Smart Space/Värmefläkt MIoT (WiFi)\",\n        \"pl\": \"Inteligentna przestrzeń / Grzejnik wentylator MIoT (WiFi)\",\n        \"ru\": \"Умное пространство / Обогреватель-вентилятор MIoT (WiFi)\",\n        \"ko\": \"스마트 공간 / 팬 히터 MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/heater_zhimi_heater_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/heater_zhimi_heater_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"heater\",\n      \"capabilities\": [\n        \"onoff\",\n        \"heater_zhimi_heater_target_temperature\",\n        \"measure_temperature\"\n      ],\n      \"id\": \"heater_zhimi_heater_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"LED\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summer\",\n                \"de\": \"Summer\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Sonnerie\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Sommer\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Brzęczyk\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"버저\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnelås\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo infantil\",\n                \"fr\": \"Sécurité enfant\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barnelås\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada dzieci\",\n                \"ru\": \"Детская блокировка\",\n                \"ko\": \"어린이 잠금\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/humidifier_deerma_humidifier_jsq/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mijia Smart Sterilization Humidifier JSQ / JSQ1 / MJJSQ (WiFi)\",\n        \"nl\": \"Mijia Smart Sterilization Humidifier JSQ / JSQ1 / MJJSQ (WiFi)\",\n        \"da\": \"Mijia Smart Sterilization Luftfugter JSQ / JSQ1 / MJJSQ (WiFi)\",\n        \"de\": \"Mijia Smart Sterilisation Luftbefeuchter JSQ / JSQ1 / MJJSQ (WiFi)\",\n        \"es\": \"Humidificador de Esterilización Inteligente Mijia JSQ / JSQ1 / MJJSQ (WiFi)\",\n        \"fr\": \"Humidificateur de Stérilisation Intelligent Mijia JSQ / JSQ1 / MJJSQ (WiFi)\",\n        \"it\": \"Umidificatore di Sterilizzazione Intelligente Mijia JSQ / JSQ1 / MJJSQ (WiFi)\",\n        \"no\": \"Mijia Smart Steriliseringsfukter JSQ / JSQ1 / MJJSQ (WiFi)\",\n        \"sv\": \"Mijia Smart Sterilisering Luftfuktare JSQ / JSQ1 / MJJSQ (WiFi)\",\n        \"pl\": \"Inteligentny Sterylizujący Nawilżacz Mijia JSQ / JSQ1 / MJJSQ (WiFi)\",\n        \"ru\": \"Умный стерилизующий увлажнитель Mijia JSQ / JSQ1 / MJJSQ (WiFi)\",\n        \"ko\": \"미지아 스마트 살균 가습기 JSQ / JSQ1 / MJJSQ (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/humidifier_deerma_humidifier_jsq/assets/images/large.jpg\",\n        \"small\": \"drivers/humidifier_deerma_humidifier_jsq/assets/images/small.jpg\"\n      },\n      \"class\": \"humidifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"target_humidity\",\n        \"humidifier_deerma_jsq_mode\",\n        \"measure_temperature\",\n        \"measure_humidity\",\n        \"alarm_water\",\n        \"alarm_tank_empty\"\n      ],\n      \"capabilitiesOptions\": {\n        \"target_humidity\": {\n          \"min\": 0.4,\n          \"max\": 0.7\n        },\n        \"alarm_water\": {\n          \"title\": {\n            \"en\": \"Waterlevel\",\n            \"nl\": \"Waterniveau\",\n            \"da\": \"Vandniveau\",\n            \"de\": \"Wasserstand\",\n            \"es\": \"Nivel de agua\",\n            \"fr\": \"Niveau d'eau\",\n            \"it\": \"Livello dell'acqua\",\n            \"no\": \"Vannivå\",\n            \"sv\": \"Vattennivå\",\n            \"pl\": \"Poziom wody\",\n            \"ru\": \"Уровень воды\",\n            \"ko\": \"수위\"\n          }\n        }\n      },\n      \"id\": \"humidifier_deerma_humidifier_jsq\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"Светодиод\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summer\",\n                \"de\": \"Summer\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Buzzer\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Summer\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Brzęczyk\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"부저\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/humidifier_deerma_humidifier_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Smart Antibacterial Humidifier MIoT (WiFi)\",\n        \"nl\": \"Mi Smart Antibacterial Humidifier MIoT (WiFi)\",\n        \"da\": \"Mi Smart Antibacterial Humidifier MIoT (WiFi)\",\n        \"de\": \"Mi Smart Antibacterial Humidifier MIoT (WiFi)\",\n        \"es\": \"Mi Humidificador Antibacteriano Inteligente MIoT (WiFi)\",\n        \"fr\": \"Humidificateur Antibactérien Intelligent MIoT (WiFi)\",\n        \"it\": \"Umidificatore Antibatterico Intelligente MIoT (WiFi)\",\n        \"no\": \"Mi Smart Antibakterielle Luftfukter MIoT (WiFi)\",\n        \"sv\": \"Mi Smart Antibakteriell Luftrenare MIoT (WiFi)\",\n        \"pl\": \"Inteligentny Nawilżacz Antybakteryjny MIoT (WiFi)\",\n        \"ru\": \"Умный Антибактериальный Увлажнитель MIoT (WiFi)\",\n        \"ko\": \"Mi 스마트 항균 가습기 MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/humidifier_deerma_humidifier_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/humidifier_deerma_humidifier_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"humidifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"target_humidity\",\n        \"humidifier_deerma_jsq_mode\",\n        \"measure_temperature\",\n        \"measure_humidity\",\n        \"alarm_tank_empty\"\n      ],\n      \"capabilitiesOptions\": {\n        \"target_humidity\": {\n          \"min\": 0.4,\n          \"max\": 0.8\n        }\n      },\n      \"id\": \"humidifier_deerma_humidifier_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración del usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"LED\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summerton\",\n                \"de\": \"Sommer\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Vibreur\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Summerton\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Buzer\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"부저\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/humidifier_leshow_humidifier_jsq1/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Xiaomi Humidifier Pro (WiFi)\",\n        \"nl\": \"Xiaomi Humidifier Pro (WiFi)\",\n        \"da\": \"Xiaomi Luftfugter Pro (WiFi)\",\n        \"de\": \"Xiaomi Befeuchter Pro (WiFi)\",\n        \"es\": \"Xiaomi Humidificador Pro (WiFi)\",\n        \"fr\": \"Xiaomi Humidificateur Pro (WiFi)\",\n        \"it\": \"Xiaomi Umidificatore Pro (WiFi)\",\n        \"no\": \"Xiaomi Luftfukter Pro (WiFi)\",\n        \"sv\": \"Xiaomi Luftfuktare Pro (WiFi)\",\n        \"pl\": \"Xiaomi Nawilżacz Pro (WiFi)\",\n        \"ru\": \"Xiaomi Увлажнитель Pro (WiFi)\",\n        \"ko\": \"샤오미 가습기 프로 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/humidifier_leshow_humidifier_jsq1/assets/images/large.jpg\",\n        \"small\": \"drivers/humidifier_leshow_humidifier_jsq1/assets/images/small.jpg\"\n      },\n      \"class\": \"humidifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"target_humidity\",\n        \"humidifier_leshow_jsq1_mode\",\n        \"measure_humidity\",\n        \"measure_filter_life\",\n        \"humidifier_water_level_state\"\n      ],\n      \"capabilitiesOptions\": {\n        \"target_humidity\": {\n          \"min\": 0.3,\n          \"max\": 0.8\n        }\n      },\n      \"id\": \"humidifier_leshow_humidifier_jsq1\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de Usuario\",\n            \"fr\": \"Paramètres Utilisateur\",\n            \"it\": \"Impostazioni Utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia Użytkownika\",\n            \"ru\": \"Настройки Пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"LED\",\n                \"ko\": \"LED\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del Dispositivo\",\n            \"fr\": \"Paramètres de l'Appareil\",\n            \"it\": \"Impostazioni del Dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia Urządzenia\",\n            \"ru\": \"Настройки Устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/humidifier_xiaomi_humidifier/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Xiaomi/Mijia Humidifier MIoT (WiFi)\",\n        \"nl\": \"Xiaomi/Mijia Humidifier MIoT (WiFi)\",\n        \"da\": \"Xiaomi/Mijia Luftfugter MIoT (WiFi)\",\n        \"de\": \"Xiaomi/Mijia Luftbefeuchter MIoT (WiFi)\",\n        \"es\": \"Xiaomi/Mijia Humidificador MIoT (WiFi)\",\n        \"fr\": \"Xiaomi/Mijia Humidificateur MIoT (WiFi)\",\n        \"it\": \"Xiaomi/Mijia Umidificatore MIoT (WiFi)\",\n        \"no\": \"Xiaomi/Mijia Luftfukter MIoT (WiFi)\",\n        \"sv\": \"Xiaomi/Mijia Luftfuktare MIoT (WiFi)\",\n        \"pl\": \"Xiaomi/Mijia Nawilżacz MIoT (WiFi)\",\n        \"ru\": \"Xiaomi/Mijia Увлажнитель MIoT (WiFi)\",\n        \"ko\": \"샤오미/미지아 가습기 MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/humidifier_xiaomi_humidifier/assets/images/large.jpg\",\n        \"small\": \"drivers/humidifier_xiaomi_humidifier/assets/images/small.jpg\"\n      },\n      \"class\": \"humidifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"onoff.dry\",\n        \"target_humidity\",\n        \"measure_temperature\",\n        \"measure_humidity\",\n        \"measure_waterlevel\",\n        \"humidifier_xiaomi_mode\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.dry\": {\n          \"title\": {\n            \"en\": \"Dry mode\",\n            \"nl\": \"Droog modus\",\n            \"da\": \"Tør tilstand\",\n            \"de\": \"Trockenmodus\",\n            \"es\": \"Modo seco\",\n            \"fr\": \"Mode sec\",\n            \"it\": \"Modalità secco\",\n            \"no\": \"Tørrmodus\",\n            \"sv\": \"Torr läge\",\n            \"pl\": \"Tryb suchy\",\n            \"ru\": \"Сухой режим\",\n            \"ko\": \"건조 모드\"\n          }\n        },\n        \"target_humidity\": {\n          \"min\": 40,\n          \"max\": 70,\n          \"step\": 10\n        }\n      },\n      \"id\": \"humidifier_xiaomi_humidifier\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\",\n            \"pt\": \"Configurações do usuário\",\n            \"ja\": \"ユーザー設定\",\n            \"zh\": \"用户设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"Светодиод\",\n                \"ko\": \"LED\",\n                \"pt\": \"LED\",\n                \"ja\": \"LED\",\n                \"zh\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summer\",\n                \"de\": \"Summer\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Buzzer\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Summer\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Brzęczyk\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"버저\",\n                \"pt\": \"Buzzer\",\n                \"ja\": \"ブザー\",\n                \"zh\": \"蜂鸣器\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnelås\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo infantil\",\n                \"fr\": \"Verrouillage enfants\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barnelås\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada dla dzieci\",\n                \"ru\": \"Блокировка от детей\",\n                \"ko\": \"잠금 기능\",\n                \"pt\": \"Bloqueio para crianças\",\n                \"ja\": \"チャイルドロック\",\n                \"zh\": \"儿童锁\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device data\",\n            \"nl\": \"Apparaat data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"디바이스 데이터\",\n            \"pt\": \"Dados do dispositivo\",\n            \"ja\": \"デバイスデータ\",\n            \"zh\": \"设备数据\"\n          },\n          \"children\": [\n            {\n              \"id\": \"error\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Error\",\n                \"nl\": \"Error\",\n                \"da\": \"Fejl\",\n                \"de\": \"Fehler\",\n                \"es\": \"Error\",\n                \"fr\": \"Erreur\",\n                \"it\": \"Errore\",\n                \"no\": \"Feil\",\n                \"sv\": \"Fel\",\n                \"pl\": \"Błąd\",\n                \"ru\": \"Ошибка\",\n                \"ko\": \"오류\",\n                \"pt\": \"Erro\",\n                \"ja\": \"エラー\",\n                \"zh\": \"错误\"\n              },\n              \"value\": \"No error\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"디바이스 설정\",\n            \"pt\": \"Configurações do dispositivo\",\n            \"ja\": \"デバイス設定\",\n            \"zh\": \"设备设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/humidifier_zhimi_humidifier/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Smartmi Humidifier v1/v2 (WiFi)\",\n        \"da\": \"Smartmi Luftfugter v1/v2 (WiFi)\",\n        \"de\": \"Smartmi Luftbefeuchter v1/v2 (WLAN)\",\n        \"es\": \"Humidificador Smartmi v1/v2 (WiFi)\",\n        \"fr\": \"Humidificateur Smartmi v1/v2 (WiFi)\",\n        \"it\": \"Umidificatore Smartmi v1/v2 (WiFi)\",\n        \"no\": \"Smartmi Luftfukter v1/v2 (WiFi)\",\n        \"sv\": \"Smartmi Luftfuktare v1/v2 (WiFi)\",\n        \"pl\": \"Nawilżacz Smartmi v1/v2 (WiFi)\",\n        \"ru\": \"Увлажнитель Smartmi v1/v2 (WiFi)\",\n        \"ko\": \"스마트미 가습기 v1/v2 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/humidifier_zhimi_humidifier/assets/images/large.jpg\",\n        \"small\": \"drivers/humidifier_zhimi_humidifier/assets/images/small.jpg\"\n      },\n      \"class\": \"humidifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"measure_temperature\",\n        \"measure_humidity\",\n        \"target_humidity\",\n        \"humidifier_zhimi_mode\"\n      ],\n      \"capabilitiesOptions\": {\n        \"target_humidity\": {\n          \"min\": 30,\n          \"max\": 80,\n          \"step\": 10\n        }\n      },\n      \"id\": \"humidifier_zhimi_humidifier\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"LED\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Buzzer\",\n                \"de\": \"Summer\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Buzzer\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Buzzeren\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Buzzer\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"부저\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnelås\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo infantil\",\n                \"fr\": \"Verrouillage enfant\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barnesikring\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada rodzicielska\",\n                \"ru\": \"Детский замок\",\n                \"ko\": \"어린이 잠금\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"기기 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/humidifier_zhimi_humidifier_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Smartmi Humidifier MIoT (WiFi)\",\n        \"nl\": \"Samrtmi Humidifier MIoT (WiFi)\",\n        \"da\": \"Smartmi Humidifier MIoT (WiFi)\",\n        \"de\": \"Smartmi Humidifier MIoT (WiFi)\",\n        \"es\": \"Smartmi Humidificador MIoT (WiFi)\",\n        \"fr\": \"Smartmi Humidificateur MIoT (WiFi)\",\n        \"it\": \"Smartmi Umidificatore MIoT (WiFi)\",\n        \"no\": \"Smartmi Humidifier MIoT (WiFi)\",\n        \"sv\": \"Smartmi Avdunstningsluftfuktare MIoT (WiFi)\",\n        \"pl\": \"Smartmi Nawilżacz Parowy MIoT (WiFi)\",\n        \"ru\": \"Smartmi Испарительный Увлажнитель MIoT (WiFi)\",\n        \"ko\": \"Smartmi 증발식 가습기 MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/humidifier_zhimi_humidifier_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/humidifier_zhimi_humidifier_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"humidifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"onoff.dry\",\n        \"dim\",\n        \"target_humidity\",\n        \"humidifier_zhimi_mode_miot\",\n        \"measure_temperature\",\n        \"measure_humidity\",\n        \"measure_waterlevel\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.dry\": {\n          \"title\": {\n            \"en\": \"Dry mode\",\n            \"nl\": \"Droog modus\",\n            \"da\": \"Tør tilstand\",\n            \"de\": \"Trockenmodus\",\n            \"es\": \"Modo seco\",\n            \"fr\": \"Mode sec\",\n            \"it\": \"Modalità secca\",\n            \"no\": \"Tørrmodus\",\n            \"sv\": \"Torrläge\",\n            \"pl\": \"Tryb suszenia\",\n            \"ru\": \"Сухой режим\",\n            \"ko\": \"건조 모드\"\n          }\n        },\n        \"dim\": {\n          \"title\": {\n            \"en\": \"Motor Speed\",\n            \"nl\": \"Motor snelheid\",\n            \"da\": \"Motors hastighed\",\n            \"de\": \"Motorgeschwindigkeit\",\n            \"es\": \"Velocidad del motor\",\n            \"fr\": \"Vitesse du moteur\",\n            \"it\": \"Velocità del motore\",\n            \"no\": \"Motors hastighet\",\n            \"sv\": \"Motorns hastighet\",\n            \"pl\": \"Prędkość silnika\",\n            \"ru\": \"Скорость двигателя\",\n            \"ko\": \"모터 속도\"\n          },\n          \"min\": 0,\n          \"max\": 1,\n          \"step\": 0.1\n        },\n        \"target_humidity\": {\n          \"min\": 30,\n          \"max\": 80,\n          \"step\": 10\n        }\n      },\n      \"id\": \"humidifier_zhimi_humidifier_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"LED\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summer\",\n                \"de\": \"Summer\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Sonnerie\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Buzzer\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Buzer\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"부저\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnesikring\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo infantil\",\n                \"fr\": \"Verrouillage enfant\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barne lås\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada rodzicielska\",\n                \"ru\": \"Блокировка от детей\",\n                \"ko\": \"어린이 잠금\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/lock_aq1/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara Lock (Gateway)\",\n        \"nl\": \"Aqara Lock (Gateway)\",\n        \"da\": \"Aqara Lock (Gateway)\",\n        \"de\": \"Aqara Lock (Gateway)\",\n        \"es\": \"Aqara Lock (Gateway)\",\n        \"fr\": \"Aqara Lock (Gateway)\",\n        \"it\": \"Aqara Lock (Gateway)\",\n        \"no\": \"Aqara Lock (Gateway)\",\n        \"sv\": \"Aqara Lock (Gateway)\",\n        \"pl\": \"Aqara Lock (Gateway)\",\n        \"ru\": \"Aqara Lock (Gateway)\",\n        \"ko\": \"Aqara Lock (Gateway)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/lock_aq1/assets/images/large.jpg\",\n        \"small\": \"/drivers/lock_aq1/assets/images/small.jpg\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"alarm_motion.finger\",\n        \"alarm_motion.code\",\n        \"alarm_motion.card\",\n        \"alarm_motion.wrongID\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"capabilitiesOptions\": {\n        \"alarm_motion.finger\": {\n          \"title\": {\n            \"en\": \"Finger\",\n            \"nl\": \"Vinger\",\n            \"da\": \"Finger\",\n            \"de\": \"Finger\",\n            \"es\": \"Finger\",\n            \"fr\": \"Doigt\",\n            \"it\": \"Dito\",\n            \"no\": \"Finger\",\n            \"sv\": \"Finger\",\n            \"pl\": \"Palec\",\n            \"ru\": \"Палец\",\n            \"ko\": \"손가락\"\n          }\n        },\n        \"alarm_motion.code\": {\n          \"title\": {\n            \"en\": \"Code\",\n            \"nl\": \"Code\",\n            \"da\": \"Kode\",\n            \"de\": \"Code\",\n            \"es\": \"Código\",\n            \"fr\": \"Code\",\n            \"it\": \"Codice\",\n            \"no\": \"Kode\",\n            \"sv\": \"Kod\",\n            \"pl\": \"Kod\",\n            \"ru\": \"Код\",\n            \"ko\": \"코드\"\n          }\n        },\n        \"alarm_motion.card\": {\n          \"title\": {\n            \"en\": \"Card\",\n            \"nl\": \"Card\",\n            \"da\": \"Kort\",\n            \"de\": \"Karte\",\n            \"es\": \"Tarjeta\",\n            \"fr\": \"Carte\",\n            \"it\": \"Carta\",\n            \"no\": \"Kort\",\n            \"sv\": \"Kort\",\n            \"pl\": \"Karta\",\n            \"ru\": \"Карта\",\n            \"ko\": \"카드\"\n          }\n        },\n        \"alarm_motion.wrongID\": {\n          \"title\": {\n            \"en\": \"Wrong ID\",\n            \"nl\": \"Verkeerd ID\",\n            \"da\": \"Forkert ID\",\n            \"de\": \"Falsche ID\",\n            \"es\": \"ID incorrecta\",\n            \"fr\": \"ID incorrecte\",\n            \"it\": \"ID sbagliato\",\n            \"no\": \"Feil ID\",\n            \"sv\": \"Fel ID\",\n            \"pl\": \"Błędne ID\",\n            \"ru\": \"Неправильный ID\",\n            \"ko\": \"잘못된 ID\"\n          }\n        }\n      },\n      \"energy\": {\n        \"batteries\": [\n          \"AAA\",\n          \"AAA\",\n          \"AAA\",\n          \"AAA\",\n          \"AAA\",\n          \"AAA\",\n          \"AAA\",\n          \"AAA\"\n        ]\n      },\n      \"id\": \"lock_aq1\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Duration of the lock alarm\",\n            \"nl\": \"Duur van het slot alarm\",\n            \"da\": \"Varighed af alarmsystemet\",\n            \"de\": \"Dauer des Schlossalarmes\",\n            \"es\": \"Duración de la alarma de la cerradura\",\n            \"fr\": \"Durée de l'alarme de verrouillage\",\n            \"it\": \"Durata dell'allarme della serratura\",\n            \"no\": \"Varighet på låsalarm\",\n            \"sv\": \"Varaktighet av låsalarm\",\n            \"pl\": \"Czas trwania alarmu blokady\",\n            \"ru\": \"Длительность тревоги блокировки\",\n            \"ko\": \"잠금 경고의 지속 시간\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_duration_number\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Disable after\",\n                \"nl\": \"Uitschakelen na\",\n                \"da\": \"Deaktiver efter\",\n                \"de\": \"Deaktivieren nach\",\n                \"es\": \"Desactivar después\",\n                \"fr\": \"Désactiver après\",\n                \"it\": \"Disabilita dopo\",\n                \"no\": \"Deaktiver etter\",\n                \"sv\": \"Inaktivera efter\",\n                \"pl\": \"Wyłącz po\",\n                \"ru\": \"Выключить через\",\n                \"ko\": \"비활성화 후\"\n              },\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 60,\n                \"max\": 86400\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuraciones del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"디바이스 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device information\",\n            \"da\": \"Enhedsoplysninger\",\n            \"de\": \"Geräteinformationen\",\n            \"es\": \"Información sobre el dispositivo\",\n            \"fr\": \"Informations sur l'appareil\",\n            \"it\": \"Informazioni sul dispositivo\",\n            \"no\": \"Enhetsinformasjon\",\n            \"sv\": \"Enhetsinformation\",\n            \"pl\": \"Informacje o urządzeniu\",\n            \"ru\": \"Информация об устройстве\",\n            \"ko\": \"장치 정보\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Device sid\",\n                \"da\": \"Enhedsid\",\n                \"de\": \"Geräte-SID\",\n                \"es\": \"Sid del dispositivo\",\n                \"fr\": \"SID de l'appareil\",\n                \"it\": \"SID del dispositivo\",\n                \"no\": \"Enhetsside\",\n                \"sv\": \"Enhets-SID\",\n                \"pl\": \"SID urządzenia\",\n                \"ru\": \"SID устройства\",\n                \"ko\": \"장치 SID\"\n              },\n              \"value\": \"0123456789abcd\"\n            },\n            {\n              \"id\": \"deviceFromGatewaySid\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Gateway sid\",\n                \"da\": \"Gateway sid\",\n                \"de\": \"Gateway SID\",\n                \"es\": \"Sid de la puerta de enlace\",\n                \"fr\": \"SID de la passerelle\",\n                \"it\": \"SID del gateway\",\n                \"no\": \"Gateway sid\",\n                \"sv\": \"Gateway SID\",\n                \"pl\": \"SID bramy\",\n                \"ru\": \"SID шлюза\",\n                \"ko\": \"게이트웨이 SID\"\n              },\n              \"value\": \"0123456789ab\"\n            },\n            {\n              \"id\": \"deviceModelName\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Device model\",\n                \"da\": \"Enhedsmodel\",\n                \"de\": \"Gerätemodell\",\n                \"es\": \"Modelo del dispositivo\",\n                \"fr\": \"Modèle de l'appareil\",\n                \"it\": \"Modello del dispositivo\",\n                \"no\": \"Enhetsmodell\",\n                \"sv\": \"Enhetsmodell\",\n                \"pl\": \"Model urządzenia\",\n                \"ru\": \"Модель устройства\",\n                \"ko\": \"장치 모델\"\n              },\n              \"value\": \"lumi.device\"\n            },\n            {\n              \"id\": \"deviceModelCodeName\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Device model code\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código del modelo del dispositivo\",\n                \"fr\": \"Code du modèle de l'appareil\",\n                \"it\": \"Codice del modello del dispositivo\",\n                \"no\": \"Enhetsmodells kode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              },\n              \"value\": \"AABBCC01LM\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Lock users\",\n            \"da\": \"Låsebrugere\",\n            \"de\": \"Schlossbenutzer\",\n            \"es\": \"Usuarios de la cerradura\",\n            \"fr\": \"Utilisateurs de verrou\",\n            \"it\": \"Utenti della serratura\",\n            \"no\": \"Låsebrukere\",\n            \"sv\": \"Låsanvändare\",\n            \"pl\": \"Użytkownicy zamka\",\n            \"ru\": \"Пользователи замка\",\n            \"ko\": \"잠금 사용자\"\n          },\n          \"children\": [\n            {\n              \"id\": \"lock0UserName\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"1 - User name\",\n                \"da\": \"1 - Brugernavn\",\n                \"de\": \"1 - Benutzername\",\n                \"es\": \"1 - Nombre de usuario\",\n                \"fr\": \"1 - Nom d'utilisateur\",\n                \"it\": \"1 - Nome utente\",\n                \"no\": \"1 - Brukernavn\",\n                \"sv\": \"1 - Användarnamn\",\n                \"pl\": \"1 - Nazwa użytkownika\",\n                \"ru\": \"1 - Имя пользователя\",\n                \"ko\": \"1 - 사용자 이름\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user0FingerID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Finger ID\",\n                \"da\": \"Finger ID\",\n                \"de\": \"Finger-ID\",\n                \"es\": \"ID de dedo\",\n                \"fr\": \"ID d'empreinte\",\n                \"it\": \"ID del dito\",\n                \"no\": \"Finger-ID\",\n                \"sv\": \"Finger-ID\",\n                \"pl\": \"ID palca\",\n                \"ru\": \"ID пальца\",\n                \"ko\": \"지문 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user0CodeID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Code ID\",\n                \"da\": \"Kode ID\",\n                \"de\": \"Code-ID\",\n                \"es\": \"ID de código\",\n                \"fr\": \"ID de code\",\n                \"it\": \"ID del codice\",\n                \"no\": \"Kode-ID\",\n                \"sv\": \"Kod-ID\",\n                \"pl\": \"ID kodu\",\n                \"ru\": \"ID кода\",\n                \"ko\": \"코드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user0CardID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Card ID\",\n                \"da\": \"Kort ID\",\n                \"de\": \"Karten-ID\",\n                \"es\": \"ID de tarjeta\",\n                \"fr\": \"ID de carte\",\n                \"it\": \"ID della carta\",\n                \"no\": \"Kort-ID\",\n                \"sv\": \"Kort-ID\",\n                \"pl\": \"ID karty\",\n                \"ru\": \"ID карты\",\n                \"ko\": \"카드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"lock1UserName\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"2 - User name\",\n                \"da\": \"2 - Brugernavn\",\n                \"de\": \"2 - Benutzername\",\n                \"es\": \"2 - Nombre de usuario\",\n                \"fr\": \"2 - Nom d'utilisateur\",\n                \"it\": \"2 - Nome utente\",\n                \"no\": \"2 - Brukernavn\",\n                \"sv\": \"2 - Användarnamn\",\n                \"pl\": \"2 - Nazwa użytkownika\",\n                \"ru\": \"2 - Имя пользователя\",\n                \"ko\": \"2 - 사용자 이름\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user1FingerID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Finger ID\",\n                \"da\": \"Finger ID\",\n                \"de\": \"Finger-ID\",\n                \"es\": \"ID de dedo\",\n                \"fr\": \"ID d'empreinte\",\n                \"it\": \"ID del dito\",\n                \"no\": \"Finger-ID\",\n                \"sv\": \"Finger-ID\",\n                \"pl\": \"ID palca\",\n                \"ru\": \"ID пальца\",\n                \"ko\": \"지문 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user1CodeID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Code ID\",\n                \"da\": \"Kode ID\",\n                \"de\": \"Code-ID\",\n                \"es\": \"ID de código\",\n                \"fr\": \"ID de code\",\n                \"it\": \"ID del codice\",\n                \"no\": \"Kode-ID\",\n                \"sv\": \"Kod-ID\",\n                \"pl\": \"ID kodu\",\n                \"ru\": \"ID кода\",\n                \"ko\": \"코드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user1CardID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Card ID\",\n                \"da\": \"Kort ID\",\n                \"de\": \"Karten-ID\",\n                \"es\": \"ID de tarjeta\",\n                \"fr\": \"ID de carte\",\n                \"it\": \"ID della carta\",\n                \"no\": \"Kort-ID\",\n                \"sv\": \"Kort-ID\",\n                \"pl\": \"ID karty\",\n                \"ru\": \"ID карты\",\n                \"ko\": \"카드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"lock2UserName\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"3 - User name\",\n                \"da\": \"3 - Brugernavn\",\n                \"de\": \"3 - Benutzername\",\n                \"es\": \"3 - Nombre de usuario\",\n                \"fr\": \"3 - Nom d'utilisateur\",\n                \"it\": \"3 - Nome utente\",\n                \"no\": \"3 - Brukernavn\",\n                \"sv\": \"3 - Användarnamn\",\n                \"pl\": \"3 - Nazwa użytkownika\",\n                \"ru\": \"3 - Имя пользователя\",\n                \"ko\": \"3 - 사용자 이름\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user2FingerID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Finger ID\",\n                \"da\": \"Finger ID\",\n                \"de\": \"Finger-ID\",\n                \"es\": \"ID de dedo\",\n                \"fr\": \"ID d'empreinte\",\n                \"it\": \"ID del dito\",\n                \"no\": \"Finger-ID\",\n                \"sv\": \"Finger-ID\",\n                \"pl\": \"ID palca\",\n                \"ru\": \"ID пальца\",\n                \"ko\": \"지문 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user2CodeID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Code ID\",\n                \"da\": \"Kode ID\",\n                \"de\": \"Code-ID\",\n                \"es\": \"ID de código\",\n                \"fr\": \"ID de code\",\n                \"it\": \"ID del codice\",\n                \"no\": \"Kode-ID\",\n                \"sv\": \"Kod-ID\",\n                \"pl\": \"ID kodu\",\n                \"ru\": \"ID кода\",\n                \"ko\": \"코드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user2CardID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Card ID\",\n                \"da\": \"Kort ID\",\n                \"de\": \"Karten-ID\",\n                \"es\": \"ID de tarjeta\",\n                \"fr\": \"ID de carte\",\n                \"it\": \"ID della carta\",\n                \"no\": \"Kort-ID\",\n                \"sv\": \"Kort-ID\",\n                \"pl\": \"ID karty\",\n                \"ru\": \"ID карты\",\n                \"ko\": \"카드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"lock3UserName\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"4 - User name\",\n                \"da\": \"4 - Brugernavn\",\n                \"de\": \"4 - Benutzername\",\n                \"es\": \"4 - Nombre de usuario\",\n                \"fr\": \"4 - Nom d'utilisateur\",\n                \"it\": \"4 - Nome utente\",\n                \"no\": \"4 - Brukernavn\",\n                \"sv\": \"4 - Användarnamn\",\n                \"pl\": \"4 - Nazwa użytkownika\",\n                \"ru\": \"4 - Имя пользователя\",\n                \"ko\": \"4 - 사용자 이름\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user3FingerID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Finger ID\",\n                \"da\": \"Finger ID\",\n                \"de\": \"Finger-ID\",\n                \"es\": \"ID de dedo\",\n                \"fr\": \"ID d'empreinte\",\n                \"it\": \"ID del dito\",\n                \"no\": \"Finger-ID\",\n                \"sv\": \"Finger-ID\",\n                \"pl\": \"ID palca\",\n                \"ru\": \"ID пальца\",\n                \"ko\": \"지문 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user3CodeID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Code ID\",\n                \"da\": \"Kode ID\",\n                \"de\": \"Code-ID\",\n                \"es\": \"ID de código\",\n                \"fr\": \"ID de code\",\n                \"it\": \"ID del codice\",\n                \"no\": \"Kode-ID\",\n                \"sv\": \"Kod-ID\",\n                \"pl\": \"ID kodu\",\n                \"ru\": \"ID кода\",\n                \"ko\": \"코드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user3CardID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Card ID\",\n                \"da\": \"Kort ID\",\n                \"de\": \"Karten-ID\",\n                \"es\": \"ID de tarjeta\",\n                \"fr\": \"ID de carte\",\n                \"it\": \"ID della carta\",\n                \"no\": \"Kort-ID\",\n                \"sv\": \"Kort-ID\",\n                \"pl\": \"ID karty\",\n                \"ru\": \"ID карты\",\n                \"ko\": \"카드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"lock4UserName\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"5 - User name\",\n                \"da\": \"5 - Brugernavn\",\n                \"de\": \"5 - Benutzername\",\n                \"es\": \"5 - Nombre de usuario\",\n                \"fr\": \"5 - Nom d'utilisateur\",\n                \"it\": \"5 - Nome utente\",\n                \"no\": \"5 - Brukernavn\",\n                \"sv\": \"5 - Användarnamn\",\n                \"pl\": \"5 - Nazwa użytkownika\",\n                \"ru\": \"5 - Имя пользователя\",\n                \"ko\": \"5 - 사용자 이름\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user4FingerID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Finger ID\",\n                \"da\": \"Finger ID\",\n                \"de\": \"Finger-ID\",\n                \"es\": \"ID de dedo\",\n                \"fr\": \"ID d'empreinte\",\n                \"it\": \"ID del dito\",\n                \"no\": \"Finger-ID\",\n                \"sv\": \"Finger-ID\",\n                \"pl\": \"ID palca\",\n                \"ru\": \"ID пальца\",\n                \"ko\": \"지문 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user4CodeID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Code ID\",\n                \"da\": \"Kode ID\",\n                \"de\": \"Code-ID\",\n                \"es\": \"ID de código\",\n                \"fr\": \"ID de code\",\n                \"it\": \"ID del codice\",\n                \"no\": \"Kode-ID\",\n                \"sv\": \"Kod-ID\",\n                \"pl\": \"ID kodu\",\n                \"ru\": \"ID кода\",\n                \"ko\": \"코드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user4CardID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Card ID\",\n                \"da\": \"Kort ID\",\n                \"de\": \"Karten-ID\",\n                \"es\": \"ID de tarjeta\",\n                \"fr\": \"ID de carte\",\n                \"it\": \"ID della carta\",\n                \"no\": \"Kort-ID\",\n                \"sv\": \"Kort-ID\",\n                \"pl\": \"ID karty\",\n                \"ru\": \"ID карты\",\n                \"ko\": \"카드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"lock5UserName\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"6 - User name\",\n                \"da\": \"6 - Brugernavn\",\n                \"de\": \"6 - Benutzername\",\n                \"es\": \"6 - Nombre de usuario\",\n                \"fr\": \"6 - Nom d'utilisateur\",\n                \"it\": \"6 - Nome utente\",\n                \"no\": \"6 - Brukernavn\",\n                \"sv\": \"6 - Användarnamn\",\n                \"pl\": \"6 - Nazwa użytkownika\",\n                \"ru\": \"6 - Имя пользователя\",\n                \"ko\": \"6 - 사용자 이름\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user5FingerID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Finger ID\",\n                \"da\": \"Finger ID\",\n                \"de\": \"Finger-ID\",\n                \"es\": \"ID de dedo\",\n                \"fr\": \"ID d'empreinte\",\n                \"it\": \"ID del dito\",\n                \"no\": \"Finger-ID\",\n                \"sv\": \"Finger-ID\",\n                \"pl\": \"ID palca\",\n                \"ru\": \"ID пальца\",\n                \"ko\": \"지문 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user5CodeID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Code ID\",\n                \"da\": \"Kode ID\",\n                \"de\": \"Code-ID\",\n                \"es\": \"ID de código\",\n                \"fr\": \"ID de code\",\n                \"it\": \"ID del codice\",\n                \"no\": \"Kode-ID\",\n                \"sv\": \"Kod-ID\",\n                \"pl\": \"ID kodu\",\n                \"ru\": \"ID кода\",\n                \"ko\": \"코드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user5CardID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Card ID\",\n                \"da\": \"Kort ID\",\n                \"de\": \"Karten-ID\",\n                \"es\": \"ID de tarjeta\",\n                \"fr\": \"ID de carte\",\n                \"it\": \"ID della carta\",\n                \"no\": \"Kort-ID\",\n                \"sv\": \"Kort-ID\",\n                \"pl\": \"ID karty\",\n                \"ru\": \"ID карты\",\n                \"ko\": \"카드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"lock6UserName\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"7 - User name\",\n                \"da\": \"7 - Brugernavn\",\n                \"de\": \"7 - Benutzername\",\n                \"es\": \"7 - Nombre de usuario\",\n                \"fr\": \"7 - Nom d'utilisateur\",\n                \"it\": \"7 - Nome utente\",\n                \"no\": \"7 - Brukernavn\",\n                \"sv\": \"7 - Användarnamn\",\n                \"pl\": \"7 - Nazwa użytkownika\",\n                \"ru\": \"7 - Имя пользователя\",\n                \"ko\": \"7 - 사용자 이름\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user6FingerID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Finger ID\",\n                \"da\": \"Finger ID\",\n                \"de\": \"Finger-ID\",\n                \"es\": \"ID de dedo\",\n                \"fr\": \"ID d'empreinte\",\n                \"it\": \"ID del dito\",\n                \"no\": \"Finger-ID\",\n                \"sv\": \"Finger-ID\",\n                \"pl\": \"ID palca\",\n                \"ru\": \"ID пальца\",\n                \"ko\": \"지문 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user6CodeID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Code ID\",\n                \"da\": \"Kode ID\",\n                \"de\": \"Code-ID\",\n                \"es\": \"ID de código\",\n                \"fr\": \"ID de code\",\n                \"it\": \"ID del codice\",\n                \"no\": \"Kode-ID\",\n                \"sv\": \"Kod-ID\",\n                \"pl\": \"ID kodu\",\n                \"ru\": \"ID кода\",\n                \"ko\": \"코드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user6CardID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Card ID\",\n                \"da\": \"Kort ID\",\n                \"de\": \"Karten-ID\",\n                \"es\": \"ID de tarjeta\",\n                \"fr\": \"ID de carte\",\n                \"it\": \"ID della carta\",\n                \"no\": \"Kort-ID\",\n                \"sv\": \"Kort-ID\",\n                \"pl\": \"ID karty\",\n                \"ru\": \"ID карты\",\n                \"ko\": \"카드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"lock7UserName\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"8 - User name\",\n                \"da\": \"8 - Brugernavn\",\n                \"de\": \"8 - Benutzername\",\n                \"es\": \"8 - Nombre de usuario\",\n                \"fr\": \"8 - Nom d'utilisateur\",\n                \"it\": \"8 - Nome utente\",\n                \"no\": \"8 - Brukernavn\",\n                \"sv\": \"8 - Användarnamn\",\n                \"pl\": \"8 - Nazwa użytkownika\",\n                \"ru\": \"8 - Имя пользователя\",\n                \"ko\": \"8 - 사용자 이름\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user7FingerID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Finger ID\",\n                \"da\": \"Finger ID\",\n                \"de\": \"Finger-ID\",\n                \"es\": \"ID de dedo\",\n                \"fr\": \"ID d'empreinte\",\n                \"it\": \"ID del dito\",\n                \"no\": \"Finger-ID\",\n                \"sv\": \"Finger-ID\",\n                \"pl\": \"ID palca\",\n                \"ru\": \"ID пальца\",\n                \"ko\": \"지문 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user7CodeID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Code ID\",\n                \"da\": \"Kode ID\",\n                \"de\": \"Code-ID\",\n                \"es\": \"ID de código\",\n                \"fr\": \"ID de code\",\n                \"it\": \"ID del codice\",\n                \"no\": \"Kode-ID\",\n                \"sv\": \"Kod-ID\",\n                \"pl\": \"ID kodu\",\n                \"ru\": \"ID кода\",\n                \"ko\": \"코드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user7CardID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Card ID\",\n                \"da\": \"Kort ID\",\n                \"de\": \"Karten-ID\",\n                \"es\": \"ID de tarjeta\",\n                \"fr\": \"ID de carte\",\n                \"it\": \"ID della carta\",\n                \"no\": \"Kort-ID\",\n                \"sv\": \"Kort-ID\",\n                \"pl\": \"ID karty\",\n                \"ru\": \"ID карты\",\n                \"ko\": \"카드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"lock8UserName\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"9 - User name\",\n                \"da\": \"9 - Brugernavn\",\n                \"de\": \"9 - Benutzername\",\n                \"es\": \"9 - Nombre de usuario\",\n                \"fr\": \"9 - Nom d'utilisateur\",\n                \"it\": \"9 - Nome utente\",\n                \"no\": \"9 - Brukernavn\",\n                \"sv\": \"9 - Användarnamn\",\n                \"pl\": \"9 - Nazwa użytkownika\",\n                \"ru\": \"9 - Имя пользователя\",\n                \"ko\": \"9 - 사용자 이름\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user8FingerID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Finger ID\",\n                \"da\": \"Finger ID\",\n                \"de\": \"Finger-ID\",\n                \"es\": \"ID de dedo\",\n                \"fr\": \"ID d'empreinte\",\n                \"it\": \"ID del dito\",\n                \"no\": \"Finger-ID\",\n                \"sv\": \"Finger-ID\",\n                \"pl\": \"ID palca\",\n                \"ru\": \"ID пальца\",\n                \"ko\": \"지문 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user8CodeID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Code ID\",\n                \"da\": \"Kode ID\",\n                \"de\": \"Code-ID\",\n                \"es\": \"ID de código\",\n                \"fr\": \"ID de code\",\n                \"it\": \"ID del codice\",\n                \"no\": \"Kode-ID\",\n                \"sv\": \"Kod-ID\",\n                \"pl\": \"ID kodu\",\n                \"ru\": \"ID кода\",\n                \"ko\": \"코드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user8CardID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Card ID\",\n                \"da\": \"Kort ID\",\n                \"de\": \"Karten-ID\",\n                \"es\": \"ID de tarjeta\",\n                \"fr\": \"ID de carte\",\n                \"it\": \"ID della carta\",\n                \"no\": \"Kort-ID\",\n                \"sv\": \"Kort-ID\",\n                \"pl\": \"ID karty\",\n                \"ru\": \"ID карты\",\n                \"ko\": \"카드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"lock9UserName\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"10 - User name\",\n                \"da\": \"10 - Brugernavn\",\n                \"de\": \"10 - Benutzername\",\n                \"es\": \"10 - Nombre de usuario\",\n                \"fr\": \"10 - Nom d'utilisateur\",\n                \"it\": \"10 - Nome utente\",\n                \"no\": \"10 - Brukernavn\",\n                \"sv\": \"10 - Användarnamn\",\n                \"pl\": \"10 - Nazwa użytkownika\",\n                \"ru\": \"10 - Имя пользователя\",\n                \"ko\": \"10 - 사용자 이름\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user9FingerID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Finger ID\",\n                \"da\": \"Finger ID\",\n                \"de\": \"Finger-ID\",\n                \"es\": \"ID de dedo\",\n                \"fr\": \"ID d'empreinte\",\n                \"it\": \"ID del dito\",\n                \"no\": \"Finger-ID\",\n                \"sv\": \"Finger-ID\",\n                \"pl\": \"ID palca\",\n                \"ru\": \"ID пальца\",\n                \"ko\": \"지문 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user9CodeID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Code ID\",\n                \"da\": \"Kode ID\",\n                \"de\": \"Code-ID\",\n                \"es\": \"ID de código\",\n                \"fr\": \"ID de code\",\n                \"it\": \"ID del codice\",\n                \"no\": \"Kode-ID\",\n                \"sv\": \"Kod-ID\",\n                \"pl\": \"ID kodu\",\n                \"ru\": \"ID кода\",\n                \"ko\": \"코드 ID\"\n              },\n              \"value\": \"\"\n            },\n            {\n              \"id\": \"user9CardID\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Card ID\",\n                \"da\": \"Kort ID\",\n                \"de\": \"Karten-ID\",\n                \"es\": \"ID de tarjeta\",\n                \"fr\": \"ID de carte\",\n                \"it\": \"ID della carta\",\n                \"no\": \"Kort-ID\",\n                \"sv\": \"Kort-ID\",\n                \"pl\": \"ID karty\",\n                \"ru\": \"ID карты\",\n                \"ko\": \"카드 ID\"\n              },\n              \"value\": \"\"\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/mi-airpurifier/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Basic Mi Air Purifier (WiFi)\",\n        \"nl\": \"Basis Mi Air Purifier (WiFi)\",\n        \"da\": \"Grundlæggende Mi Air Purifier (WiFi)\",\n        \"de\": \"Basis Mi Luftreiniger (WiFi)\",\n        \"es\": \"Purificador de aire Mi Básico (WiFi)\",\n        \"fr\": \"Purificateur d'air Mi Basique (WiFi)\",\n        \"it\": \"Depuratore d'aria Mi Base (WiFi)\",\n        \"no\": \"Grunnleggende Mi luftrenser (WiFi)\",\n        \"sv\": \"Grundläggande Mi luftrenare (WiFi)\",\n        \"pl\": \"Podstawowy Mi oczyszczacz powietrza (WiFi)\",\n        \"ru\": \"Базовый Mi очиститель воздуха (WiFi)\",\n        \"ko\": \"기본 Mi 공기 청정기 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/mi-airpurifier/assets/images/large.jpg\",\n        \"small\": \"drivers/mi-airpurifier/assets/images/small.jpg\"\n      },\n      \"class\": \"airpurifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"measure_pm25\",\n        \"airpurifier_mode\"\n      ],\n      \"id\": \"mi-airpurifier\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"LED\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Buzzer\",\n                \"de\": \"Summerton\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Buzzer\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Buzzer\",\n                \"sv\": \"Buzzer\",\n                \"pl\": \"Buzzer\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"부저\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnelås\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo para niños\",\n                \"fr\": \"Verrouillage enfant\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barnesikring\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Zabezpieczenie dzieci\",\n                \"ru\": \"Блокировка для детей\",\n                \"ko\": \"어린이 잠금 장치\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/mi-aqara-cube/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Aqara Cube (Gateway)\",\n        \"nl\": \"Mi Aqara Kubus (Gateway)\",\n        \"da\": \"Mi Aqara Cube (Gateway)\",\n        \"de\": \"Mi Aqara Würfel (Gateway)\",\n        \"es\": \"Mi Aqara Cubo (Gateway)\",\n        \"fr\": \"Mi Aqara Cube (Gateway)\",\n        \"it\": \"Mi Aqara Cubo (Gateway)\",\n        \"no\": \"Mi Aqara Cube (Gateway)\",\n        \"sv\": \"Mi Aqara Kub (Gateway)\",\n        \"pl\": \"Mi Aqara Kostka (Gateway)\",\n        \"ru\": \"Mi Aqara Куб (Gateway)\",\n        \"ko\": \"Mi Aqara 큐브 (Gateway)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/mi-aqara-cube/assets/images/large.png\",\n        \"small\": \"/drivers/mi-aqara-cube/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2450\"\n        ]\n      },\n      \"id\": \"mi-aqara-cube\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"pt\": \"Configurações do Dispositivo\",\n            \"zh\": \"设备设置\",\n            \"ja\": \"デバイス設定\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/mi-button/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Wireless Button (Gateway)\",\n        \"nl\": \"Mi Wireless Button (Gateway)\",\n        \"da\": \"Mi Wireless Knap (Gateway)\",\n        \"de\": \"Mi Drahtloser Knopf (Gateway)\",\n        \"es\": \"Mi Botón Inalámbrico (Gateway)\",\n        \"fr\": \"Mi Bouton Sans Fil (Gateway)\",\n        \"it\": \"Mi Pulsante Senza Fili (Gateway)\",\n        \"no\": \"Mi Trådløs Knapp (Gateway)\",\n        \"sv\": \"Mi Trådlös Knapp (Gateway)\",\n        \"pl\": \"Mi Bezprzewodowy Przycisk (Gateway)\",\n        \"ru\": \"Mi Беспроводная Кнопка (Шлюз)\",\n        \"ko\": \"Mi 무선 버튼 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/mi-button/assets/images/large.png\",\n        \"small\": \"/drivers/mi-button/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2032\"\n        ]\n      },\n      \"id\": \"mi-button\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración de dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"기기 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/mi-humidifier/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Humidifier v1 - Generic (WiFi)\",\n        \"nl\": \"Mi Luchtbevochtiger v1 - Generic (WiFi)\",\n        \"da\": \"Mi Luftfugter v1 - Generisk (WiFi)\",\n        \"de\": \"Mi Luftbefeuchter v1 - Generisch (WiFi)\",\n        \"es\": \"Mi Humidificador v1 - Genérico (WiFi)\",\n        \"fr\": \"Mi Humidificateur v1 - Générique (WiFi)\",\n        \"it\": \"Mi Umidificatore v1 - Generico (WiFi)\",\n        \"no\": \"Mi Luftfukter v1 - Generisk (WiFi)\",\n        \"sv\": \"Mi Luftfuktare v1 - Generisk (WiFi)\",\n        \"pl\": \"Mi Nawilżacz v1 - Ogólny (WiFi)\",\n        \"ru\": \"Mi Увлажнитель v1 - Общий (WiFi)\",\n        \"ko\": \"Mi 가습기 v1 - 일반형 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/mi-humidifier/assets/images/large.jpg\",\n        \"small\": \"drivers/mi-humidifier/assets/images/small.jpg\"\n      },\n      \"class\": \"humidifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"measure_temperature\",\n        \"measure_humidity\"\n      ],\n      \"deprecated\": true,\n      \"id\": \"mi-humidifier\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/mi-humidifier2/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Humidifier v2 - Generic (WiFi)\",\n        \"nl\": \"Mi Luchtbevochtiger v2 - Generic (WiFi)\",\n        \"da\": \"Mi Luftfugter v2 - Generisk (WiFi)\",\n        \"de\": \"Mi Luftbefeuchter v2 - Generisch (WiFi)\",\n        \"es\": \"Mi Humidificador v2 - Genérico (WiFi)\",\n        \"fr\": \"Mi Humidificateur v2 - Générique (WiFi)\",\n        \"it\": \"Mi Umidificatore v2 - Generico (WiFi)\",\n        \"no\": \"Mi Luftfukter v2 - Generisk (WiFi)\",\n        \"sv\": \"Mi Luftfuktare v2 - Generisk (WiFi)\",\n        \"pl\": \"Mi Nawilżacz v2 - Ogólny (WiFi)\",\n        \"ru\": \"Mi Увлажнитель v2 - Общий (WiFi)\",\n        \"ko\": \"Mi 가습기 v2 - 일반 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/mi-humidifier2/assets/images/large.jpg\",\n        \"small\": \"drivers/mi-humidifier2/assets/images/small.jpg\"\n      },\n      \"class\": \"humidifier\",\n      \"capabilities\": [\n        \"onoff\",\n        \"measure_temperature\",\n        \"measure_humidity\",\n        \"measure_waterlevel\",\n        \"humidifier2_mode\"\n      ],\n      \"deprecated\": true,\n      \"id\": \"mi-humidifier2\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingen\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"dropdown\",\n              \"value\": \"1\",\n              \"label\": {\n                \"en\": \"LED brightness\",\n                \"nl\": \"LED helderheid\",\n                \"da\": \"LED-ljusstyrke\",\n                \"de\": \"LED-Helligkeit\",\n                \"es\": \"Brillo LED\",\n                \"fr\": \"Luminosité LED\",\n                \"it\": \"Luminosità LED\",\n                \"no\": \"LED-lysstyrke\",\n                \"sv\": \"LED-ljusstyrka\",\n                \"pl\": \"Jasność LED\",\n                \"ru\": \"Яркость светодиода\",\n                \"ko\": \"LED 밝기\"\n              },\n              \"values\": [\n                {\n                  \"id\": \"1\",\n                  \"label\": {\n                    \"en\": \"Bright\",\n                    \"nl\": \"Helder\",\n                    \"da\": \"Lyst\",\n                    \"de\": \"Hell\",\n                    \"es\": \"Brillante\",\n                    \"fr\": \"Luminosité\",\n                    \"it\": \"Luminoso\",\n                    \"no\": \"Lys\",\n                    \"sv\": \"Ljusstark\",\n                    \"pl\": \"Jasny\",\n                    \"ru\": \"Яркий\",\n                    \"ko\": \"밝음\"\n                  }\n                },\n                {\n                  \"id\": \"2\",\n                  \"label\": {\n                    \"en\": \"Dim\",\n                    \"nl\": \"Gedimd\",\n                    \"da\": \"Dæmpet\",\n                    \"de\": \"Gedimmt\",\n                    \"es\": \"Tenue\",\n                    \"fr\": \"Atténué\",\n                    \"it\": \"Soffuso\",\n                    \"no\": \"Dempe\",\n                    \"sv\": \"Dämpad\",\n                    \"pl\": \"Przyciemniony\",\n                    \"ru\": \"Тусклый\",\n                    \"ko\": \"어두움\"\n                  }\n                },\n                {\n                  \"id\": \"3\",\n                  \"label\": {\n                    \"en\": \"Off\",\n                    \"nl\": \"Uit\",\n                    \"da\": \"Slukket\",\n                    \"de\": \"Aus\",\n                    \"es\": \"Apagado\",\n                    \"fr\": \"Éteint\",\n                    \"it\": \"Spento\",\n                    \"no\": \"Av\",\n                    \"sv\": \"Av\",\n                    \"pl\": \"Wyłączony\",\n                    \"ru\": \"Выключено\",\n                    \"ko\": \"끔\"\n                  }\n                }\n              ]\n            },\n            {\n              \"id\": \"buzzer\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Buzzer\",\n                \"nl\": \"Buzzer\",\n                \"da\": \"Summer\",\n                \"de\": \"Summer\",\n                \"es\": \"Zumbador\",\n                \"fr\": \"Sonnerie\",\n                \"it\": \"Cicalino\",\n                \"no\": \"Buzzer\",\n                \"sv\": \"Summer\",\n                \"pl\": \"Brzęczyk\",\n                \"ru\": \"Зуммер\",\n                \"ko\": \"부저\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnelås\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo infantil\",\n                \"fr\": \"Verrouillage enfant\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barnelås\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada rodzicielska\",\n                \"ru\": \"Детский замок\",\n                \"ko\": \"어린이 잠금\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/mi-magnet-sensor/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Magnet Sensor (Gateway)\",\n        \"nl\": \"Mi magneetsensor (Gateway)\",\n        \"da\": \"Mi Magnet Sensor (Gateway)\",\n        \"de\": \"Mi Magnetsensor (Gateway)\",\n        \"es\": \"Sensor Magnético Mi (Gateway)\",\n        \"fr\": \"Capteur Magnétique Mi (Gateway)\",\n        \"it\": \"Sensore Magnetico Mi (Gateway)\",\n        \"no\": \"Mi Magnet Sensor (Gateway)\",\n        \"sv\": \"Mi Magnet Sensor (Gateway)\",\n        \"pl\": \"Czujnik Magnetyczny Mi (Gateway)\",\n        \"ru\": \"Магнитный датчик Mi (Gateway)\",\n        \"ko\": \"미 자석 센서 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/mi-magnet-sensor/assets/images/large.png\",\n        \"small\": \"/drivers/mi-magnet-sensor/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"alarm_contact\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR1632\"\n        ]\n      },\n      \"id\": \"mi-magnet-sensor\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User settings\",\n            \"nl\": \"Gebruikersinstellingen\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración de usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"inverted\",\n              \"type\": \"checkbox\",\n              \"label\": {\n                \"en\": \"Inverted alarm\",\n                \"nl\": \"Omgekeerd alarm\",\n                \"da\": \"Ovendvendt alarm\",\n                \"de\": \"Umgekehrter Alarm\",\n                \"es\": \"Alarma invertida\",\n                \"fr\": \"Alarme inversée\",\n                \"it\": \"Allarme inverso\",\n                \"no\": \"Omvendt alarm\",\n                \"sv\": \"Inverterat larm\",\n                \"pl\": \"Odwrócony alarm\",\n                \"ru\": \"Инвертированная тревога\",\n                \"ko\": \"반전 알람\"\n              },\n              \"value\": false\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/mi-motion-sensor/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Motion Sensor (Gateway)\",\n        \"nl\": \"Mi bewegingssensor (Gateway)\",\n        \"da\": \"Mi bevægelsessensor (Gateway)\",\n        \"de\": \"Mi Bewegungssensor (Gateway)\",\n        \"es\": \"Mi sensor de movimiento (Gateway)\",\n        \"fr\": \"Mi capteur de mouvement (Gateway)\",\n        \"it\": \"Sensore di movimento Mi (Gateway)\",\n        \"no\": \"Mi bevegelsessensor (Gateway)\",\n        \"sv\": \"Mi rörelsesensor (Gateway)\",\n        \"pl\": \"Czujnik ruchu Mi (Gateway)\",\n        \"ru\": \"Датчик движения Mi (Gateway)\",\n        \"ko\": \"미 모션 센서 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/mi-motion-sensor/assets/images/large.png\",\n        \"small\": \"/drivers/mi-motion-sensor/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"alarm_motion\",\n        \"measure_luminance\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2450\"\n        ]\n      },\n      \"id\": \"mi-motion-sensor\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Duration of the motion alarm\",\n            \"nl\": \"Duur van het bewegingsalarm\",\n            \"da\": \"Varighed af bevægelsesalarmen\",\n            \"de\": \"Dauer des Bewegungalarms\",\n            \"es\": \"Duración de la alarma de movimiento\",\n            \"fr\": \"Durée de l'alarme de mouvement\",\n            \"it\": \"Durata dell'allarme di movimento\",\n            \"no\": \"Varighet på bevegelsesalarmen\",\n            \"sv\": \"Längd på rörelsealarm\",\n            \"pl\": \"Czas trwania alarmu ruchu\",\n            \"ru\": \"Длительность тревоги о движении\",\n            \"ko\": \"움직임 경보의 지속 시간\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_duration_number\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Disable after\",\n                \"nl\": \"Uitschakelen na\",\n                \"da\": \"Deaktiver efter\",\n                \"de\": \"Deaktivieren nach\",\n                \"es\": \"Desactivar después de\",\n                \"fr\": \"Désactiver après\",\n                \"it\": \"Disattiva dopo\",\n                \"no\": \"Deaktiver etter\",\n                \"sv\": \"Inaktivera efter\",\n                \"pl\": \"Wyłącz po\",\n                \"ru\": \"Отключить через\",\n                \"ko\": \"다음 후 비활성화\"\n              },\n              \"hint\": {\n                \"en\": \"Here you can specify after what time the alarm signal from the motion sensor will be stopped, if a motion is detected it is not detected. Usually this is for 60 seconds, you can set from 5 to 86400 seconds. \\n \\n Attention! Values less than 60 seconds are relevant only for independently modified sensors that have the ability to transmit information about the movement with a frequency of 5 seconds.\",\n                \"nl\": \"Hier kunt u opgeven hoe laat het alarmsignaal van de bewegingssensor wordt gestopt, als een beweging wordt gedetecteerd, wordt deze niet gedetecteerd. Gewoonlijk is dit 60 seconden, u kunt 5 tot 86400 seconden instellen.  n  n Let op! Waarden minder dan 60 seconden zijn alleen relevant voor onafhankelijk aangepaste sensoren die de mogelijkheid hebben om informatie over de beweging te verzenden met een frequentie van 5 seconden.\",\n                \"da\": \"Her kan du angive, hvornår alarmsignalet fra bevægelsessensorer skal stoppes, hvis en bevægelse detekteres. Normalt er dette 60 sekunder, du kan indstille fra 5 til 86400 sekunder. \\n \\n Opmærksomhed! Værdier mindre end 60 sekunder er kun relevante for selvstændigt modificerede sensorer, der har mulighed for at transmittere information om bevægelsen med en frekvens på 5 sekunder.\",\n                \"de\": \"Hier können Sie angeben, nach welcher Zeit das Alarmsignal vom Bewegungssensor gestoppt wird, wenn eine Bewegung erkannt wird. Normalerweise dauert dies 60 Sekunden. Sie können von 5 bis 86400 Sekunden einstellen. \\n \\n Achtung! Werte unter 60 Sekunden sind nur für unabhängig modifizierte Sensoren relevant, die in der Lage sind, Bewegungsinformationen mit einer Frequenz von 5 Sekunden zu senden.\",\n                \"es\": \"Aquí puede especificar después de cuánto tiempo se detendrá la señal de alarma del sensor de movimiento, si se detecta un movimiento no se detecta. Por lo general, esto es durante 60 segundos, puede configurar de 5 a 86400 segundos. \\n \\n ¡Atención! Los valores inferiores a 60 segundos son relevantes solo para sensores modificados de forma independiente que tienen la capacidad de transmitir información sobre el movimiento con una frecuencia de 5 segundos.\",\n                \"fr\": \"Ici, vous pouvez spécifier après combien de temps le signal d'alarme du détecteur de mouvement sera arrêté, si un mouvement est détecté, il n'est pas détecté. En général, cela dure 60 secondes, vous pouvez régler de 5 à 86400 secondes. \\n \\n Attention ! Les valeurs inférieures à 60 secondes ne sont pertinentes que pour les détecteurs modifiés indépendamment qui ont la capacité de transmettre des informations sur les mouvements avec une fréquence de 5 secondes.\",\n                \"it\": \"Qui puoi specificare dopo quanto tempo il segnale di allarme dal sensore di movimento verrà interrotto, se viene rilevato un movimento non viene rilevato. Di solito è per 60 secondi, puoi impostare da 5 a 86400 secondi. \\n \\n Attenzione! I valori inferiori a 60 secondi sono rilevanti solo per sensori modificati indipendentemente che hanno la capacità di trasmettere informazioni sul movimento con una frequenza di 5 secondi.\",\n                \"no\": \"Her kan du angi etter hvor lang tid alarmsignalet fra bevegelsessensoren vil bli stoppet, hvis en bevegelse blir oppdaget, blir det ikke oppdaget. Vanligvis er dette i 60 sekunder, du kan stille fra 5 til 86400 sekunder. \\n \\n Oppmerksomhet! Verdier mindre enn 60 sekunder er bare relevante for uavhengig modifiserte sensorer som har mulighet til å overføre informasjon om bevegelsen med en frekvens på 5 sekunder.\",\n                \"sv\": \"Här kan du specificera efter hur lång tid larmsignalen från rörelsesensorn ska stoppas, om en rörelse detekteras som inte detekteras. Vanligtvis är detta i 60 sekunder, du kan ställa från 5 till 86400 sekunder. \\n \\n Observera! Värden mindre än 60 sekunder är endast relevanta för oberoende modifierade sensorer som har möjlighet att överföra information om rörelsen med en frekvens på 5 sekunder.\",\n                \"pl\": \"Tutaj możesz określić, po jakim czasie sygnał alarmowy z czujnika ruchu zostanie zatrzymany, jeśli ruch zostanie wykryty, nie jest wykrywany. Zwykle trwa to 60 sekund, możesz ustawić od 5 do 86400 sekund. \\n \\n Uwaga! Wartości poniżej 60 sekund dotyczą wyłącznie samodzielnie zmodyfikowanych czujników, które mogą przesyłać informacje o ruchu z częstotliwością 5 sekund.\",\n                \"ru\": \"Здесь вы можете указать, через какое время сигнал тревоги от датчика движения будет остановлен, если движение обнаружено, оно не обнаруживается. Обычно это занимает 60 секунд, вы можете установить от 5 до 86400 секунд. \\n \\n Внимание! Значения менее 60 секунд актуальны только для независимо модифицированных датчиков, которые могут передавать информацию о движении с частотой 5 секунд.\",\n                \"ko\": \"여기서 움직임 센서의 경보 신호가 중지되는 시간을 지정할 수 있습니다. 움직임이 감지된 경우 감지되지 않습니다. 보통 60초 동안이며, 5초에서 86400초까지 설정할 수 있습니다. \\n \\n 주의! 60초 미만의 값은 5초 주기로 움직임 정보를 전송할 수 있는 독립적으로 수정된 센서에만 해당됩니다.\"\n              },\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 86400\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/mi-plug/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Smart Plug (Gateway)\",\n        \"nl\": \"Mi Smart Plug (Gateway)\",\n        \"da\": \"Mi Smart Plug (Gateway)\",\n        \"de\": \"Mi Smart Plug (Gateway)\",\n        \"es\": \"Mi Enchufe Inteligente (Gateway)\",\n        \"fr\": \"Mi Prise Intelligente (Gateway)\",\n        \"it\": \"Mi Presa Intelligente (Gateway)\",\n        \"no\": \"Mi Smart Plugg (Gateway)\",\n        \"sv\": \"Mi Smart Plugg (Gateway)\",\n        \"pl\": \"Mi Inteligentny Wtyczka (Gateway)\",\n        \"ru\": \"Mi Умная Розетка (Гейтвей)\",\n        \"ko\": \"Mi 스마트 플러그 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/mi-plug/assets/images/large.png\",\n        \"small\": \"/drivers/mi-plug/assets/images/small.png\"\n      },\n      \"class\": \"socket\",\n      \"capabilities\": [\n        \"onoff\",\n        \"meter_power\",\n        \"measure_power\"\n      ],\n      \"id\": \"mi-plug\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Ajustes de dispositivo\",\n            \"fr\": \"Réglages de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"디바이스 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"gatewaySid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789ab\",\n              \"label\": {\n                \"en\": \"Gateway SID\",\n                \"nl\": \"Gateway SID\",\n                \"da\": \"Gateway SID\",\n                \"de\": \"Gateway SID\",\n                \"es\": \"Gateway SID\",\n                \"fr\": \"Gateway SID\",\n                \"it\": \"Gateway SID\",\n                \"no\": \"Gateway SID\",\n                \"sv\": \"Gateway SID\",\n                \"pl\": \"Gateway SID\",\n                \"ru\": \"Gateway SID\",\n                \"ko\": \"Gateway SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/mi-power-plug/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Power Plug (WiFi)\",\n        \"nl\": \"Mi Power Plug (WiFi)\",\n        \"da\": \"Mi Power Plug (WiFi)\",\n        \"de\": \"Mi Power Plug (WiFi)\",\n        \"es\": \"Mi Power Plug (WiFi)\",\n        \"fr\": \"Mi Power Plug (WiFi)\",\n        \"it\": \"Mi Power Plug (WiFi)\",\n        \"no\": \"Mi Power Plug (WiFi)\",\n        \"sv\": \"Mi Power Plug (WiFi)\",\n        \"pl\": \"Mi Power Plug (WiFi)\",\n        \"ru\": \"Mi Power Plug (WiFi)\",\n        \"ko\": \"Mi Power Plug (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/mi-power-plug/assets/images/large.jpg\",\n        \"small\": \"drivers/mi-power-plug/assets/images/small.jpg\"\n      },\n      \"class\": \"socket\",\n      \"capabilities\": [\n        \"onoff\"\n      ],\n      \"deprecated\": true,\n      \"id\": \"mi-power-plug\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/mi-power-strip/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Power Strip Generic (WiFi)\",\n        \"nl\": \"Mi Power Strip Generic (WiFi)\",\n        \"da\": \"Mi Power Strip Generisk (WiFi)\",\n        \"de\": \"Mi Power Strip Generic (WiFi)\",\n        \"es\": \"Mi Power Strip Genérico (WiFi)\",\n        \"fr\": \"Mi Power Strip Générique (WiFi)\",\n        \"it\": \"Mi Power Strip Generico (WiFi)\",\n        \"no\": \"Mi Power Strip Generisk (WiFi)\",\n        \"sv\": \"Mi Power Strip Generisk (WiFi)\",\n        \"pl\": \"Mi Power Strip Generic (WiFi)\",\n        \"ru\": \"Mi Power Strip Generic (WiFi)\",\n        \"ko\": \"Mi 파워 스트립 일반 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/mi-power-strip/assets/images/large.jpg\",\n        \"small\": \"drivers/mi-power-strip/assets/images/small.jpg\"\n      },\n      \"class\": \"socket\",\n      \"capabilities\": [\n        \"onoff\",\n        \"measure_power\",\n        \"meter_power\"\n      ],\n      \"id\": \"mi-power-strip\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/mi-robot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Basic Vacuum Cleaner (WiFi)\",\n        \"nl\": \"Basis Vacuum Cleaner (WiFi)\",\n        \"da\": \"Basisstøvsuger (WiFi)\",\n        \"de\": \"Einfacher Staubsauger (WiFi)\",\n        \"es\": \"Aspiradora Básica (WiFi)\",\n        \"fr\": \"Aspirateur de base (WiFi)\",\n        \"it\": \"Aspirapolvere base (WiFi)\",\n        \"no\": \"Grunnleggende støvsuger (WiFi)\",\n        \"sv\": \"Grundläggande dammsugare (WiFi)\",\n        \"pl\": \"Podstawowy odkurzacz (WiFi)\",\n        \"ru\": \"Базовый пылесос (WiFi)\",\n        \"ko\": \"기본 청소기 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/mi-robot/assets/images/large.jpg\",\n        \"small\": \"drivers/mi-robot/assets/images/small.jpg\"\n      },\n      \"class\": \"vacuumcleaner\",\n      \"capabilities\": [\n        \"onoff\",\n        \"vacuumcleaner_state\",\n        \"measure_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"INTERNAL\"\n        ]\n      },\n      \"id\": \"mi-robot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"pt\": \"Configurações do dispositivo\",\n            \"ja\": \"デバイス設定\",\n            \"zh\": \"设备设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/mi-temperature-humidity-sensor/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Temperature & Humidity Sensor (Gateway)\",\n        \"nl\": \"Mi temperatuur & luchtvochtigheid sensor (Gateway)\",\n        \"da\": \"Mi Temperatur- og Fugtighedssensor (Gateway)\",\n        \"de\": \"Mi Temperatur- und Feuchtigkeitssensor (Gateway)\",\n        \"es\": \"Mi Sensor de Temperatura y Humedad (Gateway)\",\n        \"fr\": \"Capteur de Température et d'Humidité Mi (Gateway)\",\n        \"it\": \"Sensore di Temperatura e Umidità Mi (Gateway)\",\n        \"no\": \"Mi Temperatur- og Fuktighetssensor (Gateway)\",\n        \"sv\": \"Mi Temperatur- och Fuktighetssensor (Gateway)\",\n        \"pl\": \"Czujnik Temperatury i Wilgotności Mi (Gateway)\",\n        \"ru\": \"Датчик температуры и влажности Mi (Gateway)\",\n        \"ko\": \"Mi 온습도 센서 (Gateway)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/mi-temperature-humidity-sensor/assets/images/large.png\",\n        \"small\": \"/drivers/mi-temperature-humidity-sensor/assets/images/small.png\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"measure_temperature\",\n        \"measure_humidity\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR2032\"\n        ]\n      },\n      \"id\": \"mi-temperature-humidity-sensor\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Offset settings\",\n            \"nl\": \"Offset instellingen\",\n            \"da\": \"Offset indstillinger\",\n            \"de\": \"Offset Einstellungen\",\n            \"es\": \"Configuraciones de compensación\",\n            \"fr\": \"Paramètres de décalage\",\n            \"it\": \"Impostazioni offset\",\n            \"no\": \"Forskyvningsinnstillinger\",\n            \"sv\": \"Förskjutningsinställningar\",\n            \"pl\": \"Ustawienia przesunięcia\",\n            \"ru\": \"Настройки смещения\",\n            \"ko\": \"오프셋 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"addOrTakeOffset\",\n              \"type\": \"radio\",\n              \"label\": {\n                \"en\": \"Offset\",\n                \"nl\": \"Offset\",\n                \"da\": \"Offset\",\n                \"de\": \"Offset\",\n                \"es\": \"Compensación\",\n                \"fr\": \"Décalage\",\n                \"it\": \"Offset\",\n                \"no\": \"Forskyvning\",\n                \"sv\": \"Förskjutning\",\n                \"pl\": \"Przesunięcie\",\n                \"ru\": \"Смещение\",\n                \"ko\": \"오프셋\"\n              },\n              \"value\": \"add\",\n              \"values\": [\n                {\n                  \"id\": \"add\",\n                  \"label\": {\n                    \"en\": \"Add offset\",\n                    \"nl\": \"Offset toevoegen\",\n                    \"da\": \"Tilføj offset\",\n                    \"de\": \"Offset hinzufügen\",\n                    \"es\": \"Agregar compensación\",\n                    \"fr\": \"Ajouter un décalage\",\n                    \"it\": \"Aggiungi offset\",\n                    \"no\": \"Legg til forskyvning\",\n                    \"sv\": \"Lägg till förskjutning\",\n                    \"pl\": \"Dodaj przesunięcie\",\n                    \"ru\": \"Добавить смещение\",\n                    \"ko\": \"오프셋 추가\"\n                  }\n                },\n                {\n                  \"id\": \"take\",\n                  \"label\": {\n                    \"en\": \"Minus offset\",\n                    \"nl\": \"Offset aftrekken\",\n                    \"da\": \"Minus offset\",\n                    \"de\": \"Offset abziehen\",\n                    \"es\": \"Restar compensación\",\n                    \"fr\": \"Moins offset\",\n                    \"it\": \"Sottrai offset\",\n                    \"no\": \"Minus forskyvning\",\n                    \"sv\": \"Minus förskjutning\",\n                    \"pl\": \"Odejmij przesunięcie\",\n                    \"ru\": \"Минус смещение\",\n                    \"ko\": \"오프셋 빼기\"\n                  }\n                }\n              ]\n            },\n            {\n              \"id\": \"offset\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Offset\",\n                \"nl\": \"Offset\",\n                \"da\": \"Offset\",\n                \"de\": \"Offset\",\n                \"es\": \"Compensación\",\n                \"fr\": \"Décalage\",\n                \"it\": \"Offset\",\n                \"no\": \"Forskyvning\",\n                \"sv\": \"Förskjutning\",\n                \"pl\": \"Przesunięcie\",\n                \"ru\": \"Смещение\",\n                \"ko\": \"오프셋\"\n              },\n              \"value\": 0,\n              \"min\": 0,\n              \"max\": 5\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuraciones del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/natgas_sensor/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mijia Gas Leak Detector (Gateway)\",\n        \"nl\": \"Mijia Gas Leak Detector (Gateway)\",\n        \"da\": \"Mijia Gaslæksensor (Gateway)\",\n        \"de\": \"Mijia Gasleckdetektor (Gateway)\",\n        \"es\": \"Detector de Fugas de Gas Mijia (Gateway)\",\n        \"fr\": \"Détecteur de Fuites de Gaz Mijia (Gateway)\",\n        \"it\": \"Rilevatore di Perdite di Gas Mijia (Gateway)\",\n        \"no\": \"Mijia Gasslekkasjedetektor (Gateway)\",\n        \"sv\": \"Mijia Gassläckdetektor (Gateway)\",\n        \"pl\": \"Czujnik Wycieków Gazu Mijia (Gateway)\",\n        \"ru\": \"Датчик Утечки Газа Mijia (Gateway)\",\n        \"ko\": \"Mijia 가스 누출 감지기 (Gateway)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/natgas_sensor/assets/images/large.jpg\",\n        \"small\": \"/drivers/natgas_sensor/assets/images/small.jpg\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"alarm_co\",\n        \"measure_gas_density\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"capabilitiesOptions\": {\n        \"alarm_co\": {\n          \"title\": {\n            \"en\": \"Gas Alarm\",\n            \"nl\": \"Gasalarm\",\n            \"da\": \"Gasalarm\",\n            \"de\": \"Gasalarm\",\n            \"es\": \"Alarma de gas\",\n            \"fr\": \"Alarme de gaz\",\n            \"it\": \"Allarme gas\",\n            \"no\": \"Gassalarm\",\n            \"sv\": \"Gaslarm\",\n            \"pl\": \"Alarm Gazowy\",\n            \"ru\": \"Газовая Сигнализация\",\n            \"ko\": \"가스 경보\"\n          }\n        }\n      },\n      \"energy\": {\n        \"batteries\": [\n          \"CR2450\"\n        ]\n      },\n      \"id\": \"natgas_sensor\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Duration of the natural gas detected alarm in seconds\",\n            \"nl\": \"Duur van het gas gedetecteerd alarm in seconden\",\n            \"da\": \"Varighed af detekteret naturgasalarm i sekunder\",\n            \"de\": \"Dauer des erkannten Erdgasalarm in Sekunden\",\n            \"es\": \"Duración de la alarma de gas natural detectado en segundos\",\n            \"fr\": \"Durée de l'alarme de gaz naturel détecté en secondes\",\n            \"it\": \"Durata dell'allarme di gas naturale rilevato in secondi\",\n            \"no\": \"Varighet av naturliggassalarm oppdaget i sekunder\",\n            \"sv\": \"Varaktighet av detekterat naturgaslarm i sekunder\",\n            \"pl\": \"Czas trwania alarmu wykrycia gazu ziemnego w sekundach\",\n            \"ru\": \"Продолжительность сработавшей тревоги по обнаружению природного газа в секундах\",\n            \"ko\": \"천연가스 감지 경보 지속 시간 (초)\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_duration_number\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Disable after\",\n                \"nl\": \"Uitschakelen na\",\n                \"da\": \"Deaktiver efter\",\n                \"de\": \"Deaktivieren nach\",\n                \"es\": \"Desactivar después de\",\n                \"fr\": \"Désactiver après\",\n                \"it\": \"Disabilita dopo\",\n                \"no\": \"Deaktiver etter\",\n                \"sv\": \"Inaktivera efter\",\n                \"pl\": \"Wyłącz po\",\n                \"ru\": \"Отключить через\",\n                \"ko\": \"비활성화 시간\"\n              },\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 60,\n                \"max\": 86400\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/pet_waterer_xiaomi/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Xiaomi Smart Pet Fountain\",\n        \"nl\": \"Xiaomi Slimme Huisdierfontein\",\n        \"da\": \"Xiaomi Smart Kæledyrsfountain\",\n        \"de\": \"Xiaomi Smarter Haustierbrunnen\",\n        \"es\": \"Fuente Inteligente Xiaomi para Mascotas\",\n        \"fr\": \"Fontaine Intelligente Xiaomi pour Animaux\",\n        \"it\": \"Fontana Intelligente Xiaomi per Animali\",\n        \"no\": \"Xiaomi Smart Kjæledyrfontene\",\n        \"sv\": \"Xiaomi Smart Husdjursfontän\",\n        \"pl\": \"Xiaomi Inteligentna Fontanna dla Zwierząt\",\n        \"ru\": \"Умный фонтан Xiaomi для домашних животных\",\n        \"ko\": \"샤오미 스마트 펫 분수대\"\n      },\n      \"images\": {\n        \"large\": \"drivers/pet_waterer_xiaomi/assets/images/large.jpg\",\n        \"small\": \"drivers/pet_waterer_xiaomi/assets/images/small.jpg\"\n      },\n      \"class\": \"petfeeder\",\n      \"capabilities\": [\n        \"onoff\",\n        \"petwaterdispenser_mmgg_mode_3\",\n        \"alarm_tank_empty\",\n        \"alarm_pump_supply\",\n        \"measure_filter_life\",\n        \"measure_filter_days_left\",\n        \"alarm_water_shortage\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"INTERNAL\"\n        ]\n      },\n      \"tokens\": [\n        {\n          \"name\": \"error\",\n          \"type\": \"string\",\n          \"title\": {\n            \"en\": \"Device error\",\n            \"nl\": \"Apparaatfout\",\n            \"da\": \"Enhedsfejl\",\n            \"de\": \"Gerätefehler\",\n            \"es\": \"Error del dispositivo\",\n            \"fr\": \"Erreur de l'appareil\",\n            \"it\": \"Errore dispositivo\",\n            \"no\": \"Enhetsfeil\",\n            \"sv\": \"Enhetsfel\",\n            \"pl\": \"Błąd urządzenia\",\n            \"ru\": \"Ошибка устройства\",\n            \"ko\": \"디바이스 오류\"\n          }\n        }\n      ],\n      \"id\": \"pet_waterer_xiaomi\",\n      \"settings\": [\n        {\n          \"id\": \"led\",\n          \"type\": \"checkbox\",\n          \"label\": {\n            \"en\": \"LED\",\n            \"nl\": \"LED\",\n            \"da\": \"LED\",\n            \"de\": \"LED\",\n            \"es\": \"LED\",\n            \"fr\": \"LED\",\n            \"it\": \"LED\",\n            \"no\": \"LED\",\n            \"sv\": \"LED\",\n            \"pl\": \"LED\",\n            \"ru\": \"Светодиод\",\n            \"ko\": \"LED\"\n          },\n          \"value\": true\n        },\n        {\n          \"id\": \"filter_life_remaining\",\n          \"type\": \"label\",\n          \"label\": {\n            \"en\": \"Filter remaining\",\n            \"nl\": \"Filter over\",\n            \"da\": \"Filter tilbage\",\n            \"de\": \"Filter verbleibend\",\n            \"es\": \"Filtro restante\",\n            \"fr\": \"Filtre restant\",\n            \"it\": \"Filtro rimanente\",\n            \"no\": \"Filter gjenstår\",\n            \"sv\": \"Filter kvar\",\n            \"pl\": \"Filtr pozostały\",\n            \"ru\": \"Фильтр остался\",\n            \"ko\": \"남은 필터\"\n          },\n          \"value\": \"0%\"\n        },\n        {\n          \"id\": \"cotton_life_remaining\",\n          \"type\": \"label\",\n          \"label\": {\n            \"en\": \"Cotton remaining\",\n            \"nl\": \"Cotton over\",\n            \"da\": \"Bomuld tilbage\",\n            \"de\": \"Baumwolle verbleibend\",\n            \"es\": \"Algodón restante\",\n            \"fr\": \"Coton restant\",\n            \"it\": \"Cotone rimanente\",\n            \"no\": \"Bomull gjenstår\",\n            \"sv\": \"Bomull kvar\",\n            \"pl\": \"Bawełna pozostała\",\n            \"ru\": \"Осталось хлопка\",\n            \"ko\": \"남은 면\"\n          },\n          \"value\": \"0%\"\n        },\n        {\n          \"id\": \"cleaning_time_remaining\",\n          \"type\": \"label\",\n          \"label\": {\n            \"en\": \"Cleaning time remaining\",\n            \"nl\": \"Opschoon tijd over\",\n            \"da\": \"Rengøringstid tilbage\",\n            \"de\": \"Reinigungszeit verbleibend\",\n            \"es\": \"Tiempo de limpieza restante\",\n            \"fr\": \"Temps de nettoyage restant\",\n            \"it\": \"Tempo di pulizia rimanente\",\n            \"no\": \"Rengjøringstid gjenstår\",\n            \"sv\": \"Rengöringstid kvar\",\n            \"pl\": \"Pozostały czas czyszczenia\",\n            \"ru\": \"Осталось времени на уборку\",\n            \"ko\": \"남은 청소 시간\"\n          },\n          \"value\": \"6\"\n        },\n        {\n          \"id\": \"error\",\n          \"type\": \"label\",\n          \"label\": {\n            \"en\": \"Error\",\n            \"nl\": \"Fout\",\n            \"da\": \"Fejl\",\n            \"de\": \"Fehler\",\n            \"es\": \"Error\",\n            \"fr\": \"Erreur\",\n            \"it\": \"Errore\",\n            \"no\": \"Feil\",\n            \"sv\": \"Fel\",\n            \"pl\": \"Błąd\",\n            \"ru\": \"Ошибка\",\n            \"ko\": \"오류\"\n          },\n          \"value\": \"No error\"\n        },\n        {\n          \"id\": \"power_source\",\n          \"type\": \"label\",\n          \"label\": {\n            \"en\": \"Power source\",\n            \"nl\": \"Voedingsbron\",\n            \"da\": \"Strømkilde\",\n            \"de\": \"Stromquelle\",\n            \"es\": \"Fuente de alimentacion\",\n            \"fr\": \"Source d'alimentation\",\n            \"it\": \"Fonte di alimentazione\",\n            \"no\": \"Strømkilde\",\n            \"sv\": \"Stromkalla\",\n            \"pl\": \"Zrodlo zasilania\",\n            \"ru\": \"Источник питания\",\n            \"ko\": \"전원 공급원\"\n          },\n          \"value\": \"Unknown\"\n        },\n        {\n          \"id\": \"charging_state\",\n          \"type\": \"label\",\n          \"label\": {\n            \"en\": \"Charging state\",\n            \"nl\": \"Laadstatus\",\n            \"da\": \"Opladningsstatus\",\n            \"de\": \"Ladestatus\",\n            \"es\": \"Estado de carga\",\n            \"fr\": \"Etat de charge\",\n            \"it\": \"Stato di carica\",\n            \"no\": \"Ladestatus\",\n            \"sv\": \"Laddningsstatus\",\n            \"pl\": \"Stan ladowania\",\n            \"ru\": \"Состояние зарядки\",\n            \"ko\": \"충전 상태\"\n          },\n          \"value\": \"Unknown\"\n        },\n        {\n          \"id\": \"address\",\n          \"type\": \"text\",\n          \"label\": {\n            \"en\": \"IP Address\",\n            \"nl\": \"IP-adres\",\n            \"da\": \"IP-adresse\",\n            \"de\": \"IP-Adresse\",\n            \"es\": \"Dirección IP\",\n            \"fr\": \"Adresse IP\",\n            \"it\": \"Indirizzo IP\",\n            \"no\": \"IP-adresse\",\n            \"sv\": \"IP-adress\",\n            \"pl\": \"Adres IP\",\n            \"ru\": \"IP-адрес\",\n            \"ko\": \"IP 주소\"\n          }\n        },\n        {\n          \"id\": \"token\",\n          \"type\": \"password\",\n          \"label\": {\n            \"en\": \"Token\",\n            \"nl\": \"Token\",\n            \"da\": \"Token\",\n            \"de\": \"Token\",\n            \"es\": \"Token\",\n            \"fr\": \"Jeton\",\n            \"it\": \"Token\",\n            \"no\": \"Token\",\n            \"sv\": \"Token\",\n            \"pl\": \"Token\",\n            \"ru\": \"Токен\",\n            \"ko\": \"토큰\"\n          }\n        },\n        {\n          \"id\": \"polling\",\n          \"type\": \"number\",\n          \"label\": {\n            \"en\": \"Polling interval (seconds)\",\n            \"nl\": \"Polling-interval (seconden)\",\n            \"da\": \"Polling-interval (sekunder)\",\n            \"de\": \"Abfrageintervall (Sekunden)\",\n            \"es\": \"Intervalo de sondeo (segundos)\",\n            \"fr\": \"Intervalle de sondage (secondes)\",\n            \"it\": \"Intervallo di polling (secondi)\",\n            \"no\": \"Pollingintervall (sekunder)\",\n            \"sv\": \"Pollingintervall (sekunder)\",\n            \"pl\": \"Interwał odpytywania (sekundy)\",\n            \"ru\": \"Интервал опроса (секунды)\",\n            \"ko\": \"폴링 간격 (초)\"\n          },\n          \"value\": 60\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/petfeeder_mmgg_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Smart Pet Feeder MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"xlarge\": \"drivers/petfeeder_mmgg_miot/assets/images/xlarge.jpg\",\n        \"large\": \"drivers/petfeeder_mmgg_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/petfeeder_mmgg_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"petfeeder\",\n      \"capabilities\": [\n        \"petfeeder_foodlevel\",\n        \"petfeeder_eaten_food_today\",\n        \"petfeeder_food_out_status\",\n        \"petfeeder_food_out_progress\",\n        \"petfeeder_heap_status\",\n        \"petfeeder_status_mode\",\n        \"petfeeder_busy\",\n        \"petfeeder_food_in_bowl\",\n        \"petfeeder_schedule_progress\",\n        \"measure_desiccant\",\n        \"measure_desiccant_time\",\n        \"alarm_desiccant_low\"\n      ],\n      \"id\": \"petfeeder_mmgg_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Feeder preferences\"\n          },\n          \"children\": [\n            {\n              \"id\": \"child_lock\",\n              \"type\": \"checkbox\",\n              \"value\": false,\n              \"label\": {\n                \"en\": \"Child lock\"\n              }\n            },\n            {\n              \"id\": \"auto_screen_off\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Auto screen off\"\n              }\n            },\n            {\n              \"id\": \"display_schedule_progress\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Display schedule progress\"\n              }\n            },\n            {\n              \"id\": \"low_food_intake_threshold\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Low food intake threshold (g)\"\n              },\n              \"min\": 10,\n              \"max\": 90,\n              \"step\": 1,\n              \"value\": 30\n            },\n            {\n              \"id\": \"low_food_consumption_notify\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Low food consumption notification\"\n              }\n            },\n            {\n              \"id\": \"empty_food_bowl_duration\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Empty food bowl duration (h)\"\n              },\n              \"min\": 6,\n              \"max\": 24,\n              \"step\": 1,\n              \"value\": 12\n            },\n            {\n              \"id\": \"dispensing_error_correction\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Dispensing error correction\"\n              }\n            },\n            {\n              \"id\": \"bowl_spillage_prevention\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Food bowl spillage prevention\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device data\"\n          },\n          \"children\": [\n            {\n              \"id\": \"error\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Error\"\n              },\n              \"value\": \"No error\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device settings\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Telemetry\"\n          },\n          \"children\": [\n            {\n              \"id\": \"desiccant_alarm_threshold\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Desiccant low alarm threshold (%)\"\n              },\n              \"min\": 0,\n              \"max\": 100,\n              \"step\": 1,\n              \"value\": 20\n            },\n            {\n              \"id\": \"eaten_food_today_adjust\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Manual eaten food today (g)\"\n              },\n              \"step\": 1,\n              \"min\": 0,\n              \"value\": 0,\n              \"hint\": {\n                \"en\": \"Set the current daily eaten food amount if you need to correct the calculation.\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/petwaterdispenser_mmgg_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Smart Pet Water Dispenser MIoT (WiFi)\",\n        \"nl\": \"Smart Pet Water Dispenser MIoT (WiFi)\",\n        \"da\": \"Smart Pet Vanddispenser MIoT (WiFi)\",\n        \"de\": \"Smart Pet Wasserspender MIoT (WiFi)\",\n        \"es\": \"Dispensador de Agua Inteligente para Mascotas MIoT (WiFi)\",\n        \"fr\": \"Distributeur d'Eau Intelligent pour Animaux MIoT (WiFi)\",\n        \"it\": \"Distributore di Acqua Intelligente per Animali MIoT (WiFi)\",\n        \"no\": \"Smart Pet Vanndispenser MIoT (WiFi)\",\n        \"sv\": \"Smart Pet Vattendispensator MIoT (WiFi)\",\n        \"pl\": \"Inteligentny Podajnik Wody dla Zwierząt MIoT (WiFi)\",\n        \"ru\": \"Умный Диспенсер Для Воды Для Домашних Животных MIoT (WiFi)\",\n        \"ko\": \"스마트 애완동물 물 디스펜서 MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/petwaterdispenser_mmgg_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/petwaterdispenser_mmgg_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"petfeeder\",\n      \"capabilities\": [\n        \"onoff\",\n        \"petwaterdispenser_mmgg_mode\",\n        \"alarm_tank_empty\",\n        \"alarm_pump_supply\"\n      ],\n      \"id\": \"petwaterdispenser_mmgg_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración del usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"Светодиод\",\n                \"ko\": \"LED\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Data\",\n            \"nl\": \"Apparaat Data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"디바이스 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"filter_life_remaining\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter remaining\",\n                \"nl\": \"Filter over\",\n                \"da\": \"Filter tilbage\",\n                \"de\": \"Filter verbleibend\",\n                \"es\": \"Filtro restante\",\n                \"fr\": \"Filtre restant\",\n                \"it\": \"Filtro rimanente\",\n                \"no\": \"Filter gjenstår\",\n                \"sv\": \"Filter kvar\",\n                \"pl\": \"Filtr pozostały\",\n                \"ru\": \"Фильтр остался\",\n                \"ko\": \"남은 필터\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"cotton_life_remaining\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Cotton remaining\",\n                \"nl\": \"Cotton over\",\n                \"da\": \"Bomuld tilbage\",\n                \"de\": \"Baumwolle verbleibend\",\n                \"es\": \"Algodón restante\",\n                \"fr\": \"Coton restant\",\n                \"it\": \"Cotone rimanente\",\n                \"no\": \"Bomull gjenstår\",\n                \"sv\": \"Bomull kvar\",\n                \"pl\": \"Bawełna pozostała\",\n                \"ru\": \"Осталось хлопка\",\n                \"ko\": \"남은 면\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"cleaning_time_remaining\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Cleaning time remaining\",\n                \"nl\": \"Opschoon tid over\",\n                \"da\": \"Rengøringstid tilbage\",\n                \"de\": \"Reinigungszeit verbleibend\",\n                \"es\": \"Tiempo de limpieza restante\",\n                \"fr\": \"Temps de nettoyage restant\",\n                \"it\": \"Tempo di pulizia rimanente\",\n                \"no\": \"Rengjøringstid gjenstår\",\n                \"sv\": \"Rengöringstid kvar\",\n                \"pl\": \"Pozostały czas czyszczenia\",\n                \"ru\": \"Осталось времени на уборку\",\n                \"ko\": \"남은 청소 시간\"\n              },\n              \"value\": \"6\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device data\",\n            \"nl\": \"Apparaat data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"디바이스 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"error\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Error\",\n                \"nl\": \"Error\",\n                \"da\": \"Fejl\",\n                \"de\": \"Fehler\",\n                \"es\": \"Error\",\n                \"fr\": \"Erreur\",\n                \"it\": \"Errore\",\n                \"no\": \"Feil\",\n                \"sv\": \"Fel\",\n                \"pl\": \"Błąd\",\n                \"ru\": \"Ошибка\",\n                \"ko\": \"오류\"\n              },\n              \"value\": \"No error\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"디바이스 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/philips-bulb/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Philips Lights Generic (WiFi)\",\n        \"nl\": \"Philips Lights Generic (WiFi)\",\n        \"da\": \"Philips Lights Generisk (WiFi)\",\n        \"de\": \"Philips Licht Allgemein (WiFi)\",\n        \"es\": \"Philips Luces Genéricas (WiFi)\",\n        \"fr\": \"Philips Lumières Génériques (WiFi)\",\n        \"it\": \"Philips Luci Generiche (WiFi)\",\n        \"no\": \"Philips Lys Generisk (WiFi)\",\n        \"sv\": \"Philips Ljus Generisk (WiFi)\",\n        \"pl\": \"Philips Światła Ogólne (WiFi)\",\n        \"ru\": \"Philips Лампы Общие (WiFi)\",\n        \"ko\": \"필립스 조명 일반 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/philips-bulb/assets/images/large.jpg\",\n        \"small\": \"drivers/philips-bulb/assets/images/small.jpg\"\n      },\n      \"class\": \"light\",\n      \"capabilities\": [\n        \"onoff\",\n        \"dim\",\n        \"light_temperature\"\n      ],\n      \"id\": \"philips-bulb\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"ja\": \"デバイス設定\",\n            \"zh\": \"设备设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/philips-eyecare/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Philips Eyecare Lamp (WiFi)\",\n        \"nl\": \"Philips Eyecare Lamp (WiFi)\",\n        \"da\": \"Philips Eyecare Lampe (WiFi)\",\n        \"de\": \"Philips Eyecare Lampe (WiFi)\",\n        \"es\": \"Lámpara Philips Eyecare (WiFi)\",\n        \"fr\": \"Lampe Philips Eyecare (WiFi)\",\n        \"it\": \"Lampada Philips Eyecare (WiFi)\",\n        \"no\": \"Philips Eyecare Lampe (WiFi)\",\n        \"sv\": \"Philips Eyecare Lampa (WiFi)\",\n        \"pl\": \"Lampa Philips Eyecare (WiFi)\",\n        \"ru\": \"Лампа Philips Eyecare (WiFi)\",\n        \"ko\": \"필립스 아이케어 램프 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/philips-eyecare/assets/images/large.jpg\",\n        \"small\": \"drivers/philips-eyecare/assets/images/small.jpg\"\n      },\n      \"class\": \"light\",\n      \"capabilities\": [\n        \"onoff\",\n        \"dim\",\n        \"onoff.eyecare\",\n        \"onoff.ambilight\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.eyecare\": {\n          \"title\": {\n            \"en\": \"Eyecare\",\n            \"nl\": \"Eyecare\",\n            \"da\": \"Øjenpleje\",\n            \"de\": \"Augenpflege\",\n            \"es\": \"Cuidado de ojos\",\n            \"fr\": \"Soin des yeux\",\n            \"it\": \"Cura degli occhi\",\n            \"no\": \"Øyepleie\",\n            \"sv\": \"Ögonvård\",\n            \"pl\": \"Pielęgnacja oczu\",\n            \"ru\": \"Уход за глазами\",\n            \"ko\": \"아이케어\"\n          }\n        },\n        \"onoff.ambilight\": {\n          \"title\": {\n            \"en\": \"Ambilight\",\n            \"nl\": \"Ambilight\",\n            \"da\": \"Ambilight\",\n            \"de\": \"Ambilight\",\n            \"es\": \"Ambilight\",\n            \"fr\": \"Ambilight\",\n            \"it\": \"Ambilight\",\n            \"no\": \"Ambilight\",\n            \"sv\": \"Ambilight\",\n            \"pl\": \"Ambilight\",\n            \"ru\": \"Ambilight\",\n            \"ko\": \"Ambilight\"\n          }\n        }\n      },\n      \"id\": \"philips-eyecare\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"기기 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/philips_light_cbulb/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mijia Philips Color Bulb (WiFi)\",\n        \"nl\": \"Mijia Philips Kleur Lamp (WiFi)\",\n        \"da\": \"Mijia Philips Farve Pære (WiFi)\",\n        \"de\": \"Mijia Philips Farbige Glühbirne (WiFi)\",\n        \"es\": \"Mijia Philips Bombilla de Color (WiFi)\",\n        \"fr\": \"Mijia Philips Ampoule Couleur (WiFi)\",\n        \"it\": \"Mijia Philips Lampadina Colorata (WiFi)\",\n        \"no\": \"Mijia Philips Farget Lyspære (WiFi)\",\n        \"sv\": \"Mijia Philips Färglampa (WiFi)\",\n        \"pl\": \"Mijia Philips Kolorowa Żarówka (WiFi)\",\n        \"ru\": \"Mijia Philips Цветная Лампочка (WiFi)\",\n        \"ko\": \"Mijia Philips 컬러 전구 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/philips_light_cbulb/assets/images/large.jpg\",\n        \"small\": \"drivers/philips_light_cbulb/assets/images/small.jpg\"\n      },\n      \"class\": \"light\",\n      \"capabilities\": [\n        \"onoff\",\n        \"dim\",\n        \"light_hue\",\n        \"light_temperature\"\n      ],\n      \"capabilitiesOptions\": {\n        \"dim\": {\n          \"min\": 0.01\n        }\n      },\n      \"id\": \"philips_light_cbulb\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"pt\": \"Configurações do dispositivo\",\n            \"zh\": \"设备设置\",\n            \"ja\": \"デバイス設定\",\n            \"hi\": \"डिवाइस सेटिंग्स\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/philips_light_moonlight/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Philips Bedside Lamp (WiFi)\",\n        \"nl\": \"Philips Bedside Lamp (WiFi)\",\n        \"da\": \"Philips Sengelampe (WiFi)\",\n        \"de\": \"Philips Nachttischlampe (WiFi)\",\n        \"es\": \"Lámpara de Noche Philips (WiFi)\",\n        \"fr\": \"Lampe de Chevet Philips (WiFi)\",\n        \"it\": \"Lampada da Comodino Philips (WiFi)\",\n        \"no\": \"Philips Nattbordslampe (WiFi)\",\n        \"sv\": \"Philips Sänglampa (WiFi)\",\n        \"pl\": \"Lampka Nocna Philips (WiFi)\",\n        \"ru\": \"Прикроватная лампа Philips (WiFi)\",\n        \"ko\": \"필립스 침대 옆 램프 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/philips_light_moonlight/assets/images/large.jpg\",\n        \"small\": \"drivers/philips_light_moonlight/assets/images/small.jpg\"\n      },\n      \"class\": \"light\",\n      \"capabilities\": [\n        \"onoff\",\n        \"dim\",\n        \"light_hue\",\n        \"light_saturation\",\n        \"light_temperature\",\n        \"light_mode\"\n      ],\n      \"id\": \"philips_light_moonlight\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/philips_light_strip/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Philips / Xiaomi Light Strip (WiFi)\",\n        \"nl\": \"Philips Xiaomi Light Strip (WiFi)\",\n        \"da\": \"Philips / Xiaomi Lysstrimmel (WiFi)\",\n        \"de\": \"Philips / Xiaomi Lichtleiste (WiFi)\",\n        \"es\": \"Philips / Xiaomi Tira de Luces (WiFi)\",\n        \"fr\": \"Philips / Xiaomi Bande Lumineuse (WiFi)\",\n        \"it\": \"Philips / Xiaomi Striscia Luminosa (WiFi)\",\n        \"no\": \"Philips / Xiaomi Lyslist (WiFi)\",\n        \"sv\": \"Philips / Xiaomi Ljusremsa (WiFi)\",\n        \"pl\": \"Philips / Xiaomi Pasek LED (WiFi)\",\n        \"ru\": \"Philips / Xiaomi Светодиодная лента (WiFi)\",\n        \"ko\": \"필립스 / 샤오미 라이트 스트립 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/philips_light_strip/assets/images/large.jpg\",\n        \"small\": \"drivers/philips_light_strip/assets/images/small.jpg\"\n      },\n      \"class\": \"light\",\n      \"capabilities\": [\n        \"onoff\",\n        \"dim\",\n        \"light_hue\",\n        \"light_saturation\"\n      ],\n      \"id\": \"philips_light_strip\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"ja\": \"デバイス設定\",\n            \"zh\": \"设备设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/plug_chuangmi_plug_m1/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Smart Plug (WiFi)\",\n        \"nl\": \"Mi Smart Plug (WiFi)\",\n        \"da\": \"Mi Smart Plug (WiFi)\",\n        \"de\": \"Mi Smart Plug (WiFi)\",\n        \"es\": \"Mi Smart Plug (WiFi)\",\n        \"fr\": \"Mi Smart Plug (WiFi)\",\n        \"it\": \"Mi Smart Plug (WiFi)\",\n        \"no\": \"Mi Smart Plug (WiFi)\",\n        \"sv\": \"Mi Smart Plug (WiFi)\",\n        \"pl\": \"Mi Smart Plug (WiFi)\",\n        \"ru\": \"Mi Smart Plug (WiFi)\",\n        \"ko\": \"Mi Smart Plug (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/plug_chuangmi_plug_m1/assets/images/large.jpg\",\n        \"small\": \"drivers/plug_chuangmi_plug_m1/assets/images/small.jpg\"\n      },\n      \"class\": \"socket\",\n      \"capabilities\": [\n        \"onoff\",\n        \"measure_temperature\",\n        \"onoff.led\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.led\": {\n          \"title\": {\n            \"en\": \"WiFi LED\",\n            \"nl\": \"WiFi LED\",\n            \"da\": \"WiFi LED\",\n            \"de\": \"WiFi LED\",\n            \"es\": \"WiFi LED\",\n            \"fr\": \"WiFi LED\",\n            \"it\": \"WiFi LED\",\n            \"no\": \"WiFi LED\",\n            \"sv\": \"WiFi LED\",\n            \"pl\": \"WiFi LED\",\n            \"ru\": \"WiFi LED\",\n            \"ko\": \"WiFi LED\"\n          }\n        }\n      },\n      \"id\": \"plug_chuangmi_plug_m1\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"기기 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/plug_chuangmi_plug_v1_v3/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Smart Plug With 1 or 2 USB (WiFi)\",\n        \"nl\": \"Mi Smart Plug met 1 of 2 USB (WiFi)\",\n        \"da\": \"Mi Smart Plug med 1 eller 2 USB (WiFi)\",\n        \"de\": \"Mi Smart Plug mit 1 oder 2 USB (WiFi)\",\n        \"es\": \"Mi Smart Plug con 1 o 2 USB (WiFi)\",\n        \"fr\": \"Mi Smart Plug avec 1 ou 2 USB (WiFi)\",\n        \"it\": \"Mi Smart Plug con 1 o 2 USB (WiFi)\",\n        \"no\": \"Mi Smart Plug med 1 eller 2 USB (WiFi)\",\n        \"sv\": \"Mi Smart Plug med 1 eller 2 USB (WiFi)\",\n        \"pl\": \"Mi Smart Plug z 1 lub 2 USB (WiFi)\",\n        \"ru\": \"Mi Smart Plug с 1 или 2 USB (WiFi)\",\n        \"ko\": \"1 또는 2 USB(와이파이)를 갖춘 Mi 스마트 플러그\"\n      },\n      \"images\": {\n        \"large\": \"drivers/plug_chuangmi_plug_v1_v3/assets/images/large.jpg\",\n        \"small\": \"drivers/plug_chuangmi_plug_v1_v3/assets/images/small.jpg\"\n      },\n      \"class\": \"socket\",\n      \"capabilities\": [\n        \"onoff\",\n        \"measure_temperature\",\n        \"onoff.usb\",\n        \"onoff.led\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.usb\": {\n          \"title\": {\n            \"en\": \"USB power\",\n            \"nl\": \"USB stroom\",\n            \"da\": \"USB strøm\",\n            \"de\": \"USB Strom\",\n            \"es\": \"Potencia USB\",\n            \"fr\": \"Alimentation USB\",\n            \"it\": \"Alimentazione USB\",\n            \"no\": \"USB-strøm\",\n            \"sv\": \"USB-ström\",\n            \"pl\": \"Zasilanie USB\",\n            \"ru\": \"Питание USB\",\n            \"ko\": \"USB 전원\"\n          }\n        },\n        \"onoff.led\": {\n          \"title\": {\n            \"en\": \"WiFi LED\",\n            \"nl\": \"WiFi LED\",\n            \"da\": \"WiFi LED\",\n            \"de\": \"WiFi LED\",\n            \"es\": \"WiFi LED\",\n            \"fr\": \"WiFi LED\",\n            \"it\": \"WiFi LED\",\n            \"no\": \"WiFi LED\",\n            \"sv\": \"WiFi LED\",\n            \"pl\": \"WiFi LED\",\n            \"ru\": \"WiFi LED\",\n            \"ko\": \"와이파이 LED\"\n          }\n        }\n      },\n      \"id\": \"plug_chuangmi_plug_v1_v3\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/plug_cuco_plug/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Xiaomi Smart Plug (WiFi)\",\n        \"nl\": \"Xiaomi Smart Plug (WiFi)\",\n        \"da\": \"Xiaomi Smart Plug (WiFi)\",\n        \"de\": \"Xiaomi Smart Plug (WiFi)\",\n        \"es\": \"Xiaomi Smart Plug (WiFi)\",\n        \"fr\": \"Xiaomi Smart Plug (WiFi)\",\n        \"it\": \"Xiaomi Smart Plug (WiFi)\",\n        \"no\": \"Xiaomi Smart Plug (WiFi)\",\n        \"sv\": \"Xiaomi Smart Plug (WiFi)\",\n        \"pl\": \"Xiaomi Smart Plug (WiFi)\",\n        \"ru\": \"Xiaomi Smart Plug (WiFi)\",\n        \"ko\": \"Xiaomi Smart Plug (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/plug_cuco_plug/assets/images/large.jpg\",\n        \"small\": \"drivers/plug_cuco_plug/assets/images/small.jpg\"\n      },\n      \"class\": \"socket\",\n      \"capabilities\": [\n        \"onoff\",\n        \"measure_power\",\n        \"meter_power\",\n        \"measure_voltage\"\n      ],\n      \"id\": \"plug_cuco_plug\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"User Settings\",\n            \"nl\": \"Gebruikersinstellingem\",\n            \"da\": \"Brugerindstillinger\",\n            \"de\": \"Benutzereinstellungen\",\n            \"es\": \"Configuración del usuario\",\n            \"fr\": \"Paramètres utilisateur\",\n            \"it\": \"Impostazioni utente\",\n            \"no\": \"Brukerinnstillinger\",\n            \"sv\": \"Användarinställningar\",\n            \"pl\": \"Ustawienia użytkownika\",\n            \"ru\": \"Настройки пользователя\",\n            \"ko\": \"사용자 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"led\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"LED\",\n                \"nl\": \"LED\",\n                \"da\": \"LED\",\n                \"de\": \"LED\",\n                \"es\": \"LED\",\n                \"fr\": \"LED\",\n                \"it\": \"LED\",\n                \"no\": \"LED\",\n                \"sv\": \"LED\",\n                \"pl\": \"LED\",\n                \"ru\": \"LED\",\n                \"ko\": \"LED\"\n              }\n            },\n            {\n              \"id\": \"childLock\",\n              \"type\": \"checkbox\",\n              \"value\": true,\n              \"label\": {\n                \"en\": \"Child Lock\",\n                \"nl\": \"Kinderslot\",\n                \"da\": \"Børnesikring\",\n                \"de\": \"Kindersicherung\",\n                \"es\": \"Bloqueo para niños\",\n                \"fr\": \"Verrouillage enfant\",\n                \"it\": \"Blocco bambini\",\n                \"no\": \"Barnelås\",\n                \"sv\": \"Barnlås\",\n                \"pl\": \"Blokada dla dzieci\",\n                \"ru\": \"Блокировка от детей\",\n                \"ko\": \"어린이 잠금\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/powerstrip_qmi_powerstrip_v1/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Chingmi Smart Power Strip (WiFi)\",\n        \"es\": \"Toma de Corriente Inteligente Chingmi (WiFi)\",\n        \"fr\": \"Multiprise Intelligente Chingmi (WiFi)\",\n        \"it\": \"Ciabatta Intelligente Chingmi (WiFi)\",\n        \"no\": \"Chingmi Smart Strømuttak (WiFi)\",\n        \"sv\": \"Chingmi Smart Strömbrytare (WiFi)\",\n        \"pl\": \"Inteligentna Listwa Zasilająca Chingmi (WiFi)\",\n        \"ru\": \"Умная Линия Электропитания Chingmi (WiFi)\",\n        \"ko\": \"칭미 스마트 전원 스트립 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/powerstrip_qmi_powerstrip_v1/assets/images/large.jpg\",\n        \"small\": \"drivers/powerstrip_qmi_powerstrip_v1/assets/images/small.jpg\"\n      },\n      \"class\": \"socket\",\n      \"capabilities\": [\n        \"onoff\",\n        \"measure_power\",\n        \"measure_temperature\",\n        \"measure_voltage\"\n      ],\n      \"id\": \"powerstrip_qmi_powerstrip_v1\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/relay_c2acn01/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Aqara 2 Channel Relay (Gateway)\",\n        \"nl\": \"Aqara 2 Channel Relay (Gateway)\",\n        \"da\": \"Aqara 2-kanals relæ (Gateway)\",\n        \"de\": \"Aqara 2-Kanal-Relais (Gateway)\",\n        \"es\": \"Relé de 2 canales Aqara (Gateway)\",\n        \"fr\": \"Relais 2 canaux Aqara (Gateway)\",\n        \"it\": \"Relè a 2 canali Aqara (Gateway)\",\n        \"no\": \"Aqara 2-kanals relé (Gateway)\",\n        \"sv\": \"Aqara 2-kanals relä (Gateway)\",\n        \"pl\": \"Przekaźnik 2-kanałowy Aqara (Gateway)\",\n        \"ru\": \"Реле Aqara на 2 канала (Шлюз)\",\n        \"ko\": \"Aqara 2채널 릴레이 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/relay_c2acn01/assets/images/large.jpg\",\n        \"small\": \"/drivers/relay_c2acn01/assets/images/small.jpg\"\n      },\n      \"class\": \"socket\",\n      \"capabilities\": [\n        \"onoff.0\",\n        \"onoff.1\",\n        \"measure_power\"\n      ],\n      \"capabilitiesOptions\": {\n        \"onoff.0\": {\n          \"title\": {\n            \"en\": \"Left Switch\",\n            \"nl\": \"Linkerschakelaar\",\n            \"da\": \"Venstre kontakt\",\n            \"de\": \"Linker Schalter\",\n            \"es\": \"Interruptor izquierdo\",\n            \"fr\": \"Commutateur gauche\",\n            \"it\": \"Interruttore sinistro\",\n            \"no\": \"Venstre bryter\",\n            \"sv\": \"Vänster brytare\",\n            \"pl\": \"Lewy włącznik\",\n            \"ru\": \"Левый переключатель\",\n            \"ko\": \"왼쪽 스위치\"\n          }\n        },\n        \"onoff.1\": {\n          \"title\": {\n            \"en\": \"Right Switch\",\n            \"nl\": \"Rechterschakelaar\",\n            \"da\": \"Højre kontakt\",\n            \"de\": \"Rechter Schalter\",\n            \"es\": \"Interruptor derecho\",\n            \"fr\": \"Commutateur droit\",\n            \"it\": \"Interruttore destro\",\n            \"no\": \"Høyre bryter\",\n            \"sv\": \"Höger brytare\",\n            \"pl\": \"Prawy włącznik\",\n            \"ru\": \"Правый переключатель\",\n            \"ko\": \"오른쪽 스위치\"\n          }\n        }\n      },\n      \"id\": \"relay_c2acn01\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/remote_chuangmi_remote_v2/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"deviceTypes\"\n        },\n        {\n          \"id\": \"devices\",\n          \"navigation\": {\n            \"prev\": \"deviceTypes\"\n          }\n        },\n        {\n          \"id\": \"deviceCharacteristics\",\n          \"navigation\": {\n            \"next\": \"keys\",\n            \"prev\": \"devices\"\n          }\n        },\n        {\n          \"id\": \"keys\",\n          \"navigation\": {\n            \"next\": \"done\",\n            \"prev\": \"deviceCharacteristics\"\n          }\n        },\n        {\n          \"id\": \"done\",\n          \"navigation\": {\n            \"prev\": \"devices\"\n          }\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Universal Intelligent IR Remote Controller (WiFi)\",\n        \"nl\": \"Universal Intelligent IR Remote Controller (WiFi)\",\n        \"da\": \"Universel intelligent IR-fjernbetjening (WiFi)\",\n        \"de\": \"Universeller intelligenter IR-Fernbedienungscontroller (WiFi)\",\n        \"es\": \"Controlador de mando a distancia IR inteligente universal (WiFi)\",\n        \"fr\": \"Contrôleur de télécommande IR intelligent universel (WiFi)\",\n        \"it\": \"Controller universale intelligente IR (WiFi)\",\n        \"no\": \"Universal intelligent IR-fjernkontroll (WiFi)\",\n        \"sv\": \"Universell intelligent IR-fjärrkontroll (WiFi)\",\n        \"pl\": \"Uniwersalny inteligentny kontroler zdalny IR (WiFi)\",\n        \"ru\": \"Универсальный интеллектуальный ИК-пульт дистанционного управления (WiFi)\",\n        \"ko\": \"범용 지능형 IR 리모컨 컨트롤러 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/remote_chuangmi_remote_v2/assets/images/large.jpg\",\n        \"small\": \"drivers/remote_chuangmi_remote_v2/assets/images/small.jpg\"\n      },\n      \"class\": \"other\",\n      \"capabilities\": [\n        \"onoff\",\n        \"channel_up\",\n        \"channel_down\",\n        \"volume_up\",\n        \"volume_down\",\n        \"volume_mute\",\n        \"dim\"\n      ],\n      \"id\": \"remote_chuangmi_remote_v2\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Configure IR Codes\",\n            \"nl\": \"IR codes configureren\",\n            \"da\": \"Konfigurer IR-koder\",\n            \"de\": \"IR-Codes konfigurieren\",\n            \"es\": \"Configurar códigos IR\",\n            \"fr\": \"Configurer les codes IR\",\n            \"it\": \"Configura codici IR\",\n            \"no\": \"Konfigurer IR-koder\",\n            \"sv\": \"Konfigurera IR-koder\",\n            \"pl\": \"Konfiguruj kody IR\",\n            \"ru\": \"Настроить IR-коды\",\n            \"ko\": \"IR 코드 구성\"\n          },\n          \"children\": [\n            {\n              \"id\": \"replay\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Replay\",\n                \"nl\": \"Herhaal\",\n                \"da\": \"Genspil\",\n                \"de\": \"Wiederholen\",\n                \"es\": \"Repetir\",\n                \"fr\": \"Rejouer\",\n                \"it\": \"Rigioca\",\n                \"no\": \"Spill av igjen\",\n                \"sv\": \"Spela upp igen\",\n                \"pl\": \"Odtwórz ponownie\",\n                \"ru\": \"Повторить\",\n                \"ko\": \"재생\"\n              },\n              \"value\": 1,\n              \"min\": 1,\n              \"max\": 10\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/smoke_sensor/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Smoke Sensor (Gateway)\",\n        \"nl\": \"Smoke Sensor (Gateway)\",\n        \"da\": \"Røgsensor (Gateway)\",\n        \"de\": \"Rauchsensor (Gateway)\",\n        \"es\": \"Sensor de Humo (Gateway)\",\n        \"fr\": \"Capteur de Fumée (Gateway)\",\n        \"it\": \"Sensore di Fumo (Gateway)\",\n        \"no\": \"Røykvarsler (Gateway)\",\n        \"sv\": \"Röksensor (Gateway)\",\n        \"pl\": \"Czujnik Dymu (Gateway)\",\n        \"ru\": \"Датчик дыма (Gateway)\",\n        \"ko\": \"연기 센서 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/smoke_sensor/assets/images/large.jpg\",\n        \"small\": \"/drivers/smoke_sensor/assets/images/small.jpg\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"alarm_smoke\",\n        \"measure_smoke_density\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"CR123A\"\n        ]\n      },\n      \"id\": \"smoke_sensor\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Duration of the sensor alarm\",\n            \"nl\": \"Duur van het sensor alarm\",\n            \"da\": \"Varighed af sensoralarmen\",\n            \"de\": \"Dauer des Sensoralarms\",\n            \"es\": \"Duración de la alarma del sensor\",\n            \"fr\": \"Durée de l'alarme du capteur\",\n            \"it\": \"Durata dell'allarme del sensore\",\n            \"no\": \"Varighet av sensoralarmen\",\n            \"sv\": \"Varaktighet av sensorsignalen\",\n            \"pl\": \"Czas trwania alarmu czujnika\",\n            \"ru\": \"Длительность сигнала тревоги датчика\",\n            \"ko\": \"센서 알람 시간\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_duration_number\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Disable after\",\n                \"nl\": \"Uitschakelen na\",\n                \"da\": \"Deaktiver efter\",\n                \"de\": \"Deaktivieren nach\",\n                \"es\": \"Desactivar después de\",\n                \"fr\": \"Désactiver après\",\n                \"it\": \"Disattiva dopo\",\n                \"no\": \"Deaktiver etter\",\n                \"sv\": \"Inaktivera efter\",\n                \"pl\": \"Wyłącz po\",\n                \"ru\": \"Отключить после\",\n                \"ko\": \"다음 후 비활성화\"\n              },\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 60,\n                \"max\": 86400\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/vacuum_dreame_vacuum/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Advanced Dreame Vacuum Cleaner MIoT (WiFi)\",\n        \"nl\": \"Geavanceerde Dreame stofzuiger MIoT (WiFi)\",\n        \"da\": \"Avanceret Dreame-støvsuger MIoT (WiFi)\",\n        \"de\": \"Erweiterter Dreame-Staubsauger MIoT (WiFi)\",\n        \"es\": \"Aspiradora Dreame Avanzada MIoT (WiFi)\",\n        \"fr\": \"Aspirateur Dreame Avancé MIoT (WiFi)\",\n        \"it\": \"Aspirapolvere Dreame Avanzato MIoT (WiFi)\",\n        \"no\": \"Avansert Dreame-støvsuger MIoT (WiFi)\",\n        \"sv\": \"Avancerad Dreame-städare MIoT (WiFi)\",\n        \"pl\": \"Zaawansowany odkurzacz Dreame MIoT (WiFi)\",\n        \"ru\": \"Продвинутый пылесос Dreame MIoT (WiFi)\",\n        \"ko\": \"고급 Dreame 진공 청소기 MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/vacuum_dreame_vacuum/assets/images/large.jpg\",\n        \"small\": \"drivers/vacuum_dreame_vacuum/assets/images/small.jpg\"\n      },\n      \"class\": \"vacuumcleaner\",\n      \"capabilities\": [\n        \"onoff\",\n        \"vacuumcleaner_state\",\n        \"vacuum_dreame_fanspeed\",\n        \"button.consumable\",\n        \"measure_battery\",\n        \"alarm_battery\",\n        \"alarm_main_brush_work_time\",\n        \"alarm_side_brush_work_time\",\n        \"alarm_filter_work_time\"\n      ],\n      \"capabilitiesOptions\": {\n        \"button.consumable\": {\n          \"maintenanceAction\": true,\n          \"title\": {\n            \"en\": \"Reset consumables\",\n            \"nl\": \"Reset verbruiksartikelen\",\n            \"da\": \"Nulstil forbrugsstoffer\",\n            \"de\": \"Verbrauchsmaterialien zurücksetzen\",\n            \"es\": \"Restablecer consumibles\",\n            \"fr\": \"Réinitialiser les consommables\",\n            \"it\": \"Reimposta consumabili\",\n            \"no\": \"Tilbakestill forbruksvarer\",\n            \"sv\": \"Återställ förbrukningsvaror\",\n            \"pl\": \"Zresetuj materiały eksploatacyjne\",\n            \"ru\": \"Сбросить расходные материалы\",\n            \"ko\": \"소모품 재설정\"\n          },\n          \"desc\": {\n            \"en\": \"Reset the usage of vacuum cleaner consumables.\",\n            \"nl\": \"Reset het gebruik van de verbruiksartikelen\",\n            \"da\": \"Nulstil brugen af støvsugerens forbrugsstoffer.\",\n            \"de\": \"Verwendung der Staubsauger-Verbrauchsmaterialien zurücksetzen.\",\n            \"es\": \"Restablecer el uso de los consumibles de la aspiradora.\",\n            \"fr\": \"Réinitialiser l'utilisation des consommables de l'aspirateur.\",\n            \"it\": \"Reimposta l'uso dei consumabili dell'aspirapolvere.\",\n            \"no\": \"Tilbakestill bruken av støvsugerens forbruksvarer.\",\n            \"sv\": \"Återställ användningen av förbrukningsartiklar för dammsugaren.\",\n            \"pl\": \"Zresetuj użycie materiałów eksploatacyjnych odkurzacza.\",\n            \"ru\": \"Сбросить использование расходных материалов пылесоса.\",\n            \"ko\": \"진공 청소기 소모품 사용량 재설정.\"\n          }\n        }\n      },\n      \"energy\": {\n        \"batteries\": [\n          \"INTERNAL\"\n        ]\n      },\n      \"id\": \"vacuum_dreame_vacuum\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Consumables\",\n            \"nl\": \"Verbruiksartikelen\",\n            \"da\": \"Forbrugsvarer\",\n            \"de\": \"Verbrauchsmaterialien\",\n            \"es\": \"Consumibles\",\n            \"fr\": \"Consommables\",\n            \"it\": \"Materiali di consumo\",\n            \"no\": \"Forbruksvarer\",\n            \"sv\": \"Förbrukningsvaror\",\n            \"pl\": \"Materiały eksploatacyjne\",\n            \"ru\": \"Расходные материалы\",\n            \"ko\": \"소모품\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_threshold\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Alarm threshold\",\n                \"nl\": \"Alarm ondergrens\",\n                \"da\": \"Alarmgrænse\",\n                \"de\": \"Alarmgrenze\",\n                \"es\": \"Umbral de alarma\",\n                \"fr\": \"Seuil d'alarme\",\n                \"it\": \"Soglia di allarme\",\n                \"no\": \"Alarmterskel\",\n                \"sv\": \"Larmpådragning\",\n                \"pl\": \"Próg alarmowy\",\n                \"ru\": \"Порог срабатывания сигнализации\",\n                \"ko\": \"경보 임계값\"\n              },\n              \"hint\": {\n                \"en\": \"Threshold below which the alarm will be activated.\",\n                \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n                \"da\": \"Grænse under hvilken alarmen vil blive aktiveret.\",\n                \"de\": \"Schwelle, unter der der Alarm ausgelöst wird.\",\n                \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n                \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n                \"it\": \"Soglia al di sotto della quale verrà attivato l'allarme.\",\n                \"no\": \"Terskel under hvilket alarmen vil bli aktivert.\",\n                \"sv\": \"Tröskel under vilken larmet aktiveras.\",\n                \"pl\": \"Próg poniżej którego alarm zostanie włączony.\",\n                \"ru\": \"Порог, ниже которого срабатывает сигнализация.\",\n                \"ko\": \"경보가 활성화되는 임계값.\"\n              },\n              \"value\": 20,\n              \"attr\": {\n                \"min\": 1,\n                \"max\": 90\n              }\n            },\n            {\n              \"id\": \"main_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Main brush remaining (%)\",\n                \"nl\": \"Hoofdborstel over (%)\",\n                \"da\": \"Hovede børste resterende (%)\",\n                \"de\": \"Hauptbürste verbleibend (%)\",\n                \"es\": \"Cepillo principal restante (%)\",\n                \"fr\": \"Brosse principale restante (%)\",\n                \"it\": \"Spazzola principale restante (%)\",\n                \"no\": \"Hovedbørste gjenværende (%)\",\n                \"sv\": \"Huvudborste återstående (%)\",\n                \"pl\": \"Główna szczotka pozostało (%)\",\n                \"ru\": \"Оставшаяся основная щетка (%)\",\n                \"ko\": \"메인 브러시 남은 (%)\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"side_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Side brush remaining\",\n                \"nl\": \"Zijborstel over\",\n                \"da\": \"Sidebørste resterende\",\n                \"de\": \"Seitenbürste verbleibend\",\n                \"es\": \"Cepillo lateral restante\",\n                \"fr\": \"Brosse latérale restante\",\n                \"it\": \"Spazzola laterale restante\",\n                \"no\": \"Sidebørste gjenværende\",\n                \"sv\": \"Sidoborste återstående\",\n                \"pl\": \"Boczna szczotka pozostało\",\n                \"ru\": \"Оставшаяся боковая щетка\",\n                \"ko\": \"사이드 브러시 남은\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"filter_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter remaining\",\n                \"nl\": \"Filter over\",\n                \"da\": \"Filter resterende\",\n                \"de\": \"Filter verbleibend\",\n                \"es\": \"Filtro restante\",\n                \"fr\": \"Filtre restant\",\n                \"it\": \"Filtro restante\",\n                \"no\": \"Filter gjenværende\",\n                \"sv\": \"Filter återstående\",\n                \"pl\": \"Pozostały filtr\",\n                \"ru\": \"Оставшийся фильтр\",\n                \"ko\": \"필터 남은\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"total_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total work time\",\n                \"nl\": \"Totale gebruikstijd\",\n                \"da\": \"Total arbejdstid\",\n                \"de\": \"Gesamtarbeitszeit\",\n                \"es\": \"Tiempo total de trabajo\",\n                \"fr\": \"Temps de travail total\",\n                \"it\": \"Tempo totale di lavoro\",\n                \"no\": \"Total arbeidstid\",\n                \"sv\": \"Total arbetstid\",\n                \"pl\": \"Całkowity czas pracy\",\n                \"ru\": \"Общее рабочее время\",\n                \"ko\": \"총 작업 시간\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"total_cleared_area\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total cleaned area\",\n                \"nl\": \"Totaal geschoont\",\n                \"da\": \"Samlet rengjort areal\",\n                \"de\": \"Gesamte gereinigte Fläche\",\n                \"es\": \"Área total limpiada\",\n                \"fr\": \"Surface totale nettoyée\",\n                \"it\": \"Area totale pulita\",\n                \"no\": \"Total rengjort område\",\n                \"sv\": \"Total rengjord yta\",\n                \"pl\": \"Całkowita czyszczona powierzchnia\",\n                \"ru\": \"Общая убранная площадь\",\n                \"ko\": \"총 청소된 면적\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"total_clean_count\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total clean count\",\n                \"nl\": \"Totaal aantal opschoningen\",\n                \"da\": \"Samlet rengøringsantal\",\n                \"de\": \"Gesamte Reinigungsanzahl\",\n                \"es\": \"Conteo total de limpiezas\",\n                \"fr\": \"Compte total de nettoyages\",\n                \"it\": \"Conteggio totale delle pulizie\",\n                \"no\": \"Totalt rengjøringsantall\",\n                \"sv\": \"Total rengöringsräkning\",\n                \"pl\": \"Całkowita liczba czyszczeń\",\n                \"ru\": \"Общее количество уборок\",\n                \"ko\": \"총 청소 횟수\"\n              },\n              \"value\": \"0\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device data\",\n            \"nl\": \"Apparaat data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"장치 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"rooms\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Room cleaning segments\",\n                \"nl\": \"Kamer stofzuig segmenten\",\n                \"da\": \"Rengrumssegmenter\",\n                \"de\": \"Raumreinigungssegmente\",\n                \"es\": \"Segmentos de limpieza de habitaciones\",\n                \"fr\": \"Segments de nettoyage de la pièce\",\n                \"it\": \"Segmenti di pulizia della stanza\",\n                \"no\": \"Romrengjøringssegmenter\",\n                \"sv\": \"Rumstädningssegment\",\n                \"pl\": \"Segmenty sprzątania pomieszczeń\",\n                \"ru\": \"Сегменты очищения помещений\",\n                \"ko\": \"방 청소 세그먼트\"\n              },\n              \"value\": \"[[17,20,21]]\"\n            },\n            {\n              \"id\": \"error\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Error\",\n                \"nl\": \"Error\",\n                \"da\": \"Fejl\",\n                \"de\": \"Fehler\",\n                \"es\": \"Error\",\n                \"fr\": \"Erreur\",\n                \"it\": \"Errore\",\n                \"no\": \"Feil\",\n                \"sv\": \"Fel\",\n                \"pl\": \"Błąd\",\n                \"ru\": \"Ошибка\",\n                \"ko\": \"오류\"\n              },\n              \"value\": \"No error\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/vacuum_mi_rockrobo_vacuum_advanced/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Advanced Roborock Vacuum Cleaner (WiFi)\",\n        \"nl\": \"Geavanceerde Roborock stofzuiger (WiFi)\",\n        \"da\": \"Avanceret Roborock Støvsuger (WiFi)\",\n        \"de\": \"Fortschrittlicher Roborock Staubsauger (WLAN)\",\n        \"es\": \"Aspiradora Roborock Avanzada (WiFi)\",\n        \"fr\": \"Aspirateur Roborock Avancé (WiFi)\",\n        \"it\": \"Aspirapolvere Roborock Avanzato (WiFi)\",\n        \"no\": \"Avansert Roborock Støvsuger (WiFi)\",\n        \"sv\": \"Avancerad Roborock Dammsugare (WiFi)\",\n        \"pl\": \"Zaawansowany Odkurzacz Roborock (WiFi)\",\n        \"ru\": \"Продвинутый Робот-пылесос Roborock (WiFi)\",\n        \"ko\": \"고급 Roborock 진공 청소기 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/vacuum_mi_rockrobo_vacuum_advanced/assets/images/large.jpg\",\n        \"small\": \"drivers/vacuum_mi_rockrobo_vacuum_advanced/assets/images/small.jpg\"\n      },\n      \"class\": \"vacuumcleaner\",\n      \"capabilities\": [\n        \"onoff\",\n        \"vacuumcleaner_state\",\n        \"button.consumable\",\n        \"vacuum_roborock_fanspeed\",\n        \"measure_battery\",\n        \"alarm_battery\",\n        \"alarm_main_brush_work_time\",\n        \"alarm_side_brush_work_time\",\n        \"alarm_filter_work_time\",\n        \"alarm_sensor_dirty_time\"\n      ],\n      \"capabilitiesOptions\": {\n        \"button.consumable\": {\n          \"maintenanceAction\": true,\n          \"title\": {\n            \"en\": \"Reset consumables\",\n            \"nl\": \"Reset verbruiksartikelen\",\n            \"da\": \"Nulstil forbrugsvarer\",\n            \"de\": \"Verbrauchsmaterialien zurücksetzen\",\n            \"es\": \"Restablecer consumibles\",\n            \"fr\": \"Réinitialiser les consommables\",\n            \"it\": \"Resetta i materiali di consumo\",\n            \"no\": \"Tilbakestill forbruksvarer\",\n            \"sv\": \"Återställ förbrukningsvaror\",\n            \"pl\": \"Zresetuj materiały eksploatacyjne\",\n            \"ru\": \"Сбросить расходные материалы\",\n            \"ko\": \"소모품 초기화\"\n          },\n          \"desc\": {\n            \"en\": \"Reset the usage of vacuum cleaner consumables.\",\n            \"nl\": \"Reset het gebruik van de verbruiksartikelen\",\n            \"da\": \"Nulstil brugen af støvsugerens forbrugsvarer.\",\n            \"de\": \"Setzen Sie die Verwendung von Staubsauger-Verbrauchsmaterialien zurück.\",\n            \"es\": \"Restablezca el uso de los consumibles de la aspiradora.\",\n            \"fr\": \"Réinitialisez l'utilisation des consommables de l'aspirateur.\",\n            \"it\": \"Reimposta l'uso dei materiali di consumo dell'aspirapolvere.\",\n            \"no\": \"Tilbakestill bruken av støvsugerens forbruksvarer.\",\n            \"sv\": \"Återställ användningen av dammsugarens förbrukningsvaror.\",\n            \"pl\": \"Zresetuj użycie materiałów eksploatacyjnych odkurzacza.\",\n            \"ru\": \"Сбросить использование расходных материалов для пылесоса.\",\n            \"ko\": \"진공 청소기 소모품 사용 초기화.\"\n          }\n        }\n      },\n      \"energy\": {\n        \"batteries\": [\n          \"INTERNAL\"\n        ]\n      },\n      \"id\": \"vacuum_mi_rockrobo_vacuum_advanced\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Consumables\",\n            \"nl\": \"Verbruiksartikelen\",\n            \"da\": \"Forbrugsstoffer\",\n            \"de\": \"Verbrauchsmaterialien\",\n            \"es\": \"Consumibles\",\n            \"fr\": \"Consommables\",\n            \"it\": \"Materiali di consumo\",\n            \"no\": \"Forbruksvarer\",\n            \"sv\": \"Förbrukningsvaror\",\n            \"pl\": \"Materiały eksploatacyjne\",\n            \"ru\": \"Расходные материалы\",\n            \"ko\": \"소모품\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_threshold\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Alarm threshold\",\n                \"nl\": \"Alarm ondergrens\",\n                \"da\": \"Alarmgrænse\",\n                \"de\": \"Alarmschwelle\",\n                \"es\": \"Umbral de alarma\",\n                \"fr\": \"Seuil d'alarme\",\n                \"it\": \"Soglia di allarme\",\n                \"no\": \"Alarmterskel\",\n                \"sv\": \"Larmtröskel\",\n                \"pl\": \"Próg alarmowy\",\n                \"ru\": \"Порог тревоги\",\n                \"ko\": \"알람 임계값\"\n              },\n              \"hint\": {\n                \"en\": \"Threshold below which the alarm will be activated.\",\n                \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n                \"da\": \"Grænse under hvilken alarmen aktiveres.\",\n                \"de\": \"Schwellenwert, unter dem der Alarm ausgelöst wird.\",\n                \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n                \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n                \"it\": \"Soglia al di sotto della quale verrà attivato l'allarme.\",\n                \"no\": \"Terskel under hvilken alarmen utløses.\",\n                \"sv\": \"Tröskel under vilken larmet aktiveras.\",\n                \"pl\": \"Próg, poniżej którego zostanie aktywowany alarm.\",\n                \"ru\": \"Порог, ниже которого сработает сигнализация.\",\n                \"ko\": \"알람이 활성화될 임계값입니다.\"\n              },\n              \"value\": 20,\n              \"attr\": {\n                \"min\": 1,\n                \"max\": 90\n              }\n            },\n            {\n              \"id\": \"main_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Main brush remaining (%)\",\n                \"nl\": \"Hoofdborstel over (%)\",\n                \"da\": \"Hovedbørste tilbage (%)\",\n                \"de\": \"Hauptbürste verbleibend (%)\",\n                \"es\": \"Cepillo principal restante (%)\",\n                \"fr\": \"Brosse principale restante (%)\",\n                \"it\": \"Spazzola principale rimanente (%)\",\n                \"no\": \"Hovedbørste gjenværende (%)\",\n                \"sv\": \"Huvudborste kvar (%)\",\n                \"pl\": \"Główna szczotka pozostało (%)\",\n                \"ru\": \"Основная щетка оставшаяся (%)\",\n                \"ko\": \"메인 브러시 남은 수명 (%)\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"side_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Side brush remaining\",\n                \"nl\": \"Zijborstel over\",\n                \"da\": \"Sidebørste tilbage\",\n                \"de\": \"Seitenbürste verbleibend\",\n                \"es\": \"Cepillo lateral restante\",\n                \"fr\": \"Brosse latérale restante\",\n                \"it\": \"Spazzola laterale rimanente\",\n                \"no\": \"Sidebørste gjenværende\",\n                \"sv\": \"Sidoborste kvar\",\n                \"pl\": \"Boczna szczotka pozostało\",\n                \"ru\": \"Остаток боковой щетки\",\n                \"ko\": \"사이드 브러시 남은 수명\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"filter_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter remaining\",\n                \"nl\": \"Filter over\",\n                \"da\": \"Filter tilbage\",\n                \"de\": \"Verbleibender Filter\",\n                \"es\": \"Filtro restante\",\n                \"fr\": \"Filtre restant\",\n                \"it\": \"Filtro rimanente\",\n                \"no\": \"Filter gjenværende\",\n                \"sv\": \"Filter kvar\",\n                \"pl\": \"Filtr pozostałość\",\n                \"ru\": \"Остаток фильтра\",\n                \"ko\": \"필터 남은 수명\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"sensor_dirty_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Sensors dirty remaining\",\n                \"nl\": \"Sensor vuil over\",\n                \"da\": \"Sensorer beskidte tilbage\",\n                \"de\": \"Sensoren verschmutzt verbleibend\",\n                \"es\": \"Sensores sucios restantes\",\n                \"fr\": \"Capteurs sales restants\",\n                \"it\": \"Sensori sporchi rimanenti\",\n                \"no\": \"Sensorer skitne gjenværende\",\n                \"sv\": \"Smutsiga sensorer kvar\",\n                \"pl\": \"Pozostałe brudne czujniki\",\n                \"ru\": \"Остаток загрязненных датчиков\",\n                \"ko\": \"센서 더러움 남은 시간\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"total_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total work time\",\n                \"nl\": \"Totale gebruikstijd\",\n                \"da\": \"Samlet arbejdstid\",\n                \"de\": \"Gesamte Arbeitszeit\",\n                \"es\": \"Tiempo total de trabajo\",\n                \"fr\": \"Temps de travail total\",\n                \"it\": \"Tempo di lavoro totale\",\n                \"no\": \"Total arbeidstid\",\n                \"sv\": \"Total arbetstid\",\n                \"pl\": \"Całkowity czas pracy\",\n                \"ru\": \"Общее время работы\",\n                \"ko\": \"총 작업 시간\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"total_cleared_area\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total cleaned area\",\n                \"nl\": \"Totaal geschoont\",\n                \"da\": \"Samlet rengjort areal\",\n                \"de\": \"Gesamt gereinigte Fläche\",\n                \"es\": \"Área total limpiada\",\n                \"fr\": \"Surface nettoyée totale\",\n                \"it\": \"Area totale pulita\",\n                \"no\": \"Totalt rengjort område\",\n                \"sv\": \"Totalt rengjort område\",\n                \"pl\": \"Całkowicie oczyszczony obszar\",\n                \"ru\": \"Общая очищенная площадь\",\n                \"ko\": \"총 청소 면적\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"total_clean_count\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total clean count\",\n                \"nl\": \"Totaal aantal opschoningen\",\n                \"da\": \"Samlet rengøringsantal\",\n                \"de\": \"Gesamtanzahl der Reinigungen\",\n                \"es\": \"Cantidad total de limpiezas\",\n                \"fr\": \"Compte total de nettoyage\",\n                \"it\": \"Numero totale di pulizie\",\n                \"no\": \"Total rengjøringstellcount\",\n                \"sv\": \"Total städräkning\",\n                \"pl\": \"Całkowita liczba czyszczeń\",\n                \"ru\": \"Общее количество уборок\",\n                \"ko\": \"총 청소 횟수\"\n              },\n              \"value\": \"0\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device data\",\n            \"nl\": \"Apparaat data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"장치 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"rooms\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Room cleaning segments\",\n                \"nl\": \"Kamer stofzuig segmenten\",\n                \"da\": \"Rensegmenter i rum\",\n                \"de\": \"Raumreinigungssegmente\",\n                \"es\": \"Segmentos de limpieza de habitaciones\",\n                \"fr\": \"Segments de nettoyage de pièce\",\n                \"it\": \"Segmenti di pulizia delle stanze\",\n                \"no\": \"Rom rengjøringssegmenter\",\n                \"sv\": \"Rengöringssegment i rum\",\n                \"pl\": \"Segmenty sprzątania pomieszczeń\",\n                \"ru\": \"Сегменты уборки комнаты\",\n                \"ko\": \"방 청소 구역\"\n              },\n              \"value\": \"[[17,20,21]]\"\n            },\n            {\n              \"id\": \"error\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Error\",\n                \"nl\": \"Error\",\n                \"da\": \"Fejl\",\n                \"de\": \"Fehler\",\n                \"es\": \"Error\",\n                \"fr\": \"Erreur\",\n                \"it\": \"Errore\",\n                \"no\": \"Feil\",\n                \"sv\": \"Fel\",\n                \"pl\": \"Błąd\",\n                \"ru\": \"Ошибка\",\n                \"ko\": \"오류\"\n              },\n              \"value\": \"No error\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuraciones del dispositivo\",\n            \"fr\": \"Paramètres du dispositif\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/vacuum_mija_vacuum_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mija/Ijai Vacuum Cleaner MIoT (WiFi)\",\n        \"nl\": \"Mija/Ijai stofzuiger MIoT (WiFi)\",\n        \"da\": \"Mija/Ijai støvsuger MIoT (WiFi)\",\n        \"de\": \"Mija/Ijai Staubsauger MIoT (WiFi)\",\n        \"es\": \"Mija/Ijai aspiradora MIoT (WiFi)\",\n        \"fr\": \"Mija/Ijai Aspirateur MIoT (WiFi)\",\n        \"it\": \"Mija/Ijai Aspirapolvere MIoT (WiFi)\",\n        \"no\": \"Mija/Ijai støvsuger MIoT (WiFi)\",\n        \"sv\": \"Mija/Ijai dammsugare MIoT (WiFi)\",\n        \"pl\": \"Mija/Ijai Odkurzacz MIoT (WiFi)\",\n        \"ru\": \"Mija/Ijai пылесос MIoT (WiFi)\",\n        \"ko\": \"Mija/Ijai 진공 청소기 MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/vacuum_mija_vacuum_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/vacuum_mija_vacuum_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"vacuumcleaner\",\n      \"capabilities\": [\n        \"onoff\",\n        \"vacuumcleaner_state\",\n        \"vacuum_dreame_fanspeed\",\n        \"measure_battery\",\n        \"alarm_battery\",\n        \"alarm_main_brush_work_time\",\n        \"alarm_side_brush_work_time\",\n        \"alarm_filter_work_time\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"INTERNAL\"\n        ]\n      },\n      \"id\": \"vacuum_mija_vacuum_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Consumables\",\n            \"nl\": \"Verbruiksartikelen\",\n            \"da\": \"Forbrugsmaterialer\",\n            \"de\": \"Verbrauchsmaterialien\",\n            \"es\": \"Consumibles\",\n            \"fr\": \"Consommables\",\n            \"it\": \"Consumabili\",\n            \"no\": \"Forbruksmateriell\",\n            \"sv\": \"Förbrukningsvaror\",\n            \"pl\": \"Materiały eksploatacyjne\",\n            \"ru\": \"Расходные материалы\",\n            \"ko\": \"소모품\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_threshold\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Alarm threshold\",\n                \"nl\": \"Alarm ondergrens\",\n                \"da\": \"Alarmtærskel\",\n                \"de\": \"Alarmschwelle\",\n                \"es\": \"Umbral de alarma\",\n                \"fr\": \"Seuil d'alarme\",\n                \"it\": \"Soglia di allarme\",\n                \"no\": \"Alarmterskel\",\n                \"sv\": \"Alarmtröskel\",\n                \"pl\": \"Próg alarmowy\",\n                \"ru\": \"Порог сигнала тревоги\",\n                \"ko\": \"알람 임계값\"\n              },\n              \"hint\": {\n                \"en\": \"Threshold below which the alarm will be activated.\",\n                \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n                \"da\": \"Tærskel under hvilken alarmen aktiveres.\",\n                \"de\": \"Schwellwert, unter dem der Alarm ausgelöst wird.\",\n                \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n                \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n                \"it\": \"Soglia sotto la quale verrà attivato l'allarme.\",\n                \"no\": \"Terskel under hvilken alarmen vil bli aktivert.\",\n                \"sv\": \"Tröskel under vilken larmet aktiveras.\",\n                \"pl\": \"Próg, poniżej którego alarm zostanie włączony.\",\n                \"ru\": \"Порог, ниже которого будет активирован сигнал тревоги.\",\n                \"ko\": \"알람이 활성화되는 임계값 이하.\"\n              },\n              \"value\": 20,\n              \"attr\": {\n                \"min\": 1,\n                \"max\": 90\n              }\n            },\n            {\n              \"id\": \"main_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Main brush remaining (%)\",\n                \"nl\": \"Hoofdborstel over (%)\",\n                \"da\": \"Hovedbørste tilbage (%)\",\n                \"de\": \"Hauptbürste verbleibend (%)\",\n                \"es\": \"Cepillo principal restante (%)\",\n                \"fr\": \"Brosse principale restante (%)\",\n                \"it\": \"Percentuale residua della spazzola principale (%)\",\n                \"no\": \"Hovedbørste gjenstår (%)\",\n                \"sv\": \"Huvudborste återstår (%)\",\n                \"pl\": \"Pozostałość głównej szczotki (%)\",\n                \"ru\": \"Осталось основной щетки (%)\",\n                \"ko\": \"메인 브러시 남음 (%)\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"side_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Side brush remaining\",\n                \"nl\": \"Zijborstel over\",\n                \"da\": \"Sidebørste tilbage\",\n                \"de\": \"Seitenbürste verbleibend\",\n                \"es\": \"Cepillo lateral restante\",\n                \"fr\": \"Brosse latérale restante\",\n                \"it\": \"Percentuale residua della spazzola laterale\",\n                \"no\": \"Sidebørste gjenstår\",\n                \"sv\": \"Sidoborste återstår\",\n                \"pl\": \"Pozostałość szczotki bocznej\",\n                \"ru\": \"Осталось боковой щетки\",\n                \"ko\": \"사이드 브러시 남음\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"filter_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter remaining\",\n                \"nl\": \"Filter over\",\n                \"da\": \"Filter tilbage\",\n                \"de\": \"Filter verbleibend\",\n                \"es\": \"Filtro restante\",\n                \"fr\": \"Filtre restant\",\n                \"it\": \"Percentuale residua del filtro\",\n                \"no\": \"Filter gjenstår\",\n                \"sv\": \"Filter återstår\",\n                \"pl\": \"Pozostałość filtra\",\n                \"ru\": \"Осталось фильтра\",\n                \"ko\": \"필터 남음\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"total_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total work time\",\n                \"nl\": \"Totale gebruikstijd\",\n                \"da\": \"Samlet arbejdstid\",\n                \"de\": \"Gesamtarbeitszeit\",\n                \"es\": \"Tiempo total de trabajo\",\n                \"fr\": \"Temps de travail total\",\n                \"it\": \"Tempo totale di lavoro\",\n                \"no\": \"Total arbeidstid\",\n                \"sv\": \"Total arbetstid\",\n                \"pl\": \"Całkowity czas pracy\",\n                \"ru\": \"Общее время работы\",\n                \"ko\": \"총 작업 시간\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"total_cleared_area\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total cleaned area\",\n                \"nl\": \"Totaal geschoont\",\n                \"da\": \"Samlet renset område\",\n                \"de\": \"Gesamtfläche gereinigt\",\n                \"es\": \"Área total limpiada\",\n                \"fr\": \"Surface totale nettoyée\",\n                \"it\": \"Area pulita totale\",\n                \"no\": \"Total rengjort område\",\n                \"sv\": \"Total rengjord yta\",\n                \"pl\": \"Całkowita oczyszczona powierzchnia\",\n                \"ru\": \"Общая очищенная площадь\",\n                \"ko\": \"총 청소된 면적\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"total_clean_count\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total clean count\",\n                \"nl\": \"Totaal aantal opschoningen\",\n                \"da\": \"Samlet rengøringsantal\",\n                \"de\": \"Gesamte Reinigungsanzahl\",\n                \"es\": \"Recuento total de limpiezas\",\n                \"fr\": \"Nombre total de nettoyages\",\n                \"it\": \"Conteggio totale delle pulizie\",\n                \"no\": \"Total rengjøringsteller\",\n                \"sv\": \"Total rengöringsräkning\",\n                \"pl\": \"Całkowita liczba oczyszczeń\",\n                \"ru\": \"Общее количество уборок\",\n                \"ko\": \"총 청소 횟수\"\n              },\n              \"value\": \"0\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device data\",\n            \"nl\": \"Apparaat data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"장치 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"error\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Error\",\n                \"nl\": \"Error\",\n                \"da\": \"Fejl\",\n                \"de\": \"Fehler\",\n                \"es\": \"Error\",\n                \"fr\": \"Erreur\",\n                \"it\": \"Errore\",\n                \"no\": \"Feil\",\n                \"sv\": \"Fel\",\n                \"pl\": \"Błąd\",\n                \"ru\": \"Ошибка\",\n                \"ko\": \"오류\"\n              },\n              \"value\": \"No error\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/vacuum_roidmi_vacuum_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Roidmi Vacuum Cleaner MIoT (WiFi)\",\n        \"nl\": \"Roidmi stofzuiger MIoT (WiFi)\",\n        \"da\": \"Roidmi støvsuger MIoT (WiFi)\",\n        \"de\": \"Roidmi Staubsauger MIoT (WiFi)\",\n        \"es\": \"Aspiradora Roidmi MIoT (WiFi)\",\n        \"fr\": \"Aspirateur Roidmi MIoT (WiFi)\",\n        \"it\": \"Aspirapolvere Roidmi MIoT (WiFi)\",\n        \"no\": \"Roidmi støvsuger MIoT (WiFi)\",\n        \"sv\": \"Roidmi dammsugare MIoT (WiFi)\",\n        \"pl\": \"Odkurzacz Roidmi MIoT (WiFi)\",\n        \"ru\": \"Пылесос Roidmi MIoT (WiFi)\",\n        \"ko\": \"로이디미 진공 청소기 MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/vacuum_roidmi_vacuum_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/vacuum_roidmi_vacuum_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"vacuumcleaner\",\n      \"capabilities\": [\n        \"onoff\",\n        \"vacuumcleaner_state\",\n        \"vacuum_roidmi_fanspeed\",\n        \"vacuum_roidmi_mop_mode\",\n        \"vacuum_roidmi_waterlevel\",\n        \"measure_battery\",\n        \"alarm_battery\",\n        \"alarm_main_brush_work_time\",\n        \"alarm_side_brush_work_time\",\n        \"alarm_filter_work_time\",\n        \"alarm_sensor_dirty_time\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"INTERNAL\"\n        ]\n      },\n      \"id\": \"vacuum_roidmi_vacuum_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Consumables\",\n            \"nl\": \"Verbruiksartikelen\",\n            \"da\": \"Forbrugsvarer\",\n            \"de\": \"Verbrauchsmaterialien\",\n            \"es\": \"Consumibles\",\n            \"fr\": \"Consommables\",\n            \"it\": \"Consumabili\",\n            \"no\": \"Forbruksvarer\",\n            \"sv\": \"Förbrukningsartiklar\",\n            \"pl\": \"Materiały eksploatacyjne\",\n            \"ru\": \"Расходные материалы\",\n            \"ko\": \"소모품\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_threshold\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Alarm threshold\",\n                \"nl\": \"Alarm ondergrens\",\n                \"da\": \"Alarmgrænse\",\n                \"de\": \"Alarmschwelle\",\n                \"es\": \"Umbral de alarma\",\n                \"fr\": \"Seuil d'alarme\",\n                \"it\": \"Soglia di allarme\",\n                \"no\": \"Alarmterskel\",\n                \"sv\": \"Larmgräns\",\n                \"pl\": \"Próg alarmowy\",\n                \"ru\": \"Порог тревоги\",\n                \"ko\": \"알람 임계값\"\n              },\n              \"hint\": {\n                \"en\": \"Threshold below which the alarm will be activated.\",\n                \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n                \"da\": \"Tærskel under hvilken alarmen vil blive aktiveret.\",\n                \"de\": \"Schwelle, unter der der Alarm ausgelöst wird.\",\n                \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n                \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n                \"it\": \"Soglia al di sotto della quale verrà attivato l'allarme.\",\n                \"no\": \"Terskel under hvilken alarmen vil bli aktivert.\",\n                \"sv\": \"Tröskel under vilket larmet aktiveras.\",\n                \"pl\": \"Próg, poniżej którego zostanie uruchomiony alarm.\",\n                \"ru\": \"Порог, ниже которого будет активирована тревога.\",\n                \"ko\": \"알람이 활성화되는 임계값입니다.\"\n              },\n              \"value\": 20,\n              \"attr\": {\n                \"min\": 1,\n                \"max\": 90\n              }\n            },\n            {\n              \"id\": \"main_brush_time_remaining\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Main brush remaining (%)\",\n                \"nl\": \"Hoofdborstel over (%)\",\n                \"da\": \"Hovedbørste resterende (%)\",\n                \"de\": \"Hauptbürste verbleibend (%)\",\n                \"es\": \"Cepillo principal restante (%)\",\n                \"fr\": \"Brosse principale restante (%)\",\n                \"it\": \"Spazzola principale rimanente (%)\",\n                \"no\": \"Hovedbørste gjenværende (%)\",\n                \"sv\": \"Huvudborste kvar (%)\",\n                \"pl\": \"Pozostało głównej szczotki (%)\",\n                \"ru\": \"Осталось основной щетки (%)\",\n                \"ko\": \"메인 브러쉬 남음 (%)\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"side_brush_time_remaining\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Side brush remaining\",\n                \"nl\": \"Zijborstel over\",\n                \"da\": \"Sidebørste resterende\",\n                \"de\": \"Seitenbürste verbleibend\",\n                \"es\": \"Cepillo lateral restante\",\n                \"fr\": \"Brosse latérale restante\",\n                \"it\": \"Spazzola laterale rimanente\",\n                \"no\": \"Sidebørste gjenværende\",\n                \"sv\": \"Sidoborste kvar\",\n                \"pl\": \"Pozostało bocznej szczotki\",\n                \"ru\": \"Осталось боковой щетки\",\n                \"ko\": \"사이드 브러쉬 남음\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"filter_time_remaining\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter remaining\",\n                \"nl\": \"Filter over\",\n                \"da\": \"Filter tilbage\",\n                \"de\": \"Filter verbleibend\",\n                \"es\": \"Filtro restante\",\n                \"fr\": \"Filtre restant\",\n                \"it\": \"Filtro rimanente\",\n                \"no\": \"Filter igjen\",\n                \"sv\": \"Filter kvar\",\n                \"pl\": \"Pozostało filtra\",\n                \"ru\": \"Осталось фильтра\",\n                \"ko\": \"필터 남음\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"total_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total work time\",\n                \"nl\": \"Totale gebruikstijd\",\n                \"da\": \"Samlet arbejdstid\",\n                \"de\": \"Gesamtarbeitszeit\",\n                \"es\": \"Tiempo total de trabajo\",\n                \"fr\": \"Temps de travail total\",\n                \"it\": \"Tempo totale di lavoro\",\n                \"no\": \"Total arbeidstid\",\n                \"sv\": \"Total arbetstid\",\n                \"pl\": \"Całkowity czas pracy\",\n                \"ru\": \"Общее время работы\",\n                \"ko\": \"총 작업 시간\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"sensor_dirty_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Sensors dirty remaining\",\n                \"nl\": \"Sensor vuil over\",\n                \"da\": \"Sensorer beskidte resterende\",\n                \"de\": \"Sensoren verschmutzt verbleibend\",\n                \"es\": \"Sensores sucios restantes\",\n                \"fr\": \"Capteurs sales restants\",\n                \"it\": \"Sensori sporchi rimanenti\",\n                \"no\": \"Sensorer skitne gjenværende\",\n                \"sv\": \"Smutsiga sensorer kvar\",\n                \"pl\": \"Pozostało zabrudzonych czujników\",\n                \"ru\": \"Осталось грязных датчиков\",\n                \"ko\": \"오염 센서 남음\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"total_cleared_area\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total cleaned area\",\n                \"nl\": \"Totaal geschoont\",\n                \"da\": \"Samlet rengjort område\",\n                \"de\": \"Gesamt gereinigte Fläche\",\n                \"es\": \"Área total limpiada\",\n                \"fr\": \"Zone totale nettoyée\",\n                \"it\": \"Area totale pulita\",\n                \"no\": \"Total rengjort område\",\n                \"sv\": \"Totalt rensat område\",\n                \"pl\": \"Całkowity wyczyszczony obszar\",\n                \"ru\": \"Общая очищенная площадь\",\n                \"ko\": \"청소된 총 면적\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"total_clean_count\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total clean count\",\n                \"nl\": \"Totaal aantal opschoningen\",\n                \"da\": \"Samlet renseoptælling\",\n                \"de\": \"Gesamte Reinigungsanzahl\",\n                \"es\": \"Conteo total de limpiezas\",\n                \"fr\": \"Compte total de nettoyage\",\n                \"it\": \"Conteggio totale delle pulizie\",\n                \"no\": \"Total rensetelling\",\n                \"sv\": \"Total rengöringsantal\",\n                \"pl\": \"Całkowita liczba czyszczeń\",\n                \"ru\": \"Общее количество очисток\",\n                \"ko\": \"총 청소 횟수\"\n              },\n              \"value\": \"0\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device data\",\n            \"nl\": \"Apparaat data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"장치 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"error\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Error\",\n                \"nl\": \"Error\",\n                \"da\": \"Fejl\",\n                \"de\": \"Fehler\",\n                \"es\": \"Error\",\n                \"fr\": \"Erreur\",\n                \"it\": \"Errore\",\n                \"no\": \"Feil\",\n                \"sv\": \"Fel\",\n                \"pl\": \"Błąd\",\n                \"ru\": \"Ошибка\",\n                \"ko\": \"오류\"\n              },\n              \"value\": \"No error\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuraciones del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/vacuum_viomi_vacuum_v7/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n        \"nl\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n        \"da\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n        \"de\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n        \"es\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n        \"fr\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n        \"it\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n        \"no\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n        \"sv\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n        \"pl\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n        \"ru\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n        \"ko\": \"Mi Robot Vacuum-Mop P (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/vacuum_viomi_vacuum_v7/assets/images/large.jpg\",\n        \"small\": \"drivers/vacuum_viomi_vacuum_v7/assets/images/small.jpg\"\n      },\n      \"class\": \"vacuumcleaner\",\n      \"capabilities\": [\n        \"onoff\",\n        \"dim\",\n        \"dim.water\",\n        \"vacuum_viomi_mop_mode\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"capabilitiesOptions\": {\n        \"dim\": {\n          \"title\": {\n            \"en\": \"Speed\",\n            \"nl\": \"Snelheid\",\n            \"da\": \"Hastighed\",\n            \"de\": \"Geschwindigkeit\",\n            \"es\": \"Velocidad\",\n            \"fr\": \"Vitesse\",\n            \"it\": \"Velocità\",\n            \"no\": \"Hastighet\",\n            \"sv\": \"Hastighet\",\n            \"pl\": \"Prędkość\",\n            \"ru\": \"Скорость\",\n            \"ko\": \"속도\"\n          },\n          \"min\": 0,\n          \"max\": 3,\n          \"step\": 1\n        },\n        \"dim.water\": {\n          \"title\": {\n            \"en\": \"Mop mode\",\n            \"nl\": \"Dweil modus\",\n            \"da\": \"Moppe tilstand\",\n            \"de\": \"Wischmodus\",\n            \"es\": \"Modo de fregona\",\n            \"fr\": \"Mode serpillière\",\n            \"it\": \"Modalità mocio\",\n            \"no\": \"Moppemodus\",\n            \"sv\": \"Mopp-läge\",\n            \"pl\": \"Tryb mopa\",\n            \"ru\": \"Режим швабры\",\n            \"ko\": \"물걸레 모드\"\n          },\n          \"min\": 0,\n          \"max\": 3,\n          \"step\": 1\n        },\n        \"button.consumable\": {\n          \"maintenanceAction\": true,\n          \"title\": {\n            \"en\": \"Reset consumables\",\n            \"nl\": \"Reset verbruiksartikelen\",\n            \"da\": \"Nulstil forbrugsvarer\",\n            \"de\": \"Verbrauchsmaterialien zurücksetzen\",\n            \"es\": \"Restablecer consumibles\",\n            \"fr\": \"Réinitialiser les consommables\",\n            \"it\": \"Reimposta i consumabili\",\n            \"no\": \"Tilbakestill forbruksvarer\",\n            \"sv\": \"Återställ förbrukningsvaror\",\n            \"pl\": \"Resetuj materiały eksploatacyjne\",\n            \"ru\": \"Сбросить расходные материалы\",\n            \"ko\": \"소모품 초기화\"\n          },\n          \"desc\": {\n            \"en\": \"Reset the usage of vacuum cleaner consumables.\",\n            \"nl\": \"Reset het gebruik van de verbruiksartikelen\",\n            \"da\": \"Nulstil brugen af støvsugerens forbrugsvarer.\",\n            \"de\": \"Verwendungsdauer der Staubsauger-Verbrauchsmaterialien zurücksetzen.\",\n            \"es\": \"Restablecer el uso de los consumibles de la aspiradora.\",\n            \"fr\": \"Réinitialiser l'utilisation des consommables de l'aspirateur.\",\n            \"it\": \"Reimposta l'uso dei consumabili dell'aspirapolvere.\",\n            \"no\": \"Tilbakestill bruken av støvsugerens forbruksvarer.\",\n            \"sv\": \"Återställ användningen av dammsugarens förbrukningsvaror.\",\n            \"pl\": \"Resetuj użycie materiałów eksploatacyjnych odkurzacza.\",\n            \"ru\": \"Сбросить использование расходных материалов пылесоса.\",\n            \"ko\": \"진공 청소기 소모품 사용량 재설정.\"\n          }\n        }\n      },\n      \"energy\": {\n        \"batteries\": [\n          \"INTERNAL\"\n        ]\n      },\n      \"id\": \"vacuum_viomi_vacuum_v7\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Vacuum Consumables\",\n            \"nl\": \"Stofzuiger verbruiksartikelen\",\n            \"da\": \"Støvsuger forbrugsstoffer\",\n            \"de\": \"Staubsauger Verbrauchsmaterialien\",\n            \"es\": \"Consumibles de aspiradora\",\n            \"fr\": \"Consommables pour aspirateur\",\n            \"it\": \"Consumi aspirapolvere\",\n            \"no\": \"Støvsuger forbruksvarer\",\n            \"sv\": \"Dammsugare förbrukningsvaror\",\n            \"pl\": \"Materiały eksploatacyjne odkurzacza\",\n            \"ru\": \"Расходные материалы для пылесоса\",\n            \"ko\": \"진공 청소기 소모품\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_threshold\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Alarm threshold\",\n                \"nl\": \"Alarm ondergrens\",\n                \"da\": \"Alarmgrænse\",\n                \"de\": \"Alarmschwelle\",\n                \"es\": \"Umbral de alarma\",\n                \"fr\": \"Seuil d'alarme\",\n                \"it\": \"Soglia d'allarme\",\n                \"no\": \"Alarmterskel\",\n                \"sv\": \"Alarmtröskel\",\n                \"pl\": \"Próg alarmowy\",\n                \"ru\": \"Порог срабатывания сигнала тревоги\",\n                \"ko\": \"알람 임계값\"\n              },\n              \"hint\": {\n                \"en\": \"Threshold below which the alarm will be activated.\",\n                \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n                \"da\": \"Grænse, under hvilken alarmen vil blive aktiveret.\",\n                \"de\": \"Schwelle, unter der der Alarm ausgelöst wird.\",\n                \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n                \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n                \"it\": \"Soglia al di sotto della quale si attiverà l'allarme.\",\n                \"no\": \"Terskel under hvilket alarmen vil bli aktivert.\",\n                \"sv\": \"Tröskel under vilken larmet aktiveras.\",\n                \"pl\": \"Próg, poniżej którego uruchomi się alarm.\",\n                \"ru\": \"Порог, при котором сработает сигнал тревоги.\",\n                \"ko\": \"경보가 활성화되는 임계값입니다.\"\n              },\n              \"value\": 20,\n              \"attr\": {\n                \"min\": 1,\n                \"max\": 90\n              }\n            },\n            {\n              \"id\": \"main_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Main brush remaining (%)\",\n                \"nl\": \"Hoofdborstel over (%)\",\n                \"da\": \"Resterende hovedbørste (%)\",\n                \"de\": \"Verbleibende Hauptbürste (%)\",\n                \"es\": \"Cepillo principal restante (%)\",\n                \"fr\": \"Brosse principale restante (%)\",\n                \"it\": \"Spazzola principale rimanente (%)\",\n                \"no\": \"Gjenværende hovedbørste (%)\",\n                \"sv\": \"Huvudborste kvar (%)\",\n                \"pl\": \"Pozostało głównego pędzla (%)\",\n                \"ru\": \"Оставшаяся основная щетка (%)\",\n                \"ko\": \"남은 메인 브러쉬 (%)\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"side_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Side brush remaining (%)\",\n                \"nl\": \"Zijborstel over (%)\",\n                \"da\": \"Resterende sidebørste (%)\",\n                \"de\": \"Verbleibende Seitenbürste (%)\",\n                \"es\": \"Cepillo lateral restante (%)\",\n                \"fr\": \"Brosse latérale restante (%)\",\n                \"it\": \"Spazzola laterale rimanente (%)\",\n                \"no\": \"Gjenværende sidebørste (%)\",\n                \"sv\": \"Sidoborste kvar (%)\",\n                \"pl\": \"Pozostało bocznego pędzla (%)\",\n                \"ru\": \"Оставшаяся боковая щетка (%)\",\n                \"ko\": \"남은 사이드 브러쉬 (%)\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"filter_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter over (%)\",\n                \"nl\": \"Filter over (%)\",\n                \"da\": \"Filter over (%)\",\n                \"de\": \"Filter übrig (%)\",\n                \"es\": \"Filtro restante (%)\",\n                \"fr\": \"Filtre restant (%)\",\n                \"it\": \"Filtro rimanente (%)\",\n                \"no\": \"Filter over (%)\",\n                \"sv\": \"Filter kvar (%)\",\n                \"pl\": \"Pozostało filtra (%)\",\n                \"ru\": \"Фильтр оставшийся (%)\",\n                \"ko\": \"남은 필터 (%)\"\n              },\n              \"value\": \"0%\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/vacuum_xiaomi_vacuum_max/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Xiaomi Vacuum Cleaner MIoT MAX (WiFi)\",\n        \"nl\": \"Xiaomi stofzuiger MIoT MAX (WiFi)\",\n        \"da\": \"Xiaomi Støvsuger MIoT MAX (WiFi)\",\n        \"de\": \"Xiaomi Staubsauger MIoT MAX (WiFi)\",\n        \"es\": \"Aspiradora Xiaomi MIoT MAX (WiFi)\",\n        \"fr\": \"Aspirateur Xiaomi MIoT MAX (WiFi)\",\n        \"it\": \"Aspirapolvere Xiaomi MIoT MAX (WiFi)\",\n        \"no\": \"Xiaomi Støvsuger MIoT MAX (WiFi)\",\n        \"sv\": \"Xiaomi Dammsugare MIoT MAX (WiFi)\",\n        \"pl\": \"Odkurzacz Xiaomi MIoT MAX (WiFi)\",\n        \"ru\": \"Пылесос Xiaomi MIoT MAX (WiFi)\",\n        \"ko\": \"샤오미 진공 청소기 MIoT MAX (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/vacuum_xiaomi_vacuum_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/vacuum_xiaomi_vacuum_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"vacuumcleaner\",\n      \"capabilities\": [\n        \"onoff\",\n        \"vacuumcleaner_state\",\n        \"vacuum_xiaomi_mop_mode_max\",\n        \"vacuum_xiaomi_cleaning_mode_max\",\n        \"vacuum_xiaomi_water_level_max\",\n        \"vacuum_xiaomi_path_mode_max\",\n        \"vacuum_xiaomi_carpet_mode_max\",\n        \"vacuum_xiaomi_status\",\n        \"measure_battery\",\n        \"alarm_battery\",\n        \"alarm_main_brush_work_time\",\n        \"alarm_side_brush_work_time\",\n        \"alarm_filter_work_time\",\n        \"alarm_water_shortage\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"INTERNAL\"\n        ]\n      },\n      \"id\": \"vacuum_xiaomi_vacuum_max\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Rooms\",\n            \"nl\": \"Kamers\",\n            \"da\": \"Rum\",\n            \"de\": \"Räume\",\n            \"es\": \"Habitaciones\",\n            \"fr\": \"Pièces\",\n            \"it\": \"Stanze\",\n            \"no\": \"Rom\",\n            \"sv\": \"Rum\",\n            \"pl\": \"Pokoje\",\n            \"ru\": \"Комнаты\",\n            \"ko\": \"방\"\n          },\n          \"children\": [\n            {\n              \"id\": \"rooms\",\n              \"type\": \"text\",\n              \"label\": {\n                \"en\": \"Rooms JSON (e.g. [{\\\"id\\\":1,\\\"name\\\":\\\"Kitchen\\\"}])\",\n                \"nl\": \"Kamers JSON\",\n                \"da\": \"Rum JSON\",\n                \"de\": \"Räume JSON\",\n                \"es\": \"Habitaciones JSON\",\n                \"fr\": \"Pièces JSON\",\n                \"it\": \"Stanze JSON\",\n                \"no\": \"Rom JSON\",\n                \"sv\": \"Rum JSON\",\n                \"pl\": \"Pokoje JSON\",\n                \"ru\": \"Комнаты JSON\",\n                \"ko\": \"방 JSON\"\n              },\n              \"hint\": {\n                \"en\": \"Manual list if auto-fetch fails. Each item requires an id and name.\",\n                \"nl\": \"Handmatige lijst als automatisch ophalen mislukt.\",\n                \"da\": \"Manuel liste hvis auto-hent fejler.\",\n                \"de\": \"Manuelle Liste, wenn Auto-Abruf fehlschlägt.\",\n                \"es\": \"Lista manual si la obtención automática falla.\",\n                \"fr\": \"Liste manuelle si l'auto-récupération échoue.\",\n                \"it\": \"Elenco manuale se l'acquisizione automatica fallisce.\",\n                \"no\": \"Manuell liste hvis auto-henting feiler.\",\n                \"sv\": \"Manuell lista om auto-hämtning misslyckas.\",\n                \"pl\": \"Lista ręczna, jeśli auto-pobieranie zawiedzie.\",\n                \"ru\": \"Список вручную, если авто-выгрузка не работает.\",\n                \"ko\": \"자동 가져오기가 실패할 경우 수동 목록.\"\n              },\n              \"value\": \"[]\"\n            },\n            {\n              \"id\": \"rooms_display\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Detected rooms\",\n                \"nl\": \"Gedetecteerde kamers\",\n                \"da\": \"Registrerede rum\",\n                \"de\": \"Erkannte Räume\",\n                \"es\": \"Habitaciones detectadas\",\n                \"fr\": \"Pièces détectées\",\n                \"it\": \"Stanze rilevate\",\n                \"no\": \"Oppdagede rom\",\n                \"sv\": \"Upptäckta rum\",\n                \"pl\": \"Wykryte pokoje\",\n                \"ru\": \"Обнаруженные комнаты\",\n                \"ko\": \"감지된 방\"\n              },\n              \"value\": \"No rooms fetched yet\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Consumables\",\n            \"nl\": \"Verbruiksartikelen\",\n            \"da\": \"Forbrugsvarer\",\n            \"de\": \"Verbrauchsmaterialien\",\n            \"es\": \"Consumibles\",\n            \"fr\": \"Consommables\",\n            \"it\": \"Consumabili\",\n            \"no\": \"Forbruksvarer\",\n            \"sv\": \"Förbrukningsvaror\",\n            \"pl\": \"Materiały eksploatacyjne\",\n            \"ru\": \"Расходные материалы\",\n            \"ko\": \"소모품\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_threshold\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Alarm threshold\",\n                \"nl\": \"Alarm ondergrens\",\n                \"da\": \"Alarmgrænse\",\n                \"de\": \"Alarmschwelle\",\n                \"es\": \"Umbral de alarma\",\n                \"fr\": \"Seuil d'alarme\",\n                \"it\": \"Soglia di allarme\",\n                \"no\": \"Alarm terskel\",\n                \"sv\": \"Alarmtröskel\",\n                \"pl\": \"Próg alarmowy\",\n                \"ru\": \"Порог тревоги\",\n                \"ko\": \"알람 임계 값\"\n              },\n              \"hint\": {\n                \"en\": \"Threshold below which the alarm will be activated.\",\n                \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n                \"da\": \"Grænse under hvilken alarmen aktiveres.\",\n                \"de\": \"Schwelle, unter der der Alarm aktiviert wird.\",\n                \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n                \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n                \"it\": \"Soglia al di sotto della quale l'allarme verrà attivato.\",\n                \"no\": \"Grensen under hvilken alarmen blir aktivert.\",\n                \"sv\": \"Tröskeln under vilken larmet aktiveras.\",\n                \"pl\": \"Próg, poniżej którego alarm zostanie aktywowany.\",\n                \"ru\": \"Порог, ниже которого будет активирована тревога.\",\n                \"ko\": \"알람이 활성화되는 임계 값\"\n              },\n              \"value\": 20,\n              \"attr\": {\n                \"min\": 1,\n                \"max\": 90\n              }\n            },\n            {\n              \"id\": \"main_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Main brush remaining (%)\",\n                \"nl\": \"Hoofdborstel over (%)\",\n                \"da\": \"Hovedbørste tilbage (%)\",\n                \"de\": \"Verbleibende Hauptbürste (%)\",\n                \"es\": \"Cepillo principal restante (%)\",\n                \"fr\": \"Brosse principale restante (%)\",\n                \"it\": \"Spazzola principale rimanente (%)\",\n                \"no\": \"Hovedbørste gjenstår (%)\",\n                \"sv\": \"Huvudborste återstående (%)\",\n                \"pl\": \"Pozostało głównej szczotki (%)\",\n                \"ru\": \"Осталось главной щетки (%)\",\n                \"ko\": \"남은 주요 브러시 (%)\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"side_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Side brush remaining\",\n                \"nl\": \"Zijborstel over\",\n                \"da\": \"Sidebørste tilbage\",\n                \"de\": \"Verbleibende Seitenbürste\",\n                \"es\": \"Cepillo lateral restante\",\n                \"fr\": \"Brosse latérale restante\",\n                \"it\": \"Spazzola laterale rimanente\",\n                \"no\": \"Sidebørste gjenstår\",\n                \"sv\": \"Sidoborste återstående\",\n                \"pl\": \"Pozostało szczotki bocznej\",\n                \"ru\": \"Осталось боковой щетки\",\n                \"ko\": \"남은 사이드 브러시\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"filter_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter remaining\",\n                \"nl\": \"Filter over\",\n                \"da\": \"Filter tilbage\",\n                \"de\": \"Verbleibender Filter\",\n                \"es\": \"Filtro restante\",\n                \"fr\": \"Filtre restant\",\n                \"it\": \"Filtro rimanente\",\n                \"no\": \"Filter gjenstår\",\n                \"sv\": \"Filter kvar\",\n                \"pl\": \"Pozostało filtra\",\n                \"ru\": \"Осталось фильтра\",\n                \"ko\": \"남은 필터\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"total_work_time\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Total work time (h)\",\n                \"nl\": \"Totale gebruikstijd (u)\",\n                \"da\": \"Samlet arbejdstid (t)\",\n                \"de\": \"Gesamtarbeitszeit (h)\",\n                \"es\": \"Tiempo total de trabajo (h)\",\n                \"fr\": \"Temps de travail total (h)\",\n                \"it\": \"Tempo di lavoro totale (h)\",\n                \"no\": \"Total arbeidstid (t)\",\n                \"sv\": \"Total arbetstid (h)\",\n                \"pl\": \"Całkowity czas pracy (h)\",\n                \"ru\": \"Общее время работы (ч)\",\n                \"ko\": \"총 작업 시간 (h)\"\n              },\n              \"value\": 0,\n              \"attr\": {\n                \"min\": 0,\n                \"step\": 0.1\n              }\n            },\n            {\n              \"id\": \"total_cleared_area\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Total cleaned area (m²)\",\n                \"nl\": \"Totaal geschoont (m²)\",\n                \"da\": \"Samlet rengjort område (m²)\",\n                \"de\": \"Gesamt gereinigte Fläche (m²)\",\n                \"es\": \"Área total limpia (m²)\",\n                \"fr\": \"Surface totale nettoyée (m²)\",\n                \"it\": \"Area totale pulita (m²)\",\n                \"no\": \"Totalt rengjort område (m²)\",\n                \"sv\": \"Totalt rengjort område (m²)\",\n                \"pl\": \"Całkowita oczyszczona powierzchnia (m²)\",\n                \"ru\": \"Общая очищенная площадь (м²)\",\n                \"ko\": \"총 청소 면적 (m²)\"\n              },\n              \"value\": 0,\n              \"attr\": {\n                \"min\": 0,\n                \"step\": 0.1\n              }\n            },\n            {\n              \"id\": \"total_clean_count\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Total clean count\",\n                \"nl\": \"Totaal aantal opschoningen\",\n                \"da\": \"Samlet rengøringsantal\",\n                \"de\": \"Gesamt Reinigungsanzahl\",\n                \"es\": \"Conteo total de limpiezas\",\n                \"fr\": \"Nombre total de nettoyages\",\n                \"it\": \"Conteggio totale pulizie\",\n                \"no\": \"Total rengjøringsteller\",\n                \"sv\": \"Totalstädningsräkning\",\n                \"pl\": \"Całkowita liczba sprzątań\",\n                \"ru\": \"Общее количество уборок\",\n                \"ko\": \"총 청소 횟수\"\n              },\n              \"value\": 0,\n              \"attr\": {\n                \"min\": 0,\n                \"step\": 1\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device data\",\n            \"nl\": \"Apparaat data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"장치 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"error\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Error\",\n                \"nl\": \"Error\",\n                \"da\": \"Fejl\",\n                \"de\": \"Fehler\",\n                \"es\": \"Error\",\n                \"fr\": \"Erreur\",\n                \"it\": \"Errore\",\n                \"no\": \"Feil\",\n                \"sv\": \"Fel\",\n                \"pl\": \"Błąd\",\n                \"ru\": \"Ошибка\",\n                \"ko\": \"오류\"\n              },\n              \"value\": \"No error\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/vacuum_xiaomi_vacuum_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Xiaomi Vacuum Cleaner MIoT (WiFi)\",\n        \"nl\": \"Xiaomi stofzuiger MIoT (WiFi)\",\n        \"da\": \"Xiaomi Støvsuger MIoT (WiFi)\",\n        \"de\": \"Xiaomi Staubsauger MIoT (WiFi)\",\n        \"es\": \"Aspiradora Xiaomi MIoT (WiFi)\",\n        \"fr\": \"Aspirateur Xiaomi MIoT (WiFi)\",\n        \"it\": \"Aspirapolvere Xiaomi MIoT (WiFi)\",\n        \"no\": \"Xiaomi Støvsuger MIoT (WiFi)\",\n        \"sv\": \"Xiaomi Dammsugare MIoT (WiFi)\",\n        \"pl\": \"Odkurzacz Xiaomi MIoT (WiFi)\",\n        \"ru\": \"Пылесос Xiaomi MIoT (WiFi)\",\n        \"ko\": \"샤오미 진공 청소기 MIoT (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/vacuum_xiaomi_vacuum_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/vacuum_xiaomi_vacuum_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"vacuumcleaner\",\n      \"capabilities\": [\n        \"onoff\",\n        \"vacuumcleaner_state\",\n        \"vacuum_xiaomi_mop_mode\",\n        \"measure_battery\",\n        \"alarm_battery\",\n        \"alarm_main_brush_work_time\",\n        \"alarm_side_brush_work_time\",\n        \"alarm_filter_work_time\"\n      ],\n      \"energy\": {\n        \"batteries\": [\n          \"INTERNAL\"\n        ]\n      },\n      \"id\": \"vacuum_xiaomi_vacuum_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Consumables\",\n            \"nl\": \"Verbruiksartikelen\",\n            \"da\": \"Forbrugsvarer\",\n            \"de\": \"Verbrauchsmaterialien\",\n            \"es\": \"Consumibles\",\n            \"fr\": \"Consommables\",\n            \"it\": \"Consumabili\",\n            \"no\": \"Forbruksvarer\",\n            \"sv\": \"Förbrukningsvaror\",\n            \"pl\": \"Materiały eksploatacyjne\",\n            \"ru\": \"Расходные материалы\",\n            \"ko\": \"소모품\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_threshold\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Alarm threshold\",\n                \"nl\": \"Alarm ondergrens\",\n                \"da\": \"Alarmgrænse\",\n                \"de\": \"Alarmschwelle\",\n                \"es\": \"Umbral de alarma\",\n                \"fr\": \"Seuil d'alarme\",\n                \"it\": \"Soglia di allarme\",\n                \"no\": \"Alarm terskel\",\n                \"sv\": \"Alarmtröskel\",\n                \"pl\": \"Próg alarmowy\",\n                \"ru\": \"Порог тревоги\",\n                \"ko\": \"알람 임계 값\"\n              },\n              \"hint\": {\n                \"en\": \"Threshold below which the alarm will be activated.\",\n                \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n                \"da\": \"Grænse under hvilken alarmen aktiveres.\",\n                \"de\": \"Schwelle, unter der der Alarm aktiviert wird.\",\n                \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n                \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n                \"it\": \"Soglia al di sotto della quale l'allarme verrà attivato.\",\n                \"no\": \"Grensen under hvilken alarmen blir aktivert.\",\n                \"sv\": \"Tröskeln under vilken larmet aktiveras.\",\n                \"pl\": \"Próg, poniżej którego alarm zostanie aktywowany.\",\n                \"ru\": \"Порог, ниже которого будет активирована тревога.\",\n                \"ko\": \"알람이 활성화되는 임계 값\"\n              },\n              \"value\": 20,\n              \"attr\": {\n                \"min\": 1,\n                \"max\": 90\n              }\n            },\n            {\n              \"id\": \"main_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Main brush remaining (%)\",\n                \"nl\": \"Hoofdborstel over (%)\",\n                \"da\": \"Hovedbørste tilbage (%)\",\n                \"de\": \"Verbleibende Hauptbürste (%)\",\n                \"es\": \"Cepillo principal restante (%)\",\n                \"fr\": \"Brosse principale restante (%)\",\n                \"it\": \"Spazzola principale rimanente (%)\",\n                \"no\": \"Hovedbørste gjenstår (%)\",\n                \"sv\": \"Huvudborste återstående (%)\",\n                \"pl\": \"Pozostało głównej szczotki (%)\",\n                \"ru\": \"Осталось главной щетки (%)\",\n                \"ko\": \"남은 주요 브러시 (%)\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"side_brush_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Side brush remaining\",\n                \"nl\": \"Zijborstel over\",\n                \"da\": \"Sidebørste tilbage\",\n                \"de\": \"Verbleibende Seitenbürste\",\n                \"es\": \"Cepillo lateral restante\",\n                \"fr\": \"Brosse latérale restante\",\n                \"it\": \"Spazzola laterale rimanente\",\n                \"no\": \"Sidebørste gjenstår\",\n                \"sv\": \"Sidoborste återstående\",\n                \"pl\": \"Pozostało szczotki bocznej\",\n                \"ru\": \"Осталось боковой щетки\",\n                \"ko\": \"남은 사이드 브러시\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"filter_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Filter remaining\",\n                \"nl\": \"Filter over\",\n                \"da\": \"Filter tilbage\",\n                \"de\": \"Verbleibender Filter\",\n                \"es\": \"Filtro restante\",\n                \"fr\": \"Filtre restant\",\n                \"it\": \"Filtro rimanente\",\n                \"no\": \"Filter gjenstår\",\n                \"sv\": \"Filter kvar\",\n                \"pl\": \"Pozostało filtra\",\n                \"ru\": \"Осталось фильтра\",\n                \"ko\": \"남은 필터\"\n              },\n              \"value\": \"0%\"\n            },\n            {\n              \"id\": \"total_work_time\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total work time\",\n                \"nl\": \"Totale gebruikstijd\",\n                \"da\": \"Samlet arbejdstid\",\n                \"de\": \"Gesamtarbeitszeit\",\n                \"es\": \"Tiempo total de trabajo\",\n                \"fr\": \"Temps de travail total\",\n                \"it\": \"Tempo di lavoro totale\",\n                \"no\": \"Total arbeidstid\",\n                \"sv\": \"Total arbetstid\",\n                \"pl\": \"Całkowity czas pracy\",\n                \"ru\": \"Общее время работы\",\n                \"ko\": \"총 작업 시간\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"total_cleared_area\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total cleaned area\",\n                \"nl\": \"Totaal geschoont\",\n                \"da\": \"Samlet rengjort område\",\n                \"de\": \"Gesamt gereinigte Fläche\",\n                \"es\": \"Área total limpia\",\n                \"fr\": \"Surface totale nettoyée\",\n                \"it\": \"Area totale pulita\",\n                \"no\": \"Totalt rengjort område\",\n                \"sv\": \"Totalt rengjort område\",\n                \"pl\": \"Całkowita oczyszczona powierzchnia\",\n                \"ru\": \"Общая очищенная площадь\",\n                \"ko\": \"총 청소 면적\"\n              },\n              \"value\": \"0\"\n            },\n            {\n              \"id\": \"total_clean_count\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Total clean count\",\n                \"nl\": \"Totaal aantal opschoningen\",\n                \"da\": \"Samlet rengøringsantal\",\n                \"de\": \"Gesamt Reinigungsanzahl\",\n                \"es\": \"Conteo total de limpiezas\",\n                \"fr\": \"Nombre total de nettoyages\",\n                \"it\": \"Conteggio totale pulizie\",\n                \"no\": \"Total rengjøringsteller\",\n                \"sv\": \"Totalstädningsräkning\",\n                \"pl\": \"Całkowita liczba sprzątań\",\n                \"ru\": \"Общее количество уборок\",\n                \"ko\": \"총 청소 횟수\"\n              },\n              \"value\": \"0\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device data\",\n            \"nl\": \"Apparaat data\",\n            \"da\": \"Enhedsdata\",\n            \"de\": \"Gerätedaten\",\n            \"es\": \"Datos del dispositivo\",\n            \"fr\": \"Données de l'appareil\",\n            \"it\": \"Dati del dispositivo\",\n            \"no\": \"Enhetsdata\",\n            \"sv\": \"Enhetsdata\",\n            \"pl\": \"Dane urządzenia\",\n            \"ru\": \"Данные устройства\",\n            \"ko\": \"장치 데이터\"\n          },\n          \"children\": [\n            {\n              \"id\": \"error\",\n              \"type\": \"label\",\n              \"label\": {\n                \"en\": \"Error\",\n                \"nl\": \"Error\",\n                \"da\": \"Fejl\",\n                \"de\": \"Fehler\",\n                \"es\": \"Error\",\n                \"fr\": \"Erreur\",\n                \"it\": \"Errore\",\n                \"no\": \"Feil\",\n                \"sv\": \"Fel\",\n                \"pl\": \"Błąd\",\n                \"ru\": \"Ошибка\",\n                \"ko\": \"오류\"\n              },\n              \"value\": \"No error\"\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/vibration_sensor/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"list_devices\",\n          \"template\": \"list_devices\",\n          \"navigation\": {\n            \"next\": \"add_devices\"\n          },\n          \"options\": {\n            \"singular\": false\n          }\n        },\n        {\n          \"id\": \"add_devices\",\n          \"template\": \"add_devices\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Vibration Sensor (Gateway)\",\n        \"nl\": \"Vibration Sensor (Gateway)\",\n        \"da\": \"Vibrationssensor (Gateway)\",\n        \"de\": \"Vibrationssensor (Gateway)\",\n        \"es\": \"Sensor de Vibración (Gateway)\",\n        \"fr\": \"Capteur de Vibration (Passerelle)\",\n        \"it\": \"Sensore di Vibrazione (Gateway)\",\n        \"no\": \"Vibrasjonssensor (Gateway)\",\n        \"sv\": \"Vibrationssensor (Gateway)\",\n        \"pl\": \"Czujnik Wibracji (Gateway)\",\n        \"ru\": \"Датчик Вибрации (Шлюз)\",\n        \"ko\": \"진동 센서 (게이트웨이)\"\n      },\n      \"images\": {\n        \"large\": \"/drivers/vibration_sensor/assets/images/large.jpg\",\n        \"small\": \"/drivers/vibration_sensor/assets/images/small.jpg\"\n      },\n      \"class\": \"sensor\",\n      \"capabilities\": [\n        \"alarm_tamper\",\n        \"alarm_motion.tilt\",\n        \"alarm_motion.freefall\",\n        \"measure_battery\",\n        \"alarm_battery\"\n      ],\n      \"capabilitiesOptions\": {\n        \"alarm_tamper\": {\n          \"title\": {\n            \"en\": \"Vibrate\",\n            \"nl\": \"Vibratie\",\n            \"da\": \"Vibrering\",\n            \"de\": \"Vibrieren\",\n            \"es\": \"Vibrar\",\n            \"fr\": \"Vibrer\",\n            \"it\": \"Vibrare\",\n            \"no\": \"Vibrere\",\n            \"sv\": \"Vibrera\",\n            \"pl\": \"Wibracja\",\n            \"ru\": \"Вибрация\",\n            \"ko\": \"진동\"\n          }\n        },\n        \"alarm_motion.tilt\": {\n          \"title\": {\n            \"en\": \"Tilt\",\n            \"nl\": \"Tilt\",\n            \"da\": \"Vip\",\n            \"de\": \"Neigung\",\n            \"es\": \"Inclinación\",\n            \"fr\": \"Inclinaison\",\n            \"it\": \"Inclinazione\",\n            \"no\": \"Vippe\",\n            \"sv\": \"Lutning\",\n            \"pl\": \"Przechylenie\",\n            \"ru\": \"Наклон\",\n            \"ko\": \"기울기\"\n          }\n        },\n        \"alarm_motion.freefall\": {\n          \"title\": {\n            \"en\": \"Free fall\",\n            \"nl\": \"Vrije val\",\n            \"da\": \"Frit fald\",\n            \"de\": \"Freier Fall\",\n            \"es\": \"Caída libre\",\n            \"fr\": \"Chute libre\",\n            \"it\": \"Caduta libera\",\n            \"no\": \"Fritt fall\",\n            \"sv\": \"Fritt fall\",\n            \"pl\": \"Upadek swobodny\",\n            \"ru\": \"Свободное падение\",\n            \"ko\": \"자유 낙하\"\n          }\n        }\n      },\n      \"energy\": {\n        \"batteries\": [\n          \"CR2032\"\n        ]\n      },\n      \"id\": \"vibration_sensor\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Duration of the sensor alarm\",\n            \"nl\": \"Duur van het sensor alarm\",\n            \"da\": \"Varighed af sensoralarmen\",\n            \"de\": \"Dauer des Sensoralarms\",\n            \"es\": \"Duración de la alarma del sensor\",\n            \"fr\": \"Durée de l'alarme du capteur\",\n            \"it\": \"Durata dell'allarme del sensore\",\n            \"no\": \"Varighet av sensoralarmen\",\n            \"sv\": \"Varaktighet för sensorlarmet\",\n            \"pl\": \"Czas trwania alarmu czujnika\",\n            \"ru\": \"Длительность сигнализации датчика\",\n            \"ko\": \"센서 알람 지속 시간\"\n          },\n          \"children\": [\n            {\n              \"id\": \"alarm_duration_number\",\n              \"type\": \"number\",\n              \"label\": {\n                \"en\": \"Disable after\",\n                \"nl\": \"Uitschakelen na\",\n                \"da\": \"Deaktiver efter\",\n                \"de\": \"Deaktivieren nach\",\n                \"es\": \"Desactivar después de\",\n                \"fr\": \"Désactiver après\",\n                \"it\": \"Disattiva dopo\",\n                \"no\": \"Deaktiver etter\",\n                \"sv\": \"Avaktivera efter\",\n                \"pl\": \"Wyłącz po\",\n                \"ru\": \"Отключить после\",\n                \"ko\": \"이후 비활성화\"\n              },\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 60,\n                \"max\": 86400\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"deviceSid\",\n              \"type\": \"label\",\n              \"value\": \"0123456789abcd\",\n              \"label\": {\n                \"en\": \"Device SID\",\n                \"nl\": \"Apparaat SID\",\n                \"da\": \"Enhed SID\",\n                \"de\": \"Gerät SID\",\n                \"es\": \"Dispositivo SID\",\n                \"fr\": \"Appareil SID\",\n                \"it\": \"Dispositivo SID\",\n                \"no\": \"Enhet SID\",\n                \"sv\": \"Enhet SID\",\n                \"pl\": \"Urządzenie SID\",\n                \"ru\": \"Устройство SID\",\n                \"ko\": \"장치 SID\"\n              }\n            },\n            {\n              \"id\": \"model\",\n              \"type\": \"label\",\n              \"value\": \"lumi.device\",\n              \"label\": {\n                \"en\": \"Model\",\n                \"nl\": \"Model\",\n                \"da\": \"Model\",\n                \"de\": \"Modell\",\n                \"es\": \"Modelo\",\n                \"fr\": \"Modèle\",\n                \"it\": \"Modello\",\n                \"no\": \"Modell\",\n                \"sv\": \"Modell\",\n                \"pl\": \"Model\",\n                \"ru\": \"Модель\",\n                \"ko\": \"모델\"\n              }\n            },\n            {\n              \"id\": \"modelCode\",\n              \"type\": \"label\",\n              \"value\": \"AABBCC01LM\",\n              \"label\": {\n                \"en\": \"Device Model Code\",\n                \"nl\": \"Apparaat modelcode\",\n                \"da\": \"Enhedsmodelkode\",\n                \"de\": \"Gerätemodellcode\",\n                \"es\": \"Código de modelo del dispositivo\",\n                \"fr\": \"Code modèle de l'appareil\",\n                \"it\": \"Codice modello del dispositivo\",\n                \"no\": \"Enhetsmodellkode\",\n                \"sv\": \"Enhetsmodellkod\",\n                \"pl\": \"Kod modelu urządzenia\",\n                \"ru\": \"Код модели устройства\",\n                \"ko\": \"장치 모델 코드\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/yeelink_light_ceil43_miot/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Yeelight Arwen Ceiling Light D (WiFi)\",\n        \"nl\": \"Yeelight Arwen Plafondlamp D (WiFi)\",\n        \"da\": \"Yeelight Arwen Loftslampe D (WiFi)\",\n        \"de\": \"Yeelight Arwen Deckenleuchte D (WiFi)\",\n        \"es\": \"Luz de techo Yeelight Arwen D (WiFi)\",\n        \"fr\": \"Plafonnier Yeelight Arwen D (WiFi)\",\n        \"it\": \"Plafoniera Yeelight Arwen D (WiFi)\",\n        \"no\": \"Yeelight Arwen Taklampe D (WiFi)\",\n        \"sv\": \"Yeelight Arwen Taklampa D (WiFi)\",\n        \"pl\": \"Lampa sufitowa Yeelight Arwen D (WiFi)\",\n        \"ru\": \"Потолочный светильник Yeelight Arwen D (WiFi)\",\n        \"ko\": \"Yeelight Arwen 천장 조명 D (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/yeelink_light_ceil43_miot/assets/images/large.jpg\",\n        \"small\": \"drivers/yeelink_light_ceil43_miot/assets/images/small.jpg\"\n      },\n      \"class\": \"light\",\n      \"capabilities\": [\n        \"onoff\",\n        \"dim\",\n        \"light_mode\",\n        \"yeelight_ceil43_mode\",\n        \"light_temperature\",\n        \"light_hue\",\n        \"light_saturation\",\n        \"onoff.ambient\",\n        \"dim.ambient\",\n        \"light_mode.ambient\",\n        \"light_temperature.ambient\",\n        \"light_hue.ambient\",\n        \"light_saturation.ambient\"\n      ],\n      \"capabilitiesOptions\": {\n        \"dim\": {\n          \"min\": 0.01\n        },\n        \"onoff.ambient\": {\n          \"title\": {\n            \"en\": \"Ambient Light\",\n            \"nl\": \"Sfeerverlichting\",\n            \"da\": \"Stemningslys\",\n            \"de\": \"Ambiente-Licht\",\n            \"es\": \"Luz ambiental\",\n            \"fr\": \"Lumière d'ambiance\",\n            \"it\": \"Luce ambientale\",\n            \"no\": \"Stemningslys\",\n            \"sv\": \"Stämningsljus\",\n            \"pl\": \"Swiatlo otoczenia\",\n            \"ru\": \"Фоновая подсветка\",\n            \"ko\": \"무드등\"\n          }\n        },\n        \"dim.ambient\": {\n          \"title\": {\n            \"en\": \"Ambient Brightness\"\n          },\n          \"min\": 0.01\n        },\n        \"light_mode.ambient\": {\n          \"title\": {\n            \"en\": \"Ambient Mode\"\n          }\n        },\n        \"light_temperature.ambient\": {\n          \"title\": {\n            \"en\": \"Ambient Temperature\"\n          }\n        },\n        \"light_hue.ambient\": {\n          \"title\": {\n            \"en\": \"Ambient Hue\"\n          }\n        },\n        \"light_saturation.ambient\": {\n          \"title\": {\n            \"en\": \"Ambient Saturation\"\n          }\n        }\n      },\n      \"id\": \"yeelink_light_ceil43_miot\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\",\n            \"ja\": \"デバイス設定\",\n            \"zh\": \"设备设置\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"icon\": \"/drivers/zhimi-fan/assets/icon.svg\",\n      \"pair\": [\n        {\n          \"id\": \"start\",\n          \"navigation\": {\n            \"next\": \"pair\"\n          }\n        },\n        {\n          \"id\": \"pair\"\n        },\n        {\n          \"id\": \"add_device\"\n        }\n      ],\n      \"platforms\": [\n        \"local\"\n      ],\n      \"connectivity\": [\n        \"lan\"\n      ],\n      \"name\": {\n        \"en\": \"Basic Smartmi/ZhiMi Fan (WiFi)\",\n        \"nl\": \"Basis Smartmi/ZhiMi Fan (WiFi)\",\n        \"da\": \"Basis Smartmi/ZhiMi Fan (WiFi)\",\n        \"de\": \"Basis Smartmi/ZhiMi Fan (WiFi)\",\n        \"es\": \"Ventilador Básico Smartmi/ZhiMi (WiFi)\",\n        \"fr\": \"Ventilateur Smartmi/ZhiMi de base (WiFi)\",\n        \"it\": \"Ventilatore Smartmi/ZhiMi Base (WiFi)\",\n        \"no\": \"Grunnleggende Smartmi/ZhiMi Vifte (WiFi)\",\n        \"sv\": \"Grundläggande Smartmi/ZhiMi Fläkt (WiFi)\",\n        \"pl\": \"Podstawowy wentylator Smartmi/ZhiMi (WiFi)\",\n        \"ru\": \"Базовый вентилятор Smartmi/ZhiMi (WiFi)\",\n        \"ko\": \"기본 Smartmi/ZhiMi 팬 (WiFi)\"\n      },\n      \"images\": {\n        \"large\": \"drivers/zhimi-fan/assets/images/large.jpg\",\n        \"small\": \"drivers/zhimi-fan/assets/images/small.jpg\"\n      },\n      \"class\": \"fan\",\n      \"capabilities\": [\n        \"onoff\"\n      ],\n      \"id\": \"zhimi-fan\",\n      \"settings\": [\n        {\n          \"type\": \"group\",\n          \"label\": {\n            \"en\": \"Device Settings\",\n            \"nl\": \"Apparaat instellingen\",\n            \"da\": \"Enhedsindstillinger\",\n            \"de\": \"Geräteeinstellungen\",\n            \"es\": \"Configuración del dispositivo\",\n            \"fr\": \"Paramètres de l'appareil\",\n            \"it\": \"Impostazioni del dispositivo\",\n            \"no\": \"Enhetsinnstillinger\",\n            \"sv\": \"Enhetsinställningar\",\n            \"pl\": \"Ustawienia urządzenia\",\n            \"ru\": \"Настройки устройства\",\n            \"ko\": \"장치 설정\"\n          },\n          \"children\": [\n            {\n              \"id\": \"address\",\n              \"type\": \"text\",\n              \"value\": \"0.0.0.0\",\n              \"label\": {\n                \"en\": \"IP Address\",\n                \"nl\": \"IP adres\",\n                \"da\": \"IP-adresse\",\n                \"de\": \"IP-Adresse\",\n                \"es\": \"Dirección IP\",\n                \"fr\": \"Adresse IP\",\n                \"it\": \"Indirizzo IP\",\n                \"no\": \"IP-adresse\",\n                \"sv\": \"IP-adress\",\n                \"pl\": \"Adres IP\",\n                \"ru\": \"IP-адрес\",\n                \"ko\": \"IP 주소\"\n              }\n            },\n            {\n              \"id\": \"token\",\n              \"type\": \"text\",\n              \"value\": \"\",\n              \"label\": {\n                \"en\": \"Mi Device Token\",\n                \"nl\": \"Mi Apparaat Token\",\n                \"da\": \"Mi Enheds Token\",\n                \"de\": \"Mi Gerätetoken\",\n                \"es\": \"Token del Dispositivo Mi\",\n                \"fr\": \"Jeton de l'Appareil Mi\",\n                \"it\": \"Token Dispositivo Mi\",\n                \"no\": \"Mi Enhet Token\",\n                \"sv\": \"Mi Enhetstoken\",\n                \"pl\": \"Token Urządzenia Mi\",\n                \"ru\": \"Токен Устройства Mi\",\n                \"ko\": \"Mi 기기 토큰\"\n              }\n            },\n            {\n              \"id\": \"polling\",\n              \"type\": \"number\",\n              \"value\": 60,\n              \"attr\": {\n                \"min\": 5,\n                \"max\": 3600\n              },\n              \"label\": {\n                \"en\": \"Polling Frequency\",\n                \"nl\": \"Polling frequentie\",\n                \"da\": \"Polling Frekvens\",\n                \"de\": \"Abfragefrequenz\",\n                \"es\": \"Frecuencia de sondeo\",\n                \"fr\": \"Fréquence de sondage\",\n                \"it\": \"Frequenza di polling\",\n                \"no\": \"Polling Frekvens\",\n                \"sv\": \"Pollingfrekvens\",\n                \"pl\": \"Częstotliwość odpytywania\",\n                \"ru\": \"Частота опроса\",\n                \"ko\": \"폴링 빈도\"\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ],\n  \"capabilities\": {\n    \"airfryer_careli_food_quantity\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Food Quantity\",\n        \"nl\": \"Voedselhoeveelheid\",\n        \"da\": \"Mad Kvantitet\",\n        \"de\": \"Lebensmittelmenge\",\n        \"es\": \"Cantidad de Comida\",\n        \"fr\": \"Quantité de Nourriture\",\n        \"it\": \"Quantità di Cibo\",\n        \"no\": \"Mat Mengde\",\n        \"sv\": \"Matmängd\",\n        \"pl\": \"Ilość Jedzenia\",\n        \"ru\": \"Количество Еды\",\n        \"ko\": \"음식 양\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"None\",\n            \"nl\": \"Geen\",\n            \"da\": \"Ingen\",\n            \"de\": \"Kein\",\n            \"es\": \"Ninguna\",\n            \"fr\": \"Aucun\",\n            \"it\": \"Nessuno\",\n            \"no\": \"Ingen\",\n            \"sv\": \"Inget\",\n            \"pl\": \"Brak\",\n            \"ru\": \"Нет\",\n            \"ko\": \"없음\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Single\",\n            \"nl\": \"Enkel\",\n            \"da\": \"Enkelt\",\n            \"de\": \"Einzeln\",\n            \"es\": \"Único\",\n            \"fr\": \"Simple\",\n            \"it\": \"Singolo\",\n            \"no\": \"Enkelt\",\n            \"sv\": \"Enkel\",\n            \"pl\": \"Pojedynczy\",\n            \"ru\": \"Одинарный\",\n            \"ko\": \"단일\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Double\",\n            \"nl\": \"Dubbel\",\n            \"da\": \"Dobbelt\",\n            \"de\": \"Doppelt\",\n            \"es\": \"Doble\",\n            \"fr\": \"Double\",\n            \"it\": \"Doppio\",\n            \"no\": \"Dobbel\",\n            \"sv\": \"Dubbel\",\n            \"pl\": \"Podwójny\",\n            \"ru\": \"Двойной\",\n            \"ko\": \"더블\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Half\",\n            \"nl\": \"Half\",\n            \"da\": \"Halv\",\n            \"de\": \"Halb\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moitié\",\n            \"it\": \"Metà\",\n            \"no\": \"Halv\",\n            \"sv\": \"Halv\",\n            \"pl\": \"Połowa\",\n            \"ru\": \"Половина\",\n            \"ko\": \"반\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Full\",\n            \"nl\": \"Vol\",\n            \"da\": \"Fuldt\",\n            \"de\": \"Voll\",\n            \"es\": \"Completo\",\n            \"fr\": \"Complet\",\n            \"it\": \"Pieno\",\n            \"no\": \"Full\",\n            \"sv\": \"Full\",\n            \"pl\": \"Pełny\",\n            \"ru\": \"Полный\",\n            \"ko\": \"가득\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/food-quantity.svg\"\n    },\n    \"airfryer_careli_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Air Fryer Mode\",\n        \"nl\": \"Air Fryer Mode\",\n        \"da\": \"Airfryer-tilstand\",\n        \"de\": \"Airfryer Modus\",\n        \"es\": \"Modo Freidora de Aire\",\n        \"fr\": \"Mode Friteuse à Air\",\n        \"it\": \"Modalità Friggitrice ad Aria\",\n        \"no\": \"Luftfrityrmodus\",\n        \"sv\": \"Luftfritösläge\",\n        \"pl\": \"Tryb Frytownicy Powietrznej\",\n        \"ru\": \"Режим Аэрофритюрницы\",\n        \"ko\": \"에어프라이어 모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Shutdown\",\n            \"nl\": \"Uitgeschakeld\",\n            \"da\": \"Luk ned\",\n            \"de\": \"Abschalten\",\n            \"es\": \"Apagado\",\n            \"fr\": \"Arrêt\",\n            \"it\": \"Spegnimento\",\n            \"no\": \"Avslutte\",\n            \"sv\": \"Stänga av\",\n            \"pl\": \"Wyłączone\",\n            \"ru\": \"Выключение\",\n            \"ko\": \"종료\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Standby\",\n            \"nl\": \"Standby\",\n            \"da\": \"Stand-by\",\n            \"de\": \"Standby\",\n            \"es\": \"En Espera\",\n            \"fr\": \"Veille\",\n            \"it\": \"Standby\",\n            \"no\": \"Standby\",\n            \"sv\": \"Standby\",\n            \"pl\": \"Czekanie\",\n            \"ru\": \"Режим ожидания\",\n            \"ko\": \"대기 중\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Pause\",\n            \"nl\": \"Pauze\",\n            \"da\": \"Pause\",\n            \"de\": \"Pause\",\n            \"es\": \"Pausa\",\n            \"fr\": \"Pause\",\n            \"it\": \"Pausa\",\n            \"no\": \"Pause\",\n            \"sv\": \"Paus\",\n            \"pl\": \"Pauza\",\n            \"ru\": \"Пауза\",\n            \"ko\": \"일시 중지\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Schedule\",\n            \"nl\": \"Schema\",\n            \"da\": \"Planlægning\",\n            \"de\": \"Zeitplan\",\n            \"es\": \"Horario\",\n            \"fr\": \"Programme\",\n            \"it\": \"Programma\",\n            \"no\": \"Planlegge\",\n            \"sv\": \"Schema\",\n            \"pl\": \"Harmonogram\",\n            \"ru\": \"Расписание\",\n            \"ko\": \"일정\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Cooking\",\n            \"nl\": \"Bakken\",\n            \"da\": \"Madlavning\",\n            \"de\": \"Kochen\",\n            \"es\": \"Cocinando\",\n            \"fr\": \"Cuisson\",\n            \"it\": \"Cottura\",\n            \"no\": \"Matlaging\",\n            \"sv\": \"Matlagning\",\n            \"pl\": \"Gotowanie\",\n            \"ru\": \"Готовка\",\n            \"ko\": \"요리 중\"\n          }\n        },\n        {\n          \"id\": \"5\",\n          \"title\": {\n            \"en\": \"Preheat\",\n            \"nl\": \"Voorverwarmen\",\n            \"da\": \"Forvarm\",\n            \"de\": \"Vorheizen\",\n            \"es\": \"Precalentar\",\n            \"fr\": \"Préchauffage\",\n            \"it\": \"Preriscalda\",\n            \"no\": \"Forvarme\",\n            \"sv\": \"Förvärm\",\n            \"pl\": \"Rozgrzewanie\",\n            \"ru\": \"Предварительный нагрев\",\n            \"ko\": \"예열\"\n          }\n        },\n        {\n          \"id\": \"6\",\n          \"title\": {\n            \"en\": \"Cooked\",\n            \"nl\": \"Gebakken\",\n            \"da\": \"Tilberedt\",\n            \"de\": \"Gekocht\",\n            \"es\": \"Cocido\",\n            \"fr\": \"Cuit\",\n            \"it\": \"Cotto\",\n            \"no\": \"Kokt\",\n            \"sv\": \"Tillagad\",\n            \"pl\": \"Ugotowane\",\n            \"ru\": \"Приготовлено\",\n            \"ko\": \"조리 완료\"\n          }\n        },\n        {\n          \"id\": \"7\",\n          \"title\": {\n            \"en\": \"Preheat finished\",\n            \"nl\": \"Voorverwarmen klaar\",\n            \"da\": \"Forvarm færdig\",\n            \"de\": \"Vorheizen abgeschlossen\",\n            \"es\": \"Precalentamiento terminado\",\n            \"fr\": \"Préchauffage terminé\",\n            \"it\": \"Preriscaldamento finito\",\n            \"no\": \"Forvarming ferdig\",\n            \"sv\": \"Förvärmning klart\",\n            \"pl\": \"Rozgrzewanie zakończone\",\n            \"ru\": \"Предварительный нагрев завершен\",\n            \"ko\": \"예열 완료\"\n          }\n        },\n        {\n          \"id\": \"8\",\n          \"title\": {\n            \"en\": \"Preheat paused\",\n            \"nl\": \"Voorverwarmen gepauzeerd\",\n            \"da\": \"Forvarm sat på pause\",\n            \"de\": \"Vorheizen pausiert\",\n            \"es\": \"Precalentamiento en pausa\",\n            \"fr\": \"Préchauffage en pause\",\n            \"it\": \"Preriscaldamento in pausa\",\n            \"no\": \"Forvarming satt på pause\",\n            \"sv\": \"Förvärmning pausad\",\n            \"pl\": \"Rozgrzewanie wstrzymane\",\n            \"ru\": \"Предварительный нагрев приостановлен\",\n            \"ko\": \"예열 일시 중지\"\n          }\n        },\n        {\n          \"id\": \"9\",\n          \"title\": {\n            \"en\": \"Pause2\",\n            \"nl\": \"Pause2\",\n            \"da\": \"Pause2\",\n            \"de\": \"Pause2\",\n            \"es\": \"Pause2\",\n            \"fr\": \"Pause2\",\n            \"it\": \"Pause2\",\n            \"no\": \"Pause2\",\n            \"sv\": \"Pause2\",\n            \"pl\": \"Pause2\",\n            \"ru\": \"Pause2\",\n            \"ko\": \"Pause2\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": false,\n      \"icon\": \"/assets/icons/airfryer-mode.svg\"\n    },\n    \"airfryer_careli_target_temperature\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Target Temperature\",\n        \"nl\": \"Target Temperature\",\n        \"da\": \"Måltemperatur\",\n        \"de\": \"Zieltemperatur\",\n        \"es\": \"Temperatura Objetivo\",\n        \"fr\": \"Température Cible\",\n        \"it\": \"Temperatura Obiettivo\",\n        \"no\": \"Måltemperatur\",\n        \"sv\": \"Måltemperatur\",\n        \"pl\": \"Temperatura Docelowa\",\n        \"ru\": \"Целевая Температура\",\n        \"ko\": \"목표 온도\"\n      },\n      \"icon\": \"/assets/icons/target_temperature.svg\",\n      \"getable\": true,\n      \"setable\": true,\n      \"units\": {\n        \"en\": \"°C\",\n        \"nl\": \"°C\",\n        \"da\": \"°C\",\n        \"de\": \"°C\",\n        \"es\": \"°C\",\n        \"fr\": \"°C\",\n        \"it\": \"°C\",\n        \"no\": \"°C\",\n        \"sv\": \"°C\",\n        \"pl\": \"°C\",\n        \"ru\": \"°C\",\n        \"ko\": \"°C\"\n      },\n      \"min\": 40,\n      \"max\": 200,\n      \"decimals\": 0,\n      \"insights\": false\n    },\n    \"airfryer_careli_target_time\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Target time\",\n        \"nl\": \"Target time\",\n        \"da\": \"Måletid\",\n        \"de\": \"Zielzeit\",\n        \"es\": \"Tiempo objetivo\",\n        \"fr\": \"Temps cible\",\n        \"it\": \"Tempo target\",\n        \"no\": \"Måletid\",\n        \"sv\": \"Måltid\",\n        \"pl\": \"Czas docelowy\",\n        \"ru\": \"Целевое время\",\n        \"ko\": \"목표 시간\"\n      },\n      \"icon\": \"/assets/icons/target_time.svg\",\n      \"getable\": true,\n      \"setable\": true,\n      \"units\": {\n        \"en\": \"minutes\",\n        \"nl\": \"minuten\",\n        \"da\": \"minutter\",\n        \"de\": \"Minuten\",\n        \"es\": \"minutos\",\n        \"fr\": \"minutes\",\n        \"it\": \"minuti\",\n        \"no\": \"minutter\",\n        \"sv\": \"minuter\",\n        \"pl\": \"minuty\",\n        \"ru\": \"минуты\",\n        \"ko\": \"분\"\n      },\n      \"min\": 0,\n      \"max\": 1440,\n      \"decimals\": 0,\n      \"insights\": false\n    },\n    \"airpurifier_heater_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Air Purifier Heating Mode\",\n        \"nl\": \"Air Purifier verwarming modus\",\n        \"da\": \"Luftrenser opvarmningsfunktion\",\n        \"de\": \"Luftreiniger-Heizmodus\",\n        \"es\": \"Modo de calefacción del purificador de aire\",\n        \"fr\": \"Mode chauffage purificateur d'air\",\n        \"it\": \"Modalità riscaldamento purificatore d'aria\",\n        \"no\": \"Luftrenser oppvarmningsmodus\",\n        \"sv\": \"Luftrenare värmeläge\",\n        \"pl\": \"Tryb ogrzewania oczyszczacza powietrza\",\n        \"ru\": \"Режим обогрева воздухоочистителя\",\n        \"ko\": \"공기 청정기 난방 모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"off\",\n          \"title\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"da\": \"Slukket\",\n            \"de\": \"Aus\",\n            \"es\": \"Apagado\",\n            \"fr\": \"Éteint\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wył.\",\n            \"ru\": \"Выкл.\",\n            \"ko\": \"끄기\"\n          }\n        },\n        {\n          \"id\": \"low\",\n          \"title\": {\n            \"en\": \"Low\",\n            \"nl\": \"Laag\",\n            \"da\": \"Lav\",\n            \"de\": \"Niedrig\",\n            \"es\": \"Bajo\",\n            \"fr\": \"Faible\",\n            \"it\": \"Basso\",\n            \"no\": \"Lav\",\n            \"sv\": \"Låg\",\n            \"pl\": \"Niski\",\n            \"ru\": \"Низкий\",\n            \"ko\": \"낮음\"\n          }\n        },\n        {\n          \"id\": \"medium\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Medium\",\n            \"da\": \"Mellem\",\n            \"de\": \"Mittel\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Middels\",\n            \"sv\": \"Mellan\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"high\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Élevé\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높음\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/heater-mode.svg\"\n    },\n    \"airpurifier_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"getable\": true,\n      \"setable\": true,\n      \"values\": [\n        {\n          \"id\": \"auto\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"da\": \"Auto\",\n            \"de\": \"Auto\",\n            \"es\": \"Automático\",\n            \"fr\": \"Auto\",\n            \"it\": \"Automatico\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"silent\",\n          \"title\": {\n            \"en\": \"Silent\",\n            \"nl\": \"Stil\",\n            \"da\": \"Stille\",\n            \"de\": \"Leise\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"무음\"\n          }\n        },\n        {\n          \"id\": \"favorite\",\n          \"title\": {\n            \"en\": \"Favorite\",\n            \"nl\": \"Favoriet\",\n            \"da\": \"Favorit\",\n            \"de\": \"Favorit\",\n            \"es\": \"Favorito\",\n            \"fr\": \"Favori\",\n            \"it\": \"Preferito\",\n            \"no\": \"Favoritt\",\n            \"sv\": \"Favorit\",\n            \"pl\": \"Ulubiony\",\n            \"ru\": \"Любимый\",\n            \"ko\": \"즐겨찾기\"\n          }\n        },\n        {\n          \"id\": \"idle\",\n          \"title\": {\n            \"en\": \"Idle\",\n            \"nl\": \"Standby\",\n            \"da\": \"Inaktiv\",\n            \"de\": \"Leerlauf\",\n            \"es\": \"Inactivo\",\n            \"fr\": \"Inactif\",\n            \"it\": \"Inattivo\",\n            \"no\": \"Inaktiv\",\n            \"sv\": \"Inaktiv\",\n            \"pl\": \"Bezczynność\",\n            \"ru\": \"Ожидание\",\n            \"ko\": \"유휴\"\n          }\n        },\n        {\n          \"id\": \"low\",\n          \"title\": {\n            \"en\": \"Low\",\n            \"nl\": \"Laag\",\n            \"da\": \"Lav\",\n            \"de\": \"Niedrig\",\n            \"es\": \"Bajo\",\n            \"fr\": \"Bas\",\n            \"it\": \"Basso\",\n            \"no\": \"Lav\",\n            \"sv\": \"Låg\",\n            \"pl\": \"Niski\",\n            \"ru\": \"Низкий\",\n            \"ko\": \"낮은\"\n          }\n        },\n        {\n          \"id\": \"medium\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Medium\",\n            \"da\": \"Medium\",\n            \"de\": \"Mittel\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Middels\",\n            \"sv\": \"Medium\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"high\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Haut\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높은\"\n          }\n        },\n        {\n          \"id\": \"strong\",\n          \"title\": {\n            \"en\": \"Strong\",\n            \"nl\": \"Sterk\",\n            \"da\": \"Stærk\",\n            \"de\": \"Stark\",\n            \"es\": \"Fuerte\",\n            \"fr\": \"Fort\",\n            \"it\": \"Forte\",\n            \"no\": \"Sterk\",\n            \"sv\": \"Stark\",\n            \"pl\": \"Silny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강한\"\n          }\n        }\n      ],\n      \"icon\": \"/assets/icons/airpurifier-mode.svg\"\n    },\n    \"airpurifier_xiaomi_fanlevel\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Fan Level\",\n        \"nl\": \"Fan Level\",\n        \"da\": \"Ventilatorniveau\",\n        \"de\": \"Lüfterstufe\",\n        \"es\": \"Nivel del ventilador\",\n        \"fr\": \"Niveau du ventilateur\",\n        \"it\": \"Livello della ventola\",\n        \"no\": \"Viftenivå\",\n        \"sv\": \"Fläktnivå\",\n        \"pl\": \"Poziom wentylatora\",\n        \"ru\": \"Уровень вентилятора\",\n        \"ko\": \"팬 레벨\"\n      },\n      \"getable\": true,\n      \"setable\": true,\n      \"min\": 0,\n      \"max\": 14,\n      \"step\": 1,\n      \"icon\": \"/assets/icons/fanlevel.svg\"\n    },\n    \"airpurifier_zhimi_airfresh_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Air Fresh Mode\",\n        \"nl\": \"Air Fresh Mode\",\n        \"da\": \"Luftfriskningstilstand\",\n        \"de\": \"Luftfrisch-Modus\",\n        \"es\": \"Modo Aire Fresco\",\n        \"fr\": \"Mode Air Fresh\",\n        \"it\": \"Modalità Aria Fresca\",\n        \"no\": \"Luftfriskmodus\",\n        \"sv\": \"Luftfräschläget\",\n        \"pl\": \"Tryb Odświeżania Powietrza\",\n        \"ru\": \"Режим Очистки Воздуха\",\n        \"ko\": \"에어 프레시 모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"auto\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"da\": \"Auto\",\n            \"de\": \"Automatisch\",\n            \"es\": \"Automático\",\n            \"fr\": \"Auto\",\n            \"it\": \"Auto\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"silent\",\n          \"title\": {\n            \"en\": \"Silent\",\n            \"nl\": \"Stil\",\n            \"da\": \"Stille\",\n            \"de\": \"Leise\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"무음\"\n          }\n        },\n        {\n          \"id\": \"interval\",\n          \"title\": {\n            \"en\": \"Interval\",\n            \"nl\": \"Interval\",\n            \"da\": \"Interval\",\n            \"de\": \"Intervall\",\n            \"es\": \"Intervalo\",\n            \"fr\": \"Intervalle\",\n            \"it\": \"Intervallo\",\n            \"no\": \"Intervall\",\n            \"sv\": \"Intervall\",\n            \"pl\": \"Interwał\",\n            \"ru\": \"Интервал\",\n            \"ko\": \"간격\"\n          }\n        },\n        {\n          \"id\": \"low\",\n          \"title\": {\n            \"en\": \"Low\",\n            \"nl\": \"Laag\",\n            \"da\": \"Lav\",\n            \"de\": \"Niedrig\",\n            \"es\": \"Bajo\",\n            \"fr\": \"Bas\",\n            \"it\": \"Basso\",\n            \"no\": \"Lav\",\n            \"sv\": \"Låg\",\n            \"pl\": \"Niski\",\n            \"ru\": \"Низкий\",\n            \"ko\": \"낮음\"\n          }\n        },\n        {\n          \"id\": \"middle\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Medium\",\n            \"da\": \"Mellem\",\n            \"de\": \"Mittel\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Middels\",\n            \"sv\": \"Medium\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"strong\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Haut\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높음\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/airpurifier-mode.svg\"\n    },\n    \"airpurifier_zhimi_airpurifier_mb3_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"de\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\",\n        \"pt\": \"Modo\",\n        \"ja\": \"モード\",\n        \"zh\": \"模式\"\n      },\n      \"getable\": true,\n      \"setable\": true,\n      \"values\": [\n        {\n          \"id\": \"auto\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"de\": \"Auto\",\n            \"da\": \"Auto\",\n            \"es\": \"Auto\",\n            \"fr\": \"Auto\",\n            \"it\": \"Auto\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\",\n            \"pt\": \"Automático\",\n            \"ja\": \"オート\",\n            \"zh\": \"自动\"\n          }\n        },\n        {\n          \"id\": \"night\",\n          \"title\": {\n            \"en\": \"Night\",\n            \"nl\": \"Nacht\",\n            \"de\": \"Nacht\",\n            \"da\": \"Nat\",\n            \"es\": \"Noche\",\n            \"fr\": \"Nuit\",\n            \"it\": \"Notte\",\n            \"no\": \"Natt\",\n            \"sv\": \"Natt\",\n            \"pl\": \"Noc\",\n            \"ru\": \"Ночь\",\n            \"ko\": \"밤\",\n            \"pt\": \"Noite\",\n            \"ja\": \"夜\",\n            \"zh\": \"夜晚\"\n          }\n        },\n        {\n          \"id\": \"favorite\",\n          \"title\": {\n            \"en\": \"Favorite\",\n            \"nl\": \"Favoriet\",\n            \"de\": \"Favorit\",\n            \"da\": \"Favorit\",\n            \"es\": \"Favorito\",\n            \"fr\": \"Préféré\",\n            \"it\": \"Preferito\",\n            \"no\": \"Favoritt\",\n            \"sv\": \"Favorit\",\n            \"pl\": \"Ulubiony\",\n            \"ru\": \"Избранное\",\n            \"ko\": \"즐겨찾기\",\n            \"pt\": \"Favorito\",\n            \"ja\": \"お気に入り\",\n            \"zh\": \"最爱\"\n          }\n        },\n        {\n          \"id\": \"idle\",\n          \"title\": {\n            \"en\": \"Idle\",\n            \"nl\": \"Inactief\",\n            \"de\": \"Inaktiv\",\n            \"da\": \"Inaktiv\",\n            \"es\": \"Inactivo\",\n            \"fr\": \"Inactif\",\n            \"it\": \"Inattivo\",\n            \"no\": \"Inaktiv\",\n            \"sv\": \"Inaktiv\",\n            \"pl\": \"Bezczynny\",\n            \"ru\": \"Бездействие\",\n            \"ko\": \"대기 중\",\n            \"pt\": \"Inativo\",\n            \"ja\": \"アイドル\",\n            \"zh\": \"闲置\"\n          }\n        }\n      ],\n      \"icon\": \"/assets/icons/airpurifier-mode.svg\"\n    },\n    \"airpurifier_zhimi_fanlevel\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Fan Level\",\n        \"nl\": \"Fan Level\",\n        \"da\": \"Ventilatorniveau\",\n        \"de\": \"Lüfterstufe\",\n        \"es\": \"Nivel del ventilador\",\n        \"fr\": \"Niveau du ventilateur\",\n        \"it\": \"Livello della ventola\",\n        \"no\": \"Viftenivå\",\n        \"sv\": \"Fläktnivå\",\n        \"pl\": \"Poziom wentylatora\",\n        \"ru\": \"Уровень вентилятора\",\n        \"ko\": \"팬 레벨\"\n      },\n      \"getable\": true,\n      \"setable\": true,\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Level 1\",\n            \"nl\": \"Level 1\",\n            \"da\": \"Niveau 1\",\n            \"de\": \"Stufe 1\",\n            \"es\": \"Nivel 1\",\n            \"fr\": \"Niveau 1\",\n            \"it\": \"Livello 1\",\n            \"no\": \"Nivå 1\",\n            \"sv\": \"Nivå 1\",\n            \"pl\": \"Poziom 1\",\n            \"ru\": \"Уровень 1\",\n            \"ko\": \"레벨 1\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Level 2\",\n            \"nl\": \"Level 2\",\n            \"da\": \"Niveau 2\",\n            \"de\": \"Stufe 2\",\n            \"es\": \"Nivel 2\",\n            \"fr\": \"Niveau 2\",\n            \"it\": \"Livello 2\",\n            \"no\": \"Nivå 2\",\n            \"sv\": \"Nivå 2\",\n            \"pl\": \"Poziom 2\",\n            \"ru\": \"Уровень 2\",\n            \"ko\": \"레벨 2\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Level 3\",\n            \"nl\": \"Level 3\",\n            \"da\": \"Niveau 3\",\n            \"de\": \"Stufe 3\",\n            \"es\": \"Nivel 3\",\n            \"fr\": \"Niveau 3\",\n            \"it\": \"Livello 3\",\n            \"no\": \"Nivå 3\",\n            \"sv\": \"Nivå 3\",\n            \"pl\": \"Poziom 3\",\n            \"ru\": \"Уровень 3\",\n            \"ko\": \"레벨 3\"\n          }\n        }\n      ],\n      \"icon\": \"/assets/icons/fanlevel.svg\"\n    },\n    \"airpurifier_zhimi_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"getable\": true,\n      \"setable\": true,\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"da\": \"Auto\",\n            \"de\": \"Auto\",\n            \"es\": \"Auto\",\n            \"fr\": \"Auto\",\n            \"it\": \"Auto\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Night\",\n            \"nl\": \"Nacht\",\n            \"da\": \"Nat\",\n            \"de\": \"Nacht\",\n            \"es\": \"Noche\",\n            \"fr\": \"Nuit\",\n            \"it\": \"Notte\",\n            \"no\": \"Natt\",\n            \"sv\": \"Natt\",\n            \"pl\": \"Noc\",\n            \"ru\": \"Ночь\",\n            \"ko\": \"야간\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Favorite\",\n            \"nl\": \"Favoriet\",\n            \"da\": \"Favorit\",\n            \"de\": \"Favorit\",\n            \"es\": \"Favorito\",\n            \"fr\": \"Favori\",\n            \"it\": \"Preferito\",\n            \"no\": \"Favoritt\",\n            \"sv\": \"Favorit\",\n            \"pl\": \"Ulubiony\",\n            \"ru\": \"Избранное\",\n            \"ko\": \"선호\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Idle\",\n            \"nl\": \"Inactief\",\n            \"da\": \"Inaktiv\",\n            \"de\": \"Inaktiv\",\n            \"es\": \"Inactivo\",\n            \"fr\": \"Inactif\",\n            \"it\": \"Inattivo\",\n            \"no\": \"Inaktiv\",\n            \"sv\": \"Inaktiv\",\n            \"pl\": \"Bezczynny\",\n            \"ru\": \"Бездействие\",\n            \"ko\": \"대기\"\n          }\n        }\n      ],\n      \"icon\": \"/assets/icons/airpurifier-mode.svg\"\n    },\n    \"alarm_desiccant_low\": {\n      \"type\": \"boolean\",\n      \"title\": {\n        \"en\": \"Desiccant Low\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"uiComponent\": \"sensor\"\n    },\n    \"alarm_filter_work_time\": {\n      \"title\": {\n        \"en\": \"Filter Alert\",\n        \"nl\": \"Filter waarschuwing\",\n        \"da\": \"Filteralarm\",\n        \"de\": \"Filteralarm\",\n        \"es\": \"Alerta de Filtro\",\n        \"fr\": \"Alerte Filtre\",\n        \"it\": \"Allarme Filtro\",\n        \"no\": \"Filtervarsling\",\n        \"sv\": \"Filtervarning\",\n        \"pl\": \"Alarm filtra\",\n        \"ru\": \"Сигнал фильтра\",\n        \"ko\": \"필터 알림\"\n      },\n      \"type\": \"boolean\",\n      \"getable\": true,\n      \"setable\": false,\n      \"icon\": \"/assets/icons/vacuum_hepa_filter.svg\"\n    },\n    \"alarm_main_brush_work_time\": {\n      \"title\": {\n        \"en\": \"Main Brush Alert\",\n        \"nl\": \"Hoofdborstel waarschuwing\",\n        \"da\": \"Hovedbørstealarm\",\n        \"de\": \"Hauptbürstenalarm\",\n        \"es\": \"Alerta de cepillo principal\",\n        \"fr\": \"Alerte brosse principale\",\n        \"it\": \"Allarme spazzola principale\",\n        \"no\": \"Hovedbørstevarsel\",\n        \"sv\": \"Huvudborstevarning\",\n        \"pl\": \"Alarm głównej szczotki\",\n        \"ru\": \"Предупреждение о главной щетке\",\n        \"ko\": \"메인 브러쉬 경고\"\n      },\n      \"type\": \"boolean\",\n      \"getable\": true,\n      \"setable\": false,\n      \"icon\": \"/assets/icons/vacuum_main_brush.svg\"\n    },\n    \"alarm_sensor_dirty_time\": {\n      \"title\": {\n        \"en\": \"Sensor Alert\",\n        \"nl\": \"Sensor waarschuwing\",\n        \"da\": \"Sensoralarm\",\n        \"de\": \"Sensoralarm\",\n        \"es\": \"Alerta de sensor\",\n        \"fr\": \"Alerte de capteur\",\n        \"it\": \"Allarme sensore\",\n        \"no\": \"Sensorvarsel\",\n        \"sv\": \"Sensorlarm\",\n        \"pl\": \"Alarm czujnika\",\n        \"ru\": \"Оповещение датчика\",\n        \"ko\": \"센서 경고\"\n      },\n      \"type\": \"boolean\",\n      \"getable\": true,\n      \"setable\": false,\n      \"icon\": \"/assets/icons/vacuum_sensor_dirty.svg\"\n    },\n    \"alarm_side_brush_work_time\": {\n      \"title\": {\n        \"en\": \"Side Brush Alert\",\n        \"nl\": \"Zijborstel waarschuwing\",\n        \"da\": \"Sidebørste Advarsel\",\n        \"de\": \"Seitenbürstenalarm\",\n        \"es\": \"Alerta de Cepillo Lateral\",\n        \"fr\": \"Alerte de Brosse Latérale\",\n        \"it\": \"Allarme Spazzola Laterale\",\n        \"no\": \"Sidebørste Varsel\",\n        \"sv\": \"Sidoborste Varning\",\n        \"pl\": \"Ostrzeżenie o Szczotce Boczne\",\n        \"ru\": \"Предупреждение о Боковой Щетке\",\n        \"ko\": \"옆 브러시 알림\"\n      },\n      \"type\": \"boolean\",\n      \"getable\": true,\n      \"setable\": false,\n      \"icon\": \"/assets/icons/vacuum_side_brush.svg\"\n    },\n    \"alarm_water_shortage\": {\n      \"type\": \"boolean\",\n      \"title\": {\n        \"en\": \"Water Shortage Alarm\",\n        \"nl\": \"Watertekort Alarm\",\n        \"da\": \"Vandmangel Alarm\",\n        \"de\": \"Wassermangel Alarm\",\n        \"es\": \"Alarma de falta de agua\",\n        \"fr\": \"Alarme manque d'eau\",\n        \"it\": \"Allarme carenza acqua\",\n        \"no\": \"Vannmangel Alarm\",\n        \"sv\": \"Vattenbristlarm\",\n        \"pl\": \"Alarm braku wody\",\n        \"ru\": \"Сигнализация нехватки воды\",\n        \"ko\": \"물 부족 알림\"\n      },\n      \"desc\": {\n        \"en\": \"Indicates when there is a water shortage\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"icon\": \"/assets/icons/water-shortage.svg\"\n    },\n    \"dehumidifier_dmaker_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Smart\",\n            \"nl\": \"Slim\",\n            \"da\": \"Smart\",\n            \"de\": \"Intelligent\",\n            \"es\": \"Inteligente\",\n            \"fr\": \"Intelligent\",\n            \"it\": \"Intelligente\",\n            \"no\": \"Smart\",\n            \"sv\": \"Smart\",\n            \"pl\": \"Inteligentny\",\n            \"ru\": \"Умный\",\n            \"ko\": \"스마트\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Sleep\",\n            \"nl\": \"Slaap\",\n            \"da\": \"Søvn\",\n            \"de\": \"Schlaf\",\n            \"es\": \"Dormir\",\n            \"fr\": \"Sommeil\",\n            \"it\": \"Sonno\",\n            \"no\": \"Søvn\",\n            \"sv\": \"Sömn\",\n            \"pl\": \"Sen\",\n            \"ru\": \"Сон\",\n            \"ko\": \"수면\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Clothes Drying\",\n            \"nl\": \"Kleding drogen\",\n            \"da\": \"Tørring af tøj\",\n            \"de\": \"Kleidung trocknen\",\n            \"es\": \"Secado de ropa\",\n            \"fr\": \"Séchage des vêtements\",\n            \"it\": \"Asciugatura dei vestiti\",\n            \"no\": \"Klær tørking\",\n            \"sv\": \"Klädtorkning\",\n            \"pl\": \"Suszenie ubrań\",\n            \"ru\": \"Сушка одежды\",\n            \"ko\": \"의류 건조\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/humidifier-mode.svg\"\n    },\n    \"diffuser_xwhzp_fragrance_out_time\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Fragrance Out Time\",\n        \"nl\": \"Geurafgifte tijd\",\n        \"da\": \"Duftudslipstid\",\n        \"de\": \"Duftabgabezeit\",\n        \"es\": \"Tiempo de salida de fragancia\",\n        \"fr\": \"Duree de diffusion\",\n        \"it\": \"Durata erogazione fragranza\",\n        \"no\": \"Duftutslippstid\",\n        \"sv\": \"Doftutslappstid\",\n        \"pl\": \"Czas emisji zapachu\",\n        \"ru\": \"Vremya vydeleniya aromata\",\n        \"ko\": \"fragrance out time\"\n      },\n      \"icon\": \"/assets/icons/target_time.svg\",\n      \"getable\": true,\n      \"setable\": true,\n      \"uiComponent\": \"slider\",\n      \"units\": {\n        \"en\": \"s\",\n        \"nl\": \"s\",\n        \"da\": \"s\",\n        \"de\": \"s\",\n        \"es\": \"s\",\n        \"fr\": \"s\",\n        \"it\": \"s\",\n        \"no\": \"s\",\n        \"sv\": \"s\",\n        \"pl\": \"s\",\n        \"ru\": \"s\",\n        \"ko\": \"s\"\n      },\n      \"insights\": true\n    },\n    \"diffuser_xwhzp_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalita\",\n        \"no\": \"Modus\",\n        \"sv\": \"Lage\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Rezhim\",\n        \"ko\": \"mode\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Sleep\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Reading\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Exercise\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Wakeup\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Custom Mode 1\"\n          }\n        },\n        {\n          \"id\": \"5\",\n          \"title\": {\n            \"en\": \"Custom Mode 2\"\n          }\n        },\n        {\n          \"id\": \"6\",\n          \"title\": {\n            \"en\": \"Custom Mode 3\"\n          }\n        },\n        {\n          \"id\": \"7\",\n          \"title\": {\n            \"en\": \"Custom Mode 4\"\n          }\n        },\n        {\n          \"id\": \"8\",\n          \"title\": {\n            \"en\": \"Try It\"\n          }\n        },\n        {\n          \"id\": \"9\",\n          \"title\": {\n            \"en\": \"Idle Mode\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/humidifier-mode.svg\"\n    },\n    \"fan_dmaker_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\",\n        \"ja\": \"モード\",\n        \"zh\": \"模式\",\n        \"pt\": \"Modo\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Straight Wind\",\n            \"nl\": \"Rechte wind\",\n            \"da\": \"Lige vind\",\n            \"de\": \"Gerader Wind\",\n            \"es\": \"Viento Recto\",\n            \"fr\": \"Vent Droit\",\n            \"it\": \"Vento Diretto\",\n            \"no\": \"Rett vind\",\n            \"sv\": \"Rak vind\",\n            \"pl\": \"Prosty wiatr\",\n            \"ru\": \"Прямой ветер\",\n            \"ko\": \"직진 바람\",\n            \"ja\": \"真っ直ぐな風\",\n            \"zh\": \"直风\",\n            \"pt\": \"Vento Reto\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Natural Wind\",\n            \"nl\": \"Natuurlijke Wind\",\n            \"da\": \"Naturlig vind\",\n            \"de\": \"Natürlicher Wind\",\n            \"es\": \"Viento Natural\",\n            \"fr\": \"Vent Naturel\",\n            \"it\": \"Vento Naturale\",\n            \"no\": \"Naturlig vind\",\n            \"sv\": \"Naturlig vind\",\n            \"pl\": \"Naturalny wiatr\",\n            \"ru\": \"Естественный ветер\",\n            \"ko\": \"자연 바람\",\n            \"ja\": \"自然な風\",\n            \"zh\": \"自然风\",\n            \"pt\": \"Vento Natural\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Sleep\",\n            \"nl\": \"Slaap\",\n            \"da\": \"Søvn\",\n            \"de\": \"Schlaf\",\n            \"es\": \"Dormir\",\n            \"fr\": \"Sommeil\",\n            \"it\": \"Sonno\",\n            \"no\": \"Søvn\",\n            \"sv\": \"Sömn\",\n            \"pl\": \"Sen\",\n            \"ru\": \"Сон\",\n            \"ko\": \"수면\",\n            \"ja\": \"睡眠\",\n            \"zh\": \"睡觉\",\n            \"pt\": \"Sono\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Cold Air\",\n            \"nl\": \"Koude Lucht\",\n            \"da\": \"Kold Luft\",\n            \"de\": \"Kalte Luft\",\n            \"es\": \"Aire Frío\",\n            \"fr\": \"Air Froid\",\n            \"it\": \"Aria Fredda\",\n            \"no\": \"Kald Luft\",\n            \"sv\": \"Kall Luft\",\n            \"pl\": \"Zimne Powietrze\",\n            \"ru\": \"Холодный воздух\",\n            \"ko\": \"찬 공기\",\n            \"ja\": \"冷たい空気\",\n            \"zh\": \"冷空气\",\n            \"pt\": \"Ar Frio\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/fanlevel.svg\"\n    },\n    \"fan_zhimi_angle\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Swing Angle\",\n        \"nl\": \"Draaihoek\",\n        \"da\": \"Svingvinkel\",\n        \"de\": \"Schwenkwinkel\",\n        \"es\": \"Ángulo de giro\",\n        \"fr\": \"Angle de balancement\",\n        \"it\": \"Angolo di oscillazione\",\n        \"no\": \"Svingvinkel\",\n        \"sv\": \"Svängvinkel\",\n        \"pl\": \"Kąt huśtania\",\n        \"ru\": \"Угол поворота\",\n        \"ko\": \"스윙 각도\"\n      },\n      \"values\": [\n        {\n          \"id\": \"30\",\n          \"title\": {\n            \"en\": \"30°\",\n            \"nl\": \"30°\",\n            \"da\": \"30°\",\n            \"de\": \"30°\",\n            \"es\": \"30°\",\n            \"fr\": \"30°\",\n            \"it\": \"30°\",\n            \"no\": \"30°\",\n            \"sv\": \"30°\",\n            \"pl\": \"30°\",\n            \"ru\": \"30°\",\n            \"ko\": \"30°\"\n          }\n        },\n        {\n          \"id\": \"60\",\n          \"title\": {\n            \"en\": \"60°\",\n            \"nl\": \"60°\",\n            \"da\": \"60°\",\n            \"de\": \"60°\",\n            \"es\": \"60°\",\n            \"fr\": \"60°\",\n            \"it\": \"60°\",\n            \"no\": \"60°\",\n            \"sv\": \"60°\",\n            \"pl\": \"60°\",\n            \"ru\": \"60°\",\n            \"ko\": \"60°\"\n          }\n        },\n        {\n          \"id\": \"90\",\n          \"title\": {\n            \"en\": \"90°\",\n            \"nl\": \"90°\",\n            \"da\": \"90°\",\n            \"de\": \"90°\",\n            \"es\": \"90°\",\n            \"fr\": \"90°\",\n            \"it\": \"90°\",\n            \"no\": \"90°\",\n            \"sv\": \"90°\",\n            \"pl\": \"90°\",\n            \"ru\": \"90°\",\n            \"ko\": \"90°\"\n          }\n        },\n        {\n          \"id\": \"120\",\n          \"title\": {\n            \"en\": \"120°\",\n            \"nl\": \"120°\",\n            \"da\": \"120°\",\n            \"de\": \"120°\",\n            \"es\": \"120°\",\n            \"fr\": \"120°\",\n            \"it\": \"120°\",\n            \"no\": \"120°\",\n            \"sv\": \"120°\",\n            \"pl\": \"120°\",\n            \"ru\": \"120°\",\n            \"ko\": \"120°\"\n          }\n        },\n        {\n          \"id\": \"140\",\n          \"title\": {\n            \"en\": \"140°\",\n            \"nl\": \"140°\",\n            \"da\": \"140°\",\n            \"de\": \"140°\",\n            \"es\": \"140°\",\n            \"fr\": \"140°\",\n            \"it\": \"140°\",\n            \"no\": \"140°\",\n            \"sv\": \"140°\",\n            \"pl\": \"140°\",\n            \"ru\": \"140°\",\n            \"ko\": \"140°\"\n          }\n        },\n        {\n          \"id\": \"150\",\n          \"title\": {\n            \"en\": \"150°\",\n            \"nl\": \"150°\",\n            \"da\": \"150°\",\n            \"de\": \"150°\",\n            \"es\": \"150°\",\n            \"fr\": \"150°\",\n            \"it\": \"150°\",\n            \"no\": \"150°\",\n            \"sv\": \"150°\",\n            \"pl\": \"150°\",\n            \"ru\": \"150°\",\n            \"ko\": \"150°\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/oscillation.svg\"\n    },\n    \"fan_zhimi_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Natural Wind\",\n            \"nl\": \"Natuur wind\",\n            \"da\": \"Naturlig vind\",\n            \"de\": \"Natürlicher Wind\",\n            \"es\": \"Viento Natural\",\n            \"fr\": \"Vent Naturel\",\n            \"it\": \"Vento Naturale\",\n            \"no\": \"Naturlig Vind\",\n            \"sv\": \"Naturlig Vind\",\n            \"pl\": \"Naturalny Wiatr\",\n            \"ru\": \"Естественный ветер\",\n            \"ko\": \"자연풍\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Straight Wind\",\n            \"nl\": \"Rechte wind\",\n            \"da\": \"Lige Vind\",\n            \"de\": \"Gerader Wind\",\n            \"es\": \"Viento Recto\",\n            \"fr\": \"Vent Direct\",\n            \"it\": \"Vento Diretto\",\n            \"no\": \"Rett Vind\",\n            \"sv\": \"Rakt Vind\",\n            \"pl\": \"Prosty Wiatr\",\n            \"ru\": \"Прямой ветер\",\n            \"ko\": \"직풍\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/fanlevel.svg\"\n    },\n    \"heater_zhimi_heater_target_temperature\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Target Temperature\",\n        \"nl\": \"Target Temperature\",\n        \"da\": \"Mål Temperatur\",\n        \"de\": \"Zieltemperatur\",\n        \"es\": \"Temperatura objetivo\",\n        \"fr\": \"Température cible\",\n        \"it\": \"Temperatura target\",\n        \"no\": \"Måltemperatur\",\n        \"sv\": \"Måltemperatur\",\n        \"pl\": \"Temperatura docelowa\",\n        \"ru\": \"Целевая температура\",\n        \"ko\": \"목표 온도\"\n      },\n      \"icon\": \"/assets/icons/target_temperature.svg\",\n      \"getable\": true,\n      \"setable\": true,\n      \"units\": {\n        \"en\": \"°C\",\n        \"nl\": \"°C\",\n        \"da\": \"°C\",\n        \"de\": \"°C\",\n        \"es\": \"°C\",\n        \"fr\": \"°C\",\n        \"it\": \"°C\",\n        \"no\": \"°C\",\n        \"sv\": \"°C\",\n        \"pl\": \"°C\",\n        \"ru\": \"°C\",\n        \"ko\": \"°C\"\n      },\n      \"uiComponent\": \"thermostat\",\n      \"min\": 16,\n      \"max\": 30,\n      \"step\": 1,\n      \"decimals\": 0,\n      \"insights\": false\n    },\n    \"heater_zhimi_heatlevel\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Heatlevel\",\n        \"nl\": \"Hitte stand\",\n        \"da\": \"Varmeniveau\",\n        \"de\": \"Heizstufe\",\n        \"es\": \"Nivel de calor\",\n        \"fr\": \"Niveau de chaleur\",\n        \"it\": \"Livello di calore\",\n        \"no\": \"Varmenivå\",\n        \"sv\": \"Värmenivå\",\n        \"pl\": \"Poziom ciepła\",\n        \"ru\": \"Уровень тепла\",\n        \"ko\": \"난방 레벨\"\n      },\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Élevé\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высоко\",\n            \"ko\": \"높음\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Low\",\n            \"nl\": \"Laag\",\n            \"da\": \"Lav\",\n            \"de\": \"Niedrig\",\n            \"es\": \"Bajo\",\n            \"fr\": \"Bas\",\n            \"it\": \"Basso\",\n            \"no\": \"Lav\",\n            \"sv\": \"Låg\",\n            \"pl\": \"Niski\",\n            \"ru\": \"Низко\",\n            \"ko\": \"낮음\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/heatlevel.svg\"\n    },\n    \"heater_zhimi_oscillation\": {\n      \"type\": \"boolean\",\n      \"title\": {\n        \"en\": \"Oscillation\",\n        \"nl\": \"Oscillatie\",\n        \"da\": \"Oscillation\",\n        \"de\": \"Oszillation\",\n        \"es\": \"Oscilación\",\n        \"fr\": \"Oscillation\",\n        \"it\": \"Oscillazione\",\n        \"no\": \"Oscillasjon\",\n        \"sv\": \"Oscillation\",\n        \"pl\": \"Oscylacja\",\n        \"ru\": \"Колебание\",\n        \"ko\": \"진동\"\n      },\n      \"getable\": true,\n      \"setable\": true,\n      \"uiComponent\": \"toggle\",\n      \"insights\": false,\n      \"icon\": \"/assets/icons/oscillation.svg\"\n    },\n    \"humidifier_deerma_jsq_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\",\n        \"ja\": \"モード\",\n        \"zh\": \"模式\",\n        \"pt\": \"Modo\"\n      },\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Low\",\n            \"nl\": \"Laag\",\n            \"da\": \"Lav\",\n            \"de\": \"Niedrig\",\n            \"es\": \"Bajo\",\n            \"fr\": \"Faible\",\n            \"it\": \"Basso\",\n            \"no\": \"Lav\",\n            \"sv\": \"Låg\",\n            \"pl\": \"Niski\",\n            \"ru\": \"Низкий\",\n            \"ko\": \"낮은\",\n            \"ja\": \"低い\",\n            \"zh\": \"低\",\n            \"pt\": \"Baixo\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Medium\",\n            \"da\": \"Mellem\",\n            \"de\": \"Mittel\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Middels\",\n            \"sv\": \"Medel\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\",\n            \"ja\": \"中\",\n            \"zh\": \"中\",\n            \"pt\": \"Médio\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Élevé\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높은\",\n            \"ja\": \"高い\",\n            \"zh\": \"高\",\n            \"pt\": \"Alto\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Humidity\",\n            \"nl\": \"Luchtvochtigheid\",\n            \"da\": \"Fugtighed\",\n            \"de\": \"Feuchtigkeit\",\n            \"es\": \"Humedad\",\n            \"fr\": \"Humidité\",\n            \"it\": \"Umidità\",\n            \"no\": \"Fuktighet\",\n            \"sv\": \"Fuktighet\",\n            \"pl\": \"Wilgotność\",\n            \"ru\": \"Влажность\",\n            \"ko\": \"습도\",\n            \"ja\": \"湿度\",\n            \"zh\": \"湿度\",\n            \"pt\": \"Umidade\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/humidifier-mode.svg\"\n    },\n    \"humidifier_leshow_jsq1_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Constant Humidity\",\n            \"nl\": \"Constante luchtvochtigheid\",\n            \"da\": \"Konstant fugtighed\",\n            \"de\": \"Konstante Luftfeuchtigkeit\",\n            \"es\": \"Humedad constante\",\n            \"fr\": \"Humidité constante\",\n            \"it\": \"Umidità costante\",\n            \"no\": \"Konstant fuktighet\",\n            \"sv\": \"Konstant fuktighet\",\n            \"pl\": \"Stała wilgotność\",\n            \"ru\": \"Постоянная влажность\",\n            \"ko\": \"일정 습도\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Élevé\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높음\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Sleep\",\n            \"n;\": \"Slaapstand\",\n            \"da\": \"Søvn\",\n            \"de\": \"Schlafmodus\",\n            \"es\": \"Sueño\",\n            \"fr\": \"Veille\",\n            \"it\": \"Sonno\",\n            \"no\": \"Søvn\",\n            \"sv\": \"Sömn\",\n            \"pl\": \"Sen\",\n            \"ru\": \"Сон\",\n            \"ko\": \"수면\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/humidifier-mode.svg\"\n    },\n    \"humidifier_water_level_state\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Water level state\"\n      },\n      \"desc\": {\n        \"en\": \"Indicates the current water level state in the tank\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"values\": [\n        {\n          \"id\": \"empty\",\n          \"title\": {\n            \"en\": \"Empty\"\n          }\n        },\n        {\n          \"id\": \"normal\",\n          \"title\": {\n            \"en\": \"Normal\"\n          }\n        },\n        {\n          \"id\": \"full\",\n          \"title\": {\n            \"en\": \"Full\"\n          }\n        }\n      ],\n      \"icon\": \"/assets/icons/water-level.svg\"\n    },\n    \"humidifier_xiaomi_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Mode\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Constant Humidity\",\n            \"nl\": \"Constante luchtvochtigheid\",\n            \"da\": \"Konstant fugtighed\",\n            \"de\": \"Konstante Luftfeuchtigkeit\",\n            \"es\": \"Humedad constante\",\n            \"fr\": \"Humidité constante\",\n            \"it\": \"Umidità costante\",\n            \"no\": \"Konstant fuktighet\",\n            \"sv\": \"Konstant fuktighet\",\n            \"pl\": \"Stała wilgotność\",\n            \"ru\": \"Постоянная влажность\",\n            \"ko\": \"항상 습도\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Strong\",\n            \"nl\": \"Sterk\",\n            \"da\": \"Stærk\",\n            \"de\": \"Stark\",\n            \"es\": \"Fuerte\",\n            \"fr\": \"Fort\",\n            \"it\": \"Forte\",\n            \"no\": \"Sterk\",\n            \"sv\": \"Stark\",\n            \"pl\": \"Mocny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강한\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Sleep\",\n            \"nl\": \"Slaapstand\",\n            \"da\": \"Søvn\",\n            \"de\": \"Schlaf\",\n            \"es\": \"Sueño\",\n            \"fr\": \"Sommeil\",\n            \"it\": \"Sonno\",\n            \"no\": \"Søvn\",\n            \"sv\": \"Sömn\",\n            \"pl\": \"Sen\",\n            \"ru\": \"Сон\",\n            \"ko\": \"수면\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Air-dry\",\n            \"nl\": \"Air-dry\",\n            \"da\": \"Lufttørre\",\n            \"de\": \"Lufttrocknen\",\n            \"es\": \"Secado al aire\",\n            \"fr\": \"Sécher à l'air\",\n            \"it\": \"Asciuga all'aria\",\n            \"no\": \"Lufttørk\",\n            \"sv\": \"Lufttorka\",\n            \"pl\": \"Suszenie powietrzem\",\n            \"ru\": \"Воздушная сушка\",\n            \"ko\": \"공기 건조\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Clean\",\n            \"nl\": \"Schonen\",\n            \"da\": \"Rengør\",\n            \"de\": \"Reinigen\",\n            \"es\": \"Limpiar\",\n            \"fr\": \"Nettoyer\",\n            \"it\": \"Pulito\",\n            \"no\": \"Rengjør\",\n            \"sv\": \"Rengöra\",\n            \"pl\": \"Czystość\",\n            \"ru\": \"Чистка\",\n            \"ko\": \"청소\"\n          }\n        },\n        {\n          \"id\": \"5\",\n          \"title\": {\n            \"en\": \"Descale\",\n            \"nl\": \"Descale\",\n            \"da\": \"Afkalkning\",\n            \"de\": \"Entkalken\",\n            \"es\": \"Desincrustar\",\n            \"fr\": \"Détartrage\",\n            \"it\": \"Decalcificare\",\n            \"no\": \"Avkalking\",\n            \"sv\": \"Avkalka\",\n            \"pl\": \"Odkamienianie\",\n            \"ru\": \"Удаление накипи\",\n            \"ko\": \"제거\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/humidifier-mode.svg\"\n    },\n    \"humidifier_zhimi_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"getable\": true,\n      \"setable\": true,\n      \"values\": [\n        {\n          \"id\": \"idle\",\n          \"title\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"de\": \"Aus\",\n            \"da\": \"Slukket\",\n            \"es\": \"Apagado\",\n            \"fr\": \"Éteint\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wył.\",\n            \"ru\": \"Выкл.\",\n            \"ko\": \"낌\"\n          }\n        },\n        {\n          \"id\": \"silent\",\n          \"title\": {\n            \"en\": \"Silent\",\n            \"nl\": \"Stil\",\n            \"de\": \"Leise\",\n            \"da\": \"Stille\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"조용히\"\n          }\n        },\n        {\n          \"id\": \"medium\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Middel\",\n            \"de\": \"Mittel\",\n            \"da\": \"Mellem\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Middels\",\n            \"sv\": \"Medium\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"high\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"de\": \"Hoch\",\n            \"da\": \"Høj\",\n            \"es\": \"Alto\",\n            \"fr\": \"Élevé\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높은\"\n          }\n        },\n        {\n          \"id\": \"auto\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"de\": \"Auto\",\n            \"da\": \"Auto\",\n            \"es\": \"Auto\",\n            \"fr\": \"Auto\",\n            \"it\": \"Auto\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"strong\",\n          \"title\": {\n            \"en\": \"Strong\",\n            \"nl\": \"Sterk\",\n            \"de\": \"Stark\",\n            \"da\": \"Stærk\",\n            \"es\": \"Fuerte\",\n            \"fr\": \"Fort\",\n            \"it\": \"Forte\",\n            \"no\": \"Sterk\",\n            \"sv\": \"Stark\",\n            \"pl\": \"Mocny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강한\"\n          }\n        }\n      ],\n      \"icon\": \"/assets/icons/humidifier-mode.svg\"\n    },\n    \"humidifier_zhimi_mode_miot\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"da\": \"Auto\",\n            \"de\": \"Auto\",\n            \"es\": \"Auto\",\n            \"fr\": \"Auto\",\n            \"it\": \"Auto\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Level 1\",\n            \"nl\": \"Level 1\",\n            \"da\": \"Niveau 1\",\n            \"de\": \"Stufe 1\",\n            \"es\": \"Nivel 1\",\n            \"fr\": \"Niveau 1\",\n            \"it\": \"Livello 1\",\n            \"no\": \"Nivå 1\",\n            \"sv\": \"Nivå 1\",\n            \"pl\": \"Poziom 1\",\n            \"ru\": \"Уровень 1\",\n            \"ko\": \"레벨 1\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Level 2\",\n            \"nl\": \"Level 2\",\n            \"da\": \"Niveau 2\",\n            \"de\": \"Stufe 2\",\n            \"es\": \"Nivel 2\",\n            \"fr\": \"Niveau 2\",\n            \"it\": \"Livello 2\",\n            \"no\": \"Nivå 2\",\n            \"sv\": \"Nivå 2\",\n            \"pl\": \"Poziom 2\",\n            \"ru\": \"Уровень 2\",\n            \"ko\": \"레벨 2\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Level 3\",\n            \"nl\": \"Level 3\",\n            \"da\": \"Niveau 3\",\n            \"de\": \"Stufe 3\",\n            \"es\": \"Nivel 3\",\n            \"fr\": \"Niveau 3\",\n            \"it\": \"Livello 3\",\n            \"no\": \"Nivå 3\",\n            \"sv\": \"Nivå 3\",\n            \"pl\": \"Poziom 3\",\n            \"ru\": \"Уровень 3\",\n            \"ko\": \"레벨 3\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/humidifier-mode.svg\"\n    },\n    \"humidifier2_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalità\",\n        \"no\": \"Modus\",\n        \"sv\": \"Läge\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"getable\": true,\n      \"setable\": true,\n      \"values\": [\n        {\n          \"id\": \"idle\",\n          \"title\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"de\": \"Aus\",\n            \"da\": \"Fra\",\n            \"es\": \"Apagado\",\n            \"fr\": \"Éteint\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wyłączony\",\n            \"ru\": \"Выкл\",\n            \"ko\": \"끄기\"\n          }\n        },\n        {\n          \"id\": \"silent\",\n          \"title\": {\n            \"en\": \"Silent\",\n            \"nl\": \"Stil\",\n            \"de\": \"Leise\",\n            \"da\": \"Stille\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"조용\"\n          }\n        },\n        {\n          \"id\": \"medium\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Middel\",\n            \"de\": \"Mittel\",\n            \"da\": \"Mellem\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Middels\",\n            \"sv\": \"Mellan\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"high\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"de\": \"Hoch\",\n            \"da\": \"Høj\",\n            \"es\": \"Alto\",\n            \"fr\": \"Haut\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높음\"\n          }\n        },\n        {\n          \"id\": \"auto\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"de\": \"Auto\",\n            \"da\": \"Auto\",\n            \"es\": \"Automático\",\n            \"fr\": \"Auto\",\n            \"it\": \"Automatico\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"strong\",\n          \"title\": {\n            \"en\": \"Strong\",\n            \"nl\": \"Sterk\",\n            \"de\": \"Stark\",\n            \"da\": \"Stærk\",\n            \"es\": \"Fuerte\",\n            \"fr\": \"Fort\",\n            \"it\": \"Forte\",\n            \"no\": \"Sterk\",\n            \"sv\": \"Stark\",\n            \"pl\": \"Mocny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강한\"\n          }\n        }\n      ],\n      \"icon\": \"/assets/icons/humidifier-mode.svg\"\n    },\n    \"measure_desiccant\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Desiccant Left\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"units\": {\n        \"en\": \"%\"\n      },\n      \"decimals\": 0,\n      \"min\": 0,\n      \"max\": 100,\n      \"uiComponent\": \"sensor\"\n    },\n    \"measure_desiccant_time\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Desiccant Time Left\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"units\": {\n        \"en\": \"days\"\n      },\n      \"decimals\": 0,\n      \"min\": 0,\n      \"uiComponent\": \"sensor\"\n    },\n    \"measure_filter_days_left\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Filter Days Left\",\n        \"nl\": \"Filterdagen resterend\",\n        \"da\": \"Filtrets resterende dage\",\n        \"de\": \"Verbleibende Filtertage\",\n        \"es\": \"Días restantes del filtro\",\n        \"fr\": \"Jours de filtre restants\",\n        \"it\": \"Giorni filtro rimasti\",\n        \"no\": \"Filterdager igjen\",\n        \"sv\": \"Filterdagar kvar\",\n        \"pl\": \"Pozostało dni filtra\",\n        \"ru\": \"Осталось дней фильтра\",\n        \"ko\": \"필터 남은 일수\"\n      },\n      \"desc\": {\n        \"en\": \"Number of days the filter is expected to last\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"units\": {\n        \"en\": \"days\"\n      },\n      \"icon\": \"/assets/icons/filter_left.svg\"\n    },\n    \"measure_filter_life\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Filter Life (%)\",\n        \"nl\": \"Filter Levensduur (%)\",\n        \"da\": \"Filterlevetid (%)\",\n        \"de\": \"Filterlebensdauer (%)\",\n        \"es\": \"Vida útil del filtro (%)\",\n        \"fr\": \"Durée de vie du filtre (%)\",\n        \"it\": \"Durata del filtro (%)\",\n        \"no\": \"Filterlevetid (%)\",\n        \"sv\": \"Filterlivslängd (%)\",\n        \"pl\": \"Żywotność filtra (%)\",\n        \"ru\": \"Срок службы фильтра (%)\",\n        \"ko\": \"필터 수명 (%)\"\n      },\n      \"desc\": {\n        \"en\": \"Shows the remaining filter life in percent\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"units\": {\n        \"en\": \"%\"\n      },\n      \"icon\": \"/assets/icons/filter.svg\"\n    },\n    \"measure_gas_density\": {\n      \"title\": {\n        \"en\": \"Gas Density\",\n        \"nl\": \"Gas dichtheid\",\n        \"da\": \"Gasdensitet\",\n        \"de\": \"Gasdichte\",\n        \"es\": \"Densidad del gas\",\n        \"fr\": \"Densité de gaz\",\n        \"it\": \"Densità del gas\",\n        \"no\": \"Gassdensitet\",\n        \"sv\": \"Gasdensitet\",\n        \"pl\": \"Gęstość gazu\",\n        \"ru\": \"Плотность газа\",\n        \"ko\": \"가스 밀도\"\n      },\n      \"type\": \"number\",\n      \"units\": {\n        \"en\": \"kg/m3\",\n        \"nl\": \"kg/m3\",\n        \"da\": \"kg/m3\",\n        \"de\": \"kg/m3\",\n        \"es\": \"kg/m3\",\n        \"fr\": \"kg/m3\",\n        \"it\": \"kg/m3\",\n        \"no\": \"kg/m3\",\n        \"sv\": \"kg/m3\",\n        \"pl\": \"kg/m3\",\n        \"ru\": \"kg/m3\",\n        \"ko\": \"kg/m3\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"icon\": \"/assets/icons/measure_gas_density.svg\"\n    },\n    \"measure_smoke_density\": {\n      \"title\": {\n        \"en\": \"Smoke Density\",\n        \"nl\": \"Rook dichtheid\",\n        \"da\": \"Røgtæthed\",\n        \"de\": \"Rauchdichte\",\n        \"es\": \"Densidad de humo\",\n        \"fr\": \"Densité de fumée\",\n        \"it\": \"Densità del fumo\",\n        \"no\": \"Røykdensitet\",\n        \"sv\": \"Röktäthet\",\n        \"pl\": \"Gęstość dymu\",\n        \"ru\": \"Плотность дыма\",\n        \"ko\": \"연기 밀도\"\n      },\n      \"type\": \"number\",\n      \"units\": {\n        \"en\": \"kg/m3\",\n        \"da\": \"kg/m3\",\n        \"de\": \"kg/m3\",\n        \"es\": \"kg/m3\",\n        \"fr\": \"kg/m3\",\n        \"it\": \"kg/m3\",\n        \"no\": \"kg/m3\",\n        \"sv\": \"kg/m3\",\n        \"pl\": \"kg/m3\",\n        \"ru\": \"кг/м³\",\n        \"ko\": \"kg/m3\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"icon\": \"/assets/icons/measure_smoke_density.svg\"\n    },\n    \"measure_target_humidity\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Target humidity\"\n      },\n      \"desc\": {\n        \"en\": \"Target humidity for Insights\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"uiComponent\": null,\n      \"units\": {\n        \"en\": \"%\"\n      },\n      \"decimals\": 0,\n      \"insights\": true\n    },\n    \"measure_tvoc\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"TVOC\",\n        \"nl\": \"TVOC\",\n        \"da\": \"TVOC\",\n        \"de\": \"TVOC\",\n        \"es\": \"TVOC\",\n        \"fr\": \"TVOC\",\n        \"it\": \"TVOC\",\n        \"no\": \"TVOC\",\n        \"sv\": \"TVOC\",\n        \"pl\": \"TVOC\",\n        \"ru\": \"TVOC\",\n        \"ko\": \"TVOC\"\n      },\n      \"icon\": \"/assets/icons/measure_tvoc.svg\",\n      \"getable\": true,\n      \"setable\": false,\n      \"units\": {\n        \"en\": \"µg/m³\",\n        \"nl\": \"µg/m³\",\n        \"da\": \"µg/m³\",\n        \"de\": \"µg/m³\",\n        \"es\": \"µg/m³\",\n        \"fr\": \"µg/m³\",\n        \"it\": \"µg/m³\",\n        \"no\": \"µg/m³\",\n        \"sv\": \"µg/m³\",\n        \"pl\": \"µg/m³\",\n        \"ru\": \"µg/m³\",\n        \"ko\": \"µg/m³\"\n      },\n      \"min\": 0,\n      \"max\": 10,\n      \"decimals\": 3,\n      \"insights\": true\n    },\n    \"measure_waterlevel\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Waterlevel\",\n        \"nl\": \"Waterniveau\",\n        \"da\": \"Vandstand\",\n        \"de\": \"Wasserstand\",\n        \"es\": \"Nivel del agua\",\n        \"fr\": \"Niveau d'eau\",\n        \"it\": \"Livello dell'acqua\",\n        \"no\": \"Vannstand\",\n        \"sv\": \"Vattennivå\",\n        \"pl\": \"Poziom wody\",\n        \"ru\": \"Уровень воды\",\n        \"ko\": \"수위\"\n      },\n      \"icon\": \"/assets/icons/measure_waterlevel.svg\",\n      \"getable\": true,\n      \"setable\": false,\n      \"uiComponent\": \"sensor\",\n      \"units\": {\n        \"en\": \"%\",\n        \"nl\": \"%\",\n        \"da\": \"%\",\n        \"de\": \"%\",\n        \"es\": \"%\",\n        \"fr\": \"%\",\n        \"it\": \"%\",\n        \"no\": \"%\",\n        \"sv\": \"%\",\n        \"pl\": \"%\",\n        \"ru\": \"%\",\n        \"ko\": \"%\"\n      },\n      \"insights\": true\n    },\n    \"petfeeder_busy\": {\n      \"type\": \"boolean\",\n      \"title\": {\n        \"en\": \"Feeder busy\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"uiComponent\": \"toggle\",\n      \"insights\": true,\n      \"insightsTitleTrue\": {\n        \"en\": \"Feeding\"\n      },\n      \"insightsTitleFalse\": {\n        \"en\": \"Idle\"\n      }\n    },\n    \"petfeeder_eaten_food_today\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Eaten Food Today\"\n      },\n      \"desc\": {\n        \"en\": \"Food eaten since midnight\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"units\": {\n        \"en\": \"g\"\n      },\n      \"decimals\": 0,\n      \"min\": 0,\n      \"uiComponent\": \"sensor\",\n      \"insights\": true,\n      \"insightsTitle\": {\n        \"en\": \"Food eaten today\"\n      }\n    },\n    \"petfeeder_eaten_food_total\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Eaten Food Total\"\n      },\n      \"desc\": {\n        \"en\": \"Cumulative eaten food reported by device\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"units\": {\n        \"en\": \"g\"\n      },\n      \"decimals\": 0,\n      \"min\": 0,\n      \"uiComponent\": \"sensor\"\n    },\n    \"petfeeder_food_in_bowl\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Food left in bowl\"\n      },\n      \"units\": {\n        \"en\": \"g\"\n      },\n      \"decimals\": 1,\n      \"min\": 0,\n      \"getable\": true,\n      \"setable\": false,\n      \"insights\": true,\n      \"insightsTitle\": {\n        \"en\": \"Food in bowl\"\n      },\n      \"uiComponent\": \"sensor\"\n    },\n    \"petfeeder_food_out_progress\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Food out progress\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"units\": {\n        \"en\": \"%\"\n      },\n      \"min\": 0,\n      \"max\": 100,\n      \"decimals\": 0,\n      \"uiComponent\": \"sensor\"\n    },\n    \"petfeeder_food_out_status\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Food Out Status\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"values\": [\n        {\n          \"id\": \"ok\",\n          \"title\": {\n            \"en\": \"OK\"\n          }\n        },\n        {\n          \"id\": \"food_out\",\n          \"title\": {\n            \"en\": \"Food Out\"\n          }\n        }\n      ],\n      \"uiComponent\": \"picker\"\n    },\n    \"petfeeder_foodlevel\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Foodlevel\",\n        \"nl\": \"Voedselniveau\",\n        \"da\": \"Madniveau\",\n        \"de\": \"Futterstand\",\n        \"es\": \"Nivel de comida\",\n        \"fr\": \"Niveau de nourriture\",\n        \"it\": \"Livello di cibo\",\n        \"no\": \"Matenivå\",\n        \"sv\": \"Matnivå\",\n        \"pl\": \"Poziom jedzenia\",\n        \"ru\": \"Уровень еды\",\n        \"ko\": \"음식 수준\"\n      },\n      \"values\": [\n        {\n          \"title\": {\n            \"en\": \"Normal\"\n          },\n          \"id\": \"normal\"\n        },\n        {\n          \"title\": {\n            \"en\": \"Low\"\n          },\n          \"id\": \"low\"\n        },\n        {\n          \"title\": {\n            \"en\": \"Unknown\"\n          },\n          \"id\": \"unknown\"\n        }\n      ],\n      \"getable\": true,\n      \"setable\": false,\n      \"icon\": \"/assets/icons/petfeeder_foodlevel.svg\"\n    },\n    \"petfeeder_heap_status\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Heap Status\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"values\": [\n        {\n          \"id\": \"ok\",\n          \"title\": {\n            \"en\": \"OK\"\n          }\n        },\n        {\n          \"id\": \"heap_detected\",\n          \"title\": {\n            \"en\": \"Heap Detected\"\n          }\n        }\n      ],\n      \"uiComponent\": \"picker\"\n    },\n    \"petfeeder_schedule_progress\": {\n      \"type\": \"number\",\n      \"title\": {\n        \"en\": \"Schedule progress\"\n      },\n      \"units\": {\n        \"en\": \"%\"\n      },\n      \"decimals\": 0,\n      \"min\": 0,\n      \"max\": 100,\n      \"getable\": true,\n      \"setable\": false,\n      \"uiComponent\": \"sensor\"\n    },\n    \"petfeeder_status_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Feeder Status\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"values\": [\n        {\n          \"id\": \"unknown\",\n          \"title\": {\n            \"en\": \"Unknown\"\n          }\n        },\n        {\n          \"id\": \"idle\",\n          \"title\": {\n            \"en\": \"Idle\"\n          }\n        },\n        {\n          \"id\": \"feeding\",\n          \"title\": {\n            \"en\": \"Feeding\"\n          }\n        },\n        {\n          \"id\": \"paused\",\n          \"title\": {\n            \"en\": \"Paused\"\n          }\n        },\n        {\n          \"id\": \"fault\",\n          \"title\": {\n            \"en\": \"Fault\"\n          }\n        }\n      ],\n      \"uiComponent\": \"picker\"\n    },\n    \"petwaterdispenser_mmgg_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Pet Waterdispenser Mode\",\n        \"nl\": \"Pet Waterdispenser Mode\",\n        \"da\": \"Kæledyrsvanddispenser Mode\",\n        \"de\": \"Haustier Wasserspender Modus\",\n        \"es\": \"Modo dispensador de agua para mascotas\",\n        \"fr\": \"Mode distributeur d'eau pour animaux\",\n        \"it\": \"Modalità dispenser d'acqua per animali\",\n        \"no\": \"Kjæledyr vannedispensermodus\",\n        \"sv\": \"Husdjur vattendispenserläge\",\n        \"pl\": \"Tryb dozownika wody dla zwierząt\",\n        \"ru\": \"Режим поилки для питомцев\",\n        \"ko\": \"애완동물 물 디스펜서 모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Common\",\n            \"nl\": \"Normaal\",\n            \"da\": \"Almindelig\",\n            \"de\": \"Allgemein\",\n            \"es\": \"Común\",\n            \"fr\": \"Commun\",\n            \"it\": \"Comune\",\n            \"no\": \"Vanlig\",\n            \"sv\": \"Vanlig\",\n            \"pl\": \"Zwykły\",\n            \"ru\": \"Обычный\",\n            \"ko\": \"일반\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Smart\",\n            \"nl\": \"Slim\",\n            \"da\": \"Smart\",\n            \"de\": \"Intelligent\",\n            \"es\": \"Inteligente\",\n            \"fr\": \"Intelligent\",\n            \"it\": \"Intelligente\",\n            \"no\": \"Smart\",\n            \"sv\": \"Smart\",\n            \"pl\": \"Inteligentny\",\n            \"ru\": \"Умный\",\n            \"ko\": \"스마트\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/waterdispenser-mode.svg\"\n    },\n    \"petwaterdispenser_mmgg_mode_3\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Pet Fountain Mode\",\n        \"nl\": \"Huisdier Fontein Modus\",\n        \"da\": \"Kæledyr Fountain Mode\",\n        \"de\": \"Haustierbrunnen-Modus\",\n        \"es\": \"Modo Fuente para Mascotas\",\n        \"fr\": \"Mode Fontaine à Animaux\",\n        \"it\": \"Modalità Fontana per Animali\",\n        \"no\": \"Kjæledyr Fontenemodus\",\n        \"sv\": \"Husdjur Fontänläge\",\n        \"pl\": \"Tryb Fontanny dla Zwierząt\",\n        \"ru\": \"Режим поилки для питомцев\",\n        \"ko\": \"애완동물 분수 모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Auto\",\n            \"nl\": \"Auto\",\n            \"da\": \"Auto\",\n            \"de\": \"Auto\",\n            \"es\": \"Auto\",\n            \"fr\": \"Auto\",\n            \"it\": \"Auto\",\n            \"no\": \"Auto\",\n            \"sv\": \"Auto\",\n            \"pl\": \"Auto\",\n            \"ru\": \"Авто\",\n            \"ko\": \"자동\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Interval\",\n            \"nl\": \"Interval\",\n            \"da\": \"Interval\",\n            \"de\": \"Intervall\",\n            \"es\": \"Intervalo\",\n            \"fr\": \"Intervalle\",\n            \"it\": \"Intervallo\",\n            \"no\": \"Intervall\",\n            \"sv\": \"Intervall\",\n            \"pl\": \"Interwał\",\n            \"ru\": \"Интервал\",\n            \"ko\": \"간격\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Constant\",\n            \"nl\": \"Constant\",\n            \"da\": \"Konstant\",\n            \"de\": \"Konstant\",\n            \"es\": \"Constante\",\n            \"fr\": \"Constant\",\n            \"it\": \"Costante\",\n            \"no\": \"Konstant\",\n            \"sv\": \"Konstant\",\n            \"pl\": \"Ciągły\",\n            \"ru\": \"Постоянный\",\n            \"ko\": \"지속\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/waterdispenser-mode.svg\"\n    },\n    \"vacuum_dreame_fanspeed\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Fanspeed\",\n        \"nl\": \"Fanspeed\",\n        \"da\": \"Blæserhastighed\",\n        \"de\": \"Lüftergeschwindigkeit\",\n        \"es\": \"Velocidad del ventilador\",\n        \"fr\": \"Vitesse du ventilateur\",\n        \"it\": \"Velocità della ventola\",\n        \"no\": \"Viftehastighet\",\n        \"sv\": \"Fläkthastighet\",\n        \"pl\": \"Prędkość wentylatora\",\n        \"ru\": \"Скорость вентилятора\",\n        \"ko\": \"팬 속도\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Silent\",\n            \"nl\": \"Stil\",\n            \"da\": \"Stille\",\n            \"de\": \"Leise\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Бесшумный\",\n            \"ko\": \"조용한\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Basic\",\n            \"nl\": \"Basis\",\n            \"da\": \"Basis\",\n            \"de\": \"Basis\",\n            \"es\": \"Básico\",\n            \"fr\": \"De base\",\n            \"it\": \"Di base\",\n            \"no\": \"Grunnleggende\",\n            \"sv\": \"Grundläggande\",\n            \"pl\": \"Podstawowy\",\n            \"ru\": \"Базовый\",\n            \"ko\": \"기본\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Strong\",\n            \"nl\": \"Sterk\",\n            \"da\": \"Stærk\",\n            \"de\": \"Stark\",\n            \"es\": \"Fuerte\",\n            \"fr\": \"Fort\",\n            \"it\": \"Forte\",\n            \"no\": \"Sterk\",\n            \"sv\": \"Stark\",\n            \"pl\": \"Silny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강한\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Full speed\",\n            \"nl\": \"Volle snelheid\",\n            \"da\": \"Fuld hastighed\",\n            \"de\": \"Volle Geschwindigkeit\",\n            \"es\": \"Velocidad máxima\",\n            \"fr\": \"Vitesse maximale\",\n            \"it\": \"Velocità massima\",\n            \"no\": \"Full fart\",\n            \"sv\": \"Full hastighet\",\n            \"pl\": \"Pełna prędkość\",\n            \"ru\": \"Полная скорость\",\n            \"ko\": \"최고 속도\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/fanlevel.svg\"\n    },\n    \"vacuum_dreame_mop_intensity\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mop Intensity\",\n        \"nl\": \"Dweil intensiteit\",\n        \"da\": \"Mop Intensity\",\n        \"de\": \"Wischintensität\",\n        \"es\": \"Intensidad de fregado\",\n        \"fr\": \"Intensité de la serpillière\",\n        \"it\": \"Intensità del mop\",\n        \"no\": \"Mop Intensity\",\n        \"sv\": \"Mop Intensity\",\n        \"pl\": \"Intensywność mopa\",\n        \"ru\": \"Интенсивность швабры\",\n        \"ko\": \"물걸레 강도\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Low\",\n            \"nl\": \"Laag\",\n            \"da\": \"Lav\",\n            \"de\": \"Niedrig\",\n            \"es\": \"Bajo\",\n            \"fr\": \"Faible\",\n            \"it\": \"Basso\",\n            \"no\": \"Lav\",\n            \"sv\": \"Låg\",\n            \"pl\": \"Niski\",\n            \"ru\": \"Низкий\",\n            \"ko\": \"낮음\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Medium\",\n            \"da\": \"Middel\",\n            \"de\": \"Mittel\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Medium\",\n            \"sv\": \"Medium\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"High\",\n            \"nl\": \"Hoog\",\n            \"da\": \"Høj\",\n            \"de\": \"Hoch\",\n            \"es\": \"Alto\",\n            \"fr\": \"Élevé\",\n            \"it\": \"Alto\",\n            \"no\": \"Høy\",\n            \"sv\": \"Hög\",\n            \"pl\": \"Wysoki\",\n            \"ru\": \"Высокий\",\n            \"ko\": \"높음\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"High (specific models)\",\n            \"nl\": \"Hoog (specifieke modellen)\",\n            \"da\": \"Høj (specifikke modeller)\",\n            \"de\": \"Hoch (spezifische Modelle)\",\n            \"es\": \"Alto (modelos específicos)\",\n            \"fr\": \"Élevé (modèles spécifiques)\",\n            \"it\": \"Alto (modelli specifici)\",\n            \"no\": \"Høy (spesifikke modeller)\",\n            \"sv\": \"Hög (specifika modeller)\",\n            \"pl\": \"Wysoki (specyficzne modele)\",\n            \"ru\": \"Высокий (определённые модели)\",\n            \"ko\": \"높음 (특정 모델)\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/mopintensity.svg\"\n    },\n    \"vacuum_roborock_fanspeed\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Fanspeed\",\n        \"nl\": \"Fanspeed\",\n        \"da\": \"Blæserhastighed\",\n        \"de\": \"Lüftergeschwindigkeit\",\n        \"es\": \"Velocidad del ventilador\",\n        \"fr\": \"Vitesse du ventilateur\",\n        \"it\": \"Velocità della ventola\",\n        \"no\": \"Viftehastighet\",\n        \"sv\": \"Fläkthastighet\",\n        \"pl\": \"Prędkość wentylatora\",\n        \"ru\": \"Скорость вентилятора\",\n        \"ko\": \"팬 속도\"\n      },\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Quiet\",\n            \"nl\": \"Stil\",\n            \"da\": \"Rolig\",\n            \"de\": \"Leise\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"조용하게\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Standard\",\n            \"nl\": \"Standaard\",\n            \"da\": \"Standard\",\n            \"de\": \"Standard\",\n            \"es\": \"Estándar\",\n            \"fr\": \"Standard\",\n            \"it\": \"Standard\",\n            \"no\": \"Standard\",\n            \"sv\": \"Standard\",\n            \"pl\": \"Standardowy\",\n            \"ru\": \"Стандартный\",\n            \"ko\": \"표준\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Medium\",\n            \"nl\": \"Medium\",\n            \"da\": \"Mellem\",\n            \"de\": \"Mittel\",\n            \"es\": \"Medio\",\n            \"fr\": \"Moyen\",\n            \"it\": \"Medio\",\n            \"no\": \"Middels\",\n            \"sv\": \"Mellan\",\n            \"pl\": \"Średni\",\n            \"ru\": \"Средний\",\n            \"ko\": \"중간\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Turbo\",\n            \"nl\": \"Turbo\",\n            \"da\": \"Turbo\",\n            \"de\": \"Turbo\",\n            \"es\": \"Turbo\",\n            \"fr\": \"Turbo\",\n            \"it\": \"Turbo\",\n            \"no\": \"Turbo\",\n            \"sv\": \"Turbo\",\n            \"pl\": \"Turbo\",\n            \"ru\": \"Турбо\",\n            \"ko\": \"터보\"\n          }\n        },\n        {\n          \"id\": \"5\",\n          \"title\": {\n            \"en\": \"Max\",\n            \"nl\": \"Max\",\n            \"da\": \"Maks\",\n            \"de\": \"Max\",\n            \"es\": \"Máximo\",\n            \"fr\": \"Max\",\n            \"it\": \"Massimo\",\n            \"no\": \"Maks\",\n            \"sv\": \"Max\",\n            \"pl\": \"Maks\",\n            \"ru\": \"Макс\",\n            \"ko\": \"최대\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/fanlevel.svg\"\n    },\n    \"vacuum_roborock_mop_intensity\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mop Intensity\",\n        \"nl\": \"Dweil intensiteit\",\n        \"da\": \"Mop intensitet\",\n        \"de\": \"Wischintensität\",\n        \"es\": \"Intensidad de fregado\",\n        \"fr\": \"Intensité du nettoyage\",\n        \"it\": \"Intensità di pulizia\",\n        \"no\": \"Mop intesitet\",\n        \"sv\": \"Moppens intensitet\",\n        \"pl\": \"Intensywność mopowania\",\n        \"ru\": \"Интенсивность мытья\",\n        \"ko\": \"걸레질 강도\"\n      },\n      \"values\": [\n        {\n          \"id\": \"200\",\n          \"title\": {\n            \"en\": \"Off\",\n            \"nl\": \"Uit\",\n            \"da\": \"Slukket\",\n            \"de\": \"Aus\",\n            \"es\": \"Apagado\",\n            \"fr\": \"Éteint\",\n            \"it\": \"Spento\",\n            \"no\": \"Av\",\n            \"sv\": \"Av\",\n            \"pl\": \"Wyłączone\",\n            \"ru\": \"Выкл\",\n            \"ko\": \"꺼짐\"\n          }\n        },\n        {\n          \"id\": \"201\",\n          \"title\": {\n            \"en\": \"Mild\",\n            \"nl\": \"Mild\",\n            \"da\": \"Let\",\n            \"de\": \"Mild\",\n            \"es\": \"Suave\",\n            \"fr\": \"Doux\",\n            \"it\": \"Leggero\",\n            \"no\": \"Mild\",\n            \"sv\": \"Mild\",\n            \"pl\": \"Łagodny\",\n            \"ru\": \"Слабый\",\n            \"ko\": \"약한\"\n          }\n        },\n        {\n          \"id\": \"202\",\n          \"title\": {\n            \"en\": \"Moderate\",\n            \"nl\": \"Gemiddeld\",\n            \"da\": \"Moderat\",\n            \"de\": \"Mittel\",\n            \"es\": \"Moderado\",\n            \"fr\": \"Modéré\",\n            \"it\": \"Moderato\",\n            \"no\": \"Moderat\",\n            \"sv\": \"Medel\",\n            \"pl\": \"Umiarkowany\",\n            \"ru\": \"Средний\",\n            \"ko\": \"보통\"\n          }\n        },\n        {\n          \"id\": \"203\",\n          \"title\": {\n            \"en\": \"Intense\",\n            \"nl\": \"Intens\",\n            \"da\": \"Intens\",\n            \"de\": \"Intensiv\",\n            \"es\": \"Intenso\",\n            \"fr\": \"Intense\",\n            \"it\": \"Intenso\",\n            \"no\": \"Intens\",\n            \"sv\": \"Intensiv\",\n            \"pl\": \"Intensywny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강한\"\n          }\n        },\n        {\n          \"id\": \"204\",\n          \"title\": {\n            \"en\": \"Unknown mop intensity\",\n            \"nl\": \"Unknown mop intensity\",\n            \"da\": \"Ukendt mop intensitet\",\n            \"de\": \"Unbekannte Wischintensität\",\n            \"es\": \"Intensidad de fregado desconocida\",\n            \"fr\": \"Intensité de nettoyage inconnue\",\n            \"it\": \"Intensità di pulizia sconosciuta\",\n            \"no\": \"Ukjent mop intesitet\",\n            \"sv\": \"Okänd moppens intensitet\",\n            \"pl\": \"Nieznana intensywność mopowania\",\n            \"ru\": \"Неизвестная интенсивность мытья\",\n            \"ko\": \"알 수 없는 걸레질 강도\"\n          }\n        },\n        {\n          \"id\": \"207\",\n          \"title\": {\n            \"en\": \"Unknown mop intensity\",\n            \"nl\": \"Unknown mop intensity\",\n            \"da\": \"Ukendt mop intensitet\",\n            \"de\": \"Unbekannte Wischintensität\",\n            \"es\": \"Intensidad de fregado desconocida\",\n            \"fr\": \"Intensité de nettoyage inconnue\",\n            \"it\": \"Intensità di pulizia sconosciuta\",\n            \"no\": \"Ukjent mop intesitet\",\n            \"sv\": \"Okänd moppens intensitet\",\n            \"pl\": \"Nieznana intensywność mopowania\",\n            \"ru\": \"Неизвестная интенсивность мытья\",\n            \"ko\": \"알 수 없는 걸레질 강도\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/mopintensity.svg\"\n    },\n    \"vacuum_roidmi_fanspeed\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Fanspeed\",\n        \"nl\": \"Fanspeed\",\n        \"da\": \"Blæserhastighed\",\n        \"de\": \"Lüftergeschwindigkeit\",\n        \"es\": \"Velocidad del ventilador\",\n        \"fr\": \"Vitesse du ventilateur\",\n        \"it\": \"Velocità della ventola\",\n        \"no\": \"Viftehastighet\",\n        \"sv\": \"Fläkthastighet\",\n        \"pl\": \"Prędkość wentylatora\",\n        \"ru\": \"Скорость вентилятора\",\n        \"ko\": \"팬 속도\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Sweep\",\n            \"nl\": \"Sweep\",\n            \"da\": \"Sweep\",\n            \"de\": \"Sweep\",\n            \"es\": \"Sweep\",\n            \"fr\": \"Sweep\",\n            \"it\": \"Sweep\",\n            \"no\": \"Sweep\",\n            \"sv\": \"Sweep\",\n            \"pl\": \"Sweep\",\n            \"ru\": \"Sweep\",\n            \"ko\": \"Sweep\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Silent\",\n            \"nl\": \"Stil\",\n            \"da\": \"Stille\",\n            \"de\": \"Leise\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"조용한\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Basic\",\n            \"nl\": \"Basis\",\n            \"da\": \"Grundlæggende\",\n            \"de\": \"Basis\",\n            \"es\": \"Básico\",\n            \"fr\": \"De base\",\n            \"it\": \"Base\",\n            \"no\": \"Grunnleggende\",\n            \"sv\": \"Grundläggande\",\n            \"pl\": \"Podstawowe\",\n            \"ru\": \"Основной\",\n            \"ko\": \"기본\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Strong\",\n            \"nl\": \"Sterk\",\n            \"da\": \"Stærk\",\n            \"de\": \"Stark\",\n            \"es\": \"Fuerte\",\n            \"fr\": \"Fort\",\n            \"it\": \"Forte\",\n            \"no\": \"Sterk\",\n            \"sv\": \"Stark\",\n            \"pl\": \"Silny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강한\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Full speed\",\n            \"nl\": \"Volle snelheid\",\n            \"da\": \"Fuld fart\",\n            \"de\": \"Volle Geschwindigkeit\",\n            \"es\": \"Velocidad máxima\",\n            \"fr\": \"Pleine vitesse\",\n            \"it\": \"Piena velocità\",\n            \"no\": \"Full fart\",\n            \"sv\": \"Full fart\",\n            \"pl\": \"Pełna prędkość\",\n            \"ru\": \"Полная скорость\",\n            \"ko\": \"최고 속도\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/fanlevel.svg\"\n    },\n    \"vacuum_roidmi_mop_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Sweep and Mop Mode\",\n        \"nl\": \"Sweep and Mop modus\",\n        \"da\": \"Feje- og mopningstilstand\",\n        \"de\": \"Kehr- und Wischmodus\",\n        \"es\": \"Modo de barrido y fregado\",\n        \"fr\": \"Mode balayage et vadrouille\",\n        \"it\": \"Modalità spazzare e pulire\",\n        \"no\": \"Feie- og moppemodus\",\n        \"sv\": \"Sop- och moppningsläge\",\n        \"pl\": \"Tryb zamiatania i mopowania\",\n        \"ru\": \"Режим подметания и мытья полов\",\n        \"ko\": \"쓸기 및 물기 모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Sweep\",\n            \"nl\": \"Sweep\",\n            \"da\": \"Feje\",\n            \"de\": \"Kehren\",\n            \"es\": \"Barrer\",\n            \"fr\": \"Balayer\",\n            \"it\": \"Spazzare\",\n            \"no\": \"Feie\",\n            \"sv\": \"Sopa\",\n            \"pl\": \"Zamiatanie\",\n            \"ru\": \"Подметание\",\n            \"ko\": \"쓸기\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Mop\",\n            \"nl\": \"Mop\",\n            \"da\": \"Moppe\",\n            \"de\": \"Wischen\",\n            \"es\": \"Fregar\",\n            \"fr\": \"Passer la serpillière\",\n            \"it\": \"Pulire\",\n            \"no\": \"Moppe\",\n            \"sv\": \"Moppa\",\n            \"pl\": \"Mopowanie\",\n            \"ru\": \"Мытьё полов\",\n            \"ko\": \"물기\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Mop & Sweep\",\n            \"nl\": \"Mop & Sweep\",\n            \"da\": \"Moppe & Feje\",\n            \"de\": \"Wischen & Kehren\",\n            \"es\": \"Fregar y Barrer\",\n            \"fr\": \"Vadrouille et Balayage\",\n            \"it\": \"Pulire e Spazzare\",\n            \"no\": \"Moppe og Feie\",\n            \"sv\": \"Moppa & Sopa\",\n            \"pl\": \"Mopowanie i zamiatanie\",\n            \"ru\": \"Мытьё полов и подметание\",\n            \"ko\": \"물기 및 쓸기\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/vacuum-mop.svg\"\n    },\n    \"vacuum_roidmi_waterlevel\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Fanspeed\",\n        \"nl\": \"Fanspeed\",\n        \"da\": \"Blæserhastighed\",\n        \"de\": \"Lüftergeschwindigkeit\",\n        \"es\": \"Velocidad del ventilador\",\n        \"fr\": \"Vitesse du ventilateur\",\n        \"it\": \"Velocità della ventola\",\n        \"no\": \"Viftehastighet\",\n        \"sv\": \"Fläkthastighet\",\n        \"pl\": \"Prędkość wentylatora\",\n        \"ru\": \"Скорость вентилятора\",\n        \"ko\": \"팬 속도\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Mop\",\n            \"nl\": \"Mop\",\n            \"da\": \"Mop\",\n            \"de\": \"Mop\",\n            \"es\": \"Mopa\",\n            \"fr\": \"Serpillère\",\n            \"it\": \"Mop\",\n            \"no\": \"Mopp\",\n            \"sv\": \"Mopp\",\n            \"pl\": \"Mop\",\n            \"ru\": \"Швабра\",\n            \"ko\": \"걸레\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"First\",\n            \"nl\": \"Eerste\",\n            \"da\": \"Første\",\n            \"de\": \"Erste\",\n            \"es\": \"Primero\",\n            \"fr\": \"Premier\",\n            \"it\": \"Primo\",\n            \"no\": \"Første\",\n            \"sv\": \"Första\",\n            \"pl\": \"Pierwszy\",\n            \"ru\": \"Первый\",\n            \"ko\": \"첫번째\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Second\",\n            \"nl\": \"Tweede\",\n            \"da\": \"Anden\",\n            \"de\": \"Zweite\",\n            \"es\": \"Segundo\",\n            \"fr\": \"Deuxième\",\n            \"it\": \"Secondo\",\n            \"no\": \"Andre\",\n            \"sv\": \"Andra\",\n            \"pl\": \"Drugi\",\n            \"ru\": \"Второй\",\n            \"ko\": \"두번째\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Third\",\n            \"nl\": \"Derde\",\n            \"da\": \"Tredje\",\n            \"de\": \"Dritte\",\n            \"es\": \"Tercero\",\n            \"fr\": \"Troisième\",\n            \"it\": \"Terzo\",\n            \"no\": \"Tredje\",\n            \"sv\": \"Tredje\",\n            \"pl\": \"Trzeci\",\n            \"ru\": \"Третий\",\n            \"ko\": \"세번째\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Fourth\",\n            \"nl\": \"Vierde\",\n            \"da\": \"Fjerde\",\n            \"de\": \"Vierte\",\n            \"es\": \"Cuarto\",\n            \"fr\": \"Quatrième\",\n            \"it\": \"Quarto\",\n            \"no\": \"Fjerde\",\n            \"sv\": \"Fjärde\",\n            \"pl\": \"Czwarty\",\n            \"ru\": \"Четвертый\",\n            \"ko\": \"네번째\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": false,\n      \"icon\": \"/assets/icons/measure_waterlevel.svg\"\n    },\n    \"vacuum_viomi_mop_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Vacuum Mode\",\n        \"nl\": \"Stofzuiger modus\",\n        \"da\": \"Støvsugermodus\",\n        \"de\": \"Staubsaugermodus\",\n        \"es\": \"Modo de aspiradora\",\n        \"fr\": \"Mode aspirateur\",\n        \"it\": \"Modalità aspirapolvere\",\n        \"no\": \"Støvsugermodus\",\n        \"sv\": \"Dammsugarläge\",\n        \"pl\": \"Tryb odkurzacza\",\n        \"ru\": \"Режим пылесоса\",\n        \"ko\": \"진공 모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Vacuum\",\n            \"nl\": \"Stofzuigen\",\n            \"da\": \"Støvsuge\",\n            \"de\": \"Staubsaugen\",\n            \"es\": \"Aspirar\",\n            \"fr\": \"Aspirer\",\n            \"it\": \"Aspirare\",\n            \"no\": \"Støvsuge\",\n            \"sv\": \"Dammsuga\",\n            \"pl\": \"Odkurzać\",\n            \"ru\": \"Пылесосить\",\n            \"ko\": \"진공\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Vacuum + Mop\",\n            \"nl\": \"Stofzuigen + moppen\",\n            \"da\": \"Støvsuge + moppe\",\n            \"de\": \"Staubsaugen + Wischen\",\n            \"es\": \"Aspirar + Trapear\",\n            \"fr\": \"Aspirer + Passer la serpillière\",\n            \"it\": \"Aspirare + Lavare\",\n            \"no\": \"Støvsuge + moppe\",\n            \"sv\": \"Dammsuga + moppa\",\n            \"pl\": \"Odkurzać + Mopować\",\n            \"ru\": \"Пылесосить + Мыть\",\n            \"ko\": \"진공 + 걸레질\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Mop\",\n            \"nl\": \"Moppen\",\n            \"da\": \"Moppe\",\n            \"de\": \"Wischen\",\n            \"es\": \"Trapear\",\n            \"fr\": \"Passer la serpillière\",\n            \"it\": \"Lavare\",\n            \"no\": \"Moppe\",\n            \"sv\": \"Moppa\",\n            \"pl\": \"Mopować\",\n            \"ru\": \"Мыть\",\n            \"ko\": \"걸레질\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/vacuum-mop.svg\"\n    },\n    \"vacuum_xiaomi_carpet_mode_max\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Carpet avoidance\",\n        \"nl\": \"Tapijt vermijden\",\n        \"de\": \"Teppichvermeidung\",\n        \"da\": \"Undgå tæpper\",\n        \"es\": \"Evitar alfombras\",\n        \"fr\": \"Éviter les tapis\",\n        \"it\": \"Evitamento tappeti\",\n        \"no\": \"Unngå tepper\",\n        \"sv\": \"Undvik mattor\",\n        \"pl\": \"Unikanie dywanów\",\n        \"ru\": \"Избегание ковров\",\n        \"ko\": \"카펫 회피\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Self Adaptation\",\n            \"nl\": \"Zelfaanpassing\",\n            \"de\": \"Selbstanpassung\",\n            \"da\": \"Selvtilpasning\",\n            \"es\": \"Auto adaptación\",\n            \"fr\": \"Auto-adaptation\",\n            \"it\": \"Auto adattamento\",\n            \"no\": \"Selvtilpasning\",\n            \"sv\": \"Självanpassning\",\n            \"pl\": \"Samodopasowanie\",\n            \"ru\": \"Самоадаптация\",\n            \"ko\": \"자동 적응\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Avoid\",\n            \"nl\": \"Vermijden\",\n            \"de\": \"Vermeiden\",\n            \"da\": \"Undgå\",\n            \"es\": \"Evitar\",\n            \"fr\": \"Éviter\",\n            \"it\": \"Evita\",\n            \"no\": \"Unngå\",\n            \"sv\": \"Undvik\",\n            \"pl\": \"Unikaj\",\n            \"ru\": \"Избегать\",\n            \"ko\": \"회피\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Ignore\",\n            \"nl\": \"Negeren\",\n            \"de\": \"Ignorieren\",\n            \"da\": \"Ignorer\",\n            \"es\": \"Ignorar\",\n            \"fr\": \"Ignorer\",\n            \"it\": \"Ignora\",\n            \"no\": \"Ignorer\",\n            \"sv\": \"Ignorera\",\n            \"pl\": \"Ignoruj\",\n            \"ru\": \"Игнорировать\",\n            \"ko\": \"무시\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Span\",\n            \"nl\": \"Span\",\n            \"de\": \"Span\",\n            \"da\": \"Span\",\n            \"es\": \"Span\",\n            \"fr\": \"Span\",\n            \"it\": \"Span\",\n            \"no\": \"Span\",\n            \"sv\": \"Span\",\n            \"pl\": \"Span\",\n            \"ru\": \"Span\",\n            \"ko\": \"Span\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true\n    },\n    \"vacuum_xiaomi_cleaning_mode_max\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Cleaning Power\",\n        \"nl\": \"Reinigingskracht\",\n        \"de\": \"Reinigungsleistung\",\n        \"da\": \"Rengøringskraft\",\n        \"es\": \"Potencia de limpieza\",\n        \"fr\": \"Pouvoir de nettoyage\",\n        \"it\": \"Potenza di pulizia\",\n        \"no\": \"Rengjøringskraft\",\n        \"sv\": \"Rengöringskraft\",\n        \"pl\": \"Moc czyszczenia\",\n        \"ru\": \"Сила очистки\",\n        \"ko\": \"청소 능력\"\n      },\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Silent\",\n            \"nl\": \"Stil\",\n            \"de\": \"Leise\",\n            \"da\": \"Stille\",\n            \"es\": \"Silencioso\",\n            \"fr\": \"Silencieux\",\n            \"it\": \"Silenzioso\",\n            \"no\": \"Stille\",\n            \"sv\": \"Tyst\",\n            \"pl\": \"Cichy\",\n            \"ru\": \"Тихий\",\n            \"ko\": \"조용한\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Standard\",\n            \"nl\": \"Standaard\",\n            \"de\": \"Standard\",\n            \"da\": \"Standard\",\n            \"es\": \"Estándar\",\n            \"fr\": \"Standard\",\n            \"it\": \"Standard\",\n            \"no\": \"Standard\",\n            \"sv\": \"Standard\",\n            \"pl\": \"Standardowy\",\n            \"ru\": \"Стандартный\",\n            \"ko\": \"표준\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Strong\",\n            \"nl\": \"Sterk\",\n            \"de\": \"Stark\",\n            \"da\": \"Stærk\",\n            \"es\": \"Fuerte\",\n            \"fr\": \"Fort\",\n            \"it\": \"Forte\",\n            \"no\": \"Sterk\",\n            \"sv\": \"Stark\",\n            \"pl\": \"Silny\",\n            \"ru\": \"Сильный\",\n            \"ko\": \"강한\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Turbo\",\n            \"nl\": \"Turbo\",\n            \"de\": \"Turbo\",\n            \"da\": \"Turbo\",\n            \"es\": \"Turbo\",\n            \"fr\": \"Turbo\",\n            \"it\": \"Turbo\",\n            \"no\": \"Turbo\",\n            \"sv\": \"Turbo\",\n            \"pl\": \"Turbo\",\n            \"ru\": \"Турбо\",\n            \"ko\": \"터보\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/fanlevel.svg\"\n    },\n    \"vacuum_xiaomi_detergent_left_level\": {\n      \"title\": {\n        \"en\": \"Water left (%)\",\n        \"nl\": \"Overgebleven water (%)\",\n        \"da\": \"Resterende vand (%)\",\n        \"de\": \"Verbleibendes Wasser (%)\",\n        \"es\": \"Agua restante (%)\",\n        \"fr\": \"Eau restante (%)\",\n        \"it\": \"Acqua rimasta (%)\",\n        \"no\": \"Vann igjen (%)\",\n        \"sv\": \"Vatten kvar (%)\",\n        \"pl\": \"Pozostała woda (%)\",\n        \"ru\": \"Остаток воды (%)\",\n        \"ko\": \"남은 물 (%)\"\n      },\n      \"type\": \"number\",\n      \"getable\": true,\n      \"setable\": false,\n      \"units\": {\n        \"en\": \"%\",\n        \"nl\": \"%\",\n        \"da\": \"%\",\n        \"de\": \"%\",\n        \"es\": \"%\",\n        \"fr\": \"%\",\n        \"it\": \"%\",\n        \"no\": \"%\",\n        \"sv\": \"%\",\n        \"pl\": \"%\",\n        \"ru\": \"%\",\n        \"ko\": \"%\"\n      },\n      \"uiComponent\": \"sensor\"\n    },\n    \"vacuum_xiaomi_dust_bag_left_level\": {\n      \"title\": {\n        \"en\": \"Dust bag left (%)\",\n        \"nl\": \"Stofzak over (%)\",\n        \"da\": \"Støvsugerpose tilbage (%)\",\n        \"de\": \"Staubbeutel verbleibend (%)\",\n        \"es\": \"Bolsa de polvo restante (%)\",\n        \"fr\": \"Sac à poussière restant (%)\",\n        \"it\": \"Sacchetto della polvere rimasto (%)\",\n        \"no\": \"Støvsekk igjen (%)\",\n        \"sv\": \"Dammsugarpåse kvar (%)\",\n        \"pl\": \"Pozostało worka na kurz (%)\",\n        \"ru\": \"Осталось пылесборника (%)\",\n        \"ko\": \"먼지 봉투 남음 (%)\"\n      },\n      \"type\": \"number\",\n      \"getable\": true,\n      \"setable\": false,\n      \"units\": {\n        \"en\": \"%\",\n        \"nl\": \"%\",\n        \"da\": \"%\",\n        \"de\": \"%\",\n        \"es\": \"%\",\n        \"fr\": \"%\",\n        \"it\": \"%\",\n        \"no\": \"%\",\n        \"sv\": \"%\",\n        \"pl\": \"%\",\n        \"ru\": \"%\",\n        \"ko\": \"%\"\n      },\n      \"uiComponent\": \"sensor\"\n    },\n    \"vacuum_xiaomi_mop_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Sweep and Mop Mode\",\n        \"nl\": \"Sweep and Mop modus\",\n        \"da\": \"Feje og Moppe Tilstand\",\n        \"de\": \"Kehr- und Wischmodus\",\n        \"es\": \"Modo Barrer y Trapear\",\n        \"fr\": \"Mode Balayage et Lavage\",\n        \"it\": \"Modalità Spazza e Passa\",\n        \"no\": \"Feie- og Moppemodus\",\n        \"sv\": \"Sopa och Mopp-läge\",\n        \"pl\": \"Tryb zamiatania i mopowania\",\n        \"ru\": \"Режим подметания и мытья\",\n        \"ko\": \"청소 및 물걸레 모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Sweep\",\n            \"nl\": \"Sweep\",\n            \"da\": \"Feje\",\n            \"de\": \"Kehren\",\n            \"es\": \"Barrer\",\n            \"fr\": \"Balayer\",\n            \"it\": \"Spazza\",\n            \"no\": \"Feie\",\n            \"sv\": \"Sopa\",\n            \"pl\": \"Zamiatać\",\n            \"ru\": \"Подметать\",\n            \"ko\": \"청소\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Sweep & Mop\",\n            \"nl\": \"Sweep & Mop\",\n            \"da\": \"Feje & Moppe\",\n            \"de\": \"Kehren & Wischen\",\n            \"es\": \"Barrer y Trapear\",\n            \"fr\": \"Balayer & Laver\",\n            \"it\": \"Spazza & Passa\",\n            \"no\": \"Feie & Moppe\",\n            \"sv\": \"Sopa & Mopp\",\n            \"pl\": \"Zamiatać i mopować\",\n            \"ru\": \"Подметать и мыть\",\n            \"ko\": \"청소 및 물걸레질\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Mop\",\n            \"nl\": \"Mop\",\n            \"da\": \"Moppe\",\n            \"de\": \"Wischen\",\n            \"es\": \"Trapear\",\n            \"fr\": \"Laver\",\n            \"it\": \"Passa\",\n            \"no\": \"Moppe\",\n            \"sv\": \"Mopp\",\n            \"pl\": \"Mopować\",\n            \"ru\": \"Мыть\",\n            \"ko\": \"물걸레질\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/vacuum-mop.svg\"\n    },\n    \"vacuum_xiaomi_mop_mode_max\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Sweep & Mop Mode\",\n        \"it\": \"Modalità Spazza e Passa\",\n        \"no\": \"Feie- og Moppemodus\",\n        \"sv\": \"Sopa och Mopp-läge\",\n        \"pl\": \"Tryb zamiatania i mopowania\",\n        \"ru\": \"Режим подметания и мытья\",\n        \"ko\": \"청소 및 물걸레 모드\",\n        \"nl\": \"Vegen en Dweilen modus\",\n        \"da\": \"Fej & Moppe tilstand\",\n        \"de\": \"Kehren & Wischen Modus\",\n        \"es\": \"Modo Barrer y Trapear\",\n        \"fr\": \"Mode Balayer & Laver\"\n      },\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Sweep\",\n            \"nl\": \"Sweep\",\n            \"da\": \"Feje\",\n            \"de\": \"Kehren\",\n            \"es\": \"Barrer\",\n            \"fr\": \"Balayer\",\n            \"it\": \"Spazza\",\n            \"no\": \"Feie\",\n            \"sv\": \"Sopa\",\n            \"pl\": \"Zamiatać\",\n            \"ru\": \"Подметать\",\n            \"ko\": \"청소\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Mop\",\n            \"nl\": \"Mop\",\n            \"da\": \"Moppe\",\n            \"de\": \"Wischen\",\n            \"es\": \"Trapear\",\n            \"fr\": \"Laver\",\n            \"it\": \"Passa\",\n            \"no\": \"Moppe\",\n            \"sv\": \"Mopp\",\n            \"pl\": \"Mopować\",\n            \"ru\": \"Мыть\",\n            \"ko\": \"물걸레질\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Sweep & Mop\",\n            \"nl\": \"Sweep & Mop\",\n            \"da\": \"Feje & Moppe\",\n            \"de\": \"Kehren & Wischen\",\n            \"es\": \"Barrer y Trapear\",\n            \"fr\": \"Balayer & Laver\",\n            \"it\": \"Spazza & Passa\",\n            \"no\": \"Feie & Moppe\",\n            \"sv\": \"Sopa & Mopp\",\n            \"pl\": \"Zamiatać i mopować\",\n            \"ru\": \"Подметать и мыть\",\n            \"ko\": \"청소 및 물걸레질\"\n          }\n        },\n        {\n          \"id\": \"4\",\n          \"title\": {\n            \"en\": \"Sweep Before Mopping\",\n            \"nl\": \"Vegen voor Dweilen\",\n            \"da\": \"Fej før mopning\",\n            \"de\": \"Kehren vor dem Wischen\",\n            \"es\": \"Barrer antes de trapear\",\n            \"fr\": \"Balayer avant de laver\",\n            \"it\": \"Spazza prima di passare\",\n            \"no\": \"Feie før mopping\",\n            \"sv\": \"Sopa före moppning\",\n            \"pl\": \"Zamiataj przed mopowaniem\",\n            \"ru\": \"Подметать перед мытьём\",\n            \"ko\": \"물걸레질 전 청소\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/vacuum-mop.svg\"\n    },\n    \"vacuum_xiaomi_path_mode_max\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Path Mode\",\n        \"nl\": \"Padmodus\",\n        \"de\": \"Pfadmodus\",\n        \"da\": \"Sti mode\",\n        \"es\": \"Modo de ruta\",\n        \"fr\": \"Mode chemin\",\n        \"it\": \"Modalità percorso\",\n        \"no\": \"Bane modus\",\n        \"sv\": \"Sätt för väg\",\n        \"pl\": \"Tryb ścieżki\",\n        \"ru\": \"Режим пути\",\n        \"ko\": \"경로 모드\"\n      },\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Quick\",\n            \"nl\": \"Snel\",\n            \"de\": \"Schnell\",\n            \"da\": \"Hurtig\",\n            \"es\": \"Rápido\",\n            \"fr\": \"Rapide\",\n            \"it\": \"Veloce\",\n            \"no\": \"Rask\",\n            \"sv\": \"Snabb\",\n            \"pl\": \"Szybki\",\n            \"ru\": \"Быстрый\",\n            \"ko\": \"빠른\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Standard\",\n            \"nl\": \"Standaard\",\n            \"de\": \"Standard\",\n            \"da\": \"Standard\",\n            \"es\": \"Estándar\",\n            \"fr\": \"Standard\",\n            \"it\": \"Standard\",\n            \"no\": \"Standard\",\n            \"sv\": \"Standard\",\n            \"pl\": \"Standard\",\n            \"ru\": \"Стандарт\",\n            \"ko\": \"표준\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Deep\",\n            \"nl\": \"Diep\",\n            \"de\": \"Tief\",\n            \"da\": \"Dyb\",\n            \"es\": \"Profundo\",\n            \"fr\": \"Profond\",\n            \"it\": \"Profondo\",\n            \"no\": \"Dyp\",\n            \"sv\": \"Djupt\",\n            \"pl\": \"Głęboki\",\n            \"ru\": \"Глубокий\",\n            \"ko\": \"깊은\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/vacuum-path-mode.svg\"\n    },\n    \"vacuum_xiaomi_status\": {\n      \"type\": \"string\",\n      \"title\": {\n        \"en\": \"Status / error\",\n        \"nl\": \"Status / fout\",\n        \"da\": \"Status / fejl\",\n        \"de\": \"Status / Fehler\",\n        \"es\": \"Estado / error\",\n        \"fr\": \"Statut / erreur\",\n        \"it\": \"Stato / errore\",\n        \"no\": \"Status / feil\",\n        \"sv\": \"Status / fel\",\n        \"pl\": \"Status / błąd\",\n        \"ru\": \"Статус / ошибка\",\n        \"ko\": \"상태 / 오류\"\n      },\n      \"getable\": true,\n      \"setable\": false,\n      \"insights\": false,\n      \"icon\": \"/assets/icons/alarm_generic.svg\"\n    },\n    \"vacuum_xiaomi_water_level_max\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Water Output\",\n        \"nl\": \"Wateroutput\",\n        \"de\": \"Wasserausgabe\",\n        \"es\": \"Salida de Agua\",\n        \"fr\": \"Sortie d'Eau\",\n        \"it\": \"Uscita dell'Acqua\",\n        \"da\": \"Vandoutput\",\n        \"no\": \"Vannutgang\",\n        \"sv\": \"Vattenutgång\",\n        \"pl\": \"Wydajność wody\",\n        \"ru\": \"Вывод воды\",\n        \"ko\": \"물 출력\"\n      },\n      \"values\": [\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Level 1\",\n            \"nl\": \"Niveau 1\",\n            \"de\": \"Stufe 1\",\n            \"es\": \"Nivel 1\",\n            \"fr\": \"Niveau 1\",\n            \"it\": \"Livello 1\",\n            \"da\": \"Niveau 1\",\n            \"no\": \"Nivå 1\",\n            \"sv\": \"Nivå 1\",\n            \"pl\": \"Poziom 1\",\n            \"ru\": \"Уровень 1\",\n            \"ko\": \"레벨 1\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Level 2\",\n            \"nl\": \"Niveau 2\",\n            \"de\": \"Stufe 2\",\n            \"es\": \"Nivel 2\",\n            \"fr\": \"Niveau 2\",\n            \"it\": \"Livello 2\",\n            \"da\": \"Niveau 2\",\n            \"no\": \"Nivå 2\",\n            \"sv\": \"Nivå 2\",\n            \"pl\": \"Poziom 2\",\n            \"ru\": \"Уровень 2\",\n            \"ko\": \"레벨 2\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Level 3\",\n            \"nl\": \"Niveau 3\",\n            \"de\": \"Stufe 3\",\n            \"es\": \"Nivel 3\",\n            \"fr\": \"Niveau 3\",\n            \"it\": \"Livello 3\",\n            \"da\": \"Niveau 3\",\n            \"no\": \"Nivå 3\",\n            \"sv\": \"Nivå 3\",\n            \"pl\": \"Poziom 3\",\n            \"ru\": \"Уровень 3\",\n            \"ko\": \"레벨 3\"\n          }\n        }\n      ],\n      \"getable\": true,\n      \"setable\": true,\n      \"icon\": \"/assets/icons/water-level.svg\"\n    },\n    \"yeelight_ceil43_mode\": {\n      \"type\": \"enum\",\n      \"title\": {\n        \"en\": \"Mode\",\n        \"nl\": \"Modus\",\n        \"da\": \"Tilstand\",\n        \"de\": \"Modus\",\n        \"es\": \"Modo\",\n        \"fr\": \"Mode\",\n        \"it\": \"Modalita\",\n        \"no\": \"Modus\",\n        \"sv\": \"Lage\",\n        \"pl\": \"Tryb\",\n        \"ru\": \"Режим\",\n        \"ko\": \"모드\"\n      },\n      \"getable\": true,\n      \"setable\": true,\n      \"uiComponent\": \"picker\",\n      \"values\": [\n        {\n          \"id\": \"0\",\n          \"title\": {\n            \"en\": \"Day\",\n            \"nl\": \"Dag\",\n            \"da\": \"Dag\",\n            \"de\": \"Tag\",\n            \"es\": \"Dia\",\n            \"fr\": \"Jour\",\n            \"it\": \"Giorno\",\n            \"no\": \"Dag\",\n            \"sv\": \"Dag\",\n            \"pl\": \"Dzien\",\n            \"ru\": \"День\",\n            \"ko\": \"주간\"\n          }\n        },\n        {\n          \"id\": \"1\",\n          \"title\": {\n            \"en\": \"Night\",\n            \"nl\": \"Nacht\",\n            \"da\": \"Nat\",\n            \"de\": \"Nacht\",\n            \"es\": \"Noche\",\n            \"fr\": \"Nuit\",\n            \"it\": \"Notte\",\n            \"no\": \"Natt\",\n            \"sv\": \"Natt\",\n            \"pl\": \"Noc\",\n            \"ru\": \"Ночь\",\n            \"ko\": \"야간\"\n          }\n        },\n        {\n          \"id\": \"2\",\n          \"title\": {\n            \"en\": \"Color\",\n            \"nl\": \"Kleur\",\n            \"da\": \"Farve\",\n            \"de\": \"Farbe\",\n            \"es\": \"Color\",\n            \"fr\": \"Couleur\",\n            \"it\": \"Colore\",\n            \"no\": \"Farge\",\n            \"sv\": \"Farg\",\n            \"pl\": \"Kolor\",\n            \"ru\": \"Цвет\",\n            \"ko\": \"색상\"\n          }\n        },\n        {\n          \"id\": \"3\",\n          \"title\": {\n            \"en\": \"Flow\",\n            \"nl\": \"Flow\",\n            \"da\": \"Flow\",\n            \"de\": \"Flow\",\n            \"es\": \"Flujo\",\n            \"fr\": \"Flux\",\n            \"it\": \"Flusso\",\n            \"no\": \"Flyt\",\n            \"sv\": \"Flode\",\n            \"pl\": \"Przeplyw\",\n            \"ru\": \"Поток\",\n            \"ko\": \"흐름\"\n          }\n        }\n      ],\n      \"icon\": \"/assets/icons/airpurifier-mode.svg\"\n    }\n  }\n}"
  },
  {
    "path": "docs/mirobot_zonecleanup.md",
    "content": "# Using the \"Go To Target\" and \"Zone Cleanup\" action cards for the Mi Robot.\nBelow are instructions on how to use the zoned cleaning and goto action cards for the Xiaomi Mi Robot. Credits for this tutorial go out to user ciB on the Home Assistant forum.\n\n## Firmware\nThis functionality has recently become available for the v1 version of the Xiaomi Mi Robot. Make sure you update your Mi Robot to the latest available firmware using the Mi Home smartphone app. Disclaimer: in some cases this might result in the token being reset which requires you to find your token again.\n\n## Figuring out coordinates on the map\nUnfortunately there is no easy way without rooting the device to directly access the map with its coordinates, so you have to do some manual labor. The way the map is created works like this: the starting point of the map (which should be right in front of the dockings station - where your robot starts off at) is somewhere around [25500,25500] and the map is then build around this coordinates.\nAll you have to do is figure out a grid and then read off the coordinates that you need:\n* Step 1: Make sure your docking station is at a fixed position (so your starting point will ALWAYS be the same).\n* Step 2: If not yet created, let your robot create a full map of your apartment/flat by starting the cleaning from the Mi Home App.\n* Step 3: Use the \"go to target\" action card to send the robot to places while you have the Mi Home app open. It will then show you where you have send the robot. Increasing the x coordinate will move the robot relative to the starting point to the right (decreasing to the left), increasing the y coordinate will move the robot relative to the starting point to the top (decreasing to the bottom). With some trial and error you will be able to find the right coordinates for places you want to go and for the zones you want to clean.\n![Home Location](homezone.png?raw=true)\n\n## Using the \"Go To Target\" action card\nThis card requires you to enter the x and y coordinate of a location where you want to go. If you have not figured out the right coordinates yet you should use the Mi Home smartphone app where you can see where your Mi Robot is actually going to go after sending in some coordinates.\n\n## Using the \"Zone Cleanup\" action card\nThis action card requires you to enter one or multiple zones for cleaning. A zone takes two coordinates, the first one is the bottom left corner, the other one the top right corner and at the end you can specify the number of times the zone needs to be cleaned. So a single zone would look something like this: [25200, 27500, 27250, 30250, 1]. You can specify multiple zones by seperating them by a comma. So a zone cleanup with two zones would look like this: [25200, 27500, 27250, 30250, 1], [27000, 22250, 28200, 27000, 1].\n\nThat's it. Enjoy zone cleaning.\n"
  },
  {
    "path": "docs/obtain_token.md",
    "content": "# Obtain Mi Home device token\nUse any of these methods to obtain the device token for the supported miio devices.\n\n## Method 1 - Obtain device token from Mi home account\nToken info might be gathered using Mi `home/device_list` API method that returns the list of devices. There are two existing desktop app implementations to make this easier:\n* Get [Mi Home Devices Token](https://github.com/Maxmudjon/Get_MiHome_devices_token/releases) - allows to view device list with device info such as `ip`, `token`, etc.\n* Get [Mi Home Toolkit](https://github.com/ApplY3D/mi-home-toolkit/releases) - displays the same info as the previous one + `did`, but also allows to control devices, for example - toggling LAN/Developer mode for bulbs.\n\n\n## Method 2 - Obtain device token for miio devices that hide their token after setup\nUse one of these methods to obtain the device token for devices that hide their tokens after setup in the Mi Home App (like the Mi Robot Vacuum Cleaner with firmware 3.3.9_003077 or higher). This is usually the case for most Mi Home devices. The latest versions of the Mi Home smartphone app dont hold the token anymore so before you begin with any of these methods you will need to install an older version of the smartphone app. Version 5.0.19 works for sure with the 1st gen Vacuum Robot, for the 2nd gen (S50) you should try version 3.3.9_5.0.30. Android users can find older version of the app [here](https://www.apkmirror.com/apk/xiaomi-inc/mihome/).\n\n### Android users\n#### Rooted Android Phones\n* Setup your Android device with the Mi Home app version 5.0.19 or lower\n* Install [aSQLiteManager](https://play.google.com/store/apps/details?id=dk.andsen.asqlitemanager) on your phone\n* Use a file browser with granted root privilege and browse to /data/data/com.xiaomi.smarthome/databases/\n* Copy miio2.db to an accessable location\n* Open your copy of miio2.db with aSQLiteManager and execute the query \"select token from devicerecord where localIP is '192.168.0.1'\" where you replace the IP address with the IP address of the device you want to get the token from. It will show you the 32 character device token for your Mi Home device.\n\n#### Non-Rooted Android Phones\n##### Extract token from log file\nThis method will only work when you install the Mi Home app version v5.4.54. You can find it [here](https://android-apk.org/com.xiaomi.smarthome/43397902-mi-home/). It looks like Xiaomi made a mistake in this app version where the log file written to internal memory exposes the device tokens of your Xiaomi miio devices.\n* Setup your Android device with the Mi Home app version 5.4.54\n* Log in with you Xiaomi account\n* Use a file explorer to navigate to /sdcard/SmartHome/logs/Plug_Devicemanager/\n* Look for a log file named yyyy-mm-dd.txt and open it with a file editor\n* Search for a string similar to this with you device name and token\n```\n{\"did\":\"117383849\",\"token\":\"90557f1373xxxxxxx8314a74d547b5\",\"longitude\":\"x\",\"latitude\":\"y\",\"name\":\"Mi Robot Vacuum\",\"pid\":\"0\",\"localip\":\"192.168.88.68\",\"mac\":\"40:31:3C:AA:BB:CC\",\"ssid\":\"Your AP Name\",\"bssid\":\"E4:8D:8C:EE:FF:GG\",\"parent_id\":\"\",\"parent_model\":\"\",\"show_mode\":1,\"model\":\"rockrobo.vacuum.v1\",\"adminFlag\":1,\"shareFlag\":0,\"permitLevel\":16,\"isOnline\":true,\"desc\":\"Zoned cleanup\",\"extra\":{\"isSetPincode\":0,\"fw_version\":\"3.3.9_003460\",\"needVerifyCode\":0,\"isPasswordEncrypt\":0},\"event\":{\"event.back_to_dock\":\"{\\\"timestamp\\\":1548817566,\\\"value\\\":[0]}\n```\n* Copy the token from this string and you are done.\n\n##### Extract token from a backup on Android phones that allow non-encrypted backups\n* Setup your Android device with the Mi Home app\n* Enable developer mode and USB debugging on your phone and connect it to your computer\n* Get the ADB tool\n   - for Windows: https://developer.android.com/studio/releases/platform-tools.html\n   - for Mac: `brew install adb`\n* Create a backup of the Mi Home app:\n   - for Windows: `.\\adb backup -noapk com.xiaomi.smarthome -f mi-home-backup.ab`\n   - for Mac: `adb backup -noapk com.xiaomi.smarthome -f mi-home-backup.ab`\n* On your phone you must confirm the backup. Do not enter any password and press button to make the backup\n* (Windows Only) Get ADB Backup Extractor and install it: https://sourceforge.net/projects/adbextractor/\n* Extract all files from the backup on your computer:\n   - for Windows: `java.exe -jar ../android-backup-extractor/abe.jar unpack mi-home-backup.ab backup.tar`\n   - for Mac & Unix: `( printf \"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\" ; tail -c +25 mi-home-backup.ab) |  tar xfvz -`\n* Unzip the \".tar\" file\n* Open /com.xiaomi.smarthome/db/miio2.db with a SQLite browser (for instance http://sqlitebrowser.org/)\n* Execute the query \"select token from devicerecord where localIP is '192.168.0.1'\" where you replace the IP address with the IP address of the Mi Home device you want to get the token from. It will show you the 32 character device token for your Mi Home device.\n\n##### Extract token from a backup on Android phones that do not allow non-encrypted backups\n* Use the steps from above but install Java and use [backup extractor](https://github.com/nelenkov/android-backup-extractor) to extract the encrypted backup.\n```\n$ java -jar abe-all.jar unpack mi-home-backup.ab unpack mi-home-backup.tar\nThis backup is encrypted, please provide the password\nPassword:\n\n# extract without header trick\n$ tar -zxf mi-home-backup.tar\n\n# db file is accessible\n$ ls apps/com.xiaomi.smarthome/db/\ngeofencing.db\t\t\t\tgoogle_app_measurement.db\t\tmiio.db\t\t\t\t\tmiio2.db\t\t\t\tmistat.db\ngeofencing.db-journal\t\t\tgoogle_app_measurement.db-journal\tmiio.db-journal\t\t\t\tmiio2.db-journal\t\t\tmistat.db-journal\n```\n\n### iOS users\n### Non-Jailbroken iOS users\n* Setup your iOS device with the Mi Home app\n* Create an unencrypted backup of your iOS device on your computer using iTunes. In case you are unable to disable encryption you probably have a profile preventing this that enforces certain security policies (like work related accounts). Delete these profiles or use another iOS device to continu.\n* Install iBackup Viewer from [here](http://www.imactools.com/iphonebackupviewer/) (another tool that was suggested can be found [here](https://github.com/richinfante/iphonebackuptools)).\n* Navigate to your BACKUPS and find the name of your iOS device in the list. Open this backup by clicking the triangle in front of it and then click on raw data.\n* Sort the view by name and find the folder com.xiaomi.mihome and highlight it (it's somewhere at the end). After highlighting it click on the cockwheel above the results and select \"Save selected files\" from here and choose a location to save the files.\n* Navigate to the com.xiaomi.mihome folder which you just saved somewhere and inside this folder navigate to the /Documents/ subfolder. In this folder there is a file named <userid>_mihome.sqlite where your userid is specific for your account.\n* Open this file with a SQLite browser (for instance http://sqlitebrowser.org/)\n* Execute the query \"select ZTOKEN from ZDEVICE where ZLOCALIP is '192.168.0.1'\" where you replace the IP address with the IP address of the Mi Home device you want to get the token from. It will show you the 32 character device token for your Mi Home device.\n* The latest Mi Home app store the tokens encrypted into a 96 character key and require an extra step to decode this into the actual token. Visit [this](http://aes.online-domain-tools.com/) website and enter the details as shown below:\n** __Input type:__ text\n    * __Input text (hex):__ your 96 character key\n    * __Selectbox Plaintext / Hex:__ Hex\n    * __Function:__ AES\n    * __Mode:__ ECB\n    * __Key (hex):__ 00000000000000000000000000000000\n    * __Selectbox Plaintext / Hex:__ Hex\n* Hit the decrypt button. Your token are the first two lines of the right block of code. These two lines should contain a token of 32 characters and should be the correct token for your device.\n* If this tutorial did not work for you, [here](https://github.com/mediter/miio/blob/master/docs/ios-token-without-reset.md) is another that might work.\n\n## Jailbroken iOS users\n* Setup your iOS device with the Mi Home app\n* Use something like Forklift sFTP to connect to your iOS device and copy this file to your computer: /var/mobile/Containers/Data/Application/[UUID]/Documents/USERID_mihome.sqlite (where UUID is a specific number for your device)\n    * username: root\n    * IP address: your phones IP address\n    * password: alpine (unless you changed it something else)\n* Open this file with a SQLite browser (for instance http://sqlitebrowser.org/)\n* Execute the query \"select ZTOKEN from ZDEVICE where ZLOCALIP is '192.168.0.1'\" where you replace the IP address with the IP address of the Mi Home device you want to get the token from. It will show you the 32 character device token for your Mi Home device.\n* The latest Mi Home app store the tokens encrypted into a 96 character key and require an extra step to decode this into the actual token. Visit [this](http://aes.online-domain-tools.com/) website and enter the details as shown below:\n    * __Input type:__ text\n    * __Input text (hex):__ your 96 character key\n    * __Selectbox Plaintext / Hex:__ Hex\n    * __Function:__ AES\n    * __Mode:__ ECB\n    * __Key (hex):__ 00000000000000000000000000000000\n    * __Selectbox Plaintext / Hex:__ Hex\n* Hit the decrypt button. Your token are the first two lines of the right block of code. These two lines should contain a token of 32 characters and should be the correct token for your device.\n\n## Method 3 - Obtain Xiaomi Gateway device token\nThis method is specifically for the Xiaomi Gateway.\n\n* Open Mi Home App in your Android device.\n* Select your xiaomi device.\n* Then click on the 3 dots at the top right of the screen.\n* Then click on \"About\".\n* Tap on the version number at the bottom of the screen repeatedly.\n* You should see now 2 extra options listed.\n* Tap on the second option: \"Hub info\".\n* There you can find the device token.\n\n## Method 4 - Nodejs Command Line Tool from the miIO Device library\nThe author of the miIO Device Library which is used by this Homey app has also created a nodejs command line tool for retrieving device tokens. Please follow the steps in [these instructions](https://github.com/aholstenson/miio/blob/master/docs/management.md) to retrieve the token for the supported miio devices. Be aware that some devices hide their token after the device has been setup in the Mi Home app. Retrieving tokens for these devices will not work with this method but require method 3.\n\n## Method 5a - Packet Sender Tool\nDuring setup of Mi Home devices the device tokens an be retrieved by sending a ping command to the device. This method uses a tool called Packet Sender which you will need to download. Choose the portable version which does not require installation.\n* Download the portable version of [Packet Sender](https://packetsender.com/download).\n* Reset the device following the instructions from the device manual, this usually means holding one or two buttons for 10 seconds. This will reset all device settings including the Wi-Fi settings.\n* After reset the device will create a it's own Wi-Fi network. This network will have a name related to the device and is used for configuring the device but will also allow us to retrieve the token. Connect to this Wi-Fi network with your computer which has Packet Sender running.\n* Open Packet Sender and enter the following details.\n    * HEX: 21310020ffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n    * IP: 192.168.8.1\n    * Port: 54321\n    * Protocol dropdown: UDP\n* Click send and the device will respond with an answer which contains the unique device token. In the last 16 bytes (32 characters) of the devices response is the device token. Copy and save it somewhere.\n* Disconnect your computer from the devices network, you can now use the Mi Home app to setup the device and connect it to your Wi-Fi network.\n\n## Method 5b - netcat and Wireshark / tcpdump\nLike above you can also use this shell command to send the magic package:\n\n```sh\necho -ne '\\x21\\x31\\x00\\x20\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff' | nc -u 192.168.8.1 54321\n```\n\nWhile running this you have to listen with Wireshark or tcpdump for UDP packages sent as anser by the robot.\nExtract the last 16 bytes of the answer and convert them to a (32 characters) hexadecimal string using `xxd -p`.\n\n## Method 5c - netcat with hexdump\nLike above you can also use this shell command to send the magic package (assuming you're using a Macbook and connecting the device's wifi with `en0` network interface):\n\n```sh\n$ echo -n '\\x21\\x31\\x00\\x20'`printf '\\xff%.0s' {1..28}`|nc -u `ifconfig en0|grep 'inet '|awk -F '[. ]' '{print $2\".\"$3\".\"$4\".\"1}'` 54321 |hexdump -s 16 -e '\"token: \" 16/1 \"%02x\" \"\\n\"' \ntoken: f3940a86c4cd42f8787e37f98d2271ce\n```\n\n## Method 6 - telnet with root access\n> discovered by [#slavikme](https://github.com/slavikme)\n\nIn some devices, like \"Mi Home Security Camera 360\" (and maybe others), you are able to access the filesystem of the device using telnet.\n* Reset the device following the instructions from the device manual, this usually means holding one or two buttons for 10 seconds. This will reset all device settings including the Wi-Fi settings. Or you can just delete the device from Mi Home app, that will reset the device for you.\n* After reset the device will create it's own Wi-Fi network. This network will have a name related to the device and is used for configuring the device but will also allow us to retrieve the token. Connect to this Wi-Fi network with your computer which has a `telnet` command installed.\n* Find out Wi-Fi's gateway address ([This article](https://www.lifewire.com/how-to-find-your-default-gateway-ip-address-2626072) can help). Let's say that it is `192.168.14.1`.\n* Create a telnet connection to this addres:\n  ```bash\n  telnet 192.168.14.1\n  ```\n* It will ask you to enter a login. Just write `root`:\n  ```bash\n  Trying 192.168.14.1...\n  Connected to 192.168.14.1.\n  Escape character is '^]'.\n  mijia-camera login: root\n  #\n  ```\n* Now you have a root shell access to device's filesystem.\n* Get the hex token using the following command:\n  ```bash\n  /usr/sbin/nvram get miio_token | hd -n16 -e '16/1 \"%02x \" \"\\n\"' | sed '2!d; s/ //g'\n  ```\n  The output should be something like this:\n  ```\n  3268786f5730305661445a6375467039\n  ```\n* If you are not getting 32 characters hexadecimal string, then just run the command `/usr/sbin/nvram get miio_token` and convert it using `xxd -p` or [this tool](https://www.rapidtables.com/convert/number/ascii-to-hex.html) (don't forget to remove the space delimiter) to hexadecimal representation.  \n  Command output example:\n  ```bash\n  # /usr/sbin/nvram get miio_token\n  2hxoW00VaDZcuFp9\n  ```\n"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/zhimi.airfresh.va2\n// https://home.miot-spec.com/spec/zhimi.airfresh.va4\n\nclass MiAirFreshDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_power\", [value ? \"on\" : \"off\"], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('onoff.ptc', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_ptc_state\", [value ? \"on\" : \"off\"], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('airpurifier_zhimi_airfresh_mode', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_mode\", [value], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      const led = await this.miio.call(\"set_led_level\", [newSettings.led ? 0 : 2], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"buzzer\")) {\n      const buzzer = await this.miio.call(\"set_buzzer\", [newSettings.buzzer ? \"on\" : \"off\"], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"childLock\")) {\n      const childlock = await this.miio.call(\"set_child_lock\", [newSettings.childLock ? \"on\" : \"off\"], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_prop\", [\"power\", \"temp_dec\", \"aqi\", \"co2\", \"humidity\", \"mode\", \"buzzer\", \"child_lock\", \"led_level\", \"f1_hour_used\", \"motor1_speed\" ], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"onoff\", result[0] === \"on\" ? true : false);\n      await this.updateCapabilityValue(\"measure_pm25\", parseInt(result[2]));\n      await this.updateCapabilityValue(\"measure_co2\", parseInt(result[3]));\n      await this.updateCapabilityValue(\"measure_humidity\", parseFloat(result[4]));\n\n      /* settings */\n      await this.updateSettingValue(\"buzzer\", result[6] == \"on\" ? true : false);\n      await this.updateSettingValue(\"childLock\", result[7] == \"on\" ? true : false);\n      await this.updateSettingValue(\"led\", result[8] === 0 || 1 ? true : false);\n      await this.updateSettingValue(\"f1_hour_used\", Math.round(result[9] / 24) + \" days used\");\n      await this.updateSettingValue(\"motor_speed\", result[10]);\n\n      /* mode capability */\n      if (this.getCapabilityValue('airpurifier_zhimi_airfresh_mode') !== result[5]) {\n        const previous_mode = this.getCapabilityValue('airpurifier_zhimi_airfresh_mode');\n        await this.setCapabilityValue('airpurifier_zhimi_airfresh_mode', result[5]);\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, {\"new_mode\": mode, \"previous_mode\": previous_mode }).catch(error => { this.error(error) });\n      }\n\n      /* model specific capabilities */\n      switch (this.getStoreValue('model')) {\n        case 'zhimi.airfresh.va2':\n          await this.updateCapabilityValue(\"measure_temperature\", result[1] * 0.1);\n          break;\n        case 'zhimi.airfresh.va4':\n          await this.updateCapabilityValue(\"measure_temperature\", result[1]);\n          await this.util.sleep(2000);\n          const result_va4 = await this.miio.call(\"get_prop\", [\"ptc_state\"], { retries: 1 });\n          if (!this.hasCapability('onoff.ptc')) { await this.addCapability('onoff.ptc')};\n          await this.updateCapabilityValue(\"onoff.ptc\", result_va4[0] === \"on\" ? true : false);\n          break;\n        default:\n          break;\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n  async handleModeEvent(mode) {\n    try {\n      \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = MiAirFreshDevice;"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Smartmi Fresh Air System (WiFi)\",\n    \"nl\": \"Smartmi Fresh Air System (WiFi)\",\n    \"da\": \"Smartmi Friskluftsystem (WiFi)\",\n    \"de\": \"Smartmi Frischluftsystem (WiFi)\",\n    \"es\": \"Sistema de Aire Fresco Smartmi (WiFi)\",\n    \"fr\": \"Système d'air frais Smartmi (WiFi)\",\n    \"it\": \"Sistema di Aria Fresca Smartmi (WiFi)\",\n    \"no\": \"Smartmi Friskluftsystem (WiFi)\",\n    \"sv\": \"Smartmi Friskluftsystem (WiFi)\",\n    \"pl\": \"System świeżego powietrza Smartmi (WiFi)\",\n    \"ru\": \"Система свежего воздуха Smartmi (WiFi)\",\n    \"ko\": \"스마트미 신선한 공기 시스템 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/airfresh_zhimi_airfresh/assets/images/large.jpg\",\n    \"small\": \"drivers/airfresh_zhimi_airfresh/assets/images/small.jpg\"\n  },\n  \"class\": \"airpurifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"airpurifier_zhimi_airfresh_mode\",\n    \"measure_temperature\",\n    \"measure_humidity\",\n    \"measure_pm25\",\n    \"measure_co2\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.ptc\": {\n      \"title\": {\n        \"en\": \"Heat\",\n        \"nl\": \"Verwarmen\",\n        \"da\": \"Varme\",\n        \"de\": \"Heizen\",\n        \"es\": \"Calentar\",\n        \"fr\": \"Chauffer\",\n        \"it\": \"Riscaldare\",\n        \"no\": \"Varme\",\n        \"sv\": \"Värme\",\n        \"pl\": \"Grzanie\",\n        \"ru\": \"Нагрев\",\n        \"ko\": \"열기\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiAirFreshDriver extends Driver {}\n\nmodule.exports = MiAirFreshDriver;"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuraciones de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\",\n      \"pt\": \"Configurações do usuário\",\n      \"fi\": \"Käyttäjäasetukset\",\n      \"tr\": \"Kullanıcı Ayarları\",\n      \"zh\": \"用户设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"Светодиод\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summer\",\n          \"de\": \"Summer\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Buzzer\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Summer\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Brzęczyk\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"버저\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnelås\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo para niños\",\n          \"fr\": \"Verrouillage enfant\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barnelås\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada rodzicielska\",\n          \"ru\": \"Блокировка от детей\",\n          \"ko\": \"잠금\"\n        }\n      },\n      {\n        \"id\": \"f1_hour_used\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter life\",\n          \"nl\": \"Filter duur\",\n          \"da\": \"Filterliv\",\n          \"de\": \"Filterlebensdauer\",\n          \"es\": \"Vida del filtro\",\n          \"fr\": \"Durée de vie du filtre\",\n          \"it\": \"Vita del filtro\",\n          \"no\": \"Filterlevetid\",\n          \"sv\": \"Filterliv\",\n          \"pl\": \"Żywotność filtra\",\n          \"ru\": \"Срок службы фильтра\",\n          \"ko\": \"필터 수명\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"motor_speed\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Motorspeed\",\n          \"nl\": \"Motorsnelheid\",\n          \"da\": \"Motoreffekt\",\n          \"de\": \"Motorgeschwindigkeit\",\n          \"es\": \"Velocidad del motor\",\n          \"fr\": \"Vitesse du moteur\",\n          \"it\": \"Velocità del motore\",\n          \"no\": \"Motoreffekt\",\n          \"sv\": \"Motoreffekt\",\n          \"pl\": \"Prędkość silnika\",\n          \"ru\": \"Скорость двигателя\",\n          \"ko\": \"모터 속도\"\n        },\n        \"value\": \"400\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"pt\": \"Configurações do dispositivo\",\n      \"fi\": \"Laitteen asetukset\",\n      \"tr\": \"Aygıt Ayarları\",\n      \"zh\": \"设备设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh_miot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/zhimi.airfresh.ua1\n\n// [{'did': 'prop.2.1', 'siid': 2, 'piid': 1, 'code': 0, 'value': False}, {'did': 'prop.2.5', 'siid': 2, 'piid': 5, 'code': 0, 'value': 1}, {'did': 'prop.2.6', 'siid': 2, 'piid': 6, 'code': 0, 'value': False}, {'did': 'prop.5.1', 'siid': 5, 'piid': 1, 'code': 0, 'value': False}, {'did': 'prop.6.1', 'siid': 6, 'piid': 1, 'code': 0, 'value': True}, {'did': 'prop.7.3', 'siid': 7, 'piid': 3, 'code': 0, 'value': 0}]\n\nconst mapping = {\n  \"zhimi.airfresh.ua1\": \"properties_default\",\n  \"zhimi.airfresh.*\": \"properties_default\",\n};\n\nconst properties = {\n  \"properties_default\": {\n    \"get_properties\": [\n      { did: \"onoff\", siid: 2, piid: 1 }, // onoff\n      { did: \"heat\", siid: 2, piid: 6 }, // onoff.ptc\n      { did: \"fanlevel\", siid: 2, piid: 5 }, // airpurifier_zhimi_fanlevel\n      { did: \"fault\", siid : 2, piid: 2 }, // settings.error\n      { did: \"buzzer\", siid : 6, piid: 1 }, // settings.buzzer\n      { did: \"led\", siid : 7, piid: 3 }, // settings.buzzer\n      { did: \"childLock\", siid : 5, piid: 1 }, // settings.childLock\n      { did: \"f1_hour_used\", siid : 4, piid: 1 }, // settings.f1_hour_used\n    ]\n  }\n}\n\nclass MiAirFreshMiotDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['zhimi.airfresh.*']];\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: 2, piid: 1, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('onoff.ptc', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: 2, piid: 6, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('airpurifier_zhimi_fanlevel', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: 2, piid: 5, value: +value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      const led = await this.miio.call(\"set_properties\", [{ siid: 7, piid: 3, value: newSettings.led === 0 ? false : true }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"buzzer\")) {\n      const buzzer = await this.miio.call(\"set_properties\", [{ siid: 6, piid: 1, value: newSettings.buzzer }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"childLock\")) {\n      const childlock = await this.miio.call(\"set_properties\", [{ siid: 5, piid: 1, value: newSettings.childLock }], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const onoff = result.find(obj => obj.did === 'onoff');\n      const onoff_ptc = result.find(obj => obj.did === 'heat');\n      const fanlevel = result.find(obj => obj.did === 'fanlevel');\n\n      const fault = result.find(obj => obj.did === 'fault');\n      const buzzer = result.find(obj => obj.did === 'buzzer');\n      const led = result.find(obj => obj.did === 'led');\n      const childLock = result.find(obj => obj.did === 'childLock');\n      const f1_hour_used = result.find(obj => obj.did === 'f1_hour_used');\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"onoff\", onoff.value);\n      await this.updateCapabilityValue(\"onoff.ptc\",  onoff_ptc.value);\n      await this.updateCapabilityValue(\"airpurifier_zhimi_fanlevel\", fanlevel.value.toString());\n\n      /* settings */\n      await this.updateSettingValue(\"buzzer\", buzzer.value);\n      await this.updateSettingValue(\"led\", led.value === 0 ? false : true);\n      await this.updateSettingValue(\"childLock\", childLock.value);\n      await this.updateSettingValue(\"f1_hour_used\", Math.round(f1_hour_used.value / 60) + \" hours used\");\n\n      const error = fault.value === 0 ? 'No error' : fault.value;\n      await this.updateSettingValue(\"error\", error);\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = MiAirFreshMiotDevice;"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n    \"nl\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n    \"da\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n    \"de\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n    \"es\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n    \"fr\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n    \"it\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n    \"no\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n    \"sv\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n    \"pl\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n    \"ru\": \"Smartmi Fresh Air System MIoT (WiFi)\",\n    \"ko\": \"Smartmi Fresh Air System MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/airfresh_zhimi_airfresh_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/airfresh_zhimi_airfresh_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"airpurifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"onoff.ptc\",\n    \"airpurifier_zhimi_fanlevel\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.ptc\": {\n      \"title\": {\n        \"en\": \"Heat\",\n        \"nl\": \"Verwarmen\",\n        \"da\": \"Varme\",\n        \"de\": \"Heizen\",\n        \"es\": \"Calor\",\n        \"fr\": \"Chaleur\",\n        \"it\": \"Calore\",\n        \"no\": \"Varme\",\n        \"sv\": \"Värme\",\n        \"pl\": \"Ciepło\",\n        \"ru\": \"Тепло\",\n        \"ko\": \"난방\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiAirFreshMiotDriver extends Driver {}\n\nmodule.exports = MiAirFreshMiotDriver;"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"LED\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Sommer\",\n          \"de\": \"Summton\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Buzzer\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Buzzer\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Brzęczyk\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"부저\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnelås\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo infantil\",\n          \"fr\": \"Verrouillage enfant\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barnelås\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada rodzicielska\",\n          \"ru\": \"Родительский контроль\",\n          \"ko\": \"잠금 기능\"\n        }\n      },\n      {\n        \"id\": \"f1_hour_used\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter life\",\n          \"nl\": \"Filter duur\",\n          \"da\": \"Filtreringens liv\",\n          \"de\": \"Filterlebensdauer\",\n          \"es\": \"Vida del filtro\",\n          \"fr\": \"Durée de vie du filtre\",\n          \"it\": \"Durata del filtro\",\n          \"no\": \"Filterliv\",\n          \"sv\": \"Filterlivslängd\",\n          \"pl\": \"Żywotność filtra\",\n          \"ru\": \"Срок службы фильтра\",\n          \"ko\": \"필터 수명\"\n        },\n        \"value\": \"0%\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/airfresh_zhimi_airfresh_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/airfryer_careli_miot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/careli.fryer.maf05a // Xiaomi Smart Air Fryer Pro 4L\n// https://home.miot-spec.com/spec/careli.fryer.ybaf04 // KitchenMi Smart Air Fryer 6007WAB\n// https://home.miot-spec.com/spec/careli.fryer.ybaf03 // KitchenMi Smart Air Fryer 6007WA\n// https://home.miot-spec.com/spec/careli.fryer.maf02c // Mi Smart Air Fryer (3.5L)\n// https://home.miot-spec.com/spec/careli.fryer.maf07  // Mi Smart Air Fryer (3.5L)\n// https://home.miot-spec.com/spec/careli.fryer.maf02  // Mi Smart Air Fryer (3.5L)\n// https://home.miot-spec.com/spec/careli.fryer.maf10a  // Mi Smart Air Fryer 6.5L\n\n\nconst mapping = {\n  \"careli.fryer.maf05a\": \"properties_default\",\n  \"careli.fryer.ybaf04\": \"properties_default\",\n  \"careli.fryer.ybaf03\": \"properties_default\",\n  \"careli.fryer.maf02c\": \"properties_default\",\n  \"careli.fryer.maf07\": \"properties_default\",\n  \"careli.fryer.maf02\": \"properties_default\",\n  \"careli.fryer.maf10a\": \"properties_maf10a\",\n  \"careli.fryer.*\": \"properties_default\",\n};\n\nconst properties = {\n  \"properties_default\": {\n    \"get_properties\": [\n      { did: \"status\", siid: 2, piid: 1 }, // airfryer_careli_mode\n      { did: \"fault\", siid : 2, piid: 2 }, // settings.error\n      { did: \"target_time\", siid: 2, piid: 3 }, // airfryer_careli_target_time\n      { did: \"target_temperature\", siid: 2, piid: 4 }, // airfryer_careli_target_temperature\n      { did: \"food_quantity\", siid: 3, piid: 6 }, // airfryer_careli_food_quantity\n      { did: \"preheat_switch\", siid: 3, piid: 7 } // onoff.preheat\n    ],\n    \"set_properties\": {\n      \"start_cook\": { siid: 2, aiid: 1, did: \"call-2-1\", in: [] },\n      \"stop_cook\": { siid: 2, aiid: 2, did: \"call-2-2\", in: [] }\n    }\n  },\n  \"properties_maf10a\": {\n    \"get_properties\": [\n      { did: \"status\", siid: 2, piid: 1 }, // airfryer_careli_mode\n      { did: \"fault\", siid : 2, piid: 2 }, // settings.error\n      { did: \"target_time\", siid: 2, piid: 3 }, // airfryer_careli_target_time\n      { did: \"target_temperature\", siid: 2, piid: 4 } // airfryer_careli_target_temperature\n    ],\n    \"set_properties\": {\n      \"start_cook\": { siid: 2, aiid: 1, did: \"call-2-1\", in: [] },\n      \"stop_cook\": { siid: 2, aiid: 2, did: \"call-2-2\", in: [] }\n    }\n  }\n}\n\nconst modes = {\n  0: \"Shutdown\",\n  1: \"Standby\",\n  2: \"Pause\",\n  3: \"Schedule\",\n  4: \"Cooking\",\n  5: \"Preheat\",\n  6: \"Cooked\",\n  7: \"Preheat finished\",\n  8: \"Preheat paused\",\n  9: \"Pause2\"\n};\n\nclass AirfryerCareliMiotDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['careli.fryer.*']];\n\n      this.errorCodes = {\n        0: \"No Error\",\n        1: \"E1\",\n        2: \"E2\"\n      }\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            if (value) {\n              return await this.miio.call(\"action\", this.deviceProperties.set_properties.start_cook, { retries: 1 });\n            } else {\n              return await this.miio.call(\"action\", this.deviceProperties.set_properties.stop_cook, { retries: 1 });\n            }\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('airfryer_careli_target_time', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: 2, piid: 3, value: +value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('airfryer_careli_target_temperature', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: 2, piid: 4, value: +value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('onoff.preheat', async ( value ) => {\n        try {\n          if (this.miio) {\n            if (value) {\n              return await this.miio.call(\"set_properties\", [{ siid: 3, piid: 7, value: 2 }], { retries: 1 });\n            } else {\n              return await this.miio.call(\"set_properties\", [{ siid: 3, piid: 7, value: 1 }], { retries: 1 });\n            }\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('airfryer_careli_food_quantity', async ( value ) => {9\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: 3, piid: 6, value: +value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const status = result.find(obj => obj.did === 'status');\n      const fault = result.find(obj => obj.did === 'fault');\n      const target_time = result.find(obj => obj.did === 'target_time');\n      const target_temperature = result.find(obj => obj.did === 'target_temperature');\n      const food_quantity = result.find(obj => obj.did === 'food_quantity');\n      const onoff_preheat = result.find(obj => obj.did === 'preheat_switch');\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"airfryer_careli_target_time\", target_time.value);\n      await this.updateCapabilityValue(\"airfryer_careli_target_temperature\", target_temperature.value);\n\n      if (food_quantity !== undefined) {\n        await this.updateCapabilityValue(\"airfryer_careli_food_quantity\", food_quantity.value.toString());\n      }\n\n      /* settings */\n      const error = this.errorCodes[fault.value];\n      await this.updateSettingValue(\"error\", error);\n\n      /* onoff */\n      switch (status.value) {\n        case 4:\n        case 5:\n        case 6:\n        case 7:\n          await this.updateCapabilityValue(\"onoff\", true);\n          break;\n        default:\n          await this.updateCapabilityValue(\"onoff\", false);\n          break;\n      }\n\n      /* onoff.preheat */\n      if (onoff_preheat !== undefined) {\n        switch (onoff_preheat.value) {\n          case 2:\n            await this.updateCapabilityValue(\"onoff.preheat\", true);\n            break;\n          default:\n            await this.updateCapabilityValue(\"onoff.preheat\", false);\n            break;\n        }\n      }\n\n      /* mode capability */\n      if (this.getCapabilityValue('airfryer_careli_mode') !== status.value.toString()) {\n        const previous_mode = this.getCapabilityValue('airfryer_careli_mode');\n        await this.setCapabilityValue('airfryer_careli_mode', status.value.toString());\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, {\"new_mode\": modes[status.value], \"previous_mode\": modes[+previous_mode] }).catch(error => { this.error(error) });\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = AirfryerCareliMiotDevice;"
  },
  {
    "path": "drivers/airfryer_careli_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Air Fryers MIoT (WiFi)\",\n    \"nl\": \"Air Fryers MIoT (WiFi)\",\n    \"da\": \"Air Fryers MIoT (WiFi)\",\n    \"de\": \"Air Fryers MIoT (WiFi)\",\n    \"es\": \"Air Fryers MIoT (WiFi)\",\n    \"fr\": \"Air Fryers MIoT (WiFi)\",\n    \"it\": \"Air Fryers MIoT (WiFi)\",\n    \"no\": \"Air Fryers MIoT (WiFi)\",\n    \"sv\": \"Air Fryers MIoT (WiFi)\",\n    \"pl\": \"Air Fryers MIoT (WiFi)\",\n    \"ru\": \"Air Fryers MIoT (WiFi)\",\n    \"ko\": \"Air Fryers MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/airfryer_careli_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/airfryer_careli_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"airfryer\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"airfryer_careli_mode\",\n    \"airfryer_careli_target_time\",\n    \"airfryer_careli_target_temperature\",\n    \"onoff.preheat\",\n    \"airfryer_careli_food_quantity\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.preheat\": {\n      \"title\": {\n        \"en\": \"Preheat switch\",\n        \"nl\": \"Preheat schakelaar\",\n        \"da\": \"Forvarmingskontakt\",\n        \"de\": \"Vorheizschalter\",\n        \"es\": \"Interruptor de precalentamiento\",\n        \"fr\": \"Interrupteur de préchauffage\",\n        \"it\": \"Interruttore di preriscaldamento\",\n        \"no\": \"Forvarmingsbryter\",\n        \"sv\": \"Förvärmningsbrytare\",\n        \"pl\": \"Przełącznik nagrzewania\",\n        \"ru\": \"Выключатель предварительного нагрева\",\n        \"ko\": \"예열 스위치\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/airfryer_careli_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass AirfryerCareliMiotDriver extends Driver {}\n\nmodule.exports = AirfryerCareliMiotDriver;"
  },
  {
    "path": "drivers/airfryer_careli_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Consumables\",\n      \"nl\": \"Verbruiksartikelen\",\n      \"da\": \"Forbrugsvarer\",\n      \"de\": \"Verbrauchsmaterialien\",\n      \"es\": \"Consumibles\",\n      \"fr\": \"Consommables\",\n      \"it\": \"Consumi\",\n      \"no\": \"Forbruksartikler\",\n      \"sv\": \"Förbrukningsvaror\",\n      \"pl\": \"Materiały eksploatacyjne\",\n      \"ru\": \"Расходные материалы\",\n      \"ko\": \"소모품\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_threshold\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Alarm threshold\",\n          \"nl\": \"Alarm ondergrens\",\n          \"da\": \"Alarm tærskel\",\n          \"de\": \"Alarmgrenze\",\n          \"es\": \"Umbral de alarma\",\n          \"fr\": \"Seuil d'alarme\",\n          \"it\": \"Soglia di allarme\",\n          \"no\": \"Alarmterskel\",\n          \"sv\": \"Alarmtröskel\",\n          \"pl\": \"Próg alarmowy\",\n          \"ru\": \"Порог тревоги\",\n          \"ko\": \"알람 임계값\"\n        },\n        \"hint\": {\n          \"en\": \"Threshold below which the alarm will be activated.\",\n          \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n          \"da\": \"Tærskel under hvilken alarmen vil blive aktiveret.\",\n          \"de\": \"Schwellenwert, unter dem der Alarm ausgelöst wird.\",\n          \"es\": \"Límite por debajo del cual se activará la alarma.\",\n          \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n          \"it\": \"Soglia al di sotto della quale verrà attivato l'allarme.\",\n          \"no\": \"Terskel under hvilken alarmen vil bli aktivert.\",\n          \"sv\": \"Tröskel under vilken alarmet aktiveras.\",\n          \"pl\": \"Próg poniżej którego alarm zostanie włączony.\",\n          \"ru\": \"Порог, ниже которого будет активирована тревога.\",\n          \"ko\": \"알람이 활성화되는 임계값입니다.\"\n        },\n        \"value\": 20,\n        \"attr\": {\n          \"min\": 1,\n          \"max\": 90\n        }\n      },\n      {\n        \"id\": \"main_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Main brush remaining (%)\",\n          \"nl\": \"Hoofdborstel over (%)\",\n          \"da\": \"Hovedbørste resterende (%)\",\n          \"de\": \"Hauptbürste verbleibend (%)\",\n          \"es\": \"Cepillo principal restante (%)\",\n          \"fr\": \"Brosse principale restante (%)\",\n          \"it\": \"Spazzola principale rimanente (%)\",\n          \"no\": \"Hovedbørste gjenværende (%)\",\n          \"sv\": \"Huvudborste kvar (%)\",\n          \"pl\": \"Pozostało szczotek głównych (%)\",\n          \"ru\": \"Осталось основной щетки (%)\",\n          \"ko\": \"메인 브러시 잔여량 (%)\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"side_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Side brush remaining\",\n          \"nl\": \"Zijborstel over\",\n          \"da\": \"Sidebørste tilbageværende\",\n          \"de\": \"Seitenbürste verbleibend\",\n          \"es\": \"Cepillo lateral restante\",\n          \"fr\": \"Brosse latérale restante\",\n          \"it\": \"Spazzola laterale rimanente\",\n          \"no\": \"Sidebørste gjenværende\",\n          \"sv\": \"Sidoborste kvar\",\n          \"pl\": \"Pozostało szczotek bocznych\",\n          \"ru\": \"Осталось боковой щетки\",\n          \"ko\": \"사이드 브러시 잔여량\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"filter_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter remaining\",\n          \"nl\": \"Filter over\",\n          \"da\": \"Filter tilbageværende\",\n          \"de\": \"Filter verbleibend\",\n          \"es\": \"Filtro restante\",\n          \"fr\": \"Filtre restant\",\n          \"it\": \"Filtro rimanente\",\n          \"no\": \"Filter gjenværende\",\n          \"sv\": \"Filter kvar\",\n          \"pl\": \"Pozostało filtrów\",\n          \"ru\": \"Осталось фильтра\",\n          \"ko\": \"필터 잔여량\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"total_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total work time\",\n          \"nl\": \"Totale gebruikstijd\",\n          \"da\": \"Samlet arbejdstid\",\n          \"de\": \"Gesamte Arbeitszeit\",\n          \"es\": \"Tiempo total de trabajo\",\n          \"fr\": \"Temps de travail total\",\n          \"it\": \"Tempo di lavoro totale\",\n          \"no\": \"Total arbeidstid\",\n          \"sv\": \"Total arbetstid\",\n          \"pl\": \"Całkowity czas pracy\",\n          \"ru\": \"Общее время работы\",\n          \"ko\": \"총 작업 시간\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"total_cleared_area\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total cleaned area\",\n          \"nl\": \"Totaal geschoont\",\n          \"da\": \"Samlet rengjort område\",\n          \"de\": \"Gesamt gereinigte Fläche\",\n          \"es\": \"Área total limpiada\",\n          \"fr\": \"Surface totale nettoyée\",\n          \"it\": \"Area totale pulita\",\n          \"no\": \"Totalt rengjort område\",\n          \"sv\": \"Totalt rengjort område\",\n          \"pl\": \"Łączna powierzchnia sprzątania\",\n          \"ru\": \"Общая убранная площадь\",\n          \"ko\": \"총 청소 면적\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"total_clean_count\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total clean count\",\n          \"nl\": \"Totaal aantal opschoningen\",\n          \"da\": \"Samlet rengøringsantal\",\n          \"de\": \"Gesamtzahl der Reinigungen\",\n          \"es\": \"Recuentos de limpieza totales\",\n          \"fr\": \"Nombre total de nettoyages\",\n          \"it\": \"Conteggio totale delle pulizie\",\n          \"no\": \"Total rengjøringsteller\",\n          \"sv\": \"Total rengöringsantal\",\n          \"pl\": \"Łączna liczba czyszczenia\",\n          \"ru\": \"Общее количество чисток\",\n          \"ko\": \"총 청소 횟수\"\n        },\n        \"value\": \"0\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device data\",\n      \"nl\": \"Apparaat data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"장치 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"error\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Error\",\n          \"nl\": \"Error\",\n          \"da\": \"Fejl\",\n          \"de\": \"Fehler\",\n          \"es\": \"Error\",\n          \"fr\": \"Erreur\",\n          \"it\": \"Errore\",\n          \"no\": \"Feil\",\n          \"sv\": \"Fel\",\n          \"pl\": \"Błąd\",\n          \"ru\": \"Ошибка\",\n          \"ko\": \"오류\"\n        },\n        \"value\": \"No error\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/airfryer_careli_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/airfryer_careli_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/airfryer_careli_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/airmonitor_cgllc_zhimi_airmonitor/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/zhimi.airmonitor.v1\n// https://home.miot-spec.com/spec/cgllc.airmonitor.b1\n// https://home.miot-spec.com/spec/cgllc.airmonitor.s1\n\nclass AirmonitorZhimiCgllcDevice extends Device {\n    async onInit() {\n        try {\n            if (!this.util) this.util = new Util({ homey: this.homey });\n\n            // GENERIC DEVICE INIT ACTIONS\n            this.bootSequence();\n\n            // ADD / REMOVE DEVICES DEPENDANT CAPABILITIES\n            if (this.getStoreValue('model') === 'cgllc.airmonitor.s1') {\n                if (this.hasCapability('measure_battery')) {\n                    await this.removeCapability('measure_battery');\n                }\n                if (this.hasCapability('alarm_battery')) {\n                    await this.removeCapability('alarm_battery');\n                }\n\n                if (!this.hasCapability('measure_pm25')) {\n                    await this.addCapability('measure_pm25');\n                }\n                if (!this.hasCapability('measure_co2')) {\n                    await this.addCapability('measure_co2');\n                }\n                if (!this.hasCapability('measure_humidity')) {\n                    await this.addCapability('measure_humidity');\n                }\n                if (!this.hasCapability('measure_temperature')) {\n                    await this.addCapability('measure_temperature');\n                }\n                if (!this.hasCapability('measure_tvoc')) {\n                    await this.addCapability('measure_tvoc');\n                }\n            }\n\n            if (this.getStoreValue('model') === 'cgllc.airmonitor.v1') {\n                if (!this.hasCapability('measure_pm25')) {\n                    await this.addCapability('measure_pm25');\n                }\n                if (!this.hasCapability('measure_battery')) {\n                    await this.addCapability('measure_battery');\n                }\n                if (!this.hasCapability('alarm_battery')) {\n                    await this.addCapability('alarm_battery');\n                }\n            }\n\n            if (this.getStoreValue('model') === 'cgllc.airmonitor.b1') {\n                if (!this.hasCapability('measure_pm25')) {\n                    await this.addCapability('measure_pm25');\n                }\n                if (!this.hasCapability('measure_co2')) {\n                    await this.addCapability('measure_co2');\n                }\n                if (!this.hasCapability('measure_humidity')) {\n                    await this.addCapability('measure_humidity');\n                }\n                if (!this.hasCapability('measure_temperature')) {\n                    await this.addCapability('measure_temperature');\n                }\n                if (!this.hasCapability('measure_tvoc')) {\n                    await this.addCapability('measure_tvoc');\n                }\n            }\n\n            // LISTENERS FOR UPDATING CAPABILITIES\n            this.registerCapabilityListener('onoff', async (value) => {\n                try {\n                    if (this.miio) {\n                        return await this.miio.call('set_power', [value ? 'on' : 'off'], { retries: 1 });\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n        } catch (error) {\n            this.error(error);\n        }\n    }\n\n    async retrieveDeviceData() {\n        try {\n            /* model specific capabilities */\n            switch (this.getStoreValue('model')) {\n                case 'cgllc.airmonitor.v1':\n                    const result_v1 = await this.miio.call('get_prop', ['power', 'aqi', 'battery']);\n                    // temporary debug\n                    this.log('Retrieved data for cgllc.airmonitor.v1:', JSON.stringify(result_v1));\n                    if (!this.getAvailable()) {\n                        await this.setAvailable();\n                    }\n                    // if there will be complains on v1 version, we have to make adjustments like in case of s1\n                    if (result_v1[0] !== undefined) await this.updateCapabilityValue('onoff', result_v1[0]);\n                    if (result_v1[1] !== undefined && result_v1[1] !== 99999) await this.updateCapabilityValue('measure_pm25', parseInt(result_v1[1]));\n                    if (result_v1[2] !== undefined) await this.updateCapabilityValue('measure_battery', this.util.clamp(parseInt(result_v1[2]), 0, 100));\n                    if (result_v1[2] !== undefined) await this.updateCapabilityValue('alarm_battery', this.util.clamp(parseInt(result_v1[2]), 0, 100) > 20 ? false : true);\n                    break;\n\n                case 'cgllc.airmonitor.b1':\n                    const result_b1 = await this.miio.call('get_air_data', []);\n                    // temporary debug\n                    this.log('Retrieved data for cgllc.airmonitor.b1:', JSON.stringify(result_b1));\n                    if (!this.getAvailable()) {\n                        await this.setAvailable();\n                    }\n\n                    if (result_b1.result.pm25 !== undefined && result_b1.result.pm25 !== 99999) await this.updateCapabilityValue('measure_pm25', parseInt(result_b1.result.pm25));\n                    if (result_b1.result.co2e !== undefined) await this.updateCapabilityValue('measure_co2', parseInt(result_b1.result.co2e));\n                    if (result_b1.result.humidity !== undefined) await this.updateCapabilityValue('measure_humidity', parseFloat(result_b1.result.humidity));\n                    if (result_b1.result.temperature !== undefined) await this.updateCapabilityValue('measure_temperature', parseFloat(result_b1.result.temperature));\n                    if (result_b1.result.tvoc !== undefined) await this.updateCapabilityValue('measure_tvoc', parseInt(result_b1.result.tvoc));\n                    break;\n\n                case 'cgllc.airmonitor.s1':\n                    const result_s1 = await this.miio.call('get_value', ['co2', 'humidity', 'pm25', 'temperature', 'tvoc'], { retries: 1 });\n                    // Temporary debug\n                    this.log('Retrieved data for cgllc.airmonitor.s1:', result_s1);\n                    if (!this.getAvailable()) {\n                        await this.setAvailable();\n                        this.log('Device marked as available');\n                    }\n\n                    if (result_s1.co2 !== undefined) {\n                        const co2Value = parseInt(result_s1.co2);\n                        await this.updateCapabilityValue('measure_co2', co2Value);\n                    } else {\n                        this.log(`Skipped updating 'measure_co2'. Received value: ${result_s1.co2}`);\n                    }\n\n                    if (result_s1.humidity !== undefined) {\n                        const humidityValue = parseFloat(result_s1.humidity);\n                        await this.updateCapabilityValue('measure_humidity', humidityValue);\n                    } else {\n                        this.log(`Skipped updating 'measure_humidity'. Received value: ${result_s1.humidity}`);\n                    }\n\n                    if (result_s1.pm25 !== undefined && result_s1.pm25 !== 99999) {\n                        const pm25Value = parseFloat(result_s1.pm25);\n                        await this.updateCapabilityValue('measure_pm25', pm25Value);\n                    } else {\n                        this.log(`Skipped updating 'measure_pm25'. Received value: ${result_s1.pm25}`);\n                    }\n\n                    if (result_s1.temperature !== undefined) {\n                        const temperatureValue = parseFloat(result_s1.temperature);\n                        await this.updateCapabilityValue('measure_temperature', temperatureValue);\n                    } else {\n                        this.log(`Skipped updating 'measure_temperature'. Received value: ${result_s1.temperature}`);\n                    }\n\n                    if (result_s1.tvoc !== undefined) {\n                        const tvocValue = parseInt(result_s1.tvoc);\n                        await this.updateCapabilityValue('measure_tvoc', tvocValue);\n                    } else {\n                        this.log(`Skipped updating 'measure_tvoc'. Received value: ${result_s1.tvoc}`);\n                    }\n\n                    break;\n                default:\n                    this.log(`Unknown model: ${this.getStoreValue('model')}`);\n                    break;\n            }\n        } catch (error) {\n            this.homey.clearInterval(this.pollingInterval);\n            if (this.getAvailable()) {\n                await this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((error) => {\n                    this.error(error);\n                });\n                this.log(`Device marked as unavailable due to error: ${error.message}`);\n            }\n            this.homey.setTimeout(() => {\n                this.createDevice();\n            }, 60000);\n            this.error(`Error in retrieveDeviceData: ${error.message}`);\n        }\n    }\n}\n\nmodule.exports = AirmonitorZhimiCgllcDevice;\n"
  },
  {
    "path": "drivers/airmonitor_cgllc_zhimi_airmonitor/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Air Quality Monitor (WiFi)\",\n    \"nl\": \"Mi Air Quality Monitor (WiFi)\",\n    \"da\": \"Mi Luftkvalitetsmonitor (WiFi)\",\n    \"de\": \"Mi Luftqualitätsmonitor (WiFi)\",\n    \"es\": \"Monitor de Calidad del Aire Mi (WiFi)\",\n    \"fr\": \"Moniteur de Qualité de l'Air Mi (WiFi)\",\n    \"it\": \"Monitor della Qualità dell'Aria Mi (WiFi)\",\n    \"no\": \"Mi Luftkvalitetsmonitor (WiFi)\",\n    \"sv\": \"Mi Luftkvalitetsmonitor (WiFi)\",\n    \"pl\": \"Monitor Jakości Powietrza Mi (WiFi)\",\n    \"ru\": \"Монитор качества воздуха Mi (WiFi)\",\n    \"ko\": \"미 에어 퀄리티 모니터 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/airmonitor_cgllc_zhimi_airmonitor/assets/images/large.jpg\",\n    \"small\": \"drivers/airmonitor_cgllc_zhimi_airmonitor/assets/images/small.jpg\"\n  },\n  \"class\": \"airtreatment\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"measure_pm25\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"INTERNAL\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/airmonitor_cgllc_zhimi_airmonitor/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass AirmonitorZhimiCgllcDriver extends Driver {}\n\nmodule.exports = AirmonitorZhimiCgllcDriver;\n"
  },
  {
    "path": "drivers/airmonitor_cgllc_zhimi_airmonitor/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"ja\": \"デバイス設定\",\n      \"zh\": \"设备设置\",\n      \"pt\": \"Configurações do dispositivo\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/airmonitor_cgllc_zhimi_airmonitor/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/airmonitor_cgllc_zhimi_airmonitor/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/airmonitor_cgllc_zhimi_airmonitor/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/airpurifier_dmaker_airfresh_t2017/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/dmaker.airfresh.t2017 // Mi Air Purifier MJXFJ-300-G1\n// https://home.miot-spec.com/spec/dmaker.airfresh.a1 // Mi Air Purifier MJXFJ-150-A1\n\nconst modes = {\n  0: \"Auto\",\n  1: \"Night\",\n  2: \"Favorite\",\n  3: \"Idle\"\n};\n\nclass MiAirPurifierT2017Device extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_power\", [value], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('onoff.ptc', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_ptc_on\", [value], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('dim', async (value) => {\n        try {\n          if (this.miio) {\n            let speed = value * 100;\n            if (speed > 0) {\n              return await this.miio.call(\"set_favourite_speed\", [parseInt(speed * 2.4 + 60)], { retries: 1 });\n            }\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('airpurifier_heater_mode', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_ptc_level\", [value], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('airpurifier_zhimi_mode', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_mode\", [+value], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"display\")) {\n      const led = await this.miio.call(\"set_display\", [newSettings.display ? \"on\" : \"off\"], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"sound\")) {\n      const buzzer = await this.miio.call(\"set_sound\", [newSettings.sound ? \"on\" : \"off\"], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"childLock\")) {\n      const childlock = await this.miio.call(\"set_child_lock\", [newSettings.childLock ? \"on\" : \"off\"], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"screen_direction\")) {\n      const childlock = await this.miio.call(\"set_screen_direction\", [newSettings.screen_direction], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_prop\", [\"power\", \"pm25\", \"co2\", \"temperature_outside\", \"mode\", \"favourite_speed\", \"display\", \"sound\", \"child_lock\", \"ptc_on\", \"ptc_status\"], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      await this.updateCapabilityValue(\"onoff\", result[0]);\n      await this.updateCapabilityValue(\"measure_pm25\", parseInt(result[1]));\n      await this.updateCapabilityValue(\"measure_co2\", parseInt(result[2]));\n      await this.updateCapabilityValue(\"measure_temperature\", parseInt(result[3]));\n      \n      await this.updateCapabilityValue(\"dim\", parseInt(this.util.normalize[result[5]], 60, 300));\n      await this.updateCapabilityValue(\"onoff.ptc\", result[9]);\n\n      await this.updateSettingValue(\"display\", result[6]);\n      await this.updateSettingValue(\"sound\", result[7]);\n      await this.updateSettingValue(\"childLock\", result[8]);\n\n      /* mode capability */\n      if (this.getCapabilityValue('airpurifier_zhimi_mode') !== result[4].toString()) {\n        const previous_mode = this.getCapabilityValue('airpurifier_zhimi_mode');\n        await this.setCapabilityValue('airpurifier_zhimi_mode', result[4].toString());\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, {\"new_mode\": modes[result[4]], \"previous_mode\": modes[+previous_mode] }).catch(error => { this.error(error) });\n      }\n      \n      /* model specific capabilities */\n      switch (this.getStoreValue('model')) {\n        case 'dmaker.airfresh.t2017':\n          await this.util.sleep(2000);\n          const result_t2017 = await this.miio.call(\"get_prop\", [\"ptc_level\", \"filter_efficient\", \"filter_intermediate\", \"screen_direction\"], { retries: 1 });\n          await this.updateCapabilityValue(\"air_heater_mode\", result_t2017[0]);\n          await this.updateSettingValue(\"filter_efficient\", parseInt(result_t2017[1]).toString() + \"%\");\n          await this.updateSettingValue(\"filter_intermediate\", parseInt(result_t2017[2]).toString() + \"%\");\n          await this.updateSettingValue(\"screen_direction\", result_t2017[3]);\n          break;\n        case 'dmaker.airfresh.a1':\n          await this.util.sleep(2000);\n          const result_a1 = await this.miio.call(\"get_prop\", [\"filter_rate\", \"filter_day\"], { retries: 1 });\n          await this.updateSettingValue(\"filter_efficient\", parseInt(result_a1[0]).toString() + \"%\");\n          await this.updateSettingValue(\"filter_intermediate\", parseInt(result_a1[0]).toString() + \"%\");\n          break;\n        default:\n          break;\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = MiAirPurifierT2017Device;\n"
  },
  {
    "path": "drivers/airpurifier_dmaker_airfresh_t2017/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n    \"nl\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n    \"da\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n    \"de\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n    \"es\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n    \"fr\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n    \"it\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n    \"no\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n    \"sv\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n    \"pl\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n    \"ru\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\",\n    \"ko\": \"Mi Air Purifier MJXFJ-300-G1 / MJXFJ-150-A1 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/airpurifier_dmaker_airfresh_t2017/assets/images/large.jpg\",\n    \"small\": \"drivers/airpurifier_dmaker_airfresh_t2017/assets/images/small.jpg\"\n  },\n  \"class\": \"airpurifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"dim\",\n    \"airpurifier_zhimi_mode\",\n    \"onoff.ptc\",\n    \"measure_temperature\",\n    \"measure_pm25\",\n    \"measure_co2\"\n  ],\n  \"capabilitiesOptions\": {\n    \"dim\": {\n      \"title\": {\n        \"en\": \"Speedlevel\",\n        \"nl\": \"Snelheid\",\n        \"da\": \"Hastighedsniveau\",\n        \"de\": \"Geschwindigkeitsstufe\",\n        \"es\": \"Nivel de velocidad\",\n        \"fr\": \"Niveau de vitesse\",\n        \"it\": \"Livello di velocità\",\n        \"no\": \"Hastighetsnivå\",\n        \"sv\": \"Hastighetsnivå\",\n        \"pl\": \"Poziom prędkości\",\n        \"ru\": \"Уровень скорости\",\n        \"ko\": \"속도 레벨\"\n      }\n    },\n    \"onoff.ptc\": {\n      \"title\": {\n        \"en\": \"Heat\",\n        \"nl\": \"Verwarmen\",\n        \"da\": \"Varme\",\n        \"de\": \"Heizen\",\n        \"es\": \"Calor\",\n        \"fr\": \"Chaleur\",\n        \"it\": \"Calore\",\n        \"no\": \"Varme\",\n        \"sv\": \"Värme\",\n        \"pl\": \"Ciepło\",\n        \"ru\": \"Тепло\",\n        \"ko\": \"난방\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/airpurifier_dmaker_airfresh_t2017/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiAirPurifierT2017Driver extends Driver {}\n\nmodule.exports = MiAirPurifierT2017Driver;"
  },
  {
    "path": "drivers/airpurifier_dmaker_airfresh_t2017/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de Usuario\",\n      \"fr\": \"Paramètres de l'utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"display\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Display\",\n          \"nl\": \"Display\",\n          \"da\": \"Skærm\",\n          \"de\": \"Anzeige\",\n          \"es\": \"Pantalla\",\n          \"fr\": \"Affichage\",\n          \"it\": \"Schermo\",\n          \"no\": \"Skjerm\",\n          \"sv\": \"Skärm\",\n          \"pl\": \"Wyświetlacz\",\n          \"ru\": \"Дисплей\",\n          \"ko\": \"디스플레이\"\n        }\n      },\n      {\n        \"id\": \"Sound\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Sound\",\n          \"nl\": \"Sound\",\n          \"da\": \"Lyd\",\n          \"de\": \"Ton\",\n          \"es\": \"Sonido\",\n          \"fr\": \"Son\",\n          \"it\": \"Suono\",\n          \"no\": \"Lyd\",\n          \"sv\": \"Ljud\",\n          \"pl\": \"Dźwięk\",\n          \"ru\": \"Звук\",\n          \"ko\": \"소리\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnesikring\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo Infantil\",\n          \"fr\": \"Verrouillage enfant\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barnesikring\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada rodzicielska\",\n          \"ru\": \"Блокировка от детей\",\n          \"ko\": \"차일드 락\"\n        }\n      },\n      {\n        \"id\": \"filter_efficient\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter life\",\n          \"nl\": \"Fil;ter duur\",\n          \"da\": \"Filter levetid\",\n          \"de\": \"Filterlebensdauer\",\n          \"es\": \"Vida del filtro\",\n          \"fr\": \"Durée de vie du filtre\",\n          \"it\": \"Durata del filtro\",\n          \"no\": \"Filterliv\",\n          \"sv\": \"Filterliv\",\n          \"pl\": \"Żywotność filtra\",\n          \"ru\": \"Ресурс фильтра\",\n          \"ko\": \"필터 수명\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"filter_intermediate\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter life 2\",\n          \"da\": \"Filter levetid 2\",\n          \"de\": \"Filterlebensdauer 2\",\n          \"es\": \"Vida del filtro 2\",\n          \"fr\": \"Durée de vie du filtre 2\",\n          \"it\": \"Durata del filtro 2\",\n          \"no\": \"Filterliv 2\",\n          \"sv\": \"Filterliv 2\",\n          \"pl\": \"Żywotność filtra 2\",\n          \"ru\": \"Ресурс фильтра 2\",\n          \"ko\": \"필터 수명 2\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"screen_direction\",\n        \"type\": \"dropdown\",\n        \"value\": \"forward\",\n        \"label\": {\n          \"en\": \"Screen Direction\",\n          \"nl\": \"Scherm orientatie\",\n          \"da\": \"Skærmretning\",\n          \"de\": \"Bildschirmrichtung\",\n          \"es\": \"Dirección de la pantalla\",\n          \"fr\": \"Orientation de l'écran\",\n          \"it\": \"Orientamento schermo\",\n          \"no\": \"Skjermretning\",\n          \"sv\": \"Skärmriktning\",\n          \"pl\": \"Kierunek ekranu\",\n          \"ru\": \"Направление экрана\",\n          \"ko\": \"화면 방향\"\n        },\n        \"values\": [\n          {\n            \"id\": \"forward\",\n            \"label\": {\n              \"en\": \"Normal\",\n              \"da\": \"Normal\",\n              \"de\": \"Normal\",\n              \"es\": \"Normal\",\n              \"fr\": \"Normal\",\n              \"it\": \"Normale\",\n              \"no\": \"Normal\",\n              \"sv\": \"Normal\",\n              \"pl\": \"Normalny\",\n              \"ru\": \"Обычный\",\n              \"ko\": \"일반\"\n            }\n          },\n          {\n            \"id\": \"left\",\n            \"label\": {\n              \"en\": \"-90\",\n              \"da\": \"-90\",\n              \"de\": \"-90\",\n              \"es\": \"-90\",\n              \"fr\": \"-90\",\n              \"it\": \"-90\",\n              \"no\": \"-90\",\n              \"sv\": \"-90\",\n              \"pl\": \"-90\",\n              \"ru\": \"-90\",\n              \"ko\": \"-90\"\n            }\n          },\n          {\n            \"id\": \"right\",\n            \"label\": {\n              \"en\": \"+90\",\n              \"da\": \"+90\",\n              \"de\": \"+90\",\n              \"es\": \"+90\",\n              \"fr\": \"+90\",\n              \"it\": \"+90\",\n              \"no\": \"+90\",\n              \"sv\": \"+90\",\n              \"pl\": \"+90\",\n              \"ru\": \"+90\",\n              \"ko\": \"+90\"\n            }\n          }\n        ]\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/airpurifier_dmaker_airfresh_t2017/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/airpurifier_dmaker_airfresh_t2017/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/airpurifier_dmaker_airfresh_t2017/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/zhimi.airpurifier.v1 // Air Purifier\n// https://home.miot-spec.com/spec/zhimi.airpurifier.v2 // Air Purifier v2\n// https://home.miot-spec.com/spec/zhimi.airpurifier.v3 // Air Purifier v3\n// https://home.miot-spec.com/spec/zhimi.airpurifier.v5 // Air Purifier v5\n// https://home.miot-spec.com/spec/zhimi.airpurifier.v6 // Air Purifier Pro\n// https://home.miot-spec.com/spec/zhimi.airpurifier.v7 // Air Purifier Pro v7\n// https://home.miot-spec.com/spec/zhimi.airpurifier.m1 // Air Purifier 2 Mini\n// https://home.miot-spec.com/spec/zhimi.airpurifier.m2 // Air Purifier Mini\n// https://home.miot-spec.com/spec/zhimi.airpurifier.ma1 // Air Purifier 2S\n// https://home.miot-spec.com/spec/zhimi.airpurifier.ma2 // Air Purifier 2S\n// https://home.miot-spec.com/spec/zhimi.airpurifier.sa1 // Air Purifier Super/Max\n// https://home.miot-spec.com/spec/zhimi.airpurifier.sa2 // Air Purifier Super/Max 2\n// https://home.miot-spec.com/spec/zhimi.airpurifier.mc1 // Air Purifier 2S\n// https://home.miot-spec.com/spec/zhimi.airpurifier.mc2 // Air Purifier 2H\n\nconst MIOT_MODE_TO_CAPABILITY = {\n  0: 'auto',\n  1: 'silent',\n  2: 'favorite',\n  3: 'idle',\n};\n\nconst CAPABILITY_MODE_TO_MIOT = {\n  auto: 0,\n  silent: 1,\n  favorite: 2,\n  idle: 3,\n};\n\nconst V7_SUPPORTED_MODES = new Set(['auto', 'silent', 'favorite']);\nconst V7_MODE_OPTIONS = [\n  { id: 'auto', title: 'Auto' },\n  { id: 'silent', title: 'Night' },\n  { id: 'favorite', title: 'Favorite' },\n];\nconst V7_FAVORITE_LEVEL_MAX = 16;\n\nconst clamp = (value, min, max) => Math.min(max, Math.max(min, value));\nconst normalizeV7FavoriteLevel = (value) => clamp(Number(value) || 0, 0, V7_FAVORITE_LEVEL_MAX) / V7_FAVORITE_LEVEL_MAX;\nconst denormalizeV7FavoriteLevel = (value) => Math.round(clamp(Number(value) || 0, 0, 1) * V7_FAVORITE_LEVEL_MAX);\n\nconst MIOT_PROPERTIES = {\n  'zhimi.airp.meb1': {\n    get_properties: [\n      { did: 'power', siid: 2, piid: 1 },\n      { did: 'mode', siid: 2, piid: 4 },\n      { did: 'fanlevel', siid: 2, piid: 5 },\n      { did: 'humidity', siid: 3, piid: 1 },\n      { did: 'aqi', siid: 3, piid: 4 },\n      { did: 'temperature', siid: 3, piid: 7 },\n      { did: 'buzzer', siid: 6, piid: 1 },\n      { did: 'child_lock', siid: 8, piid: 1 },\n      { did: 'light', siid: 13, piid: 2 },\n      { did: 'filter_life_remaining', siid: 4, piid: 1 },\n      { did: 'filter_hours_used', siid: 4, piid: 3 },\n    ],\n    set_properties: {\n      power: { siid: 2, piid: 1 },\n      mode: { siid: 2, piid: 4 },\n      fanlevel: { siid: 2, piid: 5 },\n      buzzer: { siid: 6, piid: 1 },\n      child_lock: { siid: 8, piid: 1 },\n      light: { siid: 13, piid: 2 },\n    },\n    device_properties: {\n      light: { min: 0, max: 2 },\n    },\n  },\n};\n\nclass AdvancedOlderMiAirPurifierDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({ homey: this.homey });\n\n      this.model = this.getStoreValue('model');\n      this.isV7 = this.model === 'zhimi.airpurifier.v7';\n      this.isMiot = Object.prototype.hasOwnProperty.call(MIOT_PROPERTIES, this.model);\n      if (this.isMiot) {\n        this.deviceProperties = MIOT_PROPERTIES[this.model];\n      }\n\n      if (this.isV7) {\n        await this.setCapabilityOptions('airpurifier_mode', {\n          values: V7_MODE_OPTIONS,\n        });\n        await this.setCapabilityOptions('fan_speed', {\n          min: 0,\n          max: 1,\n          step: 1 / V7_FAVORITE_LEVEL_MAX,\n        });\n      }\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async (value) => {\n        try {\n          if (!this.miio) {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error); });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n\n          if (this.isMiot) {\n            return await this.miio.call('set_properties', [{\n              siid: this.deviceProperties.set_properties.power.siid,\n              piid: this.deviceProperties.set_properties.power.piid,\n              value: Boolean(value),\n            }], { retries: 1 });\n          }\n\n          return await this.onCapabilityOnoff(value);\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('fan_speed', async (value) => {\n        try {\n          if (!this.miio) {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error); });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n\n          if (this.isMiot) {\n            const numericFanLevel = Number(value);\n            if (Number.isNaN(numericFanLevel)) {\n              return Promise.reject(new Error('Invalid fan speed value: ' + value));\n            }\n\n            return await this.miio.call('set_properties', [{\n              siid: this.deviceProperties.set_properties.fanlevel.siid,\n              piid: this.deviceProperties.set_properties.fanlevel.piid,\n              value: numericFanLevel,\n            }], { retries: 1 });\n          }\n\n          const numericFanLevel = Number(value);\n          if (Number.isNaN(numericFanLevel)) {\n            return Promise.reject(new Error('Invalid fan speed value: ' + value));\n          }\n\n          return await this.miio.setFavoriteLevel(this.isV7 ? denormalizeV7FavoriteLevel(numericFanLevel) : numericFanLevel);\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('airpurifier_mode', async (value) => {\n        try {\n          if (!this.miio) {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error); });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n\n          const previousMode = this.getCapabilityValue('airpurifier_mode');\n          let result;\n\n          if (this.isMiot) {\n            const miotValue = CAPABILITY_MODE_TO_MIOT[value];\n            if (miotValue === undefined) {\n              return Promise.reject(new Error('Unsupported mode for MIoT device: ' + value));\n            }\n\n            result = await this.miio.call('set_properties', [{\n              siid: this.deviceProperties.set_properties.mode.siid,\n              piid: this.deviceProperties.set_properties.mode.piid,\n              value: miotValue,\n            }], { retries: 1 });\n          } else {\n            if (this.isV7 && !V7_SUPPORTED_MODES.has(value)) {\n              return Promise.reject(new Error('Unsupported mode for v7 device: ' + value));\n            }\n            result = await this.miio.call('set_mode', [value], { retries: 1 });\n          }\n\n          if (previousMode !== value) {\n            await this.setCapabilityValue('airpurifier_mode', value);\n            await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, { new_mode: value, previous_mode: previousMode }).catch(error => { this.error(error); });\n          }\n\n          return result;\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes('address') || changedKeys.includes('token') || changedKeys.includes('polling')) {\n      this.refreshDevice();\n    }\n\n    if (!this.miio) {\n      return Promise.reject('Device unreachable, please try again ...');\n    }\n\n    if (this.isMiot) {\n      if (changedKeys.includes('led')) {\n        await this.miio.call('set_properties', [{\n          siid: this.deviceProperties.set_properties.light.siid,\n          piid: this.deviceProperties.set_properties.light.piid,\n          value: newSettings.led ? this.deviceProperties.device_properties.light.max : this.deviceProperties.device_properties.light.min,\n        }], { retries: 1 });\n      }\n\n      if (changedKeys.includes('buzzer')) {\n        await this.miio.call('set_properties', [{\n          siid: this.deviceProperties.set_properties.buzzer.siid,\n          piid: this.deviceProperties.set_properties.buzzer.piid,\n          value: Boolean(newSettings.buzzer),\n        }], { retries: 1 });\n      }\n\n      if (changedKeys.includes('childLock')) {\n        await this.miio.call('set_properties', [{\n          siid: this.deviceProperties.set_properties.child_lock.siid,\n          piid: this.deviceProperties.set_properties.child_lock.piid,\n          value: Boolean(newSettings.childLock),\n        }], { retries: 1 });\n      }\n\n      return Promise.resolve(true);\n    }\n\n    if (changedKeys.includes('led')) {\n      await this.miio.call('set_led', [newSettings.led ? 'on' : 'off'], { retries: 1 });\n    }\n\n    if (changedKeys.includes('buzzer')) {\n      await this.miio.call('set_buzzer', [newSettings.buzzer ? 'on' : 'off'], { retries: 1 });\n    }\n\n    if (changedKeys.includes('childLock')) {\n      await this.miio.call('set_child_lock', [newSettings.childLock ? 'on' : 'off'], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n      if (this.isMiot) {\n        await this.retrieveMiotData();\n        return;\n      }\n\n      const result = await this.miio.call('get_prop', ['power', 'aqi', 'humidity', 'temp_dec', 'bright', 'mode', 'favorite_level', 'buzzer', 'led', 'child_lock', 'filter1_life', 'f1_hour_used'], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* capabilities */\n      await this.updateCapabilityValue('onoff', result[0] === 'on');\n      await this.updateCapabilityValue('measure_pm25', result[1]);\n      await this.updateCapabilityValue('measure_humidity', result[2]);\n      await this.updateCapabilityValue('measure_temperature', result[3] / 10);\n      await this.updateCapabilityValue('measure_luminance', result[4]);\n      await this.updateCapabilityValue('fan_speed', this.isV7 ? normalizeV7FavoriteLevel(result[6]) : result[6]);\n\n      /* settings */\n      await this.updateSettingValue('buzzer', result[7] === 'on');\n      await this.updateSettingValue('led', result[8] === 'on');\n      await this.updateSettingValue('childLock', result[9] === 'on');\n      await this.updateSettingValue('filter1_life', `${result[10]}%`);\n      await this.updateSettingValue('f1_hour_used', `${result[11]}h`);\n\n      /* mode capability */\n      if (this.isV7 && !V7_SUPPORTED_MODES.has(result[5])) {\n        return;\n      }\n\n      if (this.getCapabilityValue('airpurifier_mode') !== result[5]) {\n        const previousMode = this.getCapabilityValue('airpurifier_mode');\n        await this.setCapabilityValue('airpurifier_mode', result[5]);\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, { new_mode: result[5], previous_mode: previousMode }).catch(error => { this.error(error); });\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(err => { this.error(err); });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n  async retrieveMiotData() {\n    const result = await this.miio.call('get_properties', this.deviceProperties.get_properties, { retries: 1 });\n    if (!this.getAvailable()) { await this.setAvailable(); }\n\n    const findValue = (did) => {\n      const property = result.find(obj => obj.did === did);\n      return property !== undefined ? property.value : undefined;\n    };\n\n    const onoff = findValue('power');\n    if (onoff !== undefined) {\n      await this.updateCapabilityValue('onoff', Boolean(onoff));\n    }\n\n    const aqi = findValue('aqi');\n    if (aqi !== undefined) {\n      await this.updateCapabilityValue('measure_pm25', aqi);\n    }\n\n    const humidity = findValue('humidity');\n    if (humidity !== undefined) {\n      await this.updateCapabilityValue('measure_humidity', humidity);\n    }\n\n    const temperature = findValue('temperature');\n    if (temperature !== undefined) {\n      await this.updateCapabilityValue('measure_temperature', temperature);\n    }\n\n    const fanlevel = findValue('fanlevel');\n    if (fanlevel !== undefined) {\n      await this.updateCapabilityValue('fan_speed', Number(fanlevel));\n    }\n\n    const buzzer = findValue('buzzer');\n    if (buzzer !== undefined) {\n      await this.updateSettingValue('buzzer', Boolean(buzzer));\n    }\n\n    const childLock = findValue('child_lock');\n    if (childLock !== undefined) {\n      await this.updateSettingValue('childLock', Boolean(childLock));\n    }\n\n    const led = findValue('light');\n    if (led !== undefined) {\n      const ledOn = led !== this.deviceProperties.device_properties.light.min;\n      await this.updateSettingValue('led', ledOn);\n    }\n\n    const filterLife = findValue('filter_life_remaining');\n    if (filterLife !== undefined) {\n      await this.updateSettingValue('filter1_life', `${filterLife}%`);\n    }\n\n    const filterHours = findValue('filter_hours_used');\n    if (filterHours !== undefined) {\n      await this.updateSettingValue('f1_hour_used', `${filterHours}h`);\n    }\n\n    const modeValue = findValue('mode');\n    if (modeValue !== undefined && modeValue !== null) {\n      const mode = MIOT_MODE_TO_CAPABILITY[modeValue] ?? modeValue.toString();\n      if (this.getCapabilityValue('airpurifier_mode') !== mode) {\n        const previousMode = this.getCapabilityValue('airpurifier_mode');\n        await this.setCapabilityValue('airpurifier_mode', mode);\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, { new_mode: mode, previous_mode: previousMode }).catch(error => { this.error(error); });\n      }\n    }\n  }\n\n}\n\nmodule.exports = AdvancedOlderMiAirPurifierDevice;\n\n\n\n\n\n\n"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Advanced Older Mi Air Purifier (WiFi)\",\n    \"nl\": \"Geavanceerde oudere Mi Air Purifier (WiFi)\",\n    \"da\": \"Avanceret Ældre Mi Luft Purifier (WiFi)\",\n    \"de\": \"Erweiterter älterer Mi Luftreiniger (WiFi)\",\n    \"es\": \"Purificador de aire Mi avanzado para mayores (WiFi)\",\n    \"fr\": \"Purificateur d'air Mi ancien avancé (WiFi)\",\n    \"it\": \"Purificatore d'aria Mi avanzato più vecchio (WiFi)\",\n    \"no\": \"Avansert Eldre Mi Luft Purifier (WiFi)\",\n    \"sv\": \"Avancerad Äldre Mi Luft Purifier (WiFi)\",\n    \"pl\": \"Zaawansowany starszy oczyszczacz powietrza Mi (WiFi)\",\n    \"ru\": \"Продвинутый старый Mi Воздухоочиститель (WiFi)\",\n    \"ko\": \"고급 구형 Mi 공기청정기 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/airpurifier_zhimi_advanced/assets/images/large.jpg\",\n    \"small\": \"drivers/airpurifier_zhimi_advanced/assets/images/small.jpg\"\n  },\n  \"class\": \"airpurifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"measure_pm25\",\n    \"measure_humidity\",\n    \"measure_temperature\",\n    \"measure_luminance\",\n    \"airpurifier_mode\",\n    \"fan_speed\"\n  ],\n  \"capabilitiesOptions\": {\n    \"fan_speed\": {\n      \"min\": 0,\n      \"max\": 16,\n      \"step\": 1\n    }\n  }\n}"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass AdvancedOlderMiAirPurifierDriver extends Driver {}\n\nmodule.exports = AdvancedOlderMiAirPurifierDriver;"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de Usuario\",\n      \"fr\": \"Paramètres Utilisateur\",\n      \"it\": \"Impostazioni Utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia Użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"LED\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summer\",\n          \"de\": \"Summer\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Sonnerie\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Buzzer\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Brzęczyk\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"부저\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnesikring\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo infantil\",\n          \"fr\": \"Verrouillage Enfant\",\n          \"it\": \"Blocco Bambini\",\n          \"no\": \"Barnesikring\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada Dziecięca\",\n          \"ru\": \"Блокировка от детей\",\n          \"ko\": \"어린이 잠금\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Data\",\n      \"nl\": \"Apparaat Data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"기기 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"filter1_life\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter life\",\n          \"nl\": \"Filter duur\",\n          \"da\": \"Filterets levetid\",\n          \"de\": \"Filterlebensdauer\",\n          \"es\": \"Vida útil del filtro\",\n          \"fr\": \"Durée de vie du filtre\",\n          \"it\": \"Vita del filtro\",\n          \"no\": \"Filterets levetid\",\n          \"sv\": \"Filterlivslängd\",\n          \"pl\": \"Czas życia filtra\",\n          \"ru\": \"Срок службы фильтра\",\n          \"ko\": \"필터 수명\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"f1_hour_used\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter hours used\",\n          \"nl\": \"Filter uur gebruikt\",\n          \"da\": \"Filtrets brugte timer\",\n          \"de\": \"Verwendete Filterstunden\",\n          \"es\": \"Horas de uso del filtro\",\n          \"fr\": \"Heures de filtre utilisées\",\n          \"it\": \"Ore di utilizzo del filtro\",\n          \"no\": \"Filtertimer brukt\",\n          \"sv\": \"Filteranvändningstimmar\",\n          \"pl\": \"Użyte godziny filtra\",\n          \"ru\": \"Часы использования фильтра\",\n          \"ko\": \"필터 사용 시간\"\n        },\n        \"value\": \"0h\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Réglages de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced_miot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/zhimi.airpurifier.ma4 // Airpurifier 3\n// https://home.miot-spec.com/spec/zhimi.airpurifier.mb3 // Airpurifier 3H\n// https://home.miot-spec.com/spec/zhimi.airpurifier.mb3a // Airpurifier 3H\n// https://home.miot-spec.com/spec/zhimi.airp.mb3a // Airpurifier 3H\n// https://home.miot-spec.com/spec/zhimi.airpurifier.va1 // Airpurifier Pro H\n// https://home.miot-spec.com/spec/zhimi.airpurifier.vb2 // Airpurifier ProH\n// https://home.miot-spec.com/spec/zhimi.airpurifier.mb4 // Airpurifier 3C\n// https://home.miot-spec.com/spec/zhimi.airp.mb4a // Airpurifier 3C\n// https://home.miot-spec.com/spec/zhimi.airp.mb5 // Airpurifier 4\n// https://home.miot-spec.com/spec/zhimi.airp.mb5a // Airpurifier 4\n// https://home.miot-spec.com/spec/zhimi.airp.va2 // Airpurifier 4 Pro\n// https://home.miot-spec.com/spec/zhimi.airp.vb4 // Airpurifier 4 Pro\n// https://home.miot-spec.com/spec/zhimi.airpurifier.rma1 // Airpurifier 4 Lite\n// https://home.miot-spec.com/spec/zhimi.airp.rmb1 // Airpurifier 4 Lite\n// https://home.miot-spec.com/spec/zhimi.airpurifier.za1 // Smartmi Air Purifier\n// https://home.miot-spec.com/spec/zhimi.airp.meb1 // Xiaomi Smart Air Purifier Elite\n// https://home.miot-spec.com/spec/xiaomi.airp.cpa4 // Xiaomi Smart Air Purifier 4 Compact\n\nconst mapping = {\n  \"zhimi.airpurifier.ma4\": \"mapping_default\", \n  \"zhimi.airpurifier.mb3\": \"mapping_default\",\n\t\"zhimi.airpurifier.mb3a\": \"mapping_default\",\n\t\"zhimi.airp.mb3a\": \"mapping_default\",\n\t\"zhimi.airpurifier.va1\": \"mapping_default\",\n\t\"zhimi.airpurifier.vb2\": \"mapping_default\",\n\t\"zhimi.airpurifier.mb4\": \"mapping_mb4\",\n\t\"zhimi.airp.mb4a\": \"mapping_mb4\",\n\t\"zhimi.airp.mb5\": \"mapping_va2\",\n  \"zhimi.airp.mb5a\": \"mapping_va2\",\n\t\"zhimi.airp.va2\": \"mapping_va2\",\n  \"zhimi.airp.vb4\": \"mapping_vb4\",\n  \"zhimi.airpurifier.rma1\": \"mapping_rma1\",\n  \"zhimi.airp.rmb1\": \"mapping_rmb1\",\n  \"zhimi.airpurifier.za1\": \"mapping_za1\",\n  \"zhimi.airp.meb1\": \"mapping_airp_meb1\",\n  \"xiaomi.airp.cpa4\": \"mapping_cpa4\",\n  \"zhimi.airpurifier.*\": \"mapping_default\",\n};\n\nconst properties = {\n  \"mapping_default\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 2 }, // onoff\n      { did: \"fanlevel\", siid : 2, piid: 4 }, // airpurifier_zhimi_fanlevel\n      { did: \"mode\", siid: 2, piid: 5 }, // airpurifier_zhimi_mode\n      { did: \"humidity\", siid: 3, piid: 7 }, // measure_humidity\n      { did: \"temperature\", siid: 3, piid: 8 }, // measure_temperature\n      { did: \"aqi\", siid: 3, piid: 6 }, // measure_pm25\n      { did: \"buzzer\", siid: 5, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 18, piid: 13 }, // settings.childLock\n      { did: \"light\", siid: 6, piid: 1 }, // settings.led\n      { did: \"filter_life_remaining\", siid: 4, piid: 3 }, // settings.filter_life_remaining\n      { did: \"filter_hours_used\", siid: 4, piid: 5 }, // settings.filter_hours_used\n      { did: \"purify_volume\", siid: 13, piid: 1 } // settings.purify_volume\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 2 },\n      \"fanlevel\": { siid: 2, piid: 4 },\n      \"mode\": { siid: 2, piid: 5 },\n      \"buzzer\": { siid: 5, piid: 1 },\n      \"child_lock\": { siid: 18, piid: 13 },\n      \"light\": { siid: 6, piid: 1 }\n    },\n    \"device_properties\": {\n      \"light\": { \"min\": 2, \"max\": 0 }\n    }\n  },\n  \"mapping_mb4\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"mode\", siid: 2, piid: 4 }, // airpurifier_zhimi_mode\n      { did: \"aqi\", siid: 3, piid: 4 }, // measure_pm25\n      { did: \"buzzer\", siid: 6, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 8, piid: 1 }, // settings.childLock\n      { did: \"light\", siid: 7, piid: 2 }, // settings.led\n      { did: \"filter_life_remaining\", siid: 4, piid: 1 }, // settings.filter_life_remaining\n      { did: \"filter_hours_used\", siid: 4, piid: 3 } // settings.filter_hours_used\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"mode\": { siid: 2, piid: 4 },\n      \"buzzer\": { siid: 6, piid: 1 },\n      \"child_lock\": { siid: 8, piid: 1 },\n      \"light\": { siid: 7, piid: 2 }\n    },\n    \"device_properties\": {\n      \"light\": { \"min\": 0, \"max\": 8 }\n    }\n  },\n  \"mapping_va2\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"fanlevel\", siid : 2, piid: 5 }, // airpurifier_zhimi_fanlevel\n      { did: \"mode\", siid: 2, piid: 4 }, // airpurifier_zhimi_mode\n      { did: \"humidity\", siid: 3, piid: 1 }, // measure_humidity\n      { did: \"temperature\", siid: 3, piid: 7 }, // measure_temperature\n      { did: \"aqi\", siid: 3, piid: 4 }, // measure_pm25\n      { did: \"anion\", siid: 2, piid: 6 }, // onoff.ion\n      { did: \"buzzer\", siid: 6, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 8, piid: 1 }, // settings.childLock\n      { did: \"light\", siid: 13, piid: 2 }, // settings.led\n      { did: \"filter_life_remaining\", siid: 4, piid: 1 }, // settings.filter_life_remaining\n      { did: \"filter_hours_used\", siid: 4, piid: 3 }, // settings.filter_hours_used\n      { did: \"purify_volume\", siid: 11, piid: 1 } // settings.purify_volume\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"ion\": { siid: 2, piid: 6 },\n      \"fanlevel\": { siid: 2, piid: 5 },\n      \"mode\": {siid: 2, piid: 4 },\n      \"buzzer\": { siid: 5, piid: 1 },\n      \"child_lock\": { siid: 8, piid: 1 },\n      \"light\": { siid: 13, piid: 2 }\n    },\n    \"device_properties\": {\n      \"light\": { \"min\": 0, \"max\": 2 }\n    }\n  },\n  \"mapping_vb4\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"fanlevel\", siid : 2, piid: 5 }, // airpurifier_zhimi_fanlevel\n      { did: \"mode\", siid: 2, piid: 4 }, // airpurifier_zhimi_mode\n      { did: \"humidity\", siid: 3, piid: 1 }, // measure_humidity\n      { did: \"temperature\", siid: 3, piid: 7 }, // measure_temperature\n      { did: \"aqi\", siid: 3, piid: 4 }, // measure_pm25\n      { did: \"anion\", siid: 2, piid: 6 }, // onoff.ion\n      { did: \"buzzer\", siid: 6, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 8, piid: 1 }, // settings.childLock\n      { did: \"light\", siid: 13, piid: 2 }, // settings.led\n      { did: \"filter_life_remaining\", siid: 4, piid: 1 }, // settings.filter_life_remaining\n      { did: \"filter_hours_used\", siid: 4, piid: 3 }, // settings.filter_hours_used\n      { did: \"purify_volume\", siid: 11, piid: 1 } // settings.purify_volume\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"ion\": { siid: 2, piid: 6 },\n      \"fanlevel\": { siid: 2, piid: 5 },\n      \"mode\": {siid: 2, piid: 4 },\n      \"buzzer\": { siid: 6, piid: 1 },\n      \"child_lock\": { siid: 8, piid: 1 },\n      \"light\": { siid: 13, piid: 2 }\n    },\n    \"device_properties\": {\n      \"light\": { \"min\": 0, \"max\": 2 }\n    }\n  },\n  \"mapping_rma1\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"mode\", siid: 2, piid: 4 }, // airpurifier_zhimi_mode\n      { did: \"humidity\", siid: 3, piid: 1 }, // measure_humidity\n      { did: \"temperature\", siid: 3, piid: 7 }, // measure_temperature\n      { did: \"aqi\", siid: 3, piid: 4 }, // measure_pm25\n      { did: \"buzzer\", siid: 6, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 8, piid: 1 }, // settings.childLock\n      { did: \"light\", siid: 13, piid: 2 }, // settings.led\n      { did: \"filter_life_remaining\", siid: 4, piid: 1 }, // settings.filter_life_remaining\n      { did: \"filter_hours_used\", siid: 4, piid: 3 } // settings.filter_hours_used\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"mode\": {siid: 2, piid: 4 },\n      \"buzzer\": { siid: 6, piid: 1 },\n      \"child_lock\": { siid: 8, piid: 1 },\n      \"light\": { siid: 13, piid: 2 }\n    },\n    \"device_properties\": {\n      \"light\": { \"min\": 0, \"max\": 2 }\n    }\n  },\n  \"mapping_rmb1\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"mode\", siid: 2, piid: 4 }, // airpurifier_zhimi_mode\n      { did: \"humidity\", siid: 3, piid: 1 }, // measure_humidity\n      { did: \"temperature\", siid: 3, piid: 7 }, // measure_temperature\n      { did: \"aqi\", siid: 3, piid: 4 }, // measure_pm25\n      { did: \"buzzer\", siid: 6, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 8, piid: 1 }, // settings.childLock\n      { did: \"light\", siid: 13, piid: 2 }, // settings.led\n      { did: \"filter_life_remaining\", siid: 4, piid: 1 }, // settings.filter_life_remaining\n      { did: \"filter_hours_used\", siid: 4, piid: 3 } // settings.filter_hours_used\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"mode\": {siid: 2, piid: 4 },\n      \"buzzer\": { siid: 6, piid: 1 },\n      \"child_lock\": { siid: 8, piid: 1 },\n      \"light\": { siid: 13, piid: 2 }\n    },\n    \"device_properties\": {\n      \"light\": { \"min\": 0, \"max\": 2 }\n    }\n  },\n  \"mapping_za1\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"mode\", siid: 2, piid: 5 }, // airpurifier_zhimi_mode\n      { did: \"humidity\", siid: 3, piid: 7 }, // measure_humidity\n      { did: \"temperature\", siid: 3, piid: 8 }, // measure_temperature\n      { did: \"aqi\", siid: 3, piid: 6 }, // measure_pm25\n      { did: \"buzzer\", siid: 5, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 7, piid: 1 }, // settings.childLock\n      { did: \"light\", siid: 6, piid: 1 }, // settings.led\n      { did: \"filter_life_remaining\", siid: 4, piid: 3 }, // settings.filter_life_remaining\n      { did: \"filter_hours_used\", siid: 4, piid: 5 }, // settings.filter_hours_used\n      { did: \"purify_volume\", siid: 13, piid: 1 } // settings.purify_volume\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"mode\": {siid: 2, piid: 5 },\n      \"buzzer\": { siid: 5, piid: 1 },\n      \"child_lock\": { siid: 7, piid: 1 },\n      \"light\": { siid: 6, piid: 1 }\n    },\n    \"device_properties\": {\n      \"light\": { \"min\": 2, \"max\": 0 }\n    }\n  },\n  \"mapping_airp_meb1\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"mode\", siid: 2, piid: 4 }, // airpurifier_zhimi_mode\n      { did: \"fanlevel\", siid : 2, piid: 5 }, // airpurifier_zhimi_fanlevel\n      { did: \"humidity\", siid: 3, piid: 1 }, // measure_humidity\n      { did: \"aqi\", siid: 3, piid: 4 }, // measure_pm25\n      { did: \"temperature\", siid: 3, piid: 7 }, // measure_temperature\n      { did: \"buzzer\", siid: 6, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 8, piid: 1 }, // settings.childLock\n      { did: \"light\", siid: 13, piid: 2 }, // settings.led\n      { did: \"filter_life_remaining\", siid: 4, piid: 1 }, // settings.filter_life_remaining\n      { did: \"filter_hours_used\", siid: 4, piid: 3 } // settings.filter_hours_used\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"fanlevel\": { siid: 2, piid: 5 },\n      \"mode\": { siid: 2, piid: 4 },\n      \"buzzer\": { siid: 6, piid: 1 },\n      \"child_lock\": { siid: 8, piid: 1 },\n      \"light\": { siid: 13, piid: 2 }\n    },\n    \"device_properties\": {\n      \"light\": { \"min\": 0, \"max\": 2 }\n    }\n  },\n  \"mapping_cpa4\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"mode\", siid: 2, piid: 4 }, // airpurifier_zhimi_mode\n      { did: \"aqi\", siid: 3, piid: 4 }, // measure_pm25\n      { did: \"buzzer\", siid: 6, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 8, piid: 1 }, // settings.childLock\n      { did: \"light\", siid: 13, piid: 2 }, // settings.led\n      { did: \"filter_life_remaining\", siid: 4, piid: 1 }, // settings.filter_life_remaining\n      { did: \"filter_hours_used\", siid: 4, piid: 3 }, // settings.filter_hours_used\n      { did: \"fanlevel\", siid: 9, piid: 11 }, // airpurifier_xiaomi_fanlevel\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"mode\": { siid: 2, piid: 4 },\n      \"buzzer\": { siid: 6, piid: 1 },\n      \"child_lock\": { siid: 8, piid: 1 },\n      \"light\": { siid: 13, piid: 2 },\n      \"fanlevel\": { siid: 9, piid: 11 }\n    },\n    \"device_properties\": {\n      \"light\": { \"min\": 0, \"max\": 2 }\n    }\n  },\n}\n\nconst modes = {\n  0: \"Auto\",\n  1: \"Night\",\n  2: \"Favorite\",\n  3: \"Idle\"\n};\n\nclass AdvancedMiAirPurifierMiotDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // ADD DEVICES DEPENDANT CAPABILITIES\n      if (this.getStoreValue('model') === 'xiaomi.airp.cpa4' && this.hasCapability('airpurifier_zhimi_fanlevel')) {\n        this.removeCapability('airpurifier_zhimi_fanlevel');\n      }\n      if (this.getStoreValue('model') === 'xiaomi.airp.cpa4' && !this.hasCapability('airpurifier_xiaomi_fanlevel')) {\n        this.addCapability('airpurifier_xiaomi_fanlevel');\n      }\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['zhimi.airpurifier.*']];\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.power.siid, piid: this.deviceProperties.set_properties.power.piid, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('onoff.ion', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.ion.siid, piid: this.deviceProperties.set_properties.power.ion, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('airpurifier_zhimi_fanlevel', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.fanlevel.siid, piid: this.deviceProperties.set_properties.fanlevel.piid, value: +value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('airpurifier_xiaomi_fanlevel', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.fanlevel.siid, piid: this.deviceProperties.set_properties.fanlevel.piid, value: +value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('airpurifier_zhimi_mode', async (value) => {\n        try {\n          if (this.miio) {\n            const mode = modes[value];\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.mode.siid, piid: this.deviceProperties.set_properties.mode.piid, value: +value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      const led = await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.light.siid, piid: this.deviceProperties.set_properties.light.piid, value: newSettings.led ? this.deviceProperties.device_properties.light.max : this.deviceProperties.device_properties.light.min }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"buzzer\")) {\n      const buzzer = await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.buzzer.siid, piid: this.deviceProperties.set_properties.buzzer.piid, value: newSettings.buzzer }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"childLock\")) {\n      const childlock = await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.child_lock.siid, piid: this.deviceProperties.set_properties.child_lock.piid, value: newSettings.childLock }], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const onoff = result.find(obj => obj.did === 'power');\n      const fanlevel = result.find(obj => obj.did === 'fanlevel');\n      const measure_humidity = result.find(obj => obj.did === 'humidity');\n      const measure_temperature = result.find(obj => obj.did === 'temperature');\n      const measure_pm25 = result.find(obj => obj.did === 'aqi');\n      const onoff_ion = result.find(obj => obj.did === 'anion');\n\n      const buzzer = result.find(obj => obj.did === 'buzzer');\n      const child_lock = result.find(obj => obj.did === 'child_lock');\n      const led = result.find(obj => obj.did === 'light');\n      const filter_life_remaining = result.find(obj => obj.did === 'filter_life_remaining');\n      const filter_hours_used = result.find(obj => obj.did === 'filter_hours_used');\n      const purify_volume = result.find(obj => obj.did === 'purify_volume');\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"onoff\", onoff.value);\n      if (measure_humidity !== undefined) {\n        await this.updateCapabilityValue(\"measure_humidity\", measure_humidity.value);\n      }\n      if (measure_temperature !== undefined) {\n        await this.updateCapabilityValue(\"measure_temperature\", measure_temperature.value);\n      }\n      await this.updateCapabilityValue(\"measure_pm25\", measure_pm25.value);\n\n      if (onoff_ion !== undefined) {\n        await this.updateCapabilityValue(\"onoff.ion\", onoff_ion.value);\n      }\n\n      /* settings */\n      await this.updateSettingValue(\"led\", led.value === this.deviceProperties.device_properties.light.min ? false : true);\n      await this.updateSettingValue(\"buzzer\", buzzer.value);\n      await this.updateSettingValue(\"childLock\", child_lock.value);\n      await this.updateSettingValue(\"filter_life_remaining\", filter_life_remaining.value + '%');\n      await this.updateSettingValue(\"filter_hours_used\", filter_hours_used.value + 'h');\n      if (purify_volume !== undefined) {\n        await this.updateSettingValue(\"purify_volume\", purify_volume.value + 'm3');\n      }\n\n      /* mode capability */\n      const mode = result.find(obj => obj.did === 'mode');\n      if (this.getCapabilityValue('airpurifier_zhimi_mode') !== mode.value.toString()) {\n        const previous_mode = this.getCapabilityValue('airpurifier_zhimi_mode');\n        await this.setCapabilityValue('airpurifier_zhimi_mode', mode.value.toString());\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, {\"new_mode\": modes[mode.value], \"previous_mode\": modes[+previous_mode] }).catch(error => { this.error(error) });\n      }\n\n      /* device specific settings */\n      if (this.getStoreValue('model') === 'xiaomi.airp.cpa4' && fanlevel !== undefined) {\n        await this.updateCapabilityValue(\"airpurifier_xiaomi_fanlevel\", Number(fanlevel.value));\n      } else if (fanlevel !== undefined) {\n        await this.updateCapabilityValue(\"airpurifier_zhimi_fanlevel\", fanlevel.value.toString());\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = AdvancedMiAirPurifierMiotDevice;\n"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Advanced Mi Air Purifier MIoT (WiFi)\",\n    \"nl\": \"Geavanceerde Mi Air Purifier MIoT (WiFi)\",\n    \"da\": \"Avanceret Mi Air Purifier MIoT (WiFi)\",\n    \"de\": \"Erweiterter Mi Air Purifier MIoT (WiFi)\",\n    \"es\": \"Purificador de aire Mi avanzado MIoT (WiFi)\",\n    \"fr\": \"Purificateur d'air Mi avancé MIoT (WiFi)\",\n    \"it\": \"Purificatore d'aria Mi Avanzato MIoT (WiFi)\",\n    \"no\": \"Avansert Mi Air Purifier MIoT (WiFi)\",\n    \"sv\": \"Avancerad Mi Air Purifier MIoT (WiFi)\",\n    \"pl\": \"Zaawansowany Mi Air Purifier MIoT (WiFi)\",\n    \"ru\": \"Продвинутый воздухоочиститель Mi MIoT (WiFi)\",\n    \"ko\": \"고급 Mi Air Purifier MIoT (WiFi)\",\n    \"ja\": \"高度なMiエア purificador MIoT（WiFi）\",\n    \"zh\": \"高级Mi空气净化器MIoT（WiFi）\"\n  },\n  \"images\": {\n    \"large\": \"drivers/airpurifier_zhimi_advanced_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/airpurifier_zhimi_advanced_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"measure_pm25\",\n    \"airpurifier_zhimi_mode\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.ion\": {\n      \"title\": {\n        \"en\": \"Enable ions\",\n        \"nl\": \"Inschakelen ionen\",\n        \"da\": \"Aktiver ioner\",\n        \"de\": \"Ionen aktivieren\",\n        \"es\": \"Activar iones\",\n        \"fr\": \"Activer les ions\",\n        \"it\": \"Attiva ioni\",\n        \"no\": \"Aktiver ioner\",\n        \"sv\": \"Aktivera joner\",\n        \"pl\": \"Włącz jony\",\n        \"ru\": \"Включить ионы\",\n        \"ko\": \"이온 활성화\",\n        \"ja\": \"イオンを有効にする\",\n        \"zh\": \"启用离子\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass AdvancedMiAirPurifierMiotDriver extends Driver {}\n\nmodule.exports = AdvancedMiAirPurifierMiotDriver;"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"Светодиод\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summer\",\n          \"de\": \"Summton\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Buzzer\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Summer\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Brzęczyk\",\n          \"ru\": \"Звуковой сигнал\",\n          \"ko\": \"버저\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnelås\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo Infantil\",\n          \"fr\": \"Verrouillage enfant\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barnelås\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada rodzicielska\",\n          \"ru\": \"Блокировка от детей\",\n          \"ko\": \"잠금\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Data\",\n      \"nl\": \"Apparaat Data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"기기 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"filter_life_remaining\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter remaining\",\n          \"nl\": \"Filter over\",\n          \"da\": \"Filter tilbage\",\n          \"de\": \"Filter übrig\",\n          \"es\": \"Filtro restante\",\n          \"fr\": \"Filtre restant\",\n          \"it\": \"Filtro rimanente\",\n          \"no\": \"Filter gjenværende\",\n          \"sv\": \"Filter kvar\",\n          \"pl\": \"Pozostało filtra\",\n          \"ru\": \"Остаток фильтра\",\n          \"ko\": \"필터 잔여량\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"filter_hours_used\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter hours used\",\n          \"nl\": \"Filter uur gebruikt\",\n          \"da\": \"Filter timer brugt\",\n          \"de\": \"Filterstunden verwendet\",\n          \"es\": \"Horas de filtro utilizadas\",\n          \"fr\": \"Heures de filtre utilisées\",\n          \"it\": \"Ore di filtro utilizzate\",\n          \"no\": \"Filter timer brukt\",\n          \"sv\": \"Filter timmar användes\",\n          \"pl\": \"Godziny używania filtra\",\n          \"ru\": \"Использованные часы фильтра\",\n          \"ko\": \"필터 사용 시간\"\n        },\n        \"value\": \"0h\"\n      },\n      {\n        \"id\": \"purify_volume\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Air Cleared\",\n          \"nl\": \"Lucht geschoond\",\n          \"da\": \"Luft renset\",\n          \"de\": \"Luft gereinigt\",\n          \"es\": \"Aire purificado\",\n          \"fr\": \"Air purifié\",\n          \"it\": \"Aria ripulita\",\n          \"no\": \"Luft renset\",\n          \"sv\": \"Luft rensad\",\n          \"pl\": \"Oczyszczone powietrze\",\n          \"ru\": \"Воздух очищен\",\n          \"ko\": \"정화된 공기\"\n        },\n        \"value\": \"0m3\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"기기 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/airpurifier_zhimi_advanced_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/aqara-86sw1-advanced/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraWirellesSwitch extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n      \n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n  \n      /* button events */\n      if (device.data.channel_0 === \"click\") { await this.homey.flow.getDeviceTriggerCard('click_single').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.channel_0 === \"double_click\") { await this.homey.flow.getDeviceTriggerCard('click_double').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.channel_0 === \"long_click\") { await this.homey.flow.getDeviceTriggerCard('click_long').trigger(this).catch(error => { this.error(error) }); }\n\n    } catch (error) {\n      this.error(error);\n    }    \n  }\n\n}\n\nmodule.exports = AqaraWirellesSwitch;"
  },
  {
    "path": "drivers/aqara-86sw1-advanced/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Wireless Wall Single Switch gen2 (Gateway)\",\n    \"nl\": \"Aqara Wireless Wall Single Switch gen2 (Gateway)\",\n    \"da\": \"Aqara Trådløs Væg Enkel Switch gen2 (Gateway)\",\n    \"de\": \"Aqara Drahtloser Wandschalter Einzeln gen2 (Gateway)\",\n    \"es\": \"Interruptor de Pared Inalámbrico Simple Aqara gen2 (Gateway)\",\n    \"fr\": \"Interrupteur Mural Sans Fil Simple Aqara gen2 (Gateway)\",\n    \"it\": \"Interruttore da Parete Wireless Singolo Aqara gen2 (Gateway)\",\n    \"no\": \"Aqara Trådløs Vegg Enkel Bryter gen2 (Gateway)\",\n    \"sv\": \"Aqara Trådlös Vägg Enkelt Strömbrytare gen2 (Gateway)\",\n    \"pl\": \"Bezprzewodowy Przełącznik Ścienny Aqara gen2 (Gateway)\",\n    \"ru\": \"Беспроводной Настенный Переключатель Aqara gen2 (Шлюз)\",\n    \"ko\": \"Aqara 무선 벽 단일 스위치 gen2 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-86sw1-advanced/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-86sw1-advanced/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2032\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/aqara-86sw1-advanced/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraWirellesSwitch extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('click_single');\n    this.homey.flow.getDeviceTriggerCard('click_double');\n    this.homey.flow.getDeviceTriggerCard('click_long');\n\n    this.config = {\n      model: [\"remote.b186acn01\"]\n    }\n  }\n\n}\n\nmodule.exports = AqaraWirellesSwitch;"
  },
  {
    "path": "drivers/aqara-86sw1-advanced/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-86sw2-advanced/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraWirellesSwitch extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n\n      /* button events */\n      if (device.data.channel_0 === \"click\") { await this.homey.flow.getDeviceTriggerCard('click_single_left').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.channel_0 === \"double_click\") { await this.homey.flow.getDeviceTriggerCard('click_double_left').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.channel_0 === \"long_click\") { await this.homey.flow.getDeviceTriggerCard('click_long_left').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.channel_1 === \"click\") { await this.homey.flow.getDeviceTriggerCard('click_single_right').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.channel_1 === \"double_click\") { await this.homey.flow.getDeviceTriggerCard('click_double_right').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.channel_1 === \"long_click\") { await this.homey.flow.getDeviceTriggerCard('click_long_left').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.dual_channel) { await this.homey.flow.getDeviceTriggerCard('click_single_left_right').trigger(this).catch(error => { this.error(error) }); }\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraWirellesSwitch;"
  },
  {
    "path": "drivers/aqara-86sw2-advanced/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Wireless Wall Double Switch gen2 (Gateway)\",\n    \"nl\": \"Aqara Wireless Wall Double Switch gen2 (Gateway)\",\n    \"da\": \"Aqara trådløs væg dobbeltkontakt gen2 (Gateway)\",\n    \"de\": \"Aqara Drahtloser Wandschalter doppelt gen2 (Gateway)\",\n    \"es\": \"Aqara Interruptor de pared inalámbrico doble gen2 (Gateway)\",\n    \"fr\": \"Interrupteur mural sans fil double Aqara gen2 (Gateway)\",\n    \"it\": \"Interruttore da parete wireless doppio Aqara gen2 (Gateway)\",\n    \"no\": \"Aqara trådløs veggbryter dobbel gen2 (Gateway)\",\n    \"sv\": \"Aqara trådlös väggbrytare dubbel gen2 (Gateway)\",\n    \"pl\": \"Aqara bezprzewodowy podwójny przełącznik ścienny gen2 (Gateway)\",\n    \"ru\": \"Aqara Беспроводной настенный двойной выключатель gen2 (Шлюз)\",\n    \"ko\": \"Aqara 무선 벽 2 배 스위치 gen2 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-86sw2-advanced/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-86sw2-advanced/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2032\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/aqara-86sw2-advanced/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraWirellesSwitch extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('click_single_left');\n    this.homey.flow.getDeviceTriggerCard('click_double_left');\n    this.homey.flow.getDeviceTriggerCard('click_long_left');\n    this.homey.flow.getDeviceTriggerCard('click_single_right');\n    this.homey.flow.getDeviceTriggerCard('click_double_right');\n    this.homey.flow.getDeviceTriggerCard('click_long_right');\n    this.homey.flow.getDeviceTriggerCard('click_single_left_right');\n\n    this.config = {\n      model: [\"remote.b286acn01\", \"lumi.remote.b286acn02\", \"remote.b286acn02\"]\n    }\n    \n  }\n\n}\n\nmodule.exports = AqaraWirellesSwitch;"
  },
  {
    "path": "drivers/aqara-86sw2-advanced/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"pt\": \"Configurações do dispositivo\",\n      \"fi\": \"Laitteen asetukset\",\n      \"ja\": \"デバイス設定\",\n      \"zh\": \"设备设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-button/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraButton extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n  \n      /* button events */\n      if (device.data.status === \"click\") { await this.homey.flow.getDeviceTriggerCard('click_single').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"double_click\") { await this.homey.flow.getDeviceTriggerCard('click_double').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"long_click_press\") { await this.homey.flow.getDeviceTriggerCard('click_long').trigger(this).catch(error => { this.error(error) }); }\n  \n    } catch (error) {\n      this.error(error);\n    }\n  }\n  \n}\n\nmodule.exports = AqaraButton;"
  },
  {
    "path": "drivers/aqara-button/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Wireless Button (Gateway)\",\n    \"nl\": \"Aqara Wireless Button (Gateway)\",\n    \"da\": \"Aqara Trådløs Knap (Gateway)\",\n    \"de\": \"Aqara Kabelloser Knopf (Gateway)\",\n    \"es\": \"Botón Inalámbrico Aqara (Gateway)\",\n    \"fr\": \"Bouton Sans Fil Aqara (Gateway)\",\n    \"it\": \"Pulsante Wireless Aqara (Gateway)\",\n    \"no\": \"Aqara Trådløs Knapp (Gateway)\",\n    \"sv\": \"Aqara Trådlös Knapp (Gateway)\",\n    \"pl\": \"Bezprzewodowy Przycisk Aqara (Gateway)\",\n    \"ru\": \"Беспроводная Кнопка Aqara (Gateway)\",\n    \"ko\": \"아카라 무선 버튼 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-button/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-button/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2032\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/aqara-button/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraButton extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('click_single');\n    this.homey.flow.getDeviceTriggerCard('click_double');\n    this.homey.flow.getDeviceTriggerCard('click_long');\n\n    this.config = {\n      model: [\"sensor_switch.aq2\", \"sensor_switch\", \"remote.b1acn01\"]\n    }\n\n  }\n\n}\n\nmodule.exports = AqaraButton;"
  },
  {
    "path": "drivers/aqara-button/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"ja\": \"デバイス設定\",\n      \"zh\": \"设备设置\",\n      \"pt\": \"Configurações do dispositivo\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-button-advanced/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraButtonAdvanced extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n  \n      /* button events */\n      if (device.data.status === \"click\") { await this.homey.flow.getDeviceTriggerCard('click_single').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"double_click\") { await this.homey.flow.getDeviceTriggerCard('click_double').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"long_click_press\") { await this.homey.flow.getDeviceTriggerCard('click_long').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"long_click_release\") { await this.homey.flow.getDeviceTriggerCard('click_long_release').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"shake\") { await this.homey.flow.getDeviceTriggerCard('shake').trigger(this).catch(error => { this.error(error) }); }\n  \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraButtonAdvanced;"
  },
  {
    "path": "drivers/aqara-button-advanced/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Wireless Button gen2 (Gateway)\",\n    \"nl\": \"Aqara Wireless Button gen2 (Gateway)\",\n    \"da\": \"Aqara trådløs knap gen2 (Gateway)\",\n    \"de\": \"Aqara kabellose Taste gen2 (Gateway)\",\n    \"es\": \"Botón inalámbrico Aqara gen2 (Gateway)\",\n    \"fr\": \"Bouton sans fil Aqara gen2 (Gateway)\",\n    \"it\": \"Pulsante wireless Aqara gen2 (Gateway)\",\n    \"no\": \"Aqara trådløs knapp gen2 (Gateway)\",\n    \"sv\": \"Aqara trådlös knapp gen2 (Gateway)\",\n    \"pl\": \"Bezprzewodowy przycisk Aqara gen2 (Gateway)\",\n    \"ru\": \"Беспроводная кнопка Aqara gen2 (Gateway)\",\n    \"ko\": \"아카라 무선 버튼 2세대 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-button-advanced/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-button-advanced/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2032\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/aqara-button-advanced/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraButtonAdvanced extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('click_single');\n    this.homey.flow.getDeviceTriggerCard('click_double');\n    this.homey.flow.getDeviceTriggerCard('click_long');\n    this.homey.flow.getDeviceTriggerCard('click_long_release');\n    this.homey.flow.getDeviceTriggerCard('shake');\n\n    this.config = {\n      model: [\"sensor_switch.aq3\"]\n    }\n  }\n\n}\n\nmodule.exports = AqaraButtonAdvanced;"
  },
  {
    "path": "drivers/aqara-button-advanced/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-ctrl-ln1/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraCtrlLn1SwitchDevice extends Device {\n\n  async registerCapabilities() {\n    this.registerCapabilityListener('onoff', async (value) => {\n      try {\n        return await this.homey.app.mihub.sendWrite(this.data.sid, { channel_0: value ? \"on\" : \"off\" });\n      } catch (error) {\n        this.error(error);\n      }\n    });\n  }\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* onoff */\n      if (device.data.channel_0) { await this.updateCapabilityValue(\"onoff\", device.data.channel_0 === \"on\" ? true : false); }\n      \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraCtrlLn1SwitchDevice;"
  },
  {
    "path": "drivers/aqara-ctrl-ln1/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Smart Wall Single Switch With Neutral (Gateway)\",\n    \"nl\": \"Aqara Smart Wall Single Switch met nuldraad (Gateway)\",\n    \"da\": \"Aqara Smart Wall Single Switch med neutral (Gateway)\",\n    \"de\": \"Aqara Smart Wall Single Switch mit Neutralleiter (Gateway)\",\n    \"es\": \"Interruptor simple de pared inteligente Aqara con neutro (Gateway)\",\n    \"fr\": \"Interrupteur mural simple intelligent Aqara avec neutre (Gateway)\",\n    \"it\": \"Interruttore singolo da parete Aqara con neutro (Gateway)\",\n    \"no\": \"Aqara Smart veggbryter med nøytral (Gateway)\",\n    \"sv\": \"Aqara Smart Wall enkel brytare med neutral (Gateway)\",\n    \"pl\": \"Pojedynczy włącznik Aqara Smart Wall z neutralnym przewodem (Gateway)\",\n    \"ru\": \"Aqara умный настенный выключатель с нейтральным проводом (Gateway)\",\n    \"ko\": \"Aqara 스마트 벽 단일 스위치 중립선 포함 (Gateway)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-ctrl-ln1/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-ctrl-ln1/assets/images/small.png\"\n  },\n  \"class\": \"light\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"onoff\"\n  ]\n}"
  },
  {
    "path": "drivers/aqara-ctrl-ln1/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraCtrlLn1SwitchDriver extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.config = {\n      model: [\"ctrl_ln1.aq1\", \"switch_b1nacn02\"]\n    }\n    \n  }\n\n}\n\nmodule.exports = AqaraCtrlLn1SwitchDriver;"
  },
  {
    "path": "drivers/aqara-ctrl-ln1/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-ctrl-ln2/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraCtrlLn2SwitchDevice extends Device {\n\n  async registerCapabilities() {\n\n    this.registerCapabilityListener('onoff.0', async (value) => {\n      try {\n        return await this.homey.app.mihub.sendWrite(this.data.sid, { channel_0: value ? \"on\" : \"off\" });\n      } catch (error) {\n        this.error(error);\n      }\n    });\n    this.registerCapabilityListener('onoff.1', async (value) => {\n      try {\n        return await this.homey.app.mihub.sendWrite(this.data.sid, { channel_1: value ? \"on\" : \"off\" });\n      } catch (error) {\n        this.error(error);\n      }\n    });\n  }\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* onoff left switch */\n      if (device.data[\"channel_0\"]) {\n        await this.updateCapabilityValue(\"onoff.0\", device.data[\"channel_0\"] == \"on\" ? true : false);\n  \n        if (device.data[\"channel_0\"] == \"on\") {\n          await this.homey.flow.getDeviceTriggerCard('leftSwitchOn').trigger(this).catch(error => { this.error(error) });\n        } else if (device.data[\"channel_0\"] == \"off\") {\n          await this.homey.flow.getDeviceTriggerCard('leftSwitchOff').trigger(this).catch(error => { this.error(error) });\n        }\n      }\n\n      /* onoff right switch */\n      if (device.data.channel_1) {\n        await this.updateCapabilityValue(\"onoff.1\", device.data.channel_1 === \"on\" ? true : false);\n  \n        if (device.data.channel_1 === \"on\") {\n          await this.homey.flow.getDeviceTriggerCard('rightSwitchOn').trigger(this).catch(error => { this.error(error) });\n        } else if (device.data.channel_1 === \"off\") {\n          await this.homey.flow.getDeviceTriggerCard('rightSwitchOff').trigger(this).catch(error => { this.error(error) });\n        }\n      }\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraCtrlLn2SwitchDevice;"
  },
  {
    "path": "drivers/aqara-ctrl-ln2/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Smart Wall Double Switch With Neutral (Gateway)\",\n    \"nl\": \"Aqara Smart Wall Double Switch met nuldraad (Gateway)\",\n    \"da\": \"Aqara Smart Wall Dobbeltkontakt med Neutral (Gateway)\",\n    \"de\": \"Aqara Smart Wall Doppelschalter mit Neutralleiter (Gateway)\",\n    \"es\": \"Interruptor Doble de Pared Inteligente Aqara con Neutro (Gateway)\",\n    \"fr\": \"Double Interrupteur Mural Intelligent Aqara avec Neutre (Gateway)\",\n    \"it\": \"Interruttore Doppio da Parete Intelligente Aqara con Neutro (Gateway)\",\n    \"no\": \"Aqara Smart Vegg Dobbelbryter med Nøytral (Gateway)\",\n    \"sv\": \"Aqara Smart Vägg Dubbelbrytare med Neutral (Gateway)\",\n    \"pl\": \"Aqara Inteligentny Podwójny Włącznik Ścienny z Przewodem Neutralnym (Gateway)\",\n    \"ru\": \"Aqara Умный Настенный Двойной Выключатель с Нулевым (Шлюз)\",\n    \"ko\": \"아카라 스마트 벽면 더블 스위치 중성선 포함 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-ctrl-ln2/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-ctrl-ln2/assets/images/small.png\"\n  },\n  \"class\": \"light\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"onoff.0\",\n    \"onoff.1\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.0\": {\n      \"title\": {\n        \"en\": \"Left button\",\n        \"nl\": \"Linkerknop\",\n        \"da\": \"Venstre knap\",\n        \"de\": \"Linker Knopf\",\n        \"es\": \"Botón izquierdo\",\n        \"fr\": \"Bouton gauche\",\n        \"it\": \"Pulsante sinistro\",\n        \"no\": \"Venstre knapp\",\n        \"sv\": \"Vänster knapp\",\n        \"pl\": \"Lewy przycisk\",\n        \"ru\": \"Левая кнопка\",\n        \"ko\": \"왼쪽 버튼\"\n      }\n    },\n    \"onoff.1\": {\n      \"title\": {\n        \"en\": \"Right button\",\n        \"nl\": \"Rechterknop\",\n        \"da\": \"Højre knap\",\n        \"de\": \"Rechter Knopf\",\n        \"es\": \"Botón derecho\",\n        \"fr\": \"Bouton droit\",\n        \"it\": \"Pulsante destro\",\n        \"no\": \"Høyre knapp\",\n        \"sv\": \"Höger knapp\",\n        \"pl\": \"Prawy przycisk\",\n        \"ru\": \"Правая кнопка\",\n        \"ko\": \"오른쪽 버튼\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/aqara-ctrl-ln2/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraCtrlLn2SwitchDriver extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('leftSwitchOn');\n    this.homey.flow.getDeviceTriggerCard('leftSwitchOff');\n    this.homey.flow.getDeviceTriggerCard('rightSwitchOn');\n    this.homey.flow.getDeviceTriggerCard('rightSwitchOff');\n\n    this.config = {\n      model: [\"ctrl_ln2.aq1\", \"switch_b2nacn02\"]\n    }\n    \n  }\n\n}\n\nmodule.exports = AqaraCtrlLn2SwitchDriver;"
  },
  {
    "path": "drivers/aqara-ctrl-ln2/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-ctrl-neutral1/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraNeutralSwitch extends Device {\n\n  async registerCapabilities() {\n    this.registerCapabilityListener('onoff', async (value) => {\n      try {\n        return await this.homey.app.mihub.sendWrite(this.data.sid, { channel_0: value ? \"on\" : \"off\" });\n      } catch (error) {\n        this.error(error);\n      }\n    });\n  }\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* onoff */\n      if (device.data.channel_0) { await this.updateCapabilityValue(\"onoff\", device.data.channel_0 === \"on\" ? true : false); }\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraNeutralSwitch;"
  },
  {
    "path": "drivers/aqara-ctrl-neutral1/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Smart Wall Single Switch No Neutral (Gateway)\",\n    \"nl\": \"Aqara Smart Wall Single Switch zonder nuldraad (Gateway)\",\n    \"da\": \"Aqara Smart Wall Enkelt Switch Ingen Neutral (Gateway)\",\n    \"de\": \"Aqara Smart Wall Einzelner Schalter Ohne Neutralleiter (Gateway)\",\n    \"es\": \"Aqara Smart Wall Interruptor Único Sin Neutro (Gateway)\",\n    \"fr\": \"Aqara Smart Wall Interrupteur Simple Sans Neutre (Gateway)\",\n    \"it\": \"Aqara Smart Wall Interruttore Singolo Senza Neutro (Gateway)\",\n    \"no\": \"Aqara Smart Wall Enkel Bryter Ingen Nøytral (Gateway)\",\n    \"sv\": \"Aqara Smart Wall Enkel Switch Ingen Neutral (Gateway)\",\n    \"pl\": \"Aqara Smart Wall Pojedynczy Przełącznik Bez Neutralnego (Gateway)\",\n    \"ru\": \"Aqara Smart Wall Одинарный Выключатель Без Нейтрального Провода (Gateway)\",\n    \"ko\": \"Aqara Smart Wall 단일 스위치 중성선 없음 (Gateway)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-ctrl-neutral1/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-ctrl-neutral1/assets/images/small.png\"\n  },\n  \"class\": \"light\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"onoff\"\n  ]\n}"
  },
  {
    "path": "drivers/aqara-ctrl-neutral1/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraSwitch extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.config = {\n      model: [\"ctrl_neutral1\", \"switch_b1lacn02\"]\n    }\n    \n  }\n}\n\nmodule.exports = AqaraSwitch;"
  },
  {
    "path": "drivers/aqara-ctrl-neutral1/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuraciones del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-ctrl-neutral2/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraNeutral2Switch extends Device {\n\n  async registerCapabilities() {\n\n    this.registerCapabilityListener('onoff.0', async (value) => {\n      try {\n        return await this.homey.app.mihub.sendWrite(this.data.sid, { channel_0: value ? \"on\" : \"off\" });\n      } catch (error) {\n        this.error(error);\n      }\n    });\n    this.registerCapabilityListener('onoff.1', async (value) => {\n      try {\n        return await this.homey.app.mihub.sendWrite(this.data.sid, { channel_1: value ? \"on\" : \"off\" });\n      } catch (error) {\n        this.error(error);\n      }\n    });\n  }\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* onoff left switch */\n      if (device.data[\"channel_0\"]) {\n        await this.updateCapabilityValue(\"onoff.0\", device.data[\"channel_0\"] == \"on\" ? true : false);\n  \n        if (device.data[\"channel_0\"] == \"on\") {\n          await this.homey.flow.getDeviceTriggerCard('leftSwitchOn').trigger(this).catch(error => { this.error(error) });\n        } else if (device.data[\"channel_0\"] == \"off\") {\n          await this.homey.flow.getDeviceTriggerCard('leftSwitchOff').trigger(this).catch(error => { this.error(error) });\n        }\n      }\n\n      /* onoff right switch */\n      if (device.data.channel_1) {\n        await this.updateCapabilityValue(\"onoff.1\", device.data.channel_1 === \"on\" ? true : false);\n  \n        if (device.data.channel_1 === \"on\") {\n          await this.homey.flow.getDeviceTriggerCard('rightSwitchOn').trigger(this).catch(error => { this.error(error) });\n        } else if (device.data.channel_1 === \"off\") {\n          await this.homey.flow.getDeviceTriggerCard('rightSwitchOff').trigger(this).catch(error => { this.error(error) });\n        }\n      }\n      \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraNeutral2Switch;"
  },
  {
    "path": "drivers/aqara-ctrl-neutral2/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Smart Wall Double Switch No Neutral (Gateway)\",\n    \"nl\": \"Aqara Smart Wall Double Switch zonder nuldraad (Gateway)\",\n    \"da\": \"Aqara Smart Væg Dobbeltafbryder Uden Neutral (Gateway)\",\n    \"de\": \"Aqara Smart Wanddoppelschalter Ohne Neutralleiter (Gateway)\",\n    \"es\": \"Interruptor Doble de Pared Inteligente Aqara Sin Neutro (Gateway)\",\n    \"fr\": \"Interrupteur Double Intelligent Aqara Sans Neutre (Gateway)\",\n    \"it\": \"Interruttore Doppio a Parete Intelligente Aqara Senza Neutro (Gateway)\",\n    \"no\": \"Aqara Smart Vegg Dobbel Bryter Uten Nøytral (Gateway)\",\n    \"sv\": \"Aqara Smart Vägg Dubbel Switch Utan Neutral (Gateway)\",\n    \"pl\": \"Aqara Smart Podwójny Włącznik Ścienny Bez N (Gateway)\",\n    \"ru\": \"Умный Настенный Двойной Выключатель Aqara Без Нейтрали (Шлюз)\",\n    \"ko\": \"아카라 스마트 벽 스위치 더블 무중성 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-ctrl-neutral2/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-ctrl-neutral2/assets/images/small.png\"\n  },\n  \"class\": \"light\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"onoff.0\",\n    \"onoff.1\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.0\": {\n      \"title\": {\n        \"en\": \"Left button\",\n        \"nl\": \"Linkerknop\",\n        \"da\": \"Venstre knap\",\n        \"de\": \"Linker Knopf\",\n        \"es\": \"Botón izquierdo\",\n        \"fr\": \"Bouton gauche\",\n        \"it\": \"Pulsante sinistro\",\n        \"no\": \"Venstre knapp\",\n        \"sv\": \"Vänster knapp\",\n        \"pl\": \"Lewy przycisk\",\n        \"ru\": \"Левая кнопка\",\n        \"ko\": \"왼쪽 버튼\"\n      }\n    },\n    \"onoff.1\": {\n      \"title\": {\n        \"en\": \"Right button\",\n        \"nl\": \"Rechterknop\",\n        \"da\": \"Højre knap\",\n        \"de\": \"Rechter Knopf\",\n        \"es\": \"Botón derecho\",\n        \"fr\": \"Bouton droit\",\n        \"it\": \"Pulsante destro\",\n        \"no\": \"Høyre knapp\",\n        \"sv\": \"Höger knapp\",\n        \"pl\": \"Prawy przycisk\",\n        \"ru\": \"Правая кнопка\",\n        \"ko\": \"오른쪽 버튼\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/aqara-ctrl-neutral2/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraNeutral2Switch extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('leftSwitchOn');\n    this.homey.flow.getDeviceTriggerCard('leftSwitchOff');\n    this.homey.flow.getDeviceTriggerCard('rightSwitchOn');\n    this.homey.flow.getDeviceTriggerCard('rightSwitchOff');\n\n    this.config = {\n      model: [\"ctrl_neutral2\", \"switch_b2lacn02\"]\n    }\n    \n  }\n\n}\n\nmodule.exports = AqaraNeutral2Switch;"
  },
  {
    "path": "drivers/aqara-ctrl-neutral2/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-curtain/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraCurtain extends Device {\n\n  async registerCapabilities() {\n    this.registerCapabilityListener('onoff', async (value) => {\n      try {\n        const settings = this.getSettings();\n        if (value) {\n          const data = { curtain_status: settings.reverted ? \"open\" : \"close\" };\n          return await this.homey.app.mihub.sendWrite(this.data.sid, data);\n        } else {\n          const data = { curtain_status: settings.reverted ? \"close\" : \"open\" };\n          return await this.homey.app.mihub.sendWrite(this.data.sid, data);\n        }\n      } catch (error) {\n        this.error(error);\n      }\n    });\n    this.registerCapabilityListener('dim', async (value) => {\n      try {\n        const level = Math.round(value * 100);\n        const data = { curtain_level: level.toString() };\n        return await this.homey.app.mihub.sendWrite(this.data.sid, data);\n      } catch (error) {\n        this.error(error);\n      }\n    });\n    this.registerCapabilityListener('windowcoverings_state', async (value) => {\n      try {\n        const settings = this.getSettings();\n        const states = { up: \"open\", idle: \"stop\", down: \"close\" };\n        if (value == \"up\") {\n          const data = { curtain_status: states[settings.inverted_mode ? \"down\" : \"up\"] };\n          return await this.homey.app.mihub.sendWrite(this.data.sid, data);\n        } else if (value == \"down\") {\n          const data = { curtain_status: states[settings.inverted_mode ? \"up\" : \"down\"] };\n          return await this.homey.app.mihub.sendWrite(this.data.sid, data);\n        } else {\n          const data = { curtain_status: states[value] };\n          return await this.homey.app.mihub.sendWrite(this.data.sid, data);\n        }\n      } catch (error) {\n        this.error(error);\n      }\n    });\n  }\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* onoff */\n      if (parseInt(device.data.curtain_level) > 0) { await this.updateCapabilityValue(\"onoff\", this.getSetting('inverted_state') ? false : true); }\n      if (parseInt(device.data.curtain_level) == 0) { await this.updateCapabilityValue(\"onoff\", this.getSetting('inverted_state') ? true : false); }\n  \n      /* dim (curtain_level) */\n      if (device.data.curtain_level) { await this.updateCapabilityValue(\"dim\", parseInt(device.data.curtain_level) / 100); }\n      this.homey.clearTimeout(this.curtainTernaryTimeout);\n      this.curtainTernaryTimeout = setTimeout(() => {\n        this.setCapabilityValue(\"windowcoverings_state\", \"idle\");\n      }, 3000);\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraCurtain;"
  },
  {
    "path": "drivers/aqara-curtain/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Curtain Motor (Gateway)\",\n    \"nl\": \"Aqara gordijnmotor (Gateway)\",\n    \"da\": \"Aqara gardinmotor (Gateway)\",\n    \"de\": \"Aqara Vorhangmotor (Gateway)\",\n    \"es\": \"Motor de cortina Aqara (Gateway)\",\n    \"fr\": \"Moteur de rideau Aqara (Gateway)\",\n    \"it\": \"Motore per tende Aqara (Gateway)\",\n    \"no\": \"Aqara gardinmotor (Gateway)\",\n    \"sv\": \"Aqara gardinmotor (Gateway)\",\n    \"pl\": \"Silnik zasłonowy Aqara (Gateway)\",\n    \"ru\": \"Шторный мотор Aqara (Gateway)\",\n    \"ko\": \"아카라 커튼 모터 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-curtain/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-curtain/assets/images/small.png\"\n  },\n  \"class\": \"windowcoverings\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"dim\",\n    \"windowcoverings_state\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff\": {\n      \"title\": {\n        \"en\": \"Open Close\",\n        \"da\": \"Åbn Luk\",\n        \"de\": \"Öffnen Schließen\",\n        \"es\": \"Abrir Cerrar\",\n        \"fr\": \"Ouvrir Fermer\",\n        \"it\": \"Apri Chiudi\",\n        \"no\": \"Åpne Lukke\",\n        \"sv\": \"Öppna Stäng\",\n        \"pl\": \"Otwórz Zamknij\",\n        \"ru\": \"Открыть Закрыть\",\n        \"ko\": \"열기 닫기\"\n      },\n      \"greyout\": false\n    },\n    \"dim\": {\n      \"title\": {\n        \"en\": \"Level\",\n        \"da\": \"Niveau\",\n        \"de\": \"Pegel\",\n        \"es\": \"Nivel\",\n        \"fr\": \"Niveau\",\n        \"it\": \"Livello\",\n        \"no\": \"Nivå\",\n        \"sv\": \"Nivå\",\n        \"pl\": \"Poziom\",\n        \"ru\": \"Уровень\",\n        \"ko\": \"수준\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/aqara-curtain/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraCurtain extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.config = {\n      model: [\"curtain\", \"curtain.hagl04\"]\n    }\n    \n  }\n\n}\n\nmodule.exports = AqaraCurtain;"
  },
  {
    "path": "drivers/aqara-curtain/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User settings\",\n      \"nl\": \"Gebruikersinstellingen\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuraciones de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"inverted_mode\",\n        \"type\": \"checkbox\",\n        \"value\": false,\n        \"label\": {\n          \"en\": \"Inverted operation mode\",\n          \"nl\": \"Omgekeerde operatie modus\",\n          \"da\": \"Omvendt driftsindstilling\",\n          \"de\": \"Umgekehrter Betriebsmodus\",\n          \"es\": \"Modo de operación invertido\",\n          \"fr\": \"Mode de fonctionnement inversé\",\n          \"it\": \"Modalità operativa invertita\",\n          \"no\": \"Omvendt driftsmodus\",\n          \"sv\": \"Omvänd driftläge\",\n          \"pl\": \"Odwrócony tryb pracy\",\n          \"ru\": \"Инверсный режим работы\",\n          \"ko\": \"역운전 모드\"\n        }\n      },\n      {\n        \"id\": \"inverted_state\",\n        \"type\": \"checkbox\",\n        \"value\": false,\n        \"label\": {\n          \"en\": \"Inverted state\",\n          \"nl\": \"Omgekeerde status\",\n          \"da\": \"Omvendt tilstand\",\n          \"de\": \"Umgekehrter Zustand\",\n          \"es\": \"Estado invertido\",\n          \"fr\": \"État inversé\",\n          \"it\": \"Stato invertito\",\n          \"no\": \"Omvendt tilstand\",\n          \"sv\": \"Omvänd tillstånd\",\n          \"pl\": \"Odwrócony stan\",\n          \"ru\": \"Инверсное состояние\",\n          \"ko\": \"역상태\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-curtain-aq2/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraCurtainAQ2 extends Device {\n\n  async registerCapabilities() {\n    this.registerCapabilityListener('onoff', async (value) => {\n      try {\n        const newValue = value ? 'open' : 'close';\n        const data = { curtain_status: newValue };\n        return await this.homey.app.mihub.sendWrite(this.data.sid, data);\n      } catch (error) {\n        this.error(error);\n      }\n    });\n    this.registerCapabilityListener('dim', async (value) => {\n      try {\n        const level = Math.round(value * 100);\n        const data = { curtain_level: level.toString() };\n        return await this.homey.app.mihub.sendWrite(this.data.sid, data);\n      } catch (error) {\n        this.error(error);\n      }\n    });\n    this.registerCapabilityListener('windowcoverings_state', async (value) => {\n      try {\n        const settings = this.getSettings();\n        const states = { up: \"open\", idle: \"stop\", down: \"close\" };\n        if (value == \"up\") {\n          const data = { curtain_status: states[settings.inverted_mode ? \"down\" : \"up\"] };\n          return await this.homey.app.mihub.sendWrite(this.data.sid, data);\n        } else if (value == \"down\") {\n          const data = { curtain_status: states[settings.inverted_mode ? \"up\" : \"down\"] };\n          return await this.homey.app.mihub.sendWrite(this.data.sid, data);\n        } else {\n          const data = { curtain_status: states[value] };\n          return await this.homey.app.mihub.sendWrite(this.data.sid, data);\n        }\n      } catch (error) {\n        this.error(error);\n      }\n    });\n  }\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* onoff */\n      if (parseInt(device.data.curtain_level) > 0) { await this.updateCapabilityValue(\"onoff\", this.getSetting('inverted_state') ? false : true); }\n      if (parseInt(device.data.curtain_level) == 0) { await this.updateCapabilityValue(\"onoff\", this.getSetting('inverted_state') ? true : false); }\n  \n      /* dim (curtain_level) */\n      if (device.data.curtain_level) { await this.updateCapabilityValue(\"dim\", parseInt(device.data.curtain_level) / 100); }\n      this.homey.clearTimeout(this.curtainTernaryTimeout);\n      this.curtainTernaryTimeout = setTimeout(() => {\n        this.setCapabilityValue(\"windowcoverings_state\", \"idle\");\n      }, 3000);\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraCurtainAQ2;\n"
  },
  {
    "path": "drivers/aqara-curtain-aq2/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Roller Shade Controller (Gateway)\",\n    \"nl\": \"Aqara Roller Shade Controller (Gateway)\",\n    \"da\": \"Aqara Rullegardin Controller (Gateway)\",\n    \"de\": \"Aqara Rollo-Controller (Gateway)\",\n    \"es\": \"Controlador de Persiana Enrollable Aqara (Gateway)\",\n    \"fr\": \"Contrôleur de Store Enrouleur Aqara (Gateway)\",\n    \"it\": \"Controllore Tapparella Aqara (Gateway)\",\n    \"no\": \"Aqara Rullgardin Kontroller (Gateway)\",\n    \"sv\": \"Aqara Rullgardinskontroll (Gateway)\",\n    \"pl\": \"Sterownik Rolet Aqara (Gateway)\",\n    \"ru\": \"Контроллер роликовых штор Aqara (Gateway)\",\n    \"ko\": \"아카라 롤러 셰이드 컨트롤러 (Gateway)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-curtain-aq2/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-curtain-aq2/assets/images/small.png\"\n  },\n  \"class\": \"windowcoverings\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"dim\",\n    \"windowcoverings_state\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff\": {\n      \"title\": {\n        \"en\": \"Open Close\",\n        \"da\": \"Åben Luk\",\n        \"de\": \"Öffnen Schließen\",\n        \"es\": \"Abrir Cerrar\",\n        \"fr\": \"Ouvrir Fermer\",\n        \"it\": \"Apri Chiudi\",\n        \"no\": \"Åpne Lukk\",\n        \"sv\": \"Öppna Stäng\",\n        \"pl\": \"Otwórz Zamknij\",\n        \"ru\": \"Открыть Закрыть\",\n        \"ko\": \"열기 닫기\"\n      },\n      \"greyout\": false\n    },\n    \"dim\": {\n      \"title\": {\n        \"en\": \"Level\",\n        \"da\": \"Niveau\",\n        \"de\": \"Niveau\",\n        \"es\": \"Nivel\",\n        \"fr\": \"Niveau\",\n        \"it\": \"Livello\",\n        \"no\": \"Nivå\",\n        \"sv\": \"Nivå\",\n        \"pl\": \"Poziom\",\n        \"ru\": \"Уровень\",\n        \"ko\": \"수준\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/aqara-curtain-aq2/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraCurtainAQ2 extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.config = {\n      model: [\"curtain.aq2\"]\n    }\n    \n  }\n\n}\n\nmodule.exports = AqaraCurtainAQ2;"
  },
  {
    "path": "drivers/aqara-curtain-aq2/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User settings\",\n      \"nl\": \"Gebruikersinstellingen\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"inverted_mode\",\n        \"type\": \"checkbox\",\n        \"value\": false,\n        \"label\": {\n          \"en\": \"Inverted operation mode\",\n          \"nl\": \"Omgekeerde operatie modus\",\n          \"da\": \"Omvendt driftstilstand\",\n          \"de\": \"Umgekehrter Betriebsmodus\",\n          \"es\": \"Modo de operación inverso\",\n          \"fr\": \"Mode de fonctionnement inversé\",\n          \"it\": \"Modalità di funzionamento invertita\",\n          \"no\": \"Omvendt driftmodus\",\n          \"sv\": \"Inverterat driftläge\",\n          \"pl\": \"Odwrócony tryb pracy\",\n          \"ru\": \"Обратный режим работы\",\n          \"ko\": \"역방향 작동 모드\"\n        }\n      },\n      {\n        \"id\": \"inverted_state\",\n        \"type\": \"checkbox\",\n        \"value\": false,\n        \"label\": {\n          \"en\": \"Inverted state\",\n          \"nl\": \"Omgekeerde status\",\n          \"da\": \"Omvendt tilstand\",\n          \"de\": \"Umgekehrter Zustand\",\n          \"es\": \"Estado invertido\",\n          \"fr\": \"État inversé\",\n          \"it\": \"Stato invertito\",\n          \"no\": \"Omvendt tilstand\",\n          \"sv\": \"Inverterat tillstånd\",\n          \"pl\": \"Odwrócony stan\",\n          \"ru\": \"Обратное состояние\",\n          \"ko\": \"역방향 상태\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-magnet-sensor/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraMagnetSensor extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n      \n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n\n      /* alarm_contact */\n      if (device.data.status === \"open\") { await this.updateCapabilityValue(\"alarm_contact\", this.getSetting('inverted') ? false : true); }\n      if (device.data.status === \"close\") { await this.updateCapabilityValue(\"alarm_contact\", this.getSetting('inverted') ? true : false); }\n  \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraMagnetSensor;\n"
  },
  {
    "path": "drivers/aqara-magnet-sensor/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Magnet Sensor (Gateway)\",\n    \"nl\": \"Aqara magneetsensor (Gateway)\",\n    \"da\": \"Aqara Magnet Sensor (Gateway)\",\n    \"de\": \"Aqara Magnetsensor (Gateway)\",\n    \"es\": \"Sensor Magnético Aqara (Gateway)\",\n    \"fr\": \"Capteur Magnétique Aqara (Gateway)\",\n    \"it\": \"Sensore Magnetico Aqara (Gateway)\",\n    \"no\": \"Aqara Magnet Sensor (Gateway)\",\n    \"sv\": \"Aqara Magnet Sensor (Gateway)\",\n    \"pl\": \"Czujnik Magnetyczny Aqara (Gateway)\",\n    \"ru\": \"Магнитный Датчик Aqara (Gateway)\",\n    \"ko\": \"아카라 자석 센서 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-magnet-sensor/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-magnet-sensor/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"alarm_contact\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR1632\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/aqara-magnet-sensor/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraMagnetSensor extends Driver {\n\n  async onInit() {\n    \n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.config = {\n      model: [\"sensor_magnet.aq2\"]\n    }\n\n  }\n  \n}\n\nmodule.exports = AqaraMagnetSensor;"
  },
  {
    "path": "drivers/aqara-magnet-sensor/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User settings\",\n      \"nl\": \"Gebruikersinstellingen\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"inverted\",\n        \"type\": \"checkbox\",\n        \"label\": {\n          \"en\": \"Inverted alarm\",\n          \"nl\": \"Omgekeerd alarm\",\n          \"da\": \"Omvendt alarm\",\n          \"de\": \"Invertierter Alarm\",\n          \"es\": \"Alarma invertida\",\n          \"fr\": \"Alarme inversée\",\n          \"it\": \"Allarme invertito\",\n          \"no\": \"Omvendt alarm\",\n          \"sv\": \"Omvänt larm\",\n          \"pl\": \"Odwrócony alarm\",\n          \"ru\": \"Инвертированная тревога\",\n          \"ko\": \"역방향 알람\"\n        },\n        \"value\": false\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres du dispositif\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-motion-sensor/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraMotionSensor extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n\n      /* alarm_motion */\n      if (device.data.status === \"motion\") {\n        await this.updateCapabilityValue(\"alarm_motion\", true);\n\n        if (this.timeoutAlarm) { this.homey.clearTimeout(this.timeoutAlarm); }\n\n        this.timeoutAlarm = this.homey.setTimeout(async () => {\n          await this.updateCapabilityValue(\"alarm_motion\", false);\n        }, this.getSetting('alarm_duration_number') * 1000);\n      }\n\n      if (device.data.no_motion) {\n        await this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion'+ device.data.no_motion).trigger(this).catch(error => { this.error(error) });\n      }\n\n      /* measure_luminance */\n      if (device.data.lux) { await this.updateCapabilityValue(\"measure_luminance\", parseInt(device.data.lux)); }\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraMotionSensor;"
  },
  {
    "path": "drivers/aqara-motion-sensor/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Motion Sensor (Gateway)\",\n    \"nl\": \"Aqara bewegingssensor (Gateway)\",\n    \"da\": \"Aqara Bevægelsessensor (Gateway)\",\n    \"de\": \"Aqara Bewegungssensor (Gateway)\",\n    \"es\": \"Sensor de Movimiento Aqara (Gateway)\",\n    \"fr\": \"Capteur de Mouvement Aqara (Gateway)\",\n    \"it\": \"Sensore di Movimento Aqara (Gateway)\",\n    \"no\": \"Aqara Bevegelsessensor (Gateway)\",\n    \"sv\": \"Aqara Rörelsesensor (Gateway)\",\n    \"pl\": \"Czujnik Ruchu Aqara (Gateway)\",\n    \"ru\": \"Датчик движения Aqara (Gateway)\",\n    \"ko\": \"아카라 모션 센서 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-motion-sensor/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-motion-sensor/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"alarm_motion\",\n    \"measure_luminance\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2450\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/aqara-motion-sensor/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraMotionSensor extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion120');\n    this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion180');\n    this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion300');\n    this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion600');\n    this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion1200');\n    this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion1800');\n\n    this.config = {\n      model: [\"sensor_motion.aq2\"]\n    }\n    \n  }\n\n}\n\nmodule.exports = AqaraMotionSensor;"
  },
  {
    "path": "drivers/aqara-motion-sensor/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Duration of the motion alarm\",\n      \"nl\": \"Duur van het bewegingsalarm\",\n      \"da\": \"Varighed af bevægelsesalarm\",\n      \"de\": \"Dauer des Bewegungsalarms\",\n      \"es\": \"Duración de la alarma de movimiento\",\n      \"fr\": \"Durée de l'alarme de mouvement\",\n      \"it\": \"Durata dell'allarme di movimento\",\n      \"no\": \"Varighet på bevegelsesalarmen\",\n      \"sv\": \"Varaktighet för rörelselarmet\",\n      \"pl\": \"Czas trwania alarmu ruchu\",\n      \"ru\": \"Продолжительность сигнализации движения\",\n      \"ko\": \"움직임 경보 기간\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_duration_number\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Disable after\",\n          \"nl\": \"Uitschakelen na\",\n          \"da\": \"Deaktiver efter\",\n          \"de\": \"Deaktivieren nach\",\n          \"es\": \"Desactivar después de\",\n          \"fr\": \"Désactiver après\",\n          \"it\": \"Disabilita dopo\",\n          \"no\": \"Deaktiver etter\",\n          \"sv\": \"Inaktivera efter\",\n          \"pl\": \"Wyłącz po\",\n          \"ru\": \"Отключить через\",\n          \"ko\": \"다음 후 비활성화\"\n        },\n        \"hint\": {\n          \"en\": \"Here you can specify after what time the alarm signal from the motion sensor will be stopped, if a motion is detected it is not detected. Usually this is for 60 seconds, you can set from 5 to 86400 seconds. \\n \\n Attention! Values less than 60 seconds are relevant only for independently modified sensors that have the ability to transmit information about the movement with a frequency of 5 seconds.\",\n          \"nl\": \"Hier kunt u opgeven hoe laat het alarmsignaal van de bewegingssensor wordt gestopt, als een beweging wordt gedetecteerd, wordt deze niet gedetecteerd. Gewoonlijk is dit 60 seconden, u kunt 5 tot 86400 seconden instellen.  n  n Let op! Waarden minder dan 60 seconden zijn alleen relevant voor onafhankelijk aangepaste sensoren die de mogelijkheid hebben om informatie over de beweging te verzenden met een frequentie van 5 seconden.\",\n          \"da\": \"Her kan du specificere, hvornår alarmsignalet fra bevægelsessensorer vil blive stoppet, hvis en bevægelse detekteres, men ikke bliver detekteret. Normalt er dette 60 sekunder, du kan indstille fra 5 til 86400 sekunder. \\n \\n Opmærksomhed! Værdier mindre end 60 sekunder er kun relevante for uafhængigt modificerede sensorer, der har mulighed for at sende information om bevægelsen med en frekvens på 5 sekunder.\",\n          \"de\": \"Hier können Sie angeben, nach welcher Zeit das Alarmsignal des Bewegungssensors gestoppt wird, wenn eine Bewegung erkannt wird, sie jedoch nicht erkannt wird. Normalerweise liegt dieser Wert bei 60 Sekunden, Sie können von 5 bis 86400 Sekunden einstellen. \\n \\n Achtung! Werte unter 60 Sekunden sind nur für unabhängig modifizierte Sensoren relevant, die die Fähigkeit haben, Informationen über die Bewegung mit einer Frequenz von 5 Sekunden zu übertragen.\",\n          \"es\": \"Aquí puedes especificar después de cuánto tiempo se detendrá la señal de alarma del sensor de movimiento, si se detecta un movimiento no se detecta. Normalmente esto es de 60 segundos, puedes establecer desde 5 hasta 86400 segundos. \\n \\n ¡Atención! Los valores inferiores a 60 segundos solo son relevantes para sensores modificados independientemente que tienen la capacidad de transmitir información sobre el movimiento con una frecuencia de 5 segundos.\",\n          \"fr\": \"Ici, vous pouvez spécifier après combien de temps le signal d'alarme du capteur de mouvement sera arrêté, si un mouvement est détecté, il n'est pas détecté. En général, cela dure 60 secondes, vous pouvez régler de 5 à 86400 secondes. \\n \\n Attention ! Les valeurs inférieures à 60 secondes ne sont pertinentes que pour les capteurs modifiés indépendamment qui ont la capacité de transmettre des informations sur le mouvement avec une fréquence de 5 secondes.\",\n          \"it\": \"Qui puoi specificare dopo quanto tempo il segnale di allarme dal sensore di movimento verrà interrotto, se un movimento viene rilevato non viene rilevato. Di solito questo è per 60 secondi, puoi impostare da 5 a 86400 secondi. \\n \\n Attenzione! I valori inferiori a 60 secondi sono rilevanti solo per i sensori modificati indipendentemente che hanno la capacità di trasmettere informazioni sul movimento con una frequenza di 5 secondi.\",\n          \"no\": \"Her kan du spesifisere etter hvor lang tid alarmsignalet fra bevegelsessensoren vil bli stoppet, dersom en bevegelse er detektert blir det ikke detektert. Vanligvis er dette for 60 sekunder, du kan sette fra 5 til 86400 sekunder. \\n \\n Oppmerksomhet! Verdier mindre enn 60 sekunder er kun relevant for uavhengig modifiserte sensorer som har muligheten til å sende informasjon om bevegelsen med en frekvens på 5 sekunder.\",\n          \"sv\": \"Här kan du specificera efter vilken tid alarmsignalen från rörelsesensorn ska stoppas, om en rörelse detekteras detekteras den inte. Vanligtvis är detta för 60 sekunder, du kan ställa in från 5 till 86400 sekunder. \\n \\n Uppmärksamhet! Värden mindre än 60 sekunder är endast relevanta för oberoende modifierade sensorer som har förmågan att skicka information om rörelsen med en frekvens på 5 sekunder.\",\n          \"pl\": \"Tutaj możesz określić, po jakim czasie sygnał alarmowy z czujnika ruchu zostanie zatrzymany, jeśli ruch jest wykrywany, ale nie jest wykrywany. Zwykle jest to 60 sekund, można ustawić od 5 do 86400 sekund. \\n \\n Uwaga! Wartości mniejsze niż 60 sekund są istotne tylko dla niezależnie zmodyfikowanych czujników, które mają możliwość przesyłania informacji o ruchu z częstotliwością 5 sekund.\",\n          \"ru\": \"Здесь вы можете указать, через какое время будет прекращен сигнал тревоги от датчика движения, если обнаружено движение. Обычно это 60 секунд, вы можете настроить от 5 до 86400 секунд. \\n \\n Внимание! Значения менее 60 секунд имеют значение только для независимо модифицированных датчиков, которые имеют возможность передавать информацию о движении с частотой 5 секунд.\",\n          \"ko\": \"여기에서 움직임이 감지된 후 모션 센서의 경보 신호가 중지되어야 하는 시간을 지정할 수 있습니다. 일반적으로 이것은 60초입니다. 5 ~ 86400초 사이에서 설정할 수 있습니다. \\n \\n 주의! 60초 미만의 값은 5초 간격으로 움직임에 관한 정보를 전송할 수 있는 독립적으로 수정된 센서에만 관련이 있습니다.\"\n        },\n        \"value\": 60,\n        \"attr\": {\n          \"min\": 5,\n          \"max\": 86400\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuraciones del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-temperature-humidity-sensor/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraTemperatureHumiditySensor extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n      \n      const settings = this.getSettings();\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n  \n     /* measure_humidity */\n     if (device.data.humidity) { await this.updateCapabilityValue(\"measure_humidity\", parseFloat(parseFloat(device.data.humidity / 100).toFixed(1))); }\n\n     /* measure_temperature */\n      if (device.data.temperature) {\n        if (settings.addOrTakeOffset === \"add\") {\n          await this.updateCapabilityValue(\"measure_temperature\", parseFloat(parseFloat(device.data.temperature / 100 + parseFloat(settings.offset)).toFixed(1)));\n        } else if (settings.addOrTakeOffset === \"take\") {\n          await this.updateCapabilityValue(\"measure_temperature\", parseFloat(parseFloat(device.data.temperature / 100 - parseFloat(settings.offset)).toFixed(1)));\n        }\n      }\n\n      /* measure_pressure */\n      if (device.data.pressure) { await this.updateCapabilityValue(\"measure_pressure\", parseFloat(parseFloat(device.data.pressure / 100).toFixed(1))); }\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraTemperatureHumiditySensor;"
  },
  {
    "path": "drivers/aqara-temperature-humidity-sensor/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Temperature & Humidity Sensor (Gateway)\",\n    \"nl\": \"Aqara temperatuur & luchtvochtigheid sensor (Gateway)\",\n    \"da\": \"Aqara Temperatur- og Fugtighedssensor (Gateway)\",\n    \"de\": \"Aqara Temperatur- und Feuchtigkeitssensor (Gateway)\",\n    \"es\": \"Sensor de temperatura y humedad Aqara (Gateway)\",\n    \"fr\": \"Capteur de température et d'humidité Aqara (Gateway)\",\n    \"it\": \"Sensore di temperatura e umidità Aqara (Gateway)\",\n    \"no\": \"Aqara temperatur- og fuktighetssensor (Gateway)\",\n    \"sv\": \"Aqara temperatur- och fuktighetssensor (Gateway)\",\n    \"pl\": \"Czujnik temperatury i wilgotności Aqara (Gateway)\",\n    \"ru\": \"Датчик температуры и влажности Aqara (Gateway)\",\n    \"ko\": \"아카라 온습도 센서 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-temperature-humidity-sensor/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-temperature-humidity-sensor/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"measure_temperature\",\n    \"measure_humidity\",\n    \"measure_pressure\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2032\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/aqara-temperature-humidity-sensor/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraTemperatureHumiditySensor extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.config = {\n      model: [\"weather.v1\"]\n    }\n    \n  }\n\n}\n\nmodule.exports = AqaraTemperatureHumiditySensor;"
  },
  {
    "path": "drivers/aqara-temperature-humidity-sensor/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Offset settings\",\n      \"nl\": \"Offset instellingen\",\n      \"da\": \"Offset-indstillinger\",\n      \"de\": \"Offset-Einstellungen\",\n      \"es\": \"Configuración de compensación\",\n      \"fr\": \"Paramètres de décalage\",\n      \"it\": \"Impostazioni di offset\",\n      \"no\": \"Offset-innstillinger\",\n      \"sv\": \"Offset-inställningar\",\n      \"pl\": \"Ustawienia przesunięcia\",\n      \"ru\": \"Настройки смещения\",\n      \"ko\": \"오프셋 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"addOrTakeOffset\",\n        \"type\": \"radio\",\n        \"label\": {\n          \"en\": \"Offset\",\n          \"nl\": \"Offset\",\n          \"da\": \"Offset\",\n          \"de\": \"Offset\",\n          \"es\": \"Compensación\",\n          \"fr\": \"Décalage\",\n          \"it\": \"Offset\",\n          \"no\": \"Offset\",\n          \"sv\": \"Offset\",\n          \"pl\": \"Offset\",\n          \"ru\": \"Смещение\",\n          \"ko\": \"오프셋\"\n        },\n        \"value\": \"add\",\n        \"values\": [\n          {\n            \"id\": \"add\",\n            \"label\": {\n              \"en\": \"Add offset\",\n              \"nl\": \"Offset toevoegen\",\n              \"da\": \"Tilføj offset\",\n              \"de\": \"Offset hinzufügen\",\n              \"es\": \"Añadir compensación\",\n              \"fr\": \"Ajouter un décalage\",\n              \"it\": \"Aggiungi offset\",\n              \"no\": \"Legg til offset\",\n              \"sv\": \"Lägg till offset\",\n              \"pl\": \"Dodaj offset\",\n              \"ru\": \"Добавить смещение\",\n              \"ko\": \"오프셋 추가\"\n            }\n          },\n          {\n            \"id\": \"take\",\n            \"label\": {\n              \"en\": \"Minus offset\",\n              \"nl\": \"Offset verminderen\",\n              \"da\": \"Minus offset\",\n              \"de\": \"Offset abziehen\",\n              \"es\": \"Restar compensación\",\n              \"fr\": \"Moins offset\",\n              \"it\": \"Sottrai offset\",\n              \"no\": \"Minus offset\",\n              \"sv\": \"Minus offset\",\n              \"pl\": \"Minus offset\",\n              \"ru\": \"Минус смещение\",\n              \"ko\": \"오프셋 빼기\"\n            }\n          }\n        ]\n      },\n      {\n        \"id\": \"offset\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Offset\",\n          \"nl\": \"Offset\",\n          \"da\": \"Offset\",\n          \"de\": \"Offset\",\n          \"es\": \"Compensación\",\n          \"fr\": \"Décalage\",\n          \"it\": \"Offset\",\n          \"no\": \"Offset\",\n          \"sv\": \"Offset\",\n          \"pl\": \"Offset\",\n          \"ru\": \"Смещение\",\n          \"ko\": \"오프셋\"\n        },\n        \"value\": 0,\n        \"min\": 0,\n        \"max\": 5\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara-wleak-sensor/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraWleakSensor extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n  \n      /* alarm_water */\n      if (device.data.status === \"leak\") { await this.updateCapabilityValue(\"alarm_water\", true); }\n      if (device.data.status === \"no_leak\") { await this.updateCapabilityValue(\"alarm_water\", false); }\n  \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraWleakSensor;"
  },
  {
    "path": "drivers/aqara-wleak-sensor/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Waterleak Sensor (Gateway)\",\n    \"nl\": \"Aqara waterlek sensor (Gateway)\",\n    \"da\": \"Aqara Vandlækagesensor (Gateway)\",\n    \"de\": \"Aqara Wasseraustrittsensor (Gateway)\",\n    \"es\": \"Sensor de fugas de agua Aqara (Gateway)\",\n    \"fr\": \"Capteur de fuite d'eau Aqara (Gateway)\",\n    \"it\": \"Sensore di perdita d'acqua Aqara (Gateway)\",\n    \"no\": \"Aqara Vannlekkasjesensor (Gateway)\",\n    \"sv\": \"Aqara Vattenläckagesensor (Gateway)\",\n    \"pl\": \"Czujnik wycieku wody Aqara (Gateway)\",\n    \"ru\": \"Датчик утечки воды Aqara (Gateway)\",\n    \"ko\": \"아카라 물 누수 센서 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara-wleak-sensor/assets/images/large.png\",\n    \"small\": \"/drivers/aqara-wleak-sensor/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"alarm_water\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2032\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/aqara-wleak-sensor/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraWleakSensor extends Driver {\n\n  async onInit() {\n    \n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.config = {\n      model: [\"sensor_wleak.aq1\"]\n    }\n  }\n  \n}\n\nmodule.exports = AqaraWleakSensor;"
  },
  {
    "path": "drivers/aqara-wleak-sensor/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"기기 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara_86sw1_switch/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraWireless86SW1SwitchDevice extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n      \n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n  \n      /* button events */\n      if (device.data.channel_0 === \"click\") { await this.homey.flow.getDeviceTriggerCard('click_single').trigger(this).catch(error => { this.error(error) }); }\n\n    } catch (error) {\n      this.error(error);\n    }    \n  }\n\n}\n\nmodule.exports = AqaraWireless86SW1SwitchDevice;"
  },
  {
    "path": "drivers/aqara_86sw1_switch/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Wireless Wall Single Switch (Gateway)\",\n    \"nl\": \"Aqara Wireless Wall Single Switch (Gateway)\",\n    \"da\": \"Aqara trådløs væg enkeltkontakt (gateway)\",\n    \"de\": \"Aqara kabelloser Wandschalter (Gateway)\",\n    \"es\": \"Interruptor de pared inalámbrico Aqara (Gateway)\",\n    \"fr\": \"Interrupteur mural sans fil Aqara (Gateway)\",\n    \"it\": \"Interruttore singolo a parete wireless Aqara (Gateway)\",\n    \"no\": \"Aqara trådløs vegg enkel bryter (gateway)\",\n    \"sv\": \"Aqara trådlös väggbrytare (gateway)\",\n    \"pl\": \"Aqara bezprzewodowy przełącznik ścienny (bramka)\",\n    \"ru\": \"Беспроводной настенный однокнопочный выключатель Aqara (шлюз)\",\n    \"ko\": \"아카라 무선 벽 단일 스위치 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara_86sw1_switch/assets/images/large.jpg\",\n    \"small\": \"/drivers/aqara_86sw1_switch/assets/images/small.jpg\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2032\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/aqara_86sw1_switch/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraWireless86SW1SwitchDriver extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('click_single');\n\n    this.config = {\n      model: [\"86sw1\", \"lumi.remote.b186acn02\", \"remote.b186acn02\"]\n    }\n  }\n\n}\n\nmodule.exports = AqaraWireless86SW1SwitchDriver;"
  },
  {
    "path": "drivers/aqara_86sw1_switch/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/aqara_86sw2_switch/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraWireless86SW2SwitchDevice extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n\n      /* button events */\n      if (device.data.channel_0 === \"click\") { await this.homey.flow.getDeviceTriggerCard('click_single_left').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.channel_1 === \"click\") { await this.homey.flow.getDeviceTriggerCard('click_single_right').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.dual_channel === \"both_click\") { await this.homey.flow.getDeviceTriggerCard('click_single_left_right').trigger(this).catch(error => { this.error(error) }); }\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraWireless86SW2SwitchDevice;"
  },
  {
    "path": "drivers/aqara_86sw2_switch/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Wireless Wall Double Switch (Gateway)\",\n    \"nl\": \"Aqara Wireless Wall Double Switch (Gateway)\",\n    \"da\": \"Aqara Trådløs Væg Dobbeltkontakt (Gateway)\",\n    \"de\": \"Aqara Funk-Wandschalter Doppelt (Gateway)\",\n    \"es\": \"Interruptor Doble de Pared Inalámbrico Aqara (Gateway)\",\n    \"fr\": \"Interrupteur Double sans Fil Aqara (Gateway)\",\n    \"it\": \"Interruttore da Parete Wireless Doppio Aqara (Gateway)\",\n    \"no\": \"Aqara Trådløs Vegg Dobbel Bryter (Gateway)\",\n    \"sv\": \"Aqara Trådlös Väggdubbla Strömbrytare (Gateway)\",\n    \"pl\": \"Aqara Bezprzewodowy Podwójny Przełącznik Ścienny (Gateway)\",\n    \"ru\": \"Беспроводной Двойной Настенный Выключатель Aqara (Gateway)\",\n    \"ko\": \"아카라 무선 벽 이중 스위치 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/aqara_86sw2_switch/assets/images/large.jpg\",\n    \"small\": \"/drivers/aqara_86sw2_switch/assets/images/small.jpg\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2032\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/aqara_86sw2_switch/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraWireless86SW2SwitchDriver extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('click_single_left');\n    this.homey.flow.getDeviceTriggerCard('click_single_right');\n    this.homey.flow.getDeviceTriggerCard('click_single_left_right');\n\n    this.config = {\n      model: [\"86sw2\"]\n    }\n    \n  }\n\n}\n\nmodule.exports = AqaraWireless86SW2SwitchDriver;"
  },
  {
    "path": "drivers/aqara_86sw2_switch/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"pt\": \"Configurações do Dispositivo\",\n      \"zh\": \"设备设置\",\n      \"ja\": \"デバイス設定\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/clothesdryer_hyd_airer_miot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/hyd.airer.znlyj4\n\n\nconst mapping = {\n  \"hyd.airer.znlyj4\": \"mapping_default\",\n  \"hyd.airer.*\": \"mapping_default\",\n};\n\nconst properties = {\n  \"mapping_default\": {\n    \"get_properties\": [\n      { did: \"fault\", siid : 2, piid: 1 }, // settings.error\n      { did: \"position\", siid : 2, piid: 3 }, // not in use\n      { did: \"movement\", siid : 2, piid: 3 }, // windowcoverings_state\n      { did: \"light\", siid: 3, piid: 1 }, // onoff\n    ],\n    \"set_properties\": {\n      \"controls\": { siid : 2, piid: 2 }, // windowcoverings_state\n      \"light\": { siid: 3, aiid: 1, did: \"call-3-1\", in: [] } // onoff\n    }\n  }\n}\n\nclass ClothesDryerHydAirerMiotDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['hyd.airer.*']];\n\n      this.errorCodes = {\n        0: \"No Error\",\n        1: \"Obstruction\",\n        2: \"Overweight\",\n        3: \"Overheated\"\n      }\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"action\", this.deviceProperties.set_properties.light, { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('windowcoverings_state', async (value) => {\n        try {\n          if (this.miio) {\n            switch (value) {\n              case 'idle':\n                return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.controls.siid, piid: this.deviceProperties.set_properties.controls.piid, value: 0 }], { retries: 1 });\n              case 'up':\n                return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.controls.siid, piid: this.deviceProperties.set_properties.controls.piid, value: 1 }], { retries: 1 });\n              case 'down':\n                return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.controls.siid, piid: this.deviceProperties.set_properties.controls.piid, value: 2 }], { retries: 1 });\n              default:\n                return Promise.reject('State not recognized ...');\n            }\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const light = result.find(obj => obj.did === 'light');\n      const movement = result.find(obj => obj.did === 'movement');\n      const fault = result.find(obj => obj.did === 'fault');\n\n      /* capabilities */\n      if (light !== undefined) {\n        await this.updateCapabilityValue(\"onoff\", light.value);\n      }\n\n      if (movement !== undefined) {\n        switch (movement.value) {\n          case 0:\n          case 3:\n            await this.updateCapabilityValue(\"windowcoverings_state\", \"idle\");\n          case 1:\n            await this.updateCapabilityValue(\"windowcoverings_state\", \"up\");\n          case 2:\n            await this.updateCapabilityValue(\"windowcoverings_state\", \"down\");\n          default:\n            this.error('State not recognized ...');\n        }\n      }\n\n      /* settings */\n      const error = this.errorCodes[fault.value];\n      await this.updateSettingValue(\"error\", error);\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = ClothesDryerHydAirerMiotDevice;\n"
  },
  {
    "path": "drivers/clothesdryer_hyd_airer_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mijia Smart Clothes Drying Rack MIoT (WiFi)\",\n    \"nl\": \"Slim Mijia Droogrek MIoT (WiFi)\",\n    \"da\": \"Mijia Smart Tørrerist MIoT (WiFi)\",\n    \"de\": \"Mijia Smarter Wäscheständer MIoT (WiFi)\",\n    \"es\": \"Mijia Estante de Secado Inteligente MIoT (WiFi)\",\n    \"fr\": \"Séchoir à vêtements intelligent Mijia MIoT (WiFi)\",\n    \"it\": \"Stendibiancheria Intelligente Mijia MIoT (WiFi)\",\n    \"no\": \"Mijia Smart Tørkestativ MIoT (WiFi)\",\n    \"sv\": \"Mijia Smart Klädtorkställning MIoT (WiFi)\",\n    \"pl\": \"Mijia Inteligentny Wieszaki Suszarki MIoT (WiFi)\",\n    \"ru\": \"Умная сушилка для одежды Mijia MIoT (WiFi)\",\n    \"ko\": \"미지아 스마트 건조대 MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/clothesdryer_hyd_airer_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/clothesdryer_hyd_airer_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"windowcoverings_state\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff\": {\n      \"title\": {\n        \"en\": \"Light\",\n        \"nl\": \"Licht\",\n        \"da\": \"Lys\",\n        \"de\": \"Licht\",\n        \"es\": \"Luz\",\n        \"fr\": \"Lumière\",\n        \"it\": \"Luce\",\n        \"no\": \"Lys\",\n        \"sv\": \"Ljus\",\n        \"pl\": \"Światło\",\n        \"ru\": \"Свет\",\n        \"ko\": \"빛\"\n      }\n    },\n    \"windowcoverings_state\": {\n      \"title\": {\n        \"en\": \"Position\",\n        \"nl\": \"Positie\",\n        \"da\": \"Position\",\n        \"de\": \"Position\",\n        \"es\": \"Posición\",\n        \"fr\": \"Position\",\n        \"it\": \"Posizione\",\n        \"no\": \"Posisjon\",\n        \"sv\": \"Position\",\n        \"pl\": \"Pozycja\",\n        \"ru\": \"Позиция\",\n        \"ko\": \"위치\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/clothesdryer_hyd_airer_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass ClothesDryerHydAirerMiotDriver extends Driver {}\n\nmodule.exports = ClothesDryerHydAirerMiotDriver;"
  },
  {
    "path": "drivers/clothesdryer_hyd_airer_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"Светодиод\",\n          \"ko\": \"LED\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device data\",\n      \"nl\": \"Apparaat data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"장치 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"error\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Error\",\n          \"nl\": \"Error\",\n          \"da\": \"Fejl\",\n          \"de\": \"Fehler\",\n          \"es\": \"Error\",\n          \"fr\": \"Erreur\",\n          \"it\": \"Errore\",\n          \"no\": \"Feil\",\n          \"sv\": \"Fel\",\n          \"pl\": \"Błąd\",\n          \"ru\": \"Ошибка\",\n          \"ko\": \"오류\"\n        },\n        \"value\": \"No error\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"기기 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/clothesdryer_hyd_airer_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/clothesdryer_hyd_airer_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/clothesdryer_hyd_airer_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/ctrl_86plug_aq1/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass AqaraWallOutletDevice extends Device {\n\n  async registerCapabilities() {\n    this.registerCapabilityListener('onoff', async (value) => {\n      try {\n        return await this.homey.app.mihub.sendWrite(this.data.sid, { status: value });\n      } catch (error) {\n        this.error(error);\n      }\n    });\n  }\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* onoff */\n      if (device.data.status === \"on\") { await this.updateCapabilityValue(\"onoff\", true, triggers.power); }\n      if (device.data.status === \"off\") { await this.updateCapabilityValue(\"onoff\", false, triggers.power); }\n  \n      /* measure_power */\n      if (device.data.load_power) { await this.updateCapabilityValue(\"measure_power\", parseInt(device.data.load_power)); }\n  \n      /* meter_power */\n      if (device.data.power_consumed) { await this.updateCapabilityValue(\"meter_power\", parseInt(device.data.power_consumed / 1000)); }\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = AqaraWallOutletDevice;"
  },
  {
    "path": "drivers/ctrl_86plug_aq1/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Wall Outlet (Gateway)\",\n    \"nl\": \"Aqara Wall Outlet (Gateway)\",\n    \"da\": \"Aqara Vægudtag (Gateway)\",\n    \"de\": \"Aqara Wandsteckdose (Gateway)\",\n    \"es\": \"Aqara Toma de Pared (Gateway)\",\n    \"fr\": \"Prise Murale Aqara (Gateway)\",\n    \"it\": \"Presa da Muro Aqara (Gateway)\",\n    \"no\": \"Aqara Veggkontakt (Gateway)\",\n    \"sv\": \"Aqara Vägguttag (Gateway)\",\n    \"pl\": \"Gniazdko Ścienne Aqara (Gateway)\",\n    \"ru\": \"Настенная Розетка Aqara (Gateway)\",\n    \"ko\": \"아카라 벽면 콘센트 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/ctrl_86plug_aq1/assets/images/large.jpg\",\n    \"small\": \"/drivers/ctrl_86plug_aq1/assets/images/small.jpg\"\n  },\n  \"class\": \"light\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"meter_power\",\n    \"measure_power\"\n  ]\n}"
  },
  {
    "path": "drivers/ctrl_86plug_aq1/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass AqaraWallOutletDriver extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.config = {\n      model: [\"ctrl_86plug.aq1\", \"lumi.ctrl_86plug.aq1\", \"lumi.ctrl_86plug\"]\n    }\n    \n  }\n}\n\nmodule.exports = AqaraWallOutletDriver;"
  },
  {
    "path": "drivers/ctrl_86plug_aq1/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"pt\": \"Configurações do dispositivo\",\n      \"ja\": \"デバイス設定\",\n      \"zh\": \"设备设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/dehumidifier_dmaker_derh_miot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/dmaker.derh.22ht\n// https://home.miot-spec.com/spec/xiaomi.derh.lite\n\nconst mapping = {\n  \"dmaker.derh.22\": \"mapping_default\",\n  \"dmaker.derh.22ht\": \"mapping_default\",\n  \"dmaker.derh.*\": \"mapping_default\",\n  \"xiaomi.derh.lite\": \"mapping_default\",\n  \"xiaomi.derh.13l\": \"mapping_default\",\n  \"xiaomi.derh.*\": \"mapping_default\",\n};\n\nconst properties = {\n  \"mapping_default\": {\n    \"get_properties\": [\n      { did: \"onoff\", siid: 2, piid: 1 }, // onoff\n      { did: \"error\", siid: 2, piid: 2 }, // settings.error\n      { did: \"mode\", siid: 2, piid: 3 }, // dehumidifier_dmaker_mode\n      { did: \"target_humidity\", siid: 2, piid: 5 }, // target_humidity [40, 50, 60, 70]\n      { did: \"relative_humidity\", siid: 3, piid: 1 }, // measure_humidity\n      { did: \"temperature\", siid: 3, piid: 2 }, // measure_temperature\n      { did: \"buzzer\", siid: 4, piid: 1 }, // settings.buzzer\n      { did: \"led_light\", siid: 5, piid: 1 }, // settings.led\n      { did: \"child_lock\", siid: 6, piid: 1 } // settings.childLock\n    ],\n    \"set_properties\": {\n      \"onoff\": { siid: 2, piid: 1 },\n      \"mode\": { siid: 2, piid: 3 },\n      \"target_humidity\": { siid: 2, piid: 5 },\n      \"buzzer\": { siid: 4, piid: 1 },\n      \"light\": { siid: 5, piid: 1 },\n      \"child_lock\": { siid: 6, piid: 1 }\n    }\n  }\n}\n\nconst modes = {\n  0: \"Smart\",\n  1: \"Sleep\",\n  2: \"Clothes Drying\"\n};\n\nclass DehumidifierDmakerDerhMiotDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['dmaker.derh.*']];\n\n      if (!this.hasCapability('alarm_water')) {\n        await this.addCapability('alarm_water');\n      }\n\n      this.errorCodes = {\n        0: \"No Faults\",\n        1: \"Water Full\",\n        2: \"Sensor Fault1\",\n        3: \"Sensor Fault2\",\n        4: \"Communication Fault1\",\n        5: \"Filter Clean\",\n        6: \"Defrost\",\n        7: \"Fan Motor\",\n        8: \"Overload\",\n        9: \"Lack Of Refrigerant\",\n        10: \"Out Of Temperature\"\n      }\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.onoff.siid, piid: this.deviceProperties.set_properties.onoff.piid, value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('target_humidity', async ( value ) => {\n        try {\n          if (this.miio) {\n            let humidity = value * 100;\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.target_humidity.siid, piid: this.deviceProperties.set_properties.target_humidity.piid, value: humidity }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('dehumidifier_dmaker_mode', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.mode.siid, piid: this.deviceProperties.set_properties.mode.piid, value: +value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      await this.miio.call(\"set_properties\", [{ did: \"light\", siid: this.deviceProperties.set_properties.light.siid, piid: this.deviceProperties.set_properties.light.piid, value: newSettings.led }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"buzzer\")) {\n      await this.miio.call(\"set_properties\", [{ did: \"buzzer\", siid: this.deviceProperties.set_properties.buzzer.siid, piid: this.deviceProperties.set_properties.buzzer.piid, value: newSettings.buzzer }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"childLock\")) {\n      await this.miio.call(\"set_properties\", [{ did: \"child_lock\", siid: this.deviceProperties.set_properties.child_lock.siid, piid: this.deviceProperties.set_properties.child_lock.piid, value: newSettings.childLock }], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const onoff = result.find(obj => obj.did === 'onoff');\n      const errors = result.find(obj => obj.did === 'error');\n      const target_humidity = result.find(obj => obj.did === 'target_humidity');\n      const measure_humidity = result.find(obj => obj.did === 'relative_humidity');\n      const measure_temperature = result.find(obj => obj.did === 'temperature');\n      const buzzer = result.find(obj => obj.did === 'buzzer');\n      const led = result.find(obj => obj.did === 'led_light');\n      const child_lock = result.find(obj => obj.did === 'child_lock');\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"onoff\", onoff.value);\n      await this.updateCapabilityValue(\"alarm_water\", errors.value === 1);\n      await this.updateCapabilityValue(\"target_humidity\", target_humidity.value / 100);\n      await this.updateCapabilityValue(\"measure_humidity\", measure_humidity.value);\n      await this.updateCapabilityValue(\"measure_temperature\", measure_temperature.value);    \n\n      /* settings */\n      const error = this.errorCodes[errors.value];\n      await this.updateSettingValue(\"error\", error);\n\n      await this.updateSettingValue(\"led\", led.value);\n      await this.updateSettingValue(\"buzzer\", buzzer.value);\n      await this.updateSettingValue(\"childLock\", child_lock.value);\n\n      /* mode capability */\n      const mode = result.find(obj => obj.did === 'mode');\n      if (this.getCapabilityValue('dehumidifier_dmaker_mode') !== mode.value.toString()) {\n        const previous_mode = this.getCapabilityValue('dehumidifier_dmaker_mode');\n        await this.setCapabilityValue('dehumidifier_dmaker_mode', mode.value.toString());\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, {\"new_mode\": modes[mode.value], \"previous_mode\": modes[+previous_mode] }).catch(error => { this.error(error) });\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = DehumidifierDmakerDerhMiotDevice;\n"
  },
  {
    "path": "drivers/dehumidifier_dmaker_derh_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n    \"nl\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n    \"da\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n    \"de\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n    \"es\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n    \"fr\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n    \"it\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n    \"no\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n    \"sv\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n    \"pl\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n    \"ru\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\",\n    \"ko\": \"Xiaomi Smart Dehumidifier MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/dehumidifier_dmaker_derh_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/dehumidifier_dmaker_derh_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"dehumidifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"dehumidifier_dmaker_mode\",\n    \"target_humidity\",\n    \"measure_humidity\",\n    \"measure_temperature\",\n    \"alarm_water\"\n  ],\n  \"capabilitiesOptions\": {\n    \"target_humidity\": {\n      \"min\": 0.4,\n      \"max\": 0.8\n    },\n    \"alarm_water\": {\n      \"title\": {\n        \"en\": \"Water Tank Full\",\n        \"nl\": \"Watertank vol\",\n        \"da\": \"Vandtank fuld\",\n        \"de\": \"Wassertank voll\",\n        \"es\": \"Depósito de agua lleno\",\n        \"fr\": \"Réservoir d'eau plein\",\n        \"it\": \"Serbatoio dell'acqua pieno\",\n        \"no\": \"Vanntank full\",\n        \"sv\": \"Vattentank full\",\n        \"pl\": \"Zbiornik wody pełny\",\n        \"ru\": \"Резервуар для воды заполнен\",\n        \"ko\": \"물탱크 가득 참\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "drivers/dehumidifier_dmaker_derh_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass DehumidifierDmakerDerhMiotDriver extends Driver {}\n\nmodule.exports = DehumidifierDmakerDerhMiotDriver;"
  },
  {
    "path": "drivers/dehumidifier_dmaker_derh_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración del usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"LED\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summer\",\n          \"de\": \"Summer\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Vibreur\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Summerton\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Buzer\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"부저\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnelås\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo infantil\",\n          \"fr\": \"Verrouillage enfants\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barnelås\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada dla dzieci\",\n          \"ru\": \"Блокировка от детей\",\n          \"ko\": \"잠금 기능\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device data\",\n      \"nl\": \"Apparaat data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"장치 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"error\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Error\",\n          \"nl\": \"Error\",\n          \"da\": \"Fejl\",\n          \"de\": \"Fehler\",\n          \"es\": \"Error\",\n          \"fr\": \"Erreur\",\n          \"it\": \"Errore\",\n          \"no\": \"Feil\",\n          \"sv\": \"Fel\",\n          \"pl\": \"Błąd\",\n          \"ru\": \"Ошибка\",\n          \"ko\": \"오류\"\n        },\n        \"value\": \"No error\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/dehumidifier_dmaker_derh_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/dehumidifier_dmaker_derh_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/dehumidifier_dmaker_derh_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/diffuser_xwhzp_diffuser_xwxfj/device.js",
    "content": "'use strict';\n\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\nconst tinycolor = require('tinycolor2');\n\nconst MODEL_MAPPING = {\n  'xwhzp.diffuser.xwxfj': 'xwxfj'\n};\n\nconst FALLBACK_MODEL_KEY = 'xwxfj';\nconst EMPTY_LEVEL_THRESHOLD = 10;\n\nconst MODE_LABELS = {\n  0: 'Sleep',\n  1: 'Reading',\n  2: 'Exercise',\n  3: 'Wakeup',\n  4: 'Custom Mode 1',\n  5: 'Custom Mode 2',\n  6: 'Custom Mode 3',\n  7: 'Custom Mode 4',\n  8: 'Try It',\n  9: 'Idle Mode'\n};\n\nconst PROPERTIES = {\n  xwxfj: {\n    get_properties: [\n      { did: 'power', siid: 2, piid: 1 },\n      { did: 'fault', siid: 2, piid: 2 },\n      { did: 'mode', siid: 2, piid: 3 },\n      { did: 'fragrance_out_time', siid: 2, piid: 7 },\n      { did: 'lid_status', siid: 2, piid: 8 },\n      { did: 'wifi_status', siid: 2, piid: 9 },\n      { did: 'light_power', siid: 3, piid: 1 },\n      { did: 'light_brightness', siid: 3, piid: 2 },\n      { did: 'light_color', siid: 3, piid: 3 },\n      { did: 'workstate', siid: 4, piid: 2 },\n      { did: 'battery_level', siid: 5, piid: 1 },\n      { did: 'charging_state', siid: 5, piid: 2 },\n      { did: 'liquid_level_1', siid: 12, piid: 1 },\n      { did: 'liquid_name_1', siid: 12, piid: 2 },\n      { did: 'liquid_level_2', siid: 13, piid: 1 },\n      { did: 'liquid_name_2', siid: 13, piid: 2 },\n      { did: 'liquid_level_3', siid: 14, piid: 1 },\n      { did: 'liquid_name_3', siid: 14, piid: 2 }\n    ],\n    set_properties: {\n      power: { siid: 2, piid: 1 },\n      mode: { siid: 2, piid: 3 },\n      fragrance_out_time: { siid: 2, piid: 7 },\n      light_power: { siid: 3, piid: 1 },\n      light_brightness: { siid: 3, piid: 2 },\n      light_color: { siid: 3, piid: 3 }\n    }\n  }\n};\n\nclass MijiaSmartScentDiffuserDevice extends Device {\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({ homey: this.homey });\n\n      this.deviceProperties = this.resolveDeviceProperties();\n\n      this.bootSequence();\n\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      await this.ensureCapabilities([\n        'onoff',\n        'diffuser_xwhzp_mode',\n        'diffuser_xwhzp_fragrance_out_time',\n        'dim',\n        'light_hue',\n        'light_saturation',\n        'measure_waterlevel',\n        'alarm_tank_empty',\n        'measure_battery',\n        'alarm_battery'\n      ]);\n\n      this.registerCapabilityListener('onoff', (value) => this.setPropertyValue('power', this.toBoolean(value)));\n\n      this.registerCapabilityListener('diffuser_xwhzp_mode', (value) =>\n        this.setPropertyValue('mode', Number(value))\n      );\n\n      this.registerCapabilityListener('diffuser_xwhzp_fragrance_out_time', (value) => {\n        const fragranceOutTime = Math.max(30, Math.min(120, Math.round(Number(value) || 30)));\n        return this.setPropertyValue('fragrance_out_time', fragranceOutTime);\n      });\n\n      this.registerCapabilityListener('dim', (value) => this.setAmbientLightBrightness(value));\n\n      this.registerMultipleCapabilityListener(\n        ['light_hue', 'light_saturation'],\n        (valueObj) => this.setAmbientLightColor(valueObj),\n        500\n      );\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async ensureCapabilities(capabilities) {\n    for (const capability of capabilities) {\n      if (!this.hasCapability(capability)) {\n        await this.addCapability(capability).catch((error) => {\n          this.error('Failed to add capability', capability, error);\n        });\n      }\n    }\n  }\n\n  getModelIdentifier() {\n    if (typeof this.getStoreValue === 'function') {\n      const storedModel = this.getStoreValue('model');\n      if (storedModel) return storedModel;\n    }\n\n    if (typeof this.getData === 'function') {\n      const data = this.getData();\n      if (data && data.model) return data.model;\n    }\n\n    return 'unknown';\n  }\n\n  resolveDeviceProperties() {\n    const modelKey = MODEL_MAPPING[this.getModelIdentifier()] || FALLBACK_MODEL_KEY;\n    const definition = PROPERTIES[modelKey] || PROPERTIES[FALLBACK_MODEL_KEY];\n    if (!definition) {\n      throw new Error('No property definition found for current diffuser model');\n    }\n    return definition;\n  }\n\n  toBoolean(value) {\n    if (typeof value === 'boolean') return value;\n    if (typeof value === 'number') return value === 1;\n    if (typeof value === 'string') {\n      const normalized = value.toLowerCase();\n      return normalized === '1' || normalized === 'true' || normalized === 'on';\n    }\n    return false;\n  }\n\n  clamp01(value) {\n    return Math.max(0, Math.min(1, Number(value) || 0));\n  }\n\n  clamp100(value) {\n    return Math.max(0, Math.min(100, Math.round(Number(value) || 0)));\n  }\n\n  hasUsableValue(entry) {\n    if (!entry) return false;\n    if (typeof entry.code === 'number' && entry.code !== 0) return false;\n    return entry.value !== undefined && entry.value !== null && entry.value !== 'undefined' && entry.value !== 'null';\n  }\n\n  indexResults(result) {\n    const map = {};\n    if (!Array.isArray(result)) return map;\n\n    for (const entry of result) {\n      if (!entry) continue;\n      const key = entry.did || entry.did === '' ? entry.did : `${entry.siid}/${entry.piid}`;\n      map[key] = entry;\n    }\n\n    return map;\n  }\n\n  async setPropertyValue(propertyKey, value) {\n    const definition = this.deviceProperties && this.deviceProperties.set_properties\n      ? this.deviceProperties.set_properties[propertyKey]\n      : null;\n\n    if (!definition) {\n      return Promise.reject(new Error(`Property ${propertyKey} is not supported by current model`));\n    }\n\n    if (!this.miio) {\n      this.setUnavailable(this.homey.__('unreachable')).catch((error) => this.error(error));\n      this.createDevice();\n      return Promise.reject('Device unreachable, please try again ...');\n    }\n\n    return this.miio.call(\n      'set_properties',\n      [{ siid: definition.siid, piid: definition.piid, value }],\n      { retries: 1 }\n    );\n  }\n\n  async setMultipleProperties(entries) {\n    if (!this.miio) {\n      this.setUnavailable(this.homey.__('unreachable')).catch((error) => this.error(error));\n      this.createDevice();\n      return Promise.reject('Device unreachable, please try again ...');\n    }\n\n    const payload = [];\n    for (const entry of entries) {\n      const definition = this.deviceProperties && this.deviceProperties.set_properties\n        ? this.deviceProperties.set_properties[entry.key]\n        : null;\n      if (!definition) continue;\n      payload.push({ siid: definition.siid, piid: definition.piid, value: entry.value });\n    }\n\n    if (payload.length === 0) {\n      return Promise.reject(new Error('No valid properties provided for update'));\n    }\n\n    return this.miio.call('set_properties', payload, { retries: 1 });\n  }\n\n  async setAmbientLightBrightness(value) {\n    try {\n      const brightness = Math.round(this.clamp01(value) * 100);\n      const payload = brightness > 0\n        ? [\n            { key: 'light_power', value: true },\n            { key: 'light_brightness', value: brightness }\n          ]\n        : [\n            { key: 'light_brightness', value: 0 },\n            { key: 'light_power', value: false }\n          ];\n\n      return await this.setMultipleProperties(payload);\n    } catch (error) {\n      this.error(error);\n      return Promise.reject(error);\n    }\n  }\n\n  async setAmbientLightColor(valueObj) {\n    try {\n      const hueValue = typeof valueObj.light_hue !== 'undefined'\n        ? valueObj.light_hue\n        : this.getCapabilityValue('light_hue');\n      const saturationValue = typeof valueObj.light_saturation !== 'undefined'\n        ? valueObj.light_saturation\n        : this.getCapabilityValue('light_saturation');\n\n      const hue = this.clamp01(hueValue) * 360;\n      const saturation = this.clamp01(saturationValue) * 100;\n      const dimValue = this.getCapabilityValue('dim');\n      const brightness = typeof dimValue === 'number' && dimValue > 0\n        ? this.clamp01(dimValue) * 100\n        : 100;\n\n      const color = tinycolor({ h: hue, s: saturation, v: brightness });\n      const rgbAsInt = parseInt(color.toHex(), 16);\n\n      return await this.setMultipleProperties([\n        { key: 'light_power', value: true },\n        { key: 'light_color', value: rgbAsInt }\n      ]);\n    } catch (error) {\n      this.error(error);\n      return Promise.reject(error);\n    }\n  }\n\n  async onSettings({ changedKeys }) {\n    if (changedKeys.includes('address') || changedKeys.includes('token') || changedKeys.includes('polling')) {\n      this.refreshDevice();\n    }\n\n    return true;\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call('get_properties', this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) {\n        await this.setAvailable();\n      }\n\n      const indexed = this.indexResults(result);\n\n      const power = indexed.power;\n      if (this.hasUsableValue(power)) {\n        await this.updateCapabilityValue('onoff', this.toBoolean(power.value));\n      }\n\n      const mode = indexed.mode;\n      if (this.hasUsableValue(mode) && typeof mode.value === 'number') {\n        await this.handleModeEvent(mode.value);\n      }\n\n      const fragranceOutTime = indexed.fragrance_out_time;\n      if (this.hasUsableValue(fragranceOutTime) && typeof fragranceOutTime.value === 'number') {\n        await this.updateCapabilityValue('diffuser_xwhzp_fragrance_out_time', fragranceOutTime.value);\n      }\n\n      const lightPower = indexed.light_power;\n      const lightBrightness = indexed.light_brightness;\n      if (this.hasUsableValue(lightBrightness) && typeof lightBrightness.value === 'number') {\n        const dim = this.toBoolean(lightPower && lightPower.value)\n          ? this.clamp01(lightBrightness.value / 100)\n          : 0;\n        await this.updateCapabilityValue('dim', dim);\n      }\n\n      const lightColor = indexed.light_color;\n      if (this.hasUsableValue(lightColor) && typeof lightColor.value === 'number') {\n        const hexValue = lightColor.value.toString(16).padStart(6, '0');\n        const hsv = tinycolor(`#${hexValue}`).toHsv();\n        const hueNormalized = Number.isFinite(hsv.h) ? this.clamp01(hsv.h / 360) : 0;\n        const saturationNormalized = Number.isFinite(hsv.s) ? this.clamp01(hsv.s) : 0;\n\n        await this.updateCapabilityValue('light_hue', hueNormalized);\n        await this.updateCapabilityValue('light_saturation', saturationNormalized);\n      }\n\n      const battery = indexed.battery_level;\n      if (this.hasUsableValue(battery) && typeof battery.value === 'number') {\n        const batteryLevel = this.clamp100(battery.value);\n        await this.updateCapabilityValue('measure_battery', batteryLevel);\n        await this.updateCapabilityValue('alarm_battery', batteryLevel <= 20);\n      }\n\n      const levelEntries = [indexed.liquid_level_1, indexed.liquid_level_2, indexed.liquid_level_3];\n      const validLevels = levelEntries\n        .filter((entry) => this.hasUsableValue(entry) && typeof entry.value === 'number')\n        .map((entry) => this.clamp100(entry.value));\n\n      if (validLevels.length > 0) {\n        const lowestLevel = Math.min(...validLevels);\n        await this.updateCapabilityValue('measure_waterlevel', lowestLevel);\n        await this.updateCapabilityValue('alarm_tank_empty', lowestLevel <= EMPTY_LEVEL_THRESHOLD);\n      }\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((err) => {\n          this.error(err);\n        });\n      }\n\n      this.homey.setTimeout(() => {\n        this.createDevice();\n      }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n  async handleModeEvent(mode) {\n    try {\n      const modeValue = mode.toString();\n      if (this.getCapabilityValue('diffuser_xwhzp_mode') !== modeValue) {\n        const previousMode = this.getCapabilityValue('diffuser_xwhzp_mode');\n        await this.setCapabilityValue('diffuser_xwhzp_mode', modeValue);\n\n        const newModeLabel = MODE_LABELS[mode] || modeValue;\n        const previousModeLabel = previousMode !== undefined && previousMode !== null\n          ? MODE_LABELS[Number(previousMode)] || previousMode\n          : undefined;\n\n        await this.homey.flow\n          .getDeviceTriggerCard('triggerModeChanged')\n          .trigger(this, { new_mode: newModeLabel, previous_mode: previousModeLabel })\n          .catch((error) => {\n            this.error(error);\n          });\n      }\n    } catch (error) {\n      this.error(error);\n    }\n  }\n}\n\nmodule.exports = MijiaSmartScentDiffuserDevice;\n"
  },
  {
    "path": "drivers/diffuser_xwhzp_diffuser_xwxfj/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mijia Smart Scent Diffuser (WiFi)\",\n    \"nl\": \"Mijia Smart Geurverspreider (WiFi)\",\n    \"da\": \"Mijia Smart Duftdiffuser (WiFi)\",\n    \"de\": \"Mijia Smart Duftdiffusor (WiFi)\",\n    \"es\": \"Difusor Aromatico Inteligente Mijia (WiFi)\",\n    \"fr\": \"Diffuseur de parfum intelligent Mijia (WiFi)\",\n    \"it\": \"Diffusore di fragranze smart Mijia (WiFi)\",\n    \"no\": \"Mijia Smart duftspreder (WiFi)\",\n    \"sv\": \"Mijia Smart doftspridare (WiFi)\",\n    \"pl\": \"Inteligentny dyfuzor zapachu Mijia (WiFi)\",\n    \"ru\": \"Mijia smart aroma-diffuser (WiFi)\",\n    \"ko\": \"Mijia smart scent diffuser (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/diffuser_xwhzp_diffuser_xwxfj/assets/images/large.jpg\",\n    \"small\": \"drivers/diffuser_xwhzp_diffuser_xwxfj/assets/images/small.jpg\"\n  },\n  \"class\": \"humidifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"diffuser_xwhzp_mode\",\n    \"diffuser_xwhzp_fragrance_out_time\",\n    \"dim\",\n    \"light_hue\",\n    \"light_saturation\",\n    \"measure_waterlevel\",\n    \"alarm_tank_empty\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"capabilitiesOptions\": {\n    \"dim\": {\n      \"title\": {\n        \"en\": \"Ambient light brightness\",\n        \"nl\": \"Helderheid sfeerverlichting\",\n        \"da\": \"Lysstyrke for stemningslys\",\n        \"de\": \"Helligkeit des Umgebungslichts\",\n        \"es\": \"Brillo de luz ambiental\",\n        \"fr\": \"Luminosite de la lumiere d'ambiance\",\n        \"it\": \"Luminosita luce ambiente\",\n        \"no\": \"Lysstyrke for stemningslys\",\n        \"sv\": \"Ljusstyrka for omgivningsljus\",\n        \"pl\": \"Jasnosc oswietlenia ambientowego\",\n        \"ru\": \"Yarkost ambientnogo osveshcheniya\",\n        \"ko\": \"ambient light brightness\"\n      }\n    },\n    \"diffuser_xwhzp_fragrance_out_time\": {\n      \"min\": 30,\n      \"max\": 120,\n      \"step\": 10\n    }\n  },\n  \"energy\": {\n    \"batteries\": [\n      \"INTERNAL\"\n    ]\n  }\n}\n"
  },
  {
    "path": "drivers/diffuser_xwhzp_diffuser_xwxfj/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MijiaSmartScentDiffuserDriver extends Driver {}\n\nmodule.exports = MijiaSmartScentDiffuserDriver;\n"
  },
  {
    "path": "drivers/diffuser_xwhzp_diffuser_xwxfj/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"ja\": \"デバイス設定\",\n      \"zh\": \"设备设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/diffuser_xwhzp_diffuser_xwxfj/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/diffuser_xwhzp_diffuser_xwxfj/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/diffuser_xwhzp_diffuser_xwxfj/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/dmaker-fan/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass DmakerFanDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = DmakerFanDevice;\n"
  },
  {
    "path": "drivers/dmaker-fan/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Basic  Mi Smart Fan Generic (WiFi)\",\n    \"nl\": \"Basic Mi Smart Fan Generic (WiFi)\",\n    \"da\": \"Basis Mi Smart Fan Generic (WiFi)\",\n    \"de\": \"Basis Mi Smart Fan Generic (WiFi)\",\n    \"es\": \"Básico Mi Smart Fan Genérico (WiFi)\",\n    \"fr\": \"Basique Mi Smart Fan Générique (WiFi)\",\n    \"it\": \"Base Mi Smart Fan Generico (WiFi)\",\n    \"no\": \"Grunnleggende Mi Smart Fan Generic (WiFi)\",\n    \"sv\": \"Grundläggande Mi Smart Fan Generic (WiFi)\",\n    \"pl\": \"Podstawowy Mi Smart Fan Generic (WiFi)\",\n    \"ru\": \"Основной Mi Smart Fan Generic (WiFi)\",\n    \"ko\": \"베이직 Mi Smart Fan Generic (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/dmaker-fan/assets/images/large.jpg\",\n    \"small\": \"drivers/dmaker-fan/assets/images/small.jpg\"\n  },\n  \"class\": \"fan\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\"\n  ]\n}"
  },
  {
    "path": "drivers/dmaker-fan/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass DmakerFanDriver extends Driver {}\n\nmodule.exports = DmakerFanDriver;"
  },
  {
    "path": "drivers/dmaker-fan/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/dmaker-fan/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/dmaker-fan/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/dmaker-fan/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/fan_dmaker_advanced/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/dmaker.fan.p9\n// https://home.miot-spec.com/spec/dmaker.fan.p10\n// https://home.miot-spec.com/spec/dmaker.fan.p11\n// https://home.miot-spec.com/spec/dmaker.fan.p15\n// https://home.miot-spec.com/spec/dmaker.fan.p18\n// https://home.miot-spec.com/spec/dmaker.fan.p33\n// https://home.miot-spec.com/spec/dmaker.fan.p39\n// https://home.miot-spec.com/spec/dmaker.fan.p44\n// https://home.miot-spec.com/spec/dmaker.fan.1c\n// https://home.miot-spec.com/spec/xiaomi.fan.p45\n\nconst mapping = {\n    'dmaker.fan.p9': 'properties_p9',\n    'dmaker.fan.p10': 'properties_p10',\n    'dmaker.fan.p11': 'properties_p11',\n    'dmaker.fan.p15': 'properties_p11',\n    'dmaker.fan.p18': 'properties_p10',\n    'dmaker.fan.p33': 'properties_p33',\n    'dmaker.fan.p39': 'properties_p39',\n    'dmaker.fan.p44': 'properties_p44',\n    'dmaker.fan.1c': 'properties_1c',\n    'dmaker.fan.*': 'properties_p9',\n    'xiaomi.fan.p45': 'properties_p45'\n};\n\nconst properties = {\n    properties_p9: {\n        get_properties: [\n            { did: 'power', siid: 2, piid: 1 }, // onoff\n            { did: 'fan_level', siid: 2, piid: 2 }, // dim\n            { did: 'mode', siid: 2, piid: 4 }, // fan_dmaker_mode\n            { did: 'oscillating_mode', siid: 2, piid: 5 }, // oscillating\n            { did: 'oscillating_mode_angle', siid: 2, piid: 6 }, // fan_zhimi_angle\n            { did: 'fan_speed', siid: 2, piid: 11 }, // fan_speed\n            { did: 'light', siid: 2, piid: 9 }, // settings.led\n            { did: 'buzzer', siid: 2, piid: 7 }, // settings.buzzer\n            { did: 'child_lock', siid: 3, piid: 1 } // settings.childLock\n        ],\n        set_properties: {\n            oscillating_mode: { siid: 2, piid: 5 },\n            oscillating_mode_angle: { siid: 2, piid: 6 },\n            fan_speed: { siid: 2, piid: 11 },\n            mode: { siid: 2, piid: 4 },\n            light: { siid: 2, piid: 9 },\n            buzzer: { siid: 2, piid: 7 },\n            child_lock: { siid: 3, piid: 1 }\n        }\n    },\n    properties_p10: {\n        get_properties: [\n            { did: 'power', siid: 2, piid: 1 }, // onoff\n            { did: 'fan_level', siid: 2, piid: 2 }, // dim\n            { did: 'mode', siid: 2, piid: 3 }, // fan_dmaker_mode\n            { did: 'oscillating_mode', siid: 2, piid: 4 }, // oscillating\n            { did: 'oscillating_mode_angle', siid: 2, piid: 5 }, // fan_zhimi_angle\n            { did: 'fan_speed', siid: 2, piid: 10 }, // fan_speed\n            { did: 'light', siid: 2, piid: 7 }, // settings.led\n            { did: 'buzzer', siid: 2, piid: 8 }, // settings.buzzer\n            { did: 'child_lock', siid: 3, piid: 1 } // settings.childLock\n        ],\n        set_properties: {\n            oscillating_mode: { siid: 2, piid: 4 },\n            oscillating_mode_angle: { siid: 2, piid: 5 },\n            fan_speed: { siid: 2, piid: 10 },\n            mode: { siid: 2, piid: 3 },\n            light: { siid: 2, piid: 7 },\n            buzzer: { siid: 2, piid: 8 },\n            child_lock: { siid: 3, piid: 1 }\n        }\n    },\n    properties_p11: {\n        get_properties: [\n            { did: 'power', siid: 2, piid: 1 }, // onoff\n            { did: 'fan_level', siid: 2, piid: 2 }, // dim\n            { did: 'mode', siid: 2, piid: 3 }, // fan_dmaker_mode\n            { did: 'oscillating_mode', siid: 2, piid: 4 }, // oscillating\n            { did: 'oscillating_mode_angle', siid: 2, piid: 5 }, // fan_zhimi_angle\n            { did: 'fan_speed', siid: 2, piid: 6 }, // fan_speed\n            { did: 'light', siid: 4, piid: 1 }, // settings.led\n            { did: 'buzzer', siid: 5, piid: 1 }, // settings.buzzer\n            { did: 'child_lock', siid: 7, piid: 1 } // settings.childLock\n        ],\n        set_properties: {\n            oscillating_mode: { siid: 2, piid: 4 },\n            oscillating_mode_angle: { siid: 2, piid: 5 },\n            fan_speed: { siid: 2, piid: 6 },\n            mode: { siid: 2, piid: 3 },\n            light: { siid: 4, piid: 1 },\n            buzzer: { siid: 5, piid: 1 },\n            child_lock: { siid: 7, piid: 1 }\n        }\n    },\n    properties_p33: {\n        get_properties: [\n            { did: 'power', siid: 2, piid: 1 }, // onoff\n            { did: 'fan_level', siid: 2, piid: 2 }, // dim\n            { did: 'mode', siid: 2, piid: 3 }, // fan_dmaker_mode\n            { did: 'oscillating_mode', siid: 2, piid: 4 }, // oscillating\n            { did: 'oscillating_mode_angle', siid: 2, piid: 5 }, // fan_zhimi_angle\n            { did: 'fan_speed', siid: 2, piid: 6 }, // fan_speed\n            { did: 'light', siid: 4, piid: 1 }, // settings.led\n            { did: 'buzzer', siid: 5, piid: 1 }, // settings.buzzer\n            { did: 'child_lock', siid: 7, piid: 1 } // settings.childLock\n        ],\n        set_properties: {\n            oscillating_mode: { siid: 2, piid: 4 },\n            oscillating_mode_angle: { siid: 2, piid: 5 },\n            fan_speed: { siid: 2, piid: 6 },\n            mode: { siid: 2, piid: 3 },\n            light: { siid: 4, piid: 1 },\n            buzzer: { siid: 5, piid: 1 },\n            child_lock: { siid: 7, piid: 1 },\n            set_move: { siid: 6, piid: 1 } \n        }\n    },\n    properties_p39: {\n        get_properties: [\n            { did: 'power', siid: 2, piid: 1 }, // onoff\n            { did: 'fan_level', siid: 2, piid: 2 }, // dim\n            { did: 'mode', siid: 2, piid: 4 }, // fan_dmaker_mode\n            { did: 'oscillating_mode', siid: 2, piid: 5 }, // oscillating\n            { did: 'oscillating_mode_angle', siid: 2, piid: 6 }, // fan_zhimi_angle\n            { did: 'fan_speed', siid: 2, piid: 11 }, // fan_speed\n            { did: 'child_lock', siid: 3, piid: 1 } // settings.childLock\n        ],\n        set_properties: {\n            oscillating_mode: { siid: 2, piid: 5 },\n            oscillating_mode_angle: { siid: 2, piid: 6 },\n            fan_speed: { siid: 2, piid: 11 },\n            mode: { siid: 2, piid: 4 },\n            child_lock: { siid: 3, piid: 1 }\n        }\n    },\n    properties_p44: {\n        get_properties: [\n            { did: 'power', siid: 2, piid: 1 }, // onoff\n            { did: 'fan_level', siid: 2, piid: 2 }, // dim\n            { did: 'mode', siid: 2, piid: 3 }, // fan_dmaker_mode\n            { did: 'oscillating_mode', siid: 2, piid: 4 }, // oscillating\n            { did: 'light', siid: 4, piid: 1 }, // settings.led\n            { did: 'buzzer', siid: 5, piid: 1 }, // settings.buzzer\n            { did: 'child_lock', siid: 7, piid: 1 } // settings.childLock\n        ],\n        set_properties: {\n            oscillating_mode: { siid: 2, piid: 4 },\n            mode: { siid: 2, piid: 3 },\n            light: { siid: 4, piid: 1 },\n            buzzer: { siid: 5, piid: 1 },\n            child_lock: { siid: 7, piid: 1 }\n        }\n    },\n    properties_1c: {\n        get_properties: [\n            { did: 'power', siid: 2, piid: 1 }, // onoff\n            { did: 'fan_level', siid: 2, piid: 2 }, // dim\n            { did: 'mode', siid: 2, piid: 7 }, // fan_dmaker_mode\n            { did: 'oscillating_mode', siid: 2, piid: 3 }, // oscillating\n            { did: 'light', siid: 2, piid: 12 }, // setting.led\n            { did: 'buzzer', siid: 2, piid: 11 }, // settings.buzzer\n            { did: 'child_lock', siid: 3, piid: 1 } // settings.childLock\n        ],\n        set_properties: {\n            oscillating_mode: { siid: 2, piid: 3 },\n            mode: { siid: 2, piid: 7 },\n            light: { siid: 2, piid: 12 },\n            buzzer: { siid: 2, piid: 11 },\n            child_lock: { siid: 3, piid: 1 }\n        }\n    },\n    properties_p45: {\n        get_properties: [\n            { did: 'power', siid: 2, piid: 1 }, // onoff\n            { did: 'fan_level', siid: 2, piid: 4 }, // dim           (gear 1‑4)\n            { did: 'mode', siid: 2, piid: 3 }, // fan_dmaker_mode 0‑Straight / 1‑Natural / 2‑Sleep\n            { did: 'oscillating_mode', siid: 2, piid: 6 }, // oscillating   (bool)\n            { did: 'oscillating_mode_angle', siid: 2, piid: 7 }, // fan_zhimi_angle 30‑150\n            { did: 'fan_speed', siid: 2, piid: 5 }, // fan_speed     (1‑100 %)\n            { did: 'light', siid: 5, piid: 1 }, // settings.led  (bool)\n            { did: 'buzzer', siid: 7, piid: 1 }, // settings.buzzer (bool)\n            { did: 'child_lock', siid: 11, piid: 1 } // settings.childLock (bool)\n        ],\n\n        set_properties: {\n            fan_level: { siid: 2, piid: 4 },\n            oscillating_mode: { siid: 2, piid: 6 },\n            oscillating_mode_angle: { siid: 2, piid: 7 },\n            fan_speed: { siid: 2, piid: 5 },\n            mode: { siid: 2, piid: 3 },\n            light: { siid: 5, piid: 1 },\n            buzzer: { siid: 7, piid: 1 },\n            child_lock: { siid: 11, piid: 1 }\n        }\n    }\n};\n\n/* Model‑specific mode enumerations */\nconst modeMap = {\n    'dmaker.fan.p9': { 0: 'Straight Wind', 1: 'Natural Wind' },\n    'dmaker.fan.p10': { 0: 'Straight Wind', 1: 'Natural Wind', 2: 'Sleep' },\n    'dmaker.fan.p11': { 0: 'Straight Wind', 1: 'Natural Wind', 2: 'Sleep' },\n    'dmaker.fan.p15': { 0: 'Straight Wind', 1: 'Natural Wind', 2: 'Sleep' },\n    'dmaker.fan.p18': { 0: 'Straight Wind', 1: 'Natural Wind', 2: 'Sleep' },\n    'dmaker.fan.p33': { 0: 'Straight Wind', 1: 'Natural Wind' },\n    'dmaker.fan.p39': { 0: 'Straight Wind', 1: 'Natural Wind', 2: 'Sleep' },\n    'dmaker.fan.p44': { 0: 'Straight Wind', 1: 'Natural Wind', 2: 'Sleep', 3: 'Cold Air' },\n    'dmaker.fan.1c': { 0: 'Straight Wind', 1: 'Sleep' },\n    'xiaomi.fan.p45': { 0: 'Straight Wind', 1: 'Natural Wind', 2: 'Sleep' }\n};\n\nclass AdvancedDmakerFanMiotDevice extends Device {\n    async onInit() {\n        try {\n            if (!this.util) this.util = new Util({ homey: this.homey });\n\n            // GENERIC DEVICE INIT ACTIONS\n            this.bootSequence();\n\n            /* Build correct Mode selector for this model */\n            const modelId = this.getStoreValue('model');\n            const modeTable = modeMap[modelId] ?? { 0: 'Straight Wind' };\n\n            await this.setCapabilityOptions('fan_dmaker_mode', {\n                values: Object.keys(modeTable).map((id) => ({ id, title: modeTable[id] }))\n            });\n\n            // ADD DEVICES DEPENDANT CAPABILITIES\n            if (this.getStoreValue('model') === 'dmaker.fan.p44' || this.getStoreValue('model') === 'dmaker.fan.1c') {\n                if (this.hasCapability('fan_speed')) {\n                    this.removeCapability('fan_speed');\n                }\n                if (this.hasCapability('fan_zhimi_angle')) {\n                    this.removeCapability('fan_zhimi_angle');\n                }\n            }\n\n            // DEVICE VARIABLES\n            this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['dmaker.fan.*']];\n\n            // FLOW TRIGGER CARDS\n            this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n            // Register flow action for rotating left by one step\n            this.homey.flow.getActionCard('rotateLeftStep').registerRunListener(async (args, state) => {\n                return this.rotateFanHead('left');\n            });\n\n            // Register flow action for rotating right by one step\n            this.homey.flow.getActionCard('rotateRightStep').registerRunListener(async (args, state) => {\n                return this.rotateFanHead('right');\n            });\n\n            // LISTENERS FOR UPDATING CAPABILITIES\n            this.registerCapabilityListener('onoff', async (value) => {\n                try {\n                    if (this.miio) {\n                        return await this.miio.call('set_properties', [{ did: 'onoff', siid: 2, piid: 1, value: value }], { retries: 1 });\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('oscillating', async (value) => {\n                try {\n                    if (this.miio) {\n                        return await this.miio.call('set_properties', [{ did: 'oscillating_mode', siid: this.deviceProperties.set_properties.oscillating_mode.siid, piid: this.deviceProperties.set_properties.oscillating_mode.piid, value: value ? 1 : 0 }], { retries: 1 });\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            /* ─── DIM / gear fan‑level 1‑4 ─── */\n            this.registerCapabilityListener('dim', async (value) => {\n                try {\n                    if (!this.miio) throw new Error('miio not initialised');\n\n                    const prop = this.deviceProperties.set_properties.fan_level ?? { siid: 2, piid: 2 }; // fall‑back for older models\n\n                    return await this.miio.call(\n                        'set_properties',\n                        [\n                            {\n                                did: 'fan_level',\n                                siid: prop.siid,\n                                piid: prop.piid,\n                                value: value\n                            }\n                        ],\n                        { retries: 1 }\n                    );\n                } catch (error) {\n                    this.error(error);\n                    this.setUnavailable(this.homey.__('unreachable')).catch(this.error);\n                    this.createDevice();\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('fan_zhimi_angle', async (value) => {\n                try {\n                    if (this.miio) {\n                        return await this.miio.call('set_properties', [{ did: 'fan_zhimi_angle', siid: this.deviceProperties.set_properties.oscillating_mode_angle.siid, piid: this.deviceProperties.set_properties.oscillating_mode_angle.piid, value: +value }], { retries: 1 });\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('fan_speed', async (value) => {\n                try {\n                    if (this.miio) {\n                        return await this.miio.call('set_properties', [{ did: 'fan_speed', siid: this.deviceProperties.set_properties.fan_speed.siid, piid: this.deviceProperties.set_properties.fan_speed.piid, value: value * 100 }], { retries: 1 });\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('fan_dmaker_mode', async (value) => {\n                try {\n                    if (this.miio) {\n                        return await this.miio.call('set_properties', [{ did: 'set', siid: this.deviceProperties.set_properties.mode.siid, piid: this.deviceProperties.set_properties.mode.piid, value: Number(value) }], { retries: 1 });\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n        } catch (error) {\n            this.error(error);\n        }\n    }\n\n    async onSettings({ oldSettings, newSettings, changedKeys }) {\n        if (changedKeys.includes('address') || changedKeys.includes('token') || changedKeys.includes('polling')) {\n            this.refreshDevice();\n        }\n\n        if (changedKeys.includes('led') && this.getStoreValue('model') !== 'dmaker.fan.p39') {\n            await this.miio.call('set_properties', [{ did: 'light', siid: this.deviceProperties.set_properties.light.siid, piid: this.deviceProperties.set_properties.light.piid, value: newSettings.led }], { retries: 1 });\n        }\n\n        if (changedKeys.includes('buzzer') && this.getStoreValue('model') !== 'dmaker.fan.p39') {\n            await this.miio.call('set_properties', [{ did: 'buzzer', siid: this.deviceProperties.set_properties.buzzer.siid, piid: this.deviceProperties.set_properties.buzzer.piid, value: newSettings.buzzer }], { retries: 1 });\n        }\n\n        if (changedKeys.includes('childLock')) {\n            await this.miio.call('set_properties', [{ did: 'child_lock', siid: this.deviceProperties.set_properties.child_lock.siid, piid: this.deviceProperties.set_properties.child_lock.piid, value: newSettings.childLock }], { retries: 1 });\n        }\n\n        return Promise.resolve(true);\n    }\n\n    async retrieveDeviceData() {\n        try {\n            const result = await this.miio.call('get_properties', this.deviceProperties.get_properties, { retries: 1 });\n            if (!this.getAvailable()) {\n                await this.setAvailable();\n            }\n\n            /* data */\n            const onoff = result.find((obj) => obj.did === 'power');\n            const oscillating_mode = result.find((obj) => obj.did === 'oscillating_mode');\n            const dim_fan_level = result.find((obj) => obj.did === 'fan_level');\n            const mode = result.find((obj) => obj.did === 'mode');\n\n            const led = result.find((obj) => obj.did === 'light');\n            const buzzer = result.find((obj) => obj.did === 'buzzer');\n            const child_lock = result.find((obj) => obj.did === 'child_lock');\n\n            /* capabilities */\n            await this.updateCapabilityValue('onoff', onoff.value);\n            await this.updateCapabilityValue('oscillating', oscillating_mode.value);\n            await this.updateCapabilityValue('dim', +dim_fan_level.value);\n\n            if (this.hasCapability('fan_zhimi_angle')) {\n                const dim_oscillating_mode_angle = result.find((obj) => obj.did === 'oscillating_mode_angle');\n                await this.updateCapabilityValue('fan_zhimi_angle', dim_oscillating_mode_angle.value.toString());\n            }\n            if (this.hasCapability('fan_speed')) {\n                const fan_speed = result.find((obj) => obj.did === 'fan_speed');\n                await this.updateCapabilityValue('fan_speed', fan_speed.value / 100);\n            }\n\n            /* settings */\n            if (led !== undefined) {\n                await this.updateSettingValue('led', !!led.value);\n            }\n            if (buzzer !== undefined) {\n                await this.updateSettingValue('buzzer', buzzer.value);\n            }\n            await this.updateSettingValue('childLock', child_lock.value);\n\n            /* mode capability */\n            if (this.getCapabilityValue('fan_dmaker_mode') !== mode.value.toString()) {\n                const previous_mode = this.getCapabilityValue('fan_dmaker_mode');\n                await this.setCapabilityValue('fan_dmaker_mode', mode.value.toString());\n                const nameTable = modeMap[this.getStoreValue('model')] ?? {};\n                await this.homey.flow\n                    .getDeviceTriggerCard('triggerModeChanged')\n                    .trigger(this, { new_mode: nameTable[mode.value] ?? String(mode.value), previous_mode: nameTable[previous_mode] ?? String(previous_mode) })\n                    .catch((error) => {\n                        this.error(error);\n                    });\n            }\n        } catch (error) {\n            this.homey.clearInterval(this.pollingInterval);\n\n            if (this.getAvailable()) {\n                this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((error) => {\n                    this.error(error);\n                });\n            }\n\n            this.homey.setTimeout(() => {\n                this.createDevice();\n            }, 60000);\n\n            this.error(error);\n        }\n    }\n\n    /**\n     * Rotate the fan head by one device-defined step (typically 5–7.5 degrees) left or right.\n     * @param {\"left\"|\"right\"} direction\n     */\n    async rotateFanHead(direction) {\n        this.log(`[Rotate] Requesting fan to rotate ${direction}`);\n\n        // Check for model\n        const model = this.getStoreValue('model');\n        if (model === 'xiaomi.fan.p45') {\n            // Use MIOT Action call for Smart Tower Fan 2\n            let aiid;\n            if (direction === 'left') aiid = 4;\n            else if (direction === 'right') aiid = 5;\n            else throw new Error('Invalid direction for rotateFanHead');\n            try {\n                return await this.miio.call('action', {\n                    siid: 2,\n                    aiid: aiid,\n                    in: []\n                });\n            } catch (err) {\n                this.error(`[Rotate] Failed to rotate fan (miot action):`, err);\n                throw err;\n            }\n        } else {\n            // Fallback for other models using legacy \"set_move\" property if exists\n            const moveMap = this.deviceProperties.set_properties.set_move;\n            if (!moveMap) {\n                this.error('[Rotate] set_move property mapping not found for this model');\n                throw new Error('Device does not support manual rotation');\n            }\n            let value;\n            if (direction === 'right') value = 1; // Rotate right (JSON points to left)\n            else if (direction === 'left') value = 2; // Rotate left (JSON points to right)\n            else {\n                this.error('[Rotate] Invalid direction:', direction);\n                throw new Error('Invalid direction');\n            }\n            try {\n                return await this.miio.call(\n                    'set_properties',\n                    [\n                        {\n                            did: 'set_move',\n                            siid: moveMap.siid,\n                            piid: moveMap.piid,\n                            value: value\n                        }\n                    ],\n                    { retries: 1 }\n                );\n            } catch (err) {\n                this.error('[Rotate] Failed to rotate fan:', err);\n                throw err;\n            }\n        }\n    }\n}\n\nmodule.exports = AdvancedDmakerFanMiotDevice;\n"
  },
  {
    "path": "drivers/fan_dmaker_advanced/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Advanced Mi Smart Standing Fan MIoT (WiFi)\",\n    \"nl\": \"Geadvanceerde Mi Smart Standing Fan MIoT (WiFi)\",\n    \"da\": \"Avanceret Mi Smart Standing Fan MIoT (WiFi)\",\n    \"de\": \"Erweiterter Mi Smart Standventilator MIoT (WiFi)\",\n    \"es\": \"Ventilador de pie avanzado Mi Smart MIoT (WiFi)\",\n    \"fr\": \"Ventilateur sur pied intelligent Mi avancé MIoT (WiFi)\",\n    \"it\": \"Ventilatore Smart Standing avanzato Mi MIoT (WiFi)\",\n    \"no\": \"Avansert Mi Smart stående vifte MIoT (WiFi)\",\n    \"sv\": \"Avancerad Mi Smart stående fläkt MIoT (WiFi)\",\n    \"pl\": \"Zaawansowany stojący wentylator Mi Smart MIoT (WiFi)\",\n    \"ru\": \"Продвинутый Mi Smart стоячий вентилятор MIoT (WiFi)\",\n    \"ko\": \"고급형 Mi 스마트 스탠딩 팬 MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/fan_dmaker_advanced/assets/images/large.jpg\",\n    \"small\": \"drivers/fan_dmaker_advanced/assets/images/small.jpg\"\n  },\n  \"class\": \"fan\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"oscillating\",\n    \"dim\",\n    \"fan_zhimi_angle\",\n    \"fan_speed\",\n    \"fan_dmaker_mode\"\n  ],\n  \"capabilitiesOptions\": {\n    \"dim\": {\n      \"title\": {\n        \"en\": \"Fanlevel\",\n        \"nl\": \"Ventilator niveau\",\n        \"da\": \"Fan niveau\",\n        \"de\": \"Ventilatorebene\",\n        \"es\": \"Nivel de ventilador\",\n        \"fr\": \"Niveau de ventilateur\",\n        \"it\": \"Livello del ventilatore\",\n        \"no\": \"Viftenivå\",\n        \"sv\": \"Fläktnivå\",\n        \"pl\": \"Poziom wentylatora\",\n        \"ru\": \"Уровень вентилятора\",\n        \"ko\": \"팬 레벨\"\n      },\n      \"min\": 1,\n      \"max\": 4,\n      \"step\": 1\n    }\n  }\n}"
  },
  {
    "path": "drivers/fan_dmaker_advanced/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass AdvancedDmakerFanMiotDriver extends Driver {}\n\nmodule.exports = AdvancedDmakerFanMiotDriver;"
  },
  {
    "path": "drivers/fan_dmaker_advanced/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de Usuario\",\n      \"fr\": \"Paramètres Utilisateur\",\n      \"it\": \"Impostazioni Utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia Użytkownika\",\n      \"ru\": \"Пользовательские настройки\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"Светодиод\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summer\",\n          \"de\": \"Summer\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Buzzer\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Summer\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Brzęczyk\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"버저\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnelås\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo para Niños\",\n          \"fr\": \"Verrouillage Enfant\",\n          \"it\": \"Blocco Bambino\",\n          \"no\": \"Barnesikring\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada rodzicielska\",\n          \"ru\": \"Блокировка от детей\",\n          \"ko\": \"차일드 락\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del Dispositivo\",\n      \"fr\": \"Paramètres de l'Appareil\",\n      \"it\": \"Impostazioni del Dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia Urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/fan_dmaker_advanced/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/fan_dmaker_advanced/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/fan_dmaker_advanced/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/fan_zhimi_advanced/device.js",
    "content": "\"use strict\";\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/zhimi.fan.v2\n// https://home.miot-spec.com/spec/zhimi.fan.v3\n// https://home.miot-spec.com/spec/zhimi.fan.sa1\n// https://home.miot-spec.com/spec/zhimi.fan.za1\n// https://home.miot-spec.com/spec/zhimi.fan.za3\n// https://home.miot-spec.com/spec/zhimi.fan.za4\n\nconst modes = {\n  1: \"Natural Wind\",\n  2: \"Straight Wind\"\n};\n\nclass ZhiMiFanAdvancedDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_power\", [value ? \"on\" : \"off\"], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('oscillating', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_angle_enable\", [value ? \"on\" : \"off\"], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('fan_speed', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_speed_level\", [value * 100], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('measure_wind_angle', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_angle\", [value], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('fan_zhimi_mode', async ( value ) => {\n        try {\n          if (this.miio) {\n            if (this.getStoreValue('model') === 'zhimi.fan.sa1' || this.getStoreValue('model') === 'zhimi.fan.za1') {\n              value = +value + 1;\n            }\n            return await this.miio.call(\"set_natural_level\", [+value], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      const led = await this.miio.call(\"set_led_b\", [newSettings.led ? 1 : 0], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"buzzer\")) {\n      const buzzer = await this.miio.call(\"set_buzzer\", [newSettings.buzzer ? 1 : 0], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"childLock\")) {\n      const childlock = await this.miio.call(\"set_child_lock\", [newSettings.childLock ? \"on\" : \"off\"], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call(\"get_prop\", [\"power\", \"angle\", \"angle_enable\", \"speed_level\", \"natural_level\", \"child_lock\", \"buzzer\", \"led_b\"], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"onoff\", result[0] == \"on\");\n      await this.updateCapabilityValue(\"measure_wind_angle\", +result[1]);\n      await this.updateCapabilityValue(\"oscillating\", result[2] == \"on\");\n      await this.updateCapabilityValue(\"fan_speed\", result[3] / 100);\n\n      /* settings */\n      await this.updateSettingValue(\"childLock\", result[5] == \"on\");\n      await this.updateSettingValue(\"buzzer\",!!result[6]);\n      await this.updateSettingValue(\"led\", !!result[7]);\n\n      /* mode capability */\n      let mode;\n      if (this.getStoreValue('model') === 'zhimi.fan.sa1' || this.getStoreValue('model') === 'zhimi.fan.za1') {\n        mode = result[4] - 1;\n      } else {\n        mode = result[4]\n      }\n      if (mode <= 1 && this.getCapabilityValue('fan_zhimi_mode') !== mode.toString()) {\n        const previous_mode = this.getCapabilityValue('fan_zhimi_mode');\n        await this.setCapabilityValue('fan_zhimi_mode', mode.toString());\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, {\"new_mode\": modes[mode], \"previous_mode\": modes[+previous_mode] }).catch(error => { this.error(error) });\n      }\n\n      /* zhimi.fan.v2 & zhimi.fan.v3 */\n      if (this.getStoreValue('model') === 'zhimi.fan.v2' || this.getStoreValue('model') === 'zhimi.fan.v3') {\n        await this.util.sleep(2000);\n        const resultv2 = await this.miio.call(\"get_prop\", [\"battery\", \"humidity\", \"temp_dec\"], { retries: 1 });\n\n        await this.updateCapabilityValue(\"measure_battery\", +resultv2[0]);\n        await this.updateCapabilityValue(\"measure_humidity\", +resultv2[1]);\n        await this.updateCapabilityValue(\"measure_temperature\", +resultv2[2] / 10);\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = ZhiMiFanAdvancedDevice;"
  },
  {
    "path": "drivers/fan_zhimi_advanced/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Advanced Smartmi/ZhiMi Fan (WiFi)\",\n    \"nl\": \"Geadvanceerde Smartmi/ZhiMi Fan (WiFi)\",\n    \"da\": \"Avanceret Smartmi/ZhiMi Fan (WiFi)\",\n    \"de\": \"Erweiterter Smartmi/ZhiMi Ventilator (WiFi)\",\n    \"es\": \"Ventilador Smartmi/ZhiMi Avanzado (WiFi)\",\n    \"fr\": \"Ventilateur Smartmi/ZhiMi Avancé (WiFi)\",\n    \"it\": \"Ventilatore Smartmi/ZhiMi Avanzato (WiFi)\",\n    \"no\": \"Avansert Smartmi/ZhiMi Vifte (WiFi)\",\n    \"sv\": \"Avancerad Smartmi/ZhiMi Fläkt (WiFi)\",\n    \"pl\": \"Zaawansowany Smartmi/ZhiMi Wentylator (WiFi)\",\n    \"ru\": \"Продвинутый Smartmi/ZhiMi Вентилятор (WiFi)\",\n    \"ko\": \"고급 Smartmi/ZhiMi 팬 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/fan_zhimi_advanced/assets/images/large.jpg\",\n    \"small\": \"drivers/fan_zhimi_advanced/assets/images/small.jpg\"\n  },\n  \"class\": \"fan\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"oscillating\",\n    \"fan_speed\",\n    \"measure_wind_angle\",\n    \"fan_zhimi_mode\"\n  ],\n  \"capabilitiesOptions\": {\n    \"measure_wind_angle\": {\n      \"min\": 0,\n      \"max\": 120,\n      \"step\": 1\n    }\n  }\n}"
  },
  {
    "path": "drivers/fan_zhimi_advanced/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass ZhiMiFanAdvancedDriver extends Driver {}\n\nmodule.exports = ZhiMiFanAdvancedDriver;"
  },
  {
    "path": "drivers/fan_zhimi_advanced/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"LED\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summer\",\n          \"de\": \"Summer\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Sonnerie\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Summelyd\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Brzęczyk\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"버저\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnelås\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo para niños\",\n          \"fr\": \"Verrouillage enfant\",\n          \"it\": \"Blocco per bambini\",\n          \"no\": \"Barnesikring\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada dla dzieci\",\n          \"ru\": \"Детский замок\",\n          \"ko\": \"어린이 잠금 장치\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/fan_zhimi_advanced/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/fan_zhimi_advanced/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/fan_zhimi_advanced/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/fan_zhimi_fan_za5/device.js",
    "content": "\"use strict\";\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/zhimi.fan.za5\n\nconst params = [\n  { did: \"power\", siid: 2, piid: 1 }, // onoff\n  { did: \"fan_speed\", siid: 2, piid: 2 }, // fan_speed\n  { did: \"swing_mode\", siid: 2, piid: 3 }, // oscillating\n  { did: \"swing_mode_angle\", siid: 2, piid: 5 }, // fan_zhimi_angle\n  { did: \"mode\", siid: 2, piid: 7 }, // fan_zhimi_mode\n  { did: \"anion\", siid: 2, piid: 11 }, // onoff.ion\n  { did: \"child_lock\", siid: 3, piid: 1 }, // settings.childLock\n  { did: \"light\", siid: 4, piid: 3 }, // settings.led\n  { did: \"buzzer\", siid: 5, piid: 1 }, // settings.buzzer\n  { did: \"humidity\", siid: 7, piid: 1 }, // measure_humidity\n  { did: \"temperature\", siid: 7, piid: 7 }, // measure_temperature\n];\n\nconst modes = {\n  1: \"Natural Wind\",\n  2: \"Straight Wind\"\n};\n\nclass ZhiMiFanZA5Device extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: 2, piid: 1, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('oscillating', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: 2, piid: 3, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('onoff.ion', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: 2, piid: 11, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('fan_speed', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: 2, piid: 2, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('fan_zhimi_angle', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: 2, piid: 5, value: +value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('fan_zhimi_mode', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: 2, piid: 7, value: +value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      const led = await this.miio.call(\"set_properties\", [{ siid: 4, piid: 3, value: newSettings.led ? 100 : 0 }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"buzzer\")) {\n      const buzzer = await this.miio.call(\"set_properties\", [{ siid: 5, piid: 1, value: newSettings.buzzer }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"childLock\")) {\n      const childlock = await this.miio.call(\"set_properties\", [{ siid: 3, piid: 1, value: newSettings.childLock }], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call(\"get_properties\", params, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const onoff = result.find(obj => obj.did === 'power');\n      const fan_speed = result.find(obj => obj.did === 'fan_speed');\n      const oscillating = result.find(obj => obj.did === 'swing_mode');\n      const onoff_ion = result.find(obj => obj.did === 'anion');\n      const fan_zhimi_angle = result.find(obj => obj.did === 'swing_mode_angle');\n      const measure_humidity = result.find(obj => obj.did === 'humidity');\n      const measure_temperature = result.find(obj => obj.did === 'temperature');\n\n      const childLock = result.find(obj => obj.did === 'child_lock');\n      const led = result.find(obj => obj.did === 'light');\n      const buzzer = result.find(obj => obj.did === 'buzzer');\n      \n      /* capabilities */\n      await this.updateCapabilityValue(\"onoff\", onoff.value);\n      await this.updateCapabilityValue(\"fan_speed\", fan_speed.value);\n      await this.updateCapabilityValue(\"oscillating\", oscillating.value);\n      await this.updateCapabilityValue(\"onoff.ion\", onoff_ion.value);\n      await this.updateCapabilityValue(\"fan_zhimi_angle\", fan_zhimi_angle.value.toString());\n      await this.updateCapabilityValue(\"measure_humidity\", measure_humidity.value);\n      await this.updateCapabilityValue(\"measure_temperature\", measure_temperature.value);\n\n      /* settings */\n      await this.updateSettingValue(\"childLock\", childLock.value);\n      await this.updateSettingValue(\"led\", led.value);\n      await this.updateSettingValue(\"buzzer\", buzzer.value);\n\n      /* mode capability */\n      const mode = result.find(obj => obj.did === 'mode');\n      if (this.getCapabilityValue('fan_zhimi_mode') !== mode.value.toString()) {\n        const previous_mode = this.getCapabilityValue('fan_zhimi_mode');\n        await this.setCapabilityValue('fan_zhimi_mode', mode.value.toString());\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, {\"new_mode\": modes[mode.value], \"previous_mode\": modes[+previous_mode] }).catch(error => { this.error(error) });\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = ZhiMiFanZA5Device;"
  },
  {
    "path": "drivers/fan_zhimi_fan_za5/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Smartmi Standing Fan 3 (WiFi)\",\n    \"nl\": \"Smartmi Standing Fan 3 (WiFi)\",\n    \"da\": \"Smartmi Standing Fan 3 (WiFi)\",\n    \"de\": \"Smartmi Standventilator 3 (WiFi)\",\n    \"es\": \"Ventilador de Pie Smartmi 3 (WiFi)\",\n    \"fr\": \"Ventilateur Debout Smartmi 3 (WiFi)\",\n    \"it\": \"Ventilatore a Piantana Smartmi 3 (WiFi)\",\n    \"no\": \"Smartmi Stående Vifte 3 (WiFi)\",\n    \"sv\": \"Smartmi Golvfläkt 3 (WiFi)\",\n    \"pl\": \"Wentylator stojący Smartmi 3 (WiFi)\",\n    \"ru\": \"Стоящий вентилятор Smartmi 3 (WiFi)\",\n    \"ko\": \"Smartmi 스탠딩 팬 3 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/fan_zhimi_fan_za5/assets/images/large.jpg\",\n    \"small\": \"drivers/fan_zhimi_fan_za5/assets/images/small.jpg\"\n  },\n  \"class\": \"fan\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"oscillating\",\n    \"onoff.ion\",\n    \"fan_speed\",\n    \"fan_zhimi_angle\",\n    \"fan_zhimi_mode\",\n    \"measure_humidity\",\n    \"measure_temperature\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.ion\": {\n      \"title\": {\n        \"en\": \"Enable ions\",\n        \"nl\": \"Inschakelen ionen\",\n        \"da\": \"Aktiver ioner\",\n        \"de\": \"Ionen aktivieren\",\n        \"es\": \"Activar iones\",\n        \"fr\": \"Activer les ions\",\n        \"it\": \"Abilita ioni\",\n        \"no\": \"Aktiver ioner\",\n        \"sv\": \"Aktivera joner\",\n        \"pl\": \"Włącz jony\",\n        \"ru\": \"Включить ионы\",\n        \"ko\": \"이온 활성화\"\n      }\n    },\n    \"fan_speed\": {\n      \"min\": 1,\n      \"max\": 4,\n      \"step\": 1,\n      \"units\": \"level\"\n    }\n  }\n}"
  },
  {
    "path": "drivers/fan_zhimi_fan_za5/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass ZhiMiFanZA5Driver extends Driver {}\n\nmodule.exports = ZhiMiFanZA5Driver;"
  },
  {
    "path": "drivers/fan_zhimi_fan_za5/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\",\n      \"pt\": \"Configurações do usuário\",\n      \"zh\": \"用户设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"Светодиод\",\n          \"ko\": \"LED\",\n          \"pt\": \"LED\",\n          \"zh\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summer\",\n          \"de\": \"Summerton\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Sonnerie\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Summer\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Brzęczyk\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"버저\",\n          \"pt\": \"Buzzer\",\n          \"zh\": \"蜂鸣器\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnelås\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo infantil\",\n          \"fr\": \"Verrouillage enfant\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barnesikring\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada dziecięca\",\n          \"ru\": \"Блокировка от детей\",\n          \"ko\": \"자녀 보호\",\n          \"pt\": \"Bloqueio infantil\",\n          \"zh\": \"儿童锁\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"pt\": \"Configurações do dispositivo\",\n      \"zh\": \"设备设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/fan_zhimi_fan_za5/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/fan_zhimi_fan_za5/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/fan_zhimi_fan_za5/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/gateway/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\nconst tinycolor = require('tinycolor2');\n\nclass GatewayDevice extends Device {\n    async onInit() {\n        try {\n            if (!this.util) this.util = new Util({ homey: this.homey });\n\n            // GENERIC DEVICE INIT ACTIONS\n            this.bootSequence();\n\n            // LISTENERS FOR UPDATING CAPABILITIES\n            this.registerCapabilityListener('onoff', async (value) => {\n                try {\n                    if (this.miio && typeof this.miio.child === 'function') {\n                        const lightChild = this.miio.child('light');\n                        if (!lightChild || typeof lightChild.setPower !== 'function') {\n                            this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                                this.error(error);\n                            });\n                            this.createDevice();\n                            this.error('Light child device not available');\n                            return Promise.reject(new Error('Light child device not available'));\n                        }\n                        return await lightChild.setPower(value);\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('dim', async (value) => {\n                try {\n                    if (this.miio && typeof this.miio.child === 'function') {\n                        const brightness = value * 100;\n                        if (brightness < 1 && this.getCapabilityValue('onoff')) {\n                            this.triggerCapabilityListener('onoff', false);\n                        } else if (brightness > 0 && !this.getCapabilityValue('onoff')) {\n                            this.triggerCapabilityListener('onoff', true);\n                        }\n                        const lightChild = this.miio.child('light');\n                        if (!lightChild || typeof lightChild.setBrightness !== 'function') {\n                            this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                                this.error(error);\n                            });\n                            this.createDevice();\n                            this.error('Light child device not available');\n                            return Promise.reject(new Error('Light child device not available'));\n                        }\n                        return await lightChild.setBrightness(brightness);\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerMultipleCapabilityListener(\n                ['light_hue', 'light_saturation'],\n                async (valueObj) => {\n                    try {\n                        if (this.miio && typeof this.miio.child === 'function') {\n                            if (valueObj.hasOwnProperty('light_hue')) {\n                                var hue_value = valueObj.light_hue;\n                            } else {\n                                var hue_value = this.getCapabilityValue('light_hue');\n                            }\n\n                            if (valueObj.hasOwnProperty('light_saturation')) {\n                                var saturation_value = valueObj.light_saturation;\n                            } else {\n                                var saturation_value = this.getCapabilityValue('light_saturation');\n                            }\n\n                            const hue = hue_value * 360;\n                            const saturation = saturation_value * 100;\n                            const dim = this.getCapabilityValue('dim') * 100;\n                            const colorUpdate = tinycolor({ h: Math.round(hue), s: Math.round(saturation), v: dim });\n\n                            const lightChild = this.miio.child('light');\n                            if (!lightChild || typeof lightChild.color !== 'function') {\n                                this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                                    this.error(error);\n                                });\n                                this.createDevice();\n                                this.error('Light child device not available');\n                                return Promise.reject(new Error('Light child device not available'));\n                            }\n\n                            return await lightChild.color(colorUpdate.toRgbString());\n                        } else {\n                            this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                                this.error(error);\n                            });\n                            this.createDevice();\n                            return Promise.reject('Device unreachable, please try again ...');\n                        }\n                    } catch (error) {\n                        this.error(error);\n                        return Promise.reject(error);\n                    }\n                },\n                500\n            );\n\n            this.registerCapabilityListener('homealarm_state', async (value) => {\n                try {\n                    if (this.miio) {\n                        const state = value == 'armed' ? true : false;\n                        return await this.miio.setArming(state);\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('speaker_playing', async (value) => {\n                try {\n                    if (this.miio) {\n                        return await this.miio.call('play_fm', [value ? 'on' : 'off'], { retries: 1 });\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('speaker_next', async (value) => {\n                try {\n                    if (this.miio) {\n                        return await this.miio.call('play_fm', ['next'], { retries: 1 });\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('speaker_prev', async (value) => {\n                try {\n                    if (this.miio) {\n                        return await this.miio.call('play_fm', ['prev'], { retries: 1 });\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('volume_set', async (value) => {\n                try {\n                    if (this.miio) {\n                        let volume = parseInt(value * 100);\n                        return await this.miio.call('volume_ctrl_fm', [volume.toString()], { retries: 1 });\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('volume_set.alarm', async (value) => {\n                try {\n                    if (this.miio) {\n                        let volume = parseInt(value * 100);\n                        return await this.miio.call('set_alarming_volume', [volume], { retries: 1 });\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('button', async (value) => {\n                try {\n                    if (this.miio) {\n                        return await this.miio.call('start_zigbee_join', [30]);\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n        } catch (error) {\n            this.error(error);\n        }\n    }\n\n    async onSettings({ oldSettings, newSettings, changedKeys }) {\n        if (changedKeys.includes('address') || changedKeys.includes('token') || changedKeys.includes('polling')) {\n            this.refreshDevice();\n        }\n\n        for (let i = 0; i < 20; i++) {\n            if (changedKeys.includes(`favorite${i}ID`)) {\n                let newFavoriteListsID = newSettings[`favorite${i}ID`];\n                let oldFavoriteListID = oldSettings[`favorite${i}ID`];\n                let newFavoriteListsIDArray = newFavoriteListsID.split(',');\n                let oldFavoriteListsIDArray = oldFavoriteListID.split(',');\n\n                if (oldFavoriteListsIDArray[0] !== undefined && oldFavoriteListsIDArray[0] !== null && oldFavoriteListsIDArray[1] !== undefined && oldFavoriteListsIDArray[1] !== null) {\n                    let ids = oldFavoriteListsIDArray[0];\n                    ids = ids.replace(/\\s/g, '');\n                    let id = parseInt(ids);\n                    let urls = oldFavoriteListsIDArray[1];\n                    urls = urls.replace(/\\s/g, '');\n                    let url = urls.toString();\n\n                    await this.miio.call('remove_channels', { chs: [{ id: id, type: 0, url: url }] });\n                }\n\n                if (newFavoriteListsIDArray[0] !== undefined && newFavoriteListsIDArray[0] !== null && newFavoriteListsIDArray[1] !== undefined && newFavoriteListsIDArray[1] !== null) {\n                    let ids = newFavoriteListsIDArray[0];\n                    ids = ids.replace(/\\s/g, '');\n                    let id = parseInt(ids);\n                    let urls = newFavoriteListsIDArray[1];\n                    urls = urls.replace(/\\s/g, '');\n                    let url = urls.toString();\n\n                    await this.miio.call('add_channels', { chs: [{ id: id, type: 0, url: url }] });\n                }\n            }\n        }\n\n        return Promise.resolve(true);\n    }\n\n    async retrieveDeviceData() {\n        try {\n            /* onoff */\n            if (this.miio.matches('cap:power')) {\n                const power = await this.miio.power();\n                this.updateCapabilityValue('onoff', power);\n            }\n\n            /* dim */\n            if (this.miio.matches('cap:brightness')) {\n                const brightness = await this.miio.brightness();\n                const dim = brightness / 100;\n                this.updateCapabilityValue('dim', dim);\n            }\n\n            /* light */\n            if (this.miio.matches('cap:children') && typeof this.miio.child === 'function') {\n                const lightChild = this.miio.child('light');\n                if (lightChild && typeof lightChild.matches === 'function' && typeof lightChild.color === 'function') {\n                    if (lightChild.matches('cap:colorable')) {\n                        const color = await lightChild.color();\n\n                        const colorChanged = tinycolor({ r: color.values[0], g: color.values[1], b: color.values[2] });\n                        const hsv = colorChanged.toHsv();\n                        const hue = Math.round(hsv.h) / 360;\n                        const saturation = Math.round(hsv.s);\n\n                        await this.setCapabilityValue('light_hue', hue);\n                        await this.setCapabilityValue('light_saturation', saturation);\n                    }\n                }\n            }\n\n            /* alarm */\n            const alarm = await this.miio.call('get_arming', [], { retries: 1 });\n            if (alarm[0] == 'on') {\n                this.updateCapabilityValue('homealarm_state', 'armed');\n            } else if (alarm[0] == 'off') {\n                this.updateCapabilityValue('homealarm_state', 'disarmed');\n            }\n\n            const alarm_volume = await this.miio.call('get_alarming_volume', [], { retries: 1 });\n            this.updateCapabilityValue('volume_set.alarm', alarm_volume / 100);\n\n            /* radio */\n            const radio = await this.miio.call('get_prop_fm', [], { retries: 1 });\n            await this.updateCapabilityValue('volume_set', radio.current_volume / 100);\n            if (radio.current_status == 'run') {\n                await this.updateCapabilityValue('speaker_playing', true);\n                await this.updateCapabilityValue('speaker_track', 'Station: ' + radio.current_program);\n            } else if (radio.current_status == 'pause') {\n                await this.updateCapabilityValue('speaker_playing', false);\n            }\n\n            const channels = await this.miio.call('get_channels', { start: 0 }, { retries: 1 });\n            if (Array.isArray(channels.chs)) {\n                channels.chs.forEach(async (item, i, radios) => {\n                    await this.setSettings({ [`favorite${i}ID`]: item.id + ', ' + item.url });\n                    await this.util.sleep(500);\n                    if (i == radios.length - 1) {\n                        i = radios.length;\n                        for (let j = i; j < 20; j++) {\n                            await this.setSettings({ [`favorite${j}ID`]: '' });\n                            await this.util.sleep(500);\n                        }\n                    }\n                });\n            }\n        } catch (error) {\n            this.homey.clearInterval(this.pollingInterval);\n\n            if (this.getAvailable()) {\n                this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((error) => {\n                    this.error(error);\n                });\n            }\n\n            this.homey.setTimeout(() => {\n                this.createDevice();\n            }, 60000);\n\n            this.error(error);\n        }\n    }\n}\n\nmodule.exports = GatewayDevice;\n"
  },
  {
    "path": "drivers/gateway/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Xiaomi Gateway v2 (WiFi)\",\n    \"nl\": \"Xiaomi Gateway v2 (WiFi)\",\n    \"da\": \"Xiaomi Gateway v2 (WiFi)\",\n    \"de\": \"Xiaomi Gateway v2 (WiFi)\",\n    \"es\": \"Xiaomi Gateway v2 (WiFi)\",\n    \"fr\": \"Xiaomi Gateway v2 (WiFi)\",\n    \"it\": \"Xiaomi Gateway v2 (WiFi)\",\n    \"no\": \"Xiaomi Gateway v2 (WiFi)\",\n    \"sv\": \"Xiaomi Gateway v2 (WiFi)\",\n    \"pl\": \"Xiaomi Gateway v2 (WiFi)\",\n    \"ru\": \"Xiaomi Gateway v2 (WiFi)\",\n    \"ko\": \"Xiaomi Gateway v2 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/gateway/assets/images/large.jpg\",\n    \"small\": \"drivers/gateway/assets/images/small.jpg\"\n  },\n  \"class\": \"light\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"dim\",\n    \"light_hue\",\n    \"light_saturation\",\n    \"measure_luminance\",\n    \"homealarm_state\",\n    \"speaker_playing\",\n    \"speaker_next\",\n    \"speaker_prev\",\n    \"speaker_track\",\n    \"volume_set\",\n    \"volume_set.alarm\",\n    \"button\"\n  ],\n  \"capabilitiesOptions\": {\n    \"speaker_playing\": {\n      \"title\": {\n        \"en\": \"Radio\",\n        \"nl\": \"Radio\",\n        \"da\": \"Radio\",\n        \"de\": \"Radio\",\n        \"es\": \"Radio\",\n        \"fr\": \"Radio\",\n        \"it\": \"Radio\",\n        \"no\": \"Radio\",\n        \"sv\": \"Radio\",\n        \"pl\": \"Radio\",\n        \"ru\": \"Радио\",\n        \"ko\": \"라디오\"\n      }\n    },\n    \"speaker_next\": {\n      \"title\": {\n        \"en\": \"Next Station\",\n        \"nl\": \"Volgend station\",\n        \"da\": \"Næste station\",\n        \"de\": \"Nächste Station\",\n        \"es\": \"Siguiente estación\",\n        \"fr\": \"Prochaine station\",\n        \"it\": \"Stazione successiva\",\n        \"no\": \"Neste stasjon\",\n        \"sv\": \"Nästa station\",\n        \"pl\": \"Następna stacja\",\n        \"ru\": \"Следующая станция\",\n        \"ko\": \"다음 방송\"\n      }\n    },\n    \"speaker_prev\": {\n      \"title\": {\n        \"en\": \"Previous Station\",\n        \"nl\": \"Vorig station\",\n        \"da\": \"Forrige station\",\n        \"de\": \"Vorherige Station\",\n        \"es\": \"Estación anterior\",\n        \"fr\": \"Station précédente\",\n        \"it\": \"Stazione precedente\",\n        \"no\": \"Forrige stasjon\",\n        \"sv\": \"Föregående station\",\n        \"pl\": \"Poprzednia stacja\",\n        \"ru\": \"Предыдущая станция\",\n        \"ko\": \"이전 방송\"\n      }\n    },\n    \"volume_set\": {\n      \"title\": {\n        \"en\": \"Radio volume\",\n        \"nl\": \"Radio volume\",\n        \"da\": \"Radiovolumen\",\n        \"de\": \"Radiolautstärke\",\n        \"es\": \"Volumen de la radio\",\n        \"fr\": \"Volume de la radio\",\n        \"it\": \"Volume della radio\",\n        \"no\": \"Radiovolum\",\n        \"sv\": \"Radiovolym\",\n        \"pl\": \"Głośność radia\",\n        \"ru\": \"Громкость радио\",\n        \"ko\": \"라디오 볼륨\"\n      }\n    },\n    \"volume_set.alarm\": {\n      \"title\": {\n        \"en\": \"Alarm volume\",\n        \"nl\": \"Alarm volume\",\n        \"da\": \"Alarmvolumen\",\n        \"de\": \"Alarmlautstärke\",\n        \"es\": \"Volumen de la alarma\",\n        \"fr\": \"Volume de l'alarme\",\n        \"it\": \"Volume dell'allarme\",\n        \"no\": \"Alarmvolum\",\n        \"sv\": \"Alarmvolym\",\n        \"pl\": \"Głośność alarmu\",\n        \"ru\": \"Громкость сигнала тревоги\",\n        \"ko\": \"알람 볼륨\"\n      }\n    },\n    \"button\": {\n      \"title\": {\n        \"en\": \"Join / Pair\",\n        \"nl\": \"Join / Pair\",\n        \"da\": \"Join / Par\",\n        \"de\": \"Verbinden / Koppeln\",\n        \"es\": \"Unir / Emparejar\",\n        \"fr\": \"Joindre / Apparier\",\n        \"it\": \"Unisci / Abbina\",\n        \"no\": \"Koble til / Pare\",\n        \"sv\": \"Anslut / Para\",\n        \"pl\": \"Połącz / Sparuj\",\n        \"ru\": \"Присоединиться / Спарить\",\n        \"ko\": \"연결 / 페어링\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/gateway/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass GatewayDriver extends Driver {}\n\nmodule.exports = GatewayDriver;"
  },
  {
    "path": "drivers/gateway/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Gateway Favorite Stations\",\n      \"nl\": \"Gateway favoriete stations\",\n      \"da\": \"Gateway favoritradiostationer\",\n      \"de\": \"Gateway Lieblingsstationen\",\n      \"es\": \"Estaciones favoritas de Gateway\",\n      \"fr\": \"Stations favorites de la passerelle\",\n      \"it\": \"Stazioni preferite del gateway\",\n      \"no\": \"Gateway favorittstasjoner\",\n      \"sv\": \"Gateway favoritstationer\",\n      \"pl\": \"Ulubione stacje bramy\",\n      \"ru\": \"Избранные станции шлюза\",\n      \"ko\": \"게이트웨이 즐겨찾기 방송국\"\n    },\n    \"children\": [\n      {\n        \"id\": \"favorite0ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"1 - Favorite Radio\",\n          \"nl\": \"1 - Favoriet station\",\n          \"da\": \"1 - Favoritradiostation\",\n          \"de\": \"1 - Lieblingssender\",\n          \"es\": \"1 - Radio favorita\",\n          \"fr\": \"1 - Radio préférée\",\n          \"it\": \"1 - Radio preferita\",\n          \"no\": \"1 - Favorittradiostasjon\",\n          \"sv\": \"1 - Favoritstation\",\n          \"pl\": \"1 - Ulubiona stacja\",\n          \"ru\": \"1 - Любимая радиостанция\",\n          \"ko\": \"1 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite1ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"2 - Favorite Radio\",\n          \"nl\": \"2 - Favoriet station\",\n          \"da\": \"2 - Favoritradiostation\",\n          \"de\": \"2 - Lieblingssender\",\n          \"es\": \"2 - Radio favorita\",\n          \"fr\": \"2 - Radio préférée\",\n          \"it\": \"2 - Radio preferita\",\n          \"no\": \"2 - Favorittradiostasjon\",\n          \"sv\": \"2 - Favoritstation\",\n          \"pl\": \"2 - Ulubiona stacja\",\n          \"ru\": \"2 - Любимая радиостанция\",\n          \"ko\": \"2 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite2ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"3 - Favorite Radio\",\n          \"nl\": \"3 - Favoriet station\",\n          \"da\": \"3 - Favoritradiostation\",\n          \"de\": \"3 - Lieblingssender\",\n          \"es\": \"3 - Radio favorita\",\n          \"fr\": \"3 - Radio préférée\",\n          \"it\": \"3 - Radio preferita\",\n          \"no\": \"3 - Favorittradiostasjon\",\n          \"sv\": \"3 - Favoritstation\",\n          \"pl\": \"3 - Ulubiona stacja\",\n          \"ru\": \"3 - Любимая радиостанция\",\n          \"ko\": \"3 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite3ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"4 - Favorite Radio\",\n          \"nl\": \"4 - Favoriet station\",\n          \"da\": \"4 - Favoritradiostation\",\n          \"de\": \"4 - Lieblingssender\",\n          \"es\": \"4 - Radio favorita\",\n          \"fr\": \"4 - Radio préférée\",\n          \"it\": \"4 - Radio preferita\",\n          \"no\": \"4 - Favorittradiostasjon\",\n          \"sv\": \"4 - Favoritstation\",\n          \"pl\": \"4 - Ulubiona stacja\",\n          \"ru\": \"4 - Любимая радиостанция\",\n          \"ko\": \"4 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite4ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"5 - Favorite Radio\",\n          \"nl\": \"5 - Favoriet station\",\n          \"da\": \"5 - Favoritradiostation\",\n          \"de\": \"5 - Lieblingssender\",\n          \"es\": \"5 - Radio favorita\",\n          \"fr\": \"5 - Radio préférée\",\n          \"it\": \"5 - Radio preferita\",\n          \"no\": \"5 - Favorittradiostasjon\",\n          \"sv\": \"5 - Favoritstation\",\n          \"pl\": \"5 - Ulubiona stacja\",\n          \"ru\": \"5 - Любимая радиостанция\",\n          \"ko\": \"5 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite5ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"6 - Favorite Radio\",\n          \"nl\": \"6 - Favoriet station\",\n          \"da\": \"6 - Favoritradiostation\",\n          \"de\": \"6 - Lieblingssender\",\n          \"es\": \"6 - Radio favorita\",\n          \"fr\": \"6 - Radio préférée\",\n          \"it\": \"6 - Radio preferita\",\n          \"no\": \"6 - Favorittradiostasjon\",\n          \"sv\": \"6 - Favoritstation\",\n          \"pl\": \"6 - Ulubiona stacja\",\n          \"ru\": \"6 - Любимая радиостанция\",\n          \"ko\": \"6 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite6ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"7 - Favorite Radio\",\n          \"nl\": \"7 - Favoriet station\",\n          \"da\": \"7 - Favoritradiostation\",\n          \"de\": \"7 - Lieblingssender\",\n          \"es\": \"7 - Radio favorita\",\n          \"fr\": \"7 - Radio préférée\",\n          \"it\": \"7 - Radio preferita\",\n          \"no\": \"7 - Favorittradiostasjon\",\n          \"sv\": \"7 - Favoritstation\",\n          \"pl\": \"7 - Ulubiona stacja\",\n          \"ru\": \"7 - Любимая радиостанция\",\n          \"ko\": \"7 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite7ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"8 - Favorite Radio\",\n          \"nl\": \"8 - Favoriet station\",\n          \"da\": \"8 - Favoritradiostation\",\n          \"de\": \"8 - Lieblingssender\",\n          \"es\": \"8 - Radio favorita\",\n          \"fr\": \"8 - Radio préférée\",\n          \"it\": \"8 - Radio preferita\",\n          \"no\": \"8 - Favorittradiostasjon\",\n          \"sv\": \"8 - Favoritstation\",\n          \"pl\": \"8 - Ulubiona stacja\",\n          \"ru\": \"8 - Любимая радиостанция\",\n          \"ko\": \"8 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite8ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"9 - Favorite Radio\",\n          \"nl\": \"9 - Favoriet station\",\n          \"da\": \"9 - Favoritradiostation\",\n          \"de\": \"9 - Lieblingssender\",\n          \"es\": \"9 - Radio favorita\",\n          \"fr\": \"9 - Radio préférée\",\n          \"it\": \"9 - Radio preferita\",\n          \"no\": \"9 - Favorittradiostasjon\",\n          \"sv\": \"9 - Favoritstation\",\n          \"pl\": \"9 - Ulubiona stacja\",\n          \"ru\": \"9 - Любимая радиостанция\",\n          \"ko\": \"9 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite9ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"10 - Favorite Radio\",\n          \"nl\": \"10 - Favoriet station\",\n          \"da\": \"10 - Favoritradiostation\",\n          \"de\": \"10 - Lieblingssender\",\n          \"es\": \"10 - Radio favorita\",\n          \"fr\": \"10 - Radio préférée\",\n          \"it\": \"10 - Radio preferita\",\n          \"no\": \"10 - Favorittradiostasjon\",\n          \"sv\": \"10 - Favoritstation\",\n          \"pl\": \"10 - Ulubiona stacja\",\n          \"ru\": \"10 - Любимая радиостанция\",\n          \"ko\": \"10 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite10ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"11 - Favorite Radio\",\n          \"nl\": \"11 - Favoriet station\",\n          \"da\": \"11 - Favoritradiostation\",\n          \"de\": \"11 - Lieblingssender\",\n          \"es\": \"11 - Radio favorita\",\n          \"fr\": \"11 - Radio préférée\",\n          \"it\": \"11 - Radio preferita\",\n          \"no\": \"11 - Favorittradiostasjon\",\n          \"sv\": \"11 - Favoritstation\",\n          \"pl\": \"11 - Ulubiona stacja\",\n          \"ru\": \"11 - Любимая радиостанция\",\n          \"ko\": \"11 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite11ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"12 - Favorite Radio\",\n          \"nl\": \"12 - Favoriet station\",\n          \"da\": \"12 - Favoritradiostation\",\n          \"de\": \"12 - Lieblingssender\",\n          \"es\": \"12 - Radio favorita\",\n          \"fr\": \"12 - Radio préférée\",\n          \"it\": \"12 - Radio preferita\",\n          \"no\": \"12 - Favorittradiostasjon\",\n          \"sv\": \"12 - Favoritstation\",\n          \"pl\": \"12 - Ulubiona stacja\",\n          \"ru\": \"12 - Любимая радиостанция\",\n          \"ko\": \"12 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite12ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"13 - Favorite Radio\",\n          \"nl\": \"13 - Favoriet station\",\n          \"da\": \"13 - Favoritradiostation\",\n          \"de\": \"13 - Lieblingssender\",\n          \"es\": \"13 - Radio favorita\",\n          \"fr\": \"13 - Radio préférée\",\n          \"it\": \"13 - Radio preferita\",\n          \"no\": \"13 - Favorittradiostasjon\",\n          \"sv\": \"13 - Favoritstation\",\n          \"pl\": \"13 - Ulubiona stacja\",\n          \"ru\": \"13 - Любимая радиостанция\",\n          \"ko\": \"13 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite13ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"14 - Favorite Radio\",\n          \"nl\": \"14 - Favoriet station\",\n          \"da\": \"14 - Favoritradiostation\",\n          \"de\": \"14 - Lieblingssender\",\n          \"es\": \"14 - Radio favorita\",\n          \"fr\": \"14 - Radio préférée\",\n          \"it\": \"14 - Radio preferita\",\n          \"no\": \"14 - Favorittradiostasjon\",\n          \"sv\": \"14 - Favoritstation\",\n          \"pl\": \"14 - Ulubiona stacja\",\n          \"ru\": \"14 - Любимая радиостанция\",\n          \"ko\": \"14 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite14ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"15 - Favorite Radio\",\n          \"nl\": \"15 - Favoriet station\",\n          \"da\": \"15 - Favoritradiostation\",\n          \"de\": \"15 - Lieblingssender\",\n          \"es\": \"15 - Radio favorita\",\n          \"fr\": \"15 - Radio préférée\",\n          \"it\": \"15 - Radio preferita\",\n          \"no\": \"15 - Favorittradiostasjon\",\n          \"sv\": \"15 - Favoritstation\",\n          \"pl\": \"15 - Ulubiona stacja\",\n          \"ru\": \"15 - Любимая радиостанция\",\n          \"ko\": \"15 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite15ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"16 - Favorite Radio\",\n          \"da\": \"16 - Favoritradiostation\",\n          \"de\": \"16 - Lieblingssender\",\n          \"es\": \"16 - Radio favorita\",\n          \"fr\": \"16 - Radio préférée\",\n          \"it\": \"16 - Radio preferita\",\n          \"no\": \"16 - Favorittradiostasjon\",\n          \"sv\": \"16 - Favoritstation\",\n          \"pl\": \"16 - Ulubiona stacja\",\n          \"ru\": \"16 - Любимая радиостанция\",\n          \"ko\": \"16 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite16ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"17 - Favorite Radio\",\n          \"da\": \"17 - Favoritradiostation\",\n          \"de\": \"17 - Lieblingssender\",\n          \"es\": \"17 - Radio favorita\",\n          \"fr\": \"17 - Radio préférée\",\n          \"it\": \"17 - Radio preferita\",\n          \"no\": \"17 - Favorittradiostasjon\",\n          \"sv\": \"17 - Favoritstation\",\n          \"pl\": \"17 - Ulubiona stacja\",\n          \"ru\": \"17 - Любимая радиостанция\",\n          \"ko\": \"17 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite17ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"18 - Favorite Radio\",\n          \"da\": \"18 - Favoritradiostation\",\n          \"de\": \"18 - Lieblingssender\",\n          \"es\": \"18 - Radio favorita\",\n          \"fr\": \"18 - Radio préférée\",\n          \"it\": \"18 - Radio preferita\",\n          \"no\": \"18 - Favorittradiostasjon\",\n          \"sv\": \"18 - Favoritstation\",\n          \"pl\": \"18 - Ulubiona stacja\",\n          \"ru\": \"18 - Любимая радиостанция\",\n          \"ko\": \"18 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite18ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"19 - Favorite Radio\",\n          \"da\": \"19 - Favoritradiostation\",\n          \"de\": \"19 - Lieblingssender\",\n          \"es\": \"19 - Radio favorita\",\n          \"fr\": \"19 - Radio préférée\",\n          \"it\": \"19 - Radio preferita\",\n          \"no\": \"19 - Favorittradiostasjon\",\n          \"sv\": \"19 - Favoritstation\",\n          \"pl\": \"19 - Ulubiona stacja\",\n          \"ru\": \"19 - Любимая радиостанция\",\n          \"ko\": \"19 - 즐겨찾는 라디오\"\n        }\n      },\n      {\n        \"id\": \"favorite19ID\",\n        \"type\": \"text\",\n        \"value\": \"\",\n        \"label\": {\n          \"en\": \"20 - Favorite Radio\",\n          \"da\": \"20 - Favoritradiostation\",\n          \"de\": \"20 - Lieblingssender\",\n          \"es\": \"20 - Radio favorita\",\n          \"fr\": \"20 - Radio préférée\",\n          \"it\": \"20 - Radio preferita\",\n          \"no\": \"20 - Favorittradiostasjon\",\n          \"sv\": \"20 - Favoritstation\",\n          \"pl\": \"20 - Ulubiona stacja\",\n          \"ru\": \"20 - Любимая радиостанция\",\n          \"ko\": \"20 - 즐겨찾는 라디오\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/gateway/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/gateway/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/gateway/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/heater_zhimi_heater_miot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/zhimi.heater.mc2\n// https://home.miot-spec.com/spec/zhimi.heater.za2\n// https://home.miot-spec.com/spec/leshow.heater.bs1s\n// https://home.miot-spec.com/spec/zhimi.heater.nb1\n// https://home.miot-spec.com/spec/zhimi.heater.zb1a\n\nconst mapping = {\n  \"zhimi.heater.mc2\": \"properties_mc2\",\n  \"zhimi.heater.za2\": \"properties_za2\",\n\t\"leshow.heater.bs1s\": \"properties_bs1s\",\n\t\"zhimi.heater.nb1\": \"properties_nb1\",\n  \"zhimi.heater.zb1a\": \"properties_zb1a\",\n  \"zhimi.heater.*\": \"properties_mc2\"\n};\n\nconst properties = {\n  \"properties_mc2\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"target_temperature\", siid: 2, piid: 5 }, // heater_zhimi_heater_target_temperature\n      { did: \"temperature\", siid: 4, piid: 7 }, // measure_temperature\n      { did: \"light\", siid: 7, piid: 3 }, // settings.led\n      { did: \"buzzer\", siid: 6, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 5, piid: 1 } // settings.childLock\n    ],\n    \"set_properties\": {\n      \"onoff\": { siid: 2, piid: 1 },\n      \"target_temperature\": { siid: 2, piid: 5 },\n      \"light\": {siid: 7, piid: 3 },\n      \"buzzer\": {siid: 6, piid: 1 },\n      \"child_lock\": {siid: 5, piid: 1 }\n    }\n  },\n  \"properties_za2\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 2 }, // onoff\n      { did: \"target_temperature\", siid: 2, piid: 6 }, // heater_zhimi_heater_target_temperature\n      { did: \"temperature\", siid: 5, piid: 8 }, // measure_temperature\n      { did: \"humidity\", siid: 5, piid: 7 }, // measure_humidity\n      { did: \"light\", siid: 6, piid: 1 }, // settings.led\n      { did: \"buzzer\", siid: 3, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 7, piid: 1 } // settings.childLock\n    ],\n    \"set_properties\": {\n      \"onoff\": { siid: 2, piid: 1 },\n      \"target_temperature\": { siid: 2, piid: 6 },\n      \"light\": {siid: 6, piid: 3 },\n      \"buzzer\": {siid: 3, piid: 1 },\n      \"child_lock\": {siid: 7, piid: 1 }\n    }\n  },\n  \"properties_bs1s\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"target_temperature\", siid: 2, piid: 3 }, // heater_zhimi_heater_target_temperature\n      { did: \"temperature\", siid: 4, piid: 7 }, // measure_temperature\n      { did: \"light\", siid: 7, piid: 1 }, // settings.led\n      { did: \"buzzer\", siid: 5, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 6, piid: 1 } // settings.childLock\n    ],\n    \"set_properties\": {\n      \"onoff\": { siid: 2, piid: 1 },\n      \"target_temperature\": { siid: 2, piid: 3 },\n      \"light\": {siid: 7, piid: 7 },\n      \"buzzer\": {siid: 5, piid: 1 },\n      \"child_lock\": {siid: 6, piid: 1 }\n    }\n  },\n  \"properties_nb1\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 2 }, // onoff\n      { did: \"target_temperature\", siid: 2, piid: 5 }, // heater_zhimi_heater_target_temperature\n      { did: \"temperature\", siid: 9, piid: 7 }, // measure_temperature\n      { did: \"light\", siid: 6, piid: 1 }, // settings.led\n      { did: \"buzzer\", siid: 3, piid: 1 }, // settings.buzzer\n      { did: \"child_lock\", siid: 7, piid: 1 }, // settings.childLock\n      { did: \"heater_zhimi_heatlevel\", siid: 2, piid: 3 }, // heater_zhimi_heatlevel\n      { did: \"heater_zhimi_oscillation\", siid: 2, piid: 4 } // heater_zhimi_oscillation\n    ],\n    \"set_properties\": {\n      \"onoff\": { siid: 2, piid: 2 },\n      \"target_temperature\": { siid: 2, piid: 5 },\n      \"light\": {siid: 6, piid: 1 },\n      \"buzzer\": {siid: 3, piid: 1 },\n      \"child_lock\": {siid: 7, piid: 1 },\n      \"heater_zhimi_heatlevel\": { siid: 2, piid: 3 },\n      \"heater_zhimi_oscillation\": { siid: 2, piid: 4 }\n    }\n  },\n  \"properties_zb1a\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 2 }, // onoff\n      { did: \"target_temperature\", siid: 2, piid: 6 }, // heater_zhimi_heater_target_temperature\n      { did: \"buzzer\", siid: 3, piid: 1 }, // settings.buzzer\n      { did: \"temperature\", siid: 5, piid: 8 }, // measure_temperature\n      { did: \"light\", siid: 6, piid: 1 }, // settings.led\n      { did: \"child_lock\", siid: 7, piid: 1 }, // settings.childLock\n    ],\n    \"set_properties\": {\n      \"onoff\": { siid: 2, piid: 2 },\n      \"target_temperature\": { siid: 2, piid: 6 },\n      \"buzzer\": {siid: 3, piid: 1 },\n      \"light\": {siid: 6, piid: 1 },\n      \"child_lock\": {siid: 7, piid: 1 }\n    }\n  }\n}\n\nclass ZhimiHeaterMiotDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // ADD DEVICES DEPENDANT CAPABILITIES\n      if (this.getStoreValue('model') === 'zhimi.heater.za2') {\n        if (!this.hasCapability('measure_humidity')) {\n          this.addCapability('measure_humidity');\n        }\n      }\n\n      if (this.getStoreValue('model') === 'zhimi.heater.nb1') {\n        if (!this.hasCapability('heater_zhimi_heatlevel')) {\n          this.addCapability('heater_zhimi_heatlevel');\n        }\n        if (!this.hasCapability('heater_zhimi_oscillation')) {\n          this.addCapability('heater_zhimi_oscillation');\n        }\n      }\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['zhimi.heater.*']];\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ did: \"onoff\", siid: this.deviceProperties.set_properties.onoff.siid, piid: this.deviceProperties.set_properties.onoff.piid, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('heater_zhimi_heater_target_temperature', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ did: \"target_temperature\", siid: this.deviceProperties.set_properties.target_temperature.siid, piid: this.deviceProperties.set_properties.target_temperature.piid, value: Number(value) }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('heater_zhimi_heatlevel', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ did: \"heater_zhimi_heatlevel\", siid: this.deviceProperties.set_properties.heater_zhimi_heatlevel.siid, piid: this.deviceProperties.set_properties.heater_zhimi_heatlevel.piid, value: Number(value) }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('heater_zhimi_oscillation', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ did: \"heater_zhimi_oscillation\", siid: this.deviceProperties.set_properties.heater_zhimi_oscillation.siid, piid: this.deviceProperties.set_properties.heater_zhimi_oscillation.piid, value: value ? 1 : 0 }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      await this.miio.call(\"set_properties\", [{ did: \"light\", siid: this.deviceProperties.set_properties.light.siid, piid: this.deviceProperties.set_properties.light.piid, value: newSettings.led === 0 ? false : true }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"buzzer\")) {\n      await this.miio.call(\"set_properties\", [{ did: \"buzzer\", siid: this.deviceProperties.set_properties.buzzer.siid, piid: this.deviceProperties.set_properties.buzzer.piid, value: newSettings.buzzer }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"childLock\")) {\n      await this.miio.call(\"set_properties\", [{ did: \"child_lock\", siid: this.deviceProperties.set_properties.child_lock.siid, piid: this.deviceProperties.set_properties.child_lock.piid, value: newSettings.childLock }], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const onoff = result.find(obj => obj.did === 'power');\n      const target_temperature = result.find(obj => obj.did === 'target_temperature');\n      const measure_temperature = result.find(obj => obj.did === 'temperature');\n      \n      const led = result.find(obj => obj.did === 'light');\n      const buzzer = result.find(obj => obj.did === 'buzzer');\n      const child_lock = result.find(obj => obj.did === 'child_lock');\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"onoff\", onoff.value);\n      await this.updateCapabilityValue(\"heater_zhimi_heater_target_temperature\", target_temperature.value);\n      await this.updateCapabilityValue(\"measure_temperature\", measure_temperature.value);\n      \n      if (this.hasCapability('measure_humidity')) {\n        const measure_humidity = result.find(obj => obj.did === 'humidity');\n        await this.updateCapabilityValue(\"measure_humidity\", measure_humidity.value);\n      }\n\n      if (this.hasCapability('heater_zhimi_heatlevel')) {\n        const heater_zhimi_heatlevel = result.find(obj => obj.did === 'heater_zhimi_heatlevel');\n        await this.updateCapabilityValue(\"heater_zhimi_heatlevel\", heater_zhimi_heatlevel.value.toString());\n      }\n\n      if (this.hasCapability('heater_zhimi_oscillation')) {\n        const heater_zhimi_oscillation = result.find(obj => obj.did === 'heater_zhimi_oscillation');\n        await this.updateCapabilityValue(\"heater_zhimi_oscillation\", heater_zhimi_oscillation.value === 0 ? false : true);\n      }\n      \n      /* settings */\n      await this.updateSettingValue(\"led\", !!led.value);\n      await this.updateSettingValue(\"buzzer\", buzzer.value);\n      await this.updateSettingValue(\"childLock\", child_lock.value);\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = ZhimiHeaterMiotDevice;"
  },
  {
    "path": "drivers/heater_zhimi_heater_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Smart Space/Fan Heater MIoT (WiFi)\",\n    \"nl\": \"Smart Space/Fan Heater MIoT (WiFi)\",\n    \"da\": \"Smart Space/Fan Heater MIoT (WiFi)\",\n    \"de\": \"Smart Space/Fan Heater MIoT (WiFi)\",\n    \"es\": \"Espacio inteligente / Calefactor de ventilador MIoT (WiFi)\",\n    \"fr\": \"Chauffage de ventilateur/espace intelligent MIoT (WiFi)\",\n    \"it\": \"Riscaldatore a ventola / Spazio Intelligente MIoT (WiFi)\",\n    \"no\": \"Smart Space/Viftevarmer MIoT (WiFi)\",\n    \"sv\": \"Smart Space/Värmefläkt MIoT (WiFi)\",\n    \"pl\": \"Inteligentna przestrzeń / Grzejnik wentylator MIoT (WiFi)\",\n    \"ru\": \"Умное пространство / Обогреватель-вентилятор MIoT (WiFi)\",\n    \"ko\": \"스마트 공간 / 팬 히터 MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/heater_zhimi_heater_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/heater_zhimi_heater_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"heater\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"heater_zhimi_heater_target_temperature\",\n    \"measure_temperature\"\n  ]\n}"
  },
  {
    "path": "drivers/heater_zhimi_heater_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass ZhimiHeaterMiotDriver extends Driver {}\n\nmodule.exports =ZhimiHeaterMiotDriver;"
  },
  {
    "path": "drivers/heater_zhimi_heater_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"LED\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summer\",\n          \"de\": \"Summer\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Sonnerie\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Sommer\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Brzęczyk\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"버저\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnelås\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo infantil\",\n          \"fr\": \"Sécurité enfant\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barnelås\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada dzieci\",\n          \"ru\": \"Детская блокировка\",\n          \"ko\": \"어린이 잠금\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/heater_zhimi_heater_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/heater_zhimi_heater_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/heater_zhimi_heater_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_jsq/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/deerma.humidifier.mjjsq // Mijia Smart Sterilization Humidifier MJJSQ\n// https://home.miot-spec.com/spec/deerma.humidifier.jsq // Mijia Smart Sterilization Humidifier JSQ\n// https://home.miot-spec.com/spec/deerma.humidifier.jsq1 // Mijia Smart Sterilization Humidifier JSQ1\n\nconst modes = {\n  1: \"Low\",\n  2: \"Medium\",\n  3: \"High\",\n  4: \"Humidity\"\n};\n\nclass HumidifierDeermaJSQDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"Set_OnOff\", [+value]);\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('target_humidity', async ( value ) => {\n        try {\n          if (this.miio) {\n            const humidity = value * 100;\n            return await this.miio.call(\"Set_HumiValue\", [humidity]);\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('humidifier_deerma_jsq_mode', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"Set_HumidifierGears\", [Number(value)]);\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      const led = await this.miio.call(\"SetLedState\", [newSettings.led ? 1 : 0]);\n    }\n\n    if (changedKeys.includes(\"buzzer\")) {\n      const buzzer = await this.miio.call(\"SetTipSound_Status\", [newSettings.buzzer ? 1 : 0]);\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_prop\", [\"Humidifier_Gear\", \"Humidity_Value\", \"HumiSet_Value\", \"Led_State\", \"OnOff_State\", \"TemperatureValue\", \"TipSound_State\", \"waterstatus\", \"watertankstatus\"], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"measure_humidity\", parseInt(result[1]));\n      await this.updateCapabilityValue(\"target_humidity\", parseInt(result[2]) / 100);\n      await this.updateCapabilityValue(\"onoff\", result[4] === 1 ? true : false);\n      await this.updateCapabilityValue(\"measure_temperature\", parseInt(result[5]));\n      await this.updateCapabilityValue(\"alarm_water\", result[7] === 0 ? true : false);\n      await this.updateCapabilityValue(\"alarm_tank_empty\", result[8] === 0 ? false : true);\n      \n      /* settings */\n      await this.updateSettingValue(\"led\", result[3] === 1 ? true : false);\n      await this.updateSettingValue(\"buzzer\", result[6] === 1 ? true : false);\n\n      /* mode capability */\n      if (this.getCapabilityValue('humidifier_deerma_jsq_mode') !== result[0].toString()) {\n        const previous_mode = this.getCapabilityValue('humidifier_deerma_jsq_mode');\n        await this.setCapabilityValue('humidifier_deerma_jsq_mode', result[0].toString());\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, {\"new_mode\": modes[result[0]], \"previous_mode\": modes[+previous_mode] }).catch(error => { this.error(error) });\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = HumidifierDeermaJSQDevice;\n"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_jsq/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mijia Smart Sterilization Humidifier JSQ / JSQ1 / MJJSQ (WiFi)\",\n    \"nl\": \"Mijia Smart Sterilization Humidifier JSQ / JSQ1 / MJJSQ (WiFi)\",\n    \"da\": \"Mijia Smart Sterilization Luftfugter JSQ / JSQ1 / MJJSQ (WiFi)\",\n    \"de\": \"Mijia Smart Sterilisation Luftbefeuchter JSQ / JSQ1 / MJJSQ (WiFi)\",\n    \"es\": \"Humidificador de Esterilización Inteligente Mijia JSQ / JSQ1 / MJJSQ (WiFi)\",\n    \"fr\": \"Humidificateur de Stérilisation Intelligent Mijia JSQ / JSQ1 / MJJSQ (WiFi)\",\n    \"it\": \"Umidificatore di Sterilizzazione Intelligente Mijia JSQ / JSQ1 / MJJSQ (WiFi)\",\n    \"no\": \"Mijia Smart Steriliseringsfukter JSQ / JSQ1 / MJJSQ (WiFi)\",\n    \"sv\": \"Mijia Smart Sterilisering Luftfuktare JSQ / JSQ1 / MJJSQ (WiFi)\",\n    \"pl\": \"Inteligentny Sterylizujący Nawilżacz Mijia JSQ / JSQ1 / MJJSQ (WiFi)\",\n    \"ru\": \"Умный стерилизующий увлажнитель Mijia JSQ / JSQ1 / MJJSQ (WiFi)\",\n    \"ko\": \"미지아 스마트 살균 가습기 JSQ / JSQ1 / MJJSQ (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/humidifier_deerma_humidifier_jsq/assets/images/large.jpg\",\n    \"small\": \"drivers/humidifier_deerma_humidifier_jsq/assets/images/small.jpg\"\n  },\n  \"class\": \"humidifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"target_humidity\",\n    \"humidifier_deerma_jsq_mode\",\n    \"measure_temperature\",\n    \"measure_humidity\",\n    \"alarm_water\",\n    \"alarm_tank_empty\"\n  ],\n  \"capabilitiesOptions\": {\n    \"target_humidity\": {\n      \"min\": 0.4,\n      \"max\": 0.7\n    },\n    \"alarm_water\": {\n      \"title\": {\n        \"en\": \"Waterlevel\",\n        \"nl\": \"Waterniveau\",\n        \"da\": \"Vandniveau\",\n        \"de\": \"Wasserstand\",\n        \"es\": \"Nivel de agua\",\n        \"fr\": \"Niveau d'eau\",\n        \"it\": \"Livello dell'acqua\",\n        \"no\": \"Vannivå\",\n        \"sv\": \"Vattennivå\",\n        \"pl\": \"Poziom wody\",\n        \"ru\": \"Уровень воды\",\n        \"ko\": \"수위\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_jsq/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass HumidifierDeermaJSQDriver extends Driver {}\n\nmodule.exports = HumidifierDeermaJSQDriver;"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_jsq/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"Светодиод\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summer\",\n          \"de\": \"Summer\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Buzzer\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Summer\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Brzęczyk\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"부저\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_jsq/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_jsq/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_jsq/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_miot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/deerma.humidifier.jsqs \n// https://home.miot-spec.com/spec/deerma.humidifier.jsq4\n// https://home.miot-spec.com/spec/deerma.humidifier.jsq5\n// https://home.miot-spec.com/spec/deerma.humidifier.jsq2w\n\nconst mapping = {\n  \"deerma.humidifier.jsqs\": \"mapping_default\",\n  \"deerma.humidifier.jsq4\": \"mapping_default\",\n  \"deerma.humidifier.jsq5\": \"mapping_default\",\n  \"deerma.humidifier.jsq2w\": \"mapping_jsq2w\",  // custom mapping for jsq2w\n  \"deerma.humidifier.*\": \"mapping_default\",\n};\n\nconst properties = {\n  \"mapping_default\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"watertank_shortage_fault\", siid: 7, piid: 1 }, // alarm.water\n      { did: \"mode\", siid: 2, piid: 5 }, // humidifier_deerma_jsq_mode\n      { did: \"target_humidity\", siid: 2, piid: 6 }, // target_humidity [30, 40, 50, 60, 70, 80]\n      { did: \"relative_humidity\", siid: 3, piid: 1 }, // measure_humidity\n      { did: \"temperature\", siid: 3, piid: 7 }, // measure_temperature\n      { did: \"buzzer\", siid: 5, piid: 1 }, // settings.buzzer\n      { did: \"led_light\", siid: 6, piid: 1 }, // settings.led\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"mode\": { siid: 2, piid: 5 },\n      \"target_humidity\": { siid: 2, piid: 6 },\n      \"buzzer\": { siid: 5, piid: 1 },\n      \"light\": { siid: 6, piid: 1 }\n    }\n  },\n\n  \"mapping_jsq2w\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 },\n      { did: \"watertank_shortage_fault\", siid: 7, piid: 2 }, // custom: corrected piid for jsq2w\n      { did: \"mode\", siid: 2, piid: 5 },\n      { did: \"target_humidity\", siid: 2, piid: 6 },\n      { did: \"relative_humidity\", siid: 3, piid: 1 },\n      { did: \"temperature\", siid: 3, piid: 7 },\n      { did: \"buzzer\", siid: 5, piid: 1 },\n      { did: \"led_light\", siid: 6, piid: 1 },\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"mode\": { siid: 2, piid: 5 },\n      \"target_humidity\": { siid: 2, piid: 6 },\n      \"buzzer\": { siid: 5, piid: 1 },\n      \"light\": { siid: 6, piid: 1 }\n    }\n  }\n};\n\nconst modes = {\n  1: \"Level 1\",\n  2: \"Level 2\",\n  3: \"Level 3\",\n  4: \"Humidity\"\n};\n\nclass HumidifierDeermaMiotDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['deerma.humidifier.*']];\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.power.siid, piid: this.deviceProperties.set_properties.power.piid, value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('target_humidity', async ( value ) => {\n        try {\n          if (this.miio) {\n            let humidity = value * 100;\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.target_humidity.siid, piid: this.deviceProperties.set_properties.target_humidity.piid, value: humidity }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('humidifier_deerma_jsq_mode', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.mode.siid, piid: this.deviceProperties.set_properties.mode.piid, value: +value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      const led = await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.light.siid, piid: this.deviceProperties.set_properties.light.piid, value: newSettings.led }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"buzzer\")) {\n      const buzzer = await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.buzzer.siid, piid: this.deviceProperties.set_properties.buzzer.piid, value: newSettings.buzzer }], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const onoff = result.find(obj => obj.did === 'power');\n      const alarm_tank_empty = result.find(obj => obj.did === 'watertank_shortage_fault');\n      const target_humidity = result.find(obj => obj.did === 'target_humidity');\n      const measure_humidity = result.find(obj => obj.did === 'relative_humidity');\n      const measure_temperature = result.find(obj => obj.did === 'temperature');\n      const buzzer = result.find(obj => obj.did === 'buzzer');\n      const led = result.find(obj => obj.did === 'led_light');\n\n      /* capabilities */\n      if (onoff && onoff.value !== undefined) {\n        await this.updateCapabilityValue(\"onoff\", onoff.value);\n      }\n\n      if (alarm_tank_empty && alarm_tank_empty.value !== undefined) {\n        await this.updateCapabilityValue(\"alarm_tank_empty\", alarm_tank_empty.value);\n      }\n\n      if (target_humidity && typeof target_humidity.value === \"number\") {\n        await this.updateCapabilityValue(\"target_humidity\", target_humidity.value / 100);\n      }\n\n      if (measure_humidity && measure_humidity.value !== undefined) {\n        await this.updateCapabilityValue(\"measure_humidity\", measure_humidity.value);\n      }\n\n      if (measure_temperature && measure_temperature.value !== undefined) {\n        await this.updateCapabilityValue(\"measure_temperature\", measure_temperature.value);\n      }\n\n      /* settings */\n      if (led && led.value !== undefined) {\n        await this.updateSettingValue(\"led\", led.value);\n      }\n\n      if (buzzer && buzzer.value !== undefined) {\n        await this.updateSettingValue(\"buzzer\", buzzer.value);\n      }\n\n      /* mode capability */\n      const mode = result.find(obj => obj.did === \"mode\");\n      if (mode && mode.value !== undefined && mode.value !== null) {\n        const newMode = mode.value.toString();\n        const previousMode = this.getCapabilityValue(\"humidifier_deerma_jsq_mode\");\n\n        if (previousMode !== newMode) {\n          await this.setCapabilityValue(\"humidifier_deerma_jsq_mode\", newMode);\n\n          const newModeLabel = modes[mode.value] ?? newMode;\n          const previousModeLabel = (previousMode !== undefined && previousMode !== null)\n            ? (modes[Number(previousMode)] ?? previousMode)\n            : undefined;\n\n          await this.homey.flow.getDeviceTriggerCard(\"triggerModeChanged\")\n            .trigger(this, { \"new_mode\": newModeLabel, \"previous_mode\": previousModeLabel })\n            .catch(error => { this.error(error); });\n        }\n      }\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = HumidifierDeermaMiotDevice;\n"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Smart Antibacterial Humidifier MIoT (WiFi)\",\n    \"nl\": \"Mi Smart Antibacterial Humidifier MIoT (WiFi)\",\n    \"da\": \"Mi Smart Antibacterial Humidifier MIoT (WiFi)\",\n    \"de\": \"Mi Smart Antibacterial Humidifier MIoT (WiFi)\",\n    \"es\": \"Mi Humidificador Antibacteriano Inteligente MIoT (WiFi)\",\n    \"fr\": \"Humidificateur Antibactérien Intelligent MIoT (WiFi)\",\n    \"it\": \"Umidificatore Antibatterico Intelligente MIoT (WiFi)\",\n    \"no\": \"Mi Smart Antibakterielle Luftfukter MIoT (WiFi)\",\n    \"sv\": \"Mi Smart Antibakteriell Luftrenare MIoT (WiFi)\",\n    \"pl\": \"Inteligentny Nawilżacz Antybakteryjny MIoT (WiFi)\",\n    \"ru\": \"Умный Антибактериальный Увлажнитель MIoT (WiFi)\",\n    \"ko\": \"Mi 스마트 항균 가습기 MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/humidifier_deerma_humidifier_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/humidifier_deerma_humidifier_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"humidifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"target_humidity\",\n    \"humidifier_deerma_jsq_mode\",\n    \"measure_temperature\",\n    \"measure_humidity\",\n    \"alarm_tank_empty\"\n  ],\n  \"capabilitiesOptions\": {\n    \"target_humidity\": {\n      \"min\": 0.4,\n      \"max\": 0.8\n    }\n  }\n}"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass HumidifierDeermaMiotDriver extends Driver {}\n\nmodule.exports = HumidifierDeermaMiotDriver;"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración del usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"LED\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summerton\",\n          \"de\": \"Sommer\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Vibreur\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Summerton\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Buzer\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"부저\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/humidifier_deerma_humidifier_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/humidifier_leshow_humidifier_jsq1/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nconst MODEL_MAPPING = {\n  'leshow.humidifier.jsq1': 'leshow_jsq1',\n  'xiaomi.humidifier.3lite': 'xiaomi_3lite',\n};\n\nconst FALLBACK_MODEL_KEY = 'leshow_jsq1';\n\nconst MODE_LABELS = {\n  0: 'Constant Humidity',\n  1: 'Sleep',\n  2: 'Strong',\n};\n\nconst WATER_STATE_BY_FAULT = {\n  0: 'normal',\n  5: 'empty',\n};\n\nconst DEFAULT_WATER_STATE = 'normal';\n\nconst properties = {\n  leshow_jsq1: {\n    get_properties: [\n      { did: 'power', siid: 2, piid: 1 }, // Switch Status\n      { did: 'fault', siid: 2, piid: 2 }, // Device Fault\n      { did: 'mode', siid: 2, piid: 3 }, // Mode\n      { did: 'target_humidity', siid: 2, piid: 6 }, // Target humidity\n      { did: 'relative_humidity', siid: 3, piid: 1 }, // Measured humidity\n      { did: 'filter_life_level', siid: 8, piid: 1 }, // Filter life level\n      { did: 'screen_brightness', siid: 8, piid: 6 }, // LED / display brightness\n    ],\n    set_properties: {\n      power: { siid: 2, piid: 1 },\n      mode: { siid: 2, piid: 3 },\n      target_humidity: { siid: 2, piid: 6 },\n      screen_brightness: { siid: 8, piid: 6 },\n    },\n  },\n  xiaomi_3lite: {\n    get_properties: [\n      { did: 'power', siid: 2, piid: 1 }, // Switch Status\n      { did: 'fault', siid: 2, piid: 2 }, // Device Fault\n      { did: 'mode', siid: 2, piid: 3 }, // Mode\n      { did: 'target_humidity', siid: 2, piid: 5 }, // Target humidity\n      { did: 'relative_humidity', siid: 3, piid: 1 }, // Measured humidity\n      { did: 'filter_life_level', siid: 4, piid: 1 }, // Filter life level\n      { did: 'screen_brightness', siid: 6, piid: 2 }, // LED / display brightness\n    ],\n    set_properties: {\n      power: { siid: 2, piid: 1 },\n      mode: { siid: 2, piid: 3 },\n      target_humidity: { siid: 2, piid: 5 },\n      screen_brightness: { siid: 6, piid: 2 },\n    },\n  },\n};\n\nclass MiHumidifierLeshowJSQ1Device extends Device {\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({ homey: this.homey });\n\n      this.deviceProperties = this.resolveDeviceProperties();\n\n      this.bootSequence();\n\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      if (this.hasCapability('measure_waterlevel')) {\n        await this.removeCapability('measure_waterlevel').catch((error) => {\n          this.error(`Failed to remove capability measure_waterlevel: ${error.message ?? error}`);\n        });\n      }\n\n      const optionalCapabilities = ['measure_filter_life', 'humidifier_water_level_state'];\n      for (const capability of optionalCapabilities) {\n        if (!this.hasCapability(capability)) {\n          await this.addCapability(capability).catch((error) => {\n            this.error(`Failed to add capability ${capability}: ${error.message ?? error}`);\n          });\n        }\n      }\n\n      this.registerCapabilityListener('onoff', (value) => this.handleSetProperty('power', value));\n      this.registerCapabilityListener('target_humidity', (value) => this.handleTargetHumidity(value));\n      this.registerCapabilityListener('humidifier_leshow_jsq1_mode', (value) =>\n        this.handleSetProperty('mode', Number(value))\n      );\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  getModelIdentifier() {\n    if (typeof this.getStoreValue === 'function') {\n      const storedModel = this.getStoreValue('model');\n      if (storedModel) return storedModel;\n    }\n    if (typeof this.getData === 'function') {\n      const data = this.getData();\n      if (data && data.model) return data.model;\n    }\n    return 'unknown';\n  }\n\n  resolveDeviceProperties() {\n    const modelKey = MODEL_MAPPING[this.getModelIdentifier()] || FALLBACK_MODEL_KEY;\n    const definition = properties[modelKey] || properties[FALLBACK_MODEL_KEY];\n    if (!definition) {\n      throw new Error(`No property definition found for model key ${modelKey}`);\n    }\n    return definition;\n  }\n\n  async handleSetProperty(propertyKey, value) {\n    try {\n      const definition = this.deviceProperties?.set_properties?.[propertyKey];\n      if (!definition) {\n        return Promise.reject(new Error(`Property ${propertyKey} not supported by current model`));\n      }\n      if (!this.miio) {\n        this.setUnavailable(this.homey.__('unreachable')).catch((err) => this.error(err));\n        this.createDevice();\n        return Promise.reject('Device unreachable, please try again ...');\n      }\n      return await this.miio.call(\n        'set_properties',\n        [{ siid: definition.siid, piid: definition.piid, value }],\n        { retries: 1 }\n      );\n    } catch (error) {\n      this.error(error);\n      return Promise.reject(error);\n    }\n  }\n\n  async handleTargetHumidity(value) {\n    try {\n      const definition = this.deviceProperties?.set_properties?.target_humidity;\n      if (!definition) {\n        return Promise.reject(new Error('Target humidity not supported by current model'));\n      }\n      if (!this.miio) {\n        this.setUnavailable(this.homey.__('unreachable')).catch((err) => this.error(err));\n        this.createDevice();\n        return Promise.reject('Device unreachable, please try again ...');\n      }\n      const humidity = Math.round(Number(value) * 100);\n      return await this.miio.call(\n        'set_properties',\n        [{ siid: definition.siid, piid: definition.piid, value: humidity }],\n        { retries: 1 }\n      );\n    } catch (error) {\n      this.error(error);\n      return Promise.reject(error);\n    }\n  }\n\n  async onSettings({ newSettings, changedKeys }) {\n    if (changedKeys.includes('address') || changedKeys.includes('token') || changedKeys.includes('polling')) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes('led')) {\n      const definition = this.deviceProperties?.set_properties?.screen_brightness;\n      if (definition && this.miio) {\n        await this.miio.call(\n          'set_properties',\n          [{ siid: definition.siid, piid: definition.piid, value: newSettings.led ? 1 : 0 }],\n          { retries: 1 }\n        );\n      }\n    }\n\n    return true;\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call('get_properties', this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) {\n        await this.setAvailable();\n      }\n\n      const indexed = this.indexResults(result);\n\n      const powerEntry = indexed.power;\n      if (this.hasUsableValue(powerEntry)) {\n        await this.updateCapabilityValue('onoff', !!powerEntry.value);\n      }\n\n      const targetEntry = indexed.target_humidity;\n      if (this.hasUsableValue(targetEntry) && typeof targetEntry.value === 'number') {\n        await this.updateCapabilityValue('target_humidity', targetEntry.value / 100);\n      }\n\n      const humidityEntry = indexed.relative_humidity;\n      if (this.hasUsableValue(humidityEntry) && typeof humidityEntry.value === 'number') {\n        await this.updateCapabilityValue('measure_humidity', humidityEntry.value);\n      }\n\n      const filterEntry = indexed.filter_life_level;\n      if (this.hasUsableValue(filterEntry) && typeof filterEntry.value === 'number' && this.hasCapability('measure_filter_life')) {\n        const clamped = Math.max(0, Math.min(100, Number(filterEntry.value)));\n        await this.updateCapabilityValue('measure_filter_life', clamped);\n      }\n\n      const faultEntry = indexed.fault;\n      if (\n        this.hasUsableValue(faultEntry) &&\n        typeof faultEntry.value === 'number' &&\n        this.hasCapability('humidifier_water_level_state')\n      ) {\n        const faultCode = Number(faultEntry.value);\n        const waterState = Object.prototype.hasOwnProperty.call(WATER_STATE_BY_FAULT, faultCode)\n          ? WATER_STATE_BY_FAULT[faultCode]\n          : DEFAULT_WATER_STATE;\n        await this.updateCapabilityValue('humidifier_water_level_state', waterState);\n      }\n\n      const ledEntry = indexed.screen_brightness;\n      if (this.hasUsableValue(ledEntry)) {\n        await this.updateSettingValue('led', Boolean(ledEntry.value));\n      }\n\n      const modeEntry = indexed.mode;\n      if (this.hasUsableValue(modeEntry) && typeof modeEntry.value === 'number') {\n        await this.handleModeEvent(modeEntry.value);\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((err) => {\n          this.error(err);\n        });\n      }\n\n      this.homey.setTimeout(() => {\n        this.createDevice();\n      }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n  indexResults(result) {\n    const map = {};\n    if (!Array.isArray(result)) return map;\n    for (const entry of result) {\n      if (!entry) continue;\n      const key = entry.did || `${entry.siid}/${entry.piid}`;\n      map[key] = entry;\n    }\n    return map;\n  }\n\n  hasUsableValue(entry) {\n    if (!entry) return false;\n    if (typeof entry.code === 'number' && entry.code !== 0) return false;\n    return entry.value !== undefined && entry.value !== null && entry.value !== 'undefined' && entry.value !== 'null';\n  }\n\n  async handleModeEvent(mode) {\n    try {\n      const modeValue = mode.toString();\n      if (this.getCapabilityValue('humidifier_leshow_jsq1_mode') !== modeValue) {\n        const previous = this.getCapabilityValue('humidifier_leshow_jsq1_mode');\n        await this.setCapabilityValue('humidifier_leshow_jsq1_mode', modeValue);\n        const newLabel = MODE_LABELS[mode] || modeValue;\n        const previousLabel =\n          previous !== undefined && previous !== null ? MODE_LABELS[Number(previous)] || previous : undefined;\n        await this.homey.flow\n          .getDeviceTriggerCard('triggerModeChanged')\n          .trigger(this, { new_mode: newLabel, previous_mode: previousLabel })\n          .catch((error) => {\n            this.error(error);\n          });\n      }\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = MiHumidifierLeshowJSQ1Device;\n"
  },
  {
    "path": "drivers/humidifier_leshow_humidifier_jsq1/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Xiaomi Humidifier Pro (WiFi)\",\n    \"nl\": \"Xiaomi Humidifier Pro (WiFi)\",\n    \"da\": \"Xiaomi Luftfugter Pro (WiFi)\",\n    \"de\": \"Xiaomi Befeuchter Pro (WiFi)\",\n    \"es\": \"Xiaomi Humidificador Pro (WiFi)\",\n    \"fr\": \"Xiaomi Humidificateur Pro (WiFi)\",\n    \"it\": \"Xiaomi Umidificatore Pro (WiFi)\",\n    \"no\": \"Xiaomi Luftfukter Pro (WiFi)\",\n    \"sv\": \"Xiaomi Luftfuktare Pro (WiFi)\",\n    \"pl\": \"Xiaomi Nawilżacz Pro (WiFi)\",\n    \"ru\": \"Xiaomi Увлажнитель Pro (WiFi)\",\n    \"ko\": \"샤오미 가습기 프로 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/humidifier_leshow_humidifier_jsq1/assets/images/large.jpg\",\n    \"small\": \"drivers/humidifier_leshow_humidifier_jsq1/assets/images/small.jpg\"\n  },\n  \"class\": \"humidifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"target_humidity\",\n    \"humidifier_leshow_jsq1_mode\",\n    \"measure_humidity\",\n    \"measure_filter_life\",\n    \"humidifier_water_level_state\"\n  ],\n  \"capabilitiesOptions\": {\n    \"target_humidity\": {\n      \"min\": 0.3,\n      \"max\": 0.8\n    }\n  }\n}\n"
  },
  {
    "path": "drivers/humidifier_leshow_humidifier_jsq1/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiHumidifierLeshowJSQ1Driver extends Driver {}\n\nmodule.exports = MiHumidifierLeshowJSQ1Driver;"
  },
  {
    "path": "drivers/humidifier_leshow_humidifier_jsq1/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de Usuario\",\n      \"fr\": \"Paramètres Utilisateur\",\n      \"it\": \"Impostazioni Utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia Użytkownika\",\n      \"ru\": \"Настройки Пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"LED\",\n          \"ko\": \"LED\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del Dispositivo\",\n      \"fr\": \"Paramètres de l'Appareil\",\n      \"it\": \"Impostazioni del Dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia Urządzenia\",\n      \"ru\": \"Настройки Устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/humidifier_leshow_humidifier_jsq1/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/humidifier_leshow_humidifier_jsq1/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/humidifier_leshow_humidifier_jsq1/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/humidifier_xiaomi_humidifier/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/xiaomi.humidifier.airmx\n// https://home.miot-spec.com/spec/xiaomi.humidifier.600ek\n\nconst MODEL_MAPPING = {\n  'xiaomi.humidifier.airmx': 'mapping_default',\n  'xiaomi.humidifier.600ek': 'mapping_600ek',\n  'xiaomi.humidifier.*': 'mapping_default',\n};\n\nconst properties = {\n  mapping_default: {\n    get_properties: [\n      { did: 'onoff', siid: 2, piid: 1 }, // onoff\n      { did: 'error', siid: 2, piid: 2 }, // settings.error\n      { did: 'mode', siid: 2, piid: 3 }, // humidifier_xiaomi_mode\n      { did: 'target_humidity', siid: 2, piid: 6 }, // target_humidity [40, 50, 60, 70]\n      { did: 'water_level', siid: 2, piid: 7 }, // measure_waterlevel\n      { did: 'dry', siid: 2, piid: 12 }, // onoff.dry\n      { did: 'humidity', siid: 3, piid: 1 }, // measure_humidity\n      { did: 'temperature', siid: 3, piid: 2 }, // measure_temperature\n      { did: 'child_lock', siid: 11, piid: 1 }, // settings.childLock\n      { did: 'buzzer', siid: 14, piid: 1 }, // settings.buzzer\n      { did: 'light', siid: 15, piid: 2 }, // settings.led\n    ],\n    set_properties: {\n      onoff: { siid: 2, piid: 1 },\n      mode: { siid: 2, piid: 3 },\n      target_humidity: { siid: 2, piid: 6 },\n      onoff_dry: { siid: 2, piid: 12 },\n      child_lock: { siid: 11, piid: 1 },\n      buzzer: { siid: 14, piid: 1 },\n      light: { siid: 15, piid: 1 },\n    },\n  },\n  mapping_600ek: {\n    get_properties: [\n      { did: 'onoff', siid: 2, piid: 1 }, // onoff\n      { did: 'error', siid: 2, piid: 2 }, // settings.error / low-water state\n      { did: 'mode', siid: 2, piid: 3 }, // humidifier_xiaomi_mode\n      { did: 'target_humidity', siid: 2, piid: 5 }, // target_humidity [40-70]\n      { did: 'humidity', siid: 3, piid: 1 }, // measure_humidity\n      { did: 'light', siid: 6, piid: 1 }, // settings.led (screen on)\n      { did: 'buzzer', siid: 7, piid: 1 }, // settings.buzzer\n      { did: 'child_lock', siid: 8, piid: 1 }, // settings.childLock\n    ],\n    set_properties: {\n      onoff: { siid: 2, piid: 1 },\n      mode: { siid: 2, piid: 3 },\n      target_humidity: { siid: 2, piid: 5 },\n      light: { siid: 6, piid: 1 },\n      buzzer: { siid: 7, piid: 1 },\n      child_lock: { siid: 8, piid: 1 },\n    },\n  },\n};\n\nconst MODE_OPTIONS = {\n  default: [\n    { id: '0', title: 'Constant Humidity' },\n    { id: '1', title: 'Strong' },\n    { id: '2', title: 'Sleep' },\n    { id: '3', title: 'Air-dry' },\n    { id: '4', title: 'Clean' },\n    { id: '5', title: 'Descale' },\n  ],\n  'xiaomi.humidifier.600ek': [\n    { id: '0', title: 'Constant Humidity' },\n    { id: '1', title: 'Sleep' },\n    { id: '2', title: 'Strong' },\n  ],\n};\n\nconst ERROR_CODES = {\n  default: {\n    0: 'No Error',\n    1: 'Pump',\n    2: 'Low Water',\n    3: 'Pump Low Water',\n  },\n  'xiaomi.humidifier.600ek': {\n    0: 'No Faults',\n    1: 'Motor Fault',\n    2: 'Pump Fault',\n    3: 'Pump Fail',\n    4: 'Lack Of Water',\n  },\n};\n\nclass XiaomiHumidifierMIoTDevice extends Device {\n  getModel() {\n    return this.getStoreValue('model');\n  }\n\n  is600ek() {\n    return this.getModel() === 'xiaomi.humidifier.600ek';\n  }\n\n  getModeOptions() {\n    return MODE_OPTIONS[this.getModel()] || MODE_OPTIONS.default;\n  }\n\n  getModeLabel(mode) {\n    const modeValue = String(mode);\n    const option = this.getModeOptions().find((entry) => entry.id === modeValue);\n    return option ? option.title : modeValue;\n  }\n\n  getTargetHumidityOptions() {\n    if (this.is600ek()) {\n      return { min: 0.4, max: 0.7, step: 0.01, preventInsights: true };\n    }\n\n    return { min: 40, max: 70, step: 10 };\n  }\n\n  getTargetHumidityCapabilityValue(value) {\n    if (this.is600ek()) {\n      return value / 100;\n    }\n\n    return value;\n  }\n\n  getTargetHumidityMiotValue(value) {\n    if (this.is600ek()) {\n      return Math.round(value * 100);\n    }\n\n    return value;\n  }\n\n  getErrorLabel(value) {\n    const errorCodes = ERROR_CODES[this.getModel()] || ERROR_CODES.default;\n    return errorCodes[Number(value)] || 'Unknown';\n  }\n\n  normalizeBooleanValue(value) {\n    return value !== 0 && value !== false && value !== '0' && value !== 'false';\n  }\n\n  indexResults(result) {\n    const map = {};\n    if (!Array.isArray(result)) return map;\n\n    for (const entry of result) {\n      if (!entry) continue;\n      const key = entry.did || `${entry.siid}/${entry.piid}`;\n      map[key] = entry;\n    }\n\n    return map;\n  }\n\n  hasUsableValue(entry) {\n    if (!entry) return false;\n    if (typeof entry.code === 'number' && entry.code !== 0) return false;\n    return entry.value !== undefined && entry.value !== null && entry.value !== 'undefined' && entry.value !== 'null';\n  }\n\n  async handleSetProperty(propertyKey, value) {\n    try {\n      const definition = this.deviceProperties?.set_properties?.[propertyKey];\n      if (!definition) {\n        return Promise.reject(new Error(`Property ${propertyKey} not supported by current model`));\n      }\n\n      if (!this.miio) {\n        this.setUnavailable(this.homey.__('unreachable')).catch((error) => this.error(error));\n        this.createDevice();\n        return Promise.reject('Device unreachable, please try again ...');\n      }\n\n      return await this.miio.call(\n        'set_properties',\n        [{ siid: definition.siid, piid: definition.piid, value }],\n        { retries: 1 }\n      );\n    } catch (error) {\n      this.error(error);\n      return Promise.reject(error);\n    }\n  }\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({ homey: this.homey });\n\n      this.bootSequence();\n\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n      this.homey.flow.getDeviceTriggerCard('humidifier2Waterlevel');\n\n      this.deviceProperties =\n        properties[MODEL_MAPPING[this.getModel()]] !== undefined\n          ? properties[MODEL_MAPPING[this.getModel()]]\n          : properties[MODEL_MAPPING['xiaomi.humidifier.*']];\n\n      if (this.is600ek()) {\n        const unsupportedCapabilities = [\n          'onoff.dry',\n          'measure_temperature',\n          'measure_waterlevel',\n          'humidifier_water_level_state',\n        ];\n        for (const capability of unsupportedCapabilities) {\n          if (this.hasCapability(capability)) {\n            await this.removeCapability(capability).catch((error) => {\n              this.error(`Failed to remove capability ${capability}: ${error.message ?? error}`);\n            });\n          }\n        }\n\n        if (!this.hasCapability('measure_target_humidity')) {\n          await this.addCapability('measure_target_humidity').catch((error) => {\n            this.error(`Failed to add capability measure_target_humidity: ${error.message ?? error}`);\n          });\n        }\n      }\n\n      await this.setCapabilityOptions('humidifier_xiaomi_mode', {\n        values: this.getModeOptions(),\n      });\n      await this.setCapabilityOptions('target_humidity', this.getTargetHumidityOptions());\n\n      this.registerCapabilityListener('onoff', (value) => this.handleSetProperty('onoff', value));\n      this.registerCapabilityListener('humidifier_xiaomi_mode', (value) =>\n        this.handleSetProperty('mode', Number(value))\n      );\n      this.registerCapabilityListener('target_humidity', (value) => {\n        const options = this.getTargetHumidityOptions();\n        const humidity = this.getTargetHumidityMiotValue(this.util.clamp(Number(value), options.min, options.max));\n        return this.handleSetProperty('target_humidity', humidity).then(async (result) => {\n          if (this.is600ek() && this.hasCapability('measure_target_humidity')) {\n            await this.updateCapabilityValue('measure_target_humidity', humidity);\n          }\n          return result;\n        });\n      });\n\n      if (this.hasCapability('onoff.dry') && this.deviceProperties?.set_properties?.onoff_dry) {\n        this.registerCapabilityListener('onoff.dry', (value) => this.handleSetProperty('onoff_dry', value));\n      }\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes('address') || changedKeys.includes('token') || changedKeys.includes('polling')) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes('led') && this.deviceProperties?.set_properties?.light && this.miio) {\n      await this.handleSetProperty('light', this.normalizeBooleanValue(newSettings.led));\n    }\n\n    if (changedKeys.includes('buzzer') && this.deviceProperties?.set_properties?.buzzer && this.miio) {\n      await this.handleSetProperty('buzzer', this.normalizeBooleanValue(newSettings.buzzer));\n    }\n\n    if (changedKeys.includes('childLock') && this.deviceProperties?.set_properties?.child_lock && this.miio) {\n      await this.handleSetProperty('child_lock', this.normalizeBooleanValue(newSettings.childLock));\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async handleModeEvent(mode) {\n    try {\n      const modeValue = String(mode);\n      if (this.getCapabilityValue('humidifier_xiaomi_mode') !== modeValue) {\n        const previousMode = this.getCapabilityValue('humidifier_xiaomi_mode');\n        await this.setCapabilityValue('humidifier_xiaomi_mode', modeValue);\n        await this.homey.flow\n          .getDeviceTriggerCard('triggerModeChanged')\n          .trigger(this, {\n            new_mode: this.getModeLabel(mode),\n            previous_mode:\n              previousMode !== undefined && previousMode !== null\n                ? this.getModeLabel(previousMode)\n                : '',\n          })\n          .catch((error) => {\n            this.error(error);\n          });\n      }\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call('get_properties', this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) {\n        await this.setAvailable();\n      }\n\n      const indexed = this.indexResults(result);\n\n      const onoff = indexed.onoff;\n      if (this.hasUsableValue(onoff)) {\n        await this.updateCapabilityValue('onoff', !!onoff.value);\n      }\n\n      const targetHumidity = indexed.target_humidity;\n      if (this.hasUsableValue(targetHumidity) && typeof targetHumidity.value === 'number') {\n        await this.updateCapabilityValue('target_humidity', this.getTargetHumidityCapabilityValue(targetHumidity.value));\n        if (this.is600ek() && this.hasCapability('measure_target_humidity')) {\n          await this.updateCapabilityValue('measure_target_humidity', targetHumidity.value);\n        }\n      }\n\n      const onoffDry = indexed.dry;\n      if (this.hasUsableValue(onoffDry) && this.hasCapability('onoff.dry')) {\n        await this.updateCapabilityValue('onoff.dry', !!onoffDry.value);\n      }\n\n      const measureHumidity = indexed.humidity;\n      if (this.hasUsableValue(measureHumidity)) {\n        await this.updateCapabilityValue('measure_humidity', measureHumidity.value);\n      }\n\n      const measureTemperature = indexed.temperature;\n      if (this.hasUsableValue(measureTemperature) && this.hasCapability('measure_temperature')) {\n        await this.updateCapabilityValue('measure_temperature', measureTemperature.value);\n      }\n\n      const childLock = indexed.child_lock;\n      if (this.hasUsableValue(childLock)) {\n        await this.updateSettingValue('childLock', this.normalizeBooleanValue(childLock.value));\n      }\n\n      const buzzer = indexed.buzzer;\n      if (this.hasUsableValue(buzzer)) {\n        await this.updateSettingValue('buzzer', this.normalizeBooleanValue(buzzer.value));\n      }\n\n      const led = indexed.light;\n      if (this.hasUsableValue(led)) {\n        await this.updateSettingValue('led', this.normalizeBooleanValue(led.value));\n      }\n\n      const errorValue = indexed.error;\n      if (this.hasUsableValue(errorValue)) {\n        await this.updateSettingValue('error', this.getErrorLabel(errorValue.value));\n      }\n\n      const mode = indexed.mode;\n      if (this.hasUsableValue(mode) && typeof mode.value === 'number') {\n        await this.handleModeEvent(mode.value);\n      }\n\n      if (!this.is600ek()) {\n        const measureWaterlevel = indexed.water_level;\n        if (this.hasUsableValue(measureWaterlevel)) {\n          const waterLevel = measureWaterlevel.value;\n          if (this.getCapabilityValue('measure_waterlevel') !== waterLevel) {\n            const previousWaterlevel = await this.getCapabilityValue('measure_waterlevel');\n            await this.setCapabilityValue('measure_waterlevel', waterLevel);\n            await this.homey.flow\n              .getDeviceTriggerCard('humidifier2Waterlevel')\n              .trigger(this, { waterlevel: waterLevel, previous_waterlevel: previousWaterlevel })\n              .catch((error) => {\n                this.error(error);\n              });\n          }\n        }\n      }\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((setError) => {\n          this.error(setError);\n        });\n      }\n\n      this.homey.setTimeout(() => {\n        this.createDevice();\n      }, 60000);\n\n      this.error(error.message);\n    }\n  }\n}\n\nmodule.exports = XiaomiHumidifierMIoTDevice;\n"
  },
  {
    "path": "drivers/humidifier_xiaomi_humidifier/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Xiaomi/Mijia Humidifier MIoT (WiFi)\",\n    \"nl\": \"Xiaomi/Mijia Humidifier MIoT (WiFi)\",\n    \"da\": \"Xiaomi/Mijia Luftfugter MIoT (WiFi)\",\n    \"de\": \"Xiaomi/Mijia Luftbefeuchter MIoT (WiFi)\",\n    \"es\": \"Xiaomi/Mijia Humidificador MIoT (WiFi)\",\n    \"fr\": \"Xiaomi/Mijia Humidificateur MIoT (WiFi)\",\n    \"it\": \"Xiaomi/Mijia Umidificatore MIoT (WiFi)\",\n    \"no\": \"Xiaomi/Mijia Luftfukter MIoT (WiFi)\",\n    \"sv\": \"Xiaomi/Mijia Luftfuktare MIoT (WiFi)\",\n    \"pl\": \"Xiaomi/Mijia Nawilżacz MIoT (WiFi)\",\n    \"ru\": \"Xiaomi/Mijia Увлажнитель MIoT (WiFi)\",\n    \"ko\": \"샤오미/미지아 가습기 MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/humidifier_xiaomi_humidifier/assets/images/large.jpg\",\n    \"small\": \"drivers/humidifier_xiaomi_humidifier/assets/images/small.jpg\"\n  },\n  \"class\": \"humidifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"onoff.dry\",\n    \"target_humidity\",\n    \"measure_temperature\",\n    \"measure_humidity\",\n    \"measure_waterlevel\",\n    \"humidifier_xiaomi_mode\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.dry\": {\n      \"title\": {\n        \"en\": \"Dry mode\",\n        \"nl\": \"Droog modus\",\n        \"da\": \"Tør tilstand\",\n        \"de\": \"Trockenmodus\",\n        \"es\": \"Modo seco\",\n        \"fr\": \"Mode sec\",\n        \"it\": \"Modalità secco\",\n        \"no\": \"Tørrmodus\",\n        \"sv\": \"Torr läge\",\n        \"pl\": \"Tryb suchy\",\n        \"ru\": \"Сухой режим\",\n        \"ko\": \"건조 모드\"\n      }\n    },\n    \"target_humidity\": {\n      \"min\": 40,\n      \"max\": 70,\n      \"step\": 10\n    }\n  }\n}"
  },
  {
    "path": "drivers/humidifier_xiaomi_humidifier/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass XiaomiHumidifierMIoTDriver extends Driver {}\n\nmodule.exports = XiaomiHumidifierMIoTDriver;"
  },
  {
    "path": "drivers/humidifier_xiaomi_humidifier/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\",\n      \"pt\": \"Configurações do usuário\",\n      \"ja\": \"ユーザー設定\",\n      \"zh\": \"用户设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"Светодиод\",\n          \"ko\": \"LED\",\n          \"pt\": \"LED\",\n          \"ja\": \"LED\",\n          \"zh\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summer\",\n          \"de\": \"Summer\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Buzzer\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Summer\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Brzęczyk\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"버저\",\n          \"pt\": \"Buzzer\",\n          \"ja\": \"ブザー\",\n          \"zh\": \"蜂鸣器\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnelås\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo infantil\",\n          \"fr\": \"Verrouillage enfants\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barnelås\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada dla dzieci\",\n          \"ru\": \"Блокировка от детей\",\n          \"ko\": \"잠금 기능\",\n          \"pt\": \"Bloqueio para crianças\",\n          \"ja\": \"チャイルドロック\",\n          \"zh\": \"儿童锁\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device data\",\n      \"nl\": \"Apparaat data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"디바이스 데이터\",\n      \"pt\": \"Dados do dispositivo\",\n      \"ja\": \"デバイスデータ\",\n      \"zh\": \"设备数据\"\n    },\n    \"children\": [\n      {\n        \"id\": \"error\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Error\",\n          \"nl\": \"Error\",\n          \"da\": \"Fejl\",\n          \"de\": \"Fehler\",\n          \"es\": \"Error\",\n          \"fr\": \"Erreur\",\n          \"it\": \"Errore\",\n          \"no\": \"Feil\",\n          \"sv\": \"Fel\",\n          \"pl\": \"Błąd\",\n          \"ru\": \"Ошибка\",\n          \"ko\": \"오류\",\n          \"pt\": \"Erro\",\n          \"ja\": \"エラー\",\n          \"zh\": \"错误\"\n        },\n        \"value\": \"No error\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"디바이스 설정\",\n      \"pt\": \"Configurações do dispositivo\",\n      \"ja\": \"デバイス設定\",\n      \"zh\": \"设备设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/humidifier_xiaomi_humidifier/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/humidifier_xiaomi_humidifier/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/humidifier_xiaomi_humidifier/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/zhimi.humidifier.v1\n// https://home.miot-spec.com/spec/zhimi.humidifier.ca1\n// https://home.miot-spec.com/spec/zhimi.humidifier.cb1\n// https://home.miot-spec.com/spec/zhimi.humidifier.cb2\n\nclass MiHumidifierDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n      this.homey.flow.getDeviceTriggerCard('humidifier2Waterlevel');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_power\", [value ? \"on\" : \"off\"]);\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('target_humidity', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_limit_hum\", [value], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('humidifier_zhimi_mode', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_mode\", [value], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      const led = await this.miio.call(\"set_led_b\", [newSettings.led ? 1 : 0]);\n    }\n\n    if (changedKeys.includes(\"buzzer\")) {\n      const buzzer = await this.miio.call(\"set_buzzer\", [newSettings.buzzer ? \"on\" : \"off\"]);\n    }\n\n    if (changedKeys.includes(\"childLock\")) {\n      const childlock = await this.miio.call(\"set_child_lock\", [newSettings.childLock ? \"on\" : \"off\"]);\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      // BASIC CAPABILITIES\n      const result = await this.miio.call(\"get_prop\", [\"power\", \"mode\", \"humidity\", \"buzzer\", \"led_b\", \"child_lock\", \"limit_hum\"], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"onoff\", result[0] === \"on\" ? true : false);\n      await this.updateCapabilityValue(\"measure_humidity\", result[2]);\n      await this.updateCapabilityValue(\"target_humidity\", result[6]);\n      \n      /* settings */\n      await this.updateSettingValue(\"led\", result[4] === 2 ? false : true);\n      await this.updateSettingValue(\"buzzer\", result[3] === \"on\" ? true : false);\n      await this.updateSettingValue(\"childLock\", result[5] === \"on\" ? true : false);\n\n      /* mode capability */\n      if (this.getCapabilityValue('humidifier_zhimi_mode') !== result[1]) {\n        const previous_mode = this.getCapabilityValue('humidifier_zhimi_mode');\n        await this.setCapabilityValue('humidifier_zhimi_mode', result[1]);\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, {\"new_mode\": result[1], \"previous_mode\": previous_mode.toString() }).catch(error => { this.error(error) });\n      }\n\n      /* model specific capabilities */\n      switch (this.getStoreValue('model')) {\n        case 'zhimi.humidifier.v1':\n          await this.util.sleep(2000);\n          const result_extra_props_v1 = await this.miio.call(\"get_prop\", [\"temp_dec\"], { retries: 1 });\n          await this.updateCapabilityValue(\"measure_temperature\", result_extra_props_v1[0] / 10);\n          break;\n        case 'zhimi.humidifier.ca1':\n          await this.util.sleep(2000);\n          const result_extra_props_ca1 = await this.miio.call(\"get_prop\", [\"temp_dec\", \"depth\"], { retries: 1 });\n          await this.updateCapabilityValue(\"measure_temperature\", result_extra_props_ca1[0] / 10);\n          const measure_waterlevel_ca1 = this.util.normalize(result_extra_props_ca1[1], 0 , 120) * 100;\n          if (this.getCapabilityValue('measure_waterlevel') !== measure_waterlevel_ca1) {\n            const previous_waterlevel = await this.getCapabilityValue('measure_waterlevel');\n            await this.setCapabilityValue('measure_waterlevel', measure_waterlevel_ca1);\n            await this.homey.flow.getDeviceTriggerCard('humidifier2Waterlevel').trigger(this, {\"waterlevel\": measure_waterlevel_ca1, \"previous_waterlevel\": previous_waterlevel }).catch(error => { this.error(error) });\n          }\n          break;\n        case 'zhimi.humidifier.cb1':\n        case 'zhimi.humidifier.cb2':\n          await this.util.sleep(2000);\n          const result_extra_props_cb = await this.miio.call(\"get_prop\", [\"temperature\", \"depth\", \"dry\"], { retries: 1 });\n          await this.updateCapabilityValue(\"measure_temperature\", result_extra_props_cb[0]);\n          await this.updateCapabilityValue(\"onoff.dry\", result_extra_props_cb[2] === \"on\" ? true : false);\n          const measure_waterlevel_cb_value = this.util.normalize(result_extra_props_cb[1], 0 , 120) * 100;\n          const measure_waterlevel_cb = this.util.clamp(measure_waterlevel_cb_value, 0 , 100);\n          if (this.getCapabilityValue('measure_waterlevel') !== measure_waterlevel_cb) {\n            const previous_waterlevel = await this.getCapabilityValue('measure_waterlevel');\n            await this.setCapabilityValue('measure_waterlevel', measure_waterlevel_cb);\n            await this.homey.flow.getDeviceTriggerCard('humidifier2Waterlevel').trigger(this, {\"waterlevel\": measure_waterlevel_cb, \"previous_waterlevel\": previous_waterlevel }).catch(error => { this.error(error) });\n          }\n          break;\n        default:\n          break;\n      }\n      \n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = MiHumidifierDevice;\n"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier/driver.compose.json",
    "content": "{\n  \"name\": {\n\t\"en\": \"Smartmi Humidifier v1/v2 (WiFi)\",\n    \"da\": \"Smartmi Luftfugter v1/v2 (WiFi)\",\n    \"de\": \"Smartmi Luftbefeuchter v1/v2 (WLAN)\",\n    \"es\": \"Humidificador Smartmi v1/v2 (WiFi)\",\n    \"fr\": \"Humidificateur Smartmi v1/v2 (WiFi)\",\n    \"it\": \"Umidificatore Smartmi v1/v2 (WiFi)\",\n    \"no\": \"Smartmi Luftfukter v1/v2 (WiFi)\",\n    \"sv\": \"Smartmi Luftfuktare v1/v2 (WiFi)\",\n    \"pl\": \"Nawilżacz Smartmi v1/v2 (WiFi)\",\n    \"ru\": \"Увлажнитель Smartmi v1/v2 (WiFi)\",\n    \"ko\": \"스마트미 가습기 v1/v2 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/humidifier_zhimi_humidifier/assets/images/large.jpg\",\n    \"small\": \"drivers/humidifier_zhimi_humidifier/assets/images/small.jpg\"\n  },\n  \"class\": \"humidifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"measure_temperature\",\n    \"measure_humidity\",\n    \"target_humidity\",\n    \"humidifier_zhimi_mode\"\n  ],\n  \"capabilitiesOptions\": {\n    \"target_humidity\": {\n      \"min\": 30,\n      \"max\": 80,\n      \"step\": 10\n    }\n  }\n}"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiHumidifierDriver extends Driver {}\n\nmodule.exports = MiHumidifierDriver;"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"LED\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Buzzer\",\n          \"de\": \"Summer\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Buzzer\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Buzzeren\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Buzzer\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"부저\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnelås\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo infantil\",\n          \"fr\": \"Verrouillage enfant\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barnesikring\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada rodzicielska\",\n          \"ru\": \"Детский замок\",\n          \"ko\": \"어린이 잠금\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"기기 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier_miot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/zhimi.humidifier.ca4\n// https://home.miot-spec.com/spec/zhimi.humidifier.ca6\n// https://home.miot-spec.com/spec/zhimi.humidifier.jd1\n\nconst mapping = {\n  \"zhimi.humidifier.ca4\": \"mapping_default\",\n  \"zhimi.humidifier.ca6\": \"mapping_ca6\",\n  \"zhimi.humidifier.jd1\": \"mapping_jd1\",\n  \"zhimi.humidifier.*\": \"mapping_default\",\n};\n\nconst properties = {\n  \"mapping_default\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"mode\", siid: 2, piid: 5 }, // humidifier_zhimi_mode_miot\n      { did: \"target_humidity\", siid: 2, piid: 6 }, // target_humidity [30, 40, 50, 60, 70, 80]\n      { did: \"water_level\", siid: 2, piid: 7 }, // measure_waterlevel\n      { did: \"dry\", siid: 2, piid: 8 }, // onoff.dry\n      { did: \"speed_level\", siid: 2, piid: 11 }, // dim [200 - 2000]\n      { did: \"temperature\", siid: 3, piid: 7 }, // measure_temperature\n      { did: \"humidity\", siid: 3, piid: 9 }, // measure_humidity\n      { did: \"buzzer\", siid: 4, piid: 1 }, // settings.buzzer\n      { did: \"light\", siid: 5, piid: 2 }, // settings.led\n      { did: \"child_lock\", siid: 6, piid: 1 } // settings.childLock\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"mode\": { siid: 2, piid: 5 },\n      \"target_humidity\": { siid: 2, piid: 6 },\n      \"dry\":  { siid: 2, piid: 8 },\n      \"speed_level\":  { siid: 2, piid: 11 },\n      \"buzzer\": { siid: 4, piid: 1 },\n      \"light\": { siid: 5, piid: 2 },\n      \"child_lock\": { siid: 6, piid: 1 }\n    }\n  },\n  \"mapping_jd1\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"mode\", siid: 2, piid: 12 }, // humidifier_zhimi_mode_miot\n      { did: \"target_humidity\", siid: 2, piid: 6 }, // target_humidity [30, 40, 50, 60, 70, 80]\n      { did: \"water_level\", siid: 2, piid: 7 }, // measure_waterlevel\n      { did: \"temperature\", siid: 3, piid: 7 }, // measure_temperature\n      { did: \"humidity\", siid: 3, piid: 9 }, // measure_humidity\n      { did: \"buzzer\", siid: 4, piid: 1 }, // settings.buzzer\n      { did: \"light\", siid: 5, piid: 2 } // settings.led\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"mode\": { siid: 2, piid: 12 },\n      \"target_humidity\": { siid: 2, piid: 6 },\n      \"light\": { siid: 5, piid: 2 },\n      \"buzzer\": { siid: 4, piid: 1 }\n    }\n  },\n  \"mapping_ca6\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"mode\", siid: 2, piid: 5 }, // humidifier_zhimi_mode_miot\n      { did: \"target_humidity\", siid: 2, piid: 6 }, // target_humidity [30 - 60]\n      { did: \"water_level\", siid: 2, piid: 7 }, // measure_waterlevel (3-step level)\n      { did: \"dry\", siid: 2, piid: 8 }, // onoff.dry\n      { did: \"temperature\", siid: 3, piid: 7 }, // measure_temperature\n      { did: \"humidity\", siid: 3, piid: 9 }, // measure_humidity\n      { did: \"buzzer\", siid: 4, piid: 1 }, // settings.buzzer\n      { did: \"light\", siid: 5, piid: 2 }, // settings.led\n      { did: \"child_lock\", siid: 6, piid: 1 } // settings.childLock\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"mode\": { siid: 2, piid: 5 },\n      \"target_humidity\": { siid: 2, piid: 6 },\n      \"dry\": { siid: 2, piid: 8 },\n      \"buzzer\": { siid: 4, piid: 1 },\n      \"light\": { siid: 5, piid: 2 },\n      \"child_lock\": { siid: 6, piid: 1 }\n    }\n  }\n}\n\nconst modeOptions = {\n  \"default\": [\n    { id: \"0\", title: \"Auto\" },\n    { id: \"1\", title: \"Level 1\" },\n    { id: \"2\", title: \"Level 2\" },\n    { id: \"3\", title: \"Level 3\" }\n  ],\n  \"zhimi.humidifier.ca6\": [\n    { id: \"0\", title: \"Max\" },\n    { id: \"1\", title: \"Auto\" },\n    { id: \"2\", title: \"Night\" }\n  ]\n};\n\nconst CA6_WATER_LEVEL_STATE_BY_VALUE = {\n  0: 'empty',\n  1: 'normal',\n  2: 'full',\n};\n\nclass MiHumidifierCa4Device extends Device {\n\n  getModel() {\n    return this.getStoreValue('model');\n  }\n\n  isCa6() {\n    return this.getModel() === 'zhimi.humidifier.ca6';\n  }\n\n  getModeOptions() {\n    return modeOptions[this.getModel()] || modeOptions.default;\n  }\n\n  getModeLabel(mode) {\n    const value = String(mode);\n    const option = this.getModeOptions().find((entry) => entry.id === value);\n    return option ? option.title : value;\n  }\n\n  getTargetHumidityOptions() {\n    if (this.isCa6()) {\n      return { min: 30, max: 60, step: 10 };\n    }\n\n    return { min: 30, max: 80, step: 10 };\n  }\n\n  normalizeLedSettingValue(value) {\n    return value !== 0 && value !== false && value !== '0' && value !== 'false';\n  }\n\n  normalizeWaterLevelValue(value) {\n    if (value === null || value === undefined) {\n      return value;\n    }\n\n    return value;\n  }\n\n  getCa6WaterLevelState(value) {\n    const numericValue = Number(value);\n    return CA6_WATER_LEVEL_STATE_BY_VALUE[numericValue] || 'normal';\n  }\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['zhimi.humidifier.*']];\n\n      // DEVICE CAPABILITIES\n      if ((this.getModel() === 'zhimi.humidifier.jd1' || this.isCa6()) && this.hasCapability('dim')) {\n        await this.removeCapability('dim');\n      }\n      if (this.getModel() === 'zhimi.humidifier.jd1' && this.hasCapability('onoff.dry')) {\n        await this.removeCapability('onoff.dry');\n      }\n      if (this.isCa6() && this.hasCapability('measure_waterlevel')) {\n        await this.removeCapability('measure_waterlevel');\n      }\n      if (this.isCa6() && !this.hasCapability('humidifier_water_level_state')) {\n        await this.addCapability('humidifier_water_level_state');\n      }\n\n      await this.setCapabilityOptions('humidifier_zhimi_mode_miot', {\n        values: this.getModeOptions()\n      });\n      await this.setCapabilityOptions('target_humidity', this.getTargetHumidityOptions());\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n      this.homey.flow.getDeviceTriggerCard('humidifier2Waterlevel');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.power.siid, piid: this.deviceProperties.set_properties.power.piid, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      if (this.hasCapability('onoff.dry') && this.deviceProperties.set_properties.dry !== undefined) {\n        this.registerCapabilityListener('onoff.dry', async ( value ) => {\n          try {\n            if (this.miio) {\n              return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.dry.siid, piid: this.deviceProperties.set_properties.dry.piid, value: value }], { retries: 1 });\n            } else {\n              this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n              this.createDevice();\n              return Promise.reject('Device unreachable, please try again ...');\n            }\n          } catch (error) {\n            this.error(error);\n            return Promise.reject(error);\n          }\n        });\n      }\n\n      if (this.hasCapability('dim') && this.deviceProperties.set_properties.speed_level !== undefined) {\n        this.registerCapabilityListener('dim', async ( value ) => {\n          try {\n            if (this.miio) {\n              const speed = this.util.denormalize(value, 200, 2000);\n              return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.speed_level.siid, piid: this.deviceProperties.set_properties.speed_level.piid, value: speed }], { retries: 1 });\n            } else {\n              this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n              this.createDevice();\n              return Promise.reject('Device unreachable, please try again ...');\n            }\n          } catch (error) {\n            this.error(error);\n            return Promise.reject(error);\n          }\n        });\n      }\n\n      this.registerCapabilityListener('target_humidity', async ( value ) => {\n        try {\n          if (this.miio) {\n            const options = this.getTargetHumidityOptions();\n            const targetHumidity = this.util.clamp(Number(value), options.min, options.max);\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.target_humidity.siid, piid: this.deviceProperties.set_properties.target_humidity.piid, value: targetHumidity }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('humidifier_zhimi_mode_miot', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.mode.siid, piid: this.deviceProperties.set_properties.mode.piid, value: Number(value) }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.light.siid, piid: this.deviceProperties.set_properties.light.piid, value: newSettings.led ? 2 : 0 }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"buzzer\") && this.getStoreValue('model') !== 'zhimi.humidifier.jd1') {\n      await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.buzzer.siid, piid: this.deviceProperties.set_properties.buzzer.piid, value: newSettings.buzzer }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"childLock\") && this.deviceProperties.set_properties.child_lock !== undefined) {\n      await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.child_lock.siid, piid: this.deviceProperties.set_properties.child_lock.piid, value: newSettings.childLock }], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const onoff = result.find(obj => obj.did === 'power');\n      const target_humidity = result.find(obj => obj.did === 'target_humidity');\n      const measure_humidity = result.find(obj => obj.did === 'humidity');\n      const onoff_dry = result.find(obj => obj.did === 'dry');\n      const dim = result.find(obj => obj.did === 'speed_level');\n      const measure_temperature = result.find(obj => obj.did === 'temperature');\n      const buzzer = result.find(obj => obj.did === 'buzzer');\n      const child_lock = result.find(obj => obj.did === 'child_lock');\n      const led = result.find(obj => obj.did === 'light');\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"onoff\", onoff.value);\n      await this.updateCapabilityValue(\"target_humidity\", target_humidity.value);\n      await this.updateCapabilityValue(\"measure_humidity\", measure_humidity.value);\n      if (onoff_dry !== undefined && this.hasCapability('onoff.dry')) {\n        await this.updateCapabilityValue(\"onoff.dry\", onoff_dry.value);\n      }\n      if (dim !== undefined && this.hasCapability('dim')) {\n        await this.updateCapabilityValue(\"dim\", this.util.normalize(dim.value, 200, 2000));\n      }\n      await this.updateCapabilityValue(\"measure_temperature\", measure_temperature.value);\n      \n      /* settings */\n      await this.updateSettingValue(\"led\", this.normalizeLedSettingValue(led.value));\n      await this.updateSettingValue(\"buzzer\", buzzer.value);\n      if (child_lock !== undefined) {\n        await this.updateSettingValue(\"childLock\", child_lock.value);\n      }\n\n      /* mode capability */\n      const mode = result.find(obj => obj.did === 'mode');\n      if (this.getCapabilityValue('humidifier_zhimi_mode_miot') !== mode.value.toString()) {\n        const previous_mode = this.getCapabilityValue('humidifier_zhimi_mode_miot');\n        await this.setCapabilityValue('humidifier_zhimi_mode_miot', mode.value.toString());\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, {\"new_mode\": this.getModeLabel(mode.value), \"previous_mode\": previous_mode !== undefined && previous_mode !== null ? this.getModeLabel(previous_mode) : '' }).catch(error => { this.error(error) });\n      }\n\n      /* water level capability */\n      const measure_waterlevel = result.find(obj => obj.did === 'water_level');\n      if (this.isCa6()) {\n        const waterLevelState = this.getCa6WaterLevelState(measure_waterlevel.value);\n        await this.updateCapabilityValue('humidifier_water_level_state', waterLevelState);\n      } else {\n        const normalizedWaterlevel = this.normalizeWaterLevelValue(measure_waterlevel.value);\n        if (this.getCapabilityValue('measure_waterlevel') !== normalizedWaterlevel) {\n          const previous_waterlevel = await this.getCapabilityValue('measure_waterlevel');\n          await this.setCapabilityValue('measure_waterlevel', normalizedWaterlevel);\n          await this.homey.flow.getDeviceTriggerCard('humidifier2Waterlevel').trigger(this, {\"waterlevel\": normalizedWaterlevel, \"previous_waterlevel\": previous_waterlevel }).catch(error => { this.error(error) });\n        }\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = MiHumidifierCa4Device;\n"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Smartmi Humidifier MIoT (WiFi)\",\n    \"nl\": \"Samrtmi Humidifier MIoT (WiFi)\",\n    \"da\": \"Smartmi Humidifier MIoT (WiFi)\",\n    \"de\": \"Smartmi Humidifier MIoT (WiFi)\",\n    \"es\": \"Smartmi Humidificador MIoT (WiFi)\",\n    \"fr\": \"Smartmi Humidificateur MIoT (WiFi)\",\n    \"it\": \"Smartmi Umidificatore MIoT (WiFi)\",\n    \"no\": \"Smartmi Humidifier MIoT (WiFi)\",\n    \"sv\": \"Smartmi Avdunstningsluftfuktare MIoT (WiFi)\",\n    \"pl\": \"Smartmi Nawilżacz Parowy MIoT (WiFi)\",\n    \"ru\": \"Smartmi Испарительный Увлажнитель MIoT (WiFi)\",\n    \"ko\": \"Smartmi 증발식 가습기 MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/humidifier_zhimi_humidifier_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/humidifier_zhimi_humidifier_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"humidifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"onoff.dry\",\n    \"dim\",\n    \"target_humidity\",\n    \"humidifier_zhimi_mode_miot\",\n    \"measure_temperature\",\n    \"measure_humidity\",\n    \"measure_waterlevel\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.dry\": {\n      \"title\": {\n        \"en\": \"Dry mode\",\n        \"nl\": \"Droog modus\",\n        \"da\": \"Tør tilstand\",\n        \"de\": \"Trockenmodus\",\n        \"es\": \"Modo seco\",\n        \"fr\": \"Mode sec\",\n        \"it\": \"Modalità secca\",\n        \"no\": \"Tørrmodus\",\n        \"sv\": \"Torrläge\",\n        \"pl\": \"Tryb suszenia\",\n        \"ru\": \"Сухой режим\",\n        \"ko\": \"건조 모드\"\n      }\n    },\n    \"dim\": {\n      \"title\": {\n        \"en\": \"Motor Speed\",\n        \"nl\": \"Motor snelheid\",\n        \"da\": \"Motors hastighed\",\n        \"de\": \"Motorgeschwindigkeit\",\n        \"es\": \"Velocidad del motor\",\n        \"fr\": \"Vitesse du moteur\",\n        \"it\": \"Velocità del motore\",\n        \"no\": \"Motors hastighet\",\n        \"sv\": \"Motorns hastighet\",\n        \"pl\": \"Prędkość silnika\",\n        \"ru\": \"Скорость двигателя\",\n        \"ko\": \"모터 속도\"\n      },\n      \"min\": 0,\n      \"max\": 1,\n      \"step\": 0.1\n    },\n    \"target_humidity\": {\n      \"min\": 30,\n      \"max\": 80,\n      \"step\": 10\n    }\n  }\n}"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiHumidifierCa4Driver extends Driver {}\n\nmodule.exports = MiHumidifierCa4Driver;"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"LED\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summer\",\n          \"de\": \"Summer\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Sonnerie\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Buzzer\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Buzer\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"부저\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnesikring\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo infantil\",\n          \"fr\": \"Verrouillage enfant\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barne lås\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada rodzicielska\",\n          \"ru\": \"Блокировка от детей\",\n          \"ko\": \"어린이 잠금\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/humidifier_zhimi_humidifier_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/lock_aq1/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nconst fingersId = [\n  \"65536\",\n  \"65537\",\n  \"65538\",\n  \"65539\",\n  \"65540\",\n  \"65541\",\n  \"65542\",\n  \"65543\",\n  \"65544\",\n  \"65545\",\n  \"65546\",\n  \"65547\",\n  \"65548\",\n  \"65549\",\n  \"65550\",\n  \"65551\",\n  \"65552\",\n  \"65553\",\n  \"65554\",\n  \"65555\",\n  \"65556\",\n  \"65557\",\n  \"65558\",\n  \"65559\",\n  \"65560\",\n  \"65561\",\n  \"65562\",\n  \"65563\",\n  \"65564\",\n  \"65565\",\n  \"65566\",\n  \"65567\",\n  \"65568\",\n  \"65569\",\n  \"65570\",\n  \"65571\",\n  \"65572\",\n  \"65573\",\n  \"65574\",\n  \"65575\",\n  \"65576\",\n  \"65577\",\n  \"65578\",\n  \"65579\",\n  \"65580\",\n  \"65581\",\n  \"65582\",\n  \"65583\",\n  \"65584\",\n  \"65585\",\n  \"65586\",\n  \"65587\",\n  \"65588\",\n  \"65589\",\n  \"65590\",\n  \"65591\",\n  \"65592\",\n  \"65593\",\n  \"65594\",\n  \"65595\",\n  \"65596\",\n  \"65597\",\n  \"65598\",\n  \"65599\",\n  \"65600\",\n  \"65601\",\n  \"65602\",\n  \"65603\",\n  \"65604\",\n  \"65605\",\n  \"65606\",\n  \"65607\",\n  \"65608\",\n  \"65609\",\n  \"65610\",\n  \"65611\",\n  \"65612\",\n  \"65613\",\n  \"65614\",\n  \"65615\",\n  \"65616\",\n  \"65617\",\n  \"65618\",\n  \"65619\",\n  \"65620\",\n  \"65621\",\n  \"65622\",\n  \"65623\",\n  \"65624\",\n  \"65625\",\n  \"65626\",\n  \"65627\",\n  \"65628\",\n  \"65629\",\n  \"65630\",\n  \"65631\",\n  \"65632\",\n  \"65633\",\n  \"65634\",\n  \"65635\",\n];\n\nconst codesId = [\n  \"131072\",\n  \"131073\",\n  \"131074\",\n  \"131075\",\n  \"131076\",\n  \"131077\",\n  \"131078\",\n  \"131079\",\n  \"131080\",\n  \"131081\",\n  \"131082\",\n  \"131083\",\n  \"131084\",\n  \"131085\",\n  \"131086\",\n  \"131087\",\n  \"131088\",\n  \"131089\",\n  \"131090\",\n  \"131091\",\n  \"131092\",\n  \"131093\",\n  \"131094\",\n  \"131095\",\n  \"131096\",\n  \"131097\",\n  \"131098\",\n  \"131099\",\n  \"131100\",\n  \"131101\",\n  \"131102\",\n  \"131103\",\n  \"131104\",\n  \"131105\",\n  \"131106\",\n  \"131107\",\n  \"131108\",\n  \"131109\",\n  \"131110\",\n  \"131111\",\n  \"131112\",\n  \"131113\",\n  \"131114\",\n  \"131115\",\n  \"131116\",\n  \"131117\",\n  \"131118\",\n  \"131119\",\n  \"131120\",\n  \"131121\",\n  \"131122\",\n  \"131123\",\n  \"131124\",\n  \"131125\",\n  \"131126\",\n  \"131127\",\n  \"131128\",\n  \"131129\",\n  \"131130\",\n  \"131131\",\n  \"131132\",\n  \"131133\",\n  \"131134\",\n  \"131135\",\n  \"131136\",\n  \"131137\",\n  \"131138\",\n  \"131139\",\n  \"131140\",\n  \"131141\",\n  \"131142\",\n  \"131143\",\n  \"131144\",\n  \"131145\",\n  \"131146\",\n  \"131147\",\n  \"131148\",\n  \"131149\",\n  \"131150\",\n  \"131151\",\n  \"131152\",\n  \"131153\",\n  \"131154\",\n  \"131155\",\n  \"131156\",\n  \"131157\",\n  \"131158\",\n  \"131159\",\n  \"131160\",\n  \"131161\",\n  \"131162\",\n  \"131163\",\n  \"131164\",\n  \"131165\",\n  \"131166\",\n  \"131167\",\n  \"131168\",\n  \"131169\",\n  \"131170\",\n  \"131171\",\n];\n\nconst cardsId = [\n  \"196608\",\n  \"196609\",\n  \"196610\",\n  \"196611\",\n  \"196612\",\n  \"196613\",\n  \"196614\",\n  \"196615\",\n  \"196616\",\n  \"196617\",\n  \"196618\",\n  \"196619\",\n  \"196620\",\n  \"196621\",\n  \"196622\",\n  \"196623\",\n  \"196624\",\n  \"196625\",\n  \"196626\",\n  \"196627\",\n  \"196628\",\n  \"196629\",\n  \"196630\",\n  \"196631\",\n  \"196632\",\n  \"196633\",\n  \"196634\",\n  \"196635\",\n  \"196636\",\n  \"196637\",\n  \"196638\",\n  \"196639\",\n  \"196640\",\n  \"196641\",\n  \"196642\",\n  \"196643\",\n  \"196644\",\n  \"196645\",\n  \"196646\",\n  \"196647\",\n  \"196648\",\n  \"196649\",\n  \"196650\",\n  \"196651\",\n  \"196652\",\n  \"196653\",\n  \"196654\",\n  \"196655\",\n  \"196656\",\n  \"196657\",\n  \"196658\",\n  \"196659\",\n  \"196660\",\n  \"196661\",\n  \"196662\",\n  \"196663\",\n  \"196664\",\n  \"196665\",\n  \"196666\",\n  \"196667\",\n  \"196668\",\n  \"196669\",\n  \"196670\",\n  \"196671\",\n  \"196672\",\n  \"196673\",\n  \"196674\",\n  \"196675\",\n  \"196676\",\n  \"196677\",\n  \"196678\",\n  \"196679\",\n  \"196680\",\n  \"196681\",\n  \"196682\",\n  \"196683\",\n  \"196684\",\n  \"196685\",\n  \"196686\",\n  \"196687\",\n  \"196688\",\n  \"196689\",\n  \"196690\",\n  \"196691\",\n  \"196692\",\n  \"196693\",\n  \"196694\",\n  \"196695\",\n  \"196696\",\n  \"196697\",\n  \"196698\",\n  \"196699\",\n  \"196700\",\n  \"196701\",\n  \"196702\",\n  \"196703\",\n  \"196704\",\n  \"196705\",\n  \"196706\",\n  \"196707\",\n];\n\nclass LockAQ1Device extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n      \n      const settings = this.getSettings();\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n\n      \n      /* alarm_motion.finger */\n      if (device.data.fing_verified) {\n        await this.updateCapabilityValue(\"alarm_motion.finger\", true);\n        fingersId.forEach(async (item, i, arr) => {\n          if (device.data.fing_verified == item) {\n            for (let u = 0; u < 10; u++) {\n              if (settings[`user${u}FingerID`]) {\n                let userFingers = settings[`user${u}FingerID`];\n                let userFingersArray = userFingers.split(\",\");\n                let maxNumber = Math.max.apply(null, userFingersArray);\n                for (let UNF = 0; UNF <= maxNumber; UNF++) {\n                  if (i == userFingersArray[UNF]) {\n                    let userUN = settings[`lock${u}UserName`];\n                    let tokens = {\n                      finger_id: i,\n                      code_id: 404,\n                      card_id: 404,\n                      userName: userUN,\n                      wrong_id: 0,\n                    };\n                    await this.homey.flow.getDeviceTriggerCard('lockEvent').trigger(this, tokens).catch(error => { this.error(error) });\n                  }\n                }\n              }\n            }\n          }\n        });\n        this.homey.setTimeout(async () => { await this.updateCapabilityValue(\"alarm_motion.finger\", false); }, 1000 * this.getSetting('alarm_duration_number'));\n      }\n\n      /* alarm_motion.code */\n      if (device.data.psw_verified) {\n        await this.updateCapabilityValue(\"alarm_motion.code\", true); \n        codesId.forEach(async (item, i, arr) => {\n          if (device.data.psw_verified == item) {\n            for (let u = 0; u < 10; u++) {\n              if (settings[`user${u}CodeID`]) {\n                let userCodes = settings[`user${u}CodeID`];\n                let userCodesArray = userCodes.split(\",\");\n                let maxNumber = Math.max.apply(null, userCodesArray);\n                for (let UNCE = 0; UNCE <= maxNumber; UNCE++) {\n                  if (i == userCodesArray[UNCE]) {\n                    let userUN = settings[`lock${u}UserName`];\n                    let tokens = {\n                      finger_id: 404,\n                      code_id: i,\n                      card_id: 404,\n                      userName: userUN,\n                      wrong_id: 0,\n                    };\n                    await this.homey.flow.getDeviceTriggerCard('lockEvent').trigger(this, tokens).catch(error => { this.error(error) });\n                  }\n                }\n              }\n            }\n          }\n        });\n        this.homey.setTimeout(async () => { await this.updateCapabilityValue(\"alarm_motion.code\", false); }, 1000 * this.getSetting('alarm_duration_number'));\n      }\n\n      /* alarm_motion.card */\n      if (device[\"data\"][\"card_verified\"]) {\n        await this.updateCapabilityValue(\"alarm_motion.card\", true);\n        cardsId.forEach(async (item, i, arr) => {\n          if (device[\"data\"][\"card_verified\"] == item) {\n            for (let u = 0; u < 10; u++) {\n              if (settings[`user${u}CardID`]) {\n                let userCards = settings[`user${u}CardID`];\n                let userCardsArray = userCards.split(\",\");\n                let maxNumber = Math.max.apply(null, userCardsArray);\n                for (let UNCD = 0; UNCD <= maxNumber; UNCD++) {\n                  if (i == userCardsArray[UNCD]) {\n                    let userUN = settings[`lock${u}UserName`];\n                    let tokens = {\n                      finger_id: 404,\n                      code_id: 404,\n                      card_id: i,\n                      userName: userUN,\n                      wrong_id: 0,\n                    };\n                    await this.homey.flow.getDeviceTriggerCard('lockEvent').trigger(this, tokens).catch(error => { this.error(error) });\n                  }\n                }\n              }\n            }\n          }\n        });\n        this.homey.setTimeout(async () => { await this.updateCapabilityValue(\"alarm_motion.card\", false); }, 1000 * this.getSetting('alarm_duration_number'));\n      }\n\n      /* alarm_motion.wrongID */\n      if (device[\"data\"][\"verified_wrong\"]) {\n        await this.updateCapabilityValue(\"alarm_motion.wrongID\", true);\n        let tokens = {\n          finger_id: 404,\n          code_id: 404,\n          card_id: 404,\n          userName: \"Not user\",\n          wrong_id: parseInt(device[\"data\"][\"verified_wrong\"]),\n        };\n        await this.homey.flow.getDeviceTriggerCard('lockEvent').trigger(this, tokens).catch(error => { this.error(error) });\n        this.homey.setTimeout(async () => { await this.updateCapabilityValue(\"alarm_motion.wrongID\", false); }, 1000 * this.getSetting('alarm_duration_number'));\n      }\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = LockAQ1Device;"
  },
  {
    "path": "drivers/lock_aq1/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara Lock (Gateway)\",\n    \"nl\": \"Aqara Lock (Gateway)\",\n    \"da\": \"Aqara Lock (Gateway)\",\n    \"de\": \"Aqara Lock (Gateway)\",\n    \"es\": \"Aqara Lock (Gateway)\",\n    \"fr\": \"Aqara Lock (Gateway)\",\n    \"it\": \"Aqara Lock (Gateway)\",\n    \"no\": \"Aqara Lock (Gateway)\",\n    \"sv\": \"Aqara Lock (Gateway)\",\n    \"pl\": \"Aqara Lock (Gateway)\",\n    \"ru\": \"Aqara Lock (Gateway)\",\n    \"ko\": \"Aqara Lock (Gateway)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/lock_aq1/assets/images/large.jpg\",\n    \"small\": \"/drivers/lock_aq1/assets/images/small.jpg\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"alarm_motion.finger\",\n    \"alarm_motion.code\",\n    \"alarm_motion.card\",\n    \"alarm_motion.wrongID\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"capabilitiesOptions\": {\n    \"alarm_motion.finger\": {\n      \"title\": {\n        \"en\": \"Finger\",\n        \"nl\": \"Vinger\",\n        \"da\": \"Finger\",\n        \"de\": \"Finger\",\n        \"es\": \"Finger\",\n        \"fr\": \"Doigt\",\n        \"it\": \"Dito\",\n        \"no\": \"Finger\",\n        \"sv\": \"Finger\",\n        \"pl\": \"Palec\",\n        \"ru\": \"Палец\",\n        \"ko\": \"손가락\"\n      }\n    },\n    \"alarm_motion.code\": {\n      \"title\": {\n        \"en\": \"Code\",\n        \"nl\": \"Code\",\n        \"da\": \"Kode\",\n        \"de\": \"Code\",\n        \"es\": \"Código\",\n        \"fr\": \"Code\",\n        \"it\": \"Codice\",\n        \"no\": \"Kode\",\n        \"sv\": \"Kod\",\n        \"pl\": \"Kod\",\n        \"ru\": \"Код\",\n        \"ko\": \"코드\"\n      }\n    },\n    \"alarm_motion.card\": {\n      \"title\": {\n        \"en\": \"Card\",\n        \"nl\": \"Card\",\n        \"da\": \"Kort\",\n        \"de\": \"Karte\",\n        \"es\": \"Tarjeta\",\n        \"fr\": \"Carte\",\n        \"it\": \"Carta\",\n        \"no\": \"Kort\",\n        \"sv\": \"Kort\",\n        \"pl\": \"Karta\",\n        \"ru\": \"Карта\",\n        \"ko\": \"카드\"\n      }\n    },\n    \"alarm_motion.wrongID\": {\n      \"title\": {\n        \"en\": \"Wrong ID\",\n        \"nl\": \"Verkeerd ID\",\n        \"da\": \"Forkert ID\",\n        \"de\": \"Falsche ID\",\n        \"es\": \"ID incorrecta\",\n        \"fr\": \"ID incorrecte\",\n        \"it\": \"ID sbagliato\",\n        \"no\": \"Feil ID\",\n        \"sv\": \"Fel ID\",\n        \"pl\": \"Błędne ID\",\n        \"ru\": \"Неправильный ID\",\n        \"ko\": \"잘못된 ID\"\n      }\n    }\n  },\n  \"energy\": {\n    \"batteries\": [\n      \"AAA\",\n      \"AAA\",\n      \"AAA\",\n      \"AAA\",\n      \"AAA\",\n      \"AAA\",\n      \"AAA\",\n      \"AAA\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/lock_aq1/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass LockAQ1Driver extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('lockEvent');\n\n    this.config = {\n      model: [\"lock.aq1\"]\n    }\n  }\n\n}\n\nmodule.exports = LockAQ1Driver;"
  },
  {
    "path": "drivers/lock_aq1/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Duration of the lock alarm\",\n      \"nl\": \"Duur van het slot alarm\",\n      \"da\": \"Varighed af alarmsystemet\",\n      \"de\": \"Dauer des Schlossalarmes\",\n      \"es\": \"Duración de la alarma de la cerradura\",\n      \"fr\": \"Durée de l'alarme de verrouillage\",\n      \"it\": \"Durata dell'allarme della serratura\",\n      \"no\": \"Varighet på låsalarm\",\n      \"sv\": \"Varaktighet av låsalarm\",\n      \"pl\": \"Czas trwania alarmu blokady\",\n      \"ru\": \"Длительность тревоги блокировки\",\n      \"ko\": \"잠금 경고의 지속 시간\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_duration_number\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Disable after\",\n          \"nl\": \"Uitschakelen na\",\n          \"da\": \"Deaktiver efter\",\n          \"de\": \"Deaktivieren nach\",\n          \"es\": \"Desactivar después\",\n          \"fr\": \"Désactiver après\",\n          \"it\": \"Disabilita dopo\",\n          \"no\": \"Deaktiver etter\",\n          \"sv\": \"Inaktivera efter\",\n          \"pl\": \"Wyłącz po\",\n          \"ru\": \"Выключить через\",\n          \"ko\": \"비활성화 후\"\n        },\n        \"value\": 60,\n        \"attr\": {\n          \"min\": 60,\n          \"max\": 86400\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuraciones del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"디바이스 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device information\",\n      \"da\": \"Enhedsoplysninger\",\n      \"de\": \"Geräteinformationen\",\n      \"es\": \"Información sobre el dispositivo\",\n      \"fr\": \"Informations sur l'appareil\",\n      \"it\": \"Informazioni sul dispositivo\",\n      \"no\": \"Enhetsinformasjon\",\n      \"sv\": \"Enhetsinformation\",\n      \"pl\": \"Informacje o urządzeniu\",\n      \"ru\": \"Информация об устройстве\",\n      \"ko\": \"장치 정보\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Device sid\",\n          \"da\": \"Enhedsid\",\n          \"de\": \"Geräte-SID\",\n          \"es\": \"Sid del dispositivo\",\n          \"fr\": \"SID de l'appareil\",\n          \"it\": \"SID del dispositivo\",\n          \"no\": \"Enhetsside\",\n          \"sv\": \"Enhets-SID\",\n          \"pl\": \"SID urządzenia\",\n          \"ru\": \"SID устройства\",\n          \"ko\": \"장치 SID\"\n        },\n        \"value\": \"0123456789abcd\"\n      },\n      {\n        \"id\": \"deviceFromGatewaySid\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Gateway sid\",\n          \"da\": \"Gateway sid\",\n          \"de\": \"Gateway SID\",\n          \"es\": \"Sid de la puerta de enlace\",\n          \"fr\": \"SID de la passerelle\",\n          \"it\": \"SID del gateway\",\n          \"no\": \"Gateway sid\",\n          \"sv\": \"Gateway SID\",\n          \"pl\": \"SID bramy\",\n          \"ru\": \"SID шлюза\",\n          \"ko\": \"게이트웨이 SID\"\n        },\n        \"value\": \"0123456789ab\"\n      },\n      {\n        \"id\": \"deviceModelName\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Device model\",\n          \"da\": \"Enhedsmodel\",\n          \"de\": \"Gerätemodell\",\n          \"es\": \"Modelo del dispositivo\",\n          \"fr\": \"Modèle de l'appareil\",\n          \"it\": \"Modello del dispositivo\",\n          \"no\": \"Enhetsmodell\",\n          \"sv\": \"Enhetsmodell\",\n          \"pl\": \"Model urządzenia\",\n          \"ru\": \"Модель устройства\",\n          \"ko\": \"장치 모델\"\n        },\n        \"value\": \"lumi.device\"\n      },\n      {\n        \"id\": \"deviceModelCodeName\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Device model code\",\n          \"da\": \"Enhedsmodelkode\",\n          \"de\": \"Gerätemodellcode\",\n          \"es\": \"Código del modelo del dispositivo\",\n          \"fr\": \"Code du modèle de l'appareil\",\n          \"it\": \"Codice del modello del dispositivo\",\n          \"no\": \"Enhetsmodells kode\",\n          \"sv\": \"Enhetsmodellkod\",\n          \"pl\": \"Kod modelu urządzenia\",\n          \"ru\": \"Код модели устройства\",\n          \"ko\": \"장치 모델 코드\"\n        },\n        \"value\": \"AABBCC01LM\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Lock users\",\n      \"da\": \"Låsebrugere\",\n      \"de\": \"Schlossbenutzer\",\n      \"es\": \"Usuarios de la cerradura\",\n      \"fr\": \"Utilisateurs de verrou\",\n      \"it\": \"Utenti della serratura\",\n      \"no\": \"Låsebrukere\",\n      \"sv\": \"Låsanvändare\",\n      \"pl\": \"Użytkownicy zamka\",\n      \"ru\": \"Пользователи замка\",\n      \"ko\": \"잠금 사용자\"\n    },\n    \"children\": [\n      {\n        \"id\": \"lock0UserName\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"1 - User name\",\n          \"da\": \"1 - Brugernavn\",\n          \"de\": \"1 - Benutzername\",\n          \"es\": \"1 - Nombre de usuario\",\n          \"fr\": \"1 - Nom d'utilisateur\",\n          \"it\": \"1 - Nome utente\",\n          \"no\": \"1 - Brukernavn\",\n          \"sv\": \"1 - Användarnamn\",\n          \"pl\": \"1 - Nazwa użytkownika\",\n          \"ru\": \"1 - Имя пользователя\",\n          \"ko\": \"1 - 사용자 이름\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user0FingerID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Finger ID\",\n          \"da\": \"Finger ID\",\n          \"de\": \"Finger-ID\",\n          \"es\": \"ID de dedo\",\n          \"fr\": \"ID d'empreinte\",\n          \"it\": \"ID del dito\",\n          \"no\": \"Finger-ID\",\n          \"sv\": \"Finger-ID\",\n          \"pl\": \"ID palca\",\n          \"ru\": \"ID пальца\",\n          \"ko\": \"지문 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user0CodeID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Code ID\",\n          \"da\": \"Kode ID\",\n          \"de\": \"Code-ID\",\n          \"es\": \"ID de código\",\n          \"fr\": \"ID de code\",\n          \"it\": \"ID del codice\",\n          \"no\": \"Kode-ID\",\n          \"sv\": \"Kod-ID\",\n          \"pl\": \"ID kodu\",\n          \"ru\": \"ID кода\",\n          \"ko\": \"코드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user0CardID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Card ID\",\n          \"da\": \"Kort ID\",\n          \"de\": \"Karten-ID\",\n          \"es\": \"ID de tarjeta\",\n          \"fr\": \"ID de carte\",\n          \"it\": \"ID della carta\",\n          \"no\": \"Kort-ID\",\n          \"sv\": \"Kort-ID\",\n          \"pl\": \"ID karty\",\n          \"ru\": \"ID карты\",\n          \"ko\": \"카드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"lock1UserName\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"2 - User name\",\n          \"da\": \"2 - Brugernavn\",\n          \"de\": \"2 - Benutzername\",\n          \"es\": \"2 - Nombre de usuario\",\n          \"fr\": \"2 - Nom d'utilisateur\",\n          \"it\": \"2 - Nome utente\",\n          \"no\": \"2 - Brukernavn\",\n          \"sv\": \"2 - Användarnamn\",\n          \"pl\": \"2 - Nazwa użytkownika\",\n          \"ru\": \"2 - Имя пользователя\",\n          \"ko\": \"2 - 사용자 이름\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user1FingerID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Finger ID\",\n          \"da\": \"Finger ID\",\n          \"de\": \"Finger-ID\",\n          \"es\": \"ID de dedo\",\n          \"fr\": \"ID d'empreinte\",\n          \"it\": \"ID del dito\",\n          \"no\": \"Finger-ID\",\n          \"sv\": \"Finger-ID\",\n          \"pl\": \"ID palca\",\n          \"ru\": \"ID пальца\",\n          \"ko\": \"지문 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user1CodeID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Code ID\",\n          \"da\": \"Kode ID\",\n          \"de\": \"Code-ID\",\n          \"es\": \"ID de código\",\n          \"fr\": \"ID de code\",\n          \"it\": \"ID del codice\",\n          \"no\": \"Kode-ID\",\n          \"sv\": \"Kod-ID\",\n          \"pl\": \"ID kodu\",\n          \"ru\": \"ID кода\",\n          \"ko\": \"코드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user1CardID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Card ID\",\n          \"da\": \"Kort ID\",\n          \"de\": \"Karten-ID\",\n          \"es\": \"ID de tarjeta\",\n          \"fr\": \"ID de carte\",\n          \"it\": \"ID della carta\",\n          \"no\": \"Kort-ID\",\n          \"sv\": \"Kort-ID\",\n          \"pl\": \"ID karty\",\n          \"ru\": \"ID карты\",\n          \"ko\": \"카드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"lock2UserName\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"3 - User name\",\n          \"da\": \"3 - Brugernavn\",\n          \"de\": \"3 - Benutzername\",\n          \"es\": \"3 - Nombre de usuario\",\n          \"fr\": \"3 - Nom d'utilisateur\",\n          \"it\": \"3 - Nome utente\",\n          \"no\": \"3 - Brukernavn\",\n          \"sv\": \"3 - Användarnamn\",\n          \"pl\": \"3 - Nazwa użytkownika\",\n          \"ru\": \"3 - Имя пользователя\",\n          \"ko\": \"3 - 사용자 이름\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user2FingerID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Finger ID\",\n          \"da\": \"Finger ID\",\n          \"de\": \"Finger-ID\",\n          \"es\": \"ID de dedo\",\n          \"fr\": \"ID d'empreinte\",\n          \"it\": \"ID del dito\",\n          \"no\": \"Finger-ID\",\n          \"sv\": \"Finger-ID\",\n          \"pl\": \"ID palca\",\n          \"ru\": \"ID пальца\",\n          \"ko\": \"지문 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user2CodeID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Code ID\",\n          \"da\": \"Kode ID\",\n          \"de\": \"Code-ID\",\n          \"es\": \"ID de código\",\n          \"fr\": \"ID de code\",\n          \"it\": \"ID del codice\",\n          \"no\": \"Kode-ID\",\n          \"sv\": \"Kod-ID\",\n          \"pl\": \"ID kodu\",\n          \"ru\": \"ID кода\",\n          \"ko\": \"코드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user2CardID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Card ID\",\n          \"da\": \"Kort ID\",\n          \"de\": \"Karten-ID\",\n          \"es\": \"ID de tarjeta\",\n          \"fr\": \"ID de carte\",\n          \"it\": \"ID della carta\",\n          \"no\": \"Kort-ID\",\n          \"sv\": \"Kort-ID\",\n          \"pl\": \"ID karty\",\n          \"ru\": \"ID карты\",\n          \"ko\": \"카드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"lock3UserName\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"4 - User name\",\n          \"da\": \"4 - Brugernavn\",\n          \"de\": \"4 - Benutzername\",\n          \"es\": \"4 - Nombre de usuario\",\n          \"fr\": \"4 - Nom d'utilisateur\",\n          \"it\": \"4 - Nome utente\",\n          \"no\": \"4 - Brukernavn\",\n          \"sv\": \"4 - Användarnamn\",\n          \"pl\": \"4 - Nazwa użytkownika\",\n          \"ru\": \"4 - Имя пользователя\",\n          \"ko\": \"4 - 사용자 이름\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user3FingerID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Finger ID\",\n          \"da\": \"Finger ID\",\n          \"de\": \"Finger-ID\",\n          \"es\": \"ID de dedo\",\n          \"fr\": \"ID d'empreinte\",\n          \"it\": \"ID del dito\",\n          \"no\": \"Finger-ID\",\n          \"sv\": \"Finger-ID\",\n          \"pl\": \"ID palca\",\n          \"ru\": \"ID пальца\",\n          \"ko\": \"지문 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user3CodeID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Code ID\",\n          \"da\": \"Kode ID\",\n          \"de\": \"Code-ID\",\n          \"es\": \"ID de código\",\n          \"fr\": \"ID de code\",\n          \"it\": \"ID del codice\",\n          \"no\": \"Kode-ID\",\n          \"sv\": \"Kod-ID\",\n          \"pl\": \"ID kodu\",\n          \"ru\": \"ID кода\",\n          \"ko\": \"코드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user3CardID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Card ID\",\n          \"da\": \"Kort ID\",\n          \"de\": \"Karten-ID\",\n          \"es\": \"ID de tarjeta\",\n          \"fr\": \"ID de carte\",\n          \"it\": \"ID della carta\",\n          \"no\": \"Kort-ID\",\n          \"sv\": \"Kort-ID\",\n          \"pl\": \"ID karty\",\n          \"ru\": \"ID карты\",\n          \"ko\": \"카드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"lock4UserName\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"5 - User name\",\n          \"da\": \"5 - Brugernavn\",\n          \"de\": \"5 - Benutzername\",\n          \"es\": \"5 - Nombre de usuario\",\n          \"fr\": \"5 - Nom d'utilisateur\",\n          \"it\": \"5 - Nome utente\",\n          \"no\": \"5 - Brukernavn\",\n          \"sv\": \"5 - Användarnamn\",\n          \"pl\": \"5 - Nazwa użytkownika\",\n          \"ru\": \"5 - Имя пользователя\",\n          \"ko\": \"5 - 사용자 이름\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user4FingerID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Finger ID\",\n          \"da\": \"Finger ID\",\n          \"de\": \"Finger-ID\",\n          \"es\": \"ID de dedo\",\n          \"fr\": \"ID d'empreinte\",\n          \"it\": \"ID del dito\",\n          \"no\": \"Finger-ID\",\n          \"sv\": \"Finger-ID\",\n          \"pl\": \"ID palca\",\n          \"ru\": \"ID пальца\",\n          \"ko\": \"지문 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user4CodeID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Code ID\",\n          \"da\": \"Kode ID\",\n          \"de\": \"Code-ID\",\n          \"es\": \"ID de código\",\n          \"fr\": \"ID de code\",\n          \"it\": \"ID del codice\",\n          \"no\": \"Kode-ID\",\n          \"sv\": \"Kod-ID\",\n          \"pl\": \"ID kodu\",\n          \"ru\": \"ID кода\",\n          \"ko\": \"코드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user4CardID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Card ID\",\n          \"da\": \"Kort ID\",\n          \"de\": \"Karten-ID\",\n          \"es\": \"ID de tarjeta\",\n          \"fr\": \"ID de carte\",\n          \"it\": \"ID della carta\",\n          \"no\": \"Kort-ID\",\n          \"sv\": \"Kort-ID\",\n          \"pl\": \"ID karty\",\n          \"ru\": \"ID карты\",\n          \"ko\": \"카드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"lock5UserName\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"6 - User name\",\n          \"da\": \"6 - Brugernavn\",\n          \"de\": \"6 - Benutzername\",\n          \"es\": \"6 - Nombre de usuario\",\n          \"fr\": \"6 - Nom d'utilisateur\",\n          \"it\": \"6 - Nome utente\",\n          \"no\": \"6 - Brukernavn\",\n          \"sv\": \"6 - Användarnamn\",\n          \"pl\": \"6 - Nazwa użytkownika\",\n          \"ru\": \"6 - Имя пользователя\",\n          \"ko\": \"6 - 사용자 이름\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user5FingerID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Finger ID\",\n          \"da\": \"Finger ID\",\n          \"de\": \"Finger-ID\",\n          \"es\": \"ID de dedo\",\n          \"fr\": \"ID d'empreinte\",\n          \"it\": \"ID del dito\",\n          \"no\": \"Finger-ID\",\n          \"sv\": \"Finger-ID\",\n          \"pl\": \"ID palca\",\n          \"ru\": \"ID пальца\",\n          \"ko\": \"지문 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user5CodeID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Code ID\",\n          \"da\": \"Kode ID\",\n          \"de\": \"Code-ID\",\n          \"es\": \"ID de código\",\n          \"fr\": \"ID de code\",\n          \"it\": \"ID del codice\",\n          \"no\": \"Kode-ID\",\n          \"sv\": \"Kod-ID\",\n          \"pl\": \"ID kodu\",\n          \"ru\": \"ID кода\",\n          \"ko\": \"코드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user5CardID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Card ID\",\n          \"da\": \"Kort ID\",\n          \"de\": \"Karten-ID\",\n          \"es\": \"ID de tarjeta\",\n          \"fr\": \"ID de carte\",\n          \"it\": \"ID della carta\",\n          \"no\": \"Kort-ID\",\n          \"sv\": \"Kort-ID\",\n          \"pl\": \"ID karty\",\n          \"ru\": \"ID карты\",\n          \"ko\": \"카드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"lock6UserName\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"7 - User name\",\n          \"da\": \"7 - Brugernavn\",\n          \"de\": \"7 - Benutzername\",\n          \"es\": \"7 - Nombre de usuario\",\n          \"fr\": \"7 - Nom d'utilisateur\",\n          \"it\": \"7 - Nome utente\",\n          \"no\": \"7 - Brukernavn\",\n          \"sv\": \"7 - Användarnamn\",\n          \"pl\": \"7 - Nazwa użytkownika\",\n          \"ru\": \"7 - Имя пользователя\",\n          \"ko\": \"7 - 사용자 이름\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user6FingerID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Finger ID\",\n          \"da\": \"Finger ID\",\n          \"de\": \"Finger-ID\",\n          \"es\": \"ID de dedo\",\n          \"fr\": \"ID d'empreinte\",\n          \"it\": \"ID del dito\",\n          \"no\": \"Finger-ID\",\n          \"sv\": \"Finger-ID\",\n          \"pl\": \"ID palca\",\n          \"ru\": \"ID пальца\",\n          \"ko\": \"지문 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user6CodeID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Code ID\",\n          \"da\": \"Kode ID\",\n          \"de\": \"Code-ID\",\n          \"es\": \"ID de código\",\n          \"fr\": \"ID de code\",\n          \"it\": \"ID del codice\",\n          \"no\": \"Kode-ID\",\n          \"sv\": \"Kod-ID\",\n          \"pl\": \"ID kodu\",\n          \"ru\": \"ID кода\",\n          \"ko\": \"코드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user6CardID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Card ID\",\n          \"da\": \"Kort ID\",\n          \"de\": \"Karten-ID\",\n          \"es\": \"ID de tarjeta\",\n          \"fr\": \"ID de carte\",\n          \"it\": \"ID della carta\",\n          \"no\": \"Kort-ID\",\n          \"sv\": \"Kort-ID\",\n          \"pl\": \"ID karty\",\n          \"ru\": \"ID карты\",\n          \"ko\": \"카드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"lock7UserName\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"8 - User name\",\n          \"da\": \"8 - Brugernavn\",\n          \"de\": \"8 - Benutzername\",\n          \"es\": \"8 - Nombre de usuario\",\n          \"fr\": \"8 - Nom d'utilisateur\",\n          \"it\": \"8 - Nome utente\",\n          \"no\": \"8 - Brukernavn\",\n          \"sv\": \"8 - Användarnamn\",\n          \"pl\": \"8 - Nazwa użytkownika\",\n          \"ru\": \"8 - Имя пользователя\",\n          \"ko\": \"8 - 사용자 이름\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user7FingerID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Finger ID\",\n          \"da\": \"Finger ID\",\n          \"de\": \"Finger-ID\",\n          \"es\": \"ID de dedo\",\n          \"fr\": \"ID d'empreinte\",\n          \"it\": \"ID del dito\",\n          \"no\": \"Finger-ID\",\n          \"sv\": \"Finger-ID\",\n          \"pl\": \"ID palca\",\n          \"ru\": \"ID пальца\",\n          \"ko\": \"지문 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user7CodeID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Code ID\",\n          \"da\": \"Kode ID\",\n          \"de\": \"Code-ID\",\n          \"es\": \"ID de código\",\n          \"fr\": \"ID de code\",\n          \"it\": \"ID del codice\",\n          \"no\": \"Kode-ID\",\n          \"sv\": \"Kod-ID\",\n          \"pl\": \"ID kodu\",\n          \"ru\": \"ID кода\",\n          \"ko\": \"코드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user7CardID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Card ID\",\n          \"da\": \"Kort ID\",\n          \"de\": \"Karten-ID\",\n          \"es\": \"ID de tarjeta\",\n          \"fr\": \"ID de carte\",\n          \"it\": \"ID della carta\",\n          \"no\": \"Kort-ID\",\n          \"sv\": \"Kort-ID\",\n          \"pl\": \"ID karty\",\n          \"ru\": \"ID карты\",\n          \"ko\": \"카드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"lock8UserName\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"9 - User name\",\n          \"da\": \"9 - Brugernavn\",\n          \"de\": \"9 - Benutzername\",\n          \"es\": \"9 - Nombre de usuario\",\n          \"fr\": \"9 - Nom d'utilisateur\",\n          \"it\": \"9 - Nome utente\",\n          \"no\": \"9 - Brukernavn\",\n          \"sv\": \"9 - Användarnamn\",\n          \"pl\": \"9 - Nazwa użytkownika\",\n          \"ru\": \"9 - Имя пользователя\",\n          \"ko\": \"9 - 사용자 이름\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user8FingerID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Finger ID\",\n          \"da\": \"Finger ID\",\n          \"de\": \"Finger-ID\",\n          \"es\": \"ID de dedo\",\n          \"fr\": \"ID d'empreinte\",\n          \"it\": \"ID del dito\",\n          \"no\": \"Finger-ID\",\n          \"sv\": \"Finger-ID\",\n          \"pl\": \"ID palca\",\n          \"ru\": \"ID пальца\",\n          \"ko\": \"지문 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user8CodeID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Code ID\",\n          \"da\": \"Kode ID\",\n          \"de\": \"Code-ID\",\n          \"es\": \"ID de código\",\n          \"fr\": \"ID de code\",\n          \"it\": \"ID del codice\",\n          \"no\": \"Kode-ID\",\n          \"sv\": \"Kod-ID\",\n          \"pl\": \"ID kodu\",\n          \"ru\": \"ID кода\",\n          \"ko\": \"코드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user8CardID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Card ID\",\n          \"da\": \"Kort ID\",\n          \"de\": \"Karten-ID\",\n          \"es\": \"ID de tarjeta\",\n          \"fr\": \"ID de carte\",\n          \"it\": \"ID della carta\",\n          \"no\": \"Kort-ID\",\n          \"sv\": \"Kort-ID\",\n          \"pl\": \"ID karty\",\n          \"ru\": \"ID карты\",\n          \"ko\": \"카드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"lock9UserName\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"10 - User name\",\n          \"da\": \"10 - Brugernavn\",\n          \"de\": \"10 - Benutzername\",\n          \"es\": \"10 - Nombre de usuario\",\n          \"fr\": \"10 - Nom d'utilisateur\",\n          \"it\": \"10 - Nome utente\",\n          \"no\": \"10 - Brukernavn\",\n          \"sv\": \"10 - Användarnamn\",\n          \"pl\": \"10 - Nazwa użytkownika\",\n          \"ru\": \"10 - Имя пользователя\",\n          \"ko\": \"10 - 사용자 이름\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user9FingerID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Finger ID\",\n          \"da\": \"Finger ID\",\n          \"de\": \"Finger-ID\",\n          \"es\": \"ID de dedo\",\n          \"fr\": \"ID d'empreinte\",\n          \"it\": \"ID del dito\",\n          \"no\": \"Finger-ID\",\n          \"sv\": \"Finger-ID\",\n          \"pl\": \"ID palca\",\n          \"ru\": \"ID пальца\",\n          \"ko\": \"지문 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user9CodeID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Code ID\",\n          \"da\": \"Kode ID\",\n          \"de\": \"Code-ID\",\n          \"es\": \"ID de código\",\n          \"fr\": \"ID de code\",\n          \"it\": \"ID del codice\",\n          \"no\": \"Kode-ID\",\n          \"sv\": \"Kod-ID\",\n          \"pl\": \"ID kodu\",\n          \"ru\": \"ID кода\",\n          \"ko\": \"코드 ID\"\n        },\n        \"value\": \"\"\n      },\n      {\n        \"id\": \"user9CardID\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Card ID\",\n          \"da\": \"Kort ID\",\n          \"de\": \"Karten-ID\",\n          \"es\": \"ID de tarjeta\",\n          \"fr\": \"ID de carte\",\n          \"it\": \"ID della carta\",\n          \"no\": \"Kort-ID\",\n          \"sv\": \"Kort-ID\",\n          \"pl\": \"ID karty\",\n          \"ru\": \"ID карты\",\n          \"ko\": \"카드 ID\"\n        },\n        \"value\": \"\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/mi-airpurifier/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass MiAirPurifierDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n\n      this.registerCapabilityListener('airpurifier_mode', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.setMode(value);\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async handleDeviceSettings() {\n    try {\n\n      const result = await this.miio.call(\"get_prop\", [\"led\", \"buzzer\", \"child_lock\"], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      await this.setSettings({ led: result[0] == \"on\" ? true : false });\n      await this.setSettings({ buzzer: result[1] == \"on\" ? true : false });\n      await this.setSettings({ childLock: result[2] == \"on\" ? true : false });\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.error(error.message);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      const led = await this.miio.call(\"set_led\", [newSettings.led ? \"on\" : \"off\"], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"buzzer\")) {\n      const buzzer = await this.miio.call(\"set_buzzer\", [newSettings.buzzer ? \"on\" : \"off\"], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"childLock\")) {\n      const childlock = await this.miio.call(\"set_child_lock\", [newSettings.childLock ? \"on\" : \"off\"], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n\n  }\n\n}\n\nmodule.exports = MiAirPurifierDevice;\n"
  },
  {
    "path": "drivers/mi-airpurifier/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Basic Mi Air Purifier (WiFi)\",\n    \"nl\": \"Basis Mi Air Purifier (WiFi)\",\n    \"da\": \"Grundlæggende Mi Air Purifier (WiFi)\",\n    \"de\": \"Basis Mi Luftreiniger (WiFi)\",\n    \"es\": \"Purificador de aire Mi Básico (WiFi)\",\n    \"fr\": \"Purificateur d'air Mi Basique (WiFi)\",\n    \"it\": \"Depuratore d'aria Mi Base (WiFi)\",\n    \"no\": \"Grunnleggende Mi luftrenser (WiFi)\",\n    \"sv\": \"Grundläggande Mi luftrenare (WiFi)\",\n    \"pl\": \"Podstawowy Mi oczyszczacz powietrza (WiFi)\",\n    \"ru\": \"Базовый Mi очиститель воздуха (WiFi)\",\n    \"ko\": \"기본 Mi 공기 청정기 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/mi-airpurifier/assets/images/large.jpg\",\n    \"small\": \"drivers/mi-airpurifier/assets/images/small.jpg\"\n  },\n  \"class\": \"airpurifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"measure_pm25\",\n    \"airpurifier_mode\"\n  ]\n}"
  },
  {
    "path": "drivers/mi-airpurifier/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiAirPurifierDriver extends Driver {}\n\nmodule.exports = MiAirPurifierDriver;"
  },
  {
    "path": "drivers/mi-airpurifier/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"LED\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Buzzer\",\n          \"de\": \"Summerton\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Buzzer\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Buzzer\",\n          \"sv\": \"Buzzer\",\n          \"pl\": \"Buzzer\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"부저\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnelås\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo para niños\",\n          \"fr\": \"Verrouillage enfant\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barnesikring\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Zabezpieczenie dzieci\",\n          \"ru\": \"Блокировка для детей\",\n          \"ko\": \"어린이 잠금 장치\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/mi-airpurifier/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/mi-airpurifier/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/mi-airpurifier/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/mi-aqara-cube/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass MiAqaraCube extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n  \n      /* cube events */\n      if (device.data.status === \"shake_air\") { await this.homey.flow.getDeviceTriggerCard('shake_air_cube').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"tap_twice\") { await this.homey.flow.getDeviceTriggerCard('tap_twice_cube').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"move\") { await this.homey.flow.getDeviceTriggerCard('move_cube').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"flip180\") { await this.homey.flow.getDeviceTriggerCard('flip180_cube').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"flip90\") { await this.homey.flow.getDeviceTriggerCard('flip90_cube').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"free_fall\") { await this.homey.flow.getDeviceTriggerCard('free_fall_cube').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"alert\") { await this.homey.flow.getDeviceTriggerCard('alert_cube').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.rotate) { await this.homey.flow.getDeviceTriggerCard('cubeRotated').trigger(this, {cube_rotated: parseInt(device.data.rotate)}).catch(error => { this.error(error) }); }\n      if (parseInt(device.data.rotate) > 0) { await this.homey.flow.getDeviceTriggerCard('rotate_positive_cube').trigger(this).catch(error => { this.error(error) }); }\n      if (parseInt(device.data.rotate) < 0) { await this.homey.flow.getDeviceTriggerCard('rotate_negative_cube').trigger(this).catch(error => { this.error(error) }); }\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = MiAqaraCube;"
  },
  {
    "path": "drivers/mi-aqara-cube/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Aqara Cube (Gateway)\",\n    \"nl\": \"Mi Aqara Kubus (Gateway)\",\n    \"da\": \"Mi Aqara Cube (Gateway)\",\n    \"de\": \"Mi Aqara Würfel (Gateway)\",\n    \"es\": \"Mi Aqara Cubo (Gateway)\",\n    \"fr\": \"Mi Aqara Cube (Gateway)\",\n    \"it\": \"Mi Aqara Cubo (Gateway)\",\n    \"no\": \"Mi Aqara Cube (Gateway)\",\n    \"sv\": \"Mi Aqara Kub (Gateway)\",\n    \"pl\": \"Mi Aqara Kostka (Gateway)\",\n    \"ru\": \"Mi Aqara Куб (Gateway)\",\n    \"ko\": \"Mi Aqara 큐브 (Gateway)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/mi-aqara-cube/assets/images/large.png\",\n    \"small\": \"/drivers/mi-aqara-cube/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2450\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/mi-aqara-cube/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass MiAqaraCube extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('shake_air_cube');\n    this.homey.flow.getDeviceTriggerCard('tap_twice_cube');\n    this.homey.flow.getDeviceTriggerCard('move_cube');\n    this.homey.flow.getDeviceTriggerCard('flip180_cube');\n    this.homey.flow.getDeviceTriggerCard('flip90_cube');\n    this.homey.flow.getDeviceTriggerCard('free_fall_cube');\n    this.homey.flow.getDeviceTriggerCard('alert_cube');\n    this.homey.flow.getDeviceTriggerCard('cubeRotated');\n    this.homey.flow.getDeviceTriggerCard('rotate_positive_cube');\n    this.homey.flow.getDeviceTriggerCard('rotate_negative_cube');\n\n    this.config = {\n      model: [\"cube\", \"sensor_cube.aqgl01\", \"sensor_cube\"]\n    }\n  }\n\n}\n\nmodule.exports = MiAqaraCube;"
  },
  {
    "path": "drivers/mi-aqara-cube/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"pt\": \"Configurações do Dispositivo\",\n      \"zh\": \"设备设置\",\n      \"ja\": \"デバイス設定\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/mi-button/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass MiButton extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n  \n      /* button events */\n      if (device.data.status === \"click\") { await this.homey.flow.getDeviceTriggerCard('click_single').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"double_click\") { await this.homey.flow.getDeviceTriggerCard('click_double').trigger(this).catch(error => { this.error(error) }); }\n      if (device.data.status === \"long_click_press\") { await this.homey.flow.getDeviceTriggerCard('click_long').trigger(this).catch(error => { this.error(error) }); }\n  \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = MiButton;\n"
  },
  {
    "path": "drivers/mi-button/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Wireless Button (Gateway)\",\n    \"nl\": \"Mi Wireless Button (Gateway)\",\n    \"da\": \"Mi Wireless Knap (Gateway)\",\n    \"de\": \"Mi Drahtloser Knopf (Gateway)\",\n    \"es\": \"Mi Botón Inalámbrico (Gateway)\",\n    \"fr\": \"Mi Bouton Sans Fil (Gateway)\",\n    \"it\": \"Mi Pulsante Senza Fili (Gateway)\",\n    \"no\": \"Mi Trådløs Knapp (Gateway)\",\n    \"sv\": \"Mi Trådlös Knapp (Gateway)\",\n    \"pl\": \"Mi Bezprzewodowy Przycisk (Gateway)\",\n    \"ru\": \"Mi Беспроводная Кнопка (Шлюз)\",\n    \"ko\": \"Mi 무선 버튼 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/mi-button/assets/images/large.png\",\n    \"small\": \"/drivers/mi-button/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2032\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/mi-button/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass MiButton extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('click_single');\n    this.homey.flow.getDeviceTriggerCard('click_double');\n    this.homey.flow.getDeviceTriggerCard('click_long');\n\n    this.config = {\n      model: [\"switch\"]\n    }\n  }\n  \n}\n\nmodule.exports = MiButton;"
  },
  {
    "path": "drivers/mi-button/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración de dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"기기 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/mi-humidifier/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass MiHumidifierDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = MiHumidifierDevice;\n"
  },
  {
    "path": "drivers/mi-humidifier/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Humidifier v1 - Generic (WiFi)\",\n    \"nl\": \"Mi Luchtbevochtiger v1 - Generic (WiFi)\",\n    \"da\": \"Mi Luftfugter v1 - Generisk (WiFi)\",\n    \"de\": \"Mi Luftbefeuchter v1 - Generisch (WiFi)\",\n    \"es\": \"Mi Humidificador v1 - Genérico (WiFi)\",\n    \"fr\": \"Mi Humidificateur v1 - Générique (WiFi)\",\n    \"it\": \"Mi Umidificatore v1 - Generico (WiFi)\",\n    \"no\": \"Mi Luftfukter v1 - Generisk (WiFi)\",\n    \"sv\": \"Mi Luftfuktare v1 - Generisk (WiFi)\",\n    \"pl\": \"Mi Nawilżacz v1 - Ogólny (WiFi)\",\n    \"ru\": \"Mi Увлажнитель v1 - Общий (WiFi)\",\n    \"ko\": \"Mi 가습기 v1 - 일반형 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/mi-humidifier/assets/images/large.jpg\",\n    \"small\": \"drivers/mi-humidifier/assets/images/small.jpg\"\n  },\n  \"class\": \"humidifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"measure_temperature\",\n    \"measure_humidity\"\n  ],\n  \"deprecated\": true\n}"
  },
  {
    "path": "drivers/mi-humidifier/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiHumidifierDriver extends Driver {}\n\nmodule.exports = MiHumidifierDriver;"
  },
  {
    "path": "drivers/mi-humidifier/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/mi-humidifier/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/mi-humidifier/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/mi-humidifier/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/mi-humidifier2/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass MiHumidifier2Device extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n\n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n\n      this.registerCapabilityListener('humidifier2_mode', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.setMode(value);\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async handleDeviceSettings() {\n    try {\n\n      const result = await this.miio.call(\"get_prop\", [\"led_b\", \"buzzer\", \"child_lock\"], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      await this.updateSettingValue(\"led\", result[0].toString());\n      await this.updateSettingValue(\"buzzer\", result[1] == \"on\" ? true : false);\n      await this.updateSettingValue(\"childLock\", result[2] == \"on\" ? true : false);\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.error(error.message);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      const led = await this.miio.call(\"set_led_b\", Number(newSettings.led), { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"buzzer\")) {\n      const buzzer = await this.miio.call(\"set_buzzer\", [newSettings.buzzer ? \"on\" : \"off\"], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"childLock\")) {\n      const childlock = await this.miio.call(\"set_child_lock\", [newSettings.childLock ? \"on\" : \"off\"], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n\n  }\n\n}\n\nmodule.exports = MiHumidifier2Device;\n"
  },
  {
    "path": "drivers/mi-humidifier2/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Humidifier v2 - Generic (WiFi)\",\n    \"nl\": \"Mi Luchtbevochtiger v2 - Generic (WiFi)\",\n    \"da\": \"Mi Luftfugter v2 - Generisk (WiFi)\",\n    \"de\": \"Mi Luftbefeuchter v2 - Generisch (WiFi)\",\n    \"es\": \"Mi Humidificador v2 - Genérico (WiFi)\",\n    \"fr\": \"Mi Humidificateur v2 - Générique (WiFi)\",\n    \"it\": \"Mi Umidificatore v2 - Generico (WiFi)\",\n    \"no\": \"Mi Luftfukter v2 - Generisk (WiFi)\",\n    \"sv\": \"Mi Luftfuktare v2 - Generisk (WiFi)\",\n    \"pl\": \"Mi Nawilżacz v2 - Ogólny (WiFi)\",\n    \"ru\": \"Mi Увлажнитель v2 - Общий (WiFi)\",\n    \"ko\": \"Mi 가습기 v2 - 일반 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/mi-humidifier2/assets/images/large.jpg\",\n    \"small\": \"drivers/mi-humidifier2/assets/images/small.jpg\"\n  },\n  \"class\": \"humidifier\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"measure_temperature\",\n    \"measure_humidity\",\n    \"measure_waterlevel\",\n    \"humidifier2_mode\"\n  ],\n  \"deprecated\": true\n}"
  },
  {
    "path": "drivers/mi-humidifier2/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiHumidifier2Driver extends Driver {}\n\nmodule.exports = MiHumidifier2Driver;\n"
  },
  {
    "path": "drivers/mi-humidifier2/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingen\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"dropdown\",\n        \"value\": \"1\",\n        \"label\": {\n          \"en\": \"LED brightness\",\n          \"nl\": \"LED helderheid\",\n          \"da\": \"LED-ljusstyrke\",\n          \"de\": \"LED-Helligkeit\",\n          \"es\": \"Brillo LED\",\n          \"fr\": \"Luminosité LED\",\n          \"it\": \"Luminosità LED\",\n          \"no\": \"LED-lysstyrke\",\n          \"sv\": \"LED-ljusstyrka\",\n          \"pl\": \"Jasność LED\",\n          \"ru\": \"Яркость светодиода\",\n          \"ko\": \"LED 밝기\"\n        },\n        \"values\": [\n          {\n            \"id\": \"1\",\n            \"label\": {\n              \"en\": \"Bright\",\n              \"nl\": \"Helder\",\n              \"da\": \"Lyst\",\n              \"de\": \"Hell\",\n              \"es\": \"Brillante\",\n              \"fr\": \"Luminosité\",\n              \"it\": \"Luminoso\",\n              \"no\": \"Lys\",\n              \"sv\": \"Ljusstark\",\n              \"pl\": \"Jasny\",\n              \"ru\": \"Яркий\",\n              \"ko\": \"밝음\"\n            }\n          },\n          {\n            \"id\": \"2\",\n            \"label\": {\n              \"en\": \"Dim\",\n              \"nl\": \"Gedimd\",\n              \"da\": \"Dæmpet\",\n              \"de\": \"Gedimmt\",\n              \"es\": \"Tenue\",\n              \"fr\": \"Atténué\",\n              \"it\": \"Soffuso\",\n              \"no\": \"Dempe\",\n              \"sv\": \"Dämpad\",\n              \"pl\": \"Przyciemniony\",\n              \"ru\": \"Тусклый\",\n              \"ko\": \"어두움\"\n            }\n          },\n          {\n            \"id\": \"3\",\n            \"label\": {\n              \"en\": \"Off\",\n              \"nl\": \"Uit\",\n              \"da\": \"Slukket\",\n              \"de\": \"Aus\",\n              \"es\": \"Apagado\",\n              \"fr\": \"Éteint\",\n              \"it\": \"Spento\",\n              \"no\": \"Av\",\n              \"sv\": \"Av\",\n              \"pl\": \"Wyłączony\",\n              \"ru\": \"Выключено\",\n              \"ko\": \"끔\"\n            }\n          }\n        ]\n      },\n      {\n        \"id\": \"buzzer\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Buzzer\",\n          \"nl\": \"Buzzer\",\n          \"da\": \"Summer\",\n          \"de\": \"Summer\",\n          \"es\": \"Zumbador\",\n          \"fr\": \"Sonnerie\",\n          \"it\": \"Cicalino\",\n          \"no\": \"Buzzer\",\n          \"sv\": \"Summer\",\n          \"pl\": \"Brzęczyk\",\n          \"ru\": \"Зуммер\",\n          \"ko\": \"부저\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnelås\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo infantil\",\n          \"fr\": \"Verrouillage enfant\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barnelås\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada rodzicielska\",\n          \"ru\": \"Детский замок\",\n          \"ko\": \"어린이 잠금\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/mi-humidifier2/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/mi-humidifier2/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/mi-humidifier2/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/mi-magnet-sensor/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass MiMagnetSensor extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n  \n      /* alarm_contact */\n      if (device.data.status === \"open\") { await this.updateCapabilityValue(\"alarm_contact\", this.getSetting('inverted') ? false : true); }\n      if (device.data.status === \"close\") { await this.updateCapabilityValue(\"alarm_contact\", this.getSetting('inverted') ? true : false); }\n  \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = MiMagnetSensor;"
  },
  {
    "path": "drivers/mi-magnet-sensor/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Magnet Sensor (Gateway)\",\n    \"nl\": \"Mi magneetsensor (Gateway)\",\n    \"da\": \"Mi Magnet Sensor (Gateway)\",\n    \"de\": \"Mi Magnetsensor (Gateway)\",\n    \"es\": \"Sensor Magnético Mi (Gateway)\",\n    \"fr\": \"Capteur Magnétique Mi (Gateway)\",\n    \"it\": \"Sensore Magnetico Mi (Gateway)\",\n    \"no\": \"Mi Magnet Sensor (Gateway)\",\n    \"sv\": \"Mi Magnet Sensor (Gateway)\",\n    \"pl\": \"Czujnik Magnetyczny Mi (Gateway)\",\n    \"ru\": \"Магнитный датчик Mi (Gateway)\",\n    \"ko\": \"미 자석 센서 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/mi-magnet-sensor/assets/images/large.png\",\n    \"small\": \"/drivers/mi-magnet-sensor/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"alarm_contact\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR1632\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/mi-magnet-sensor/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass MiMagnetSensor extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n    \n    this.config = {\n      model: [\"magnet\"]\n    }\n  }\n  \n}\n\nmodule.exports = MiMagnetSensor;"
  },
  {
    "path": "drivers/mi-magnet-sensor/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User settings\",\n      \"nl\": \"Gebruikersinstellingen\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración de usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"inverted\",\n        \"type\": \"checkbox\",\n        \"label\": {\n          \"en\": \"Inverted alarm\",\n          \"nl\": \"Omgekeerd alarm\",\n          \"da\": \"Ovendvendt alarm\",\n          \"de\": \"Umgekehrter Alarm\",\n          \"es\": \"Alarma invertida\",\n          \"fr\": \"Alarme inversée\",\n          \"it\": \"Allarme inverso\",\n          \"no\": \"Omvendt alarm\",\n          \"sv\": \"Inverterat larm\",\n          \"pl\": \"Odwrócony alarm\",\n          \"ru\": \"Инвертированная тревога\",\n          \"ko\": \"반전 알람\"\n        },\n        \"value\": false\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/mi-motion-sensor/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass MiMotionSensor extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n\n      /* alarm_motion */\n      if (device.data.status === \"motion\") {\n        await this.updateCapabilityValue(\"alarm_motion\", true);\n\n        if (this.timeoutAlarm) { this.homey.clearTimeout(this.timeoutAlarm); }\n\n        this.timeoutAlarm = this.homey.setTimeout(async () => {\n          await this.updateCapabilityValue(\"alarm_motion\", false);\n        }, this.getSetting('alarm_duration_number') * 1000);\n\n      }\n      if (device.data.no_motion) {\n        await this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion'+ device.data.no_motion).trigger(this).catch(error => { this.error(error) });\n      }\n\n      /* measure_luminance */\n      if (device.data.lux) { await this.updateCapabilityValue(\"measure_luminance\", parseInt(device.data.lux)); }\n  \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = MiMotionSensor;"
  },
  {
    "path": "drivers/mi-motion-sensor/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Motion Sensor (Gateway)\",\n    \"nl\": \"Mi bewegingssensor (Gateway)\",\n    \"da\": \"Mi bevægelsessensor (Gateway)\",\n    \"de\": \"Mi Bewegungssensor (Gateway)\",\n    \"es\": \"Mi sensor de movimiento (Gateway)\",\n    \"fr\": \"Mi capteur de mouvement (Gateway)\",\n    \"it\": \"Sensore di movimento Mi (Gateway)\",\n    \"no\": \"Mi bevegelsessensor (Gateway)\",\n    \"sv\": \"Mi rörelsesensor (Gateway)\",\n    \"pl\": \"Czujnik ruchu Mi (Gateway)\",\n    \"ru\": \"Датчик движения Mi (Gateway)\",\n    \"ko\": \"미 모션 센서 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/mi-motion-sensor/assets/images/large.png\",\n    \"small\": \"/drivers/mi-motion-sensor/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"alarm_motion\",\n    \"measure_luminance\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2450\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/mi-motion-sensor/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass MiMotionSensor extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion120');\n    this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion180');\n    this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion300');\n    this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion600');\n    this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion1200');\n    this.homey.flow.getDeviceTriggerCard('motionSensorNoMotion1800');\n\n    this.config = {\n      model: [\"motion\"]\n    }\n  }\n\n}\n\nmodule.exports = MiMotionSensor;"
  },
  {
    "path": "drivers/mi-motion-sensor/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Duration of the motion alarm\",\n      \"nl\": \"Duur van het bewegingsalarm\",\n      \"da\": \"Varighed af bevægelsesalarmen\",\n      \"de\": \"Dauer des Bewegungalarms\",\n      \"es\": \"Duración de la alarma de movimiento\",\n      \"fr\": \"Durée de l'alarme de mouvement\",\n      \"it\": \"Durata dell'allarme di movimento\",\n      \"no\": \"Varighet på bevegelsesalarmen\",\n      \"sv\": \"Längd på rörelsealarm\",\n      \"pl\": \"Czas trwania alarmu ruchu\",\n      \"ru\": \"Длительность тревоги о движении\",\n      \"ko\": \"움직임 경보의 지속 시간\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_duration_number\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Disable after\",\n          \"nl\": \"Uitschakelen na\",\n          \"da\": \"Deaktiver efter\",\n          \"de\": \"Deaktivieren nach\",\n          \"es\": \"Desactivar después de\",\n          \"fr\": \"Désactiver après\",\n          \"it\": \"Disattiva dopo\",\n          \"no\": \"Deaktiver etter\",\n          \"sv\": \"Inaktivera efter\",\n          \"pl\": \"Wyłącz po\",\n          \"ru\": \"Отключить через\",\n          \"ko\": \"다음 후 비활성화\"\n        },\n        \"hint\": {\n          \"en\": \"Here you can specify after what time the alarm signal from the motion sensor will be stopped, if a motion is detected it is not detected. Usually this is for 60 seconds, you can set from 5 to 86400 seconds. \\n \\n Attention! Values less than 60 seconds are relevant only for independently modified sensors that have the ability to transmit information about the movement with a frequency of 5 seconds.\",\n          \"nl\": \"Hier kunt u opgeven hoe laat het alarmsignaal van de bewegingssensor wordt gestopt, als een beweging wordt gedetecteerd, wordt deze niet gedetecteerd. Gewoonlijk is dit 60 seconden, u kunt 5 tot 86400 seconden instellen.  n  n Let op! Waarden minder dan 60 seconden zijn alleen relevant voor onafhankelijk aangepaste sensoren die de mogelijkheid hebben om informatie over de beweging te verzenden met een frequentie van 5 seconden.\",\n          \"da\": \"Her kan du angive, hvornår alarmsignalet fra bevægelsessensorer skal stoppes, hvis en bevægelse detekteres. Normalt er dette 60 sekunder, du kan indstille fra 5 til 86400 sekunder. \\n \\n Opmærksomhed! Værdier mindre end 60 sekunder er kun relevante for selvstændigt modificerede sensorer, der har mulighed for at transmittere information om bevægelsen med en frekvens på 5 sekunder.\",\n          \"de\": \"Hier können Sie angeben, nach welcher Zeit das Alarmsignal vom Bewegungssensor gestoppt wird, wenn eine Bewegung erkannt wird. Normalerweise dauert dies 60 Sekunden. Sie können von 5 bis 86400 Sekunden einstellen. \\n \\n Achtung! Werte unter 60 Sekunden sind nur für unabhängig modifizierte Sensoren relevant, die in der Lage sind, Bewegungsinformationen mit einer Frequenz von 5 Sekunden zu senden.\",\n          \"es\": \"Aquí puede especificar después de cuánto tiempo se detendrá la señal de alarma del sensor de movimiento, si se detecta un movimiento no se detecta. Por lo general, esto es durante 60 segundos, puede configurar de 5 a 86400 segundos. \\n \\n ¡Atención! Los valores inferiores a 60 segundos son relevantes solo para sensores modificados de forma independiente que tienen la capacidad de transmitir información sobre el movimiento con una frecuencia de 5 segundos.\",\n          \"fr\": \"Ici, vous pouvez spécifier après combien de temps le signal d'alarme du détecteur de mouvement sera arrêté, si un mouvement est détecté, il n'est pas détecté. En général, cela dure 60 secondes, vous pouvez régler de 5 à 86400 secondes. \\n \\n Attention ! Les valeurs inférieures à 60 secondes ne sont pertinentes que pour les détecteurs modifiés indépendamment qui ont la capacité de transmettre des informations sur les mouvements avec une fréquence de 5 secondes.\",\n          \"it\": \"Qui puoi specificare dopo quanto tempo il segnale di allarme dal sensore di movimento verrà interrotto, se viene rilevato un movimento non viene rilevato. Di solito è per 60 secondi, puoi impostare da 5 a 86400 secondi. \\n \\n Attenzione! I valori inferiori a 60 secondi sono rilevanti solo per sensori modificati indipendentemente che hanno la capacità di trasmettere informazioni sul movimento con una frequenza di 5 secondi.\",\n          \"no\": \"Her kan du angi etter hvor lang tid alarmsignalet fra bevegelsessensoren vil bli stoppet, hvis en bevegelse blir oppdaget, blir det ikke oppdaget. Vanligvis er dette i 60 sekunder, du kan stille fra 5 til 86400 sekunder. \\n \\n Oppmerksomhet! Verdier mindre enn 60 sekunder er bare relevante for uavhengig modifiserte sensorer som har mulighet til å overføre informasjon om bevegelsen med en frekvens på 5 sekunder.\",\n          \"sv\": \"Här kan du specificera efter hur lång tid larmsignalen från rörelsesensorn ska stoppas, om en rörelse detekteras som inte detekteras. Vanligtvis är detta i 60 sekunder, du kan ställa från 5 till 86400 sekunder. \\n \\n Observera! Värden mindre än 60 sekunder är endast relevanta för oberoende modifierade sensorer som har möjlighet att överföra information om rörelsen med en frekvens på 5 sekunder.\",\n          \"pl\": \"Tutaj możesz określić, po jakim czasie sygnał alarmowy z czujnika ruchu zostanie zatrzymany, jeśli ruch zostanie wykryty, nie jest wykrywany. Zwykle trwa to 60 sekund, możesz ustawić od 5 do 86400 sekund. \\n \\n Uwaga! Wartości poniżej 60 sekund dotyczą wyłącznie samodzielnie zmodyfikowanych czujników, które mogą przesyłać informacje o ruchu z częstotliwością 5 sekund.\",\n          \"ru\": \"Здесь вы можете указать, через какое время сигнал тревоги от датчика движения будет остановлен, если движение обнаружено, оно не обнаруживается. Обычно это занимает 60 секунд, вы можете установить от 5 до 86400 секунд. \\n \\n Внимание! Значения менее 60 секунд актуальны только для независимо модифицированных датчиков, которые могут передавать информацию о движении с частотой 5 секунд.\",\n          \"ko\": \"여기서 움직임 센서의 경보 신호가 중지되는 시간을 지정할 수 있습니다. 움직임이 감지된 경우 감지되지 않습니다. 보통 60초 동안이며, 5초에서 86400초까지 설정할 수 있습니다. \\n \\n 주의! 60초 미만의 값은 5초 주기로 움직임 정보를 전송할 수 있는 독립적으로 수정된 센서에만 해당됩니다.\"\n        },\n        \"value\": 60,\n        \"attr\": {\n          \"min\": 5,\n          \"max\": 86400\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/mi-plug/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass MiPlug extends Device {\n\n  async registerCapabilities() {\n    this.registerCapabilityListener('onoff', async (value) => {\n      try {\n        return await this.homey.app.mihub.sendWrite(this.data.sid, { channel_0: value ? \"on\" : \"off\" });\n      } catch (error) {\n        this.error(error);\n      }\n    });\n  }\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* onoff */\n      if (device.data.status === \"on\") { await this.updateCapabilityValue(\"onoff\", true); }\n      if (device.data.status === \"off\") { await this.updateCapabilityValue(\"onoff\", false); }\n\n      /* measure_power */\n      if (device.data.load_power) {\n        await this.updateCapabilityValue(\"measure_power\", parseInt(device.data.load_power));\n      }\n\n      /* meter_power */\n      if (device.data.power_consumed) {\n        await this.updateCapabilityValue(\"meter_power\", parseFloat(device.data.power_consumed / 1000));\n      }\n  \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = MiPlug;"
  },
  {
    "path": "drivers/mi-plug/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Smart Plug (Gateway)\",\n    \"nl\": \"Mi Smart Plug (Gateway)\",\n    \"da\": \"Mi Smart Plug (Gateway)\",\n    \"de\": \"Mi Smart Plug (Gateway)\",\n    \"es\": \"Mi Enchufe Inteligente (Gateway)\",\n    \"fr\": \"Mi Prise Intelligente (Gateway)\",\n    \"it\": \"Mi Presa Intelligente (Gateway)\",\n    \"no\": \"Mi Smart Plugg (Gateway)\",\n    \"sv\": \"Mi Smart Plugg (Gateway)\",\n    \"pl\": \"Mi Inteligentny Wtyczka (Gateway)\",\n    \"ru\": \"Mi Умная Розетка (Гейтвей)\",\n    \"ko\": \"Mi 스마트 플러그 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/mi-plug/assets/images/large.png\",\n    \"small\": \"/drivers/mi-plug/assets/images/small.png\"\n  },\n  \"class\": \"socket\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"meter_power\",\n    \"measure_power\"\n  ]\n}"
  },
  {
    "path": "drivers/mi-plug/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass MiPlug extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.config = {\n      model: [\"plug\"]\n    }\n\n  }\n\n}\n\nmodule.exports = MiPlug;\n"
  },
  {
    "path": "drivers/mi-plug/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Ajustes de dispositivo\",\n      \"fr\": \"Réglages de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"디바이스 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"gatewaySid\",\n        \"$extends\": \"gatewaySid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/mi-power-plug/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass PowerPlugDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = PowerPlugDevice;\n"
  },
  {
    "path": "drivers/mi-power-plug/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Power Plug (WiFi)\",\n    \"nl\": \"Mi Power Plug (WiFi)\",\n    \"da\": \"Mi Power Plug (WiFi)\",\n    \"de\": \"Mi Power Plug (WiFi)\",\n    \"es\": \"Mi Power Plug (WiFi)\",\n    \"fr\": \"Mi Power Plug (WiFi)\",\n    \"it\": \"Mi Power Plug (WiFi)\",\n    \"no\": \"Mi Power Plug (WiFi)\",\n    \"sv\": \"Mi Power Plug (WiFi)\",\n    \"pl\": \"Mi Power Plug (WiFi)\",\n    \"ru\": \"Mi Power Plug (WiFi)\",\n    \"ko\": \"Mi Power Plug (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/mi-power-plug/assets/images/large.jpg\",\n    \"small\": \"drivers/mi-power-plug/assets/images/small.jpg\"\n  },\n  \"class\": \"socket\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\"\n  ],\n  \"deprecated\": true\n}"
  },
  {
    "path": "drivers/mi-power-plug/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass PowerPlugDriver extends Driver {}\n\nmodule.exports = PowerPlugDriver;"
  },
  {
    "path": "drivers/mi-power-plug/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/mi-power-plug/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/mi-power-plug/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/mi-power-plug/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/mi-power-strip/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass PowerStripDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = PowerStripDevice;\n"
  },
  {
    "path": "drivers/mi-power-strip/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Power Strip Generic (WiFi)\",\n    \"nl\": \"Mi Power Strip Generic (WiFi)\",\n    \"da\": \"Mi Power Strip Generisk (WiFi)\",\n    \"de\": \"Mi Power Strip Generic (WiFi)\",\n    \"es\": \"Mi Power Strip Genérico (WiFi)\",\n    \"fr\": \"Mi Power Strip Générique (WiFi)\",\n    \"it\": \"Mi Power Strip Generico (WiFi)\",\n    \"no\": \"Mi Power Strip Generisk (WiFi)\",\n    \"sv\": \"Mi Power Strip Generisk (WiFi)\",\n    \"pl\": \"Mi Power Strip Generic (WiFi)\",\n    \"ru\": \"Mi Power Strip Generic (WiFi)\",\n    \"ko\": \"Mi 파워 스트립 일반 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/mi-power-strip/assets/images/large.jpg\",\n    \"small\": \"drivers/mi-power-strip/assets/images/small.jpg\"\n  },\n  \"class\": \"socket\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"measure_power\",\n    \"meter_power\"\n  ]\n}"
  },
  {
    "path": "drivers/mi-power-strip/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass PowerStripDriver extends Driver {}\n\nmodule.exports = PowerStripDriver;"
  },
  {
    "path": "drivers/mi-power-strip/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/mi-power-strip/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/mi-power-strip/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/mi-power-strip/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/mi-robot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass MiRobotDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('statusVacuum');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoffVacuumcleaner.bind(this));\n      this.registerCapabilityListener(\"vacuumcleaner_state\", this.onCapabilityVacuumcleanerState.bind(this));\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n      var battery = this.miio.getState('batteryLevel');\n      var fanspeed = this.miio.getState('fanSpeed');\n\n      if (this.miio.property('state') == 'charging' && battery !== 100) {\n        var onoff = false;\n        var state = 'charging';\n      } else if (this.miio.property('state') == 'docking' || this.miio.property('state') == 'full' || this.miio.property('state') == 'returning' || this.miio.property('state') == 'waiting' || this.miio.property('state') == 'charging') {\n        var onoff = false;\n        var state = 'docked';\n      } else if (this.miio.property('state') == 'cleaning' || this.miio.property('state') == 'zone-cleaning') {\n        var onoff = true;\n        var state = 'cleaning';\n      } else if (this.miio.property('state') == 'spot-cleaning') {\n        var onoff = true;\n        var state = 'spot_cleaning';\n      } else {\n        var onoff = false;\n        var state = 'stopped';\n      }\n\n      if (this.getCapabilityValue('onoff') != onoff) {\n        await this.setCapabilityValue('onoff', onoff);\n      }\n      if (this.getCapabilityValue('measure_battery') != battery) {\n        await this.setCapabilityValue('measure_battery', this.util.clamp(battery, 0, 100));\n      }\n      if (this.getStoreValue('fanspeed') != fanspeed) {\n        await this.setStoreValue('fanspeed', fanspeed);\n      }\n\n      if (this.getCapabilityValue('vacuumcleaner_state') !== state) {\n        await this.setCapabilityValue('vacuumcleaner_state', state);\n        await this.homey.flow.getDeviceTriggerCard('statusVacuum').trigger(this, {\"status\": this.miio.property('state')}).catch(error => { this.error(error) });\n      }\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = MiRobotDevice;\n"
  },
  {
    "path": "drivers/mi-robot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Basic Vacuum Cleaner (WiFi)\",\n    \"nl\": \"Basis Vacuum Cleaner (WiFi)\",\n    \"da\": \"Basisstøvsuger (WiFi)\",\n    \"de\": \"Einfacher Staubsauger (WiFi)\",\n    \"es\": \"Aspiradora Básica (WiFi)\",\n    \"fr\": \"Aspirateur de base (WiFi)\",\n    \"it\": \"Aspirapolvere base (WiFi)\",\n    \"no\": \"Grunnleggende støvsuger (WiFi)\",\n    \"sv\": \"Grundläggande dammsugare (WiFi)\",\n    \"pl\": \"Podstawowy odkurzacz (WiFi)\",\n    \"ru\": \"Базовый пылесос (WiFi)\",\n    \"ko\": \"기본 청소기 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/mi-robot/assets/images/large.jpg\",\n    \"small\": \"drivers/mi-robot/assets/images/small.jpg\"\n  },\n  \"class\": \"vacuumcleaner\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"vacuumcleaner_state\",\n    \"measure_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"INTERNAL\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/mi-robot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiRobotDriver extends Driver {}\n\nmodule.exports = MiRobotDriver;"
  },
  {
    "path": "drivers/mi-robot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"pt\": \"Configurações do dispositivo\",\n      \"ja\": \"デバイス設定\",\n      \"zh\": \"设备设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/mi-robot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/mi-robot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/mi-robot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/mi-temperature-humidity-sensor/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass MiTemperatureHumiditySensor extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n      \n      const settings = this.getSettings();\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n  \n     /* measure_humidity */\n     if (device.data.humidity) { await this.updateCapabilityValue(\"measure_humidity\", parseFloat(parseFloat(device.data.humidity / 100).toFixed(1))); }\n\n     /* measure_temperature */\n      if (device.data.temperature) {\n        if (settings.addOrTakeOffset === \"add\") {\n          await this.updateCapabilityValue(\"measure_temperature\", parseFloat(parseFloat(device.data.temperature / 100 + parseFloat(settings.offset)).toFixed(1)));\n        } else if (settings.addOrTakeOffset === \"take\") {\n          await this.updateCapabilityValue(\"measure_temperature\", parseFloat(parseFloat(device.data.temperature / 100 - parseFloat(settings.offset)).toFixed(1)));\n        }\n      }\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = MiTemperatureHumiditySensor;"
  },
  {
    "path": "drivers/mi-temperature-humidity-sensor/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Temperature & Humidity Sensor (Gateway)\",\n    \"nl\": \"Mi temperatuur & luchtvochtigheid sensor (Gateway)\",\n    \"da\": \"Mi Temperatur- og Fugtighedssensor (Gateway)\",\n    \"de\": \"Mi Temperatur- und Feuchtigkeitssensor (Gateway)\",\n    \"es\": \"Mi Sensor de Temperatura y Humedad (Gateway)\",\n    \"fr\": \"Capteur de Température et d'Humidité Mi (Gateway)\",\n    \"it\": \"Sensore di Temperatura e Umidità Mi (Gateway)\",\n    \"no\": \"Mi Temperatur- og Fuktighetssensor (Gateway)\",\n    \"sv\": \"Mi Temperatur- och Fuktighetssensor (Gateway)\",\n    \"pl\": \"Czujnik Temperatury i Wilgotności Mi (Gateway)\",\n    \"ru\": \"Датчик температуры и влажности Mi (Gateway)\",\n    \"ko\": \"Mi 온습도 센서 (Gateway)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/mi-temperature-humidity-sensor/assets/images/large.png\",\n    \"small\": \"/drivers/mi-temperature-humidity-sensor/assets/images/small.png\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"measure_temperature\",\n    \"measure_humidity\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR2032\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/mi-temperature-humidity-sensor/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass MiTemperatureHumiditySensor extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.config = {\n      model: [\"sensor_ht\"]\n    }\n\n  }\n\n}\n\nmodule.exports = MiTemperatureHumiditySensor;"
  },
  {
    "path": "drivers/mi-temperature-humidity-sensor/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Offset settings\",\n      \"nl\": \"Offset instellingen\",\n      \"da\": \"Offset indstillinger\",\n      \"de\": \"Offset Einstellungen\",\n      \"es\": \"Configuraciones de compensación\",\n      \"fr\": \"Paramètres de décalage\",\n      \"it\": \"Impostazioni offset\",\n      \"no\": \"Forskyvningsinnstillinger\",\n      \"sv\": \"Förskjutningsinställningar\",\n      \"pl\": \"Ustawienia przesunięcia\",\n      \"ru\": \"Настройки смещения\",\n      \"ko\": \"오프셋 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"addOrTakeOffset\",\n        \"type\": \"radio\",\n        \"label\": {\n          \"en\": \"Offset\",\n          \"nl\": \"Offset\",\n          \"da\": \"Offset\",\n          \"de\": \"Offset\",\n          \"es\": \"Compensación\",\n          \"fr\": \"Décalage\",\n          \"it\": \"Offset\",\n          \"no\": \"Forskyvning\",\n          \"sv\": \"Förskjutning\",\n          \"pl\": \"Przesunięcie\",\n          \"ru\": \"Смещение\",\n          \"ko\": \"오프셋\"\n        },\n        \"value\": \"add\",\n        \"values\": [\n          {\n            \"id\": \"add\",\n            \"label\": {\n              \"en\": \"Add offset\",\n              \"nl\": \"Offset toevoegen\",\n              \"da\": \"Tilføj offset\",\n              \"de\": \"Offset hinzufügen\",\n              \"es\": \"Agregar compensación\",\n              \"fr\": \"Ajouter un décalage\",\n              \"it\": \"Aggiungi offset\",\n              \"no\": \"Legg til forskyvning\",\n              \"sv\": \"Lägg till förskjutning\",\n              \"pl\": \"Dodaj przesunięcie\",\n              \"ru\": \"Добавить смещение\",\n              \"ko\": \"오프셋 추가\"\n            }\n          },\n          {\n            \"id\": \"take\",\n            \"label\": {\n              \"en\": \"Minus offset\",\n              \"nl\": \"Offset aftrekken\",\n              \"da\": \"Minus offset\",\n              \"de\": \"Offset abziehen\",\n              \"es\": \"Restar compensación\",\n              \"fr\": \"Moins offset\",\n              \"it\": \"Sottrai offset\",\n              \"no\": \"Minus forskyvning\",\n              \"sv\": \"Minus förskjutning\",\n              \"pl\": \"Odejmij przesunięcie\",\n              \"ru\": \"Минус смещение\",\n              \"ko\": \"오프셋 빼기\"\n            }\n          }\n        ]\n      },\n      {\n        \"id\": \"offset\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Offset\",\n          \"nl\": \"Offset\",\n          \"da\": \"Offset\",\n          \"de\": \"Offset\",\n          \"es\": \"Compensación\",\n          \"fr\": \"Décalage\",\n          \"it\": \"Offset\",\n          \"no\": \"Forskyvning\",\n          \"sv\": \"Förskjutning\",\n          \"pl\": \"Przesunięcie\",\n          \"ru\": \"Смещение\",\n          \"ko\": \"오프셋\"\n        },\n        \"value\": 0,\n        \"min\": 0,\n        \"max\": 5\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuraciones del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/natgas_sensor/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass NatSensorDevice extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n\n      /* alarm_co */\n      if (device.data.alarm == \"1\") {\n        await this.updateCapabilityValue(\"alarm_co\", true);\n\n        if (this.timeoutAlarm) { this.homey.clearTimeout(this.timeoutAlarm); }\n\n        this.timeoutAlarm = setTimeout(async () => {\n          await this.updateCapabilityValue(\"alarm_co\", false);\n        }, this.getSetting('alarm_duration_number') * 1000);\n        \n      }\n\n      /* measure_gas_density */\n      if (device.data.density) { await this.updateCapabilityValue(\"measure_gas_density\", parseInt(device.data.density)); }\n  \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = NatSensorDevice;"
  },
  {
    "path": "drivers/natgas_sensor/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mijia Gas Leak Detector (Gateway)\",\n    \"nl\": \"Mijia Gas Leak Detector (Gateway)\",\n    \"da\": \"Mijia Gaslæksensor (Gateway)\",\n    \"de\": \"Mijia Gasleckdetektor (Gateway)\",\n    \"es\": \"Detector de Fugas de Gas Mijia (Gateway)\",\n    \"fr\": \"Détecteur de Fuites de Gaz Mijia (Gateway)\",\n    \"it\": \"Rilevatore di Perdite di Gas Mijia (Gateway)\",\n    \"no\": \"Mijia Gasslekkasjedetektor (Gateway)\",\n    \"sv\": \"Mijia Gassläckdetektor (Gateway)\",\n    \"pl\": \"Czujnik Wycieków Gazu Mijia (Gateway)\",\n    \"ru\": \"Датчик Утечки Газа Mijia (Gateway)\",\n    \"ko\": \"Mijia 가스 누출 감지기 (Gateway)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/natgas_sensor/assets/images/large.jpg\",\n    \"small\": \"/drivers/natgas_sensor/assets/images/small.jpg\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"alarm_co\",\n    \"measure_gas_density\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"capabilitiesOptions\": {\n    \"alarm_co\": {\n      \"title\": {\n        \"en\": \"Gas Alarm\",\n        \"nl\": \"Gasalarm\",\n        \"da\": \"Gasalarm\",\n        \"de\": \"Gasalarm\",\n        \"es\": \"Alarma de gas\",\n        \"fr\": \"Alarme de gaz\",\n        \"it\": \"Allarme gas\",\n        \"no\": \"Gassalarm\",\n        \"sv\": \"Gaslarm\",\n        \"pl\": \"Alarm Gazowy\",\n        \"ru\": \"Газовая Сигнализация\",\n        \"ko\": \"가스 경보\"\n      }\n    }\n  },\n  \"energy\": {\n    \"batteries\": [\n      \"CR2450\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/natgas_sensor/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass NatSensorDriver extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.config = {\n      model: [\"natgas\", \"sensor_natgas\"]\n    }\n  }\n\n}\n\nmodule.exports = NatSensorDriver;"
  },
  {
    "path": "drivers/natgas_sensor/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Duration of the natural gas detected alarm in seconds\",\n      \"nl\": \"Duur van het gas gedetecteerd alarm in seconden\",\n      \"da\": \"Varighed af detekteret naturgasalarm i sekunder\",\n      \"de\": \"Dauer des erkannten Erdgasalarm in Sekunden\",\n      \"es\": \"Duración de la alarma de gas natural detectado en segundos\",\n      \"fr\": \"Durée de l'alarme de gaz naturel détecté en secondes\",\n      \"it\": \"Durata dell'allarme di gas naturale rilevato in secondi\",\n      \"no\": \"Varighet av naturliggassalarm oppdaget i sekunder\",\n      \"sv\": \"Varaktighet av detekterat naturgaslarm i sekunder\",\n      \"pl\": \"Czas trwania alarmu wykrycia gazu ziemnego w sekundach\",\n      \"ru\": \"Продолжительность сработавшей тревоги по обнаружению природного газа в секундах\",\n      \"ko\": \"천연가스 감지 경보 지속 시간 (초)\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_duration_number\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Disable after\",\n          \"nl\": \"Uitschakelen na\",\n          \"da\": \"Deaktiver efter\",\n          \"de\": \"Deaktivieren nach\",\n          \"es\": \"Desactivar después de\",\n          \"fr\": \"Désactiver après\",\n          \"it\": \"Disabilita dopo\",\n          \"no\": \"Deaktiver etter\",\n          \"sv\": \"Inaktivera efter\",\n          \"pl\": \"Wyłącz po\",\n          \"ru\": \"Отключить через\",\n          \"ko\": \"비활성화 시간\"\n        },\n        \"value\": 60,\n        \"attr\": {\n          \"min\": 60,\n          \"max\": 86400\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/pet_waterer_xiaomi/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/xiaomi.pet_waterer.iv02 // Xiaomi Smart Pet Fountain 2\n\nconst mapping = {\n    'xiaomi.pet_waterer.iv02': 'mapping_iv02'\n};\n\nconst chargingStates = {\n    0: 'Not charging',\n    1: 'Charging',\n    2: 'Charge full'\n};\n\nconst properties = {\n    mapping_iv02: {\n        get_properties: [\n            { did: 'onoff', siid: 2, piid: 1 }, // Power\n            { did: 'fault', siid: 2, piid: 2 }, // Error\n            { did: 'status', siid: 2, piid: 3 }, // Status (1=Waterless, 2=Watering)\n            { did: 'mode', siid: 2, piid: 4 }, // Mode (0=Auto, 1=Interval, 2=Constant)\n            { did: 'out_water_interval_15', siid: 2, piid: 7 }, // Out water interval (step 15)\n            { did: 'water_shortage_status', siid: 2, piid: 10 }, // Water shortage (bool)\n            { did: 'out_water_interval_5', siid: 2, piid: 11 }, // Out water interval (step 5)\n            { did: 'filter_life_level', siid: 3, piid: 1 }, // Filter life (%)\n            { did: 'filter_left_time', siid: 3, piid: 2 }, // Filter left time (days)\n            { did: 'battery_level', siid: 5, piid: 1 }, // Battery level (%)\n            { did: 'charging_state', siid: 5, piid: 2 }, // Charging state\n            { did: 'low_battery', siid: 9, piid: 5 }, // Insufficient power\n            { did: 'usb_insert_state', siid: 9, piid: 6 } // USB plug-in status\n        ],\n        set_properties: {\n            onoff: { siid: 2, piid: 1 },\n            mode: { siid: 2, piid: 4 }\n        }\n    }\n};\n\n// Fountain modes (for capability petwaterdispenser_mmgg_mode_3)\nconst modes_iv02 = {\n    0: 'Auto',\n    1: 'Interval',\n    2: 'Constant'\n};\n\nclass PetwaterdispenserXiaomiDevice extends Device {\n    normalizeBooleanValue(value) {\n        if (typeof value === 'boolean') return value;\n        if (typeof value === 'number') return value === 1;\n        if (typeof value === 'string') {\n            const normalized = value.toLowerCase();\n            return normalized === '1' || normalized === 'true' || normalized === 'on';\n        }\n        return false;\n    }\n\n    getPropertyDefinition(did) {\n        return this.deviceProperties.get_properties.find((property) => property.did === did);\n    }\n\n    getPropertyResult(result, did) {\n        const property = this.getPropertyDefinition(did);\n        if (!property) return undefined;\n\n        return result.find((entry) => {\n            if (entry.did === did) return true;\n            return entry.siid === property.siid && entry.piid === property.piid;\n        });\n    }\n\n    // Helper method to pretty print properties (similar to the reference device)\n    prettyPrintProperties(result, propertyDefs) {\n        try {\n            const formatted = result.map((item) => {\n                const def = propertyDefs.find((p) => p.siid === item.siid && p.piid === item.piid);\n                return {\n                    did: def ? def.did : `unknown_${item.siid}_${item.piid}`,\n                    siid: item.siid,\n                    piid: item.piid,\n                    value: item.value,\n                    code: item.code\n                };\n            });\n            return JSON.stringify(formatted, null, 2);\n        } catch (error) {\n            this.error('Error formatting properties:', error);\n            return JSON.stringify(result);\n        }\n    }\n\n    async onInit() {\n        try {\n            if (!this.util) this.util = new Util({ homey: this.homey });\n\n            this.log('Xiaomi Smart Pet Fountain 2 initializing...');\n\n            // Use mapping/properties for model (future-proof)\n            this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['xiaomi.pet_waterer.iv02']];\n\n            this.bootSequence();\n\n            // FLOW TRIGGER CARDS\n            this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n            // Register flow action card for setting mode\n            this.homey.flow.getActionCard('petwaterdispenserMmggMode_Xiaomi').registerRunListener(async (args, state) => {\n                this.log(`[flow] Setting fountain mode to: ${args.mode} (${modes_iv02[args.mode]})`);\n                return await this.triggerCapabilityListener('petwaterdispenser_mmgg_mode_3', args.mode);\n            });\n\n            // Capability listeners\n            this.registerCapabilityListener('onoff', async (value) => {\n                try {\n                    this.log(`[onoff] Setting power to: ${value}`);\n                    if (this.miio) {\n                        return await this.miio.call(\n                            'set_properties',\n                            [\n                                {\n                                    siid: this.deviceProperties.set_properties.onoff.siid,\n                                    piid: this.deviceProperties.set_properties.onoff.piid,\n                                    value: !!value\n                                }\n                            ],\n                            { retries: 1 }\n                        );\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((e) => this.error(e));\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('petwaterdispenser_mmgg_mode_3', async (value) => {\n                try {\n                    this.log(`[mode] Setting mode to: ${value}`);\n                    if (this.miio) {\n                        return await this.miio.call(\n                            'set_properties',\n                            [\n                                {\n                                    siid: this.deviceProperties.set_properties.mode.siid,\n                                    piid: this.deviceProperties.set_properties.mode.piid,\n                                    value: +value\n                                }\n                            ],\n                            { retries: 1 }\n                        );\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((e) => this.error(e));\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n        } catch (error) {\n            this.error(error);\n        }\n    }\n\n    async onSettings({ oldSettings, newSettings, changedKeys }) {\n        if (changedKeys.includes('address') || changedKeys.includes('token') || changedKeys.includes('polling')) {\n            this.refreshDevice();\n        }\n        return Promise.resolve(true);\n    }\n\n    async retrieveDeviceData() {\n        try {\n            const result = await this.miio.call('get_properties', this.deviceProperties.get_properties, { retries: 1 });\n            if (!this.getAvailable()) await this.setAvailable();\n\n            // Store previous values to compare\n            const prevProps = this._lastPropertyValues || {};\n\n            // Extract current values into a simple object for comparison\n            const resultValues = {};\n            for (const def of this.deviceProperties.get_properties) {\n                const found = result.find((obj) => obj.siid === def.siid && obj.piid === def.piid);\n                resultValues[def.did] = found ? found.value : null;\n            }\n\n            // Compare all props, only log if any value changed\n            let valueChanged = false;\n            for (const key of Object.keys(resultValues)) {\n                if (prevProps[key] !== resultValues[key]) {\n                    valueChanged = true;\n                    break;\n                }\n            }\n            if (valueChanged) {\n                this.log('Raw property data: ' + this.prettyPrintProperties(result, this.deviceProperties.get_properties));\n            }\n            this._lastPropertyValues = resultValues;\n\n            const onoff = this.getPropertyResult(result, 'onoff');\n            const error_value = this.getPropertyResult(result, 'fault');\n            const mode = this.getPropertyResult(result, 'mode');\n            const water_shortage = this.getPropertyResult(result, 'water_shortage_status');\n            const filter_life = this.getPropertyResult(result, 'filter_life_level');\n            const filter_days_left = this.getPropertyResult(result, 'filter_left_time');\n            const battery_level = this.getPropertyResult(result, 'battery_level');\n            const charging_state = this.getPropertyResult(result, 'charging_state');\n            const low_battery = this.getPropertyResult(result, 'low_battery');\n            const usb_insert_state = this.getPropertyResult(result, 'usb_insert_state');\n\n            /* Capabilities */\n            if (onoff) {\n                await this.updateCapabilityValue('onoff', this.normalizeBooleanValue(onoff.value));\n            }\n\n            if (mode && this.getCapabilityValue('petwaterdispenser_mmgg_mode_3') !== mode.value.toString()) {\n                const prev_mode = this.getCapabilityValue('petwaterdispenser_mmgg_mode_3');\n                await this.setCapabilityValue('petwaterdispenser_mmgg_mode_3', mode.value.toString());\n                await this.homey.flow\n                    .getDeviceTriggerCard('triggerModeChanged')\n                    .trigger(this, {\n                        new_mode: modes_iv02[mode.value],\n                        previous_mode: modes_iv02[+prev_mode]\n                    })\n                    .catch((err) => this.error(err));\n                this.log(`[diagnostics] Device mode changed: ${mode.value}`);\n            }\n\n            if (water_shortage) {\n                await this.updateCapabilityValue('alarm_tank_empty', !!water_shortage.value);\n            }\n\n            if (battery_level && typeof battery_level.value === 'number') {\n                const batteryPercentage = this.util.clamp(battery_level.value, 0, 100);\n                const isLowBattery = low_battery ? this.normalizeBooleanValue(low_battery.value) : batteryPercentage <= 20;\n\n                await this.updateCapabilityValue('measure_battery', batteryPercentage);\n                await this.updateCapabilityValue('alarm_battery', isLowBattery);\n            } else if (low_battery) {\n                await this.updateCapabilityValue('alarm_battery', this.normalizeBooleanValue(low_battery.value));\n            }\n\n            if (usb_insert_state) {\n                const powerSource = this.normalizeBooleanValue(usb_insert_state.value) ? 'Connected to power' : 'Battery powered';\n                await this.updateSettingValue('power_source', powerSource);\n            }\n\n            if (charging_state && chargingStates[charging_state.value] !== undefined) {\n                await this.updateSettingValue('charging_state', chargingStates[charging_state.value]);\n            }\n\n            if (error_value) {\n                const errorMsg = error_value.value === 0 ? 'No Error' : `Error code: ${error_value.value}`;\n                await this.updateSettingValue('error', errorMsg);\n                this.log(`[diagnostics] Device error status: ${errorMsg}`);\n            }\n\n            // Update filter status as capabilities\n            if (filter_life) {\n                await this.updateSettingValue('filter_life_remaining', `${filter_life.value}%`);\n                await this.updateCapabilityValue('measure_filter_life', filter_life.value);\n            }\n\n            if (filter_days_left) {\n                await this.setSettings({ filter_days_left: filter_days_left.value });\n                await this.updateCapabilityValue('measure_filter_days_left', filter_days_left.value);\n            }\n        } catch (error) {\n            this.homey.clearInterval(this.pollingInterval);\n            if (this.getAvailable()) {\n                this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((e) => this.error(e));\n            }\n            this.homey.setTimeout(() => this.createDevice(), 60000);\n            this.error(error.message);\n        }\n    }\n}\n\nmodule.exports = PetwaterdispenserXiaomiDevice;\n"
  },
  {
    "path": "drivers/pet_waterer_xiaomi/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Xiaomi Smart Pet Fountain\",\n    \"nl\": \"Xiaomi Slimme Huisdierfontein\",\n    \"da\": \"Xiaomi Smart Kæledyrsfountain\",\n    \"de\": \"Xiaomi Smarter Haustierbrunnen\",\n    \"es\": \"Fuente Inteligente Xiaomi para Mascotas\",\n    \"fr\": \"Fontaine Intelligente Xiaomi pour Animaux\",\n    \"it\": \"Fontana Intelligente Xiaomi per Animali\",\n    \"no\": \"Xiaomi Smart Kjæledyrfontene\",\n    \"sv\": \"Xiaomi Smart Husdjursfontän\",\n    \"pl\": \"Xiaomi Inteligentna Fontanna dla Zwierząt\",\n    \"ru\": \"Умный фонтан Xiaomi для домашних животных\",\n    \"ko\": \"샤오미 스마트 펫 분수대\"\n  },\n  \"images\": {\n    \"large\": \"drivers/pet_waterer_xiaomi/assets/images/large.jpg\",\n    \"small\": \"drivers/pet_waterer_xiaomi/assets/images/small.jpg\"\n  },\n  \"class\": \"petfeeder\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"petwaterdispenser_mmgg_mode_3\",\n    \"alarm_tank_empty\",\n    \"alarm_pump_supply\",\n    \"measure_filter_life\",\n    \"measure_filter_days_left\",\n    \"alarm_water_shortage\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"INTERNAL\"\n    ]\n  },\n  \"tokens\": [\n    {\n      \"name\": \"error\",\n      \"type\": \"string\",\n      \"title\": {\n        \"en\": \"Device error\",\n        \"nl\": \"Apparaatfout\",\n        \"da\": \"Enhedsfejl\",\n        \"de\": \"Gerätefehler\",\n        \"es\": \"Error del dispositivo\",\n        \"fr\": \"Erreur de l'appareil\",\n        \"it\": \"Errore dispositivo\",\n        \"no\": \"Enhetsfeil\",\n        \"sv\": \"Enhetsfel\",\n        \"pl\": \"Błąd urządzenia\",\n        \"ru\": \"Ошибка устройства\",\n        \"ko\": \"디바이스 오류\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "drivers/pet_waterer_xiaomi/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass PetwaterdispenserMmggMiotDriver extends Driver {}\n\nmodule.exports = PetwaterdispenserMmggMiotDriver;"
  },
  {
    "path": "drivers/pet_waterer_xiaomi/driver.settings.compose.json",
    "content": "[\n  {\n    \"id\": \"led\",\n    \"type\": \"checkbox\",\n    \"label\": {\n      \"en\": \"LED\",\n      \"nl\": \"LED\",\n      \"da\": \"LED\",\n      \"de\": \"LED\",\n      \"es\": \"LED\",\n      \"fr\": \"LED\",\n      \"it\": \"LED\",\n      \"no\": \"LED\",\n      \"sv\": \"LED\",\n      \"pl\": \"LED\",\n      \"ru\": \"Светодиод\",\n      \"ko\": \"LED\"\n    },\n    \"value\": true\n  },\n  {\n    \"id\": \"filter_life_remaining\",\n    \"type\": \"label\",\n    \"label\": {\n      \"en\": \"Filter remaining\",\n      \"nl\": \"Filter over\",\n      \"da\": \"Filter tilbage\",\n      \"de\": \"Filter verbleibend\",\n      \"es\": \"Filtro restante\",\n      \"fr\": \"Filtre restant\",\n      \"it\": \"Filtro rimanente\",\n      \"no\": \"Filter gjenstår\",\n      \"sv\": \"Filter kvar\",\n      \"pl\": \"Filtr pozostały\",\n      \"ru\": \"Фильтр остался\",\n      \"ko\": \"남은 필터\"\n    },\n    \"value\": \"0%\"\n  },\n  {\n    \"id\": \"cotton_life_remaining\",\n    \"type\": \"label\",\n    \"label\": {\n      \"en\": \"Cotton remaining\",\n      \"nl\": \"Cotton over\",\n      \"da\": \"Bomuld tilbage\",\n      \"de\": \"Baumwolle verbleibend\",\n      \"es\": \"Algodón restante\",\n      \"fr\": \"Coton restant\",\n      \"it\": \"Cotone rimanente\",\n      \"no\": \"Bomull gjenstår\",\n      \"sv\": \"Bomull kvar\",\n      \"pl\": \"Bawełna pozostała\",\n      \"ru\": \"Осталось хлопка\",\n      \"ko\": \"남은 면\"\n    },\n    \"value\": \"0%\"\n  },\n  {\n    \"id\": \"cleaning_time_remaining\",\n    \"type\": \"label\",\n    \"label\": {\n      \"en\": \"Cleaning time remaining\",\n      \"nl\": \"Opschoon tijd over\",\n      \"da\": \"Rengøringstid tilbage\",\n      \"de\": \"Reinigungszeit verbleibend\",\n      \"es\": \"Tiempo de limpieza restante\",\n      \"fr\": \"Temps de nettoyage restant\",\n      \"it\": \"Tempo di pulizia rimanente\",\n      \"no\": \"Rengjøringstid gjenstår\",\n      \"sv\": \"Rengöringstid kvar\",\n      \"pl\": \"Pozostały czas czyszczenia\",\n      \"ru\": \"Осталось времени на уборку\",\n      \"ko\": \"남은 청소 시간\"\n    },\n    \"value\": \"6\"\n  },\n  {\n    \"id\": \"error\",\n    \"type\": \"label\",\n    \"label\": {\n      \"en\": \"Error\",\n      \"nl\": \"Fout\",\n      \"da\": \"Fejl\",\n      \"de\": \"Fehler\",\n      \"es\": \"Error\",\n      \"fr\": \"Erreur\",\n      \"it\": \"Errore\",\n      \"no\": \"Feil\",\n      \"sv\": \"Fel\",\n      \"pl\": \"Błąd\",\n      \"ru\": \"Ошибка\",\n      \"ko\": \"오류\"\n    },\n    \"value\": \"No error\"\n  },\n  {\n    \"id\": \"power_source\",\n    \"type\": \"label\",\n    \"label\": {\n      \"en\": \"Power source\",\n      \"nl\": \"Voedingsbron\",\n      \"da\": \"Strømkilde\",\n      \"de\": \"Stromquelle\",\n      \"es\": \"Fuente de alimentacion\",\n      \"fr\": \"Source d'alimentation\",\n      \"it\": \"Fonte di alimentazione\",\n      \"no\": \"Strømkilde\",\n      \"sv\": \"Stromkalla\",\n      \"pl\": \"Zrodlo zasilania\",\n      \"ru\": \"Источник питания\",\n      \"ko\": \"전원 공급원\"\n    },\n    \"value\": \"Unknown\"\n  },\n  {\n    \"id\": \"charging_state\",\n    \"type\": \"label\",\n    \"label\": {\n      \"en\": \"Charging state\",\n      \"nl\": \"Laadstatus\",\n      \"da\": \"Opladningsstatus\",\n      \"de\": \"Ladestatus\",\n      \"es\": \"Estado de carga\",\n      \"fr\": \"Etat de charge\",\n      \"it\": \"Stato di carica\",\n      \"no\": \"Ladestatus\",\n      \"sv\": \"Laddningsstatus\",\n      \"pl\": \"Stan ladowania\",\n      \"ru\": \"Состояние зарядки\",\n      \"ko\": \"충전 상태\"\n    },\n    \"value\": \"Unknown\"\n  },\n  {\n    \"id\": \"address\",\n    \"type\": \"text\",\n    \"label\": {\n      \"en\": \"IP Address\",\n      \"nl\": \"IP-adres\",\n      \"da\": \"IP-adresse\",\n      \"de\": \"IP-Adresse\",\n      \"es\": \"Dirección IP\",\n      \"fr\": \"Adresse IP\",\n      \"it\": \"Indirizzo IP\",\n      \"no\": \"IP-adresse\",\n      \"sv\": \"IP-adress\",\n      \"pl\": \"Adres IP\",\n      \"ru\": \"IP-адрес\",\n      \"ko\": \"IP 주소\"\n    }\n  },\n  {\n    \"id\": \"token\",\n    \"type\": \"password\",\n    \"label\": {\n      \"en\": \"Token\",\n      \"nl\": \"Token\",\n      \"da\": \"Token\",\n      \"de\": \"Token\",\n      \"es\": \"Token\",\n      \"fr\": \"Jeton\",\n      \"it\": \"Token\",\n      \"no\": \"Token\",\n      \"sv\": \"Token\",\n      \"pl\": \"Token\",\n      \"ru\": \"Токен\",\n      \"ko\": \"토큰\"\n    }\n  },\n  {\n    \"id\": \"polling\",\n    \"type\": \"number\",\n    \"label\": {\n      \"en\": \"Polling interval (seconds)\",\n      \"nl\": \"Polling-interval (seconden)\",\n      \"da\": \"Polling-interval (sekunder)\",\n      \"de\": \"Abfrageintervall (Sekunden)\",\n      \"es\": \"Intervalo de sondeo (segundos)\",\n      \"fr\": \"Intervalle de sondage (secondes)\",\n      \"it\": \"Intervallo di polling (secondi)\",\n      \"no\": \"Pollingintervall (sekunder)\",\n      \"sv\": \"Pollingintervall (sekunder)\",\n      \"pl\": \"Interwał odpytywania (sekundy)\",\n      \"ru\": \"Интервал опроса (секунды)\",\n      \"ko\": \"폴링 간격 (초)\"\n    },\n    \"value\": 60\n  }\n]\n"
  },
  {
    "path": "drivers/pet_waterer_xiaomi/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/pet_waterer_xiaomi/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/pet_waterer_xiaomi/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/petfeeder_mmgg_miot/device.js",
    "content": "'use strict';\n\n/**\n * Pet Feeder MIoT (Wi-Fi)\n * Target model: xiaomi.feeder.iv2001 (CN)\n *\n * Features:\n *  • Eaten food (today/total)\n *  • Food-out and Heap statuses\n *  • Status (mode) text\n *  • Desiccant level (%) + time (days) + low alarm\n *\n * Engineering notes:\n *  • No dependency on base boot sequence (we do not call bootSequence()).\n *  • Guarded, self-contained polling loop with clear diagnostic logs.\n *  • Defensive MIoT handling (code -4001 / undefined) — never throws.\n *  • Backwards compatible; adds capabilities if missing.\n */\n\nconst Homey = require('homey');\nconst DeviceBase = require('../wifi_device.js'); // your base Wi-Fi device class\nconst miio = require('miio');\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Model mapping (restored) — preset selector with wildcard for mmgg.feeder.*\n// ───────────────────────────────────────────────────────────────────────────────\n\nconst MODEL_TO_PRESET = {\n    'mmgg.feeder.fi1': 'default',\n    'mmgg.feeder.inland': 'default',\n    'mmgg.feeder.spec': 'default',\n    'xiaomi.feeder.pi2001': 'pi2001',\n    'xiaomi.feeder.iv2001': 'iv2001' // https://github.com/al-one/hass-xiaomi-miot/issues/2415#issuecomment-2727063411\n};\n\nfunction resolvePresetId(model) {\n    if (MODEL_TO_PRESET[model]) return MODEL_TO_PRESET[model];\n    if (typeof model === 'string' && model.startsWith('mmgg.feeder.')) return 'default';\n    return 'iv2001'; // safe default for our implementation\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// MIoT defaults (static mapping)\n// ───────────────────────────────────────────────────────────────────────────────\n\nconst BASE_GET_PROPS = [\n    { did: 'error', siid: 2, piid: 1 },\n    { did: 'foodlevel', siid: 2, piid: 6 }\n];\n\nconst LEGACY_MIOT_PROPS = {\n    eaten_food_today: { siid: 2, piid: 18 }, // daily eaten grams\n    food_in_bowl: { siid: 4, piid: 6 }, // firmware-dependent; may be unsupported (-4001)\n    food_out_status: { siid: 2, piid: 26 }, // FOOD_OUT_STATUS (0/1)\n    food_out_progress: { siid: 5, piid: 11 }, // xiaomi-spec: food-out progress (%)\n    heap_status: { siid: 2, piid: 15 }, // spec v2: heap/accumulation flag\n    // Note: Legacy MIoT mappings are inconsistent; derive status from flags/progress.\n    target_feeding_measure: { siid: 2, piid: 8 }, // FEEDING_MEASURE (often -4001 for read)\n    target_feeding_measure_legacy: { siid: 2, piid: 7 }, // fallback (observed on some firmwares)\n    desiccant_level: { siid: 6, piid: 1 }, // correct MIoT mapping (percent remaining)\n    desiccant_time: { siid: 6, piid: 2 }, // correct MIoT mapping (days remaining, some firmware returns hours)\n    schedule_progress: { siid: 5, piid: 15 }, // feeding schedule progress (%)\n    refill_reminder: { siid: 5, piid: 16 } // optional: refill reminder flag / counter\n};\n\nconst IV2001_MIOT_PROPS = {\n    eaten_food_today: { siid: 2, piid: 18 }, // eaten-food-measure\n    eaten_food_today_alt: { siid: 2, piid: 23 }, // eaten-food-measure (alt)\n    food_out_status: { siid: 2, piid: 10 }, // food stuck status (0 normal, 1 abnormal)\n    target_feeding_measure: { siid: 2, piid: 7 }, // target-feeding-measure\n    feeding_measure: { siid: 2, piid: 8 }, // feeding-measure (action input)\n    food_out_progress: { siid: 5, piid: 11 }, // food-out progress (%)\n    screen_display_mode: { siid: 5, piid: 18 }, // set-screen-display\n    desiccant_level: { siid: 6, piid: 1 }, // desiccant-left-level\n    desiccant_time: { siid: 6, piid: 2 } // desiccant-left-time\n};\n\nconst LEGACY_SETTING_PROPS = {\n    child_lock: { siid: 3, piid: 1, type: 'bool' }, // physical-controls-locked\n    auto_screen_off: { siid: 3, piid: 3, type: 'uint8_bool' }, // mode 0/1 (auto screen-off)\n    display_schedule_progress: { siid: 5, piid: 4, type: 'bool' }, // plan-process-display\n    low_food_intake_threshold: { siid: 5, piid: 5, type: 'number', range: [10, 90] }, // grams (10-90)\n    low_food_consumption_notify: { siid: 5, piid: 6, type: 'bool' }, // food-intake-state\n    empty_food_bowl_duration: { siid: 5, piid: 10, type: 'number', range: [6, 24] }, // add-meal-cycle hours\n    dispensing_error_correction: { siid: 5, piid: 12, type: 'uint8_bool' }, // compensate-switch 0/1\n    bowl_spillage_prevention: { siid: 5, piid: 14, type: 'uint8_bool' } // prevent-accumulation 0/1\n};\n\nconst IV2001_SETTING_PROPS = {\n    child_lock: { siid: 3, piid: 3, type: 'uint8_bool' } // physical control locked mode (0/1)\n};\n\nfunction resolveMiotProps(presetId) {\n    return presetId === 'iv2001' ? IV2001_MIOT_PROPS : LEGACY_MIOT_PROPS;\n}\n\nfunction resolveSettingProps(presetId) {\n    return presetId === 'iv2001' ? IV2001_SETTING_PROPS : LEGACY_SETTING_PROPS;\n}\n\nconst MANUAL_FEED_PORTION_GRAMS = 5; // fallback grams per portion when target measure missing\nconst DESICCANT_FULL_DAYS = 30; // according to device UI (full pack lifetime)\nconst MANUAL_FEED_MAX_PORTIONS = 30;\nconst STORE_KEYS = {\n    todaySnapshot: 'iv2001_today_snapshot'\n};\nconst BOWL_DELTA_THRESHOLD = 0.5; // grams, ignore noise smaller than this\nconst PROGRESS_COMPLETE_THRESHOLD = 99.5; // treat >=99.5% as completed dispensing\n\n\n// Human-readable mode mapping (conservative)\nconst MODE_MAP = new Map([\n    [0, 'idle'],\n    [1, 'feeding'],\n    [2, 'paused'],\n    [3, 'fault']\n]);\n\nconst FOODLEVEL_ENUM_VALUES = new Set(['0', '1']);\nconst FOODLEVEL_LABELS = new Map([\n    ['0', 'normal'],\n    ['1', 'low']\n]);\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Small helpers\n// ───────────────────────────────────────────────────────────────────────────────\n\nfunction toNumber(v) {\n    const n = Number(v);\n    return Number.isFinite(n) ? n : undefined;\n}\n\nfunction normalizePercent(v) {\n    const n = toNumber(v);\n    if (!Number.isFinite(n)) return undefined;\n    return Math.max(0, Math.min(100, Math.round(n)));\n}\n\nfunction clampNumber(value, min, max) {\n    if (!Number.isFinite(value)) return undefined;\n    if (Number.isFinite(min)) value = Math.max(min, value);\n    if (Number.isFinite(max)) value = Math.min(max, value);\n    return value;\n}\n\nfunction fromMiotBool(v) {\n    if (typeof v === 'boolean') return v;\n    if (typeof v === 'number') return v !== 0;\n    if (typeof v === 'string') return v === 'on' || v === 'true' || v === '1';\n    return undefined;\n}\n\nfunction toMiotBoolInput(v, format) {\n    const truthy = v === true || v === 'true' || v === 'on' || Number(v) === 1;\n    if (format === 'bool') return truthy;\n    return truthy ? 1 : 0;\n}\n\nfunction normalizeDesiccantDays(v) {\n    const n = toNumber(v);\n    if (n === undefined) return undefined;\n\n    const clamp = (value) => Math.max(0, Math.min(3650, Math.round(value)));\n\n    if (n >= 86400 && n % 60 === 0) {\n        return { days: clamp(n / 86400), branch: 'seconds' };\n    }\n    if (n > 24 && n < 86400 && n % 24 === 0) {\n        return { days: clamp(n / 24), branch: 'hours' };\n    }\n    if (n >= 0 && n <= 3650) {\n        return { days: clamp(n), branch: 'days' };\n    }\n    return undefined;\n}\n\n// ───────────────────────────────────────────────────────────────────────────────\n// Device class\n// ───────────────────────────────────────────────────────────────────────────────\n\nclass PetFeederMiotDevice extends DeviceBase {\n    // Local warn that never throws (SDK doesn’t expose this.warn())\n    _warn(...args) {\n        try {\n            this.log('[WARN]', ...args);\n        } catch (_) {}\n    }\n\n    async onInit() {\n        try {\n            // Resolve model->preset (kept for completeness; we operate fine on any feeder)\n            const model = this.getStoreValue('model') || this.getData()?.model || 'xiaomi.feeder.iv2001';\n            this._presetId = resolvePresetId(model);\n            this._miotProps = resolveMiotProps(this._presetId);\n            this._settingProps = resolveSettingProps(this._presetId);\n\n            // Ensure capabilities exist (upgrade-safe)\n            await this._ensureCapabilities();\n\n            // Settings defaults\n            const s = this.getSettings() || {};\n            const patch = {};\n            if (typeof s.desiccant_alarm_threshold !== 'number') patch.desiccant_alarm_threshold = 20;\n            if (Object.keys(patch).length) {\n                await this.setSettings(patch).catch((e) => this._warn('[SETTINGS] default patch failed:', e?.message));\n            }\n\n            // Flow triggers\n            this._flow = {\n                feederStatusChanged: this.homey.flow.getDeviceTriggerCard('feeder_status_changed'),\n                eatenFoodChanged: this.homey.flow.getDeviceTriggerCard('eaten_food_changed'),\n                desiccantLow: this.homey.flow.getDeviceTriggerCard('desiccant_low')\n            };\n\n            // State\n            const ymdNow = this._ymdNow();\n            const storedSnapshotRaw = this.getStoreValue(STORE_KEYS.todaySnapshot);\n            const trackerSnapshot =\n                storedSnapshotRaw && typeof storedSnapshotRaw === 'object'\n                    ? {\n                          ymd: typeof storedSnapshotRaw.ymd === 'string' ? storedSnapshotRaw.ymd : ymdNow,\n                          value: toNumber(storedSnapshotRaw.value)\n                      }\n                    : { ymd: ymdNow, value: 0 };\n            if (!Number.isFinite(trackerSnapshot.value)) trackerSnapshot.value = 0;\n            this._state = {\n                once: new Set(),\n                lastMode: 'unknown',\n                targetFeedingMeasure: MANUAL_FEED_PORTION_GRAMS,\n                suppressSettingApply: false,\n                desiccantAlarm: this.getCapabilityValue('alarm_desiccant_low') === true,\n                todayTracker: trackerSnapshot,\n                pendingDuringDispense: 0,\n                lastBowlGrams: Number.isFinite(toNumber(this.getCapabilityValue('petfeeder_food_in_bowl')))\n                    ? Math.max(0, toNumber(this.getCapabilityValue('petfeeder_food_in_bowl')))\n                    : undefined,\n                estimatedBowl: Number.isFinite(toNumber(this.getCapabilityValue('petfeeder_food_in_bowl')))\n                    ? Math.max(0, toNumber(this.getCapabilityValue('petfeeder_food_in_bowl')))\n                    : undefined,\n                lastProgressValue: undefined,\n                lastProgressComplete: true,\n                bowlUnsupported: false,\n                progressActive: false,\n                progressDose: undefined,\n                lastDesiccantBranchLogAt: 0,\n                lastDesiccantBranchLogged: undefined,\n                lastDesiccantPct: undefined,\n                lastDesiccantDays: undefined,\n                lastTimeline: { excerpt: undefined, at: 0 }\n            };\n\n\n            await this._syncEatenSetting(trackerSnapshot.value);\n\n            // Read-only guard (prevents \"Missing Capability Listener\" warnings)\n            if (this.hasCapability('petfeeder_foodlevel')) {\n                this.registerCapabilityListener('petfeeder_foodlevel', async () => {\n                    throw new Error('petfeeder_foodlevel is read-only');\n                });\n            }\n\n            // Establish MIoT connection ourselves (we do not use bootSequence/pollDevice)\n            // Do not await here to avoid blocking init on long probes/timeouts\n            this._initMiio();\n\n            // Start our own guarded poller.\n            const pollSeconds = Math.max(5, Number(this.getSettings().polling) || 15);\n            this._pollMs = pollSeconds * 1000;\n            if (this._pollTimer) this.homey.clearInterval(this._pollTimer);\n            this._pollTimer = this.homey.setInterval(() => this._pollOnce(), this._pollMs);\n            this.homey.setTimeout(() => this._pollOnce(), 1000);\n        } catch (err) {\n            this.error('[IV2001] onInit error:', err?.message || err);\n        }\n    }\n\n    async onUninit() {\n        try {\n            if (this._pollTimer) this.homey.clearInterval(this._pollTimer);\n        } catch (_) {}\n        if (super.onUninit) return super.onUninit();\n    }\n\n    async onSettings({ oldSettings, newSettings, changedKeys }) {\n        try {\n            if (!this._state) this._state = { suppressSettingApply: false };\n            this._state.onSettingsActive = true;\n            if (changedKeys.includes('address') || changedKeys.includes('token') || changedKeys.includes('polling')) {\n                if (this._pollTimer) this.homey.clearInterval(this._pollTimer);\n                await this._initMiio();\n                const pollSeconds = Math.max(5, Number(newSettings.polling) || Number(this.getSettings().polling) || 15);\n                this._pollMs = pollSeconds * 1000;\n                this._pollTimer = this.homey.setInterval(() => this._pollOnce(), this._pollMs);\n            }\n\n            for (const key of changedKeys) {\n                if (!Object.prototype.hasOwnProperty.call(this._settingProps || {}, key)) continue;\n                if (this._state?.suppressSettingApply) continue;\n                try {\n                    await this._applySettingToDevice(key, newSettings[key]);\n                } catch (err) {\n                    const message = err?.message || err;\n                    this._warn('[IV2001] setting apply failed', key, message);\n                    if (oldSettings[key] !== undefined) {\n                        await this.updateSettingValue(key, oldSettings[key]);\n                    }\n                }\n            }\n\n            if (changedKeys.includes('eaten_food_today_adjust')) {\n                const adjustValue = toNumber(newSettings.eaten_food_today_adjust);\n                if (Number.isFinite(adjustValue) && adjustValue >= 0) {\n                    await this._applyManualEatenAdjust(adjustValue, true);\n                } else if (adjustValue !== undefined) {\n                    this._warn('[SETTINGS] invalid eaten_food_today_adjust value');\n                }\n            }\n\n        } catch (e) {\n            this._warn('[IV2001] onSettings error:', e?.message);\n        } finally {\n            if (this._state) this._state.onSettingsActive = false;\n        }\n        return true;\n    }\n\n    // ───────────────────────────────────────────────────────────────────────────\n    // Polling\n    // ───────────────────────────────────────────────────────────────────────────\n\n    async _pollOnce() {\n        if (this._polling) return;\n        this._polling = true;\n\n        try {\n            if (!this.miio) {\n                // Connection not ready yet; do not try to \"fix\" here. Base will init miio.\n                this._onceWarn('[IV2001] miio not ready; skipping this poll');\n                return;\n            }\n\n            const miotProps = this._miotProps || LEGACY_MIOT_PROPS;\n            const settingProps = this._settingProps || LEGACY_SETTING_PROPS;\n\n            // Build default read set\n            const settingsReq = Object.entries(settingProps).map(([key, def]) => ({\n                did: `setting_${key}`,\n                siid: def.siid,\n                piid: def.piid\n            }));\n\n            const req = [...BASE_GET_PROPS];\n            const addProp = (did, def) => {\n                if (!def) return;\n                req.push({ did, siid: def.siid, piid: def.piid });\n            };\n\n            addProp('eaten_food_today', miotProps.eaten_food_today);\n            addProp('eaten_food_today_alt', miotProps.eaten_food_today_alt);\n            addProp('food_in_bowl', miotProps.food_in_bowl);\n            addProp('food_out_status', miotProps.food_out_status);\n            addProp('food_out_progress', miotProps.food_out_progress);\n            addProp('heap_status', miotProps.heap_status);\n            addProp('target_feeding_measure', miotProps.target_feeding_measure);\n            addProp('target_feeding_measure_legacy', miotProps.target_feeding_measure_legacy);\n            addProp('feeding_measure', miotProps.feeding_measure);\n            addProp('desiccant_level', miotProps.desiccant_level);\n            addProp('desiccant_time', miotProps.desiccant_time);\n            addProp('schedule_progress', miotProps.schedule_progress);\n            addProp('refill_reminder', miotProps.refill_reminder);\n            addProp('screen_display_mode', miotProps.screen_display_mode);\n\n            req.push(...settingsReq);\n\n            const res = await this._safeGetProps(req);\n            const got = this._indexResults(req, res);\n\n            // Short one-time debug of available default props\n            if (!this._state.once.has('debug_dump_defaults')) {\n                this._state.once.add('debug_dump_defaults');\n                const summary = Object.entries(got)\n                    .filter(([, r]) => r && r.code === 0)\n                    .map(([k, r]) => `${k}@${r.siid}/${r.piid}=${JSON.stringify(r.value)}`);\n                this.log('[DEBUG] available defaults:', summary.join(', ') || 'none');\n            }\n\n            // Publish values\n            await this._updateFaultAndFoodLevel(got);\n            await this._updateEatenFood(got);\n            await this._updateFoodOutAndHeap(got);\n            await this._updateStatusMode(got);\n            await this._updateTargetFeedingMeasure(got);\n            await this._updateDesiccant(got);\n            await this._syncSettingsFromMiot(got);\n\n        } catch (e) {\n            this._warn('[IV2001] poll error:', e?.message);\n        } finally {\n            this._polling = false;\n        }\n    }\n\n    // ───────────────────────────────────────────────────────────────────────────\n    // Update blocks\n    // ───────────────────────────────────────────────────────────────────────────\n\n    async _updateFaultAndFoodLevel(g) {\n        const e = g.error,\n            f = g.foodlevel;\n\n        if (e && e.code === 0) {\n            const val = e.value;\n            const numeric = toNumber(val);\n            const isClear = val === 0 || val === '0' || numeric === 0;\n            if (!isClear && typeof val !== 'undefined') {\n                this.log('[FAULT] device code =', val);\n            }\n        } else if (e && e.code === -4001) {\n            this._onceWarn('[FAULT] unsupported (-4001)');\n        }\n\n        if (this.hasCapability('petfeeder_foodlevel')) {\n            if (f && f.code === 0 && typeof f.value !== 'undefined') {\n                const rawValue = String(f.value);\n                if (!FOODLEVEL_ENUM_VALUES.has(rawValue)) {\n                    this._onceWarn(`[FOODLEVEL] unexpected value: ${JSON.stringify(f.value)}`);\n                }\n                const mappedValue = FOODLEVEL_LABELS.get(rawValue) || 'unknown';\n                await this._setCap('petfeeder_foodlevel', mappedValue);\n            } else if (f && f.code === -4001) {\n                this._onceWarn('[FOODLEVEL] unsupported (-4001)');\n            }\n        }\n    }\n\n    async _updateEatenFood(g) {\n        const progressOutProp = g.food_out_progress;\n        const scheduleProp = g.schedule_progress;\n\n        let progress;\n        if (progressOutProp && progressOutProp.code === 0) {\n            const raw = toNumber(progressOutProp.value);\n            if (Number.isFinite(raw)) progress = clampNumber(raw, 0, 100);\n        } else if (progressOutProp && progressOutProp.code === -4001) {\n            this._onceWarn('[EATEN] food-out progress unsupported (-4001)');\n        }\n\n        if (progress === undefined) {\n            if (scheduleProp && scheduleProp.code === 0) {\n                const raw = toNumber(scheduleProp.value);\n                if (Number.isFinite(raw)) progress = clampNumber(raw, 0, 100);\n            } else if (scheduleProp && scheduleProp.code === -4001) {\n                this._onceWarn('[EATEN] schedule progress unsupported (-4001)');\n            }\n        }\n\n        const progressValue = typeof progress === 'number' ? progress : undefined;\n        const progressComplete = progressValue === undefined ? true : progressValue >= PROGRESS_COMPLETE_THRESHOLD;\n        const progressLabel = progressValue === undefined ? 'n/a' : progressValue.toFixed(1);\n\n        if (this.hasCapability('petfeeder_food_out_progress') && typeof progressValue === 'number') {\n            await this._setCap('petfeeder_food_out_progress', Math.round(progressValue));\n        }\n        if (this.hasCapability('petfeeder_schedule_progress') && typeof progressValue === 'number') {\n            await this._setCap('petfeeder_schedule_progress', Math.round(progressValue));\n        }\n        if (this.hasCapability('petfeeder_busy')) {\n            await this._setCap('petfeeder_busy', !progressComplete);\n        }\n\n        if (this._state) {\n            this._state.lastProgressValue = progressValue;\n            this._state.lastProgressComplete = progressComplete;\n        }\n\n        const miotEaten = (() => {\n            const primary = g.eaten_food_today;\n            const alt = g.eaten_food_today_alt;\n            const pick = primary && primary.code === 0 ? primary : alt && alt.code === 0 ? alt : undefined;\n            if (!pick) return undefined;\n            const value = toNumber(pick.value);\n            return Number.isFinite(value) ? Math.max(0, value) : undefined;\n        })();\n\n        if (this._presetId === 'iv2001' && Number.isFinite(miotEaten)) {\n            const ymdNow = this._ymdNow();\n            const prevTracker = this._state.todayTracker || { ymd: ymdNow, value: 0 };\n            const prevValue = Number.isFinite(prevTracker.value) ? prevTracker.value : 0;\n            const sameDay = prevTracker.ymd === ymdNow;\n            const normalized = Math.max(0, Math.round(miotEaten));\n            const deltaRaw = sameDay ? normalized - prevValue : normalized;\n            const delta = deltaRaw > 0 ? deltaRaw : 0;\n\n            const tracker = { ymd: ymdNow, value: normalized };\n            const changed = !sameDay || Math.abs(prevValue - normalized) > 0.1;\n            if (changed) {\n                try {\n                    await this.setStoreValue(STORE_KEYS.todaySnapshot, tracker);\n                } catch (_) {}\n            }\n\n            this._state.todayTracker = tracker;\n            this._state.pendingDuringDispense = 0;\n            this._state.fallbackPending = 0;\n            this._state.progressActive = false;\n            this._state.progressDose = undefined;\n\n            if (this.hasCapability('petfeeder_eaten_food_today')) {\n                await this._setCap('petfeeder_eaten_food_today', normalized);\n            }\n\n            await this._syncEatenSetting(normalized);\n\n            if (delta > 0.1) {\n                await this._triggerEatenChanged(normalized, delta);\n            }\n            return;\n        }\n\n        const bowlProp = g.food_in_bowl;\n        let bowl;\n        let bowlSupported = false;\n        if (bowlProp && bowlProp.code === 0) {\n            const raw = toNumber(bowlProp.value);\n            if (Number.isFinite(raw)) {\n                bowl = Math.max(0, raw);\n                bowlSupported = true;\n                if (this._state) {\n                    this._state.bowlUnsupported = false;\n                    this._state.estimatedBowl = bowl;\n                }\n            }\n        } else if (bowlProp && bowlProp.code === -4001) {\n            this._onceWarn('[EATEN] bowl level unsupported (-4001)');\n            if (this._state) this._state.bowlUnsupported = true;\n        }\n        if (!bowlSupported && this._state?.estimatedBowl !== undefined) {\n            bowl = this._state.estimatedBowl;\n        }\n\n        if (this._state) {\n            const progressActiveNow = !progressComplete;\n            if (progressActiveNow) {\n                if (!this._state.progressActive) {\n                    this._state.progressActive = true;\n                    if (this._state.bowlUnsupported) {\n                        const expected = Number.isFinite(this._state.targetFeedingMeasure) && this._state.targetFeedingMeasure > 0\n                            ? this._state.targetFeedingMeasure\n                            : MANUAL_FEED_PORTION_GRAMS;\n                        this._state.progressDose = expected;\n                        this.log(`[EATEN] feed started (no bowl sensor), expect ${expected} g`);\n                    }\n                }\n            } else if (this._state.progressActive) {\n                if (this._state.bowlUnsupported && Number.isFinite(this._state.progressDose) && this._state.progressDose > 0) {\n                    const existing = Number.isFinite(this._state.fallbackPending) ? this._state.fallbackPending : 0;\n                    this._state.fallbackPending = existing + this._state.progressDose;\n                    this.log(`[EATEN] feed finished (no bowl sensor) -> ${this._state.progressDose} g`);\n                }\n                this._state.progressActive = false;\n                this._state.progressDose = undefined;\n            }\n        }\n\n        if (bowlSupported && this.hasCapability('petfeeder_food_in_bowl') && typeof bowl === 'number') {\n            await this._setCap('petfeeder_food_in_bowl', bowl);\n        }\n\n        const ymdNow = this._ymdNow();\n        const prevTracker = this._state.todayTracker || { ymd: ymdNow, value: 0 };\n        const tracker =\n            prevTracker.ymd === ymdNow\n                ? { ymd: prevTracker.ymd, value: Number.isFinite(prevTracker.value) ? prevTracker.value : 0 }\n                : { ymd: ymdNow, value: 0 };\n\n        const prevBowl = this._state.lastBowlGrams;\n        let pending = Number.isFinite(this._state.pendingDuringDispense) ? this._state.pendingDuringDispense : 0;\n        if (Number.isFinite(this._state?.fallbackPending) && this._state.fallbackPending > 0) {\n            pending += this._state.fallbackPending;\n            this._state.fallbackPending = 0;\n        }\n        let delta = 0;\n\n        if (bowlSupported && typeof bowl === 'number' && typeof prevBowl === 'number') {\n            const diff = prevBowl - bowl;\n            if (diff > BOWL_DELTA_THRESHOLD) {\n                if (progressComplete) {\n                    delta += diff;\n                } else {\n                    pending += diff;\n                    this.log(`[EATEN] queued ${diff.toFixed(1)} g while dispenser active (${progressLabel}%)`);\n                }\n            } else if (diff < -BOWL_DELTA_THRESHOLD) {\n                const message = progressComplete\n                    ? `[EATEN] bowl increased by ${Math.abs(diff).toFixed(1)} g with dispenser idle`\n                    : `[EATEN] bowl increased by ${Math.abs(diff).toFixed(1)} g while dispenser active (${progressLabel}%)`;\n                this.log(message);\n            }\n        } else if (bowlSupported && typeof bowl === 'number' && typeof prevBowl !== 'number') {\n            this.log(`[EATEN] tracking bowl at ${bowl.toFixed(1)} g (progress ${progressLabel}%)`);\n        }\n\n        if (progressComplete && pending > 0) {\n            delta += pending;\n            this.log(`[EATEN] applied ${pending.toFixed(1)} g collected during dispensing`);\n            pending = 0;\n        }\n\n        if (!Number.isFinite(tracker.value)) tracker.value = 0;\n        tracker.value = Math.max(0, tracker.value + delta);\n\n        const previousValue = Number.isFinite(prevTracker.value) ? prevTracker.value : 0;\n        const todayChanged = tracker.ymd !== prevTracker.ymd || Math.abs(previousValue - tracker.value) > 0.1;\n        if (todayChanged || delta > 0.01) {\n            try {\n                await this.setStoreValue(STORE_KEYS.todaySnapshot, tracker);\n            } catch (_) {}\n        }\n\n        this._state.todayTracker = tracker;\n        if (delta > 0 && this._state && this._state.bowlUnsupported) {\n            const previousBowl = Number.isFinite(prevBowl)\n                ? prevBowl\n                : Number.isFinite(this._state.estimatedBowl)\n                ? this._state.estimatedBowl\n                : 0;\n            const estimated = Math.max(0, previousBowl - delta);\n            this._state.estimatedBowl = estimated;\n            this._state.lastBowlGrams = estimated;\n            if (this.hasCapability('petfeeder_food_in_bowl')) {\n                const rounded = Math.round(estimated * 10) / 10;\n                await this._setCap('petfeeder_food_in_bowl', Math.max(0, rounded));\n            }\n        }\n        this._state.pendingDuringDispense = pending;\n        if (bowlSupported && typeof bowl === 'number') {\n            this._state.lastBowlGrams = bowl;\n        } else if (this._state && this._state.estimatedBowl !== undefined) {\n            this._state.lastBowlGrams = this._state.estimatedBowl;\n        }\n\n        const todayRounded = Math.round(tracker.value);\n        if (this.hasCapability('petfeeder_eaten_food_today')) {\n            await this._setCap('petfeeder_eaten_food_today', todayRounded);\n        }\n\n        await this._syncEatenSetting(todayRounded);\n\n        if (delta > 0.1) {\n            await this._triggerEatenChanged(todayRounded, delta);\n        }\n    }\n\n    async _updateFoodOutAndHeap(g) {\n        const mapFlag = (raw, which) => {\n            const v = toNumber(raw);\n            if (v === 0) return 'ok';\n            if (v === 1) return which === 'food' ? 'food_out' : 'heap_detected';\n            this._warn(`[${which === 'food' ? 'FOODOUT' : 'HEAP'}] unexpected value:`, raw);\n            return 'ok';\n        };\n\n        const out = g.food_out_status;\n        if (this.hasCapability('petfeeder_food_out_status')) {\n            if (out && out.code === 0) await this._setCap('petfeeder_food_out_status', mapFlag(out.value, 'food'));\n            else if (out && out.code === -4001) this._onceWarn('[FOODOUT] unsupported (-4001)');\n        }\n\n        const heap = g.heap_status;\n        if (this.hasCapability('petfeeder_heap_status')) {\n            if (heap && heap.code === 0) await this._setCap('petfeeder_heap_status', mapFlag(heap.value, 'heap'));\n            else if (heap && heap.code === -4001) this._onceWarn('[HEAP] unsupported (-4001)');\n        }\n    }\n\n    async _updateStatusMode(g) {\n        if (!this.hasCapability('petfeeder_status_mode')) return;\n\n        const isFault = (() => {\n            const err = g.error;\n            if (err && err.code === 0) {\n                const v = toNumber(err.value);\n                if (Number.isFinite(v) && v !== 0) return true;\n                if (typeof err.value !== 'undefined' && String(err.value) !== '0') return true;\n            }\n            const out = g.food_out_status;\n            if (out && out.code === 0 && toNumber(out.value) === 1) return true;\n            const heap = g.heap_status;\n            if (heap && heap.code === 0 && toNumber(heap.value) === 1) return true;\n            return false;\n        })();\n\n        const isFeeding = (() => {\n            if (this.getCapabilityValue('petfeeder_busy') === true) return true;\n\n            const progress = g.food_out_progress;\n            if (progress && progress.code === 0) {\n                const v = toNumber(progress.value);\n                if (Number.isFinite(v) && v < PROGRESS_COMPLETE_THRESHOLD) return true;\n            }\n            const schedule = g.schedule_progress;\n            if (schedule && schedule.code === 0) {\n                const v = toNumber(schedule.value);\n                if (Number.isFinite(v) && v < PROGRESS_COMPLETE_THRESHOLD) return true;\n            }\n            return false;\n        })();\n\n        const text = isFault ? 'fault' : isFeeding ? 'feeding' : 'idle';\n        const prev = this._state.lastMode;\n        await this._setCap('petfeeder_status_mode', text);\n        if (text !== prev) {\n            await this._flow.feederStatusChanged?.trigger(this, { new_status: text, previous_status: prev || 'unknown' }, {});\n            this.log('[MODE] change:', prev, '->', text);\n            this._state.lastMode = text;\n            await this._timeline(`Feeder status -> ${text}`);\n        }\n    }\n\n    async _updateTargetFeedingMeasure(g) {\n        const primary = g.target_feeding_measure;\n        const legacy = g.target_feeding_measure_legacy;\n        const pick = primary && primary.code === 0 ? primary : legacy && legacy.code === 0 ? legacy : undefined;\n        if (!pick) return;\n\n        const value = toNumber(pick.value);\n        if (!Number.isFinite(value) || value <= 0) return;\n        const normalized = Math.max(1, Math.round(value));\n        if (this._state.targetFeedingMeasure !== normalized) {\n            this._state.targetFeedingMeasure = normalized;\n            this.log('[TARGET] feeding measure set to', normalized, 'g');\n        }\n    }\n\n    async _syncSettingsFromMiot(g) {\n        const patch = {};\n        const settingProps = this._settingProps || LEGACY_SETTING_PROPS;\n        for (const [key, def] of Object.entries(settingProps)) {\n            const entry = g[`setting_${key}`];\n            if (!entry || entry.code !== 0) continue;\n            const normalized = this._normalizeSettingFromDevice(def, entry.value);\n            if (normalized === undefined) continue;\n            const current = this.getSetting(key);\n            if (current === undefined || current !== normalized) {\n                patch[key] = normalized;\n            }\n        }\n        if (Object.keys(patch).length === 0) return;\n        try {\n            this._state.suppressSettingApply = true;\n            await this.setSettings(patch);\n        } catch (e) {\n            this._warn('[SETTINGS] sync failed', e?.message);\n        } finally {\n            this._state.suppressSettingApply = false;\n        }\n    }\n\n    async _updateDesiccant(g) {\n        const lvl = g.desiccant_level;\n        const tim = g.desiccant_time;\n\n        let pct, days;\n        if (lvl && lvl.code === 0) {\n            const normalized = normalizePercent(lvl.value);\n            if (typeof normalized === 'number') pct = normalized;\n        } else if (lvl && lvl.code === -4001) this._onceWarn('[DESICCANT] level unsupported (-4001)');\n\n        if (tim && tim.code === 0) {\n            const raw = toNumber(tim.value);\n            if (Number.isFinite(raw)) {\n                const normalized = normalizeDesiccantDays(raw);\n                if (normalized) {\n                    let computedDays = normalized.days;\n                    if (normalized.branch === 'hours' && computedDays > DESICCANT_FULL_DAYS * 2) {\n                        computedDays = Math.round(computedDays / 10);\n                    } else if (normalized.branch === 'seconds' && computedDays > DESICCANT_FULL_DAYS * 2) {\n                        computedDays = Math.round(computedDays / (24 * 10));\n                    }\n                    computedDays = clampNumber(computedDays, 0, 3650);\n                    if (Number.isFinite(computedDays)) {\n                        days = computedDays;\n                        this._logDesiccantConversion(normalized.branch, raw, days);\n                    }\n                }\n            }\n        } else if (tim && tim.code === -4001) this._onceWarn('[DESICCANT] time unsupported (-4001)');\n\n        if (typeof pct !== 'number' && typeof days === 'number') {\n            const estimated = clampNumber((days / DESICCANT_FULL_DAYS) * 100, 0, 100);\n            if (Number.isFinite(estimated)) {\n                pct = Math.round(estimated);\n            }\n        }\n        if (typeof days !== 'number' && typeof pct === 'number') {\n            const estimatedDays = clampNumber((pct / 100) * DESICCANT_FULL_DAYS, 0, DESICCANT_FULL_DAYS);\n            if (Number.isFinite(estimatedDays)) {\n                days = Math.round(estimatedDays);\n            }\n        }\n\n        if (typeof pct === 'number' && this.hasCapability('measure_desiccant')) {\n            await this._setCap('measure_desiccant', pct);\n            this._state.lastDesiccantPct = pct;\n        }\n        if (typeof days === 'number' && this.hasCapability('measure_desiccant_time')) {\n            await this._setCap('measure_desiccant_time', days);\n            this._state.lastDesiccantDays = days;\n        }\n\n        if (this.hasCapability('alarm_desiccant_low') && typeof pct === 'number') {\n            const thr = Number(this.getSettings().desiccant_alarm_threshold) || 20;\n            const alarm = pct < thr;\n            const currentCap = this.getCapabilityValue('alarm_desiccant_low');\n            if (alarm !== this._state.desiccantAlarm || currentCap !== alarm) {\n                await this._setCap('alarm_desiccant_low', alarm);\n                this._state.desiccantAlarm = alarm;\n                if (alarm) {\n                    await this._flow.desiccantLow?.trigger(this, { level_percent: pct }, {});\n                    this.log('[DESICCANT] alarm ON at', pct, '% (<', thr, ')');\n                    await this._timeline(`Desiccant low (${pct}%)`);\n                } else {\n                    this.log('[DESICCANT] alarm OFF at', pct, '% (>=', thr, ')');\n                    await this._timeline(`Desiccant recovered (${pct}%)`);\n                }\n            }\n        }\n    }\n\n    // ───────────────────────────────────────────────────────────────────────────\n    // ───────────────────────────────────────────────────────────────────────────\n\n    // ───────────────────────────────────────────────────────────────────────────\n    // MIoT helpers & capability setters\n    // ───────────────────────────────────────────────────────────────────────────\n\n    async _initMiio() {\n        try {\n            // Dispose any previous instance\n            try {\n                this.miio?.destroy();\n            } catch (_) {}\n\n            const address = this.getSetting('address');\n            const token = this.getSetting('token');\n            if (!address || !token) {\n                this._onceWarn('[IV2001] missing address/token settings');\n                return;\n            }\n\n            this.miio = await miio.device({ address, token });\n            if (!this.getAvailable()) {\n                await this.setAvailable().catch(() => {});\n            }\n            this.log('[IV2001] miio ready');\n        } catch (error) {\n            this._warn('[IV2001] miio init failed:', error?.message);\n            // Retry later\n            this.homey.setTimeout(() => this._initMiio(), 10000);\n        }\n    }\n\n    async _safeGetProps(requestArray) {\n        try {\n            if (!Array.isArray(requestArray) || requestArray.length === 0) return [];\n\n            // Use small batches to avoid timeouts or rate limits\n            const CHUNK_SIZE = 14;\n            const results = [];\n            for (let i = 0; i < requestArray.length; i += CHUNK_SIZE) {\n                const batch = requestArray.slice(i, i + CHUNK_SIZE);\n                try {\n                    const res = await this._callMiio('get_properties', batch, { retries: 1 }, 5000);\n                    if (Array.isArray(res)) {\n                        results.push(...res);\n                        const missing = batch.length - res.length;\n                        for (let k = 0; k < missing; k++) results.push({});\n                    } else {\n                        for (let k = 0; k < batch.length; k++) results.push({});\n                    }\n                } catch (e) {\n                    this._warn('[MIOT] get_properties error (chunk):', e?.message);\n                    for (let k = 0; k < batch.length; k++) results.push({});\n                }\n            }\n            return results;\n        } catch (e) {\n            this._warn('[MIOT] get_properties error:', e?.message);\n            return [];\n        }\n    }\n\n    async setDisplaySchedule(enabled) {\n        const bool = enabled === true || enabled === 'true' || enabled === 1 || enabled === '1';\n        await this._applySettingToDevice('display_schedule_progress', bool);\n        try {\n            this._state.suppressSettingApply = true;\n            await this.updateSettingValue('display_schedule_progress', bool);\n        } finally {\n            this._state.suppressSettingApply = false;\n        }\n        return true;\n    }\n\n    async servePortions(portionCount) {\n        try {\n            if (!this.miio) {\n                throw new Error('miio not ready');\n            }\n            const raw = Number(portionCount);\n            const count = Number.isFinite(raw) ? Math.max(1, Math.min(MANUAL_FEED_MAX_PORTIONS, Math.round(raw))) : 1;\n            const gramsPerPortion = Number.isFinite(this._state.targetFeedingMeasure) && this._state.targetFeedingMeasure > 0 ? this._state.targetFeedingMeasure : MANUAL_FEED_PORTION_GRAMS;\n            const grams = count * gramsPerPortion;\n            let result;\n            if (this._presetId === 'iv2001') {\n                const actionPayload = { siid: 2, aiid: 1, in: [grams] };\n                result = await this._callMiio('action', actionPayload, { retries: 1 }, 12000);\n            } else {\n                const propertyPayload = [\n                    { siid: 2, piid: 8, value: grams }\n                ];\n                await this._callMiio('set_properties', propertyPayload, { retries: 1 }, 8000);\n                const actionPayload = { siid: 2, aiid: 1, in: [] };\n                result = await this._callMiio('action', actionPayload, { retries: 1 }, 12000);\n            }\n            this.log('[FEED] manual feed', { portions: count, grams, grams_per_portion: gramsPerPortion });\n            await this._timeline(`Manual feed: ${count}x (${grams} g)`);\n            return result;\n        } catch (err) {\n            const message = err?.message || err;\n            this._warn('[FEED] manual feed error:', message);\n            throw err;\n        }\n    }\n\n    async _callMiio(method, params, options, timeoutMs = 8000) {\n        const op = (async () => {\n            return await this.miio.call(method, params, options || {});\n        })();\n        const timeout = new Promise((_, reject) => {\n            this.homey.setTimeout(() => reject(new Error('timeout')), timeoutMs);\n        });\n        return Promise.race([op, timeout]);\n    }\n\n    _indexResults(reqList, respList) {\n        const out = {};\n        for (let i = 0; i < reqList.length; i++) {\n            const req = reqList[i];\n            const res = respList[i] || {};\n            const key = req.did || `${req.siid}/${req.piid}`;\n            out[key] = { code: typeof res.code === 'number' ? res.code : -1, value: res.value, siid: req.siid, piid: req.piid };\n        }\n        return out;\n    }\n\n    async _setCap(cap, value) {\n        try {\n            if (!this.hasCapability(cap)) return;\n            const cur = this.getCapabilityValue(cap);\n            if (cur !== value) {\n                try {\n                    await this.setCapabilityValue(cap, value);\n                } catch (e) {\n                    const expectsString = /expected string|InvalidTypeError/i.test(String(e?.message || ''));\n                    if (expectsString && typeof value !== 'string') {\n                        await this.setCapabilityValue(cap, String(value));\n                    } else {\n                        throw e;\n                    }\n                }\n                this.log('[CAP]', cap, '=', value);\n            }\n        } catch (e) {\n            this._warn('[CAP] set error', cap, e?.message);\n        }\n    }\n\n    async _timeline(excerpt, data) {\n        try {\n            if (!excerpt || !this.homey?.notifications?.createNotification) return;\n            const now = Date.now();\n            const last = this._state.lastTimeline || {};\n            if (last.excerpt === excerpt && now - (last.at || 0) < 60 * 1000) return;\n            await this.homey.notifications.createNotification({ excerpt, data });\n            this._state.lastTimeline = { excerpt, at: now };\n        } catch (e) {\n            this._warn('[TIMELINE] notification failed', e?.message);\n        }\n    }\n\n    async _triggerEatenChanged(todayG, deltaG) {\n        try {\n            const todayValue = Number.isFinite(todayG) ? Math.round(todayG) : 0;\n            const deltaValue = Number.isFinite(deltaG) ? Math.round(deltaG) : 0;\n            await this._flow.eatenFoodChanged?.trigger(\n                this,\n                {\n                    today_g: todayValue,\n                    total_g: todayValue,\n                    delta_g: deltaValue\n                },\n                {}\n            );\n            this.log('[EATEN] trigger:', { today_g: todayValue, delta_g: deltaValue });\n            if (deltaValue > 0) {\n                await this._timeline(`Pet ate ${deltaValue} g (today ${todayValue} g)`);\n            }\n        } catch (e) {\n            this._warn('[EATEN] trigger error:', e?.message);\n        }\n    }\n\n    async _applyManualEatenAdjust(value, skipSettingSync = false) {\n        const ymdNow = this._ymdNow();\n        const normalized = Number.isFinite(value) ? Math.max(0, Math.round(value)) : 0;\n        const tracker = { ymd: ymdNow, value: normalized };\n        this._state.todayTracker = tracker;\n        this._state.pendingDuringDispense = 0;\n        try {\n            await this.setStoreValue(STORE_KEYS.todaySnapshot, tracker);\n        } catch (_) {}\n        if (this.hasCapability('petfeeder_eaten_food_today')) {\n            await this._setCap('petfeeder_eaten_food_today', normalized);\n        }\n        this.log('[EATEN] manual correction applied', normalized, 'g');\n        if (!skipSettingSync) {\n            await this._syncEatenSetting(normalized);\n        }\n    }\n\n    async _syncEatenSetting(value) {\n        if (!this._state) return;\n        if (this._state.suppressSettingApply) return;\n        if (this._state.onSettingsActive) return;\n        const settings = this.getSettings() || {};\n        const currentRaw = toNumber(settings.eaten_food_today_adjust);\n        const target = Number.isFinite(value) ? Math.max(0, Math.round(value)) : 0;\n        const currentNormalized = Number.isFinite(currentRaw) ? Math.max(0, Math.round(currentRaw)) : 0;\n        if (currentNormalized === target) return;\n        try {\n            this._state.suppressSettingApply = true;\n            await this.updateSettingValue('eaten_food_today_adjust', target);\n        } catch (e) {\n            this._warn('[SETTINGS] sync eaten value failed', e?.message);\n        } finally {\n            this._state.suppressSettingApply = false;\n        }\n    }\n\n    _onceWarn(msg) {\n        if (!this._state.once.has(msg)) {\n            this._state.once.add(msg);\n            this._warn(msg);\n        }\n    }\n\n    _ymdNow() {\n        const d = new Date();\n        return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;\n    }\n\n\n    _logDesiccantConversion(branch, raw, days) {\n        if (!branch) return;\n        const now = Date.now();\n        const shouldLog =\n            now - (this._state.lastDesiccantBranchLogAt || 0) > 60 * 60 * 1000 ||\n            this._state.lastDesiccantBranchLogged !== branch;\n        if (!shouldLog) return;\n        this.log(`[DESICCANT] unit ${branch} raw=${JSON.stringify(raw)} -> ${days}d`);\n        this._state.lastDesiccantBranchLogAt = now;\n        this._state.lastDesiccantBranchLogged = branch;\n    }\n\n    async _ensureCapabilities() {\n        const required = [\n            'petfeeder_foodlevel',\n            'petfeeder_eaten_food_today',\n            'petfeeder_food_out_status',\n            'petfeeder_food_out_progress',\n            'petfeeder_heap_status',\n            'petfeeder_status_mode',\n            'petfeeder_busy',\n            'petfeeder_food_in_bowl',\n            'petfeeder_schedule_progress',\n            'measure_desiccant',\n            'measure_desiccant_time',\n            'alarm_desiccant_low'\n        ];\n        for (const id of required) {\n            try {\n                if (!this.hasCapability(id)) {\n                    await this.addCapability(id);\n                    this.log('[INIT] added capability:', id);\n                }\n            } catch (e) {\n                this._warn('[INIT] addCapability failed', id, e?.message);\n            }\n        }\n\n        if (this.hasCapability('petfeeder_eaten_food_total')) {\n            try {\n                await this.removeCapability('petfeeder_eaten_food_total');\n                this.log('[INIT] removed capability:', 'petfeeder_eaten_food_total');\n            } catch (e) {\n                this._warn('[INIT] removeCapability failed', 'petfeeder_eaten_food_total', e?.message);\n            }\n        }\n    }\n\n    _normalizeSettingFromDevice(def, rawValue) {\n        if (!def) return undefined;\n        if (def.type === 'bool' || def.type === 'uint8_bool') {\n            return fromMiotBool(rawValue);\n        }\n        if (def.type === 'number') {\n            const num = toNumber(rawValue);\n            if (!Number.isFinite(num)) return undefined;\n            const [min, max] = def.range || [];\n            const clamped = clampNumber(num, min, max);\n            if (!Number.isFinite(clamped)) return undefined;\n            return Math.round(clamped);\n        }\n        return undefined;\n    }\n\n    _serializeSettingForDevice(def, value) {\n        if (!def) return undefined;\n        if (def.type === 'bool') {\n            return toMiotBoolInput(value, 'bool');\n        }\n        if (def.type === 'uint8_bool') {\n            return toMiotBoolInput(value, 'uint8');\n        }\n        if (def.type === 'number') {\n            const num = toNumber(value);\n            if (!Number.isFinite(num)) return undefined;\n            const [min, max] = def.range || [];\n            const clamped = clampNumber(num, min, max);\n            if (!Number.isFinite(clamped)) return undefined;\n            return Math.round(clamped);\n        }\n        return undefined;\n    }\n\n    async _applySettingToDevice(key, value) {\n        const def = (this._settingProps || LEGACY_SETTING_PROPS)[key];\n        if (!def) return;\n        if (!this.miio) throw new Error('miio not ready');\n\n        const payload = this._serializeSettingForDevice(def, value);\n        if (payload === undefined) throw new Error('invalid setting value');\n\n        try {\n            await this.miio.call(\n                'set_properties',\n                [\n                    {\n                        siid: def.siid,\n                        piid: def.piid,\n                        value: payload\n                    }\n                ],\n                { retries: 1 }\n            );\n            this.log('[SETTINGS] apply', key, '->', payload);\n        } catch (error) {\n            const message = error?.message || error;\n            this._warn('[SETTINGS] apply failed', key, message);\n            throw error;\n        }\n    }\n}\n\nmodule.exports = PetFeederMiotDevice;\n"
  },
  {
    "path": "drivers/petfeeder_mmgg_miot/driver.compose.json",
    "content": "{\n  \"name\": { \"en\": \"Smart Pet Feeder MIoT (WiFi)\" },\n  \"images\": {\n    \"xlarge\": \"drivers/petfeeder_mmgg_miot/assets/images/xlarge.jpg\",\n    \"large\":  \"drivers/petfeeder_mmgg_miot/assets/images/large.jpg\",\n    \"small\":  \"drivers/petfeeder_mmgg_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"petfeeder\",\n  \"$extends\": [\"defaults\"],\n  \"capabilities\": [\n    \"petfeeder_foodlevel\",\n    \"petfeeder_eaten_food_today\",\n    \"petfeeder_food_out_status\",\n    \"petfeeder_food_out_progress\",\n    \"petfeeder_heap_status\",\n    \"petfeeder_status_mode\",\n    \"petfeeder_busy\",\n    \"petfeeder_food_in_bowl\",\n    \"petfeeder_schedule_progress\",\n    \"measure_desiccant\",\n    \"measure_desiccant_time\",\n    \"alarm_desiccant_low\"\n  ]\n}\n"
  },
  {
    "path": "drivers/petfeeder_mmgg_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass PetFeederMmggMiotDriver extends Driver {}\n\nmodule.exports = PetFeederMmggMiotDriver;"
  },
  {
    "path": "drivers/petfeeder_mmgg_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Feeder preferences\"\n    },\n    \"children\": [\n      {\n        \"id\": \"child_lock\",\n        \"type\": \"checkbox\",\n        \"value\": false,\n        \"label\": {\n          \"en\": \"Child lock\"\n        }\n      },\n      {\n        \"id\": \"auto_screen_off\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Auto screen off\"\n        }\n      },\n      {\n        \"id\": \"display_schedule_progress\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Display schedule progress\"\n        }\n      },\n      {\n        \"id\": \"low_food_intake_threshold\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Low food intake threshold (g)\"\n        },\n        \"min\": 10,\n        \"max\": 90,\n        \"step\": 1,\n        \"value\": 30\n      },\n      {\n        \"id\": \"low_food_consumption_notify\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Low food consumption notification\"\n        }\n      },\n      {\n        \"id\": \"empty_food_bowl_duration\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Empty food bowl duration (h)\"\n        },\n        \"min\": 6,\n        \"max\": 24,\n        \"step\": 1,\n        \"value\": 12\n      },\n      {\n        \"id\": \"dispensing_error_correction\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Dispensing error correction\"\n        }\n      },\n      {\n        \"id\": \"bowl_spillage_prevention\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Food bowl spillage prevention\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device data\"\n    },\n    \"children\": [\n      {\n        \"id\": \"error\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Error\"\n        },\n        \"value\": \"No error\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device settings\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Telemetry\"\n    },\n    \"children\": [\n      {\n        \"id\": \"desiccant_alarm_threshold\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Desiccant low alarm threshold (%)\"\n        },\n        \"min\": 0,\n        \"max\": 100,\n        \"step\": 1,\n        \"value\": 20\n      },\n      {\n        \"id\": \"eaten_food_today_adjust\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Manual eaten food today (g)\"\n        },\n        \"step\": 1,\n        \"min\": 0,\n        \"value\": 0,\n        \"hint\": {\n          \"en\": \"Set the current daily eaten food amount if you need to correct the calculation.\"\n        }\n      }\n    ]\n  }\n]\n"
  },
  {
    "path": "drivers/petfeeder_mmgg_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/petfeeder_mmgg_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/petfeeder_mmgg_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/petwaterdispenser_mmgg_miot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/mmgg.pet_waterer.s1 // Xiaomi Smart Pet Fountain\n// https://home.miot-spec.com/spec/mmgg.pet_waterer.s4 // Xiaomi Smart Pet Fountain\n// https://home.miot-spec.com/spec/mmgg.pet_waterer.wi11 // Xiaomi Smart Pet Fountain\n\nconst mapping = {\n  \"mmgg.pet_waterer.s1\": \"mapping_sx\", \n  \"mmgg.pet_waterer.s4\": \"mapping_sx\",\n\t\"mmgg.pet_waterer.wi11\": \"mapping_wix\",\n  \"mmgg.pet_waterer.*\": \"mapping_sx\",\n};\n\nconst properties = {\n  \"mapping_sx\": {\n    \"get_properties\": [\n      { did: \"onoff\", siid: 2, piid: 2 }, // onoff\n      { did: \"mode\", siid: 2, piid: 3 }, // petwaterdispenser_mmgg_mode\n      { did: \"no_water_flag\", siid : 7, piid: 1 }, // alarm_tank_empty\n      { did: \"pump_block_flag\", siid : 7, piid: 3 }, // alarm_pump_supply\n      { did: \"error\", siid: 2, piid: 1 }, // settings.error\n      { did: \"filter_life_remaining\", siid: 3, piid: 1 }, // settings.filter_life_remaining\n      { did: \"cotton_life_remaining\", siid: 5, piid: 1 }, // settings.cotton_life_remaining\n      { did: \"cleaning_time_remaining\", siid: 6, piid: 1 }, // settings.cleaning_time_remaining\n      { did: \"light\", siid: 4, piid: 1 }, // settings.led\n    ],\n    \"set_properties\": {\n      \"onoff\": { siid: 2, piid: 2 },\n      \"mode\": { siid: 2, piid: 3 },\n      \"light\": { siid: 4, piid: 1 }\n    }\n  },\n  \"mapping_wix\": {\n    \"get_properties\": [\n      { did: \"onoff\", siid: 2, piid: 1 }, // onoff\n      { did: \"mode\", siid: 2, piid: 3 }, // petwaterdispenser_mmgg_mode\n      { did: \"no_water_flag\", siid : 7, piid: 1 }, // alarm_tank_empty\n      { did: \"pump_block_flag\", siid : 7, piid: 3 }, // alarm_pump_supply\n      { did: \"error\", siid: 2, piid: 2 }, // settings.error\n      { did: \"filter_life_remaining\", siid: 3, piid: 1 }, // settings.filter_life_remaining\n      { did: \"cotton_life_remaining\", siid: 5, piid: 1 }, // settings.cotton_life_remaining\n      { did: \"cleaning_time_remaining\", siid: 6, piid: 1 }, // settings.cleaning_time_remaining\n      { did: \"light\", siid: 4, piid: 1 }, // settings.led\n    ],\n    \"set_properties\": {\n      \"onoff\": { siid: 2, piid: 1 },\n      \"mode\": { siid: 2, piid: 3 },\n      \"light\": { siid: 4, piid: 1 }\n    }\n  }\n}\n\nconst modes = {\n  1: \"Common\",\n  2: \"Smart\"\n};\n\nclass PetwaterdispenserMmggMiotDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence(); \n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping[this.getStoreValue('mmgg.pet_waterer.*')]];\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('triggerModeChanged');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async (value) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.onoff.siid, piid: this.deviceProperties.set_properties.onoff.piid, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('petwaterdispenser_mmgg_mode', async (value) => {\n        try {\n          if (this.miio) {\n            const mode = modes[value];\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.mode.siid, piid: this.deviceProperties.set_properties.mode.piid, value: +value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      const led = await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.light.siid, piid: this.deviceProperties.set_properties.light.piid, value: newSettings.led ? 1 : 0 }], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const onoff = result.find(obj => obj.did === 'onoff');\n      const alarm_tank_empty = result.find(obj => obj.did === 'no_water_flag');\n      const alarm_pump_supply = result.find(obj => obj.did === 'pump_block_flag');\n      const error_value = result.find(obj => obj.did === 'error');\n      const led = result.find(obj => obj.did === 'light');\n      const filter_life_remaining = result.find(obj => obj.did === 'filter_life_remaining');\n      const cotton_life_remaining = result.find(obj => obj.did === 'cotton_life_remaining');\n      const cleaning_time_remaining = result.find(obj => obj.did === 'cleaning_time_remaining');\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"onoff\", onoff.value);\n      await this.updateCapabilityValue(\"alarm_tank_empty\", alarm_tank_empty.value ? false : true);\n      await this.updateCapabilityValue(\"alarm_pump_supply\", alarm_pump_supply.value);\n\n      /* settings */\n      await this.updateSettingValue(\"led\", led.value === 0 ? false : true);\n      await this.updateSettingValue(\"filter_life_remaining\", filter_life_remaining.value + '%');\n      await this.updateSettingValue(\"cotton_life_remaining\", cotton_life_remaining.value + '%');\n      await this.updateSettingValue(\"cleaning_time_remaining\", cleaning_time_remaining.value);\n\n      /* settings device error */\n      if (error_value.value === 0) {\n        var error = \"No Error\";\n      } else {\n        var error = \"Error with code \"+ error_value.value ;\n      }\n      if ( this.getSetting('error') !== error ) {\n        await this.setSettings({ error: error });\n      }\n\n      /* mode capability */\n      const mode = result.find(obj => obj.did === 'mode');\n      if (this.getCapabilityValue('petwaterdispenser_mmgg_mode') !== mode.value.toString()) {\n        const previous_mode = this.getCapabilityValue('petwaterdispenser_mmgg_mode');\n        await this.setCapabilityValue('petwaterdispenser_mmgg_mode', mode.value.toString());\n        await this.homey.flow.getDeviceTriggerCard('triggerModeChanged').trigger(this, {\"new_mode\": modes[mode.value], \"previous_mode\": modes[+previous_mode] }).catch(error => { this.error(error) });\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = PetwaterdispenserMmggMiotDevice;\n"
  },
  {
    "path": "drivers/petwaterdispenser_mmgg_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Smart Pet Water Dispenser MIoT (WiFi)\",\n    \"nl\": \"Smart Pet Water Dispenser MIoT (WiFi)\",\n    \"da\": \"Smart Pet Vanddispenser MIoT (WiFi)\",\n    \"de\": \"Smart Pet Wasserspender MIoT (WiFi)\",\n    \"es\": \"Dispensador de Agua Inteligente para Mascotas MIoT (WiFi)\",\n    \"fr\": \"Distributeur d'Eau Intelligent pour Animaux MIoT (WiFi)\",\n    \"it\": \"Distributore di Acqua Intelligente per Animali MIoT (WiFi)\",\n    \"no\": \"Smart Pet Vanndispenser MIoT (WiFi)\",\n    \"sv\": \"Smart Pet Vattendispensator MIoT (WiFi)\",\n    \"pl\": \"Inteligentny Podajnik Wody dla Zwierząt MIoT (WiFi)\",\n    \"ru\": \"Умный Диспенсер Для Воды Для Домашних Животных MIoT (WiFi)\",\n    \"ko\": \"스마트 애완동물 물 디스펜서 MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/petwaterdispenser_mmgg_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/petwaterdispenser_mmgg_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"petfeeder\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"petwaterdispenser_mmgg_mode\",\n    \"alarm_tank_empty\",\n    \"alarm_pump_supply\"\n  ]\n}"
  },
  {
    "path": "drivers/petwaterdispenser_mmgg_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass PetwaterdispenserMmggMiotDriver extends Driver {}\n\nmodule.exports = PetwaterdispenserMmggMiotDriver;"
  },
  {
    "path": "drivers/petwaterdispenser_mmgg_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración del usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"Светодиод\",\n          \"ko\": \"LED\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Data\",\n      \"nl\": \"Apparaat Data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"디바이스 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"filter_life_remaining\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter remaining\",\n          \"nl\": \"Filter over\",\n          \"da\": \"Filter tilbage\",\n          \"de\": \"Filter verbleibend\",\n          \"es\": \"Filtro restante\",\n          \"fr\": \"Filtre restant\",\n          \"it\": \"Filtro rimanente\",\n          \"no\": \"Filter gjenstår\",\n          \"sv\": \"Filter kvar\",\n          \"pl\": \"Filtr pozostały\",\n          \"ru\": \"Фильтр остался\",\n          \"ko\": \"남은 필터\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"cotton_life_remaining\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Cotton remaining\",\n          \"nl\": \"Cotton over\",\n          \"da\": \"Bomuld tilbage\",\n          \"de\": \"Baumwolle verbleibend\",\n          \"es\": \"Algodón restante\",\n          \"fr\": \"Coton restant\",\n          \"it\": \"Cotone rimanente\",\n          \"no\": \"Bomull gjenstår\",\n          \"sv\": \"Bomull kvar\",\n          \"pl\": \"Bawełna pozostała\",\n          \"ru\": \"Осталось хлопка\",\n          \"ko\": \"남은 면\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"cleaning_time_remaining\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Cleaning time remaining\",\n          \"nl\": \"Opschoon tid over\",\n          \"da\": \"Rengøringstid tilbage\",\n          \"de\": \"Reinigungszeit verbleibend\",\n          \"es\": \"Tiempo de limpieza restante\",\n          \"fr\": \"Temps de nettoyage restant\",\n          \"it\": \"Tempo di pulizia rimanente\",\n          \"no\": \"Rengjøringstid gjenstår\",\n          \"sv\": \"Rengöringstid kvar\",\n          \"pl\": \"Pozostały czas czyszczenia\",\n          \"ru\": \"Осталось времени на уборку\",\n          \"ko\": \"남은 청소 시간\"\n        },\n        \"value\": \"6\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device data\",\n      \"nl\": \"Apparaat data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"디바이스 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"error\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Error\",\n          \"nl\": \"Error\",\n          \"da\": \"Fejl\",\n          \"de\": \"Fehler\",\n          \"es\": \"Error\",\n          \"fr\": \"Erreur\",\n          \"it\": \"Errore\",\n          \"no\": \"Feil\",\n          \"sv\": \"Fel\",\n          \"pl\": \"Błąd\",\n          \"ru\": \"Ошибка\",\n          \"ko\": \"오류\"\n        },\n        \"value\": \"No error\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"디바이스 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/petwaterdispenser_mmgg_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/petwaterdispenser_mmgg_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/petwaterdispenser_mmgg_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/philips-bulb/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass PhilipsBulbDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n      this.registerCapabilityListener(\"dim\", this.onCapabilityDim.bind(this));\n\n      this.registerCapabilityListener('light_temperature', (value) => {\n        try {\n          if (this.miio) {\n            const colorvalue = this.util.denormalize(value, 3000, 5700);\n            const colortemp = ''+ colorvalue +'K';\n            return this.miio.color(colortemp);\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });     \n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = PhilipsBulbDevice;\n"
  },
  {
    "path": "drivers/philips-bulb/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Philips Lights Generic (WiFi)\",\n    \"nl\": \"Philips Lights Generic (WiFi)\",\n    \"da\": \"Philips Lights Generisk (WiFi)\",\n    \"de\": \"Philips Licht Allgemein (WiFi)\",\n    \"es\": \"Philips Luces Genéricas (WiFi)\",\n    \"fr\": \"Philips Lumières Génériques (WiFi)\",\n    \"it\": \"Philips Luci Generiche (WiFi)\",\n    \"no\": \"Philips Lys Generisk (WiFi)\",\n    \"sv\": \"Philips Ljus Generisk (WiFi)\",\n    \"pl\": \"Philips Światła Ogólne (WiFi)\",\n    \"ru\": \"Philips Лампы Общие (WiFi)\",\n    \"ko\": \"필립스 조명 일반 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/philips-bulb/assets/images/large.jpg\",\n    \"small\": \"drivers/philips-bulb/assets/images/small.jpg\"\n  },\n  \"class\": \"light\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"dim\",\n    \"light_temperature\"\n  ]\n}"
  },
  {
    "path": "drivers/philips-bulb/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass PhilipsBulbDriver extends Driver {}\n\nmodule.exports = PhilipsBulbDriver;"
  },
  {
    "path": "drivers/philips-bulb/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"ja\": \"デバイス設定\",\n      \"zh\": \"设备设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/philips-bulb/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/philips-bulb/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/philips-bulb/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/philips-eyecare/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass PhilipsEyecareDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n      this.registerCapabilityListener(\"dim\", this.onCapabilityDim.bind(this));\n\n      this.registerCapabilityListener('onoff.eyecare', (value) => {\n        try {\n          if (this.miio) {\n            return this.miio.call(\"set_eyecare\", [value ? \"on\" : \"off\"], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('onoff.ambilight', (value) => {\n        try {\n          if (this.miio) {\n            return this.miio.call(\"enable_amb\", [value ? \"on\" : \"off\"], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_prop\", [\"power\", \"bright\", \"ambstatus\", \"eyecare\"], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      await this.updateCapabilityValue(\"onoff\", result[0] === \"on\" ? true : false);\n      await this.updateCapabilityValue(\"dim\", result[1] / 100);\n      await this.updateCapabilityValue(\"onoff.ambilight\", result[2] === \"on\" ? true : false);\n      await this.updateCapabilityValue(\"onoff.eyecare\", result[3] === \"on\" ? true : false);\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = PhilipsEyecareDevice;\n"
  },
  {
    "path": "drivers/philips-eyecare/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Philips Eyecare Lamp (WiFi)\",\n    \"nl\": \"Philips Eyecare Lamp (WiFi)\",\n    \"da\": \"Philips Eyecare Lampe (WiFi)\",\n    \"de\": \"Philips Eyecare Lampe (WiFi)\",\n    \"es\": \"Lámpara Philips Eyecare (WiFi)\",\n    \"fr\": \"Lampe Philips Eyecare (WiFi)\",\n    \"it\": \"Lampada Philips Eyecare (WiFi)\",\n    \"no\": \"Philips Eyecare Lampe (WiFi)\",\n    \"sv\": \"Philips Eyecare Lampa (WiFi)\",\n    \"pl\": \"Lampa Philips Eyecare (WiFi)\",\n    \"ru\": \"Лампа Philips Eyecare (WiFi)\",\n    \"ko\": \"필립스 아이케어 램프 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/philips-eyecare/assets/images/large.jpg\",\n    \"small\": \"drivers/philips-eyecare/assets/images/small.jpg\"\n  },\n  \"class\": \"light\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"dim\",\n    \"onoff.eyecare\",\n    \"onoff.ambilight\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.eyecare\": {\n      \"title\": {\n        \"en\": \"Eyecare\",\n        \"nl\": \"Eyecare\",\n        \"da\": \"Øjenpleje\",\n        \"de\": \"Augenpflege\",\n        \"es\": \"Cuidado de ojos\",\n        \"fr\": \"Soin des yeux\",\n        \"it\": \"Cura degli occhi\",\n        \"no\": \"Øyepleie\",\n        \"sv\": \"Ögonvård\",\n        \"pl\": \"Pielęgnacja oczu\",\n        \"ru\": \"Уход за глазами\",\n        \"ko\": \"아이케어\"\n      }\n    },\n    \"onoff.ambilight\": {\n      \"title\": {\n        \"en\": \"Ambilight\",\n        \"nl\": \"Ambilight\",\n        \"da\": \"Ambilight\",\n        \"de\": \"Ambilight\",\n        \"es\": \"Ambilight\",\n        \"fr\": \"Ambilight\",\n        \"it\": \"Ambilight\",\n        \"no\": \"Ambilight\",\n        \"sv\": \"Ambilight\",\n        \"pl\": \"Ambilight\",\n        \"ru\": \"Ambilight\",\n        \"ko\": \"Ambilight\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/philips-eyecare/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass PhilipsEyecareDriver extends Driver {}\n\nmodule.exports = PhilipsEyecareDriver;"
  },
  {
    "path": "drivers/philips-eyecare/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"기기 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/philips-eyecare/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/philips-eyecare/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/philips-eyecare/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/philips_light_cbulb/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass PhilipsColorBulbDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n      this.registerCapabilityListener(\"dim\", this.onCapabilityDim.bind(this));\n\n      this.registerCapabilityListener('light_temperature', (value) => {\n        try {\n          if (this.miio) {\n            const color_temp = this.util.denormalize(value, 1880, 7000);\n            return this.miio.call(\"set_cct\", [color_temp], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('light_hue', (value) => {\n        try {\n          if (this.miio) {\n            return this.miio.call(\"set_cid\", [value * 359], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_prop\", [\"power\", \"bright\", \"cct\", \"cid\"], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      await this.updateCapabilityValue(\"onoff\", result[0] == \"on\");\n      await this.updateCapabilityValue(\"dim\", result[1] / 100);\n      await this.updateCapabilityValue(\"light_temperature\", this.util.clamp(this.util.normalize(result[2], 1880, 7000), 0 , 100));\n      await this.updateCapabilityValue(\"light_hue\", result[3] / 359);\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = PhilipsColorBulbDevice;\n"
  },
  {
    "path": "drivers/philips_light_cbulb/driver.compose.json",
    "content": "{\n  \"name\": {\n\t\"en\": \"Mijia Philips Color Bulb (WiFi)\", \n    \"nl\": \"Mijia Philips Kleur Lamp (WiFi)\",\n    \"da\": \"Mijia Philips Farve Pære (WiFi)\",\n    \"de\": \"Mijia Philips Farbige Glühbirne (WiFi)\",\n    \"es\": \"Mijia Philips Bombilla de Color (WiFi)\",\n    \"fr\": \"Mijia Philips Ampoule Couleur (WiFi)\",\n    \"it\": \"Mijia Philips Lampadina Colorata (WiFi)\",\n    \"no\": \"Mijia Philips Farget Lyspære (WiFi)\",\n    \"sv\": \"Mijia Philips Färglampa (WiFi)\",\n    \"pl\": \"Mijia Philips Kolorowa Żarówka (WiFi)\",\n    \"ru\": \"Mijia Philips Цветная Лампочка (WiFi)\",\n    \"ko\": \"Mijia Philips 컬러 전구 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/philips_light_cbulb/assets/images/large.jpg\",\n    \"small\": \"drivers/philips_light_cbulb/assets/images/small.jpg\"\n  },\n  \"class\": \"light\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"dim\",\n    \"light_hue\",\n    \"light_temperature\"\n  ],\n  \"capabilitiesOptions\": {\n    \"dim\": {\n      \"min\": 0.01\n    }\n  }\n}"
  },
  {
    "path": "drivers/philips_light_cbulb/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass PhilipsColorBulbDriver extends Driver {}\n\nmodule.exports = PhilipsColorBulbDriver;"
  },
  {
    "path": "drivers/philips_light_cbulb/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"pt\": \"Configurações do dispositivo\",\n      \"zh\": \"设备设置\",\n      \"ja\": \"デバイス設定\",\n      \"hi\": \"डिवाइस सेटिंग्स\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/philips_light_cbulb/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/philips_light_cbulb/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/philips_light_cbulb/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/philips_light_moonlight/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass PhilipsBedsideLampDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n      this.registerCapabilityListener(\"dim\", this.onCapabilityDim.bind(this));\n\n      this.registerCapabilityListener('light_temperature', (value) => {\n        try {\n          if (this.miio) {\n            const color_temp = this.util.denormalize(value, 1700, 6500);\n            return this.miio.call(\"set_ct_abx\", [color_temp, \"smooth\", 500], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('light_hue', (value) => {\n        try {\n          if (this.miio) {\n            let rgbToSend = this.hsb2rgb([value * 359, 1, 1]);\n            let argbToSend = rgbToSend[0] * 65536 + rgbToSend[1] * 256 + rgbToSend[2];\n            return this.miio.call(\"set_rgb\", [argbToSend], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_prop\", [\"pow\", \"bright\", \"rgb\", \"cct\"], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      await this.updateCapabilityValue(\"onoff\", result[0] === \"on\" ? true : false);\n      await this.updateCapabilityValue(\"dim\", result[1] / 100);\n\n      this.brightness = result[1] / 100;\n      this.drgb = result[2];\n      this.colorTemperature = result[3];\n\n      if (this.drgb != undefined && this.drgb != null) {\n        let red = (this.drgb >> 16) & 0xff;\n        let green = (this.drgb >> 8) & 0xff;\n        let blue = this.drgb & 0xff;\n        let hsbc = this.rgb2hsb([red, green, blue]);\n        const hue = hsbc[0] / 359;\n\n        await this.updateCapabilityValue(\"light_hue\", hue);\n        await this.updateCapabilityValue(\"light_saturation\", this.brightness);\n      }\n\n      if (this.colorTemperature != undefined && this.colorTemperature != null) {\n        var colorTemp = this.util.normalize(this.colorTemperature, 1700, 6500);\n\n        await this.updateCapabilityValue(\"light_temperature\", colorTemp);\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n  hsb2rgb(hsb) {\n    let rgb = [];\n    for (let offset = 240, i = 0; i < 3; i++, offset -= 120) {\n      let x = Math.abs(((hsb[0] + offset) % 360) - 240);\n      if (x <= 60) rgb[i] = 255;\n      else if (60 < x && x < 120) rgb[i] = (1 - (x - 60) / 60) * 255;\n      else rgb[i] = 0;\n    }\n    for (let i = 0; i < 3; i++) rgb[i] += (255 - rgb[i]) * (1 - hsb[1]);\n    for (let i = 0; i < 3; i++) rgb[i] *= hsb[2];\n    for (let i = 0; i < 3; i++) rgb[i] = Math.round(rgb[i]);\n    return rgb;\n  }\n\n  rgb2hsb(rgb) {\n    var hsb = [];\n    var rearranged = rgb.slice(0);\n    var maxIndex = 0,\n      minIndex = 0;\n    var tmp;\n    for (var i = 0; i < 2; i++) {\n      for (var j = 0; j < 2 - i; j++)\n        if (rearranged[j] > rearranged[j + 1]) {\n          tmp = rearranged[j + 1];\n          rearranged[j + 1] = rearranged[j];\n          rearranged[j] = tmp;\n        }\n    }\n    for (var i = 0; i < 3; i++) {\n      if (rearranged[0] == rgb[i]) minIndex = i;\n      if (rearranged[2] == rgb[i]) maxIndex = i;\n    }\n    hsb[2] = rearranged[2] / 255.0;\n    hsb[1] = 1 - rearranged[0] / rearranged[2];\n    hsb[0] = maxIndex * 120 + 60 * (rearranged[1] / hsb[1] / rearranged[2] + (1 - 1 / hsb[1])) * ((maxIndex - minIndex + 3) % 3 == 1 ? 1 : -1);\n    hsb[0] = (hsb[0] + 360) % 360;\n    return hsb;\n  }\n\n}\n\nmodule.exports = PhilipsBedsideLampDevice;\n"
  },
  {
    "path": "drivers/philips_light_moonlight/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Philips Bedside Lamp (WiFi)\",\n    \"nl\": \"Philips Bedside Lamp (WiFi)\",\n    \"da\": \"Philips Sengelampe (WiFi)\",\n    \"de\": \"Philips Nachttischlampe (WiFi)\",\n    \"es\": \"Lámpara de Noche Philips (WiFi)\",\n    \"fr\": \"Lampe de Chevet Philips (WiFi)\",\n    \"it\": \"Lampada da Comodino Philips (WiFi)\",\n    \"no\": \"Philips Nattbordslampe (WiFi)\",\n    \"sv\": \"Philips Sänglampa (WiFi)\",\n    \"pl\": \"Lampka Nocna Philips (WiFi)\",\n    \"ru\": \"Прикроватная лампа Philips (WiFi)\",\n    \"ko\": \"필립스 침대 옆 램프 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/philips_light_moonlight/assets/images/large.jpg\",\n    \"small\": \"drivers/philips_light_moonlight/assets/images/small.jpg\"\n  },\n  \"class\": \"light\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"dim\",\n    \"light_hue\",\n    \"light_saturation\",\n    \"light_temperature\",\n    \"light_mode\"\n  ]\n}"
  },
  {
    "path": "drivers/philips_light_moonlight/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass PhilipsBedsideLampDriver extends Driver {}\n\nmodule.exports = PhilipsBedsideLampDriver;"
  },
  {
    "path": "drivers/philips_light_moonlight/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/philips_light_moonlight/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/philips_light_moonlight/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/philips_light_moonlight/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/philips_light_strip/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\nconst tinycolor = require(\"tinycolor2\");\n\n/* supported devices */\n// https://home.miot-spec.com/spec/philips.light.strip5 // Xiaomi Smart Lightstrip Pro\n\nconst mapping = {\n  \"philips.light.strip5\": \"mapping_default\",\n  \"philips.light.*\": \"mapping_default\",\n};\n\nconst properties = {\n  \"mapping_default\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"mode\", siid: 2, piid: 2 }, // ?\n      { did: \"brightness\", siid: 2, piid: 3 }, // dim\n      { did: \"color\", siid: 3, piid: 4 }, // light_hue, light_saturation\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"mode\": { siid: 2, piid: 2 },\n      \"brightness\": { siid: 2, piid: 3 },\n      \"color\":  { siid: 2, piid: 4 }\n    }\n  }\n}\n\nclass PhilipsLightStripDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['philips.light.*']];\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.power.siid, piid: this.deviceProperties.set_properties.power.piid, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('dim', async ( value ) => {\n        try {\n          if (this.miio) {\n            const brightness = value * 100;\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.brightness.siid, piid: this.deviceProperties.set_properties.brightness.piid, value: brightness }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerMultipleCapabilityListener(['light_hue', 'light_saturation'], async (valueObj) => {\n        try {\n          if (this.miio) {\n            const hue_value = typeof valueObj.light_hue !== 'undefined' ? valueObj.light_hue : this.getCapabilityValue('light_hue');\n            const saturation_value = typeof valueObj.light_saturation !== 'undefined' ? valueObj.light_saturation : this.getCapabilityValue('light_saturation');\n            const color = tinycolor({h: hue_value, s: saturation_value, v: 1 });\n            const rgbValue = color.toHex();\n            const intValue = parseInt(rgbValue.substring(1), 16);\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.color.siid, piid: this.deviceProperties.set_properties.color.piid, value: intValue }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const onoff = result.find(obj => obj.did === 'power');\n      const brightness = result.find(obj => obj.did === 'brightness');\n      const color = result.find(obj => obj.did === 'color');\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"onoff\", onoff.value);\n      await this.updateCapabilityValue(\"dim\", brightness.value / 100);\n\n      const hexValue = color.value.toString(16).padStart(6, '0');\n      const colorvalue = tinycolor(`#${hexValue}`);\n\n      await this.updateCapabilityValue(\"light_hue\", colorvalue.toHsv().h);\n      await this.updateCapabilityValue(\"light_saturation\", colorvalue.toHsv().s);\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = PhilipsLightStripDevice;\n"
  },
  {
    "path": "drivers/philips_light_strip/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Philips / Xiaomi Light Strip (WiFi)\",\n    \"nl\": \"Philips Xiaomi Light Strip (WiFi)\",\n    \"da\": \"Philips / Xiaomi Lysstrimmel (WiFi)\",\n    \"de\": \"Philips / Xiaomi Lichtleiste (WiFi)\",\n    \"es\": \"Philips / Xiaomi Tira de Luces (WiFi)\",\n    \"fr\": \"Philips / Xiaomi Bande Lumineuse (WiFi)\",\n    \"it\": \"Philips / Xiaomi Striscia Luminosa (WiFi)\",\n    \"no\": \"Philips / Xiaomi Lyslist (WiFi)\",\n    \"sv\": \"Philips / Xiaomi Ljusremsa (WiFi)\",\n    \"pl\": \"Philips / Xiaomi Pasek LED (WiFi)\",\n    \"ru\": \"Philips / Xiaomi Светодиодная лента (WiFi)\",\n    \"ko\": \"필립스 / 샤오미 라이트 스트립 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/philips_light_strip/assets/images/large.jpg\",\n    \"small\": \"drivers/philips_light_strip/assets/images/small.jpg\"\n  },\n  \"class\": \"light\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"dim\",\n    \"light_hue\",\n    \"light_saturation\"\n  ]\n}"
  },
  {
    "path": "drivers/philips_light_strip/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass PhilipsLightStripDriver extends Driver {}\n\nmodule.exports = PhilipsLightStripDriver;"
  },
  {
    "path": "drivers/philips_light_strip/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"ja\": \"デバイス設定\",\n      \"zh\": \"设备设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/philips_light_strip/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/philips_light_strip/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/philips_light_strip/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/plug_chuangmi_plug_m1/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/chuangmi.plug.m1\n\nclass MiSmartPlugWiFiDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n\n      this.registerCapabilityListener('onoff.led', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_wifi_led\", [value ? \"on\" : \"off\"]);\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call(\"get_prop\", [\"power\", \"temperature\", \"wifi_led\"]);\n      if (!this.getAvailable()) { await this.setAvailable(); }\n      \n      await this.updateCapabilityValue(\"onoff\", result[0] === \"on\" ? true : false);\n      await this.updateCapabilityValue(\"measure_temperature\", result[1]);\n      await this.updateCapabilityValue(\"onoff.led\", result[2] === \"on\" ? true : false);\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = MiSmartPlugWiFiDevice;\n"
  },
  {
    "path": "drivers/plug_chuangmi_plug_m1/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Smart Plug (WiFi)\",\n    \"nl\": \"Mi Smart Plug (WiFi)\",\n    \"da\": \"Mi Smart Plug (WiFi)\",\n    \"de\": \"Mi Smart Plug (WiFi)\",\n    \"es\": \"Mi Smart Plug (WiFi)\",\n    \"fr\": \"Mi Smart Plug (WiFi)\",\n    \"it\": \"Mi Smart Plug (WiFi)\",\n    \"no\": \"Mi Smart Plug (WiFi)\",\n    \"sv\": \"Mi Smart Plug (WiFi)\",\n    \"pl\": \"Mi Smart Plug (WiFi)\",\n    \"ru\": \"Mi Smart Plug (WiFi)\",\n    \"ko\": \"Mi Smart Plug (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/plug_chuangmi_plug_m1/assets/images/large.jpg\",\n    \"small\": \"drivers/plug_chuangmi_plug_m1/assets/images/small.jpg\"\n  },\n  \"class\": \"socket\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"measure_temperature\",\n    \"onoff.led\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.led\": {\n      \"title\": {\n        \"en\": \"WiFi LED\",\n        \"nl\": \"WiFi LED\",\n        \"da\": \"WiFi LED\",\n        \"de\": \"WiFi LED\",\n        \"es\": \"WiFi LED\",\n        \"fr\": \"WiFi LED\",\n        \"it\": \"WiFi LED\",\n        \"no\": \"WiFi LED\",\n        \"sv\": \"WiFi LED\",\n        \"pl\": \"WiFi LED\",\n        \"ru\": \"WiFi LED\",\n        \"ko\": \"WiFi LED\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/plug_chuangmi_plug_m1/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiSmartPlugWiFiDriver extends Driver {}\n\nmodule.exports = MiSmartPlugWiFiDriver;"
  },
  {
    "path": "drivers/plug_chuangmi_plug_m1/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"기기 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/plug_chuangmi_plug_m1/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/plug_chuangmi_plug_m1/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/plug_chuangmi_plug_m1/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/plug_chuangmi_plug_v1_v3/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/chuangmi.plug.v1\n// https://home.miot-spec.com/spec/chuangmi.plug.v3\n\nclass MiSmartPlugWiFiWithUSBDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n\n      this.registerCapabilityListener('onoff.usb', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(value ? \"set_usb_on\" : \"set_usb_off\", []);\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('onoff.led', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_wifi_led\", [value ? \"on\" : \"off\"]);\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call(\"get_prop\", [\"power\", \"usb_on\", \"temperature\", \"wifi_led\"]);\n      if (!this.getAvailable()) { await this.setAvailable(); }\n      \n      await this.updateCapabilityValue(\"onoff\", result[0] == \"on\" ? true : false);\n      await this.updateCapabilityValue(\"onoff.usb\", result[1]);\n      await this.updateCapabilityValue(\"measure_temperature\", result[2]);\n      await this.updateCapabilityValue(\"onoff.led\", result[3] == \"on\" ? true : false);\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = MiSmartPlugWiFiWithUSBDevice;\n"
  },
  {
    "path": "drivers/plug_chuangmi_plug_v1_v3/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Smart Plug With 1 or 2 USB (WiFi)\",\n    \"nl\": \"Mi Smart Plug met 1 of 2 USB (WiFi)\",\n    \"da\": \"Mi Smart Plug med 1 eller 2 USB (WiFi)\",\n    \"de\": \"Mi Smart Plug mit 1 oder 2 USB (WiFi)\",\n    \"es\": \"Mi Smart Plug con 1 o 2 USB (WiFi)\",\n    \"fr\": \"Mi Smart Plug avec 1 ou 2 USB (WiFi)\",\n    \"it\": \"Mi Smart Plug con 1 o 2 USB (WiFi)\",\n    \"no\": \"Mi Smart Plug med 1 eller 2 USB (WiFi)\",\n    \"sv\": \"Mi Smart Plug med 1 eller 2 USB (WiFi)\",\n    \"pl\": \"Mi Smart Plug z 1 lub 2 USB (WiFi)\",\n    \"ru\": \"Mi Smart Plug с 1 или 2 USB (WiFi)\",\n    \"ko\": \"1 또는 2 USB(와이파이)를 갖춘 Mi 스마트 플러그\"\n  },\n  \"images\": {\n    \"large\": \"drivers/plug_chuangmi_plug_v1_v3/assets/images/large.jpg\",\n    \"small\": \"drivers/plug_chuangmi_plug_v1_v3/assets/images/small.jpg\"\n  },\n  \"class\": \"socket\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"measure_temperature\",\n    \"onoff.usb\",\n    \"onoff.led\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.usb\": {\n      \"title\": {\n        \"en\": \"USB power\",\n        \"nl\": \"USB stroom\",\n        \"da\": \"USB strøm\",\n        \"de\": \"USB Strom\",\n        \"es\": \"Potencia USB\",\n        \"fr\": \"Alimentation USB\",\n        \"it\": \"Alimentazione USB\",\n        \"no\": \"USB-strøm\",\n        \"sv\": \"USB-ström\",\n        \"pl\": \"Zasilanie USB\",\n        \"ru\": \"Питание USB\",\n        \"ko\": \"USB 전원\"\n      }\n    },\n    \"onoff.led\": {\n      \"title\": {\n        \"en\": \"WiFi LED\",\n        \"nl\": \"WiFi LED\",\n        \"da\": \"WiFi LED\",\n        \"de\": \"WiFi LED\",\n        \"es\": \"WiFi LED\",\n        \"fr\": \"WiFi LED\",\n        \"it\": \"WiFi LED\",\n        \"no\": \"WiFi LED\",\n        \"sv\": \"WiFi LED\",\n        \"pl\": \"WiFi LED\",\n        \"ru\": \"WiFi LED\",\n        \"ko\": \"와이파이 LED\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/plug_chuangmi_plug_v1_v3/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiSmartPlugWiFiWithUSBDriver extends Driver {}\n\nmodule.exports = MiSmartPlugWiFiWithUSBDriver;"
  },
  {
    "path": "drivers/plug_chuangmi_plug_v1_v3/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/plug_chuangmi_plug_v1_v3/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/plug_chuangmi_plug_v1_v3/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/plug_chuangmi_plug_v1_v3/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/plug_cuco_plug/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/cuco.plug.v2eur // Xiaomi Smart Plug 2\n\nconst mapping = {\n  \"cuco.plug.v2eur\": \"mapping_default\",\n  \"cuco.plug.*\": \"mapping_default\",\n};\n\nconst properties = {\n  \"mapping_default\": {\n    \"get_properties\": [\n      { did: \"power\", siid: 2, piid: 1 }, // onoff\n      { did: \"meter_power\", siid: 11, piid: 1 }, // meter_power\n      { did: \"measure_power\", siid: 11, piid: 2 }, // measure_power\n      { did: \"child_lock\", siid: 7, piid: 1 }, // settings.childLock\n      { did: \"light\", siid: 13, piid: 1 } // settings.led\n    ],\n    \"set_properties\": {\n      \"power\": { siid: 2, piid: 1 },\n      \"child_lock\": { siid: 7, piid: 1 },\n      \"light\": { siid: 13, piid: 1 }\n    }\n  }\n}\n\nclass CucoPlugDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['cuco.plug.*']];\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.power.siid, piid: this.deviceProperties.set_properties.power.piid, value: value }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onSettings({ oldSettings, newSettings, changedKeys }) {\n    if (changedKeys.includes(\"address\") || changedKeys.includes(\"token\") || changedKeys.includes(\"polling\")) {\n      this.refreshDevice();\n    }\n\n    if (changedKeys.includes(\"led\")) {\n      const led = await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.light.siid, piid: this.deviceProperties.set_properties.light.piid, value: newSettings.led ? 2 : 0 }], { retries: 1 });\n    }\n\n    if (changedKeys.includes(\"child_lock\")) {\n      const childlock = await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.child_lock.siid, piid: this.deviceProperties.set_properties.child_lock.piid, value: newSettings.childLock }], { retries: 1 });\n    }\n\n    return Promise.resolve(true);\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const onoff = result.find(obj => obj.did === 'power');\n      const meter_power = result.find(obj => obj.did === 'meter_power');\n      const measure_power = result.find(obj => obj.did === 'measure_power');\n      const child_lock = result.find(obj => obj.did === 'child_lock');\n      const led = result.find(obj => obj.did === 'light');\n\n      /* capabilities */\n      await this.updateCapabilityValue(\"onoff\", onoff.value);\n      await this.updateCapabilityValue(\"meter_power\", meter_power.value / 1000);\n      await this.updateCapabilityValue(\"measure_power\", measure_power.value);\n\n      /* settings */\n      await this.updateSettingValue(\"led\", led.value);\n      await this.updateSettingValue(\"childLock\", child_lock.value); \n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = CucoPlugDevice;\n"
  },
  {
    "path": "drivers/plug_cuco_plug/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Xiaomi Smart Plug (WiFi)\",\n    \"nl\": \"Xiaomi Smart Plug (WiFi)\",\n    \"da\": \"Xiaomi Smart Plug (WiFi)\",\n    \"de\": \"Xiaomi Smart Plug (WiFi)\",\n    \"es\": \"Xiaomi Smart Plug (WiFi)\",\n    \"fr\": \"Xiaomi Smart Plug (WiFi)\",\n    \"it\": \"Xiaomi Smart Plug (WiFi)\",\n    \"no\": \"Xiaomi Smart Plug (WiFi)\",\n    \"sv\": \"Xiaomi Smart Plug (WiFi)\",\n    \"pl\": \"Xiaomi Smart Plug (WiFi)\",\n    \"ru\": \"Xiaomi Smart Plug (WiFi)\",\n    \"ko\": \"Xiaomi Smart Plug (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/plug_cuco_plug/assets/images/large.jpg\",\n    \"small\": \"drivers/plug_cuco_plug/assets/images/small.jpg\"\n  },\n  \"class\": \"socket\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"measure_power\",\n    \"meter_power\",\n    \"measure_voltage\"\n  ]\n}"
  },
  {
    "path": "drivers/plug_cuco_plug/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass CucoPlugDriver extends Driver {}\n\nmodule.exports = CucoPlugDriver;"
  },
  {
    "path": "drivers/plug_cuco_plug/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"User Settings\",\n      \"nl\": \"Gebruikersinstellingem\",\n      \"da\": \"Brugerindstillinger\",\n      \"de\": \"Benutzereinstellungen\",\n      \"es\": \"Configuración del usuario\",\n      \"fr\": \"Paramètres utilisateur\",\n      \"it\": \"Impostazioni utente\",\n      \"no\": \"Brukerinnstillinger\",\n      \"sv\": \"Användarinställningar\",\n      \"pl\": \"Ustawienia użytkownika\",\n      \"ru\": \"Настройки пользователя\",\n      \"ko\": \"사용자 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"led\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"LED\",\n          \"nl\": \"LED\",\n          \"da\": \"LED\",\n          \"de\": \"LED\",\n          \"es\": \"LED\",\n          \"fr\": \"LED\",\n          \"it\": \"LED\",\n          \"no\": \"LED\",\n          \"sv\": \"LED\",\n          \"pl\": \"LED\",\n          \"ru\": \"LED\",\n          \"ko\": \"LED\"\n        }\n      },\n      {\n        \"id\": \"childLock\",\n        \"type\": \"checkbox\",\n        \"value\": true,\n        \"label\": {\n          \"en\": \"Child Lock\",\n          \"nl\": \"Kinderslot\",\n          \"da\": \"Børnesikring\",\n          \"de\": \"Kindersicherung\",\n          \"es\": \"Bloqueo para niños\",\n          \"fr\": \"Verrouillage enfant\",\n          \"it\": \"Blocco bambini\",\n          \"no\": \"Barnelås\",\n          \"sv\": \"Barnlås\",\n          \"pl\": \"Blokada dla dzieci\",\n          \"ru\": \"Блокировка от детей\",\n          \"ko\": \"어린이 잠금\"\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/plug_cuco_plug/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/plug_cuco_plug/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/plug_cuco_plug/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/powerstrip_qmi_powerstrip_v1/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass PowerStripQMIV1Device extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_prop\", [\"power\", \"power_consume_rate\", \"voltage\", \"temperature\"], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      await this.updateCapabilityValue(\"onoff\", result[0] == \"on\" ? true : false);\n      await this.updateCapabilityValue(\"measure_power\", parseInt(result[1]));\n      await this.updateCapabilityValue(\"measure_voltage\", result[2] / 100);\n      await this.updateCapabilityValue(\"measure_temperature\", result[3]);\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = PowerStripQMIV1Device;\n"
  },
  {
    "path": "drivers/powerstrip_qmi_powerstrip_v1/driver.compose.json",
    "content": "{\n  \"name\": {\n\t\"en\": \"Chingmi Smart Power Strip (WiFi)\", \n    \"es\": \"Toma de Corriente Inteligente Chingmi (WiFi)\",\n    \"fr\": \"Multiprise Intelligente Chingmi (WiFi)\",\n    \"it\": \"Ciabatta Intelligente Chingmi (WiFi)\",\n    \"no\": \"Chingmi Smart Strømuttak (WiFi)\",\n    \"sv\": \"Chingmi Smart Strömbrytare (WiFi)\",\n    \"pl\": \"Inteligentna Listwa Zasilająca Chingmi (WiFi)\",\n    \"ru\": \"Умная Линия Электропитания Chingmi (WiFi)\",\n    \"ko\": \"칭미 스마트 전원 스트립 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/powerstrip_qmi_powerstrip_v1/assets/images/large.jpg\",\n    \"small\": \"drivers/powerstrip_qmi_powerstrip_v1/assets/images/small.jpg\"\n  },\n  \"class\": \"socket\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"measure_power\",\n    \"measure_temperature\",\n    \"measure_voltage\"\n  ]\n}"
  },
  {
    "path": "drivers/powerstrip_qmi_powerstrip_v1/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass PowerStripQMIV1Driver extends Driver {}\n\nmodule.exports = PowerStripQMIV1Driver;"
  },
  {
    "path": "drivers/powerstrip_qmi_powerstrip_v1/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/powerstrip_qmi_powerstrip_v1/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/powerstrip_qmi_powerstrip_v1/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/powerstrip_qmi_powerstrip_v1/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/relay_c2acn01/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass RelayC2ACN01Device extends Device {\n\n  async registerCapabilities() {\n\n    this.registerCapabilityListener('onoff.0', async (value) => {\n      try {\n        return await this.homey.app.mihub.sendWrite(this.data.sid, { channel_0: value ? \"on\" : \"off\" });\n      } catch (error) {\n        this.error(error);\n      }\n    });\n    this.registerCapabilityListener('onoff.1', async (value) => {\n      try {\n        return await this.homey.app.mihub.sendWrite(this.data.sid, { channel_1: value ? \"on\" : \"off\" });\n      } catch (error) {\n        this.error(error);\n      }\n    });\n  }\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* onoff left switch */\n      if (device.data[\"channel_0\"]) {\n        await this.updateCapabilityValue(\"onoff.0\", device.data[\"channel_0\"] == \"on\" ? true : false);\n  \n        if (device.data[\"channel_0\"] == \"on\") {\n          await this.homey.flow.getDeviceTriggerCard('leftSwitchOn').trigger(this).catch(error => { this.error(error) });\n        } else if (device.data[\"channel_0\"] == \"off\") {\n          await this.homey.flow.getDeviceTriggerCard('leftSwitchOff').trigger(this).catch(error => { this.error(error) });\n        }\n      }\n\n      /* onoff right switch */\n      if (device.data[\"channel_1\"]) {\n        await this.updateCapabilityValue(\"onoff.1\", device.data[\"channel_1\"] == \"on\" ? true : false);\n  \n        if (device.data[\"channel_1\"] == \"on\") {\n          await this.homey.flow.getDeviceTriggerCard('rightSwitchOn').trigger(this).catch(error => { this.error(error) });\n        } else if (device.data[\"channel_1\"] == \"off\") {\n          await this.homey.flow.getDeviceTriggerCard('rightSwitchOff').trigger(this).catch(error => { this.error(error) });\n        }\n      }\n\n      /* measure_power */\n      if (device.data[\"load_power\"]) {\n        await this.updateCapabilityValue(\"measure_power\", parseInt(device.data[\"load_power\"]));\n      }\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = RelayC2ACN01Device;"
  },
  {
    "path": "drivers/relay_c2acn01/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Aqara 2 Channel Relay (Gateway)\",\n    \"nl\": \"Aqara 2 Channel Relay (Gateway)\",\n    \"da\": \"Aqara 2-kanals relæ (Gateway)\",\n    \"de\": \"Aqara 2-Kanal-Relais (Gateway)\",\n    \"es\": \"Relé de 2 canales Aqara (Gateway)\",\n    \"fr\": \"Relais 2 canaux Aqara (Gateway)\",\n    \"it\": \"Relè a 2 canali Aqara (Gateway)\",\n    \"no\": \"Aqara 2-kanals relé (Gateway)\",\n    \"sv\": \"Aqara 2-kanals relä (Gateway)\",\n    \"pl\": \"Przekaźnik 2-kanałowy Aqara (Gateway)\",\n    \"ru\": \"Реле Aqara на 2 канала (Шлюз)\",\n    \"ko\": \"Aqara 2채널 릴레이 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/relay_c2acn01/assets/images/large.jpg\",\n    \"small\": \"/drivers/relay_c2acn01/assets/images/small.jpg\"\n  },\n  \"class\": \"socket\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"onoff.0\",\n    \"onoff.1\",\n    \"measure_power\"\n  ],\n  \"capabilitiesOptions\": {\n    \"onoff.0\": {\n      \"title\": {\n        \"en\": \"Left Switch\",\n        \"nl\": \"Linkerschakelaar\",\n        \"da\": \"Venstre kontakt\",\n        \"de\": \"Linker Schalter\",\n        \"es\": \"Interruptor izquierdo\",\n        \"fr\": \"Commutateur gauche\",\n        \"it\": \"Interruttore sinistro\",\n        \"no\": \"Venstre bryter\",\n        \"sv\": \"Vänster brytare\",\n        \"pl\": \"Lewy włącznik\",\n        \"ru\": \"Левый переключатель\",\n        \"ko\": \"왼쪽 스위치\"\n      }\n    },\n    \"onoff.1\": {\n      \"title\": {\n        \"en\": \"Right Switch\",\n        \"nl\": \"Rechterschakelaar\",\n        \"da\": \"Højre kontakt\",\n        \"de\": \"Rechter Schalter\",\n        \"es\": \"Interruptor derecho\",\n        \"fr\": \"Commutateur droit\",\n        \"it\": \"Interruttore destro\",\n        \"no\": \"Høyre bryter\",\n        \"sv\": \"Höger brytare\",\n        \"pl\": \"Prawy włącznik\",\n        \"ru\": \"Правый переключатель\",\n        \"ko\": \"오른쪽 스위치\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "drivers/relay_c2acn01/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass RelayC2ACN01Driver extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('leftSwitchOn');\n    this.homey.flow.getDeviceTriggerCard('leftSwitchOff');\n    this.homey.flow.getDeviceTriggerCard('rightSwitchOn');\n    this.homey.flow.getDeviceTriggerCard('rightSwitchOff');\n\n    this.config = {\n      model: [\"relay.c2acn01\"]\n    }\n  }\n\n}\n\nmodule.exports = RelayC2ACN01Driver;"
  },
  {
    "path": "drivers/relay_c2acn01/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/remote_chuangmi_remote_v2/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass IRRemoteDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // DEVICE SPECIFIC VARIABLES\n      this.data = this.getData();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (value) {\n            if (this.data && this.data.onoff1) {\n              return await this.sendIrCode(this.data.onoff1);\n            } else {\n              return await this.sendIrCode(this.data.onoff);\n            }\n          } else {\n            if (this.data && this.data.onoff2) {\n              return await this.sendIrCode(this.data.onoff2);\n            } else {\n              return await this.sendIrCode(this.data.onoff);\n            }\n          }\n          return Promise.resolve(true);\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('channel_up', async ( value ) => {\n        try {\n          return await this.sendIrCode(this.data.channel_up);\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('channel_down', async ( value ) => {\n        try {\n          return await this.sendIrCode(this.data.channel_down);\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('volume_up', async ( value ) => {\n        try {\n          return await this.sendIrCode(this.data.volume_up);\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('volume_down', async ( value ) => {\n        try {\n          return await this.sendIrCode(this.data.volume_down);\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('volume_mute', async ( value ) => {\n        try {\n          return await this.sendIrCode(this.data.volume_mute);\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('dim', async ( value ) => {\n        try {\n          if (this.data && this.data.dim1) {\n            return await this.sendIrCode(this.data.dim + value);\n          } else {\n            return await this.sendIrCode(this.data.dim);\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async sendIrCode(code) {\n    try {\n      const settings = this.getSettings();\n      for (let i = 0; i < settings.replay; i++) {\n        await this.util.sleep(500);\n        await this.miio.call(\"miIO.ir_play\", { freq: 38400, code: code });\n      }\n      return Promise.resolve(true);\n    } catch (error) {\n      this.error(error);\n      return Promise.reject(error);\n    }\n  }\n\n}\n\nmodule.exports = IRRemoteDevice;\n"
  },
  {
    "path": "drivers/remote_chuangmi_remote_v2/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Universal Intelligent IR Remote Controller (WiFi)\",\n    \"nl\": \"Universal Intelligent IR Remote Controller (WiFi)\",\n    \"da\": \"Universel intelligent IR-fjernbetjening (WiFi)\",\n    \"de\": \"Universeller intelligenter IR-Fernbedienungscontroller (WiFi)\",\n    \"es\": \"Controlador de mando a distancia IR inteligente universal (WiFi)\",\n    \"fr\": \"Contrôleur de télécommande IR intelligent universel (WiFi)\",\n    \"it\": \"Controller universale intelligente IR (WiFi)\",\n    \"no\": \"Universal intelligent IR-fjernkontroll (WiFi)\",\n    \"sv\": \"Universell intelligent IR-fjärrkontroll (WiFi)\",\n    \"pl\": \"Uniwersalny inteligentny kontroler zdalny IR (WiFi)\",\n    \"ru\": \"Универсальный интеллектуальный ИК-пульт дистанционного управления (WiFi)\",\n    \"ko\": \"범용 지능형 IR 리모컨 컨트롤러 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/remote_chuangmi_remote_v2/assets/images/large.jpg\",\n    \"small\": \"drivers/remote_chuangmi_remote_v2/assets/images/small.jpg\"\n  },\n  \"class\": \"other\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"channel_up\",\n    \"channel_down\",\n    \"volume_up\",\n    \"volume_down\",\n    \"volume_mute\",\n    \"dim\"\n  ],\n  \"pair\": [\n    {\n      \"id\": \"deviceTypes\"\n    },\n    {\n      \"id\": \"devices\",\n      \"navigation\": {\n        \"prev\": \"deviceTypes\"\n      }\n    },\n    {\n      \"id\": \"deviceCharacteristics\",\n      \"navigation\": {\n        \"next\": \"keys\",\n        \"prev\": \"devices\"\n      }\n    },\n    {\n      \"id\": \"keys\",\n      \"navigation\": {\n        \"next\": \"done\",\n        \"prev\": \"deviceCharacteristics\"\n      }\n    },\n    {\n      \"id\": \"done\",\n      \"navigation\": {\n        \"prev\": \"devices\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "drivers/remote_chuangmi_remote_v2/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\nconst miio = require('miio');\n\nclass IRRemoteDriver extends Driver {\n\n  onPair(session) {\n\n    let pairingDevice = {\n      name: \"Unknown\",\n      settings: {},\n      data: {},\n      capabilities: [],\n      capabilitiesOptions: {}\n    };\n\n    let type = \"other\";\n\n    session.setHandler('getCurrentDevice', async (data) => {\n      try {\n        return Promise.resolve(pairingDevice);\n      } catch (error) {\n        this.error(error);\n        return Promise.reject(error);\n      }\n    });\n\n    session.setHandler('getCurrentDeviceForCharacteristics', async (data) => {\n      try {\n        return Promise.resolve(pairingDevice);\n      } catch (error) {\n        this.error(error);\n        return Promise.reject(error);\n      }\n    });\n\n    session.setHandler('getDevicesList', async (data) => {\n      try {\n        const devices = await this.homey.settings.get(\"irDevicesList\");\n        return Promise.resolve(devices || []);\n      } catch (error) {\n        this.error(error);\n        return Promise.reject(error);\n      }\n    });\n\n    session.setHandler('newCharacteristics', async (data) => {\n      try {\n        pairingDevice = data;\n\n        if (pairingDevice.capabilitiesOptions && pairingDevice.capabilitiesOptions.dim) {\n          pairingDevice.capabilitiesOptions.dim.max = parseInt(data.characteristicsSettings.dim);\n        }\n\n        return Promise.resolve(pairingDevice.capabilitiesOptions);\n      } catch (error) {\n        this.error(error);\n        return Promise.reject(error);\n      }\n    });\n\n    session.setHandler('learnCode', async (data) => {\n      try {\n        this.timekey = \"123456789012345\";\n        this.data = data;\n\n        const device = await miio.device({ address: data.ip, token: data.token });\n        const ir_learn = await device.call(\"miIO.ir_learn\", { key: this.timekey });\n\n        setTimeout(async () => {\n          const ir_read = await device.call(\"miIO.ir_read\", { key: this.timekey });\n\n          if (ir_read[\"code\"] !== \"\") {\n            let value = { code: ir_read[\"code\"] };\n            pairingDevice.data[data.key] = ir_read[\"code\"];\n            return Promise.resolve(value);\n          } else {\n            return Promise.reject(\"timeout\");\n          }\n        }, 5000);\n\n\n      } catch (error) {\n        this.error(error);\n        if (error == \"Error: Could not connect to device, handshake timeout\") {\n          return Promise.reject(\"offline\");\n        } else {\n          return Promise.reject(error);\n        }\n      }\n    });\n\n    session.setHandler('selectedType', async (data) => {\n      try {\n        type = data.type;\n        pairingDevice.name = data.name;\n        pairingDevice.icon = data.type + \".svg\";\n        pairingDevice.capabilities = data.capabilities;\n        pairingDevice.capabilitiesOptions = data.capabilitiesOptions;\n        pairingDevice.characteristicsSettings = data.characteristicsSettings;\n\n        return Promise.resolve(type);\n      } catch (error) {\n        this.error(error);\n        return Promise.reject(error);\n      }\n    });\n\n    session.setHandler('selectedDevice', async (data) => {\n      try {\n        pairingDevice.settings.deviceIp = data.devices.ip;\n        pairingDevice.settings.deviceToken = data.devices.token;\n        pairingDevice.data.id =\n          pairingDevice.name +\n          \"-\" +\n          data.devices.ip +\n          \"-\" +\n          Math.floor((1 + Math.random()) * 0x10000)\n            .toString(16)\n            .substring(1);\n\n        return Promise.resolve(pairingDevice);\n      } catch (error) {\n        this.error(error);\n        return Promise.reject(error);\n      }\n    });\n\n    session.setHandler('allmostDone', async (data) => {\n      try {\n        return Promise.resolve(pairingDevice);\n      } catch (error) {\n        this.error(error);\n        return Promise.reject(error);\n      }\n    });\n\n  }\n\n}\n\nmodule.exports = IRRemoteDriver;"
  },
  {
    "path": "drivers/remote_chuangmi_remote_v2/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Configure IR Codes\",\n      \"nl\": \"IR codes configureren\",\n      \"da\": \"Konfigurer IR-koder\",\n      \"de\": \"IR-Codes konfigurieren\",\n      \"es\": \"Configurar códigos IR\",\n      \"fr\": \"Configurer les codes IR\",\n      \"it\": \"Configura codici IR\",\n      \"no\": \"Konfigurer IR-koder\",\n      \"sv\": \"Konfigurera IR-koder\",\n      \"pl\": \"Konfiguruj kody IR\",\n      \"ru\": \"Настроить IR-коды\",\n      \"ko\": \"IR 코드 구성\"\n    },\n    \"children\": [\n      {\n        \"id\": \"replay\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Replay\",\n          \"nl\": \"Herhaal\",\n          \"da\": \"Genspil\",\n          \"de\": \"Wiederholen\",\n          \"es\": \"Repetir\",\n          \"fr\": \"Rejouer\",\n          \"it\": \"Rigioca\",\n          \"no\": \"Spill av igjen\",\n          \"sv\": \"Spela upp igen\",\n          \"pl\": \"Odtwórz ponownie\",\n          \"ru\": \"Повторить\",\n          \"ko\": \"재생\"\n        },\n        \"value\": 1,\n        \"min\": 1,\n        \"max\": 10\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/remote_chuangmi_remote_v2/pair/capabilities.js",
    "content": "var devices = {\n  tv: {\n    name: \"TV\",\n    capabilities: [\"onoff\", \"volume_up\", \"volume_down\", \"channel_up\", \"channel_down\", \"volume_mute\"],\n    capabilitiesOptions: {\n      onoff: {\n        title: {\n          en: \"Standby\"\n        }\n      },\n      volume_up: {\n        title: {\n          en: \"Volume UP\"\n        }\n      },\n      volume_down: {\n        title: {\n          en: \"Volume DOWN\"\n        }\n      },\n      channel_up: {\n        title: {\n          en: \"Channel UP\"\n        }\n      },\n      channel_down: {\n        title: {\n          en: \"Channel DOWN\"\n        }\n      },\n      volume_mute: {\n        title: {\n          en: \"Volume MUTE\"\n        }\n      }\n    },\n    defaultCapabilities: [\"onoff\"],\n    characteristicsSettings: {\n      onoff: 1\n    }\n  },\n  projector: {\n    name: \"Projector\",\n    capabilities: [\"onoff\"],\n    capabilitiesOptions: {\n      onoff: {\n        title: {\n          en: \"Standby\"\n        }\n      }\n    },\n    defaultCapabilities: [\"onoff\"],\n    characteristicsSettings: {\n      onoff: 1\n    }\n  },\n  airConditioner: {\n    name: \"Air Conditioner\",\n    class: \"thermostat\",\n    capabilities: [\"onoff\", \"thermostat\"],\n    capabilitiesOptions: {\n      onoff: {\n        title: {\n          en: \"Standby\"\n        }\n      }\n    },\n    defaultCapabilities: [\"onoff\"],\n    characteristicsSettings: {\n      onoff: 1,\n      thermostat: {\n        heat: true,\n        cold: true,\n        auto: true\n      }\n    }\n  },\n  amplifier: {\n    name: \"Amplifier\",\n    capabilities: [\"onoff\", \"volume_mute\", \"volume_up\", \"volume_down\"],\n    capabilitiesOptions: {\n      onoff: {\n        title: {\n          en: \"Standby\"\n        }\n      }\n    },\n    defaultCapabilities: [\"onoff\"],\n    characteristicsSettings: {\n      onoff: 1\n    }\n  },\n  fan: {\n    name: \"FAN\",\n    capabilities: [\"onoff\", \"dim\"],\n    capabilitiesOptions: {\n      onoff: {\n        title: {\n          en: \"Standby\"\n        }\n      },\n      dim: {\n        title: {\n          en: \"Fan speed\"\n        },\n        min: 0,\n        max: 1,\n        step: 1\n      }\n    },\n    defaultCapabilities: [\"onoff\"],\n    characteristicsSettings: {\n      onoff: 1,\n      dim: 1\n    }\n  }\n};\n"
  },
  {
    "path": "drivers/remote_chuangmi_remote_v2/pair/deviceCharacteristics.html",
    "content": "<script src=\"../../../assets/vue.min.js\"></script>\n<link rel=\"stylesheet\" href=\"../../../assets/bootstrap.min.css\" />\n<script src=\"./capabilities.js\"></script>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\" />\n\n<script>\n  Homey.setTitle(\"Device characteristics\");\n  Homey.emit('getCurrentDeviceForCharacteristics', null)\n    .then(result => {\n      new Vue({\n        el: \"#deviceCharacteristics\",\n        data: {\n          device: result,\n          heat: true,\n          cool: true,\n          auto: true\n        },\n        methods: {\n          characteristics() {\n            Homey.emit(\"newCharacteristics\", this.device).catch(error => { console.log(error) });\n          }\n        }\n      });\n    }).catch(error => {\n      console.log(err);\n      return;\n    });\n</script>\n\n<div id=\"deviceCharacteristics\">\n  <h5>Please indicate how you control this device with the remote control</h5>\n  <div v-for=\"capability in device.capabilities\">\n    <div v-if=\"capability == 'onoff'\" class=\"mt-3\">\n      <h5>{{ capability.toUpperCase() }}</h5>\n      <div class=\"custom-control custom-radio\">\n        <input type=\"radio\" id=\"onoffType1\" class=\"custom-control-input\" value=\"1\" v-model=\"device.characteristicsSettings.onoff\" @change=\"characteristics\" />\n        <label class=\"custom-control-label\" for=\"onoffType1\">'on' and 'off' using one button</label>\n      </div>\n      <div class=\"custom-control custom-radio\">\n        <input type=\"radio\" id=\"onoffType2\" class=\"custom-control-input\" value=\"2\" v-model=\"device.characteristicsSettings.onoff\" @change=\"characteristics\" />\n        <label class=\"custom-control-label\" for=\"onoffType2\">'on' and 'off' using the two button</label>\n      </div>\n    </div>\n    <div v-if=\"capability == 'dim'\" class=\"mt-3\">\n      <h5>{{ capability.toUpperCase() }}</h5>\n      <div>\n        <label for=\"dimLevel\">Dim level</label>\n        <input type=\"number\" id=\"dimLevel\" placeholder=\"level\" v-model=\"device.characteristicsSettings.dim\" @change=\"characteristics\" />\n      </div>\n    </div>\n    <div v-if=\"capability == 'thermostat'\" class=\"mt-3\">\n      <h5>{{ capability.toUpperCase() }} - Modes</h5>\n      {{ heat }} - {{ cool }} - {{ auto }}\n      <div class=\"ui form\">\n        <div class=\"inline field\">\n          <div class=\"ui checkbox checked\">\n            <input type=\"checkbox\" class=\"hidden\" :checked=\"heat\" @change=\"characteristics\" />\n            <label>Heat mode</label>\n          </div>\n          <div class=\"ui checkbox checked\">\n            <input type=\"checkbox\" class=\"hidden\" :checked=\"cool\" @change=\"characteristics\" />\n            <label>Cold mode</label>\n          </div>\n          <div class=\"ui checkbox checked\">\n            <input type=\"checkbox\" class=\"hidden\" :checked=\"auto\" @change=\"characteristics\" />\n            <label>Auto mode</label>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "drivers/remote_chuangmi_remote_v2/pair/deviceTypes.html",
    "content": "<script src=\"../../../assets/vue.min.js\"></script>\n<link rel=\"stylesheet\" href=\"../../../assets/semantic.min.css\" />\n<script src=\"./capabilities.js\"></script>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\" />\n<script>\n  Homey.setTitle(\"Select type\");\n  new Vue({\n    el: \"#allTypes\",\n    methods: {\n      select(device) {\n        let selectedDeviceType = document.getElementsByClassName(\"selectedDeviceType\");\n        let selectedDeviceTypeId = document.getElementById(\"selectedDeviceType\");\n        let tvCard = document.getElementById(\"tv\");\n        let projectorCard = document.getElementById(\"projector\");\n        // let airConditionerCard = document.getElementById(\"airConditioner\");\n        // let satelliteCard = document.getElementById(\"satellite\");\n        let fanCard = document.getElementById(\"fan\");\n        let amplifierCard = document.getElementById(\"amplifier\");\n        // let boxCard = document.getElementById(\"box\");\n        // let dvdCard = document.getElementById(\"dvd\");\n        // let purifierCard = document.getElementById(\"purifier\");\n        // let cameraCard = document.getElementById(\"camera\");\n        // let unknownCard = document.getElementById(\"unknown\");\n        if (device == \"tv\") {\n          projectorCard.classList.remove(\"red\");\n          // airConditionerCard.classList.remove(\"red\");\n          // satelliteCard.classList.remove(\"red\");\n          fanCard.classList.remove(\"red\");\n          amplifierCard.classList.remove(\"red\");\n          // boxCard.classList.remove(\"red\");\n          // dvdCard.classList.remove(\"red\");\n          // purifierCard.classList.remove(\"red\");\n          // cameraCard.classList.remove(\"red\");\n          // unknownCard.classList.remove(\"red\");\n          tvCard.classList.add(\"red\");\n          selectedDeviceType[0].innerHTML = \"Selected TV\";\n          selectedDeviceTypeId.style.removeProperty(\"display\");\n        } else if (device == \"projector\") {\n          tvCard.classList.remove(\"red\");\n          // airConditionerCard.classList.remove(\"red\");\n          // satelliteCard.classList.remove(\"red\");\n          fanCard.classList.remove(\"red\");\n          amplifierCard.classList.remove(\"red\");\n          // boxCard.classList.remove(\"red\");\n          // dvdCard.classList.remove(\"red\");\n          // purifierCard.classList.remove(\"red\");\n          // cameraCard.classList.remove(\"red\");\n          // unknownCard.classList.remove(\"red\");\n          projectorCard.classList.add(\"red\");\n          selectedDeviceType[0].innerHTML = \"Selected Projector\";\n          selectedDeviceTypeId.style.removeProperty(\"display\");\n        } else if (device == \"airConditioner\") {\n          tvCard.classList.remove(\"red\");\n          projectorCard.classList.remove(\"red\");\n          // satelliteCard.classList.remove(\"red\");\n          fanCard.classList.remove(\"red\");\n          amplifierCard.classList.remove(\"red\");\n          // boxCard.classList.remove(\"red\");\n          // dvdCard.classList.remove(\"red\");\n          // purifierCard.classList.remove(\"red\");\n          // cameraCard.classList.remove(\"red\");\n          // unknownCard.classList.remove(\"red\");\n          // airConditionerCard.classList.add(\"red\");\n          selectedDeviceType[0].innerHTML = \"Selected Air conditioner\";\n          selectedDeviceTypeId.style.removeProperty(\"display\");\n        } else if (device == \"satellite\") {\n          tvCard.classList.remove(\"red\");\n          // airConditionerCard.classList.remove(\"red\");\n          projectorCard.classList.remove(\"red\");\n          fanCard.classList.remove(\"red\");\n          amplifierCard.classList.remove(\"red\");\n          // boxCard.classList.remove(\"red\");\n          // dvdCard.classList.remove(\"red\");\n          // purifierCard.classList.remove(\"red\");\n          // cameraCard.classList.remove(\"red\");\n          // unknownCard.classList.remove(\"red\");\n          // satelliteCard.classList.add(\"red\");\n          selectedDeviceType[0].innerHTML = \"Selected Satellite\";\n          selectedDeviceTypeId.style.removeProperty(\"display\");\n        } else if (device == \"fan\") {\n          tvCard.classList.remove(\"red\");\n          // airConditionerCard.classList.remove(\"red\");\n          projectorCard.classList.remove(\"red\");\n          // satelliteCard.classList.remove(\"red\");\n          amplifierCard.classList.remove(\"red\");\n          // boxCard.classList.remove(\"red\");\n          // dvdCard.classList.remove(\"red\");\n          // purifierCard.classList.remove(\"red\");\n          // cameraCard.classList.remove(\"red\");\n          // unknownCard.classList.remove(\"red\");\n          fanCard.classList.add(\"red\");\n          selectedDeviceType[0].innerHTML = \"Selected Fan\";\n          selectedDeviceTypeId.style.removeProperty(\"display\");\n        } else if (device == \"amplifier\") {\n          tvCard.classList.remove(\"red\");\n          airConditionerCard.classList.remove(\"red\");\n          projectorCard.classList.remove(\"red\");\n          // satelliteCard.classList.remove(\"red\");\n          fanCard.classList.remove(\"red\");\n          // boxCard.classList.remove(\"red\");\n          // dvdCard.classList.remove(\"red\");\n          // purifierCard.classList.remove(\"red\");\n          // cameraCard.classList.remove(\"red\");\n          // unknownCard.classList.remove(\"red\");\n          amplifierCard.classList.add(\"red\");\n          selectedDeviceType[0].innerHTML = \"Selected Amplifier\";\n          selectedDeviceTypeId.style.removeProperty(\"display\");\n        } else if (device == \"box\") {\n          tvCard.classList.remove(\"red\");\n          // airConditionerCard.classList.remove(\"red\");\n          projectorCard.classList.remove(\"red\");\n          // satelliteCard.classList.remove(\"red\");\n          amplifierCard.classList.remove(\"red\");\n          fanCard.classList.remove(\"red\");\n          // dvdCard.classList.remove(\"red\");\n          // purifierCard.classList.remove(\"red\");\n          // cameraCard.classList.remove(\"red\");\n          // unknownCard.classList.remove(\"red\");\n          // boxCard.classList.add(\"red\");\n          selectedDeviceType[0].innerHTML = \"Selected Box\";\n          selectedDeviceTypeId.style.removeProperty(\"display\");\n        } else if (device == \"dvd\") {\n          tvCard.classList.remove(\"red\");\n          // airConditionerCard.classList.remove(\"red\");\n          projectorCard.classList.remove(\"red\");\n          // satelliteCard.classList.remove(\"red\");\n          amplifierCard.classList.remove(\"red\");\n          // boxCard.classList.remove(\"red\");\n          fanCard.classList.remove(\"red\");\n          // purifierCard.classList.remove(\"red\");\n          // cameraCard.classList.remove(\"red\");\n          // unknownCard.classList.remove(\"red\");\n          // dvdCard.classList.add(\"red\");\n          selectedDeviceType[0].innerHTML = \"Selected DVD\";\n          selectedDeviceTypeId.style.removeProperty(\"display\");\n        } else if (device == \"purifier\") {\n          tvCard.classList.remove(\"red\");\n          // airConditionerCard.classList.remove(\"red\");\n          projectorCard.classList.remove(\"red\");\n          // satelliteCard.classList.remove(\"red\");\n          amplifierCard.classList.remove(\"red\");\n          // boxCard.classList.remove(\"red\");\n          // dvdCard.classList.remove(\"red\");\n          fanCard.classList.remove(\"red\");\n          // cameraCard.classList.remove(\"red\");\n          // unknownCard.classList.remove(\"red\");\n          // purifierCard.classList.add(\"red\");\n          selectedDeviceType[0].innerHTML = \"Selected Purifier\";\n          selectedDeviceTypeId.style.removeProperty(\"display\");\n        } else if (device == \"camera\") {\n          tvCard.classList.remove(\"red\");\n          // airConditionerCard.classList.remove(\"red\");\n          projectorCard.classList.remove(\"red\");\n          // satelliteCard.classList.remove(\"red\");\n          amplifierCard.classList.remove(\"red\");\n          // boxCard.classList.remove(\"red\");\n          // dvdCard.classList.remove(\"red\");\n          // purifierCard.classList.remove(\"red\");\n          fanCard.classList.remove(\"red\");\n          // unknownCard.classList.remove(\"red\");\n          // cameraCard.classList.add(\"red\");\n          selectedDeviceType[0].innerHTML = \"Selected Camera\";\n          selectedDeviceTypeId.style.removeProperty(\"display\");\n        } else if (device == \"unknown\") {\n          tvCard.classList.remove(\"red\");\n          // airConditionerCard.classList.remove(\"red\");\n          projectorCard.classList.remove(\"red\");\n          // satelliteCard.classList.remove(\"red\");\n          amplifierCard.classList.remove(\"red\");\n          // boxCard.classList.remove(\"red\");\n          // dvdCard.classList.remove(\"red\");\n          // purifierCard.classList.remove(\"red\");\n          // cameraCard.classList.remove(\"red\");\n          fanCard.classList.remove(\"red\");\n          // unknownCard.classList.add(\"red\");\n          selectedDeviceType[0].innerHTML = \"Selected Unknown\";\n          selectedDeviceTypeId.style.removeProperty(\"display\");\n        }\n        Homey.emit(\"selectedType\",\n            {\n              name: devices[device].name,\n              type: device,\n              capabilities: devices[device].capabilities,\n              capabilitiesOptions: devices[device].capabilitiesOptions,\n              characteristicsSettings: devices[device].characteristicsSettings\n            }\n          )\n          .then(result => {\n            Homey.nextView();\n          }).catch(error => { \n            console.log(error)\n          });\n\n      }\n    }\n  });\n</script>\n\n<div id=\"allTypes\">\n  <div class=\"ui segment selectedDeviceType\" id=\"selectedDeviceType\" style=\"text-align: center; display: none\"></div>\n  <div class=\"ui eight doubling cards\" style=\"text-align: center; margin: auto;\">\n    <a class=\"card\" id=\"tv\" @click=\"select('tv')\">\n      <div class=\"image\" style=\"padding: 10px;\" style=\"padding: 10px;\"><img src=\"./img/types/irv2_device_type_tv_normal.png\" /></div>\n      <div class=\"content\"><div class=\"description\">TV</div></div>\n    </a>\n    <a class=\"card\" id=\"projector\" @click=\"select('projector')\">\n      <div class=\"image\" style=\"padding: 10px;\"><img src=\"./img/types/irv2_device_type_projector_normal.png\" /></div>\n      <div class=\"content\"><div class=\"description\">Projector</div></div>\n    </a>\n    <!-- <a class=\"card\" id=\"airConditioner\" @click=\"select('airConditioner')\">\n      <div class=\"image\" style=\"padding: 10px;\"><img src=\"./img/types/irv2_device_type_air_conditioner_normal.png\" /></div>\n      <div class=\"content\"><div class=\"description\">Air conditioner</div></div>\n    </a> -->\n    <!-- <a class=\"card\" id=\"satellite\" @click=\"select('satellite')\">\n      <div class=\"image\" style=\"padding: 10px;\"><img src=\"./img/types/irv2_device_type_set_top_box_normal.png\" /></div>\n      <div class=\"content\"><div class=\"description\">Satellite</div></div>\n    </a> -->\n    <a class=\"card\" id=\"fan\" @click=\"select('fan')\">\n      <div class=\"image\" style=\"padding: 10px;\"><img src=\"./img/types/irv2_device_type_fan_normal.png\" /></div>\n      <div class=\"content\"><div class=\"description\">Fan</div></div>\n    </a>\n    <a class=\"card\" id=\"amplifier\" @click=\"select('amplifier')\">\n      <div class=\"image\" style=\"padding: 10px;\"><img src=\"./img/types/irv2_device_type_amplifier_normal.png\" /></div>\n      <div class=\"content\"><div class=\"description\">Amplifier</div></div>\n    </a>\n    <!-- <a class=\"card\" id=\"box\" @click=\"select('box')\">\n      <div class=\"image\" style=\"padding: 10px;\"><img src=\"./img/types/irv2_device_type_box_normal.png\" /></div>\n      <div class=\"content\"><div class=\"description\">Box</div></div>\n    </a> -->\n    <!-- <a class=\"card\" id=\"dvd\" @click=\"select('dvd')\">\n      <div class=\"image\" style=\"padding: 10px;\"><img src=\"./img/types/irv2_device_type_dvd_normal.png\" /></div>\n      <div class=\"content\"><div class=\"description\">DVD</div></div>\n    </a> -->\n    <!-- <a class=\"card\" id=\"purifier\" @click=\"select('purifier')\">\n      <div class=\"image\" style=\"padding: 10px;\"><img src=\"./img/types/irv2_device_type_purifier_normal.png\" /></div>\n      <div class=\"content\"><div class=\"description\">Purifier</div></div>\n    </a> -->\n    <!-- <a class=\"card\" id=\"camera\" @click=\"select('camera')\">\n      <div class=\"image\" style=\"padding: 10px;\"><img src=\"./img/types/irv2_device_type_camera_normal.png\" /></div>\n      <div class=\"content\"><div class=\"description\">camera</div></div>\n    </a>\n    <a class=\"card\" id=\"unknown\" @click=\"select('unknown')\">\n      <div class=\"image\" style=\"padding: 10px;\"><img src=\"./img/types/irv2_device_type_unknown_normal.png\" /></div>\n      <div class=\"content\"><div class=\"description\">Unknown</div></div>\n    </a> -->\n  </div>\n</div>\n"
  },
  {
    "path": "drivers/remote_chuangmi_remote_v2/pair/devices.html",
    "content": "<script src=\"../../../assets/vue.min.js\"></script>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\" />\n<script>\n  Homey.setTitle(\"Select remote control device\");\n  Homey.emit('getDevicesList', null)\n    .then(result => {\n      var allDevices = result;\n      let info = document.getElementsByClassName(\"selectedDeviceType\");\n      let infoStyle = document.getElementById(\"info\");\n\n      new Vue({\n        el: \"#alldevices\",\n        data: {\n          selectedDevices: [],\n          devices: {}\n        },\n        mounted() {\n          this.devices = allDevices;\n        },\n        methods: {},\n        watch: {\n          selectedDevices(val) {\n            Homey.emit(\"selectedDevice\", { devices: val })\n              .then(result => {\n                Homey.nextView();\n              }).catch(error => { \n                console.log(error);\n              });\n          }\n        }\n      });\n\n    }).catch(error => {\n      console.log(err);\n      return;\n    });\n</script>\n\n<div id=\"alldevices\">\n  <div class=\"selectedDeviceType\" id=\"info\" style=\"text-align: center; display: none\"></div>\n  <!-- <div style=\"text-align: center\">This part is under development, will be soon</div> -->\n  <ul id=\"devices-list\">\n    <li class=\"device\" v-for=\"device in devices\">\n      <label :for=\"device.ip\" class=\"name\">\n        <div class=\"overlay\"></div>\n        <span class=\"name\" tabindex=\"-1\">{{ device.name }} | {{ device.ip }}</span>\n      </label>\n      <label :for=\"device.ip\" class=\"radio\"> <input :id=\"device.ip\" :value=\"device\" name=\"device\" type=\"radio\" tabindex=\"2\" v-model=\"selectedDevices\" /> </label>\n    </li>\n  </ul>\n</div>\n"
  },
  {
    "path": "drivers/remote_chuangmi_remote_v2/pair/done.html",
    "content": "<script>\n  Homey.setTitle(\"Adding device to Homey...\");\n\n  Homey.emit(\"allmostDone\", { devices: val })\n    .then(result => {\n      Homey.addDevice(result)\n        .then(result => {\n          Homey.done();\n        }).catch(error => { \n          return Homey.alert(error);\n        });\n    }).catch(error => { \n      return Homey.alert(error);\n    });\n</script>\n"
  },
  {
    "path": "drivers/remote_chuangmi_remote_v2/pair/keys.html",
    "content": "<script src=\"../../../assets/vue.min.js\"></script>\n<link rel=\"stylesheet\" href=\"../../../assets/bootstrap.min.css\" />\n<link rel=\"stylesheet\" href=\"../../../assets/semantic.min.css\" />\n<script src=\"./capabilities.js\"></script>\n\n<script>\n  Homey.setTitle(\"Add keys code\");\n\n  Homey.emit(\"getCurrentDevice\", null)\n    .then(result => {\n\n      new Vue({\n        el: \"#keys\",\n        data: {\n          device: result,\n          learnButton: false,\n          onoff: {\n            1: { title: \"ON\" },\n            2: { title: \"OFF\" }\n          }\n        },\n        methods: {\n          learn(value, index) {\n            let learned, btn;\n            if (index) {\n              learned = document.getElementById(value + index + \"learned\");\n              btn = document.getElementById(value + index + \"btn\");\n            } else {\n              learned = document.getElementById(value + \"learned\");\n              btn = document.getElementById(value + \"btn\");\n            }\n\n            let data = { key: index ? value + index : value, ip: this.device.settings.deviceIp, token: this.device.settings.deviceToken };\n            Homey.emit(\"learnCode\", data)\n              .then(result => {\n                  if (result == \"timeout\") {\n                  learned.classList.remove(\"grey\");\n                  learned.classList.remove(\"red\");\n                  learned.classList.remove(\"green\");\n                  learned.classList.add(\"yellow\");\n                  learned.innerHTML = \"Timeout\";\n                }\n\n                if (result == \"offline\") {\n                  learned.classList.remove(\"grey\");\n                  learned.classList.remove(\"red\");\n                  learned.classList.remove(\"green\");\n                  learned.classList.add(\"yellow\");\n                  learned.innerHTML = \"Device offline\";\n                }\n\n                if (result.code) {\n                  learned.classList.remove(\"grey\");\n                  learned.classList.remove(\"red\");\n                  learned.classList.remove(\"yellow\");\n                  learned.classList.add(\"green\");\n                  learned.innerHTML = \"Learned\";\n                  btn.classList.add(\"disabled\");\n                }\n              }).catch(error => { \n                learned.classList.remove(\"grey\");\n                learned.classList.remove(\"green\");\n                learned.classList.remove(\"yellow\");\n                learned.classList.add(\"red\");\n                learned.innerHTML = \"Error\";\n              });\n          }\n        }\n      });\n      \n    }).catch(error => { \n      console.log(error);\n    });\n</script>\n\n<div id=\"keys\">\n  <div v-for=\"(capability, index) in device.capabilities\" :key=\"index\">\n    <div v-if=\"parseInt(device.characteristicsSettings[capability]) == 1\">\n      <div class=\"ui form\">\n        <div class=\"inline fields\">\n          <label>{{ capability.toUpperCase() }}</label>\n          <div class=\"field\">\n            <a class=\"ui grey label\" :id=\"capability + 'learned'\">Not learned</a>\n          </div>\n          <div class=\"field\">\n            <button class=\"ui primary basic button\" :id=\"capability + 'btn'\" @click=\"learn(capability)\">Learn</button>\n          </div>\n        </div>\n      </div>\n    </div>\n    <div v-else-if=\"parseInt(device.characteristicsSettings[capability]) > 1\">\n      <div class=\"ui form\" v-for=\"(characteristic) in parseInt(device.characteristicsSettings[capability])\" :key=\"characteristic + index\">\n        <div class=\"inline fields\">\n          <label v-if=\"capability == 'onoff'\">{{ capability.toUpperCase() }} - {{ onoff[characteristic].title }}</label>\n          <label v-if=\"capability == 'dim'\">{{ capability.toUpperCase() }} - {{ characteristic }}</label>\n          <div class=\"field\">\n            <a class=\"ui grey label\" :id=\"capability + characteristic + 'learned'\">Not learned</a>\n          </div>\n          <div class=\"field\">\n            <button class=\"ui primary basic button\" :id=\"capability + characteristic + 'btn'\" @click=\"learn(capability, characteristic)\">Learn</button>\n          </div>\n        </div>\n      </div>\n    </div>\n    <div v-else>\n      <div class=\"ui form\">\n        <div class=\"inline fields\">\n          <label>{{ capability.toUpperCase() }}</label>\n          <div class=\"field\">\n            <a class=\"ui grey label\" :id=\"capability  + 'learned'\">Not learned</a>\n          </div>\n          <div class=\"field\">\n            <button class=\"ui primary basic button\" :id=\"capability + 'btn'\" @click=\"learn(capability)\">Learn</button>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "drivers/smoke_sensor/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass SmokeSensorDevice extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n      \n      const settings = this.getSettings();\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n\n      /* alarm_tamper */\n      if (device.data.alarm == \"1\") {\n        await this.updateCapabilityValue(\"alarm_smoke\", true);\n\n        if (this.timeoutAlarm) { this.homey.clearTimeout(this.timeoutAlarm); }\n\n        this.timeoutAlarm = setTimeout(async () => {\n          await this.updateCapabilityValue(\"alarm_smoke\", false);\n        }, this.getSetting('alarm_duration_number') * 1000);\n\n      }\n\n      /* measure_some_density */\n      if (device.data.density) { await this.updateCapabilityValue(\"measure_smoke_density\", parseInt(device.data.density)); }\n  \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = SmokeSensorDevice;"
  },
  {
    "path": "drivers/smoke_sensor/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Smoke Sensor (Gateway)\",\n    \"nl\": \"Smoke Sensor (Gateway)\",\n    \"da\": \"Røgsensor (Gateway)\",\n    \"de\": \"Rauchsensor (Gateway)\",\n    \"es\": \"Sensor de Humo (Gateway)\",\n    \"fr\": \"Capteur de Fumée (Gateway)\",\n    \"it\": \"Sensore di Fumo (Gateway)\",\n    \"no\": \"Røykvarsler (Gateway)\",\n    \"sv\": \"Röksensor (Gateway)\",\n    \"pl\": \"Czujnik Dymu (Gateway)\",\n    \"ru\": \"Датчик дыма (Gateway)\",\n    \"ko\": \"연기 센서 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/smoke_sensor/assets/images/large.jpg\",\n    \"small\": \"/drivers/smoke_sensor/assets/images/small.jpg\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"alarm_smoke\",\n    \"measure_smoke_density\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"CR123A\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/smoke_sensor/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass SmokeSensorDriver extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.config = {\n      model: [\"smoke\", \"sensor_smoke\"]\n    }\n  }\n\n}\n\nmodule.exports = SmokeSensorDriver;"
  },
  {
    "path": "drivers/smoke_sensor/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Duration of the sensor alarm\",\n      \"nl\": \"Duur van het sensor alarm\",\n      \"da\": \"Varighed af sensoralarmen\",\n      \"de\": \"Dauer des Sensoralarms\",\n      \"es\": \"Duración de la alarma del sensor\",\n      \"fr\": \"Durée de l'alarme du capteur\",\n      \"it\": \"Durata dell'allarme del sensore\",\n      \"no\": \"Varighet av sensoralarmen\",\n      \"sv\": \"Varaktighet av sensorsignalen\",\n      \"pl\": \"Czas trwania alarmu czujnika\",\n      \"ru\": \"Длительность сигнала тревоги датчика\",\n      \"ko\": \"센서 알람 시간\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_duration_number\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Disable after\",\n          \"nl\": \"Uitschakelen na\",\n          \"da\": \"Deaktiver efter\",\n          \"de\": \"Deaktivieren nach\",\n          \"es\": \"Desactivar después de\",\n          \"fr\": \"Désactiver après\",\n          \"it\": \"Disattiva dopo\",\n          \"no\": \"Deaktiver etter\",\n          \"sv\": \"Inaktivera efter\",\n          \"pl\": \"Wyłącz po\",\n          \"ru\": \"Отключить после\",\n          \"ko\": \"다음 후 비활성화\"\n        },\n        \"value\": 60,\n        \"attr\": {\n          \"min\": 60,\n          \"max\": 86400\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/subdevice_device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Util = require('../lib/util.js');\n\nclass MiSubDeviceDevice extends Homey.Device {\n\n  async onInit() {\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.initialize = this.initialize.bind(this);\n    this.onEventFromGateway = this.onEventFromGateway.bind(this);\n    this.data = this.getData();\n    this.initialize();\n    this.log(\"Sub Device Init: \" + this.getName() + \" with capabilities: \" + this.getCapabilities().toString() + \" and model \" + this.getSetting('model'));\n  }\n\n  async onDeleted() {\n    try {\n      this.unregisterStateChangeListener();\n      this.unregisterAuthChangeListener();\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async onUninit() {\n    try {\n      this.unregisterStateChangeListener();\n      this.unregisterAuthChangeListener();\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  // HELPER FUNCTIONS\n\n  /* initialize the device */\n  async initialize() {\n    if (this.homey.app.mihub.hubs) {\n      this.registerCapabilities();\n      this.registerStateChangeListener();\n    } else {\n      this.unregisterStateChangeListener();\n    }\n  }\n\n  /* placeholder for registering capabilities, device specific */\n  registerCapabilities() { }\n\n  /* register events listener from gateway */\n  registerStateChangeListener() {\n    this.homey.app.mihub.on(this.data.sid, this.onEventFromGateway);\n  }\n\n  /* unregister events listener from gateway */\n  unregisterStateChangeListener() {\n    this.homey.app.mihub.removeListener(this.data.sid, this.onEventFromGateway);\n  }\n\n  /* unregister from gatewaysList events */\n  unregisterAuthChangeListener() {\n    this.homey.app.mihub.removeListener(\"gatewaysList\", this.initialize);\n  }\n\n  /* update capabilities */\n  async updateCapabilityValue(capability, value) {\n    try {\n      if (this.hasCapability(capability)) {\n        if (value !== this.getCapabilityValue(capability) && value !== null && value !== 'null' && value !== 'undefined' && value !== undefined) {\n          await this.setCapabilityValue(capability, value);\n        }\n      } else {\n        this.log('adding capability '+ capability +' to '+ this.getName() +' with model '+ this.getSettings('model') +' as the device seems to have values for this capability ...');\n            await this.addCapability(capability);\n            await this.setCapabilityValue(capability, value);\n        }\n    } catch (error) {\n      this.error('Trying to update or add capability', capability, 'with value', value, 'for device', this.getName(), 'with device id', this.getData().sid);\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = MiSubDeviceDevice;"
  },
  {
    "path": "drivers/subdevice_driver.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Util = require('../lib/util.js');\n\nclass MiHomeSubDeviceDriver extends Homey.Driver {\n\n  onInit() {\n    if (!this.util) this.util = new Util({homey: this.homey});\n  }\n\n  onPair(session) {\n\n    session.setHandler('list_devices', async (data) => {\n      try {\n        if (this.homey.app.mihub.hubs) {\n          const discoverDevices = await this.homey.app.mihub.getDevicesByModel(this.config.model);\n\n          return discoverDevices.map(device => {\n            return {\n              name: device.name + \" | \" + device.sid,\n              data: {\n                sid: device.sid\n              },\n              settings: {\n                deviceSid: device.sid,\n                model: device.model,\n                modelCode: device.modelCode\n              }\n            };\n          });\n        } else {\n          return Promise.reject(this.homey.__(\"pair.no_gateways\"));\n        }\n      } catch (error) {\n        this.error(error);\n        return Promise.reject(this.homey.__(\"pair.no_devices_found\"));\n      }\n    });\n\n  }\n\n}\n\nmodule.exports = MiHomeSubDeviceDriver;"
  },
  {
    "path": "drivers/vacuum_dreame_vacuum/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/dreame.vacuum.mc1808\n// https://home.miot-spec.com/spec/dreame.vacuum.p2008\n// https://home.miot-spec.com/spec/dreame.vacuum.p2009\n// https://home.miot-spec.com/spec/dreame.vacuum.p2041o\n// https://home.miot-spec.com/spec/dreame.vacuum.p2150a\n// https://home.miot-spec.com/spec/dreame.vacuum.p2150o\n// https://home.miot-spec.com/spec/dreame.vacuum.p2027\n// https://home.miot-spec.com/spec/dreame.vacuum.p2028\n// https://home.miot-spec.com/spec/dreame.vacuum.p2029\n// https://home.miot-spec.com/spec/dreame.vacuum.p2041\n// https://home.miot-spec.com/spec/dreame.vacuum.r2205\n// https://home.miot-spec.com/spec/dreame.vacuum.r2228o\n// https://home.miot-spec.com/spec/dreame.vacuum.r2209\n// https://home.miot-spec.com/spec/dreame.vacuum.p2114a\n// https://home.miot-spec.com/spec/dreame.vacuum.r2211o\n// https://home.miot-spec.com/spec/dreame.vacuum.r2232c\n// https://home.miot-spec.com/spec/dreame.vacuum.r2338a (not supported, docs is missing)\n// https://home.miot-spec.com/spec/dreame.vacuum.r2416 (not supported, docs is missing)\n// https://home.miot-spec.com/spec/dreame.vacuum.r2449 (not supported, docs is missing)\n\n\nconst mapping = {\n  \"dreame.vacuum.mc1808\": \"properties_mc1808\",\n  \"dreame.vacuum.p2008\": \"properties_p2008\",\n\t\"dreame.vacuum.p2009\": \"properties_p2008\",\n  \"dreame.vacuum.p2027\": \"properties_p2008\",\n\t\"dreame.vacuum.p2028\": \"properties_p2008\",\n  \"dreame.vacuum.p2029\": \"properties_p2029\",\n\t\"dreame.vacuum.p2041o\": \"properties_p2008\",\n\t\"dreame.vacuum.p2150a\": \"properties_p2008\",\n\t\"dreame.vacuum.p2150o\": \"properties_p2008\",\n  // duplicated ??\n\t// \"dreame.vacuum.p2041\": \"properties_p2008\", \n\t\"dreame.vacuum.p2041\": \"properties_p2029\",\n  \"dreame.vacuum.r2205\": \"properties_r2205\",\n  \"dreame.vacuum.r2228o\": \"properties_r2205\",\n  \"dreame.vacuum.r2209\": \"properties_r2205\",\n  \"dreame.vacuum.p2114a\": \"properties_r2205\",\n  \"dreame.vacuum.r2211o\": \"properties_r2205\",\n  \"dreame.vacuum.r2232c\": \"properties_r2205\",\n  \"dreame.vacuum.r2338a\": \"properties_r2205\",\n  \"dreame.vacuum.r2416\": \"properties_r2205\",\n  \"dreame.vacuum.r2449\": \"properties_r2205\",\n  \"dreame.vacuum.*\": \"properties_p2008\",\n  \n};\n\nconst properties = {\n  \"properties_mc1808\": {\n    \"get_properties\": [\n      { did: \"battery_level\", siid: 2, piid: 1 }, // measure_battery\n      { did: \"device_fault\", siid : 3, piid: 1 }, // settings.error\n      { did: \"device_status\", siid: 3, piid: 2 }, // vacuumcleaner_state\n      { did: \"brush_life_level\", siid: 26, piid: 2 }, // settings.main_brush_work_time\n      { did: \"filter_life_level\", siid: 27, piid: 1 }, // settings.filter_work_time\n      { did: \"brush_life_level2\", siid: 28, piid: 2 }, // settings.side_brush_work_time\n      { did: \"cleaning_mode\", siid: 18, piid: 6 }, // vacuum_dreame_fanspeed\n      { did: \"total_clean_time\", siid: 18, piid: 13 }, // settings.total_work_time\n      { did: \"total_clean_times\", siid: 18, piid: 14 }, // settings.clean_count\n      { did: \"total_clean_area\", siid: 18, piid: 15 } // settings.total_cleared_area\n    ],\n    \"set_properties\": {\n      \"start_clean\": { siid: 3, aiid: 1, did: \"call-3-1\", in: [] },\n      \"stop_clean\": { siid: 3, aiid: 2, did: \"call-3-2\", in: [] },\n      \"home\": { siid: 2, aiid: 1, did: \"call-2-1\", in: [] },\n      \"fanspeed\": { siid: 18, piid: 6 }\n    }\n  },\n  \"properties_p2008\": {\n    \"get_properties\": [\n      { did: \"device_status\", siid: 2, piid: 1 }, // vacuumcleaner_state\n      { did: \"device_fault\", siid : 2, piid: 2 }, // settings.error\n      { did: \"rooms\", siid: 2, piid: 4 }, // settings.rooms\n      { did: \"battery_level\", siid: 3, piid: 1 }, // measure_battery\n      { did: \"cleaning_mode\", siid: 4, piid: 4 }, // vacuum_dreame_fanspeed\n      { did: \"water_flow\", siid: 4, piid: 5 }, // vacuum_dreame_mop_intensity\n      { did: \"brush_life_level\", siid: 9, piid: 2 }, // settings.main_brush_work_time\n      { did: \"filter_life_level\", siid: 11, piid: 1 }, // settings.filter_work_time\n      { did: \"brush_life_level2\", siid: 10, piid: 2 }, // settings.side_brush_work_time\n      { did: \"total_clean_time\", siid: 12, piid: 2 }, // settings.total_work_time\n      { did: \"total_clean_times\", siid: 12, piid: 3 }, // settings.clean_count\n      { did: \"total_clean_area\", siid: 12, piid: 4 }, // settings.total_cleared_area\n    ],\n    \"set_properties\": {\n      \"start_clean\": { siid: 4, aiid: 1, did: \"call-4-1\", in: [] },\n      \"stop_clean\": { siid: 4, aiid: 2, did: \"call-4-2\", in: [] },\n      \"home\": { siid: 3, aiid: 1, did: \"call-3-1\", in: [] },\n      \"fanspeed\": { siid: 4, piid: 4 },\n      \"mop_intensity\": { siid: 4, piid: 5 }\n    }\n  },\n  \"properties_p2029\": {\n    \"get_properties\": [\n      { did: \"device_status\", siid: 2, piid: 1 }, // vacuumcleaner_state\n      { did: \"device_fault\", siid : 2, piid: 2 }, // settings.error\n      { did: \"rooms\", siid: 2, piid: 4 }, // settings.rooms\n      { did: \"battery_level\", siid: 3, piid: 1 }, // measure_battery\n      { did: \"cleaning_mode\", siid: 4, piid: 4 }, // vacuum_dreame_fanspeed\n      { did: \"water_flow\", siid: 4, piid: 5 }, // vacuum_dreame_mop_intensity\n      { did: \"brush_life_level\", siid: 9, piid: 2 }, // settings.main_brush_work_time\n      { did: \"filter_life_level\", siid: 11, piid: 1 }, // settings.filter_work_time\n      { did: \"brush_life_level2\", siid: 10, piid: 2 }, // settings.side_brush_work_time\n      { did: \"total_clean_time\", siid: 12, piid: 2 }, // settings.total_work_time\n      { did: \"total_clean_times\", siid: 12, piid: 3 }, // settings.clean_count\n      { did: \"total_clean_area\", siid: 12, piid: 4 }, // settings.total_cleared_area\n    ],\n    \"set_properties\": {\n      \"start_clean\": { siid: 4, aiid: 1, did: \"call-4-1\", in: [] },\n      \"stop_clean\": { siid: 4, aiid: 2, did: \"call-4-2\", in: [] },\n      \"home\": { siid: 3, aiid: 1, did: \"call-3-1\", in: [] },\n      \"fanspeed\": { siid: 4, piid: 4 },\n      \"mop_intensity\": { siid: 4, piid: 5 }\n    }\n  },\n  \"properties_r2205\": {\n    \"get_properties\": [\n      { did: \"device_status\", siid: 2, piid: 1 }, // vacuumcleaner_state\n      { did: \"device_fault\", siid : 2, piid: 2 }, // settings.error\n      { did: \"cleaning_mode\", siid: 2, piid: 3 }, // vacuum_dreame_fanspeed\n      { did: \"rooms\", siid: 2, piid: 4 }, // settings.rooms\n      { did: \"battery_level\", siid: 3, piid: 1 }, // measure_battery\n      { did: \"water_flow\", siid: 4, piid: 5 }, // vacuum_dreame_mop_intensity\n      { did: \"brush_life_level\", siid: 9, piid: 2 }, // settings.main_brush_work_time\n      { did: \"brush_life_level2\", siid: 10, piid: 2 }, // settings.side_brush_work_time\n      { did: \"filter_life_level\", siid: 11, piid: 1 }, // settings.filter_work_time\n      { did: \"total_clean_time\", siid: 12, piid: 2 }, // settings.total_work_time\n      { did: \"total_clean_times\", siid: 12, piid: 3 }, // settings.clean_count\n      { did: \"total_clean_area\", siid: 12, piid: 4 }, // settings.total_cleared_area\n    ],\n    \"set_properties\": {\n      \"start_clean\": { siid: 4, aiid: 1, did: \"call-4-1\", in: [] },\n      \"stop_clean\": { siid: 4, aiid: 2, did: \"call-4-2\", in: [] },\n      \"home\": { siid: 3, aiid: 1, did: \"call-3-1\", in: [] },\n      \"fanspeed\": { siid: 4, piid: 4 },\n      \"mop_intensity\": { siid: 4, piid: 5 }\n    }\n  }\n}\n\nclass AdvancedDreameMiotDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // ADD DEVICES DEPENDANT CAPABILITIES\n      if (this.getStoreValue('model') !== 'dreame.vacuum.mc1808') {\n        if (!this.hasCapability('vacuum_dreame_mop_intensity')) {\n          this.addCapability('vacuum_dreame_mop_intensity');\n        }\n      }\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['dreame.vacuum.*']];\n\n      this.vacuumErrorCodes = {\n        0: \"Normal\",\n        1: \"Drop\",\n        2: \"Cliff\",\n        3: \"Bumper\",\n        4: \"Gesture\",\n        5: \"Bumper Repeat\",\n        6: \"Drop Repeat\",\n        7: \"Optical Flow\",\n        8: \"No Container\",\n        9: \"No Tank\",\n        10: \"Waterbox Empty\",\n        11: \"Container Full\",\n        12: \"Brush\",\n        13: \"Sidebrush\",\n        14: \"Fan\",\n        15: \"Left Wheel Motor\",\n        16: \"Right Wheel Motor\",\n        17: \"Turn Soffacate\",\n        18: \"Forward Soffacate\",\n        19: \"Charger Get\",\n        20: \"Battery Low\",\n        21: \"Charge Fault\",\n        22: \"Battery Percentage\",\n        23: \"Heart\",\n        24: \"Camera Occlusion\",\n        25: \"Camera Fault\",\n        26: \"Event Battery\",\n        27: \"Forward Looking\",\n        28: \"Gyroscope\"\n      }\n\n      // RESET CONSUMABLE ALARMS\n      this.updateCapabilityValue(\"alarm_main_brush_work_time\", false);\n      this.updateCapabilityValue(\"alarm_side_brush_work_time\", false);\n      this.updateCapabilityValue(\"alarm_filter_work_time\", false);\n\n      // DEVICE TOKENS\n      this.main_brush_lifetime_token = await this.homey.flow.createToken(\"main_brush_lifetime\"+ this.getData().id, {type: \"number\", title: \"Main Brush Lifetime \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.side_brush_lifetime_token = await this.homey.flow.createToken(\"side_brush_lifetime\"+ this.getData().id, {type: \"number\", title: \"Side Brush Lifetime \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.filter_lifetime_token = await this.homey.flow.createToken(\"filter_lifetime\"+ this.getData().id, {type: \"number\", title: \"Filter LifeTime \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.sensor_dirty_lifetime_token = await this.homey.flow.createToken(\"sensor_dirty_lifetime\"+ this.getData().id, {type: \"number\", title: \"Sensor Dirty Time \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.total_work_time_token = await this.homey.flow.createToken(\"total_work_time\"+ this.getData().id, {type: \"number\", title: \"Total Work Time \" + this.getName() +\" h)\" }).catch(error => { this.error(error) });\n      this.total_cleared_area_token = await this.homey.flow.createToken(\"total_cleared_area\"+ this.getData().id, {type: \"number\", title: \"Total Cleaned Area \" + this.getName() +\" (m2)\" }).catch(error => { this.error(error) });\n      this.total_clean_count_token = await this.homey.flow.createToken(\"total_clean_count\"+ this.getData().id, {type: \"number\", title: \"Total Clean Count \"+ this.getName() }).catch(error => { this.error(error) });\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('alertVacuum');\n      this.homey.flow.getDeviceTriggerCard('statusVacuum');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            if (value) {\n              return await this.miio.call(\"action\", this.deviceProperties.set_properties.start_clean, { retries: 1 });\n            } else {\n              return await this.miio.call(\"action\", this.deviceProperties.set_properties.stop_clean, { retries: 1 });\n            }\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('vacuumcleaner_state', async ( value ) => {\n        try {\n          if (this.miio) {\n            switch (value) {\n              case \"cleaning\":\n              case \"spot_cleaning\":\n                return await this.triggerCapabilityListener('onoff', true);\n              case \"docked\":\n              case \"charging\":\n                return await this.miio.call(\"action\", this.deviceProperties.set_properties.home, { retries: 1 });\n              case \"stopped\":\n                return await this.triggerCapabilityListener('onoff', false);\n            }\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      /* vacuumcleaner dreame fanspeed */\n      this.registerCapabilityListener('vacuum_dreame_fanspeed', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.fanspeed.siid, piid: this.deviceProperties.set_properties.fanspeed.piid, value: Number(value) }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      /* vacuumcleaner dreame mop intensity */\n      this.registerCapabilityListener('vacuum_dreame_mop_intensity', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.mop_intensity.siid, piid: this.deviceProperties.set_properties.mop_intensity.piid, value: Number(value) }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('button.consumable', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"reset_consumable\", [\"main_brush_work_time\", \"side_brush_work_time\", \"filter_work_time\"], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const device_status = result.find(obj => obj.did === 'device_status');\n      const battery_level = result.find(obj => obj.did === 'battery_level');\n      const rooms = result.find(obj => obj.did === 'rooms');\n      const cleaning_mode = result.find(obj => obj.did === 'cleaning_mode');\n      const brush_life_level = result.find(obj => obj.did === 'brush_life_level');\n      const brush_life_level2 = result.find(obj => obj.did === 'brush_life_level2');\n      const filter_life_level = result.find(obj => obj.did === 'filter_life_level');\n      const total_clean_time = result.find(obj => obj.did === 'total_clean_time');\n      const total_clean_times = result.find(obj => obj.did === 'total_clean_times');\n      const total_clean_area = result.find(obj => obj.did === 'total_clean_area');\n      const device_fault = result.find(obj => obj.did === 'device_fault');\n\n      const consumables = [\n        {\n          \"main_brush_work_time\": brush_life_level.value,\n          \"side_brush_work_time\": brush_life_level2.value,\n          \"filter_work_time\": filter_life_level.value,\n        }\n      ]\n\n      const totals = {\n        \"clean_time\": total_clean_time.value,\n        \"clean_count\": total_clean_times.value,\n        \"clean_area\": total_clean_area.value\n      }\n\n      /* onoff & vacuumcleaner_state */\n      switch (device_status.value) {\n        case 1:\n        case 5:\n        case 7:\n        case 12:\n          this.vacuumCleanerState(\"cleaning\");\n          break;\n        case 2:\n        case 3:\n        case 11:\n          this.vacuumCleanerState(\"stopped\");\n          break;\n        case 6:\n          if (this.getCapabilityValue('measure_battery') === 100) {\n            this.vacuumCleanerState(\"docked\");\n          } else {\n            this.vacuumCleanerState(\"charging\");\n          }\n          break;\n        case 4:\n          this.vacuumCleanerState(\"stopped_error\");\n          break;\n        case 13:\n        case 14:\n          this.vacuumCleanerState(\"docked\");\n          break;\n        default:\n          this.log(\"Not a valid vacuumcleaner_state\", device_status.value);\n          break;\n      }\n\n      /* measure_battery & alarm_battery */\n      await this.updateCapabilityValue(\"measure_battery\", battery_level.value);\n      await this.updateCapabilityValue(\"alarm_battery\", battery_level.value <= 20 ? true : false);\n\n      /* vacuum_dreame_fanspeed */\n      await this.updateCapabilityValue(\"vacuum_dreame_fanspeed\", cleaning_mode.value.toString());\n\n       /* vacuum_dreame_mop_intensity */\n       if (this.hasCapability('vacuum_dreame_mop_intensity')) {\n        const water_flow = result.find(obj => obj.did === 'water_flow');\n        await this.updateCapabilityValue(\"vacuum_dreame_mop_intensity\", water_flow.value.toString());\n      }\n\n      /* consumable settings */\n      this.vacuumConsumables(consumables);\n\n      /* totals */\n      this.vacuumTotals(totals);\n\n      /* room ID settings */\n      if (rooms !== undefined) {\n        await this.updateSettingValue(\"rooms\", rooms.value);\n      } else {\n        await this.updateSettingValue(\"rooms\", \"Not supported for this model\");\n      }\n\n      /* settings device error */\n      const error = this.vacuumErrorCodes[device_fault.value] || String(device_fault.value);\n      if (this.getSetting('error') !== error && error !== undefined) {\n        await this.setSettings({ error: error });\n        if (error !== 0) {\n          await this.homey.flow.getDeviceTriggerCard('statusVacuum').trigger(this, {\"status\": error }).catch(error => { this.error(error) });\n        }\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = AdvancedDreameMiotDevice;\n"
  },
  {
    "path": "drivers/vacuum_dreame_vacuum/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Advanced Dreame Vacuum Cleaner MIoT (WiFi)\",\n    \"nl\": \"Geavanceerde Dreame stofzuiger MIoT (WiFi)\",\n    \"da\": \"Avanceret Dreame-støvsuger MIoT (WiFi)\",\n    \"de\": \"Erweiterter Dreame-Staubsauger MIoT (WiFi)\",\n    \"es\": \"Aspiradora Dreame Avanzada MIoT (WiFi)\",\n    \"fr\": \"Aspirateur Dreame Avancé MIoT (WiFi)\",\n    \"it\": \"Aspirapolvere Dreame Avanzato MIoT (WiFi)\",\n    \"no\": \"Avansert Dreame-støvsuger MIoT (WiFi)\",\n    \"sv\": \"Avancerad Dreame-städare MIoT (WiFi)\",\n    \"pl\": \"Zaawansowany odkurzacz Dreame MIoT (WiFi)\",\n    \"ru\": \"Продвинутый пылесос Dreame MIoT (WiFi)\",\n    \"ko\": \"고급 Dreame 진공 청소기 MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/vacuum_dreame_vacuum/assets/images/large.jpg\",\n    \"small\": \"drivers/vacuum_dreame_vacuum/assets/images/small.jpg\"\n  },\n  \"class\": \"vacuumcleaner\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"vacuumcleaner_state\",\n    \"vacuum_dreame_fanspeed\",\n    \"button.consumable\",\n    \"measure_battery\",\n    \"alarm_battery\",\n    \"alarm_main_brush_work_time\",\n    \"alarm_side_brush_work_time\",\n    \"alarm_filter_work_time\"\n  ],\n  \"capabilitiesOptions\": {\n    \"button.consumable\": {\n      \"maintenanceAction\": true,\n      \"title\": {\n        \"en\": \"Reset consumables\",\n        \"nl\": \"Reset verbruiksartikelen\",\n        \"da\": \"Nulstil forbrugsstoffer\",\n        \"de\": \"Verbrauchsmaterialien zurücksetzen\",\n        \"es\": \"Restablecer consumibles\",\n        \"fr\": \"Réinitialiser les consommables\",\n        \"it\": \"Reimposta consumabili\",\n        \"no\": \"Tilbakestill forbruksvarer\",\n        \"sv\": \"Återställ förbrukningsvaror\",\n        \"pl\": \"Zresetuj materiały eksploatacyjne\",\n        \"ru\": \"Сбросить расходные материалы\",\n        \"ko\": \"소모품 재설정\"\n      },\n      \"desc\": {\n        \"en\": \"Reset the usage of vacuum cleaner consumables.\",\n        \"nl\": \"Reset het gebruik van de verbruiksartikelen\",\n        \"da\": \"Nulstil brugen af støvsugerens forbrugsstoffer.\",\n        \"de\": \"Verwendung der Staubsauger-Verbrauchsmaterialien zurücksetzen.\",\n        \"es\": \"Restablecer el uso de los consumibles de la aspiradora.\",\n        \"fr\": \"Réinitialiser l'utilisation des consommables de l'aspirateur.\",\n        \"it\": \"Reimposta l'uso dei consumabili dell'aspirapolvere.\",\n        \"no\": \"Tilbakestill bruken av støvsugerens forbruksvarer.\",\n        \"sv\": \"Återställ användningen av förbrukningsartiklar för dammsugaren.\",\n        \"pl\": \"Zresetuj użycie materiałów eksploatacyjnych odkurzacza.\",\n        \"ru\": \"Сбросить использование расходных материалов пылесоса.\",\n        \"ko\": \"진공 청소기 소모품 사용량 재설정.\"\n      }\n    }\n  },\n  \"energy\": {\n    \"batteries\": [\n      \"INTERNAL\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/vacuum_dreame_vacuum/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass AdvancedDreameMiotDriver extends Driver {}\n\nmodule.exports = AdvancedDreameMiotDriver;"
  },
  {
    "path": "drivers/vacuum_dreame_vacuum/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Consumables\",\n      \"nl\": \"Verbruiksartikelen\",\n      \"da\": \"Forbrugsvarer\",\n      \"de\": \"Verbrauchsmaterialien\",\n      \"es\": \"Consumibles\",\n      \"fr\": \"Consommables\",\n      \"it\": \"Materiali di consumo\",\n      \"no\": \"Forbruksvarer\",\n      \"sv\": \"Förbrukningsvaror\",\n      \"pl\": \"Materiały eksploatacyjne\",\n      \"ru\": \"Расходные материалы\",\n      \"ko\": \"소모품\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_threshold\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Alarm threshold\",\n          \"nl\": \"Alarm ondergrens\",\n          \"da\": \"Alarmgrænse\",\n          \"de\": \"Alarmgrenze\",\n          \"es\": \"Umbral de alarma\",\n          \"fr\": \"Seuil d'alarme\",\n          \"it\": \"Soglia di allarme\",\n          \"no\": \"Alarmterskel\",\n          \"sv\": \"Larmpådragning\",\n          \"pl\": \"Próg alarmowy\",\n          \"ru\": \"Порог срабатывания сигнализации\",\n          \"ko\": \"경보 임계값\"\n        },\n        \"hint\": {\n          \"en\": \"Threshold below which the alarm will be activated.\",\n          \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n          \"da\": \"Grænse under hvilken alarmen vil blive aktiveret.\",\n          \"de\": \"Schwelle, unter der der Alarm ausgelöst wird.\",\n          \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n          \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n          \"it\": \"Soglia al di sotto della quale verrà attivato l'allarme.\",\n          \"no\": \"Terskel under hvilket alarmen vil bli aktivert.\",\n          \"sv\": \"Tröskel under vilken larmet aktiveras.\",\n          \"pl\": \"Próg poniżej którego alarm zostanie włączony.\",\n          \"ru\": \"Порог, ниже которого срабатывает сигнализация.\",\n          \"ko\": \"경보가 활성화되는 임계값.\"\n        },\n        \"value\": 20,\n        \"attr\": {\n          \"min\": 1,\n          \"max\": 90\n        }\n      },\n      {\n        \"id\": \"main_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Main brush remaining (%)\",\n          \"nl\": \"Hoofdborstel over (%)\",\n          \"da\": \"Hovede børste resterende (%)\",\n          \"de\": \"Hauptbürste verbleibend (%)\",\n          \"es\": \"Cepillo principal restante (%)\",\n          \"fr\": \"Brosse principale restante (%)\",\n          \"it\": \"Spazzola principale restante (%)\",\n          \"no\": \"Hovedbørste gjenværende (%)\",\n          \"sv\": \"Huvudborste återstående (%)\",\n          \"pl\": \"Główna szczotka pozostało (%)\",\n          \"ru\": \"Оставшаяся основная щетка (%)\",\n          \"ko\": \"메인 브러시 남은 (%)\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"side_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Side brush remaining\",\n          \"nl\": \"Zijborstel over\",\n          \"da\": \"Sidebørste resterende\",\n          \"de\": \"Seitenbürste verbleibend\",\n          \"es\": \"Cepillo lateral restante\",\n          \"fr\": \"Brosse latérale restante\",\n          \"it\": \"Spazzola laterale restante\",\n          \"no\": \"Sidebørste gjenværende\",\n          \"sv\": \"Sidoborste återstående\",\n          \"pl\": \"Boczna szczotka pozostało\",\n          \"ru\": \"Оставшаяся боковая щетка\",\n          \"ko\": \"사이드 브러시 남은\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"filter_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter remaining\",\n          \"nl\": \"Filter over\",\n          \"da\": \"Filter resterende\",\n          \"de\": \"Filter verbleibend\",\n          \"es\": \"Filtro restante\",\n          \"fr\": \"Filtre restant\",\n          \"it\": \"Filtro restante\",\n          \"no\": \"Filter gjenværende\",\n          \"sv\": \"Filter återstående\",\n          \"pl\": \"Pozostały filtr\",\n          \"ru\": \"Оставшийся фильтр\",\n          \"ko\": \"필터 남은\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"total_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total work time\",\n          \"nl\": \"Totale gebruikstijd\",\n          \"da\": \"Total arbejdstid\",\n          \"de\": \"Gesamtarbeitszeit\",\n          \"es\": \"Tiempo total de trabajo\",\n          \"fr\": \"Temps de travail total\",\n          \"it\": \"Tempo totale di lavoro\",\n          \"no\": \"Total arbeidstid\",\n          \"sv\": \"Total arbetstid\",\n          \"pl\": \"Całkowity czas pracy\",\n          \"ru\": \"Общее рабочее время\",\n          \"ko\": \"총 작업 시간\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"total_cleared_area\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total cleaned area\",\n          \"nl\": \"Totaal geschoont\",\n          \"da\": \"Samlet rengjort areal\",\n          \"de\": \"Gesamte gereinigte Fläche\",\n          \"es\": \"Área total limpiada\",\n          \"fr\": \"Surface totale nettoyée\",\n          \"it\": \"Area totale pulita\",\n          \"no\": \"Total rengjort område\",\n          \"sv\": \"Total rengjord yta\",\n          \"pl\": \"Całkowita czyszczona powierzchnia\",\n          \"ru\": \"Общая убранная площадь\",\n          \"ko\": \"총 청소된 면적\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"total_clean_count\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total clean count\",\n          \"nl\": \"Totaal aantal opschoningen\",\n          \"da\": \"Samlet rengøringsantal\",\n          \"de\": \"Gesamte Reinigungsanzahl\",\n          \"es\": \"Conteo total de limpiezas\",\n          \"fr\": \"Compte total de nettoyages\",\n          \"it\": \"Conteggio totale delle pulizie\",\n          \"no\": \"Totalt rengjøringsantall\",\n          \"sv\": \"Total rengöringsräkning\",\n          \"pl\": \"Całkowita liczba czyszczeń\",\n          \"ru\": \"Общее количество уборок\",\n          \"ko\": \"총 청소 횟수\"\n        },\n        \"value\": \"0\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device data\",\n      \"nl\": \"Apparaat data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"장치 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"rooms\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Room cleaning segments\",\n          \"nl\": \"Kamer stofzuig segmenten\",\n          \"da\": \"Rengrumssegmenter\",\n          \"de\": \"Raumreinigungssegmente\",\n          \"es\": \"Segmentos de limpieza de habitaciones\",\n          \"fr\": \"Segments de nettoyage de la pièce\",\n          \"it\": \"Segmenti di pulizia della stanza\",\n          \"no\": \"Romrengjøringssegmenter\",\n          \"sv\": \"Rumstädningssegment\",\n          \"pl\": \"Segmenty sprzątania pomieszczeń\",\n          \"ru\": \"Сегменты очищения помещений\",\n          \"ko\": \"방 청소 세그먼트\"\n        },\n        \"value\": \"[[17,20,21]]\"\n      },\n      {\n        \"id\": \"error\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Error\",\n          \"nl\": \"Error\",\n          \"da\": \"Fejl\",\n          \"de\": \"Fehler\",\n          \"es\": \"Error\",\n          \"fr\": \"Erreur\",\n          \"it\": \"Errore\",\n          \"no\": \"Feil\",\n          \"sv\": \"Fel\",\n          \"pl\": \"Błąd\",\n          \"ru\": \"Ошибка\",\n          \"ko\": \"오류\"\n        },\n        \"value\": \"No error\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/vacuum_dreame_vacuum/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/vacuum_dreame_vacuum/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_dreame_vacuum/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_mi_rockrobo_vacuum_advanced/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* basic supported devices */\n// https://home.miot-spec.com/spec/rockrobo.vacuum.v1\n// https://home.miot-spec.com/spec/rockrobo.vacuum.m1s\n// https://home.miot-spec.com/spec/rockrobo.vacuum.c1\n// https://home.miot-spec.com/spec/roborock.vacuum.e2\n// https://home.miot-spec.com/spec/roborock.vacuum.s4\n// https://home.miot-spec.com/spec/roborock.vacuum.s5\n// https://home.miot-spec.com/spec/roborock.vacuum.s5e\n// https://home.miot-spec.com/spec/roborock.vacuum.s6\n// https://home.miot-spec.com/spec/roborock.vacuum.t6\n// https://home.miot-spec.com/spec/roborock.vacuum.a01\n// https://home.miot-spec.com/spec/roborock.vacuum.a08\n// https://home.miot-spec.com/spec/roborock.vacuum.a10\n// https://home.miot-spec.com/spec/roborock.vacuum.a11\n// https://home.miot-spec.com/spec/roborock.vacuum.a14\n// https://home.miot-spec.com/spec/roborock.vacuum.a15\n// https://home.miot-spec.com/spec/roborock.vacuum.a19\n// https://home.miot-spec.com/spec/roborock.vacuum.a23\n// https://home.miot-spec.com/spec/roborock.vacuum.a27\n// https://home.miot-spec.com/spec/roborock.vacuum.a29\n// https://home.miot-spec.com/spec/roborock.vacuum.a34\n// https://home.miot-spec.com/spec/roborock.vacuum.a38\n// https://home.miot-spec.com/spec/roborock.vacuum.a40\n// https://home.miot-spec.com/spec/roborock.vacuum.a46\n// https://home.miot-spec.com/spec/roborock.vacuum.a51\n// https://home.miot-spec.com/spec/roborock.vacuum.a62\n// https://home.miot-spec.com/spec/roborock.vacuum.a70\n// https://home.miot-spec.com/spec/roborock.vacuum.a73\n// https://home.miot-spec.com/spec/roborock.vacuum.a75\n\nconst mapping = {\n  \"rockrobo.vacuum.v1\": \"rockrobo_vacuum_v3\",\n  \"rockrobo.vacuum.m1s\": \"rockrobo_vacuum_v2\",\n\t\"rockrobo.vacuum.c1\": \"rockrobo_vacuum_v2\",\n\t\"roborock.vacuum.e2\": \"rockrobo_vacuum_e2\",\n\t\"roborock.vacuum.s4\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.t4\": \"rockrobo_vacuum_v2\",\n\t\"roborock.vacuum.s5\": \"rockrobo_vacuum_v2\",\n\t\"roborock.vacuum.s5e\": \"rockrobo_vacuum_v2\",\n\t\"roborock.vacuum.s6\": \"rockrobo_vacuum_v2\",\n\t\"roborock.vacuum.a01\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.a08\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.a09\": \"rockrobo_vacuum_v2\",\n\t\"roborock.vacuum.a10\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.a11\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.a14\": \"rockrobo_vacuum_v2\",\n\t\"roborock.vacuum.a15\": \"rockrobo_vacuum_s7\",\n\t\"roborock.vacuum.a19\": \"rockrobo_vacuum_v2\",\n\t\"roborock.vacuum.a23\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.a26\": \"rockrobo_vacuum_v2\",\n\t\"roborock.vacuum.a27\": \"rockrobo_vacuum_s7_vmax\",\n\t\"roborock.vacuum.a29\": \"rockrobo_vacuum_v2\",\n\t\"roborock.vacuum.a34\": \"rockrobo_vacuum_v2\",\n\t\"roborock.vacuum.a38\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.a40\": \"rockrobo_vacuum_v2\",\n\t\"roborock.vacuum.a46\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.a51\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.a62\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.a70\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.a73\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.a75\": \"rockrobo_vacuum_v2\",\n  \"roborock.vacuum.*\": \"rockrobo_vacuum_v2\",\n};\n\nconst properties = {\n  \"rockrobo_vacuum_v1\": {\n    \"fanspeeds\": {\n      1: 38,\n      2: 60,\n      3: 77,\n      4: 90,\n      5: 90,\n      38: 1,\n      60: 2,\n      77: 3,\n      90: 4\n    }\n  },\n  \"rockrobo_vacuum_v2\": {\n    \"fanspeeds\": {\n      1: 101,\n      2: 102,\n      3: 103,\n      4: 104,\n      5: 105,\n      101: 1,\n      102: 2,\n      103: 3,\n      104: 4,\n      105: 5,\n      106: 5\n    }\n  },\n  \"rockrobo_vacuum_v3\": {\n    \"fanspeeds\": {\n      1: 38,\n      2: 60,\n      3: 75,\n      4: 100,\n      5: 100,\n      38: 1,\n      60: 2,\n      75: 3,\n      100: 4\n    }\n  },\n  \"rockrobo_vacuum_e2\": {\n    \"fanspeeds\": {\n      1: 41,\n      2: 50,\n      3: 68,\n      4: 79,\n      5: 100,\n      41: 1,\n      50: 2,\n      68: 3,\n      79: 4,\n      100: 5\n    }\n  },\n  \"rockrobo_vacuum_s7\": {\n    \"fanspeeds\": {\n      1: 101,\n      2: 102,\n      3: 103,\n      4: 104,\n      5: 105,\n      101: 1,\n      102: 2,\n      103: 3,\n      104: 4,\n      105: 5,\n      106: 5\n    }\n  },\n  \"rockrobo_vacuum_s7_vmax\": {\n    \"fanspeeds\": {\n      1: 101,\n      2: 102,\n      3: 103,\n      4: 104,\n      5: 108,\n      101: 1,\n      102: 2,\n      103: 3,\n      104: 4,\n      105: 4,\n      108: 5\n    }\n  }\n}\n\nclass MiRobotAdvancedDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['roborock.vacuum.*']];\n\n      // DEVICE VARIABLES\n      this.vacuumErrorCodes = {\n        0: \"No error\",\n        1: \"Laser distance sensor error\",\n        2: \"Collision sensor error\",\n        3: \"Wheels on top of void, move robot\",\n        4: \"Clean hovering sensors, move robot\",\n        5: \"Clean main brush\",\n        6: \"Clean side brush\",\n        7: \"Main wheel stuck?\",\n        8: \"Device stuck, clean area\",\n        9: \"Dust collector missing\",\n        10: \"Clean filter\",\n        11: \"Stuck in magnetic barrier\",\n        12: \"Low battery\",\n        13: \"Charging fault\",\n        14: \"Battery fault\",\n        15: \"Wall sensors dirty, wipe them\",\n        16: \"Place me on flat surface\",\n        17: \"Side brushes problem, reboot me\",\n        18: \"Suction fan problem\",\n        19: \"Unpowered charging station\",\n      };\n\n      // RESET CONSUMABLE ALARMS\n      this.updateCapabilityValue(\"alarm_main_brush_work_time\", false);\n      this.updateCapabilityValue(\"alarm_side_brush_work_time\", false);\n      this.updateCapabilityValue(\"alarm_filter_work_time\", false);\n      this.updateCapabilityValue(\"alarm_sensor_dirty_time\", false);\n\n      // DEVICE TOKENS\n      this.main_brush_lifetime_token = await this.homey.flow.createToken(\"main_brush_lifetime\"+ this.getData().id, {type: \"number\", title: \"Main Brush Lifetime \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.side_brush_lifetime_token = await this.homey.flow.createToken(\"side_brush_lifetime\"+ this.getData().id, {type: \"number\", title: \"Side Brush Lifetime \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.filter_lifetime_token = await this.homey.flow.createToken(\"filter_lifetime\"+ this.getData().id, {type: \"number\", title: \"Filter LifeTime \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.sensor_dirty_lifetime_token = await this.homey.flow.createToken(\"sensor_dirty_lifetime\"+ this.getData().id, {type: \"number\", title: \"Sensor Dirty Time \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.total_work_time_token = await this.homey.flow.createToken(\"total_work_time\"+ this.getData().id, {type: \"number\", title: \"Total Work Time \" + this.getName() +\" h)\" }).catch(error => { this.error(error) });\n      this.total_cleared_area_token = await this.homey.flow.createToken(\"total_cleared_area\"+ this.getData().id, {type: \"number\", title: \"Total Cleaned Area \" + this.getName() +\" (m2)\" }).catch(error => { this.error(error) });\n      this.total_clean_count_token = await this.homey.flow.createToken(\"total_clean_count\"+ this.getData().id, {type: \"number\", title: \"Total Clean Count \"+ this.getName() }).catch(error => { this.error(error) });\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('statusVacuum');\n      this.homey.flow.getDeviceTriggerCard('alertVacuum');\n      this.homey.flow.getDeviceTriggerCard('triggerVacuumRoomSegments');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoffVacuumcleaner.bind(this));\n      this.registerCapabilityListener(\"vacuumcleaner_state\", this.onCapabilityVacuumcleanerState.bind(this));\n      this.registerCapabilityListener(\"vacuum_roborock_mop_intensity\", this.onCapabilityVacuumMopIntensity.bind(this));\n      this.registerCapabilityListener(\"button.consumable\", this.onCapabilityButtonConsumable.bind(this));\n\n      this.registerCapabilityListener('vacuum_roborock_fanspeed', async ( value ) => {\n        try {\n          if (this.miio) {\n            const fanspeed = this.deviceProperties.fanspeeds[+value];\n            return await this.miio.call(\"set_custom_mode\", [fanspeed], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call(\"get_status\", [], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const fanspeed = this.deviceProperties.fanspeeds[result[0][\"fan_power\"]];\n      if (fanspeed !== undefined) {\n        await this.updateCapabilityValue(\"vacuum_roborock_fanspeed\", fanspeed.toString());\n      }\n      await this.updateCapabilityValue(\"measure_battery\", parseInt(result[0][\"battery\"]));\n      await this.updateCapabilityValue(\"alarm_battery\", parseInt(result[0][\"battery\"]) === 20 ? true : false);\n\n      if (result[0].hasOwnProperty('error_code')) {\n        const error = this.vacuumErrorCodes[result[0].error_code];\n        if (this.getSetting('error') !== error ) {\n          await this.setSettings({ error: error });\n          if (error !== 0) {\n            await this.homey.flow.getDeviceTriggerCard('statusVacuum').trigger(this, {\"status\": error }).catch(error => { this.error(error) });\n          }\n        }\n      }\n\n      if (result[0].hasOwnProperty('water_box_mode')) {\n        if (!this.hasCapability('vacuum_roborock_mop_intensity')) {\n          this.addCapability('vacuum_roborock_mop_intensity')\n        } else {\n          await this.updateCapabilityValue(\"vacuum_roborock_mop_intensity\", result[0][\"water_box_mode\"].toString());\n        }\n      }\n\n      /* vacuumcleaner_state */\n      switch (result[0][\"state\"]) {\n        case 1:\n        case 5:\n        case 6:\n        case 7:\n        case 16:\n        case 17:\n        case 18:\n          this.vacuumCleanerState(\"cleaning\");\n          break;\n        case 11:\n          this.vacuumCleanerState(\"spot_cleaning\");\n          break;\n        case 3:\n        case 4:\n        case 10:\n        case 13:\n          this.vacuumCleanerState(\"stopped\");\n          break;\n        case 15:\n          this.vacuumCleanerState(\"docked\");\n          break;\n        case 8:\n          if (this.getCapabilityValue('measure_battery') === 100) {\n            this.vacuumCleanerState(\"docked\");\n          } else {\n            this.vacuumCleanerState(\"charging\");\n          }\n          break;\n        case 9:\n        case 12:\n        case 13:\n        case 101:\n          this.vacuumCleanerState(\"stopped_error\");\n          break;\n        default:\n          this.log(\"Not a valid vacuumcleaner_state\", result[0][\"state\"]);\n          break;\n      }\n\n      const consumables = await this.miio.call(\"get_consumable\", [], { retries: 1 });\n      this.vacuumConsumables(consumables);\n\n      const totals = await this.miio.call(\"get_clean_summary\", [], { retries: 1 });\n      this.vacuumTotals(totals);\n\n      const rooms = await this.miio.call(\"get_room_mapping\", [], { retries: 1 });\n      if (rooms !== undefined) {\n        if (rooms.toString() !== 'unknown_method') {\n          if (this.getSetting('rooms') !== rooms.toString() ) {\n            await this.setSettings({ rooms: rooms.toString() });\n            await this.homey.flow.getDeviceTriggerCard('triggerVacuumRoomSegments').trigger(this, {\"segments\": rooms.toString() }).catch(error => { this.error(error) });\n          }\n        } else {\n          if (this.getSetting('rooms') !== 'Feature Not Supported' ) {\n            await this.setSettings({ rooms: 'Feature Not Supported' });\n          }\n        }\n      }\n      \n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = MiRobotAdvancedDevice;\n"
  },
  {
    "path": "drivers/vacuum_mi_rockrobo_vacuum_advanced/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Advanced Roborock Vacuum Cleaner (WiFi)\",\n    \"nl\": \"Geavanceerde Roborock stofzuiger (WiFi)\",\n    \"da\": \"Avanceret Roborock Støvsuger (WiFi)\",\n    \"de\": \"Fortschrittlicher Roborock Staubsauger (WLAN)\",\n    \"es\": \"Aspiradora Roborock Avanzada (WiFi)\",\n    \"fr\": \"Aspirateur Roborock Avancé (WiFi)\",\n    \"it\": \"Aspirapolvere Roborock Avanzato (WiFi)\",\n    \"no\": \"Avansert Roborock Støvsuger (WiFi)\",\n    \"sv\": \"Avancerad Roborock Dammsugare (WiFi)\",\n    \"pl\": \"Zaawansowany Odkurzacz Roborock (WiFi)\",\n    \"ru\": \"Продвинутый Робот-пылесос Roborock (WiFi)\",\n    \"ko\": \"고급 Roborock 진공 청소기 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/vacuum_mi_rockrobo_vacuum_advanced/assets/images/large.jpg\",\n    \"small\": \"drivers/vacuum_mi_rockrobo_vacuum_advanced/assets/images/small.jpg\"\n  },\n  \"class\": \"vacuumcleaner\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"vacuumcleaner_state\",\n    \"button.consumable\",\n    \"vacuum_roborock_fanspeed\",\n    \"measure_battery\",\n    \"alarm_battery\",\n    \"alarm_main_brush_work_time\",\n    \"alarm_side_brush_work_time\",\n    \"alarm_filter_work_time\",\n    \"alarm_sensor_dirty_time\"\n  ],\n  \"capabilitiesOptions\": {\n    \"button.consumable\": {\n      \"maintenanceAction\": true,\n      \"title\": {\n        \"en\": \"Reset consumables\",\n        \"nl\": \"Reset verbruiksartikelen\",\n        \"da\": \"Nulstil forbrugsvarer\",\n        \"de\": \"Verbrauchsmaterialien zurücksetzen\",\n        \"es\": \"Restablecer consumibles\",\n        \"fr\": \"Réinitialiser les consommables\",\n        \"it\": \"Resetta i materiali di consumo\",\n        \"no\": \"Tilbakestill forbruksvarer\",\n        \"sv\": \"Återställ förbrukningsvaror\",\n        \"pl\": \"Zresetuj materiały eksploatacyjne\",\n        \"ru\": \"Сбросить расходные материалы\",\n        \"ko\": \"소모품 초기화\"\n      },\n      \"desc\": {\n        \"en\": \"Reset the usage of vacuum cleaner consumables.\",\n        \"nl\": \"Reset het gebruik van de verbruiksartikelen\",\n        \"da\": \"Nulstil brugen af støvsugerens forbrugsvarer.\",\n        \"de\": \"Setzen Sie die Verwendung von Staubsauger-Verbrauchsmaterialien zurück.\",\n        \"es\": \"Restablezca el uso de los consumibles de la aspiradora.\",\n        \"fr\": \"Réinitialisez l'utilisation des consommables de l'aspirateur.\",\n        \"it\": \"Reimposta l'uso dei materiali di consumo dell'aspirapolvere.\",\n        \"no\": \"Tilbakestill bruken av støvsugerens forbruksvarer.\",\n        \"sv\": \"Återställ användningen av dammsugarens förbrukningsvaror.\",\n        \"pl\": \"Zresetuj użycie materiałów eksploatacyjnych odkurzacza.\",\n        \"ru\": \"Сбросить использование расходных материалов для пылесоса.\",\n        \"ko\": \"진공 청소기 소모품 사용 초기화.\"\n      }\n    }\n  },\n  \"energy\": {\n    \"batteries\": [\n      \"INTERNAL\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/vacuum_mi_rockrobo_vacuum_advanced/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MiRobotAdvancedDriver extends Driver {}\n\nmodule.exports = MiRobotAdvancedDriver;"
  },
  {
    "path": "drivers/vacuum_mi_rockrobo_vacuum_advanced/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Consumables\",\n      \"nl\": \"Verbruiksartikelen\",\n      \"da\": \"Forbrugsstoffer\",\n      \"de\": \"Verbrauchsmaterialien\",\n      \"es\": \"Consumibles\",\n      \"fr\": \"Consommables\",\n      \"it\": \"Materiali di consumo\",\n      \"no\": \"Forbruksvarer\",\n      \"sv\": \"Förbrukningsvaror\",\n      \"pl\": \"Materiały eksploatacyjne\",\n      \"ru\": \"Расходные материалы\",\n      \"ko\": \"소모품\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_threshold\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Alarm threshold\",\n          \"nl\": \"Alarm ondergrens\",\n          \"da\": \"Alarmgrænse\",\n          \"de\": \"Alarmschwelle\",\n          \"es\": \"Umbral de alarma\",\n          \"fr\": \"Seuil d'alarme\",\n          \"it\": \"Soglia di allarme\",\n          \"no\": \"Alarmterskel\",\n          \"sv\": \"Larmtröskel\",\n          \"pl\": \"Próg alarmowy\",\n          \"ru\": \"Порог тревоги\",\n          \"ko\": \"알람 임계값\"\n        },\n        \"hint\": {\n          \"en\": \"Threshold below which the alarm will be activated.\",\n          \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n          \"da\": \"Grænse under hvilken alarmen aktiveres.\",\n          \"de\": \"Schwellenwert, unter dem der Alarm ausgelöst wird.\",\n          \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n          \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n          \"it\": \"Soglia al di sotto della quale verrà attivato l'allarme.\",\n          \"no\": \"Terskel under hvilken alarmen utløses.\",\n          \"sv\": \"Tröskel under vilken larmet aktiveras.\",\n          \"pl\": \"Próg, poniżej którego zostanie aktywowany alarm.\",\n          \"ru\": \"Порог, ниже которого сработает сигнализация.\",\n          \"ko\": \"알람이 활성화될 임계값입니다.\"\n        },\n        \"value\": 20,\n        \"attr\": {\n          \"min\": 1,\n          \"max\": 90\n        }\n      },\n      {\n        \"id\": \"main_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Main brush remaining (%)\",\n          \"nl\": \"Hoofdborstel over (%)\",\n          \"da\": \"Hovedbørste tilbage (%)\",\n          \"de\": \"Hauptbürste verbleibend (%)\",\n          \"es\": \"Cepillo principal restante (%)\",\n          \"fr\": \"Brosse principale restante (%)\",\n          \"it\": \"Spazzola principale rimanente (%)\",\n          \"no\": \"Hovedbørste gjenværende (%)\",\n          \"sv\": \"Huvudborste kvar (%)\",\n          \"pl\": \"Główna szczotka pozostało (%)\",\n          \"ru\": \"Основная щетка оставшаяся (%)\",\n          \"ko\": \"메인 브러시 남은 수명 (%)\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"side_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Side brush remaining\",\n          \"nl\": \"Zijborstel over\",\n          \"da\": \"Sidebørste tilbage\",\n          \"de\": \"Seitenbürste verbleibend\",\n          \"es\": \"Cepillo lateral restante\",\n          \"fr\": \"Brosse latérale restante\",\n          \"it\": \"Spazzola laterale rimanente\",\n          \"no\": \"Sidebørste gjenværende\",\n          \"sv\": \"Sidoborste kvar\",\n          \"pl\": \"Boczna szczotka pozostało\",\n          \"ru\": \"Остаток боковой щетки\",\n          \"ko\": \"사이드 브러시 남은 수명\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"filter_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter remaining\",\n          \"nl\": \"Filter over\",\n          \"da\": \"Filter tilbage\",\n          \"de\": \"Verbleibender Filter\",\n          \"es\": \"Filtro restante\",\n          \"fr\": \"Filtre restant\",\n          \"it\": \"Filtro rimanente\",\n          \"no\": \"Filter gjenværende\",\n          \"sv\": \"Filter kvar\",\n          \"pl\": \"Filtr pozostałość\",\n          \"ru\": \"Остаток фильтра\",\n          \"ko\": \"필터 남은 수명\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"sensor_dirty_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Sensors dirty remaining\",\n          \"nl\": \"Sensor vuil over\",\n          \"da\": \"Sensorer beskidte tilbage\",\n          \"de\": \"Sensoren verschmutzt verbleibend\",\n          \"es\": \"Sensores sucios restantes\",\n          \"fr\": \"Capteurs sales restants\",\n          \"it\": \"Sensori sporchi rimanenti\",\n          \"no\": \"Sensorer skitne gjenværende\",\n          \"sv\": \"Smutsiga sensorer kvar\",\n          \"pl\": \"Pozostałe brudne czujniki\",\n          \"ru\": \"Остаток загрязненных датчиков\",\n          \"ko\": \"센서 더러움 남은 시간\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"total_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total work time\",\n          \"nl\": \"Totale gebruikstijd\",\n          \"da\": \"Samlet arbejdstid\",\n          \"de\": \"Gesamte Arbeitszeit\",\n          \"es\": \"Tiempo total de trabajo\",\n          \"fr\": \"Temps de travail total\",\n          \"it\": \"Tempo di lavoro totale\",\n          \"no\": \"Total arbeidstid\",\n          \"sv\": \"Total arbetstid\",\n          \"pl\": \"Całkowity czas pracy\",\n          \"ru\": \"Общее время работы\",\n          \"ko\": \"총 작업 시간\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"total_cleared_area\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total cleaned area\",\n          \"nl\": \"Totaal geschoont\",\n          \"da\": \"Samlet rengjort areal\",\n          \"de\": \"Gesamt gereinigte Fläche\",\n          \"es\": \"Área total limpiada\",\n          \"fr\": \"Surface nettoyée totale\",\n          \"it\": \"Area totale pulita\",\n          \"no\": \"Totalt rengjort område\",\n          \"sv\": \"Totalt rengjort område\",\n          \"pl\": \"Całkowicie oczyszczony obszar\",\n          \"ru\": \"Общая очищенная площадь\",\n          \"ko\": \"총 청소 면적\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"total_clean_count\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total clean count\",\n          \"nl\": \"Totaal aantal opschoningen\",\n          \"da\": \"Samlet rengøringsantal\",\n          \"de\": \"Gesamtanzahl der Reinigungen\",\n          \"es\": \"Cantidad total de limpiezas\",\n          \"fr\": \"Compte total de nettoyage\",\n          \"it\": \"Numero totale di pulizie\",\n          \"no\": \"Total rengjøringstellcount\",\n          \"sv\": \"Total städräkning\",\n          \"pl\": \"Całkowita liczba czyszczeń\",\n          \"ru\": \"Общее количество уборок\",\n          \"ko\": \"총 청소 횟수\"\n        },\n        \"value\": \"0\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device data\",\n      \"nl\": \"Apparaat data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"장치 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"rooms\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Room cleaning segments\",\n          \"nl\": \"Kamer stofzuig segmenten\",\n          \"da\": \"Rensegmenter i rum\",\n          \"de\": \"Raumreinigungssegmente\",\n          \"es\": \"Segmentos de limpieza de habitaciones\",\n          \"fr\": \"Segments de nettoyage de pièce\",\n          \"it\": \"Segmenti di pulizia delle stanze\",\n          \"no\": \"Rom rengjøringssegmenter\",\n          \"sv\": \"Rengöringssegment i rum\",\n          \"pl\": \"Segmenty sprzątania pomieszczeń\",\n          \"ru\": \"Сегменты уборки комнаты\",\n          \"ko\": \"방 청소 구역\"\n        },\n        \"value\": \"[[17,20,21]]\"\n      },\n      {\n        \"id\": \"error\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Error\",\n          \"nl\": \"Error\",\n          \"da\": \"Fejl\",\n          \"de\": \"Fehler\",\n          \"es\": \"Error\",\n          \"fr\": \"Erreur\",\n          \"it\": \"Errore\",\n          \"no\": \"Feil\",\n          \"sv\": \"Fel\",\n          \"pl\": \"Błąd\",\n          \"ru\": \"Ошибка\",\n          \"ko\": \"오류\"\n        },\n        \"value\": \"No error\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuraciones del dispositivo\",\n      \"fr\": \"Paramètres du dispositif\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/vacuum_mi_rockrobo_vacuum_advanced/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/vacuum_mi_rockrobo_vacuum_advanced/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_mi_rockrobo_vacuum_advanced/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_mija_vacuum_miot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/mijia.vacuum.v1\n// https://home.miot-spec.com/spec/mijia.vacuum.v2\n// https://home.miot-spec.com/spec/mijia.vacuum.v3\n// https://home.miot-spec.com/spec/mijia.vacuum.b108za\n// https://home.miot-spec.com/spec/mijia.vacuum.b108zb\n// https://home.miot-spec.com/spec/ijai.vacuum.v1\n// https://home.miot-spec.com/spec/ijai.vacuum.v2\n// https://home.miot-spec.com/spec/ijai.vacuum.v3\n// https://home.miot-spec.com/spec/ijai.vacuum.v10\n// https://home.miot-spec.com/spec/ijai.vacuum.v13\n// https://home.miot-spec.com/spec/ijai.vacuum.v14\n// https://home.miot-spec.com/spec/ijai.vacuum.v15\n// https://home.miot-spec.com/spec/ijai.vacuum.v16\n// https://home.miot-spec.com/spec/ijai.vacuum.v17\n// https://home.miot-spec.com/spec/ijai.vacuum.v18\n// https://home.miot-spec.com/spec/ijai.vacuum.v19\n\nconst mapping = {\n  \"mijia.vacuum.v1\": \"properties_default\",\n  \"mijia.vacuum.v2\": \"properties_default\",\n  \"mijia.vacuum.v3\": \"properties_mijia_v3\",\n  \"mijia.vacuum.b108za\": \"properties_mijia_b108za\",\n  \"mijia.vacuum.b108zb\": \"properties_mijia_b108za\",\n  \"ijai.vacuum.v1\": \"properties_ijai_v1\",\n  \"ijai.vacuum.v2\": \"properties_ijai_v1\",\n  \"ijai.vacuum.v3\": \"properties_ijai_v1\",\n  \"ijai.vacuum.v10\": \"properties_ijai_v1\",\n  \"ijai.vacuum.v13\": \"properties_ijai_v1\",\n  \"ijai.vacuum.v14\": \"properties_ijai_v1\",\n  \"ijai.vacuum.v15\": \"properties_ijai_v1\",\n  \"ijai.vacuum.v16\": \"properties_ijai_v1\",\n  \"ijai.vacuum.v17\": \"properties_ijai_v1\",\n  \"ijai.vacuum.v18\": \"properties_ijai_v1\",\n  \"ijai.vacuum.v19\": \"properties_ijai_v1\",\n  \"mijia.vacuum.*\": \"properties_default\",\n};\n\nconst properties = {\n  \"properties_default\": {\n    \"get_properties\": [\n      { did: \"battery\", siid: 3, piid: 1 }, // measure_battery\n      { did: \"device_fault\", siid : 2, piid: 2 }, // settings.error\n      { did: \"device_status\", siid: 2, piid: 1 }, // vacuumcleaner_state\n      { did: \"fan_speed\", siid: 2, piid: 6 }, // vacuum_dreame_fanspeed\n      { did: \"main_brush_life_level\", siid: 24, piid: 2 }, // settings.main_brush_work_time\n      { did: \"side_brush_life_level\", siid: 25, piid: 1 }, // settings.side_brush_work_time\n      { did: \"filter_life_level\", siid: 11, piid: 1 }, // settings.filter_work_time\n      { did: \"total_clean_time\", siid: 9, piid: 4 }, // settings.total_work_time\n      { did: \"total_clean_count\", siid: 9, piid: 5 }, // settings.clean_count\n      { did: \"total_clean_area\", siid: 9, piid: 3 } // settings.total_cleared_area\n    ],\n    \"set_properties\": {\n      \"start_clean\": { siid: 2, aiid: 1, did: \"call-2-1\", in: [] },\n      \"stop_clean\": { siid: 2, aiid: 2, did: \"call-2-2\", in: [] },\n      \"find\": { siid: 6, aiid: 1, did: \"call-6-1\", in: [] },\n      \"home\": { siid: 2, aiid: 3, did: \"call-2-3\", in: [] },\n      \"fanspeed\": { siid: 2, piid: 6 }\n    },\n    \"error_codes\": {\n      0: \"No Error\",\n      1: \"Left-wheel-error\",\n      2: \"Right-wheel-error\",\n      3: \"Cliff-error\",\n      4: \"Low-battery-error\",\n      5: \"Bump-error\",\n      6: \"Main-brush-error\",\n      7: \"Side-brush-error\",\n      8: \"Fan-motor-error\",\n      9: \"Dustbin-error\",\n      10: \"Charging-error\",\n      11: \"No-water-error\",\n      0: \"Everything-is-ok\",\n      12: \"Pick-up-error\"\n    },\n    \"status_mapping\": {\n      \"cleaning\": [2, 6],\n      \"spot_cleaning\": [],\n      \"docked\": [],\n      \"charging\": [5],\n      \"stopped\": [1, 3],\n      \"stopped_error\": [4]\n    }\n  },\n  \"properties_mijia_v3\": {\n    \"get_properties\": [\n      { did: \"battery\", siid: 3, piid: 1 }, // measure_battery\n      { did: \"device_fault\", siid : 2, piid: 2 }, // settings.error\n      { did: \"device_status\", siid: 2, piid: 1 }, // vacuumcleaner_state\n      { did: \"fan_speed\", siid: 2, piid: 6 }, // vacuum_dreame_fanspeed\n      { did: \"main_brush_life_level\", siid: 14, piid: 1 }, // settings.main_brush_work_time\n      { did: \"side_brush_life_level\", siid: 15, piid: 1 }, // settings.side_brush_work_time\n      { did: \"filter_life_level\", siid: 11, piid: 1 }, // settings.filter_work_time\n      { did: \"total_clean_time\", siid: 9, piid: 4 }, // settings.total_work_time\n      { did: \"total_clean_count\", siid: 9, piid: 5 }, // settings.clean_count\n      { did: \"total_clean_area\", siid: 9, piid: 3 } // settings.total_cleared_area\n    ],\n    \"set_properties\": {\n      \"start_clean\": { siid: 2, aiid: 1, did: \"call-2-1\", in: [] },\n      \"stop_clean\": { siid: 2, aiid: 2, did: \"call-2-2\", in: [] },\n      \"find\": { siid: 6, aiid: 1, did: \"call-6-1\", in: [] },\n      \"home\": { siid: 2, aiid: 3, did: \"call-2-3\", in: [] },\n      \"fanspeed\": { siid: 2, piid: 6 }\n    },\n    \"error_codes\": {\n      0: \"No Error\",\n      1: \"Left-wheel-error\",\n      2: \"Right-wheel-error\",\n      3: \"Cliff-error\",\n      4: \"Low-battery-error\",\n      5: \"Bump-error\",\n      6: \"Main-brush-error\",\n      7: \"Side-brush-error\",\n      8: \"Fan-motor-error\",\n      9: \"Dustbin-error\",\n      10: \"Charging-error\",\n      11: \"No-water-error\",\n      0: \"Everything-is-ok\",\n      12: \"Pick-up-error\"\n    },\n    \"status_mapping\": {\n      \"cleaning\": [2, 6],\n      \"spot_cleaning\": [],\n      \"docked\": [],\n      \"charging\": [5],\n      \"stopped\": [1, 3],\n      \"stopped_error\": [4]\n    }\n  },\n  \"properties_mijia_b108za\": {\n    \"get_properties\": [\n      { did: \"battery\", siid: 3, piid: 1 }, // measure_battery\n      { did: \"device_fault\", siid : 2, piid: 2 }, // settings.error\n      { did: \"device_status\", siid: 2, piid: 1 }, // vacuumcleaner_state\n      { did: \"fan_speed\", siid: 2, piid: 8 }, // vacuum_dreame_fanspeed\n      { did: \"main_brush_life_level\", siid: 8, piid: 1 }, // settings.main_brush_work_time\n      { did: \"side_brush_life_level\", siid: 9, piid: 1 }, // settings.side_brush_work_time\n      { did: \"filter_life_level\", siid: 10, piid: 2 }, // settings.filter_work_time\n      { did: \"total_clean_time\", siid: 2, piid: 6 }, // settings.total_work_time\n      { did: \"total_clean_count\", siid: 2, piid: 7 }, // settings.clean_count\n      { did: \"total_clean_area\", siid: 2, piid: 5 } // settings.total_cleared_area\n    ],\n    \"set_properties\": {\n      \"start_clean\": { siid: 2, aiid: 1, did: \"call-2-1\", in: [] },\n      \"stop_clean\": { siid: 2, aiid: 2, did: \"call-2-2\", in: [] },\n      \"find\": { siid: 6, aiid: 6, did: \"call-6-6\", in: [] },\n      \"home\": { siid: 6, aiid: 15, did: \"call-6-15\", in: [] },\n      \"fanspeed\": { siid: 2, piid: 8 }\n    },\n    \"error_codes\": {\n      0: \"No Error\",\n      1: \"Left-wheel-error\",\n      2: \"Right-wheel-error\",\n      3: \"Cliff-error\",\n      4: \"Low-battery-error\",\n      5: \"Bump-error\",\n      6: \"Main-brush-error\",\n      7: \"Side-brush-error\",\n      8: \"Fan-motor-error\",\n      9: \"Dustbin-error\",\n      10: \"Charging-error\",\n      11: \"No-water-error\",\n      0: \"Everything-is-ok\",\n      12: \"Pick-up-error\"\n    },\n    \"status_mapping\": {\n      \"cleaning\": [4, 6, 7],\n      \"spot_cleaning\": [],\n      \"docked\": [8],\n      \"charging\": [2, 3],\n      \"stopped\": [1, 5, 9, 10],\n      \"stopped_error\": []\n    }\n  },\n  \"properties_ijai_v1\": {\n    \"get_properties\": [\n      { did: \"device_status\", siid: 2, piid: 1 }, // vacuumcleaner_state\n      { did: \"device_fault\", siid : 2, piid: 2 }, // settings.error\n      { did: \"battery\", siid: 3, piid: 1 }, // measure_battery\n      { did: \"main_brush_life_level\", siid: 7, piid: 10 }, // settings.main_brush_work_time\n      { did: \"side_brush_life_level\", siid: 7, piid: 8 }, // settings.side_brush_work_time\n      { did: \"filter_life_level\", siid: 7, piid: 12 }, // settings.filter_work_time\n      { did: \"total_clean_time\", siid: 7, piid: 28 }, // settings.total_work_time\n      { did: \"total_clean_count\", siid: 7, piid: 22 }, // settings.clean_count\n      { did: \"total_clean_area\", siid: 7, piid: 29 } // settings.total_cleared_area\n    ],\n    \"set_properties\": {\n      \"start_clean\": { siid: 2, aiid: 1, did: \"call-2-1\", in: [] },\n      \"stop_clean\": { siid: 2, aiid: 2, did: \"call-2-2\", in: [] },\n      \"find\": { siid: 6, aiid: 6, did: \"call-6-6\", in: [] },\n      \"home\": { siid: 3, aiid: 1, did: \"call-3-1\", in: [] }\n    },\n    \"error_codes\": {\n      0: \"No Error\",\n      1: \"Left-wheel-error\",\n      2: \"Right-wheel-error\",\n      3: \"Cliff-error\",\n      4: \"Low-battery-error\",\n      5: \"Bump-error\",\n      6: \"Main-brush-error\",\n      7: \"Side-brush-error\",\n      8: \"Fan-motor-error\",\n      9: \"Dustbin-error\",\n      10: \"Charging-error\",\n      11: \"No-water-error\",\n      0: \"Everything-is-ok\",\n      12: \"Pick-up-error\"\n    },\n    \"status_mapping\": {\n      \"cleaning\": [3, 5, 6, 7],\n      \"spot_cleaning\": [],\n      \"docked\": [0],\n      \"charging\": [4],\n      \"stopped\": [1, 2, 8],\n      \"stopped_error\": []\n    }\n  }\n}\n\nclass MijaVacuumMiotDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // ADD/REMOVE DEVICES DEPENDANT CAPABILITIES\n      if (this.getStoreValue('model').startsWith('ijai.vacuum')) {\n        if (this.hasCapability('vacuum_dreame_fanspeed')) {\n          this.removeCapability('vacuum_dreame_fanspeed');\n        }\n      }\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['mijia.vacuum.*']];\n\n      // RESET CONSUMABLE ALARMS\n      this.updateCapabilityValue(\"alarm_main_brush_work_time\", false);\n      this.updateCapabilityValue(\"alarm_side_brush_work_time\", false);\n      this.updateCapabilityValue(\"alarm_filter_work_time\", false);\n\n      // DEVICE TOKENS\n      this.main_brush_lifetime_token = await this.homey.flow.createToken(\"main_brush_lifetime\"+ this.getData().id, {type: \"number\", title: \"Main Brush Lifetime \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.side_brush_lifetime_token = await this.homey.flow.createToken(\"side_brush_lifetime\"+ this.getData().id, {type: \"number\", title: \"Side Brush Lifetime \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.filter_lifetime_token = await this.homey.flow.createToken(\"filter_lifetime\"+ this.getData().id, {type: \"number\", title: \"Filter LifeTime \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.total_work_time_token = await this.homey.flow.createToken(\"total_work_time\"+ this.getData().id, {type: \"number\", title: \"Total Work Time \" + this.getName() +\" h)\" }).catch(error => { this.error(error) });\n      this.total_cleared_area_token = await this.homey.flow.createToken(\"total_cleared_area\"+ this.getData().id, {type: \"number\", title: \"Total Cleaned Area \" + this.getName() +\" (m2)\" }).catch(error => { this.error(error) });\n      this.total_clean_count_token = await this.homey.flow.createToken(\"total_clean_count\"+ this.getData().id, {type: \"number\", title: \"Total Clean Count \"+ this.getName() }).catch(error => { this.error(error) });\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('alertVacuum');\n      this.homey.flow.getDeviceTriggerCard('statusVacuum');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            if (value) {\n              return await this.miio.call(\"action\", this.deviceProperties.set_properties.start_clean, { retries: 1 });\n            } else {\n              return await this.miio.call(\"action\", this.deviceProperties.set_properties.stop_clean, { retries: 1 });\n            }\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('vacuumcleaner_state', async ( value ) => {\n        try {\n          if (this.miio) {\n            switch (value) {\n              case \"cleaning\":\n              case \"spot_cleaning\":\n                return await this.triggerCapabilityListener('onoff', true);\n              case \"docked\":\n              case \"charging\":\n                return await this.miio.call(\"action\", this.deviceProperties.set_properties.home, { retries: 1 });\n              case \"stopped\":\n                return await this.triggerCapabilityListener('onoff', false);\n            }\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      /* vacuumcleaner dreame fanspeed */\n      this.registerCapabilityListener('vacuum_dreame_fanspeed', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.fanspeed.siid, piid: this.deviceProperties.set_properties.fanspeed.piid, value: Number(value) }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const device_status = result.find(obj => obj.did === 'device_status');\n      const battery = result.find(obj => obj.did === 'battery');\n      const fan_speed = result.find(obj => obj.did === 'fan_speed');\n      const main_brush_life_level = result.find(obj => obj.did === 'main_brush_life_level');\n      const side_brush_life_level = result.find(obj => obj.did === 'side_brush_life_level');\n      const filter_life_level = result.find(obj => obj.did === 'filter_life_level');\n      const total_clean_time = result.find(obj => obj.did === 'total_clean_time');\n      const total_clean_count = result.find(obj => obj.did === 'total_clean_count');\n      const total_clean_area = result.find(obj => obj.did === 'total_clean_area');\n      const device_fault = result.find(obj => obj.did === 'device_fault');\n\n      const consumables = [\n        {\n          \"main_brush_work_time\": main_brush_life_level.value,\n          \"side_brush_work_time\": side_brush_life_level.value,\n          \"filter_work_time\": filter_life_level.value,\n        }\n      ]\n\n      const totals = {\n        \"clean_time\": total_clean_time.value,\n        \"clean_count\": total_clean_count.value,\n        \"clean_area\": total_clean_area.value,\n      }\n\n      /* onoff & vacuumcleaner_state */\n      for (let key in this.deviceProperties.status_mapping) {\n        if (this.deviceProperties.status_mapping[key].includes(device_status.value)) {\n          if (this.getCapabilityValue('measure_battery') === 100 && (key === \"stopped\" || key === \"charging\")) {\n            this.vacuumCleanerState(\"docked\");\n          } else {\n            this.vacuumCleanerState(key);\n          }\n        } else {\n          this.log(\"Not a valid vacuumcleaner_state\", device_status.value);\n        }\n      }\n\n      /* measure_battery & alarm_battery */\n      await this.updateCapabilityValue(\"measure_battery\", battery.value);\n      await this.updateCapabilityValue(\"alarm_battery\", battery.value <= 20 ? true : false);\n\n      /* vacuum_dreame_fanspeed */\n      if (fan_speed !== undefined && this.hasCapability('vacuum_dreame_fanspeed')) {\n        await this.updateCapabilityValue(\"vacuum_dreame_fanspeed\", fan_speed.value.toString());\n      }\n\n      /* consumable settings */\n      this.vacuumConsumables(consumables);\n\n      /* totals */\n      this.vacuumTotals(totals);\n\n      /* settings device error */\n      const error = this.deviceProperties.error_codes[device_fault.value];\n      if (this.getSetting('error') !== error ) {\n        await this.setSettings({ error: error });\n        if (error !== 0) {\n          await this.homey.flow.getDeviceTriggerCard('statusVacuum').trigger(this, {\"status\": error }).catch(error => { this.error(error) });\n        }\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = MijaVacuumMiotDevice;"
  },
  {
    "path": "drivers/vacuum_mija_vacuum_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mija/Ijai Vacuum Cleaner MIoT (WiFi)\",\n    \"nl\": \"Mija/Ijai stofzuiger MIoT (WiFi)\",\n    \"da\": \"Mija/Ijai støvsuger MIoT (WiFi)\",\n    \"de\": \"Mija/Ijai Staubsauger MIoT (WiFi)\",\n    \"es\": \"Mija/Ijai aspiradora MIoT (WiFi)\",\n    \"fr\": \"Mija/Ijai Aspirateur MIoT (WiFi)\",\n    \"it\": \"Mija/Ijai Aspirapolvere MIoT (WiFi)\",\n    \"no\": \"Mija/Ijai støvsuger MIoT (WiFi)\",\n    \"sv\": \"Mija/Ijai dammsugare MIoT (WiFi)\",\n    \"pl\": \"Mija/Ijai Odkurzacz MIoT (WiFi)\",\n    \"ru\": \"Mija/Ijai пылесос MIoT (WiFi)\",\n    \"ko\": \"Mija/Ijai 진공 청소기 MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/vacuum_mija_vacuum_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/vacuum_mija_vacuum_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"vacuumcleaner\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"vacuumcleaner_state\",\n    \"vacuum_dreame_fanspeed\",\n    \"measure_battery\",\n    \"alarm_battery\",\n    \"alarm_main_brush_work_time\",\n    \"alarm_side_brush_work_time\",\n    \"alarm_filter_work_time\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"INTERNAL\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/vacuum_mija_vacuum_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass MijaVacuumMiotDriver extends Driver {}\n\nmodule.exports = MijaVacuumMiotDriver;"
  },
  {
    "path": "drivers/vacuum_mija_vacuum_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Consumables\",\n      \"nl\": \"Verbruiksartikelen\",\n      \"da\": \"Forbrugsmaterialer\",\n      \"de\": \"Verbrauchsmaterialien\",\n      \"es\": \"Consumibles\",\n      \"fr\": \"Consommables\",\n      \"it\": \"Consumabili\",\n      \"no\": \"Forbruksmateriell\",\n      \"sv\": \"Förbrukningsvaror\",\n      \"pl\": \"Materiały eksploatacyjne\",\n      \"ru\": \"Расходные материалы\",\n      \"ko\": \"소모품\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_threshold\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Alarm threshold\",\n          \"nl\": \"Alarm ondergrens\",\n          \"da\": \"Alarmtærskel\",\n          \"de\": \"Alarmschwelle\",\n          \"es\": \"Umbral de alarma\",\n          \"fr\": \"Seuil d'alarme\",\n          \"it\": \"Soglia di allarme\",\n          \"no\": \"Alarmterskel\",\n          \"sv\": \"Alarmtröskel\",\n          \"pl\": \"Próg alarmowy\",\n          \"ru\": \"Порог сигнала тревоги\",\n          \"ko\": \"알람 임계값\"\n        },\n        \"hint\": {\n          \"en\": \"Threshold below which the alarm will be activated.\",\n          \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n          \"da\": \"Tærskel under hvilken alarmen aktiveres.\",\n          \"de\": \"Schwellwert, unter dem der Alarm ausgelöst wird.\",\n          \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n          \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n          \"it\": \"Soglia sotto la quale verrà attivato l'allarme.\",\n          \"no\": \"Terskel under hvilken alarmen vil bli aktivert.\",\n          \"sv\": \"Tröskel under vilken larmet aktiveras.\",\n          \"pl\": \"Próg, poniżej którego alarm zostanie włączony.\",\n          \"ru\": \"Порог, ниже которого будет активирован сигнал тревоги.\",\n          \"ko\": \"알람이 활성화되는 임계값 이하.\"\n        },\n        \"value\": 20,\n        \"attr\": {\n          \"min\": 1,\n          \"max\": 90\n        }\n      },\n      {\n        \"id\": \"main_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Main brush remaining (%)\",\n          \"nl\": \"Hoofdborstel over (%)\",\n          \"da\": \"Hovedbørste tilbage (%)\",\n          \"de\": \"Hauptbürste verbleibend (%)\",\n          \"es\": \"Cepillo principal restante (%)\",\n          \"fr\": \"Brosse principale restante (%)\",\n          \"it\": \"Percentuale residua della spazzola principale (%)\",\n          \"no\": \"Hovedbørste gjenstår (%)\",\n          \"sv\": \"Huvudborste återstår (%)\",\n          \"pl\": \"Pozostałość głównej szczotki (%)\",\n          \"ru\": \"Осталось основной щетки (%)\",\n          \"ko\": \"메인 브러시 남음 (%)\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"side_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Side brush remaining\",\n          \"nl\": \"Zijborstel over\",\n          \"da\": \"Sidebørste tilbage\",\n          \"de\": \"Seitenbürste verbleibend\",\n          \"es\": \"Cepillo lateral restante\",\n          \"fr\": \"Brosse latérale restante\",\n          \"it\": \"Percentuale residua della spazzola laterale\",\n          \"no\": \"Sidebørste gjenstår\",\n          \"sv\": \"Sidoborste återstår\",\n          \"pl\": \"Pozostałość szczotki bocznej\",\n          \"ru\": \"Осталось боковой щетки\",\n          \"ko\": \"사이드 브러시 남음\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"filter_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter remaining\",\n          \"nl\": \"Filter over\",\n          \"da\": \"Filter tilbage\",\n          \"de\": \"Filter verbleibend\",\n          \"es\": \"Filtro restante\",\n          \"fr\": \"Filtre restant\",\n          \"it\": \"Percentuale residua del filtro\",\n          \"no\": \"Filter gjenstår\",\n          \"sv\": \"Filter återstår\",\n          \"pl\": \"Pozostałość filtra\",\n          \"ru\": \"Осталось фильтра\",\n          \"ko\": \"필터 남음\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"total_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total work time\",\n          \"nl\": \"Totale gebruikstijd\",\n          \"da\": \"Samlet arbejdstid\",\n          \"de\": \"Gesamtarbeitszeit\",\n          \"es\": \"Tiempo total de trabajo\",\n          \"fr\": \"Temps de travail total\",\n          \"it\": \"Tempo totale di lavoro\",\n          \"no\": \"Total arbeidstid\",\n          \"sv\": \"Total arbetstid\",\n          \"pl\": \"Całkowity czas pracy\",\n          \"ru\": \"Общее время работы\",\n          \"ko\": \"총 작업 시간\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"total_cleared_area\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total cleaned area\",\n          \"nl\": \"Totaal geschoont\",\n          \"da\": \"Samlet renset område\",\n          \"de\": \"Gesamtfläche gereinigt\",\n          \"es\": \"Área total limpiada\",\n          \"fr\": \"Surface totale nettoyée\",\n          \"it\": \"Area pulita totale\",\n          \"no\": \"Total rengjort område\",\n          \"sv\": \"Total rengjord yta\",\n          \"pl\": \"Całkowita oczyszczona powierzchnia\",\n          \"ru\": \"Общая очищенная площадь\",\n          \"ko\": \"총 청소된 면적\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"total_clean_count\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total clean count\",\n          \"nl\": \"Totaal aantal opschoningen\",\n          \"da\": \"Samlet rengøringsantal\",\n          \"de\": \"Gesamte Reinigungsanzahl\",\n          \"es\": \"Recuento total de limpiezas\",\n          \"fr\": \"Nombre total de nettoyages\",\n          \"it\": \"Conteggio totale delle pulizie\",\n          \"no\": \"Total rengjøringsteller\",\n          \"sv\": \"Total rengöringsräkning\",\n          \"pl\": \"Całkowita liczba oczyszczeń\",\n          \"ru\": \"Общее количество уборок\",\n          \"ko\": \"총 청소 횟수\"\n        },\n        \"value\": \"0\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device data\",\n      \"nl\": \"Apparaat data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"장치 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"error\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Error\",\n          \"nl\": \"Error\",\n          \"da\": \"Fejl\",\n          \"de\": \"Fehler\",\n          \"es\": \"Error\",\n          \"fr\": \"Erreur\",\n          \"it\": \"Errore\",\n          \"no\": \"Feil\",\n          \"sv\": \"Fel\",\n          \"pl\": \"Błąd\",\n          \"ru\": \"Ошибка\",\n          \"ko\": \"오류\"\n        },\n        \"value\": \"No error\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/vacuum_mija_vacuum_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/vacuum_mija_vacuum_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_mija_vacuum_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_roidmi_vacuum_miot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/roidmi.vacuum.v60 // Roidmi Eve\n// https://home.miot-spec.com/spec/roidmi.vacuum.v66 // Roidmi Eva\n\n\nconst mapping = {\n  \"roidmi.vacuum.v60\": \"properties_default\",\n  \"roidmi.vacuum.v66\": \"properties_default\",\n  \"roidmi.vacuum.*\": \"properties_default\",\n};\n\nconst properties = {\n  \"properties_default\": {\n    \"get_properties\": [\n      { did: \"battery\", siid: 3, piid: 1 }, // measure_battery\n      { did: \"charge_state\", siid: 3, piid: 2 },\n      { did: \"device_fault\", siid : 2, piid: 2 }, // settings.error\n      { did: \"device_status\", siid: 2, piid: 1 }, // vacuumcleaner_state\n      { did: \"fan_speed\", siid: 2, piid: 4 }, // vacuum_roidmi_fanspeed\n      { did: \"sweep_mode\", siid: 14, piid: 1 },\n      { did: \"sweep_type\", siid: 2, piid: 8 }, // vacuum_roidmi_mop_mode\n      { did: \"water_level\", siid: 8, piid: 11 }, // vacuum_roidmi_waterlevel\n      { did: \"main_brush_time_remaining\", siid: 11, piid: 2 }, // settings.main_brush_time_remaining\n      { did: \"side_brush_time_remaining\", siid: 12, piid: 2 }, // settings.side_brush_time_remaining\n      { did: \"filter_time_remaining\", siid: 10, piid: 1 }, // settings.filter_time_remaining\n      { did: \"sensor_time_remaining\", siid: 15, piid: 2 }, // settings.sensor_time_remaining\n      { did: \"total_clean_area\", siid: 8, piid: 14 }, // settings.total_cleared_area\n      { did: \"total_clean_count\", siid: 8, piid: 18 }, // settings.clean_count\n      { did: \"total_clean_time\", siid: 8, piid: 13 } // settings.total_work_time      \n    ],\n    \"set_properties\": {\n      \"start_clean\": { siid: 2, aiid: 1, did: \"call-2-1\", in: [] },\n      \"stop_clean\": { siid: 2, aiid: 2, did: \"call-2-2\", in: [] },\n      \"find\": { siid: 8, aiid: 1, did: \"call-8-1\", in: [] },\n      \"home\": { siid: 3, aiid: 1, did: \"call-3-1\", in: [] },\n      \"fanspeed\": { siid: 2, piid: 4 },\n      \"mopmode\": { siid: 2, piid: 8 }\n    }\n  }\n}\n\nclass RoidmiMiotDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // DEVICE VARIABLES\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['roidmi.vacuum.*']];\n\n      this.errorCodes = {\n        0: \"No Error\",\n        1: \"Low Battery Find Charger\",\n        2: \"Low Battery And Poweroff\",\n        3: \"Wheel Trap\",\n        4: \"Collision Error\",\n        5: \"Tile Do Task\",\n        6: \"Lidar Point Error\",\n        7: \"Front Wall Error\",\n        8: \"Psd Dirty\",\n        9: \"Middle Brush Fatal\",\n        10: \"Sid Brush\",\n        11: \"Fan Speed Error\",\n        12: \"Lidar Cover\",\n        13: \"Garbage Box Full\",\n        14: \"Garbage Box Out\",\n        15: \"Garbage Box Full Out\",\n        16: \"Physical Trapped\",\n        17: \"Pick Up Do Task\",\n        18: \"No Water Box Do Task\",\n        19: \"Water Box Empty\",\n        20: \"Clean Cannot Arrive\",\n        21: \"Start Form Forbid\",\n        22: \"Drop\",\n        23: \"Kit Water Pump\",\n        24: \"Find Charger Failed\",\n        25: \"Low Power Clean\"\n      };\n\n      // RESET CONSUMABLE ALARMS\n      this.updateCapabilityValue(\"alarm_main_brush_work_time\", false);\n      this.updateCapabilityValue(\"alarm_side_brush_work_time\", false);\n      this.updateCapabilityValue(\"alarm_filter_work_time\", false);\n      this.updateCapabilityValue(\"alarm_sensor_dirty_time\", false);\n\n      // DEVICE TOKENS\n      this.main_brush_lifetime_token = await this.homey.flow.createToken(\"main_brush_lifetime\"+ this.getData().id, {type: \"number\", title: \"Main Brush Lifetime \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.side_brush_lifetime_token = await this.homey.flow.createToken(\"side_brush_lifetime\"+ this.getData().id, {type: \"number\", title: \"Side Brush Lifetime \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.filter_lifetime_token = await this.homey.flow.createToken(\"filter_lifetime\"+ this.getData().id, {type: \"number\", title: \"Filter LifeTime \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.sensor_dirty_lifetime_token = await this.homey.flow.createToken(\"sensor_dirty_lifetime\"+ this.getData().id, {type: \"number\", title: \"Sensor Dirty Time \" + this.getName() +\" (%)\" }).catch(error => { this.error(error) });\n      this.total_work_time_token = await this.homey.flow.createToken(\"total_work_time\"+ this.getData().id, {type: \"number\", title: \"Total Work Time \" + this.getName() +\" h)\" }).catch(error => { this.error(error) });\n      this.total_cleared_area_token = await this.homey.flow.createToken(\"total_cleared_area\"+ this.getData().id, {type: \"number\", title: \"Total Cleaned Area \" + this.getName() +\" (m2)\" }).catch(error => { this.error(error) });\n      this.total_clean_count_token = await this.homey.flow.createToken(\"total_clean_count\"+ this.getData().id, {type: \"number\", title: \"Total Clean Count \"+ this.getName() }).catch(error => { this.error(error) });\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('alertVacuum');\n      this.homey.flow.getDeviceTriggerCard('statusVacuum');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            if (value) {\n              return await this.miio.call(\"action\", this.deviceProperties.set_properties.start_clean, { retries: 1 });\n            } else {\n              return await this.miio.call(\"action\", this.deviceProperties.set_properties.stop_clean, { retries: 1 });\n            }\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('vacuumcleaner_state', async ( value ) => {\n        try {\n          if (this.miio) {\n            switch (value) {\n              case \"cleaning\":\n              case \"spot_cleaning\":\n                return await this.triggerCapabilityListener('onoff', true);\n              case \"docked\":\n              case \"charging\":\n                return await this.miio.call(\"action\", this.deviceProperties.set_properties.home, { retries: 1 });\n              case \"stopped\":\n                return await this.triggerCapabilityListener('onoff', false);\n            }\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      /* vacuumcleaner roidmi fanspeed */\n      this.registerCapabilityListener('vacuum_roidmi_fanspeed', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.fanspeed.siid, piid: this.deviceProperties.set_properties.fanspeed.piid, value: Number(value) }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      /* vacuumcleaner roidmi mop mode */\n      this.registerCapabilityListener('vacuum_roidmi_mop_mode', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_properties\", [{ siid: this.deviceProperties.set_properties.mopmode.siid, piid: this.deviceProperties.set_properties.mopmode.piid, value: Number(value) }], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_properties\", this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      /* data */\n      const device_status = result.find(obj => obj.did === 'device_status');\n      const battery = result.find(obj => obj.did === 'battery');\n      const fan_speed = result.find(obj => obj.did === 'fan_speed');\n      const mop_mode = result.find(obj => obj.did === 'sweep_type');\n      const water_level = result.find(obj => obj.did === 'water_level');\n      const main_brush_time_remaining = result.find(obj => obj.did === 'main_brush_time_remaining');\n      const side_brush_time_remaining = result.find(obj => obj.did === 'side_brush_time_remaining');\n      const filter_time_remaining = result.find(obj => obj.did === 'filter_time_remaining');\n      const sensor_time_remaining = result.find(obj => obj.did === 'sensor_time_remaining');\n      const total_clean_time = result.find(obj => obj.did === 'total_clean_time');\n      const total_clean_count = result.find(obj => obj.did === 'total_clean_count');\n      const total_clean_area = result.find(obj => obj.did === 'total_clean_area');\n      const device_fault = result.find(obj => obj.did === 'device_fault');\n\n      const consumables = [\n        {\n          \"main_brush_work_time\": main_brush_time_remaining.value,\n          \"side_brush_work_time\": side_brush_time_remaining.value,\n          \"filter_work_time\": filter_time_remaining.value,\n          \"sensor_dirty_time\": sensor_time_remaining.value,\n        }\n      ]\n\n      const totals = {\n        \"clean_time\": total_clean_time.value,\n        \"clean_count\": total_clean_count.value,\n        \"clean_area\": total_clean_area.value,\n      }\n\n      /* onoff & vacuumcleaner_state */\n      switch (device_status.value) {\n        case 4:\n        case 5:\n        case 8:\n          this.vacuumCleanerState(\"cleaning\");\n          break;\n        case 1:\n        case 2:\n        case 3:\n        case 10:\n        case 11:\n          this.vacuumCleanerState(\"stopped\");\n          break;\n        case 6:\n          if (this.getCapabilityValue('measure_battery') === 100) {\n            this.vacuumCleanerState(\"docked\");\n          } else {\n            this.vacuumCleanerState(\"charging\");\n          }\n          break;\n        case 9:\n          this.vacuumCleanerState(\"docked\");\n          break;\n        case 7:\n          this.vacuumCleanerState(\"stopped_error\");\n          break;\n        default:\n          this.log(\"Not a valid vacuumcleaner_state\", device_status.value);\n          break;\n      }\n\n      /* measure_battery & alarm_battery */\n      await this.updateCapabilityValue(\"measure_battery\", battery.value);\n      await this.updateCapabilityValue(\"alarm_battery\", battery.value <= 20 ? true : false);\n\n      /* vacuum_roidmi_fanspeed */\n      await this.updateCapabilityValue(\"vacuum_roidmi_fanspeed\", fan_speed.value.toString());\n\n      /* vacuum_roidmi_mop_mode */\n      await this.updateCapabilityValue(\"vacuum_roidmi_mop_mode\", mop_mode.value.toString());\n\n      /* vacuum_roidmi_waterlevel */\n      await this.updateCapabilityValue(\"vacuum_roidmi_waterlevel\", water_level.value.toString());\n\n      /* consumable settings */\n      this.vacuumConsumables(consumables);\n\n      /* totals */\n      this.vacuumTotals(totals);\n\n      /* settings device error */\n      const error = this.errorCodes[device_fault.value];\n      if (this.getSetting('error') !== error ) {\n        await this.setSettings({ error: error });\n        if (error !== 0) {\n          await this.homey.flow.getDeviceTriggerCard('statusVacuum').trigger(this, {\"status\": error }).catch(error => { this.error(error) });\n        }\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = RoidmiMiotDevice;"
  },
  {
    "path": "drivers/vacuum_roidmi_vacuum_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Roidmi Vacuum Cleaner MIoT (WiFi)\",\n    \"nl\": \"Roidmi stofzuiger MIoT (WiFi)\",\n    \"da\": \"Roidmi støvsuger MIoT (WiFi)\",\n    \"de\": \"Roidmi Staubsauger MIoT (WiFi)\",\n    \"es\": \"Aspiradora Roidmi MIoT (WiFi)\",\n    \"fr\": \"Aspirateur Roidmi MIoT (WiFi)\",\n    \"it\": \"Aspirapolvere Roidmi MIoT (WiFi)\",\n    \"no\": \"Roidmi støvsuger MIoT (WiFi)\",\n    \"sv\": \"Roidmi dammsugare MIoT (WiFi)\",\n    \"pl\": \"Odkurzacz Roidmi MIoT (WiFi)\",\n    \"ru\": \"Пылесос Roidmi MIoT (WiFi)\",\n    \"ko\": \"로이디미 진공 청소기 MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/vacuum_roidmi_vacuum_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/vacuum_roidmi_vacuum_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"vacuumcleaner\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"vacuumcleaner_state\",\n    \"vacuum_roidmi_fanspeed\",\n    \"vacuum_roidmi_mop_mode\",\n    \"vacuum_roidmi_waterlevel\",\n    \"measure_battery\",\n    \"alarm_battery\",\n    \"alarm_main_brush_work_time\",\n    \"alarm_side_brush_work_time\",\n    \"alarm_filter_work_time\",\n    \"alarm_sensor_dirty_time\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"INTERNAL\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/vacuum_roidmi_vacuum_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass RoidmiMiotDriver extends Driver {}\n\nmodule.exports = RoidmiMiotDriver;"
  },
  {
    "path": "drivers/vacuum_roidmi_vacuum_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Consumables\",\n      \"nl\": \"Verbruiksartikelen\",\n      \"da\": \"Forbrugsvarer\",\n      \"de\": \"Verbrauchsmaterialien\",\n      \"es\": \"Consumibles\",\n      \"fr\": \"Consommables\",\n      \"it\": \"Consumabili\",\n      \"no\": \"Forbruksvarer\",\n      \"sv\": \"Förbrukningsartiklar\",\n      \"pl\": \"Materiały eksploatacyjne\",\n      \"ru\": \"Расходные материалы\",\n      \"ko\": \"소모품\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_threshold\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Alarm threshold\",\n          \"nl\": \"Alarm ondergrens\",\n          \"da\": \"Alarmgrænse\",\n          \"de\": \"Alarmschwelle\",\n          \"es\": \"Umbral de alarma\",\n          \"fr\": \"Seuil d'alarme\",\n          \"it\": \"Soglia di allarme\",\n          \"no\": \"Alarmterskel\",\n          \"sv\": \"Larmgräns\",\n          \"pl\": \"Próg alarmowy\",\n          \"ru\": \"Порог тревоги\",\n          \"ko\": \"알람 임계값\"\n        },\n        \"hint\": {\n          \"en\": \"Threshold below which the alarm will be activated.\",\n          \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n          \"da\": \"Tærskel under hvilken alarmen vil blive aktiveret.\",\n          \"de\": \"Schwelle, unter der der Alarm ausgelöst wird.\",\n          \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n          \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n          \"it\": \"Soglia al di sotto della quale verrà attivato l'allarme.\",\n          \"no\": \"Terskel under hvilken alarmen vil bli aktivert.\",\n          \"sv\": \"Tröskel under vilket larmet aktiveras.\",\n          \"pl\": \"Próg, poniżej którego zostanie uruchomiony alarm.\",\n          \"ru\": \"Порог, ниже которого будет активирована тревога.\",\n          \"ko\": \"알람이 활성화되는 임계값입니다.\"\n        },\n        \"value\": 20,\n        \"attr\": {\n          \"min\": 1,\n          \"max\": 90\n        }\n      },\n      {\n        \"id\": \"main_brush_time_remaining\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Main brush remaining (%)\",\n          \"nl\": \"Hoofdborstel over (%)\",\n          \"da\": \"Hovedbørste resterende (%)\",\n          \"de\": \"Hauptbürste verbleibend (%)\",\n          \"es\": \"Cepillo principal restante (%)\",\n          \"fr\": \"Brosse principale restante (%)\",\n          \"it\": \"Spazzola principale rimanente (%)\",\n          \"no\": \"Hovedbørste gjenværende (%)\",\n          \"sv\": \"Huvudborste kvar (%)\",\n          \"pl\": \"Pozostało głównej szczotki (%)\",\n          \"ru\": \"Осталось основной щетки (%)\",\n          \"ko\": \"메인 브러쉬 남음 (%)\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"side_brush_time_remaining\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Side brush remaining\",\n          \"nl\": \"Zijborstel over\",\n          \"da\": \"Sidebørste resterende\",\n          \"de\": \"Seitenbürste verbleibend\",\n          \"es\": \"Cepillo lateral restante\",\n          \"fr\": \"Brosse latérale restante\",\n          \"it\": \"Spazzola laterale rimanente\",\n          \"no\": \"Sidebørste gjenværende\",\n          \"sv\": \"Sidoborste kvar\",\n          \"pl\": \"Pozostało bocznej szczotki\",\n          \"ru\": \"Осталось боковой щетки\",\n          \"ko\": \"사이드 브러쉬 남음\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"filter_time_remaining\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter remaining\",\n          \"nl\": \"Filter over\",\n          \"da\": \"Filter tilbage\",\n          \"de\": \"Filter verbleibend\",\n          \"es\": \"Filtro restante\",\n          \"fr\": \"Filtre restant\",\n          \"it\": \"Filtro rimanente\",\n          \"no\": \"Filter igjen\",\n          \"sv\": \"Filter kvar\",\n          \"pl\": \"Pozostało filtra\",\n          \"ru\": \"Осталось фильтра\",\n          \"ko\": \"필터 남음\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"total_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total work time\",\n          \"nl\": \"Totale gebruikstijd\",\n          \"da\": \"Samlet arbejdstid\",\n          \"de\": \"Gesamtarbeitszeit\",\n          \"es\": \"Tiempo total de trabajo\",\n          \"fr\": \"Temps de travail total\",\n          \"it\": \"Tempo totale di lavoro\",\n          \"no\": \"Total arbeidstid\",\n          \"sv\": \"Total arbetstid\",\n          \"pl\": \"Całkowity czas pracy\",\n          \"ru\": \"Общее время работы\",\n          \"ko\": \"총 작업 시간\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"sensor_dirty_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Sensors dirty remaining\",\n          \"nl\": \"Sensor vuil over\",\n          \"da\": \"Sensorer beskidte resterende\",\n          \"de\": \"Sensoren verschmutzt verbleibend\",\n          \"es\": \"Sensores sucios restantes\",\n          \"fr\": \"Capteurs sales restants\",\n          \"it\": \"Sensori sporchi rimanenti\",\n          \"no\": \"Sensorer skitne gjenværende\",\n          \"sv\": \"Smutsiga sensorer kvar\",\n          \"pl\": \"Pozostało zabrudzonych czujników\",\n          \"ru\": \"Осталось грязных датчиков\",\n          \"ko\": \"오염 센서 남음\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"total_cleared_area\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total cleaned area\",\n          \"nl\": \"Totaal geschoont\",\n          \"da\": \"Samlet rengjort område\",\n          \"de\": \"Gesamt gereinigte Fläche\",\n          \"es\": \"Área total limpiada\",\n          \"fr\": \"Zone totale nettoyée\",\n          \"it\": \"Area totale pulita\",\n          \"no\": \"Total rengjort område\",\n          \"sv\": \"Totalt rensat område\",\n          \"pl\": \"Całkowity wyczyszczony obszar\",\n          \"ru\": \"Общая очищенная площадь\",\n          \"ko\": \"청소된 총 면적\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"total_clean_count\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total clean count\",\n          \"nl\": \"Totaal aantal opschoningen\",\n          \"da\": \"Samlet renseoptælling\",\n          \"de\": \"Gesamte Reinigungsanzahl\",\n          \"es\": \"Conteo total de limpiezas\",\n          \"fr\": \"Compte total de nettoyage\",\n          \"it\": \"Conteggio totale delle pulizie\",\n          \"no\": \"Total rensetelling\",\n          \"sv\": \"Total rengöringsantal\",\n          \"pl\": \"Całkowita liczba czyszczeń\",\n          \"ru\": \"Общее количество очисток\",\n          \"ko\": \"총 청소 횟수\"\n        },\n        \"value\": \"0\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device data\",\n      \"nl\": \"Apparaat data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"장치 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"error\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Error\",\n          \"nl\": \"Error\",\n          \"da\": \"Fejl\",\n          \"de\": \"Fehler\",\n          \"es\": \"Error\",\n          \"fr\": \"Erreur\",\n          \"it\": \"Errore\",\n          \"no\": \"Feil\",\n          \"sv\": \"Fel\",\n          \"pl\": \"Błąd\",\n          \"ru\": \"Ошибка\",\n          \"ko\": \"오류\"\n        },\n        \"value\": \"No error\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuraciones del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/vacuum_roidmi_vacuum_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/vacuum_roidmi_vacuum_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_roidmi_vacuum_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_viomi_vacuum_v7/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass ViomiV7Device extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // FLOW TRIGGER CARDS\n      this.homey.flow.getDeviceTriggerCard('alertVacuum');\n      this.homey.flow.getDeviceTriggerCard('statusVacuum');\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener('onoff', async ( value ) => {\n        try {\n          if (this.miio) {\n            if (value) {\n              return await this.miio.call(\"set_mode_withroom\", [0, 1, 0], { refresh: [\"state\"], refreshDelay: 1000});\n            } else {\n              return await this.miio.call(\"set_charge\", [1], { refresh: [\"state\"], refreshDelay: 1000 });\n            }\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('dim', async ( value ) => {\n        try {\n          if (this.miio) {\n            if (value === 0) {\n              return await this.miio.call(\"set_mode\", [0], { refresh: [\"state\"], refreshDelay: 1000 });\n            } else {\n              return await this.miio.call(\"set_suction\", [value], { refresh: [\"fanSpeed\"] });\n            }\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('dim.water', async ( value ) => {\n        try {\n          if (this.miio) {\n            const speeds = { 0: 11, 1: 12, 2: 13 };\n            return await this.miio.call(\"set_suction\", [speeds[value]], { refresh: [\"waterBoxMode\"] });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('vacuum_viomi_mop_mode', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"set_mop\", [Number(value)], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n      this.registerCapabilityListener('button.consumable', async ( value ) => {\n        try {\n          if (this.miio) {\n            return await this.miio.call(\"reset_consumable\", [\"main_brush_work_time\", \"side_brush_work_time\", \"filter_work_time\"], { retries: 1 });\n          } else {\n            this.setUnavailable(this.homey.__('unreachable')).catch(error => { this.error(error) });\n            this.createDevice();\n            return Promise.reject('Device unreachable, please try again ...');\n          }\n        } catch (error) {\n          this.error(error);\n          return Promise.reject(error);\n        }\n      });\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async retrieveDeviceData() {\n    try {\n\n      const result = await this.miio.call(\"get_prop\", [\"run_state\", \"suction_grade\", \"battary_life\", \"is_mop\", \"water_grade\", \"mop_route\", \"main_brush_life\", \"side_brush_life\", \"hypa_life\"], { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      if (result[0] == 3) {\n        await this.updateCapabilityValue(\"onoff\", true);\n      } else if (result[0] == 6 || result[0] == 7) {\n        await this.updateCapabilityValue(\"onoff\", true);\n      } else if (result[0] == 5) {\n        await this.updateCapabilityValue(\"onoff\", false);\n      } else if (result[0] == 3) {\n        await this.updateCapabilityValue(\"onoff\", false);\n      } else if (result[0] == 2) {\n        await this.updateCapabilityValue(\"onoff\", true);\n      }\n\n      switch (parseInt(result[1])) {\n        case 0:\n          await this.updateCapabilityValue(\"dim\", 0.25);\n          break;\n        case 1:\n          await this.updateCapabilityValue(\"dim\", 0.5);\n          break;\n        case 2:\n          await this.updateCapabilityValue(\"dim\", 0.75);\n          break;\n        case 3:\n          await this.updateCapabilityValue(\"dim\", 1);\n          break;\n      }\n\n      await this.updateCapabilityValue(\"measure_battery\", parseInt(result[2]));\n      await this.updateCapabilityValue(\"alarm_battery\", parseInt(result[2]) <= 20 ? true : false);\n      await this.updateCapabilityValue(\"vacuum_viomi_mop_mode\", parseInt(result[3]));\n\n      switch (parseInt(result[4])) {\n        case 0:\n          await this.updateCapabilityValue(\"dim.water\", 0.33);\n          break;\n        case 1:\n          await this.updateCapabilityValue(\"dim.water\", 0.66);\n          break;\n        case 2:\n          await this.updateCapabilityValue(\"dim.water\", 1);\n          break;\n      }\n\n      const mainBrushLifeTime = 1080000;\n      const mainBrushCurrentLife = parseInt(result[6]);\n      const mainBrushLifeTimePercent = (mainBrushCurrentLife / mainBrushLifeTime) * 100;\n      const sideBrushLifeTime = 720000;\n      const sideBrushCurrentLife = parseInt(result[7]);\n      const sideBrushLifeTimePercent = (sideBrushCurrentLife / sideBrushLifeTime) * 100;\n      const filterLifeTime = 540000;\n      const filterCurrentLife = parseInt(result[8]);\n      const filterLifeTimePercent = (filterCurrentLife / filterLifeTime) * 100;\n\n      await this.updateSettingValue(\"main_brush_work_time\", parseInt(mainBrushLifeTimePercent) + \"%\");\n      let main_brush_alarm = 100 - parseInt(mainBrushLifeTimePercent) <= this.getSetting(\"alarm_threshold\") ? true : false;\n      if (main_brush_alarm) {\n        await this.homey.flow.getDeviceTriggerCard('alertVacuum').trigger(this, {\"consumable\": \"Main Brush\", \"value\": parseInt(mainBrushLifeTimePercent) + \"%\" }).catch(error => { this.error(error) });\n      }\n\n      await this.updateSettingValue(\"side_brush_work_time\", parseInt(sideBrushLifeTimePercent) + \"%\");\n      let side_brush_alarm = 100 - parseInt(sideBrushLifeTimePercent) <= this.getSetting(\"alarm_threshold\") ? true : false;\n      if (side_brush_alarm) {\n        await this.homey.flow.getDeviceTriggerCard('alertVacuum').trigger(this, {\"consumable\": \"Side Brush\", \"value\": parseInt(sideBrushLifeTimePercent) + \"%\" }).catch(error => { this.error(error) });\n      }\n\n      await this.updateSettingValue(\"filter_work_time\", parseInt(filterLifeTimePercent) + \"%\");\n      let filter_alarm = 100 - parseInt(filterLifeTimePercent) <= this.getSetting(\"alarm_threshold\") ? true : false;\n      if (filter_alarm) {\n        await this.homey.flow.getDeviceTriggerCard('alertVacuum').trigger(this, {\"consumable\": \"Filter\", \"value\": parseInt(sideBrushLifeTimePercent) + \"%\" }).catch(error => { this.error(error) });\n      }\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch(error => { this.error(error) });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = ViomiV7Device;\n"
  },
  {
    "path": "drivers/vacuum_viomi_vacuum_v7/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n    \"nl\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n    \"da\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n    \"de\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n    \"es\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n    \"fr\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n    \"it\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n    \"no\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n    \"sv\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n    \"pl\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n    \"ru\": \"Mi Robot Vacuum-Mop P (WiFi)\",\n    \"ko\": \"Mi Robot Vacuum-Mop P (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/vacuum_viomi_vacuum_v7/assets/images/large.jpg\",\n    \"small\": \"drivers/vacuum_viomi_vacuum_v7/assets/images/small.jpg\"\n  },\n  \"class\": \"vacuumcleaner\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"dim\",\n    \"dim.water\",\n    \"vacuum_viomi_mop_mode\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"capabilitiesOptions\": {\n    \"dim\": {\n      \"title\": {\n        \"en\": \"Speed\",\n        \"nl\": \"Snelheid\",\n        \"da\": \"Hastighed\",\n        \"de\": \"Geschwindigkeit\",\n        \"es\": \"Velocidad\",\n        \"fr\": \"Vitesse\",\n        \"it\": \"Velocità\",\n        \"no\": \"Hastighet\",\n        \"sv\": \"Hastighet\",\n        \"pl\": \"Prędkość\",\n        \"ru\": \"Скорость\",\n        \"ko\": \"속도\"\n      },\n      \"min\": 0,\n      \"max\": 3,\n      \"step\": 1\n    },\n    \"dim.water\": {\n      \"title\": {\n        \"en\": \"Mop mode\",\n        \"nl\": \"Dweil modus\",\n        \"da\": \"Moppe tilstand\",\n        \"de\": \"Wischmodus\",\n        \"es\": \"Modo de fregona\",\n        \"fr\": \"Mode serpillière\",\n        \"it\": \"Modalità mocio\",\n        \"no\": \"Moppemodus\",\n        \"sv\": \"Mopp-läge\",\n        \"pl\": \"Tryb mopa\",\n        \"ru\": \"Режим швабры\",\n        \"ko\": \"물걸레 모드\"\n      },\n      \"min\": 0,\n      \"max\": 3,\n      \"step\": 1\n    },\n    \"button.consumable\": {\n      \"maintenanceAction\": true,\n      \"title\": {\n        \"en\": \"Reset consumables\",\n        \"nl\": \"Reset verbruiksartikelen\",\n        \"da\": \"Nulstil forbrugsvarer\",\n        \"de\": \"Verbrauchsmaterialien zurücksetzen\",\n        \"es\": \"Restablecer consumibles\",\n        \"fr\": \"Réinitialiser les consommables\",\n        \"it\": \"Reimposta i consumabili\",\n        \"no\": \"Tilbakestill forbruksvarer\",\n        \"sv\": \"Återställ förbrukningsvaror\",\n        \"pl\": \"Resetuj materiały eksploatacyjne\",\n        \"ru\": \"Сбросить расходные материалы\",\n        \"ko\": \"소모품 초기화\"\n      },\n      \"desc\": {\n        \"en\": \"Reset the usage of vacuum cleaner consumables.\",\n        \"nl\": \"Reset het gebruik van de verbruiksartikelen\",\n        \"da\": \"Nulstil brugen af støvsugerens forbrugsvarer.\",\n        \"de\": \"Verwendungsdauer der Staubsauger-Verbrauchsmaterialien zurücksetzen.\",\n        \"es\": \"Restablecer el uso de los consumibles de la aspiradora.\",\n        \"fr\": \"Réinitialiser l'utilisation des consommables de l'aspirateur.\",\n        \"it\": \"Reimposta l'uso dei consumabili dell'aspirapolvere.\",\n        \"no\": \"Tilbakestill bruken av støvsugerens forbruksvarer.\",\n        \"sv\": \"Återställ användningen av dammsugarens förbrukningsvaror.\",\n        \"pl\": \"Resetuj użycie materiałów eksploatacyjnych odkurzacza.\",\n        \"ru\": \"Сбросить использование расходных материалов пылесоса.\",\n        \"ko\": \"진공 청소기 소모품 사용량 재설정.\"\n      }\n    }\n  },\n  \"energy\": {\n    \"batteries\": [\n      \"INTERNAL\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/vacuum_viomi_vacuum_v7/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass ViomiV7Driver extends Driver {}\n\nmodule.exports = ViomiV7Driver;"
  },
  {
    "path": "drivers/vacuum_viomi_vacuum_v7/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Vacuum Consumables\",\n      \"nl\": \"Stofzuiger verbruiksartikelen\",\n      \"da\": \"Støvsuger forbrugsstoffer\",\n      \"de\": \"Staubsauger Verbrauchsmaterialien\",\n      \"es\": \"Consumibles de aspiradora\",\n      \"fr\": \"Consommables pour aspirateur\",\n      \"it\": \"Consumi aspirapolvere\",\n      \"no\": \"Støvsuger forbruksvarer\",\n      \"sv\": \"Dammsugare förbrukningsvaror\",\n      \"pl\": \"Materiały eksploatacyjne odkurzacza\",\n      \"ru\": \"Расходные материалы для пылесоса\",\n      \"ko\": \"진공 청소기 소모품\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_threshold\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Alarm threshold\",\n          \"nl\": \"Alarm ondergrens\",\n          \"da\": \"Alarmgrænse\",\n          \"de\": \"Alarmschwelle\",\n          \"es\": \"Umbral de alarma\",\n          \"fr\": \"Seuil d'alarme\",\n          \"it\": \"Soglia d'allarme\",\n          \"no\": \"Alarmterskel\",\n          \"sv\": \"Alarmtröskel\",\n          \"pl\": \"Próg alarmowy\",\n          \"ru\": \"Порог срабатывания сигнала тревоги\",\n          \"ko\": \"알람 임계값\"\n        },\n        \"hint\": {\n          \"en\": \"Threshold below which the alarm will be activated.\",\n          \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n          \"da\": \"Grænse, under hvilken alarmen vil blive aktiveret.\",\n          \"de\": \"Schwelle, unter der der Alarm ausgelöst wird.\",\n          \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n          \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n          \"it\": \"Soglia al di sotto della quale si attiverà l'allarme.\",\n          \"no\": \"Terskel under hvilket alarmen vil bli aktivert.\",\n          \"sv\": \"Tröskel under vilken larmet aktiveras.\",\n          \"pl\": \"Próg, poniżej którego uruchomi się alarm.\",\n          \"ru\": \"Порог, при котором сработает сигнал тревоги.\",\n          \"ko\": \"경보가 활성화되는 임계값입니다.\"\n        },\n        \"value\": 20,\n        \"attr\": {\n          \"min\": 1,\n          \"max\": 90\n        }\n      },\n      {\n        \"id\": \"main_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Main brush remaining (%)\",\n          \"nl\": \"Hoofdborstel over (%)\",\n          \"da\": \"Resterende hovedbørste (%)\",\n          \"de\": \"Verbleibende Hauptbürste (%)\",\n          \"es\": \"Cepillo principal restante (%)\",\n          \"fr\": \"Brosse principale restante (%)\",\n          \"it\": \"Spazzola principale rimanente (%)\",\n          \"no\": \"Gjenværende hovedbørste (%)\",\n          \"sv\": \"Huvudborste kvar (%)\",\n          \"pl\": \"Pozostało głównego pędzla (%)\",\n          \"ru\": \"Оставшаяся основная щетка (%)\",\n          \"ko\": \"남은 메인 브러쉬 (%)\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"side_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Side brush remaining (%)\",\n          \"nl\": \"Zijborstel over (%)\",\n          \"da\": \"Resterende sidebørste (%)\",\n          \"de\": \"Verbleibende Seitenbürste (%)\",\n          \"es\": \"Cepillo lateral restante (%)\",\n          \"fr\": \"Brosse latérale restante (%)\",\n          \"it\": \"Spazzola laterale rimanente (%)\",\n          \"no\": \"Gjenværende sidebørste (%)\",\n          \"sv\": \"Sidoborste kvar (%)\",\n          \"pl\": \"Pozostało bocznego pędzla (%)\",\n          \"ru\": \"Оставшаяся боковая щетка (%)\",\n          \"ko\": \"남은 사이드 브러쉬 (%)\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"filter_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter over (%)\",\n          \"nl\": \"Filter over (%)\",\n          \"da\": \"Filter over (%)\",\n          \"de\": \"Filter übrig (%)\",\n          \"es\": \"Filtro restante (%)\",\n          \"fr\": \"Filtre restant (%)\",\n          \"it\": \"Filtro rimanente (%)\",\n          \"no\": \"Filter over (%)\",\n          \"sv\": \"Filter kvar (%)\",\n          \"pl\": \"Pozostało filtra (%)\",\n          \"ru\": \"Фильтр оставшийся (%)\",\n          \"ko\": \"남은 필터 (%)\"\n        },\n        \"value\": \"0%\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/vacuum_viomi_vacuum_v7/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/vacuum_viomi_vacuum_v7/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_viomi_vacuum_v7/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_max/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/xiaomi.vacuum.d109gl // Xiaomi Robot Vacuum X20 Max\n// https://home.miot-spec.com/spec/xiaomi.vacuum.d102gl // Xiaomi Robot Vacuum X20 Pro  (original mapping kept)\n// https://home.miot-spec.com/spec/xiaomi.vacuum.d101 // Xiaomi Robot Vacuum H40\n// https://home.miot-spec.com/spec/xiaomi.vacuum.c102gl // Xiaomi Robot Vacuum X20 / X20+\n// https://home.miot-spec.com/spec/xiaomi.vacuum.b108gl // Xiaomi Robot Vacuum S20+\n\n/** ------------------------------------------------------------------\n *  Shared constants (hoisted)\n *  ------------------------------------------------------------------ */\nconst ERROR_CODES = {\n    0: 'OK',\n    1: 'Left-wheel-error',\n    2: 'Right-wheel-error',\n    3: 'Cliff-error',\n    4: 'Low-battery-error',\n    5: 'Bump-error',\n    6: 'Main-brush-error',\n    7: 'Side-brush-error',\n    8: 'Fan-motor-error',\n    9: 'Dustbin-error',\n    10: 'Charging-error',\n    11: 'No-water-error',\n    12: 'Pick-up-error',\n    100008: 'OK / Busy',\n    210030: 'Water tank empty',\n    210004: 'Stuck-error',\n    210002: 'Wheel-error',\n    210013: 'Dustbin-error',\n    210050: 'No-water-error',\n    320002: 'Cliff-error'\n};\n\nconst STATUS_MAPPING = {\n    cleaning: [4, 7, 8, 10, 12, 16, 17, 19],\n    spot_cleaning: [],\n    docked: [9, 11, 14, 68], // 68 observed on your X20+ as \"docked\"\n    charging: [2, 6, 13, 21],\n    stopped: [1, 3, 5, 18, 20],\n    stopped_error: [15]\n};\n\n// c102gl status values (observed on MIoT driver variant)\nconst STATUS_MAPPING_C102 = {\n    cleaning: [1, 5, 7, 8, 9, 10, 12],\n    spot_cleaning: [],\n    docked: [0, 11, 13, 14, 19],\n    charging: [6],\n    stopped: [2, 3, 21, 22, 23],\n    stopped_error: [4]\n};\n\nconst STATUS_MAPPING_B108GL = {\n    cleaning: [4, 7, 9],\n    spot_cleaning: [],\n    docked: [8],\n    charging: [2, 3, 6],\n    stopped: [1, 5, 10],\n    stopped_error: []\n};\n\nconst STATUS_MAPPING_D101 = {\n    cleaning: [4, 7, 8, 10, 12, 16, 17, 19, 22],\n    spot_cleaning: [],\n    docked: [9, 11, 14, 23],\n    charging: [2, 3, 6, 13, 21, 24],\n    stopped: [1, 5, 18, 20],\n    stopped_error: [15]\n};\n\n/** Model → property-set */\nconst mapping = {\n    'xiaomi.vacuum.d109gl': 'properties_d109gl',\n    'xiaomi.vacuum.d102gl': 'properties_d109gl', // unchanged — you said it’s flawless\n    'xiaomi.vacuum.d101': 'properties_d101',\n    'xiaomi.vacuum.d101gl': 'properties_d101',\n    'xiaomi.vacuum.ov51gl': 'properties_d101',\n    'xiaomi.vacuum.c102gl': 'properties_c102gl', // X20 / X20+ specific minimal + room action change\n    'xiaomi.vacuum.b108gl': 'properties_b108gl'\n};\n\n/** Property sets */\nconst properties = {\n    /* Baseline (d109gl / d102gl) — unchanged except for our code hardening */\n    properties_d109gl: {\n        get_rooms: [{ did: 'rooms', siid: 2, piid: 16 }],\n        get_properties: [\n            { did: 'device_status', siid: 2, piid: 2 },\n            { did: 'device_fault', siid: 2, piid: 3 },\n            { did: 'mode', siid: 2, piid: 4 },\n            { did: 'battery', siid: 3, piid: 1 },\n            { did: 'main_brush_life_level', siid: 12, piid: 1 },\n            { did: 'side_brush_life_level', siid: 13, piid: 1 },\n            { did: 'filter_life_level', siid: 14, piid: 1 },\n            { did: 'total_clean_time', siid: 2, piid: 7 },\n            { did: 'total_clean_count', siid: 2, piid: 8 },\n            { did: 'total_clean_area', siid: 2, piid: 6 },\n            { did: 'cleaning_mode', siid: 2, piid: 9 },\n            { did: 'water_level', siid: 2, piid: 10 },\n            { did: 'path_mode', siid: 2, piid: 74 },\n            { did: 'detergent_left_level', siid: 18, piid: 1 },\n            { did: 'detergent_self_delivery', siid: 18, piid: 2 },\n            { did: 'detergent_self_delivery_lvl', siid: 18, piid: 3 },\n            { did: 'dust_bag_life_level', siid: 19, piid: 1 },\n            { did: 'dust_bag_left_time', siid: 19, piid: 2 },\n            { did: 'detergent_depletion_reminder', siid: 2, piid: 71 },\n            { did: 'carpet_avoidance', siid: 2, piid: 73 }\n        ],\n        set_properties: {\n            start_clean: { siid: 2, aiid: 1, did: 'call-2-1', in: [] },\n            stop_clean: { siid: 2, aiid: 2, did: 'call-2-2', in: [] },\n            find: { siid: 6, aiid: 1, did: 'call-6-1', in: [] },\n            home: { siid: 3, aiid: 1, did: 'call-3-1', in: [] },\n            mopmode: { siid: 2, piid: 4 },\n            cleaning_mode: { siid: 2, piid: 9 },\n            water_level: { siid: 2, piid: 10 },\n            path_mode: { siid: 2, piid: 74 },\n            room_clean_action: { siid: 2, aiid: 16, piid: 15 }, // baseline\n            carpet_avoidance: { siid: 2, piid: 73 }\n        },\n        supports: {\n            rooms: true,\n            mopmode: true,\n            cleaning_mode: true,\n            water_level: true,\n            path_mode: true,\n            carpet_avoidance: true,\n            consumables: true,\n            detergent: true\n        },\n        scale: {\n            area_divisor: 100,\n            time_divisor: 3600\n        },\n        error_codes: ERROR_CODES,\n        status_mapping: STATUS_MAPPING\n    },\n\n    /* H40 (d101) */\n    properties_d101: {\n        get_rooms: [{ did: 'rooms', siid: 2, piid: 16 }],\n        get_properties: [\n            { did: 'device_status', siid: 2, piid: 2 },\n            { did: 'device_fault', siid: 2, piid: 3 },\n            { did: 'mode', siid: 2, piid: 4 },\n            { did: 'battery', siid: 3, piid: 1 },\n            { did: 'main_brush_life_level', siid: 12, piid: 1 },\n            { did: 'side_brush_life_level', siid: 13, piid: 1 },\n            { did: 'filter_life_level', siid: 14, piid: 1 },\n            { did: 'total_clean_time', siid: 2, piid: 7 },\n            { did: 'total_clean_count', siid: 2, piid: 8 },\n            { did: 'total_clean_area', siid: 2, piid: 6 },\n            { did: 'cleaning_mode', siid: 2, piid: 9 },\n            { did: 'water_level', siid: 2, piid: 10 },\n            { did: 'path_mode', siid: 2, piid: 74 },\n            { did: 'carpet_avoidance', siid: 2, piid: 73 }\n        ],\n        set_properties: {\n            start_clean: { siid: 2, aiid: 1, did: 'call-2-1', in: [] },\n            stop_clean: { siid: 2, aiid: 2, did: 'call-2-2', in: [] },\n            find: { siid: 6, aiid: 1, did: 'call-6-1', in: [] },\n            home: { siid: 3, aiid: 1, did: 'call-3-1', in: [] },\n            mopmode: { siid: 2, piid: 4 },\n            cleaning_mode: { siid: 2, piid: 9 },\n            water_level: { siid: 2, piid: 10 },\n            path_mode: { siid: 2, piid: 74 },\n            room_clean_action: { siid: 2, aiid: 16, piid: 15 },\n            carpet_avoidance: { siid: 2, piid: 73 }\n        },\n        supports: {\n            rooms: true,\n            mopmode: true,\n            cleaning_mode: true,\n            water_level: true,\n            path_mode: true,\n            carpet_avoidance: true,\n            consumables: true,\n            detergent: false\n        },\n        scale: {\n            area_divisor: 100,\n            time_divisor: 3600\n        },\n        error_codes: ERROR_CODES,\n        status_mapping: STATUS_MAPPING_D101\n    },\n\n    /* X20 / X20+ (c102gl)\n     * Uses c102-specific MIOT mappings for room actions and exposes extended controls.\n  */\n    properties_c102gl: {\n        get_rooms: [{ did: 'rooms', siid: 2, piid: 16 }],\n        get_properties: [\n            { did: 'device_status', siid: 2, piid: 1 },\n            { did: 'device_fault', siid: 2, piid: 2 },\n            { did: 'battery', siid: 3, piid: 1 },\n            { did: 'mode', siid: 2, piid: 4 },\n            { did: 'cleaning_mode', siid: 7, piid: 5 },\n            { did: 'water_level', siid: 7, piid: 6 },\n            { did: 'path_mode', siid: 7, piid: 38 },\n            { did: 'carpet_avoidance', siid: 7, piid: 44 },\n            // totals (observed working on c102gl)\n            { did: 'total_clean_time', siid: 12, piid: 2 },\n            { did: 'total_clean_count', siid: 12, piid: 3 },\n            { did: 'total_clean_area', siid: 12, piid: 4 },\n            // consumables (percent values)\n            { did: 'main_brush_life_level', siid: 9, piid: 2 },\n            { did: 'side_brush_life_level', siid: 10, piid: 2 },\n            { did: 'filter_life_level', siid: 11, piid: 1 }\n        ],\n        set_properties: {\n            start_clean: { siid: 2, aiid: 1, did: 'call-2-1', in: [] },\n            stop_clean: { siid: 2, aiid: 2, did: 'call-2-2', in: [] },\n            find: { siid: 6, aiid: 1, did: 'call-6-1', in: [] },\n            home: { siid: 3, aiid: 1, did: 'call-3-1', in: [] },\n            mopmode: { siid: 2, piid: 4 },\n            cleaning_mode: { siid: 7, piid: 5 },\n            water_level: { siid: 7, piid: 6 },\n            path_mode: { siid: 7, piid: 38 },\n            carpet_avoidance: { siid: 7, piid: 44 },\n            carpet_avoidance_toggle: { siid: 7, piid: 47 },\n            // X20+/X20 specific room action (string payload)\n            room_clean_action: { siid: 2, aiid: 3, piid: 4 }\n        },\n        supports: {\n            rooms: true,\n            mopmode: true,\n            cleaning_mode: true,\n            water_level: true,\n            path_mode: true,\n            carpet_avoidance: true,\n            consumables: true,\n            detergent: false\n        },\n        scale: {\n            area_divisor: 1,\n            time_divisor: 60\n        },\n        error_codes: ERROR_CODES,\n        status_mapping: STATUS_MAPPING_C102\n    },\n\n    /* S20+ (b108gl) */\n    properties_b108gl: {\n        get_rooms: [{ did: 'rooms', siid: 2, piid: 13 }],\n        get_properties: [\n            { did: 'device_status', siid: 2, piid: 1 },\n            { did: 'device_fault', siid: 2, piid: 2 },\n            { did: 'battery', siid: 3, piid: 1 },\n            { did: 'mode', siid: 2, piid: 3 },\n            { did: 'cleaning_mode', siid: 2, piid: 8 },\n            { did: 'water_level', siid: 2, piid: 9 },\n            { did: 'carpet_avoidance', siid: 2, piid: 20 },\n            { did: 'total_clean_time', siid: 2, piid: 6 },\n            { did: 'total_clean_area', siid: 2, piid: 5 }\n        ],\n        set_properties: {\n            start_clean: { siid: 2, aiid: 1, did: 'call-2-1', in: [] },\n            stop_clean: { siid: 2, aiid: 2, did: 'call-2-2', in: [] },\n            home: { siid: 3, aiid: 1, did: 'call-3-1', in: [] },\n            mopmode: { siid: 2, piid: 3 },\n            cleaning_mode: { siid: 2, piid: 8 },\n            water_level: { siid: 2, piid: 9 },\n            room_clean_action: { siid: 2, aiid: 13, piid: 13 },\n            carpet_avoidance: { siid: 2, piid: 20 }\n        },\n        supports: {\n            rooms: true,\n            mopmode: true,\n            cleaning_mode: true,\n            water_level: true,\n            path_mode: false,\n            carpet_avoidance: true,\n            consumables: false,\n            detergent: false\n        },\n        scale: {\n            area_divisor: 100,\n            time_divisor: 3600\n        },\n        error_codes: ERROR_CODES,\n        status_mapping: STATUS_MAPPING_B108GL\n    }\n};\n\nclass XiaomiVacuumMiotDeviceMax extends Device {\n    getMiotProp(result, propName) {\n        const propDef = this.deviceProperties.get_properties.find((p) => p.did === propName);\n        if (!propDef) {\n            this.log(`[DEBUG] Property definition for \"${propName}\" not found.`);\n            return undefined;\n        }\n        const found = result.find((obj) => obj.siid === propDef.siid && obj.piid === propDef.piid);\n        if (!found) {\n            this.log(`[DEBUG] MIOT property \"${propName}\" (siid: ${propDef.siid}, piid: ${propDef.piid}) not in result.`);\n        }\n        return found;\n    }\n\n    _getDeviceModel() {\n        if (this.miio) {\n            return this.miio.miioModel || (this.miio.management && this.miio.management.model) || null;\n        }\n        return null;\n    }\n\n    _applyModelProperties(model) {\n        const mappedKey = mapping[model];\n        this.deviceProperties = properties[mappedKey] || properties.properties_d109gl;\n        this._model = model;\n        if (this._model === 'xiaomi.vacuum.d102gl') {\n            this.deviceProperties = {\n                ...this.deviceProperties,\n                get_properties: [...this.deviceProperties.get_properties]\n            };\n            const extraProps = [\n                { did: 'water_check_status', siid: 2, piid: 54 },\n                { did: 'fault_ids', siid: 2, piid: 66 }\n            ];\n            for (const prop of extraProps) {\n                if (!this.deviceProperties.get_properties.some((existing) => existing.did === prop.did)) {\n                    this.deviceProperties.get_properties.push(prop);\n                }\n            }\n        }\n        this._areaDivisor = (this.deviceProperties.scale && this.deviceProperties.scale.area_divisor) || 100;\n        this._timeDivisor = (this.deviceProperties.scale && this.deviceProperties.scale.time_divisor) || 3600;\n    }\n\n    _syncModelFromDevice() {\n        const actualModel = this._getDeviceModel();\n        if (!actualModel) return true;\n\n        if (this._model !== actualModel) {\n            if (!this._modelMismatchLogged) {\n                this.log(`[MODEL] Detected model change: ${this._model || 'unknown'} -> ${actualModel}`);\n                this._modelMismatchLogged = true;\n            }\n            this._model = actualModel;\n            try {\n                this.setStoreValue('model', actualModel);\n            } catch (_) {}\n        }\n\n        const mappedKey = mapping[this._model];\n        if (!mappedKey) {\n            if (this._unsupportedModel !== this._model) {\n                this._unsupportedModel = this._model;\n                this.log(`[MODEL] Unsupported model for vacuum_xiaomi_vacuum_max: ${this._model}`);\n            }\n            if (this.getAvailable()) {\n                this.setUnavailable(`Unsupported model for this driver: ${this._model}`).catch(() => {});\n            }\n            return false;\n        }\n\n        if (this._unsupportedModel) this._unsupportedModel = null;\n\n        this._applyModelProperties(this._model);\n\n        return true;\n    }\n\n    async onInit() {\n        try {\n            if (!this.util) this.util = new Util({ homey: this.homey });\n\n            // GENERIC DEVICE INIT ACTIONS\n            this.bootSequence();\n\n            // remember last state\n            this.lastVacState = 'unknown';\n            this._prevAreaRaw = 0;\n            this._prevTimeRaw = 0;\n            this._sessionStartAreaRaw = 0;\n            this._sessionStartTimeRaw = 0;\n            this._isSessionActive = false;\n\n            const model = this.getStoreValue('model');\n            this._applyModelProperties(model);\n            this._carpetModeState = this.getStoreValue('carpetModeState') || '0';\n            if (!this.getStoreValue('carpetModeState')) {\n                try {\n                    await this.setStoreValue('carpetModeState', this._carpetModeState);\n                } catch (_) {}\n            }\n\n            // Only add optional caps if model actually supports them\n            if (this.deviceProperties.supports.path_mode && !this.hasCapability('vacuum_xiaomi_path_mode_max')) {\n                await this.addCapability('vacuum_xiaomi_path_mode_max');\n            }\n            if (!this.deviceProperties.supports.path_mode && this.hasCapability('vacuum_xiaomi_path_mode_max')) {\n                await this.removeCapability('vacuum_xiaomi_path_mode_max');\n            }\n            if (this.deviceProperties.supports.carpet_avoidance && !this.hasCapability('vacuum_xiaomi_carpet_mode_max')) {\n                await this.addCapability('vacuum_xiaomi_carpet_mode_max');\n            }\n            if (!this.hasCapability('alarm_water_shortage')) {\n                await this.addCapability('alarm_water_shortage');\n            }\n\n            if (this.deviceProperties.supports.carpet_avoidance) {\n                await this.updateCapabilityValue('vacuum_xiaomi_carpet_mode_max', this._carpetModeState);\n            }\n\n            // RESET consumable alarms (only for models that support them)\n            if (this.deviceProperties.supports.consumables) {\n                this.updateCapabilityValue('alarm_main_brush_work_time', false);\n                this.updateCapabilityValue('alarm_side_brush_work_time', false);\n                this.updateCapabilityValue('alarm_filter_work_time', false);\n            }\n\n            // Tokens\n            this.main_brush_lifetime_token = await this.getOrCreateToken('main_brush_lifetime' + this.getData().id, `Main Brush Lifetime ${this.getName()} (%)`);\n            this.side_brush_lifetime_token = await this.getOrCreateToken('side_brush_lifetime' + this.getData().id, `Side Brush Lifetime ${this.getName()} (%)`);\n            this.filter_lifetime_token = await this.getOrCreateToken('filter_lifetime' + this.getData().id, `Filter Lifetime ${this.getName()} (%)`);\n            this.sensor_dirty_lifetime_token = await this.getOrCreateToken('sensor_dirty_lifetime' + this.getData().id, `Sensor Dirty Lifetime ${this.getName()} (%)`);\n            this.total_work_time_token = await this.getOrCreateToken('total_work_time' + this.getData().id, `Total Work Time ${this.getName()} (h)`);\n            this.total_cleared_area_token = await this.getOrCreateToken('total_cleared_area' + this.getData().id, `Total Cleaned Area ${this.getName()} (m²)`);\n            this.total_clean_count_token = await this.getOrCreateToken('total_clean_count' + this.getData().id, `Total Clean Count ${this.getName()}`);\n\n            // FLOW CARDS (optional; if not present, triggers are try/catch’d below)\n            this.homey.flow.getDeviceTriggerCard('alertVacuum');\n            this.homey.flow.getDeviceTriggerCard('statusVacuum');\n\n            // Advanced room cleaning (works for all, just skips unsupported set_properties)\n            this.homey.flow.getActionCard('advanced_room_cleaning').registerRunListener(async (args) => {\n                const rawRooms = args.device.getSetting('rooms');\n                let list_room = [];\n                try {\n                    if (Array.isArray(rawRooms)) {\n                        list_room = rawRooms;\n                    } else if (typeof rawRooms === 'string') {\n                        try {\n                            list_room = JSON.parse(rawRooms);\n                        } catch (_) {\n                            try {\n                                list_room = JSON.parse(rawRooms.replace(/\\\\\"/g, '\"'));\n                            } catch (_) {\n                                if (rawRooms.startsWith('\"') && rawRooms.endsWith('\"')) {\n                                    list_room = JSON.parse(JSON.parse(rawRooms));\n                                }\n                            }\n                        }\n                    }\n                } catch (e) {\n                    this.error('Rooms list in settings is invalid/missing.', e);\n                    return Promise.reject('Room list is not available. Please sync device first.');\n                }\n                if (!Array.isArray(list_room)) list_room = [];\n\n                let selected_ids;\n                if (args.room === 'all') {\n                    selected_ids = list_room.map((el) => el.id);\n                } else {\n                    selected_ids = [];\n                    for (const rawToken of String(args.room || '').split(',')) {\n                        const token = rawToken.trim();\n                        if (!token) continue;\n                        if (/^\\d+$/.test(token)) {\n                            selected_ids.push(Number(token));\n                            continue;\n                        }\n                        const name = token.toLowerCase();\n                        const match = list_room.find((el) => (el.name || '').toLowerCase() === name);\n                        if (match) selected_ids.push(match.id);\n                    }\n                }\n\n                if (!selected_ids.length) {\n                    return Promise.reject(`No valid room selected. Requested: \"${args.room}\". Available: ${list_room.map((r) => r.name).join(', ')}.`);\n                }\n\n                let room_list = selected_ids.join(',');\n                if (selected_ids.length === 1) room_list += ',' + room_list; // single room workaround\n\n                // Only push properties that the model supports\n                const props = [];\n                const selectedMode = String(args.mode);\n                if (this.deviceProperties.supports.mopmode) {\n                    const mopOutbound = this.mapMopModeOutbound(selectedMode);\n                    if (mopOutbound != null) {\n                        props.push({\n                            siid: this.deviceProperties.set_properties.mopmode.siid,\n                            piid: this.deviceProperties.set_properties.mopmode.piid,\n                            value: mopOutbound\n                        });\n                    }\n                }\n                if (this.deviceProperties.supports.path_mode) {\n                    const pathOutbound = this.mapPathModeOutbound(String(args.accuracy));\n                    if (pathOutbound != null) {\n                        props.push({\n                            siid: this.deviceProperties.set_properties.path_mode.siid,\n                            piid: this.deviceProperties.set_properties.path_mode.piid,\n                            value: pathOutbound\n                        });\n                    }\n                }\n                if (this.deviceProperties.supports.cleaning_mode && (selectedMode === '1' || selectedMode === '3')) {\n                    const sweepOutbound = this.mapCleaningModeOutbound(String(args.mode_sweep));\n                    if (sweepOutbound != null) {\n                        props.push({\n                            siid: this.deviceProperties.set_properties.cleaning_mode.siid,\n                            piid: this.deviceProperties.set_properties.cleaning_mode.piid,\n                            value: sweepOutbound\n                        });\n                    }\n                }\n                if (this.deviceProperties.supports.water_level && (selectedMode === '2' || selectedMode === '3')) {\n                    const mopLevelOutbound = this.mapWaterLevelOutbound(String(args.mode_mop));\n                    if (mopLevelOutbound != null) {\n                        props.push({\n                            siid: this.deviceProperties.set_properties.water_level.siid,\n                            piid: this.deviceProperties.set_properties.water_level.piid,\n                            value: mopLevelOutbound\n                        });\n                    }\n                }\n                if (this.deviceProperties.supports.carpet_avoidance && typeof args.carpet_avoidance !== 'undefined') {\n                    const carpetPayload = this.buildCarpetModeSetPayload(String(args.carpet_avoidance));\n                    if (carpetPayload.length) {\n                        props.push(...carpetPayload);\n                    }\n                }\n\n                const action = {\n                    siid: this.deviceProperties.set_properties.room_clean_action.siid,\n                    aiid: this.deviceProperties.set_properties.room_clean_action.aiid,\n                    in: [\n                        {\n                            siid: this.deviceProperties.set_properties.room_clean_action.siid,\n                            piid: this.deviceProperties.set_properties.room_clean_action.piid,\n                            code: 0,\n                            value: room_list\n                        }\n                    ]\n                };\n\n                this.log('[ADV_ROOM_CLEAN] props:', JSON.stringify(props));\n                this.log('[ADV_ROOM_CLEAN] action:', JSON.stringify(action));\n\n                if (args.device.miio && typeof args.device.miio.call === 'function') {\n                    if (props.length) await args.device.miio.call('set_properties', props, { retries: 1 });\n                    await args.device.miio.call('action', action, { retries: 3 });\n                } else {\n                    this.setUnavailable(this.homey.__('unreachable')).catch((error) => this.error(error));\n                    this.createDevice();\n                    return Promise.reject('Device unreachable, please try again ...');\n                }\n            });\n\n            const registerVacuumAction = (cardId, capabilityId, argKey, supportKey) => {\n                this.homey.flow.getActionCard(cardId).registerRunListener(async (args) => {\n                    try {\n                        const target = args.device;\n                        if (!target || !target.deviceProperties || !target.deviceProperties.supports || !target.deviceProperties.supports[supportKey]) {\n                            return Promise.reject('Feature not supported by this device.');\n                        }\n                        if (!target.hasCapability(capabilityId)) {\n                            return Promise.reject('Capability not available on this device.');\n                        }\n                        return await target.triggerCapabilityListener(capabilityId, args[argKey]);\n                    } catch (error) {\n                        return Promise.reject(error && error.message ? error.message : error);\n                    }\n                });\n            };\n\n            registerVacuumAction('set_sweep_mop_type', 'vacuum_xiaomi_mop_mode_max', 'mode', 'mopmode');\n            registerVacuumAction('set_cleaning_mode', 'vacuum_xiaomi_cleaning_mode_max', 'power', 'cleaning_mode');\n            registerVacuumAction('set_water_level', 'vacuum_xiaomi_water_level_max', 'level', 'water_level');\n            registerVacuumAction('set_path_mode', 'vacuum_xiaomi_path_mode_max', 'mode', 'path_mode');\n            registerVacuumAction('set_carpet_avoidance', 'vacuum_xiaomi_carpet_mode_max', 'mode', 'carpet_avoidance');\n\n            // Capability listeners: register only for supported features\n            if (this.deviceProperties.supports.carpet_avoidance) {\n                this.registerCapabilityListener('vacuum_xiaomi_carpet_mode_max', async (value) => {\n                    try {\n                        const { payload, state } = this.buildCarpetModeSetPayload(String(value));\n                        if (!payload.length) return null;\n                        if (this.miio) {\n                            const result = await this.miio.call('set_properties', payload, { retries: 1 });\n                            this._carpetModeState = state;\n                            try {\n                                await this.setStoreValue('carpetModeState', state);\n                            } catch (_) {}\n                            await this.updateCapabilityValue('vacuum_xiaomi_carpet_mode_max', state);\n                            return result;\n                        }\n                        this.setUnavailable(this.homey.__('unreachable')).catch((err) => this.error(err));\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again …');\n                    } catch (error) {\n                        this.error(error);\n                        return Promise.reject(error);\n                    }\n                });\n            }\n\n            this.registerCapabilityListener('onoff', async (value) => {\n                try {\n                    if (this.miio) {\n                        if (value) return await this.miio.call('action', this.deviceProperties.set_properties.start_clean, { retries: 1 });\n                        return await this.miio.call('action', this.deviceProperties.set_properties.stop_clean, { retries: 1 });\n                    }\n                    this.setUnavailable(this.homey.__('unreachable')).catch((error) => this.error(error));\n                    this.createDevice();\n                    return Promise.reject('Device unreachable, please try again ...');\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('vacuumcleaner_state', async (value) => {\n                try {\n                    if (this.miio) {\n                        switch (value) {\n                            case 'cleaning':\n                            case 'spot_cleaning':\n                                return await this.triggerCapabilityListener('onoff', true);\n                            case 'docked':\n                            case 'charging':\n                                return await this.miio.call('action', this.deviceProperties.set_properties.home, { retries: 1 });\n                            case 'stopped':\n                                return await this.triggerCapabilityListener('onoff', false);\n                        }\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => this.error(error));\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            if (this.deviceProperties.supports.mopmode) {\n                this.registerCapabilityListener('vacuum_xiaomi_mop_mode_max', async (value) => {\n                    try {\n                        const mappedValue = this.mapMopModeOutbound(String(value));\n                        if (mappedValue == null) return null;\n                        if (this.miio) {\n                            return await this.miio.call('set_properties', [{ siid: this.deviceProperties.set_properties.mopmode.siid, piid: this.deviceProperties.set_properties.mopmode.piid, value: mappedValue }], { retries: 1 });\n                        }\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => this.error(error));\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    } catch (error) {\n                        this.error(error);\n                        return Promise.reject(error);\n                    }\n                });\n            }\n\n            if (this.deviceProperties.supports.cleaning_mode) {\n                this.registerCapabilityListener('vacuum_xiaomi_cleaning_mode_max', async (value) => {\n                    try {\n                        const mappedValue = this.mapCleaningModeOutbound(String(value));\n                        if (mappedValue == null) return null;\n                        if (this.miio) {\n                            return await this.miio.call('set_properties', [{ siid: this.deviceProperties.set_properties.cleaning_mode.siid, piid: this.deviceProperties.set_properties.cleaning_mode.piid, value: mappedValue }], { retries: 1 });\n                        }\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => this.error(error));\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    } catch (error) {\n                        this.error(error);\n                        return Promise.reject(error);\n                    }\n                });\n            }\n\n            if (this.deviceProperties.supports.water_level) {\n                this.registerCapabilityListener('vacuum_xiaomi_water_level_max', async (value) => {\n                    try {\n                        const mappedValue = this.mapWaterLevelOutbound(String(value));\n                        if (mappedValue == null) return null;\n                        if (this.miio) {\n                            return await this.miio.call('set_properties', [{ siid: this.deviceProperties.set_properties.water_level.siid, piid: this.deviceProperties.set_properties.water_level.piid, value: mappedValue }], { retries: 1 });\n                        }\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => this.error(error));\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    } catch (error) {\n                        this.error(error);\n                        return Promise.reject(error);\n                    }\n                });\n            }\n\n            if (this.deviceProperties.supports.path_mode) {\n                this.registerCapabilityListener('vacuum_xiaomi_path_mode_max', async (value) => {\n                    try {\n                        const mappedValue = this.mapPathModeOutbound(String(value));\n                        if (mappedValue == null) return null;\n                        if (this.miio) {\n                            return await this.miio.call('set_properties', [{ siid: this.deviceProperties.set_properties.path_mode.siid, piid: this.deviceProperties.set_properties.path_mode.piid, value: mappedValue }], { retries: 1 });\n                        }\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => this.error(error));\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    } catch (error) {\n                        this.error(error);\n                        return Promise.reject(error);\n                    }\n                });\n            }\n\n            // Use safe totals handler for all models (no-op for unsupported fields)\n            this.vacuumTotals = this.customVacuumTotals;\n            this.vacuumConsumables = this.deviceProperties.supports.consumables ? this.customVacuumConsumables : async () => {}; // noop on c102gl\n\n            // One-time SIID/PIID discovery scan for c102gl to aid debugging/model support\n            /*\n            if (model === 'xiaomi.vacuum.c102gl' && !this._siidPiidScanned) {\n                this._siidPiidScanned = true;\n                this.homey.setTimeout(() => {\n                    this._runOneTimeMiotScan().catch((e) => this.error('[MIOT_SCAN] failed', e));\n                }, 25000);\n            }*/\n\n            // Initialize one-time room logging/discovery flags\n            this._roomsLogOnce = false;\n            this._roomsDiscovered = false;\n        } catch (error) {\n            this.error(error);\n        }\n            \n    }\n\n    async retrieveDeviceData() {\n        try {\n            if (!this.miio || typeof this.miio.call !== 'function') {\n                if (this.getAvailable()) {\n                    this.setUnavailable(this.homey.__('device.unreachable')).catch((error) => this.error(error));\n                }\n                this.createDevice();\n                return;\n            }\n            if (!this._syncModelFromDevice()) return;\n            const result = await this.miio.call('get_properties', this.deviceProperties.get_properties, { retries: 1 });\n\n            // Fetch rooms only when needed and only until discovered\n            let result_rooms = null;\n            if (this.deviceProperties.supports.rooms && !this._roomsDiscovered) {\n                const currentRooms = this.getSetting('rooms');\n                try {\n                    const parsedRooms = JSON.parse(currentRooms || '[]');\n                    if (Array.isArray(parsedRooms) && parsedRooms.length > 0) {\n                        this._roomsDiscovered = true;\n                    }\n                } catch (_) {}\n\n                if (!this._roomsDiscovered) {\n                    result_rooms = await this.miio.call('get_properties', this.deviceProperties.get_rooms, { retries: 1 });\n                    if (!result_rooms || !result_rooms.length || !result_rooms[0].value) {\n                        const candidates = [\n                            [{ did: 'rooms', siid: 4, piid: 20 }],\n                            [{ did: 'rooms', siid: 6, piid: 15 }], // user-facing strings sometimes here\n                            [{ did: 'rooms', siid: 7, piid: 3 }]\n                        ];\n                        for (const c of candidates) {\n                            try {\n                                const r = await this.miio.call('get_properties', c, { retries: 1 });\n                                if (r && r[0] && r[0].value) {\n                                    result_rooms = r;\n                                    break;\n                                }\n                            } catch (_) {}\n                        }\n                    }\n                }\n            }\n\n            if (!this.getAvailable()) await this.setAvailable();\n\n            // diff logging\n            const prevProps = this._lastPropertyValues || {};\n            const resultValues = {};\n            for (const def of this.deviceProperties.get_properties) {\n                const found = result.find((obj) => obj.siid === def.siid && obj.piid === def.piid);\n                resultValues[def.did] = found ? found.value : null;\n            }\n            let valueChanged = Object.keys(resultValues).some((k) => prevProps[k] !== resultValues[k]);\n            if (valueChanged) this.log('Raw property data: ' + this.prettyPrintProperties(result, this.deviceProperties.get_properties));\n            this._lastPropertyValues = resultValues;\n\n            const device_status = this.getMiotProp(result, 'device_status');\n            const battery = this.getMiotProp(result, 'battery');\n            const total_clean_time = this.getMiotProp(result, 'total_clean_time');\n            const total_clean_count = this.getMiotProp(result, 'total_clean_count');\n            const total_clean_area = this.getMiotProp(result, 'total_clean_area');\n            const device_fault = this.getMiotProp(result, 'device_fault');\n            const mop_mode = this.getMiotProp(result, 'mode');\n            const cleaning_mode_prop = this.getMiotProp(result, 'cleaning_mode');\n            const water_level_prop = this.getMiotProp(result, 'water_level');\n            const path_mode_prop = this.getMiotProp(result, 'path_mode');\n            const carpet_mode_prop = this.getMiotProp(result, 'carpet_avoidance');\n            const water_check_status = this._model === 'xiaomi.vacuum.d102gl' ? this.getMiotProp(result, 'water_check_status') : null;\n            const fault_ids = this._model === 'xiaomi.vacuum.d102gl' ? this.getMiotProp(result, 'fault_ids') : null;\n\n            const consumables = this.deviceProperties.supports.consumables\n                ? [\n                      {\n                          main_brush_work_time: Math.max(0, Math.min(100, Number((this.getMiotProp(result, 'main_brush_life_level') || {}).value ?? 0))),\n                          side_brush_work_time: Math.max(0, Math.min(100, Number((this.getMiotProp(result, 'side_brush_life_level') || {}).value ?? 0))),\n                          filter_work_time: Math.max(0, Math.min(100, Number((this.getMiotProp(result, 'filter_life_level') || {}).value ?? 0)))\n                      }\n                  ]\n                : [];\n\n            const totalsReport = {\n                clean_time: total_clean_time ? total_clean_time.value : 0,\n                clean_count: total_clean_count ? total_clean_count.value : 0,\n                clean_area: total_clean_area ? total_clean_area.value : 0\n            };\n\n            /* vacuumcleaner_state */\n            let matched = false;\n            let stateKey = null;\n\n            if (device_status) {\n                for (const key in this.deviceProperties.status_mapping) {\n                    if (this.deviceProperties.status_mapping[key].includes(device_status.value)) {\n                        matched = true;\n                        stateKey = key;\n                        if (this.getCapabilityValue('measure_battery') === 100 && (key === 'stopped' || key === 'charging')) {\n                            this.vacuumCleanerState('docked');\n                        } else {\n                            this.vacuumCleanerState(key);\n                        }\n                        break;\n                    }\n                }\n                if (!matched) this.log('Not a valid vacuumcleaner_state (driver level)', device_status.value);\n            } else {\n                this.log('device_status not found, cannot set vacuumcleaner_state!');\n            }\n\n            // session handling\n            if (stateKey === 'cleaning' && !this._isSessionActive) {\n                this._isSessionActive = true;\n                this._prevAreaRaw = total_clean_area ? total_clean_area.value : 0;\n                this._prevTimeRaw = total_clean_time ? total_clean_time.value : 0;\n                this._sessionStartAreaRaw = this._prevAreaRaw;\n                this._sessionStartTimeRaw = this._prevTimeRaw;\n                const startAreaM2 = this._sessionStartAreaRaw / this._areaDivisor;\n                const startTimeHours = this._sessionStartTimeRaw / this._timeDivisor;\n                this.log(`[SESSION] Cleaning started: startArea(m²)=${startAreaM2.toFixed(2)}, startTime(h)=${startTimeHours.toFixed(2)}`);\n            }\n            if (stateKey === 'cleaning' && this._isSessionActive) {\n                const currentAreaRaw = total_clean_area ? total_clean_area.value : 0;\n                const currentTimeRaw = total_clean_time ? total_clean_time.value : 0;\n                const deltaAreaRaw = currentAreaRaw - this._prevAreaRaw;\n                const deltaTimeRaw = currentTimeRaw - this._prevTimeRaw;\n\n                if (deltaAreaRaw > 0 || deltaTimeRaw > 0) {\n                    await this._addLiveDelta(deltaAreaRaw, deltaTimeRaw);\n                    this._prevAreaRaw = currentAreaRaw;\n                    this._prevTimeRaw = currentTimeRaw;\n                }\n            }\n            if (this.lastVacState === 'cleaning' && ['docked', 'charging', 'stopped'].includes(stateKey)) {\n                try {\n                    await this._accumulateJobTotals();\n                    this._isSessionActive = false;\n                    this.log('[SESSION] Cleaning ended. Count incremented.');\n                } catch (e) {\n                    this.error('Session completion handling failed', e);\n                }\n            }\n\n            if (this.deviceProperties.supports.mopmode && mop_mode && mop_mode.value != null && this.hasCapability('vacuum_xiaomi_mop_mode_max')) {\n                const mappedMop = this.mapMopModeInbound(mop_mode.value);\n                if (mappedMop != null) await this.updateCapabilityValue('vacuum_xiaomi_mop_mode_max', mappedMop);\n            }\n\n            if (this.deviceProperties.supports.cleaning_mode && cleaning_mode_prop && cleaning_mode_prop.value != null && this.hasCapability('vacuum_xiaomi_cleaning_mode_max')) {\n                const mappedCleaning = this.mapCleaningModeInbound(cleaning_mode_prop.value);\n                if (mappedCleaning != null) await this.updateCapabilityValue('vacuum_xiaomi_cleaning_mode_max', mappedCleaning);\n            }\n\n            if (this.deviceProperties.supports.water_level && water_level_prop && water_level_prop.value != null && this.hasCapability('vacuum_xiaomi_water_level_max')) {\n                const mappedWater = this.mapWaterLevelInbound(water_level_prop.value);\n                if (mappedWater != null) await this.updateCapabilityValue('vacuum_xiaomi_water_level_max', mappedWater);\n            }\n\n            if (this.deviceProperties.supports.path_mode && path_mode_prop && path_mode_prop.value != null && this.hasCapability('vacuum_xiaomi_path_mode_max')) {\n                const mappedPath = this.mapPathModeInbound(path_mode_prop.value);\n                if (mappedPath != null) await this.updateCapabilityValue('vacuum_xiaomi_path_mode_max', mappedPath);\n            }\n\n            if (this.deviceProperties.supports.carpet_avoidance && this.hasCapability('vacuum_xiaomi_carpet_mode_max')) {\n                const mappedCarpet = this.mapCarpetModeInbound(carpet_mode_prop ? carpet_mode_prop.value : null);\n                if (mappedCarpet != null && mappedCarpet !== this._carpetModeState) {\n                    this._carpetModeState = mappedCarpet;\n                    try {\n                        await this.setStoreValue('carpetModeState', mappedCarpet);\n                    } catch (_) {}\n                    await this.updateCapabilityValue('vacuum_xiaomi_carpet_mode_max', mappedCarpet);\n                } else if (mappedCarpet == null) {\n                    await this.updateCapabilityValue('vacuum_xiaomi_carpet_mode_max', this._carpetModeState);\n                }\n            }\n\n            // Totals\n            try {\n                await this.vacuumTotals(totalsReport);\n            } catch (e) {\n                this.error('[Totals] Skipping due to error:', e && e.message ? e.message : e);\n            }\n\n            // battery\n            if (battery && battery.value != null) {\n                await this.updateCapabilityValue('measure_battery', battery.value);\n                await this.updateCapabilityValue('alarm_battery', battery.value <= 20);\n            }\n\n            // rooms\n            if (result_rooms && result_rooms.length === 1 && result_rooms[0].value) {\n                try {\n                    const rawVal = result_rooms[0].value;\n                    if (!this._roomsLogOnce) this.log('[ROOMS] raw:', typeof rawVal === 'string' ? rawVal : JSON.stringify(rawVal));\n\n                    let parsed = null;\n                    if (typeof rawVal === 'string') {\n                        try {\n                            parsed = JSON.parse(rawVal);\n                        } catch (_) {\n                            try {\n                                parsed = JSON.parse(rawVal.replace(/\\\\\"/g, '\"'));\n                            } catch (_) {\n                                try {\n                                    if (rawVal.startsWith('\"') && rawVal.endsWith('\"')) parsed = JSON.parse(JSON.parse(rawVal));\n                                } catch (_) {}\n                            }\n                        }\n                    } else if (rawVal && typeof rawVal === 'object') {\n                        parsed = rawVal;\n                    }\n\n                    if (!parsed) {\n                        if (!this._roomsLogOnce) this.log('[ROOMS] Unable to parse rooms payload');\n                        return;\n                    }\n\n                    let roomsArr = [];\n                    if (parsed && Array.isArray(parsed.rooms)) {\n                        roomsArr = parsed.rooms;\n                    } else if (parsed && Array.isArray(parsed.sections)) {\n                        roomsArr = parsed.sections;\n                    } else if (Array.isArray(parsed)) {\n                        roomsArr = parsed.filter((x) => x && typeof x === 'object' && 'id' in x);\n                    } else if (parsed && Array.isArray(parsed.selects)) {\n                        const ids = Array.from(new Set(parsed.selects.flat().filter((n) => typeof n === 'number')));\n                        roomsArr = ids.map((id) => ({ id, name: 'Room ' + id }));\n                    }\n\n                    if (roomsArr.length) {\n                        await this.setSettings({ rooms: JSON.stringify(roomsArr), rooms_display: roomsArr.map((r) => r.name || ('Room ' + r.id)).join(', ') });\n                        this._roomsDiscovered = true;\n                    } else {\n                        if (!this._roomsLogOnce) this.log('[ROOMS] No parsable rooms in payload');\n                    }\n                    this._roomsLogOnce = true;\n                } catch (e) {\n                    if (!this._roomsLogOnce) this.error('[ROOMS] Failed to parse:', e && e.message ? e.message : e);\n                    this._roomsLogOnce = true;\n                }\n            }\n\n            // consumables only if supported (prevents invalid_flow_card_id logs)\n            if (this.deviceProperties.supports.consumables) {\n                this.vacuumConsumables(consumables);\n            }\n\n            /* error/status tiles + flows */\n            let err = 'Everything-is-ok';\n            if (device_fault && this.deviceProperties.error_codes.hasOwnProperty(device_fault.value)) {\n                err = this.deviceProperties.error_codes[device_fault.value];\n            }\n\n            const isWaterTankFault = device_fault && Number(device_fault.value) === 210030;\n            if (isWaterTankFault && this._model === 'xiaomi.vacuum.d102gl') {\n                const waterCheckValue = water_check_status && water_check_status.value != null ? Number(water_check_status.value) : null;\n                const waterCheckSuccess = waterCheckValue === 2;\n                const waterCheckFail = waterCheckValue === 3;\n                let hasWaterFaultId = null;\n                if (fault_ids && typeof fault_ids.value === 'string') {\n                    const ids = fault_ids.value.match(/\\d+/g);\n                    if (!ids) {\n                        hasWaterFaultId = false;\n                    } else {\n                        hasWaterFaultId = ids.map((id) => Number(id)).includes(210030);\n                    }\n                }\n\n                if (waterCheckSuccess || hasWaterFaultId === false || (stateKey === 'cleaning' && !waterCheckFail && hasWaterFaultId !== true)) {\n                    err = 'Everything-is-ok';\n                } else if (waterCheckFail) {\n                    err = 'Water tank empty';\n                }\n            }\n\n            if (this.hasCapability('alarm_water_shortage')) {\n                const waterShortageErrors = new Set(['Water tank empty', 'No-water-error']);\n                let detergentShortage = false;\n                if (this.deviceProperties.supports.detergent) {\n                    const det = this.getMiotProp(result, 'detergent_depletion_reminder');\n                    detergentShortage = !!(det && det.value != null && det.value);\n                }\n                await this.updateCapabilityValue('alarm_water_shortage', waterShortageErrors.has(err) || detergentShortage);\n            }\n\n            let safeError = typeof err === 'string' ? err : 'Unknown Error';\n            const okStates = new Set(['Everything-is-ok', 'OK', 'OK / Busy']);\n            if (stateKey === 'cleaning' && okStates.has(err)) safeError = 'OK - Working';\n\n            await this.updateCapabilityValue('vacuum_xiaomi_status', safeError);\n            if (this.getSetting('error') !== err) {\n                await this.setSettings({ error: err }).catch(() => {});\n                if (device_fault && err !== 'Everything-is-ok') {\n                    try {\n                        await this.homey.flow.getDeviceTriggerCard('statusVacuum').trigger(this, { status: safeError });\n                    } catch (_) {\n                        /* ignore invalid_flow_card_id */\n                    }\n                }\n            }\n\n            this.lastVacState = stateKey;\n        } catch (error) {\n            this.log(error);\n            this.homey.clearInterval(this.pollingInterval);\n            if (this.getAvailable()) {\n                this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((err) => this.error(err));\n            }\n            this.homey.setTimeout(() => this.createDevice(), 60000);\n            this.error(error.message);\n        }\n    }\n\n    /* Safe totals for all models */\n    async customVacuumTotals(totals) {\n        try {\n            const timeDiv = this._timeDivisor || 3600;\n            const areaDiv = this._areaDivisor || 100;\n\n            // Clean up any legacy string values (e.g. \"0 h\") that break numeric settings.\n            const currentTimeSetting = Number(this.getSetting('total_work_time'));\n            const currentAreaSetting = Number(this.getSetting('total_cleared_area'));\n            const currentCountSetting = Number(this.getSetting('total_clean_count'));\n            if (!Number.isFinite(currentTimeSetting)) {\n                await this.setSettings({ total_work_time: 0 });\n                await this.total_work_time_token.setValue(0);\n            }\n            if (!Number.isFinite(currentAreaSetting)) {\n                await this.setSettings({ total_cleared_area: 0 });\n                await this.total_cleared_area_token.setValue(0);\n            }\n            if (!Number.isFinite(currentCountSetting)) {\n                await this.setSettings({ total_clean_count: 0 });\n                await this.total_clean_count_token.setValue(0);\n            }\n\n            if (this.getSetting('total_work_time') === undefined) {\n                const h = +((totals.clean_time || 0) / timeDiv).toFixed(3);\n                await this.setSettings({ total_work_time: h });\n                await this.total_work_time_token.setValue(h);\n            }\n            if (this.getSetting('total_cleared_area') === undefined) {\n                const m2 = +((totals.clean_area || 0) / areaDiv).toFixed(3);\n                await this.setSettings({ total_cleared_area: m2 });\n                await this.total_cleared_area_token.setValue(m2);\n            }\n            if (this.getSetting('total_clean_count') === undefined) {\n                const cnt = totals.clean_count || 0;\n                await this.setSettings({ total_clean_count: cnt });\n                await this.total_clean_count_token.setValue(cnt);\n            } else {\n                const robotCnt = totals.clean_count || 0;\n                const current = Number(this.getSetting('total_clean_count'));\n                if (robotCnt > current) {\n                    await this.setSettings({ total_clean_count: robotCnt });\n                    await this.total_clean_count_token.setValue(robotCnt);\n                }\n            }\n            this.initialTokenTotal = true;\n        } catch (err) {\n            this.error('[ERROR] [CUSTOM_TOTALS] Failed:', err);\n        }\n    }\n\n    async customVacuumConsumables(consumables) {\n        try {\n            let main_val = 0,\n                side_val = 0,\n                filter_val = 0;\n\n            if (Array.isArray(consumables) && consumables.length) {\n                const data = consumables[0];\n\n                if (Object.prototype.hasOwnProperty.call(data, 'main_brush_work_time')) {\n                    main_val = Number(data.main_brush_work_time) || 0;\n                    const str = main_val + '%';\n                    if (this.getSetting('main_brush_work_time') !== str) {\n                        await this.setSettings({ main_brush_work_time: str });\n                        if (this.main_brush_lifetime_token) await this.main_brush_lifetime_token.setValue(main_val);\n                    }\n                    if (main_val < this.getSetting('alarm_threshold') && !this.getCapabilityValue('alarm_main_brush_work_time')) {\n                        await this.updateCapabilityValue('alarm_main_brush_work_time', true);\n                        try {\n                            await this.homey.flow.getDeviceTriggerCard('alertVacuum').trigger(this, { consumable: 'Main Brush', value: str });\n                        } catch (_) {}\n                    } else if (main_val > this.getSetting('alarm_threshold') && this.getCapabilityValue('alarm_main_brush_work_time')) {\n                        this.updateCapabilityValue('alarm_main_brush_work_time', false);\n                    }\n                }\n\n                if (Object.prototype.hasOwnProperty.call(data, 'side_brush_work_time')) {\n                    side_val = Number(data.side_brush_work_time) || 0;\n                    const str = side_val + '%';\n                    if (this.getSetting('side_brush_work_time') !== str) {\n                        await this.setSettings({ side_brush_work_time: str });\n                        if (this.side_brush_lifetime_token) await this.side_brush_lifetime_token.setValue(side_val);\n                    }\n                    if (side_val < this.getSetting('alarm_threshold') && !this.getCapabilityValue('alarm_side_brush_work_time')) {\n                        await this.updateCapabilityValue('alarm_side_brush_work_time', true);\n                        try {\n                            await this.homey.flow.getDeviceTriggerCard('alertVacuum').trigger(this, { consumable: 'Side Brush', value: str });\n                        } catch (_) {}\n                    } else if (side_val > this.getSetting('alarm_threshold') && this.getCapabilityValue('alarm_side_brush_work_time')) {\n                        this.updateCapabilityValue('alarm_side_brush_work_time', false);\n                    }\n                }\n\n                if (Object.prototype.hasOwnProperty.call(data, 'filter_work_time')) {\n                    filter_val = Number(data.filter_work_time) || 0;\n                    const str = filter_val + '%';\n                    if (this.getSetting('filter_work_time') !== str) {\n                        await this.setSettings({ filter_work_time: str });\n                        if (this.filter_lifetime_token) await this.filter_lifetime_token.setValue(filter_val);\n                    }\n                    if (filter_val < this.getSetting('alarm_threshold') && !this.getCapabilityValue('alarm_filter_work_time')) {\n                        await this.updateCapabilityValue('alarm_filter_work_time', true);\n                        try {\n                            await this.homey.flow.getDeviceTriggerCard('alertVacuum').trigger(this, { consumable: 'Filter', value: str });\n                        } catch (_) {}\n                    } else if (filter_val > this.getSetting('alarm_threshold') && this.getCapabilityValue('alarm_filter_work_time')) {\n                        this.updateCapabilityValue('alarm_filter_work_time', false);\n                    }\n                }\n\n                if (!this.initialTokenConsumable) {\n                    if (this.main_brush_lifetime_token) await this.main_brush_lifetime_token.setValue(main_val);\n                    if (this.side_brush_lifetime_token) await this.side_brush_lifetime_token.setValue(side_val);\n                    if (this.filter_lifetime_token) await this.filter_lifetime_token.setValue(filter_val);\n                    this.initialTokenConsumable = true;\n                }\n            }\n        } catch (error) {\n            this.error('Error in customVacuumConsumables:', error);\n        }\n    }\n\n    async getOrCreateToken(id, title) {\n        try {\n            return await this.homey.flow.createToken(id, { type: 'number', title });\n        } catch (err) {\n            if (err && err.statusCode === 409) return await this.homey.flow.getToken(id);\n            if (err && err.message === 'token_not_registered') return await this.homey.flow.createToken(id, { type: 'number', title });\n            throw err;\n        }\n    }\n\n    async _accumulateJobTotals() {\n        const prevRaw = Number(this.getSetting('total_clean_count'));\n        const prev = Number.isFinite(prevRaw) ? prevRaw : 0;\n        const next = prev + 1;\n        await this.setSettings({ total_clean_count: next });\n        await this.total_clean_count_token.setValue(next);\n        this.log(`[DIAG] [FINAL] Clean count incremented: ${prev} → ${next}`);\n    }\n\n    async _addLiveDelta(deltaAreaRaw, deltaTimeRaw) {\n        if (deltaAreaRaw <= 0 && deltaTimeRaw <= 0) return;\n        const areaDiv = this._areaDivisor || 100;\n        const timeDiv = this._timeDivisor || 3600;\n        const deltaAreaM2 = deltaAreaRaw / areaDiv;\n        const deltaHours = deltaTimeRaw / timeDiv;\n        const prevAreaRaw = Number(this.getSetting('total_cleared_area'));\n        const prevTimeRaw = Number(this.getSetting('total_work_time'));\n        const prevArea = Number.isFinite(prevAreaRaw) ? prevAreaRaw : 0;\n        const prevTime = Number.isFinite(prevTimeRaw) ? prevTimeRaw : 0;\n        const newArea = +(prevArea + deltaAreaM2).toFixed(2);\n        const newTime = +(prevTime + deltaHours).toFixed(3);\n        const safeArea = Number.isFinite(newArea) ? newArea : 0;\n        const safeTime = Number.isFinite(newTime) ? newTime : 0;\n        await this.setSettings({ total_cleared_area: safeArea, total_work_time: safeTime });\n        await this.total_cleared_area_token.setValue(safeArea);\n        await this.total_work_time_token.setValue(safeTime);\n        this.log(`[SESSION] deltaArea=${deltaAreaM2.toFixed(2)}m², deltaTime=${deltaHours.toFixed(2)}h`);\n    }\n\n    async onSettings({ oldSettings, newSettings, changedKeys }) {\n        if (super.onSettings) await super.onSettings({ oldSettings, newSettings, changedKeys });\n\n        const lifetimeKeys = ['total_work_time', 'total_cleared_area', 'total_clean_count'];\n        const changedLifetime = changedKeys.filter((k) => lifetimeKeys.includes(k));\n        if (!changedLifetime.length) return true;\n\n        try {\n            if (changedLifetime.includes('total_work_time')) {\n                await this.total_work_time_token.setValue(parseFloat(newSettings.total_work_time) || 0);\n            }\n            if (changedLifetime.includes('total_cleared_area')) {\n                await this.total_cleared_area_token.setValue(parseFloat(newSettings.total_cleared_area) || 0);\n            }\n            if (changedLifetime.includes('total_clean_count')) {\n                await this.total_clean_count_token.setValue(parseInt(newSettings.total_clean_count) || 0);\n            }\n        } catch (err) {\n            this.error('Failed to sync lifetime totals from settings', err);\n            return Promise.reject(err);\n        }\n        return true;\n    }\n\n    prettyPrintProperties(rawProps, propertyDefs) {\n        return rawProps\n            .map((item) => {\n                const def = propertyDefs.find((d) => d.siid === item.siid && d.piid === item.piid);\n                const name = def ? def.did : `siid:${item.siid}/piid:${item.piid}`;\n                return `${name}: ${item.value} (code:${item.code})`;\n            })\n            .join(', ');\n    }\n\n\n    getModelIdentifier() {\n        return this._model || (this.getStoreValue ? this.getStoreValue('model') : undefined);\n    }\n\n    mapMopModeInbound(raw) {\n        if (raw == null) return null;\n        if (this.getModelIdentifier() === 'xiaomi.vacuum.c102gl') {\n            const mapping = ['1', '2', '3', '4'];\n            const idx = Number(raw);\n            return Number.isNaN(idx) ? '1' : (mapping[idx] !== undefined ? mapping[idx] : '1');\n        }\n        return String(raw);\n    }\n\n    mapMopModeOutbound(value) {\n        if (value == null) return null;\n        if (this.getModelIdentifier() === 'xiaomi.vacuum.c102gl') {\n            const mapping = { '1': 0, '2': 1, '3': 2, '4': 3 };\n            const mapped = mapping[String(value)];\n            return mapped !== undefined ? mapped : 0;\n        }\n        const numericValue = Number(value);\n        return Number.isNaN(numericValue) ? null : numericValue;\n    }\n\n    mapCleaningModeInbound(raw) {\n        if (raw == null) return null;\n        if (this.getModelIdentifier() === 'xiaomi.vacuum.c102gl') {\n            const mapping = ['1', '2', '3', '4'];\n            const idx = Number(raw);\n            return Number.isNaN(idx) ? '1' : (mapping[idx] !== undefined ? mapping[idx] : '1');\n        }\n        return String(raw);\n    }\n\n    mapCleaningModeOutbound(value) {\n        if (value == null) return null;\n        if (this.getModelIdentifier() === 'xiaomi.vacuum.c102gl') {\n            const mapping = { '1': 0, '2': 1, '3': 2, '4': 3 };\n            const mapped = mapping[String(value)];\n            return mapped !== undefined ? mapped : 0;\n        }\n        const numericValue = Number(value);\n        return Number.isNaN(numericValue) ? null : numericValue;\n    }\n\n    mapWaterLevelInbound(raw) {\n        if (raw == null) return null;\n        if (this.getModelIdentifier() === 'xiaomi.vacuum.c102gl') {\n            const mapping = ['1', '2', '3'];\n            const idx = Number(raw);\n            return Number.isNaN(idx) ? '1' : (mapping[idx] !== undefined ? mapping[idx] : '1');\n        }\n        if (this.getModelIdentifier() === 'xiaomi.vacuum.b108gl') {\n            const numeric = Number(raw);\n            if (Number.isNaN(numeric)) return '1';\n            if (numeric <= 0) return '1';\n            if (numeric > 3) return '3';\n            return String(numeric);\n        }\n        return String(raw);\n    }\n\n    mapWaterLevelOutbound(value) {\n        if (value == null) return null;\n        if (this.getModelIdentifier() === 'xiaomi.vacuum.c102gl') {\n            const mapping = { '1': 0, '2': 1, '3': 2 };\n            const mapped = mapping[String(value)];\n            return mapped !== undefined ? mapped : 0;\n        }\n        const numericValue = Number(value);\n        return Number.isNaN(numericValue) ? null : numericValue;\n    }\n\n    mapPathModeInbound(raw) {\n        if (raw == null) return null;\n        if (this.getModelIdentifier() === 'xiaomi.vacuum.c102gl') {\n            const idx = Number(raw);\n            if (Number.isNaN(idx)) return '1';\n            const bounded = Math.max(0, Math.min(2, idx));\n            return String(bounded + 1);\n        }\n        return String(raw);\n    }\n\n    mapPathModeOutbound(value) {\n        if (value == null) return null;\n        if (this.getModelIdentifier() === 'xiaomi.vacuum.c102gl') {\n            const mapping = { '1': 0, '2': 1, '3': 2 };\n            const mapped = mapping[String(value)];\n            return mapped !== undefined ? mapped : 1;\n        }\n        const numericValue = Number(value);\n        return Number.isNaN(numericValue) ? null : numericValue;\n    }\n\n    mapCarpetModeInbound(raw) {\n        if (this.getModelIdentifier() === 'xiaomi.vacuum.c102gl') {\n            if (raw == null) return null;\n            const mode = Number(raw);\n            if (mode === 0) return '2';\n            if (mode === 1) return '0';\n            return null;\n        }\n        if (raw == null) return null;\n        return String(raw);\n    }\n\n    buildCarpetModeSetPayload(value) {\n        const model = this.getModelIdentifier();\n        const desired = String(value);\n        if (model === 'xiaomi.vacuum.c102gl') {\n            const primary = this.deviceProperties.set_properties.carpet_avoidance;\n            if (!primary) return { payload: [], state: this._carpetModeState };\n            const toggle = this.deviceProperties.set_properties.carpet_avoidance_toggle;\n            const payload = [];\n            const pushToggle = (val) => {\n                if (toggle) payload.push({ siid: toggle.siid, piid: toggle.piid, value: val });\n            };\n            switch (desired) {\n                case '0':\n                    payload.push({ siid: primary.siid, piid: primary.piid, value: 1 });\n                    pushToggle(0);\n                    return { payload, state: '0' };\n                case '1':\n                    payload.push({ siid: primary.siid, piid: primary.piid, value: 1 });\n                    pushToggle(1);\n                    return { payload, state: '1' };\n                case '2':\n                    payload.push({ siid: primary.siid, piid: primary.piid, value: 0 });\n                    pushToggle(0);\n                    return { payload, state: '2' };\n                case '3':\n                    payload.push({ siid: primary.siid, piid: primary.piid, value: 1 });\n                    pushToggle(0);\n                    return { payload, state: '3' };\n                default:\n                    return { payload: [], state: this._carpetModeState };\n            }\n        }\n        if (model === 'xiaomi.vacuum.b108gl') {\n            const primary = this.deviceProperties.set_properties.carpet_avoidance;\n            if (!primary) {\n                return { payload: [], state: this._carpetModeState };\n            }\n            const normalizedValue = desired === '3' ? 0 : Number(desired);\n            if (Number.isNaN(normalizedValue)) {\n                return { payload: [], state: this._carpetModeState };\n            }\n            return {\n                payload: [{ siid: primary.siid, piid: primary.piid, value: normalizedValue }],\n                state: String(normalizedValue)\n            };\n        }\n        const primary = this.deviceProperties.set_properties.carpet_avoidance;\n        if (!primary) {\n            return { payload: [], state: desired };\n        }\n        const numericValue = Number(desired);\n        if (Number.isNaN(numericValue)) {\n            return { payload: [], state: this._carpetModeState };\n        }\n        return {\n            payload: [{ siid: primary.siid, piid: primary.piid, value: numericValue }],\n            state: desired\n        };\n    }\n\n    async _runOneTimeMiotScan() {\n        try {\n            if (!this.miio || typeof this.miio.call !== 'function') return;\n            const results = [];\n            // conservative range to avoid heavy traffic; adjust if needed\n            for (let siid = 1; siid <= 18; siid++) {\n                for (let piid = 1; piid <= 30; piid++) {\n                    try {\n                        const res = await this.miio.call('get_properties', [{ siid, piid }], { retries: 1 });\n                        if (Array.isArray(res) && res[0] && res[0].code === 0) {\n                            results.push({ siid, piid, value: res[0].value });\n                        }\n                    } catch (_) {\n                        // ignore invalid combos\n                    }\n                }\n            }\n            this.log('[MIOT_SCAN]', results.length ? JSON.stringify(results) : 'no readable properties in range');\n        } catch (e) {\n            this.error('[MIOT_SCAN] error', e);\n        }\n    }\n}\n\nmodule.exports = XiaomiVacuumMiotDeviceMax;\n\n"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_max/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Xiaomi Vacuum Cleaner MIoT MAX (WiFi)\",\n    \"nl\": \"Xiaomi stofzuiger MIoT MAX (WiFi)\",\n    \"da\": \"Xiaomi Støvsuger MIoT MAX (WiFi)\",\n    \"de\": \"Xiaomi Staubsauger MIoT MAX (WiFi)\",\n    \"es\": \"Aspiradora Xiaomi MIoT MAX (WiFi)\",\n    \"fr\": \"Aspirateur Xiaomi MIoT MAX (WiFi)\",\n    \"it\": \"Aspirapolvere Xiaomi MIoT MAX (WiFi)\",\n    \"no\": \"Xiaomi Støvsuger MIoT MAX (WiFi)\",\n    \"sv\": \"Xiaomi Dammsugare MIoT MAX (WiFi)\",\n    \"pl\": \"Odkurzacz Xiaomi MIoT MAX (WiFi)\",\n    \"ru\": \"Пылесос Xiaomi MIoT MAX (WiFi)\",\n    \"ko\": \"샤오미 진공 청소기 MIoT MAX (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/vacuum_xiaomi_vacuum_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/vacuum_xiaomi_vacuum_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"vacuumcleaner\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"vacuumcleaner_state\",\n    \"vacuum_xiaomi_mop_mode_max\",\n    \"vacuum_xiaomi_cleaning_mode_max\",\n    \"vacuum_xiaomi_water_level_max\",\n    \"vacuum_xiaomi_path_mode_max\",\n    \"vacuum_xiaomi_carpet_mode_max\",\n    \"vacuum_xiaomi_status\",\n    \"measure_battery\",\n    \"alarm_battery\",\n    \"alarm_main_brush_work_time\",\n    \"alarm_side_brush_work_time\",\n    \"alarm_filter_work_time\",\n    \"alarm_water_shortage\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"INTERNAL\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_max/driver.flow.compose.json",
    "content": "{\n  \"triggers\": [\n    {\n      \"id\": \"vacuum_on_error\",\n      \"title\": {\n        \"en\": \"The vacuum encountered an error\",\n        \"it\": \"Il robot aspirapolvere ha riscontrato un problema.\",\n        \"nl\": \"De robotstofzuiger heeft een foutmelding gegeven. \",\n        \"da\": \"Robotstøvsugeren har givet en fejl\",\n        \"de\": \"Der Saugroboter hat einen Fehler gemeldet\",\n        \"es\": \"El robot aspirador ha dado un error\",\n        \"fr\": \"L'aspirateur robot a rencontré une erreur\",\n        \"no\": \"Robotstøvsugeren har gitt en feil\",\n        \"sv\": \"Robotdammsugaren har rapporterat ett fel\",\n        \"pl\": \"Odkurzacz robot zgłosił błąd\",\n        \"ru\": \"Робот-пылесос сообщил об ошибке\",\n        \"ko\": \"로봇 청소기가 오류를 발생시켰습니다\"\n      },\n      \"description\": {\n        \"en\": \"the vacuum has raised an error. Please check the device for details.\",\n        \"it\": \"il robot aspirapolvere è andato in errore. Per favore controlla il dispositivo per i dettagli.\",\n        \"nl\": \"De robotstofzuiger heeft een foutmelding gegeven. Controleer het apparaat voor meer details.\",\n        \"da\": \"Robotstøvsugeren har givet en fejl. Kontroller enheden for flere detaljer.\",\n        \"de\": \"Der Saugroboter hat einen Fehler gemeldet. Bitte überprüfen Sie das Gerät für weitere Details.\",\n        \"es\": \"El robot aspirador ha dado un error. Por favor, revise el dispositivo para más detalles.\",\n        \"fr\": \"L'aspirateur robot a rencontré une erreur. Veuillez vérifier l'appareil pour plus de détails.\",\n        \"no\": \"Robotstøvsugeren har gitt en feil. Vennligst sjekk enheten for flere detaljer.\",\n        \"sv\": \"Robotdammsugaren har rapporterat ett fel. Kontrollera enheten för mer information.\",\n        \"pl\": \"Odkurzacz robot zgłosił błąd. Proszę sprawdzić urządzenie, aby uzyskać więcej szczegółów.\",\n        \"ru\": \"Робот-пылесос сообщил об ошибке. Пожалуйста, проверьте устройство для получения подробной информации.\",\n        \"ko\": \"로봇 청소기가 오류를 발생시켰습니다. 자세한 내용은 장치를 확인하십시오.\"\n      },\n      \"tokens\": [\n        {\n          \"name\": \"error\",\n          \"type\": \"string\",\n          \"title\": {\n            \"en\": \"vacuum error raised\",\n            \"it\": \"errore segnalato dal robot aspirapolvere\",\n            \"nl\": \"robotstofzuiger foutmelding gegeven\",\n            \"da\": \"robotstøvsuger fejl\",\n            \"de\": \"Saugroboterfehler\",\n            \"es\": \"error del robot aspirador\",\n            \"fr\": \"erreur de l'aspirateur robot\",\n            \"no\": \"robotstøvsugerfeil\",\n            \"sv\": \"robotdammsugarefel\",\n            \"pl\": \"błąd odkurzacza robota\",\n            \"ru\": \"ошибка робота-пылесоса\",\n            \"ko\": \"로봇 청소기 오류\"\n          }\n        }\n      ]\n    }\n  ],\n  \"conditions\": [],\n  \"actions\": [\n    {\n      \"id\": \"advanced_room_cleaning\",\n      \"title\": {\n        \"en\": \"advanced cleaning\",\n        \"it\": \"Pulizia avanzata\",\n        \"nl\": \"Geavanceerde reiniging\",\n        \"da\": \"Avanceret rengøring\",\n        \"de\": \"Erweiterte Reinigung\",\n        \"es\": \"Limpieza avanzada\",\n        \"fr\": \"Nettoyage avancé\",\n        \"no\": \"Avansert rengjøring\",\n        \"sv\": \"Avancerad rengöring\",\n        \"pl\": \"Zaawansowane czyszczenie\",\n        \"ru\": \"Расширенная очистка\",\n        \"ko\": \"고급 청소\"\n      },\n      \"titleFormatted\": {\n        \"en\": \"Start [[mode]] with accuracy [[accuracy]]. Sweep [[mode_sweep]] and mop [[mode_mop]] on room [[room]] (carpet-avoid: [[carpet_avoidance]])\",\n        \"it\": \"Attiva [[mode]] con accuratezza percorso [[accuracy]]. Aspirazione [[mode_sweep]] e lavaggio [[mode_mop]] in stanza [[room]] (evita tappeti: [[carpet_avoidance]])\",\n        \"nl\": \"Start [[mode]] met nauwkeurigheid [[accuracy]]. Stofzuigen [[mode_sweep]] en dweilen [[mode_mop]] in kamer [[room]] (tapijt vermijden: [[carpet_avoidance]])\",\n        \"da\": \"Start [[mode]] med nøjagtighed [[accuracy]]. Støvsug [[mode_sweep]] og moppe [[mode_mop]] i rum [[room]] (undgå tæpper: [[carpet_avoidance]])\",\n        \"de\": \"Starte [[mode]] mit Genauigkeit [[accuracy]]. Saugen [[mode_sweep]] und Wischen [[mode_mop]] im Raum [[room]] (Teppich-Vermeidung: [[carpet_avoidance]])\",\n        \"es\": \"Iniciar [[mode]] con precisión [[accuracy]]. Barrer [[mode_sweep]] y fregar [[mode_mop]] en la habitación [[room]] (evitar alfombras: [[carpet_avoidance]])\",\n        \"fr\": \"Démarrer [[mode]] avec précision [[accuracy]]. Balayer [[mode_sweep]] et frotter [[mode_mop]] dans la pièce [[room]] (éviter tapis: [[carpet_avoidance]])\",\n        \"no\": \"Start [[mode]] med nøyaktighet [[accuracy]]. Støvsuge [[mode_sweep]] og moppe [[mode_mop]] i rom [[room]] (unngå tepper: [[carpet_avoidance]])\",\n        \"sv\": \"Starta [[mode]] med noggrannhet [[accuracy]]. Dammsuga [[mode_sweep]] och moppa [[mode_mop]] i rum [[room]] (undvik mattor: [[carpet_avoidance]])\",\n        \"pl\": \"Rozpocznij [[mode]] z dokładnością [[accuracy]]. Odkurzanie [[mode_sweep]] i mycie [[mode_mop]] w pokoju [[room]] (unikaj dywanów: [[carpet_avoidance]])\",\n        \"ru\": \"Запустить [[mode]] с точностью [[accuracy]]. Пылесосить [[mode_sweep]] и мыть [[mode_mop]] в комнате [[room]] (избегать ковров: [[carpet_avoidance]])\",\n        \"ko\": \"[[mode]]를 [[accuracy]] 정확도로 시작합니다. [[mode_sweep]] 청소 및 [[mode_mop]] 방 [[room]] (카펫 회피: [[carpet_avoidance]])\"\n      },\n      \"args\": [\n        {\n          \"name\": \"mode\",\n          \"type\": \"dropdown\",\n          \"title\": {\n            \"en\": \"Select mode\",\n            \"it\": \"Seleziona modalità\",\n            \"nl\": \"Selecteer modus\",\n            \"da\": \"Vælg tilstand\",\n            \"de\": \"Modus auswählen\",\n            \"es\": \"Seleccionar modo\",\n            \"fr\": \"Sélectionner le mode\",\n            \"no\": \"Velg modus\",\n            \"sv\": \"Välj läge\",\n            \"pl\": \"Wybierz tryb\",\n            \"ru\": \"Выберите режим\",\n            \"ko\": \"모드 선택\"\n          },\n          \"values\": [\n            {\n              \"id\": \"1\",\n              \"label\": {\n                \"en\": \"Sweep\",\n                \"it\": \"Aspirazione\",\n                \"nl\": \"Stofzuigen\",\n                \"da\": \"Støvsugning\",\n                \"de\": \"Saugen\",\n                \"es\": \"Aspirar\",\n                \"fr\": \"Aspirer\",\n                \"no\": \"Støvsuging\",\n                \"sv\": \"Dammsugning\",\n                \"pl\": \"Odkurzanie\",\n                \"ru\": \"Пылесосить\",\n                \"ko\": \"청소하기\"\n              }\n            },\n            {\n              \"id\": \"2\",\n              \"label\": {\n                \"en\": \"Mop\",\n                \"it\": \"Lavaggio\",\n                \"nl\": \"Dweilen\",\n                \"da\": \"Gulvvask\",\n                \"de\": \"Wischen\",\n                \"es\": \"Fregar\",\n                \"fr\": \"Laver\",\n                \"no\": \"Vask\",\n                \"sv\": \"Moppning\",\n                \"pl\": \"Mycie\",\n                \"ru\": \"Мытье\",\n                \"ko\": \"청소하기\"\n              }\n            },\n            {\n              \"id\": \"3\",\n              \"label\": {\n                \"en\": \"Sweep and mop\",\n                \"it\": \"Aspirazione e lavaggio\",\n                \"nl\": \"Stofzuigen en dweilen\",\n                \"da\": \"Støvsugning og gulvvask\",\n                \"de\": \"Saugen und Wischen\",\n                \"es\": \"Aspirar y fregar\",\n                \"fr\": \"Aspirer et laver\",\n                \"no\": \"Støvsuging og vask\",\n                \"sv\": \"Dammsugning och moppning\",\n                \"pl\": \"Odkurzanie i mycie\",\n                \"ru\": \"Пылесосить и мыть\",\n                \"ko\": \"청소 및 세척\"\n              }\n            },\n            {\n              \"id\": \"4\",\n              \"label\": {\n                \"en\": \"Sweep and after mop\",\n                \"it\": \"Aspirazione e successivamente lavaggio\",\n                \"nl\": \"Stofzuigen en daarna dweilen\",\n                \"da\": \"Støvsugning og derefter gulvvask\",\n                \"de\": \"Saugen und anschließend wischen\",\n                \"es\": \"Aspirar y luego fregar\",\n                \"fr\": \"Aspirer puis laver\",\n                \"no\": \"Støvsuging og deretter vask\",\n                \"sv\": \"Dammsugning och sedan moppning\",\n                \"pl\": \"Odkurzanie, a następnie mycie\",\n                \"ru\": \"Сначала пылесосить, а затем мыть\",\n                \"ko\": \"먼저 청소한 후 세척\"\n              }\n            }\n          ]\n        },\n        {\n          \"name\": \"accuracy\",\n          \"type\": \"dropdown\",\n          \"title\": {\n            \"en\": \"Select clean accuracy\",\n            \"it\": \"Seleziona accuratezza percorso pulizia\",\n            \"nl\": \"Selecteer reinigingsnauwkeurigheid\",\n            \"da\": \"Vælg rengøringsnøjagtighed\",\n            \"de\": \"Reinigungsgenauigkeit auswählen\",\n            \"es\": \"Seleccionar precisión de limpieza\",\n            \"fr\": \"Sélectionner la précision de nettoyage\",\n            \"no\": \"Velg rengjøringsnøyaktighet\",\n            \"sv\": \"Välj rengöringsnoggrannhet\",\n            \"pl\": \"Wybierz dokładność czyszczenia\",\n            \"ru\": \"Выберите точность очистки\",\n            \"ko\": \"청소 정확도 선택\"\n          },\n          \"values\": [\n            {\n              \"id\": \"1\",\n              \"label\": {\n                \"en\": \"Quick\",\n                \"it\": \"Veloce\",\n                \"nl\": \"Snel\",\n                \"da\": \"Hurtig\",\n                \"de\": \"Schnell\",\n                \"es\": \"Rápido\",\n                \"fr\": \"Rapide\",\n                \"no\": \"Rask\",\n                \"sv\": \"Snabb\",\n                \"pl\": \"Szybki\",\n                \"ru\": \"Быстрый\",\n                \"ko\": \"빠름\"\n              }\n            },\n            {\n              \"id\": \"2\",\n              \"label\": {\n                \"en\": \"Standard\",\n                \"it\": \"Standard\",\n                \"nl\": \"Standaard\",\n                \"da\": \"Standard\",\n                \"de\": \"Standard\",\n                \"es\": \"Estándar\",\n                \"fr\": \"Standard\",\n                \"no\": \"Standard\",\n                \"sv\": \"Standard\",\n                \"pl\": \"Standardowy\",\n                \"ru\": \"Стандартный\",\n                \"ko\": \"표준\"\n              }\n            },\n            {\n              \"id\": \"3\",\n              \"label\": {\n                \"en\": \"Deep\",\n                \"it\": \"Profondo\",\n                \"nl\": \"Diep\",\n                \"da\": \"Dyb\",\n                \"de\": \"Tief\",\n                \"es\": \"Profundo\",\n                \"fr\": \"Profond\",\n                \"no\": \"Dyp\",\n                \"sv\": \"Djup\",\n                \"pl\": \"Głęboki\",\n                \"ru\": \"Глубокий\",\n                \"ko\": \"딥\"\n              }\n            }\n          ]\n        },\n        {\n          \"name\": \"mode_sweep\",\n          \"type\": \"dropdown\",\n          \"title\": {\n            \"en\": \"Select sweep power\",\n            \"it\": \"Seleziona potenza aspirazione\",\n            \"nl\": \"Selecteer stofzuigkracht\",\n            \"da\": \"Vælg støvsugerkraft\",\n            \"de\": \"Saugleistung auswählen\",\n            \"es\": \"Seleccionar potencia de succión\",\n            \"fr\": \"Sélectionner la puissance d'aspiration\",\n            \"no\": \"Velg sugekraft\",\n            \"sv\": \"Välj sugkraft\",\n            \"pl\": \"Wybierz moc ssania\",\n            \"ru\": \"Выберите мощность всасывания\",\n            \"ko\": \"흡입력 선택\"\n          },\n          \"values\": [\n            {\n              \"id\": \"1\",\n              \"label\": {\n                \"en\": \"Silent\",\n                \"it\": \"Silenzioso\",\n                \"nl\": \"Stil\",\n                \"da\": \"Stille\",\n                \"de\": \"Leise\",\n                \"es\": \"Silencioso\",\n                \"fr\": \"Silencieux\",\n                \"no\": \"Stille\",\n                \"sv\": \"Tyst\",\n                \"pl\": \"Cichy\",\n                \"ru\": \"Тихий\",\n                \"ko\": \"조용한\"\n              }\n            },\n            {\n              \"id\": \"2\",\n              \"label\": {\n                \"en\": \"Basic\",\n                \"it\": \"Normale\",\n                \"nl\": \"Basis\",\n                \"da\": \"Basis\",\n                \"de\": \"Basis\",\n                \"es\": \"Básico\",\n                \"fr\": \"Basique\",\n                \"no\": \"Grunnleggende\",\n                \"sv\": \"Grundläggande\",\n                \"pl\": \"Podstawowy\",\n                \"ru\": \"Базовый\",\n                \"ko\": \"기본\"\n              }\n            },\n            {\n              \"id\": \"3\",\n              \"label\": {\n                \"en\": \"Strong\",\n                \"it\": \"Forte\",\n                \"nl\": \"Sterk\",\n                \"da\": \"Stærk\",\n                \"de\": \"Stark\",\n                \"es\": \"Fuerte\",\n                \"fr\": \"Forte\",\n                \"no\": \"Sterk\",\n                \"sv\": \"Stark\",\n                \"pl\": \"Mocny\",\n                \"ru\": \"Сильный\",\n                \"ko\": \"강한\"\n              }\n            },\n            {\n              \"id\": \"4\",\n              \"label\": {\n                \"en\": \"Full Speed\",\n                \"it\": \"Massima potenza\",\n                \"nl\": \"Volledige snelheid\",\n                \"da\": \"Fuld hastighed\",\n                \"de\": \"Vollgas\",\n                \"es\": \"A toda velocidad\",\n                \"fr\": \"Vitesse maximale\",\n                \"no\": \"Full hastighet\",\n                \"sv\": \"Full hastighet\",\n                \"pl\": \"Pełna prędkość\",\n                \"ru\": \"Максимальная скорость\",\n                \"ko\": \"최고속\"\n              }\n            }\n          ]\n        },\n        {\n          \"name\": \"mode_mop\",\n          \"type\": \"dropdown\",\n          \"title\": {\n            \"en\": \"Mop mode\",\n            \"it\": \"Modalità lavaggio\",\n            \"nl\": \"Dweilmodus\",\n            \"da\": \"Moppefunktion\",\n            \"de\": \"Wischmodus\",\n            \"es\": \"Modo fregona\",\n            \"fr\": \"Mode serpillère\",\n            \"no\": \"Moppemodus\",\n            \"sv\": \"Moppläge\",\n            \"pl\": \"Tryb mopa\",\n            \"ru\": \"Режим швабры\",\n            \"ko\": \"대걸레 모드\"\n          },\n          \"values\": [\n            {\n              \"id\": \"0\",\n              \"label\": {\n                \"en\": \"Off\",\n                \"it\": \"Nessuno\",\n                \"nl\": \"Uit\",\n                \"da\": \"Fra\",\n                \"de\": \"Aus\",\n                \"es\": \"Apagar\",\n                \"fr\": \"Éteindre\",\n                \"no\": \"Av\",\n                \"sv\": \"Av\",\n                \"pl\": \"Wyłączony\",\n                \"ru\": \"Выключить\",\n                \"ko\": \"끔\"\n              }\n            },\n            {\n              \"id\": \"1\",\n              \"label\": {\n                \"en\": \"Level 1\",\n                \"it\": \"Livello 1\",\n                \"nl\": \"Niveau 1\",\n                \"da\": \"Niveau 1\",\n                \"de\": \"Stufe 1\",\n                \"es\": \"Nivel 1\",\n                \"fr\": \"Niveau 1\",\n                \"no\": \"Nivå 1\",\n                \"sv\": \"Nivå 1\",\n                \"pl\": \"Poziom 1\",\n                \"ru\": \"Уровень 1\",\n                \"ko\": \"레벨 1\"\n              }\n            },\n            {\n              \"id\": \"2\",\n              \"label\": {\n                \"en\": \"Level 2\",\n                \"it\": \"Livello 2\",\n                \"nl\": \"Niveau 2\",\n                \"da\": \"Niveau 2\",\n                \"de\": \"Stufe 2\",\n                \"es\": \"Nivel 2\",\n                \"fr\": \"Niveau 2\",\n                \"no\": \"Nivå 2\",\n                \"sv\": \"Nivå 2\",\n                \"pl\": \"Poziom 2\",\n                \"ru\": \"Уровень 2\",\n                \"ko\": \"레벨 2\"\n              }\n            },\n            {\n              \"id\": \"3\",\n              \"label\": {\n                \"en\": \"Level 3\",\n                \"it\": \"Livello 3\",\n                \"nl\": \"Niveau 3\",\n                \"da\": \"Niveau 3\",\n                \"de\": \"Stufe 3\",\n                \"es\": \"Nivel 3\",\n                \"fr\": \"Niveau 3\",\n                \"no\": \"Nivå 3\",\n                \"sv\": \"Nivå 3\",\n                \"pl\": \"Poziom 3\",\n                \"ru\": \"Уровень 3\",\n                \"ko\": \"레벨 3\"\n              }\n            }\n          ]\n        },\n        {\n          \"name\": \"carpet_avoidance\",\n          \"type\": \"dropdown\",\n          \"title\": {\n            \"en\": \"Carpet avoidance\",\n            \"it\": \"Evitamento tappeti\",\n            \"nl\": \"Tapijt vermijden\",\n            \"da\": \"Undgå tæpper\",\n            \"de\": \"Teppichvermeidung\",\n            \"es\": \"Evitar alfombras\",\n            \"fr\": \"Éviter les tapis\",\n            \"no\": \"Unngå tepper\",\n            \"sv\": \"Undvik mattor\",\n            \"pl\": \"Unikaj dywanów\",\n            \"ru\": \"Избегать ковров\",\n            \"ko\": \"카펫 회피\"\n          },\n          \"values\": [\n            {\n              \"id\": \"0\",\n              \"label\": {\n                \"en\": \"Self Adaptation\",\n                \"it\": \"Auto adattamento\",\n                \"nl\": \"Zelfaanpassing\",\n                \"da\": \"Selvtilpasning\",\n                \"de\": \"Selbstanpassung\",\n                \"es\": \"Auto adaptación\",\n                \"fr\": \"Auto-adaptation\",\n                \"no\": \"Selvtilpasning\",\n                \"sv\": \"Självanpassning\",\n                \"pl\": \"Samodopasowanie\",\n                \"ru\": \"Самоадаптация\",\n                \"ko\": \"자동 적응\"\n              }\n            },\n            {\n              \"id\": \"1\",\n              \"label\": {\n                \"en\": \"Avoid\",\n                \"it\": \"Evita\",\n                \"nl\": \"Vermijden\",\n                \"da\": \"Undgå\",\n                \"de\": \"Vermeiden\",\n                \"es\": \"Evitar\",\n                \"fr\": \"Éviter\",\n                \"no\": \"Unngå\",\n                \"sv\": \"Undvik\",\n                \"pl\": \"Unikaj\",\n                \"ru\": \"Избегать\",\n                \"ko\": \"회피\"\n              }\n            },\n            {\n              \"id\": \"2\",\n              \"label\": {\n                \"en\": \"Ignore\",\n                \"it\": \"Ignora\",\n                \"nl\": \"Negeren\",\n                \"da\": \"Ignorer\",\n                \"de\": \"Ignorieren\",\n                \"es\": \"Ignorar\",\n                \"fr\": \"Ignorer\",\n                \"no\": \"Ignorer\",\n                \"sv\": \"Ignorera\",\n                \"pl\": \"Ignoruj\",\n                \"ru\": \"Игнорировать\",\n                \"ko\": \"무시\"\n              }\n            },\n            {\n              \"id\": \"3\",\n              \"label\": {\n                \"en\": \"Span\",\n                \"it\": \"Span\",\n                \"nl\": \"Span\",\n                \"da\": \"Span\",\n                \"de\": \"Span\",\n                \"es\": \"Span\",\n                \"fr\": \"Span\",\n                \"no\": \"Span\",\n                \"sv\": \"Span\",\n                \"pl\": \"Span\",\n                \"ru\": \"Span\",\n                \"ko\": \"Span\"\n              }\n            }\n          ]\n        },\n        {\n          \"type\": \"text\",\n          \"name\": \"room\",\n          \"title\": {\n            \"en\": \"Select room separated by commas ('all' for all rooms)\",\n            \"it\": \"Seleziona stanze separate da virgole ('all' per tutte le stanze)\",\n            \"nl\": \"Selecteer kamer gescheiden door komma's ('all' voor alle kamers)\",\n            \"da\": \"Vælg rum adskilt af kommaer ('all' for alle rum)\",\n            \"de\": \"Wählen Sie Räume, die durch Kommas getrennt sind ('all' für alle Räume)\",\n            \"es\": \"Seleccionar habitación separada por comas ('all' para todas las habitaciones)\",\n            \"fr\": \"Sélectionner la pièce séparée par des virgules ('all' pour toutes les pièces)\",\n            \"no\": \"Velg rom atskilt med kommaer ('all' for alle rom)\",\n            \"sv\": \"Välj rum åtskilt med kommatecken ('all' för alla rum)\",\n            \"pl\": \"Wybierz pokój oddzielony przecinkami ('all' dla wszystkich pokoi)\",\n            \"ru\": \"Выберите комнату, разделенную запятыми ('all' для всех комнат)\",\n            \"ko\": \"방을 쉼표로 구분하여 선택합니다('all'은 모든 방에 해당)\"\n          },\n          \"placeholder\": {\n            \"en\": \"all\"\n          }\n        }\n      ]\n    },\n    {\n      \"id\": \"set_sweep_mop_type\",\n      \"title\": {\n        \"en\": \"Set vacuum mode\",\n        \"it\": \"Imposta modalità aspirazione\",\n        \"nl\": \"Stel zuigmodus in\",\n        \"da\": \"Indstil støvsugningsmodus\",\n        \"de\": \"Saugmodus einstellen\",\n        \"es\": \"Establecer modo aspiración\",\n        \"fr\": \"Définir le mode aspirateur\",\n        \"no\": \"Angi støvsugmodus\",\n        \"sv\": \"Ställ in dammsägarläge\",\n        \"pl\": \"Ustaw tryb odkurzania\",\n        \"ru\": \"Установить режим уборки\",\n        \"ko\": \"청소 모드 설정\"\n      },\n      \"titleFormatted\": {\n        \"en\": \"Set vacuum mode to [[mode]]\",\n        \"it\": \"Imposta modalità aspirazione su [[mode]]\",\n        \"nl\": \"Stel zuigmodus in op [[mode]]\",\n        \"da\": \"Indstil støvsugningsmodus til [[mode]]\",\n        \"de\": \"Saugmodus einstellen auf [[mode]]\",\n        \"es\": \"Establecer modo aspiración en [[mode]]\",\n        \"fr\": \"Définir le mode aspirateur sur [[mode]]\",\n        \"no\": \"Angi støvsugmodus til [[mode]]\",\n        \"sv\": \"Ställ in dammsägarläge på [[mode]]\",\n        \"pl\": \"Ustaw tryb odkurzania na [[mode]]\",\n        \"ru\": \"Установить режим уборки на [[mode]]\",\n        \"ko\": \"청소 모드를 [[mode]]로 설정\"\n      },\n      \"args\": [\n        {\n          \"name\": \"mode\",\n          \"type\": \"dropdown\",\n          \"title\": {\n            \"en\": \"Vacuum mode\",\n            \"it\": \"Modalità aspirazione\",\n            \"nl\": \"Zuigmodus\",\n            \"da\": \"Støvsugningsmodus\",\n            \"de\": \"Saugmodus\",\n            \"es\": \"Modo aspirar\",\n            \"fr\": \"Mode aspiration\",\n            \"no\": \"Støvsugmodus\",\n            \"sv\": \"Dammsägarläge\",\n            \"pl\": \"Tryb odkurzania\",\n            \"ru\": \"Режим уборки\",\n            \"ko\": \"청소 모드\"\n          },\n          \"values\": [\n            {\n              \"id\": \"1\",\n              \"label\": {\n                \"en\": \"Sweep only\",\n                \"it\": \"Solo aspirazione\",\n                \"nl\": \"Alleen stofzuigen\",\n                \"da\": \"Kun støvsugning\",\n                \"de\": \"Nur Saugen\",\n                \"es\": \"Solo aspirar\",\n                \"fr\": \"Aspirer seulement\",\n                \"no\": \"Kun støvsuging\",\n                \"sv\": \"Endast dammsugning\",\n                \"pl\": \"Tylko odkurzanie\",\n                \"ru\": \"Только уборка\",\n                \"ko\": \"청소만\"\n              }\n            },\n            {\n              \"id\": \"2\",\n              \"label\": {\n                \"en\": \"Mop only\",\n                \"it\": \"Solo lavaggio\",\n                \"nl\": \"Alleen dweilen\",\n                \"da\": \"Kun gulvvask\",\n                \"de\": \"Nur Wischen\",\n                \"es\": \"Solo fregar\",\n                \"fr\": \"Lavette seulement\",\n                \"no\": \"Kun vask\",\n                \"sv\": \"Endast moppning\",\n                \"pl\": \"Tylko mopowanie\",\n                \"ru\": \"Только мытье\",\n                \"ko\": \"물걸레만\"\n              }\n            },\n            {\n              \"id\": \"3\",\n              \"label\": {\n                \"en\": \"Sweep & mop\",\n                \"it\": \"Aspirazione e lavaggio\",\n                \"nl\": \"Stofzuigen en dweilen\",\n                \"da\": \"Støvsugning og gulvvask\",\n                \"de\": \"Saugen und Wischen\",\n                \"es\": \"Aspirar y fregar\",\n                \"fr\": \"Aspirer et laver\",\n                \"no\": \"Støvsuging og vask\",\n                \"sv\": \"Dammsugning och moppning\",\n                \"pl\": \"Odkurzanie i mopowanie\",\n                \"ru\": \"Уборка и мытье\",\n                \"ko\": \"청소 및 물걸레\"\n              }\n            },\n            {\n              \"id\": \"4\",\n              \"label\": {\n                \"en\": \"Sweep then mop\",\n                \"it\": \"Prima aspirare poi lavare\",\n                \"nl\": \"Eerst stofzuigen daarna dweilen\",\n                \"da\": \"Først støvsug, derefter gulvvask\",\n                \"de\": \"Zuerst saugen, dann wischen\",\n                \"es\": \"Primero aspirar, luego fregar\",\n                \"fr\": \"D'abord aspirer, puis laver\",\n                \"no\": \"Først støvsug, deretter vask\",\n                \"sv\": \"Först dammsugning, sedan moppning\",\n                \"pl\": \"Najpierw odkurzanie, potem mopowanie\",\n                \"ru\": \"Сначала уборка, затем мытье\",\n                \"ko\": \"먼저 청소 후 물걸레\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"id\": \"set_cleaning_mode\",\n      \"title\": {\n        \"en\": \"Set cleaning power\",\n        \"it\": \"Imposta potenza di pulizia\",\n        \"nl\": \"Stel zuigvermogen in\",\n        \"da\": \"Indstil rengøringseffekt\",\n        \"de\": \"Reinigungsstärke einstellen\",\n        \"es\": \"Establecer potencia de limpieza\",\n        \"fr\": \"Définir la puissance de nettoyage\",\n        \"no\": \"Angi rengjøringsstyrke\",\n        \"sv\": \"Ställ in rengöringsstyrka\",\n        \"pl\": \"Ustaw moc odkurzania\",\n        \"ru\": \"Установить мощность уборки\",\n        \"ko\": \"청소 세기 설정\"\n      },\n      \"titleFormatted\": {\n        \"en\": \"Set cleaning power to [[power]]\",\n        \"it\": \"Imposta potenza di pulizia su [[power]]\",\n        \"nl\": \"Stel zuigvermogen in op [[power]]\",\n        \"da\": \"Indstil rengøringseffekt til [[power]]\",\n        \"de\": \"Reinigungsstärke einstellen auf [[power]]\",\n        \"es\": \"Establecer potencia de limpieza en [[power]]\",\n        \"fr\": \"Définir la puissance de nettoyage sur [[power]]\",\n        \"no\": \"Angi rengjøringsstyrke til [[power]]\",\n        \"sv\": \"Ställ in rengöringsstyrka på [[power]]\",\n        \"pl\": \"Ustaw moc odkurzania na [[power]]\",\n        \"ru\": \"Установить мощность уборки на [[power]]\",\n        \"ko\": \"청소 세기를 [[power]]로 설정\"\n      },\n      \"args\": [\n        {\n          \"name\": \"power\",\n          \"type\": \"dropdown\",\n          \"title\": {\n            \"en\": \"Cleaning power\",\n            \"it\": \"Potenza di pulizia\",\n            \"nl\": \"Zuigkracht\",\n            \"da\": \"Rengøringseffekt\",\n            \"de\": \"Reinigungsstärke\",\n            \"es\": \"Potencia de limpieza\",\n            \"fr\": \"Puissance de nettoyage\",\n            \"no\": \"Rengjøringsstyrke\",\n            \"sv\": \"Rengöringsstyrka\",\n            \"pl\": \"Moc odkurzania\",\n            \"ru\": \"Мощность уборки\",\n            \"ko\": \"청소 세기\"\n          },\n          \"values\": [\n            {\n              \"id\": \"1\",\n              \"label\": {\n                \"en\": \"Silent\",\n                \"it\": \"Silenzioso\",\n                \"nl\": \"Stil\",\n                \"da\": \"Stille\",\n                \"de\": \"Leise\",\n                \"es\": \"Silencioso\",\n                \"fr\": \"Silencieux\",\n                \"no\": \"Stille\",\n                \"sv\": \"Tyst\",\n                \"pl\": \"Cichy\",\n                \"ru\": \"Тихо\",\n                \"ko\": \"조용함\"\n              }\n            },\n            {\n              \"id\": \"2\",\n              \"label\": {\n                \"en\": \"Basic\",\n                \"it\": \"Normale\",\n                \"nl\": \"Basis\",\n                \"da\": \"Basis\",\n                \"de\": \"Basis\",\n                \"es\": \"Básico\",\n                \"fr\": \"Basique\",\n                \"no\": \"Grunnleggende\",\n                \"sv\": \"Grundläggande\",\n                \"pl\": \"Podstawowy\",\n                \"ru\": \"Базовый\",\n                \"ko\": \"기본\"\n              }\n            },\n            {\n              \"id\": \"3\",\n              \"label\": {\n                \"en\": \"Strong\",\n                \"it\": \"Forte\",\n                \"nl\": \"Sterk\",\n                \"da\": \"Stærk\",\n                \"de\": \"Stark\",\n                \"es\": \"Fuerte\",\n                \"fr\": \"Forte\",\n                \"no\": \"Sterk\",\n                \"sv\": \"Stark\",\n                \"pl\": \"Mocny\",\n                \"ru\": \"Сильный\",\n                \"ko\": \"강함\"\n              }\n            },\n            {\n              \"id\": \"4\",\n              \"label\": {\n                \"en\": \"Full Speed\",\n                \"it\": \"Massima potenza\",\n                \"nl\": \"Volledige snelheid\",\n                \"da\": \"Fuld hastighed\",\n                \"de\": \"Vollgas\",\n                \"es\": \"A toda velocidad\",\n                \"fr\": \"Vitesse maximale\",\n                \"no\": \"Full hastighet\",\n                \"sv\": \"Full hastighet\",\n                \"pl\": \"Pełna prędkość\",\n                \"ru\": \"Максимальная скорость\",\n                \"ko\": \"최고속\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"id\": \"set_water_level\",\n      \"title\": {\n        \"en\": \"Set water output level\",\n        \"it\": \"Imposta livello acqua\",\n        \"nl\": \"Stel waterniveau in\",\n        \"da\": \"Indstil vandniveau\",\n        \"de\": \"Wasserstand einstellen\",\n        \"es\": \"Establecer nivel de agua\",\n        \"fr\": \"Définir le niveau d'eau\",\n        \"no\": \"Angi vannivå\",\n        \"sv\": \"Ställ in vattennivå\",\n        \"pl\": \"Ustaw poziom wody\",\n        \"ru\": \"Установить уровень воды\",\n        \"ko\": \"물 세기 설정\"\n      },\n      \"titleFormatted\": {\n        \"en\": \"Set water level to [[level]]\",\n        \"it\": \"Imposta livello acqua su [[level]]\",\n        \"nl\": \"Stel waterniveau in op [[level]]\",\n        \"da\": \"Indstil vandniveau til [[level]]\",\n        \"de\": \"Wasserstand einstellen auf [[level]]\",\n        \"es\": \"Establecer nivel de agua en [[level]]\",\n        \"fr\": \"Définir le niveau d'eau sur [[level]]\",\n        \"no\": \"Angi vannivå til [[level]]\",\n        \"sv\": \"Ställ in vattennivå på [[level]]\",\n        \"pl\": \"Ustaw poziom wody na [[level]]\",\n        \"ru\": \"Установить уровень воды на [[level]]\",\n        \"ko\": \"물 세기를 [[level]]로 설정\"\n      },\n      \"args\": [\n        {\n          \"name\": \"level\",\n          \"type\": \"dropdown\",\n          \"title\": {\n            \"en\": \"Water level\",\n            \"it\": \"Livello acqua\",\n            \"nl\": \"Waterniveau\",\n            \"da\": \"Vandniveau\",\n            \"de\": \"Wasserstand\",\n            \"es\": \"Nivel de agua\",\n            \"fr\": \"Niveau d'eau\",\n            \"no\": \"Vannivå\",\n            \"sv\": \"Vattennivå\",\n            \"pl\": \"Poziom wody\",\n            \"ru\": \"Уровень воды\",\n            \"ko\": \"물 세기\"\n          },\n          \"values\": [\n            {\n              \"id\": \"0\",\n              \"label\": {\n                \"en\": \"Off\",\n                \"it\": \"Spento\",\n                \"nl\": \"Uit\",\n                \"da\": \"Fra\",\n                \"de\": \"Aus\",\n                \"es\": \"Apagado\",\n                \"fr\": \"Désactivé\",\n                \"no\": \"Av\",\n                \"sv\": \"Av\",\n                \"pl\": \"Wyłączony\",\n                \"ru\": \"Выключено\",\n                \"ko\": \"끔\"\n              }\n            },\n            {\n              \"id\": \"1\",\n              \"label\": {\n                \"en\": \"Level 1\",\n                \"it\": \"Livello 1\",\n                \"nl\": \"Niveau 1\",\n                \"da\": \"Niveau 1\",\n                \"de\": \"Stufe 1\",\n                \"es\": \"Nivel 1\",\n                \"fr\": \"Niveau 1\",\n                \"no\": \"Nivå 1\",\n                \"sv\": \"Nivå 1\",\n                \"pl\": \"Poziom 1\",\n                \"ru\": \"Уровень 1\",\n                \"ko\": \"레벨 1\"\n              }\n            },\n            {\n              \"id\": \"2\",\n              \"label\": {\n                \"en\": \"Level 2\",\n                \"it\": \"Livello 2\",\n                \"nl\": \"Niveau 2\",\n                \"da\": \"Niveau 2\",\n                \"de\": \"Stufe 2\",\n                \"es\": \"Nivel 2\",\n                \"fr\": \"Niveau 2\",\n                \"no\": \"Nivå 2\",\n                \"sv\": \"Nivå 2\",\n                \"pl\": \"Poziom 2\",\n                \"ru\": \"Уровень 2\",\n                \"ko\": \"레벨 2\"\n              }\n            },\n            {\n              \"id\": \"3\",\n              \"label\": {\n                \"en\": \"Level 3\",\n                \"it\": \"Livello 3\",\n                \"nl\": \"Niveau 3\",\n                \"da\": \"Niveau 3\",\n                \"de\": \"Stufe 3\",\n                \"es\": \"Nivel 3\",\n                \"fr\": \"Niveau 3\",\n                \"no\": \"Nivå 3\",\n                \"sv\": \"Nivå 3\",\n                \"pl\": \"Poziom 3\",\n                \"ru\": \"Уровень 3\",\n                \"ko\": \"레벨 3\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"id\": \"set_path_mode\",\n      \"title\": {\n        \"en\": \"Set path mode\",\n        \"it\": \"Imposta modalità percorso\",\n        \"nl\": \"Stel padmodus in\",\n        \"da\": \"Indstil stiemodus\",\n        \"de\": \"Pfadmodus einstellen\",\n        \"es\": \"Establecer modo de recorrido\",\n        \"fr\": \"Définir le mode de chemin\",\n        \"no\": \"Angi sti-modus\",\n        \"sv\": \"Ställ in sökläge\",\n        \"pl\": \"Ustaw tryb trasy\",\n        \"ru\": \"Установить режим траектории\",\n        \"ko\": \"경로 모드 설정\"\n      },\n      \"titleFormatted\": {\n        \"en\": \"Set path mode to [[mode]]\",\n        \"it\": \"Imposta modalità percorso su [[mode]]\",\n        \"nl\": \"Stel padmodus in op [[mode]]\",\n        \"da\": \"Indstil stiemodus til [[mode]]\",\n        \"de\": \"Pfadmodus einstellen auf [[mode]]\",\n        \"es\": \"Establecer modo de recorrido en [[mode]]\",\n        \"fr\": \"Définir le mode de chemin sur [[mode]]\",\n        \"no\": \"Angi sti-modus til [[mode]]\",\n        \"sv\": \"Ställ in sökläge på [[mode]]\",\n        \"pl\": \"Ustaw tryb trasy na [[mode]]\",\n        \"ru\": \"Установить режим траектории на [[mode]]\",\n        \"ko\": \"경로 모드를 [[mode]]로 설정\"\n      },\n      \"args\": [\n        {\n          \"name\": \"mode\",\n          \"type\": \"dropdown\",\n          \"title\": {\n            \"en\": \"Path mode\",\n            \"it\": \"Modalità percorso\",\n            \"nl\": \"Padmodus\",\n            \"da\": \"Stiemodus\",\n            \"de\": \"Pfadmodus\",\n            \"es\": \"Modo de recorrido\",\n            \"fr\": \"Mode de chemin\",\n            \"no\": \"Sti-modus\",\n            \"sv\": \"Sökläge\",\n            \"pl\": \"Tryb trasy\",\n            \"ru\": \"Режим траектории\",\n            \"ko\": \"경로 모드\"\n          },\n          \"values\": [\n            {\n              \"id\": \"1\",\n              \"label\": {\n                \"en\": \"Quick\",\n                \"it\": \"Veloce\",\n                \"nl\": \"Snel\",\n                \"da\": \"Hurtig\",\n                \"de\": \"Schnell\",\n                \"es\": \"Rápido\",\n                \"fr\": \"Rapide\",\n                \"no\": \"Rask\",\n                \"sv\": \"Snabb\",\n                \"pl\": \"Szybki\",\n                \"ru\": \"Быстрый\",\n                \"ko\": \"빠름\"\n              }\n            },\n            {\n              \"id\": \"2\",\n              \"label\": {\n                \"en\": \"Standard\",\n                \"it\": \"Standard\",\n                \"nl\": \"Standaard\",\n                \"da\": \"Standard\",\n                \"de\": \"Standard\",\n                \"es\": \"Estándar\",\n                \"fr\": \"Standard\",\n                \"no\": \"Standard\",\n                \"sv\": \"Standard\",\n                \"pl\": \"Standardowy\",\n                \"ru\": \"Стандартный\",\n                \"ko\": \"표준\"\n              }\n            },\n            {\n              \"id\": \"3\",\n              \"label\": {\n                \"en\": \"Deep\",\n                \"it\": \"Profondo\",\n                \"nl\": \"Diep\",\n                \"da\": \"Dyb\",\n                \"de\": \"Tief\",\n                \"es\": \"Profundo\",\n                \"fr\": \"Profond\",\n                \"no\": \"Dyp\",\n                \"sv\": \"Djup\",\n                \"pl\": \"Głęboki\",\n                \"ru\": \"Глубокий\",\n                \"ko\": \"딥\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"id\": \"set_carpet_avoidance\",\n      \"title\": {\n        \"en\": \"Set carpet avoidance\",\n        \"nl\": \"Stel tapijtvermijding in\",\n        \"de\": \"Teppichvermeidung einstellen\",\n        \"da\": \"Indstil tæppeundgåelse\",\n        \"es\": \"Establecer evasión de alfombras\",\n        \"fr\": \"Définir l’évitement des tapis\",\n        \"it\": \"Imposta evitamento tappeti\",\n        \"no\": \"Sett teppeunngåelse\",\n        \"sv\": \"Ställ in mattundvikande\",\n        \"pl\": \"Ustaw unikanie dywanów\",\n        \"ru\": \"Установить избегание ковров\",\n        \"ko\": \"카펫 회피 설정\"\n      },\n      \"titleFormatted\": {\n        \"en\": \"Set carpet avoidance to [[mode]]\",\n        \"nl\": \"Stel tapijtvermijding in op [[mode]]\",\n        \"de\": \"Teppichvermeidung einstellen auf [[mode]]\",\n        \"da\": \"Indstil tæppeundgåelse til [[mode]]\",\n        \"es\": \"Establecer evasión de alfombras a [[mode]]\",\n        \"fr\": \"Définir l’évitement des tapis sur [[mode]]\",\n        \"it\": \"Imposta evitamento tappeti su [[mode]]\",\n        \"no\": \"Sett teppeunngåelse til [[mode]]\",\n        \"sv\": \"Ställ in mattundvikande till [[mode]]\",\n        \"pl\": \"Ustaw unikanie dywanów na [[mode]]\",\n        \"ru\": \"Установить избегание ковров на [[mode]]\",\n        \"ko\": \"[[mode]]로 카펫 회피 설정\"\n      },\n      \"args\": [\n        {\n          \"name\": \"mode\",\n          \"type\": \"dropdown\",\n          \"title\": {\n            \"en\": \"Carpet avoidance mode\",\n            \"nl\": \"Tapijtvermijdingsmodus\",\n            \"de\": \"Teppichvermeidungsmodus\",\n            \"da\": \"Tæppeundgåelsestilstand\",\n            \"es\": \"Modo de evasión de alfombras\",\n            \"fr\": \"Mode d’évitement des tapis\",\n            \"it\": \"Modalità evitamento tappeti\",\n            \"no\": \"Teppeunngåelsesmodus\",\n            \"sv\": \"Mattundvikandeläge\",\n            \"pl\": \"Tryb unikania dywanów\",\n            \"ru\": \"Режим избегания ковров\",\n            \"ko\": \"카펫 회피 모드\"\n          },\n          \"values\": [\n            {\n              \"id\": \"0\",\n              \"label\": {\n                \"en\": \"Self Adaptation\",\n                \"nl\": \"Zelfaanpassing\",\n                \"de\": \"Selbstanpassung\",\n                \"da\": \"Selvtilpasning\",\n                \"es\": \"Auto adaptación\",\n                \"fr\": \"Auto-adaptation\",\n                \"it\": \"Auto adattamento\",\n                \"no\": \"Selvtilpasning\",\n                \"sv\": \"Självanpassning\",\n                \"pl\": \"Samodopasowanie\",\n                \"ru\": \"Самоадаптация\",\n                \"ko\": \"자동 적응\"\n              }\n            },\n            {\n              \"id\": \"1\",\n              \"label\": {\n                \"en\": \"Avoid\",\n                \"nl\": \"Vermijden\",\n                \"de\": \"Vermeiden\",\n                \"da\": \"Undgå\",\n                \"es\": \"Evitar\",\n                \"fr\": \"Éviter\",\n                \"it\": \"Evita\",\n                \"no\": \"Unngå\",\n                \"sv\": \"Undvik\",\n                \"pl\": \"Unikaj\",\n                \"ru\": \"Избегать\",\n                \"ko\": \"회피\"\n              }\n            },\n            {\n              \"id\": \"2\",\n              \"label\": {\n                \"en\": \"Ignore\",\n                \"nl\": \"Negeren\",\n                \"de\": \"Ignorieren\",\n                \"da\": \"Ignorer\",\n                \"es\": \"Ignorar\",\n                \"fr\": \"Ignorer\",\n                \"it\": \"Ignora\",\n                \"no\": \"Ignorer\",\n                \"sv\": \"Ignorera\",\n                \"pl\": \"Ignoruj\",\n                \"ru\": \"Игнорировать\",\n                \"ko\": \"무시\"\n              }\n            },\n            {\n              \"id\": \"3\",\n              \"label\": {\n                \"en\": \"Span\",\n                \"nl\": \"Span\",\n                \"de\": \"Span\",\n                \"da\": \"Span\",\n                \"es\": \"Span\",\n                \"fr\": \"Span\",\n                \"it\": \"Span\",\n                \"no\": \"Span\",\n                \"sv\": \"Span\",\n                \"pl\": \"Span\",\n                \"ru\": \"Span\",\n                \"ko\": \"Span\"\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_max/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass XiaomiVacuumMiotDriver extends Driver {}\n\nmodule.exports = XiaomiVacuumMiotDriver;"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_max/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Rooms\",\n      \"nl\": \"Kamers\",\n      \"da\": \"Rum\",\n      \"de\": \"Räume\",\n      \"es\": \"Habitaciones\",\n      \"fr\": \"Pièces\",\n      \"it\": \"Stanze\",\n      \"no\": \"Rom\",\n      \"sv\": \"Rum\",\n      \"pl\": \"Pokoje\",\n      \"ru\": \"Комнаты\",\n      \"ko\": \"방\"\n    },\n    \"children\": [\n      {\n        \"id\": \"rooms\",\n        \"type\": \"text\",\n        \"label\": {\n          \"en\": \"Rooms JSON (e.g. [{\\\"id\\\":1,\\\"name\\\":\\\"Kitchen\\\"}])\",\n          \"nl\": \"Kamers JSON\",\n          \"da\": \"Rum JSON\",\n          \"de\": \"Räume JSON\",\n          \"es\": \"Habitaciones JSON\",\n          \"fr\": \"Pièces JSON\",\n          \"it\": \"Stanze JSON\",\n          \"no\": \"Rom JSON\",\n          \"sv\": \"Rum JSON\",\n          \"pl\": \"Pokoje JSON\",\n          \"ru\": \"Комнаты JSON\",\n          \"ko\": \"방 JSON\"\n        },\n        \"hint\": {\n          \"en\": \"Manual list if auto-fetch fails. Each item requires an id and name.\",\n          \"nl\": \"Handmatige lijst als automatisch ophalen mislukt.\",\n          \"da\": \"Manuel liste hvis auto-hent fejler.\",\n          \"de\": \"Manuelle Liste, wenn Auto-Abruf fehlschlägt.\",\n          \"es\": \"Lista manual si la obtención automática falla.\",\n          \"fr\": \"Liste manuelle si l'auto-récupération échoue.\",\n          \"it\": \"Elenco manuale se l'acquisizione automatica fallisce.\",\n          \"no\": \"Manuell liste hvis auto-henting feiler.\",\n          \"sv\": \"Manuell lista om auto-hämtning misslyckas.\",\n          \"pl\": \"Lista ręczna, jeśli auto-pobieranie zawiedzie.\",\n          \"ru\": \"Список вручную, если авто-выгрузка не работает.\",\n          \"ko\": \"자동 가져오기가 실패할 경우 수동 목록.\"\n        },\n        \"value\": \"[]\"\n      },\n      {\n        \"id\": \"rooms_display\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Detected rooms\",\n          \"nl\": \"Gedetecteerde kamers\",\n          \"da\": \"Registrerede rum\",\n          \"de\": \"Erkannte Räume\",\n          \"es\": \"Habitaciones detectadas\",\n          \"fr\": \"Pièces détectées\",\n          \"it\": \"Stanze rilevate\",\n          \"no\": \"Oppdagede rom\",\n          \"sv\": \"Upptäckta rum\",\n          \"pl\": \"Wykryte pokoje\",\n          \"ru\": \"Обнаруженные комнаты\",\n          \"ko\": \"감지된 방\"\n        },\n        \"value\": \"No rooms fetched yet\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Consumables\",\n      \"nl\": \"Verbruiksartikelen\",\n      \"da\": \"Forbrugsvarer\",\n      \"de\": \"Verbrauchsmaterialien\",\n      \"es\": \"Consumibles\",\n      \"fr\": \"Consommables\",\n      \"it\": \"Consumabili\",\n      \"no\": \"Forbruksvarer\",\n      \"sv\": \"Förbrukningsvaror\",\n      \"pl\": \"Materiały eksploatacyjne\",\n      \"ru\": \"Расходные материалы\",\n      \"ko\": \"소모품\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_threshold\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Alarm threshold\",\n          \"nl\": \"Alarm ondergrens\",\n          \"da\": \"Alarmgrænse\",\n          \"de\": \"Alarmschwelle\",\n          \"es\": \"Umbral de alarma\",\n          \"fr\": \"Seuil d'alarme\",\n          \"it\": \"Soglia di allarme\",\n          \"no\": \"Alarm terskel\",\n          \"sv\": \"Alarmtröskel\",\n          \"pl\": \"Próg alarmowy\",\n          \"ru\": \"Порог тревоги\",\n          \"ko\": \"알람 임계 값\"\n        },\n        \"hint\": {\n          \"en\": \"Threshold below which the alarm will be activated.\",\n          \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n          \"da\": \"Grænse under hvilken alarmen aktiveres.\",\n          \"de\": \"Schwelle, unter der der Alarm aktiviert wird.\",\n          \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n          \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n          \"it\": \"Soglia al di sotto della quale l'allarme verrà attivato.\",\n          \"no\": \"Grensen under hvilken alarmen blir aktivert.\",\n          \"sv\": \"Tröskeln under vilken larmet aktiveras.\",\n          \"pl\": \"Próg, poniżej którego alarm zostanie aktywowany.\",\n          \"ru\": \"Порог, ниже которого будет активирована тревога.\",\n          \"ko\": \"알람이 활성화되는 임계 값\"\n        },\n        \"value\": 20,\n        \"attr\": {\n          \"min\": 1,\n          \"max\": 90\n        }\n      },\n      {\n        \"id\": \"main_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Main brush remaining (%)\",\n          \"nl\": \"Hoofdborstel over (%)\",\n          \"da\": \"Hovedbørste tilbage (%)\",\n          \"de\": \"Verbleibende Hauptbürste (%)\",\n          \"es\": \"Cepillo principal restante (%)\",\n          \"fr\": \"Brosse principale restante (%)\",\n          \"it\": \"Spazzola principale rimanente (%)\",\n          \"no\": \"Hovedbørste gjenstår (%)\",\n          \"sv\": \"Huvudborste återstående (%)\",\n          \"pl\": \"Pozostało głównej szczotki (%)\",\n          \"ru\": \"Осталось главной щетки (%)\",\n          \"ko\": \"남은 주요 브러시 (%)\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"side_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Side brush remaining\",\n          \"nl\": \"Zijborstel over\",\n          \"da\": \"Sidebørste tilbage\",\n          \"de\": \"Verbleibende Seitenbürste\",\n          \"es\": \"Cepillo lateral restante\",\n          \"fr\": \"Brosse latérale restante\",\n          \"it\": \"Spazzola laterale rimanente\",\n          \"no\": \"Sidebørste gjenstår\",\n          \"sv\": \"Sidoborste återstående\",\n          \"pl\": \"Pozostało szczotki bocznej\",\n          \"ru\": \"Осталось боковой щетки\",\n          \"ko\": \"남은 사이드 브러시\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"filter_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter remaining\",\n          \"nl\": \"Filter over\",\n          \"da\": \"Filter tilbage\",\n          \"de\": \"Verbleibender Filter\",\n          \"es\": \"Filtro restante\",\n          \"fr\": \"Filtre restant\",\n          \"it\": \"Filtro rimanente\",\n          \"no\": \"Filter gjenstår\",\n          \"sv\": \"Filter kvar\",\n          \"pl\": \"Pozostało filtra\",\n          \"ru\": \"Осталось фильтра\",\n          \"ko\": \"남은 필터\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"total_work_time\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Total work time (h)\",\n          \"nl\": \"Totale gebruikstijd (u)\",\n          \"da\": \"Samlet arbejdstid (t)\",\n          \"de\": \"Gesamtarbeitszeit (h)\",\n          \"es\": \"Tiempo total de trabajo (h)\",\n          \"fr\": \"Temps de travail total (h)\",\n          \"it\": \"Tempo di lavoro totale (h)\",\n          \"no\": \"Total arbeidstid (t)\",\n          \"sv\": \"Total arbetstid (h)\",\n          \"pl\": \"Całkowity czas pracy (h)\",\n          \"ru\": \"Общее время работы (ч)\",\n          \"ko\": \"총 작업 시간 (h)\"\n        },\n        \"value\": 0,\n        \"attr\": {\n          \"min\": 0,\n          \"step\": 0.1\n        }\n      },\n      {\n        \"id\": \"total_cleared_area\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Total cleaned area (m²)\",\n          \"nl\": \"Totaal geschoont (m²)\",\n          \"da\": \"Samlet rengjort område (m²)\",\n          \"de\": \"Gesamt gereinigte Fläche (m²)\",\n          \"es\": \"Área total limpia (m²)\",\n          \"fr\": \"Surface totale nettoyée (m²)\",\n          \"it\": \"Area totale pulita (m²)\",\n          \"no\": \"Totalt rengjort område (m²)\",\n          \"sv\": \"Totalt rengjort område (m²)\",\n          \"pl\": \"Całkowita oczyszczona powierzchnia (m²)\",\n          \"ru\": \"Общая очищенная площадь (м²)\",\n          \"ko\": \"총 청소 면적 (m²)\"\n        },\n        \"value\": 0,\n        \"attr\": {\n          \"min\": 0,\n          \"step\": 0.1\n        }\n      },\n      {\n        \"id\": \"total_clean_count\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Total clean count\",\n          \"nl\": \"Totaal aantal opschoningen\",\n          \"da\": \"Samlet rengøringsantal\",\n          \"de\": \"Gesamt Reinigungsanzahl\",\n          \"es\": \"Conteo total de limpiezas\",\n          \"fr\": \"Nombre total de nettoyages\",\n          \"it\": \"Conteggio totale pulizie\",\n          \"no\": \"Total rengjøringsteller\",\n          \"sv\": \"Totalstädningsräkning\",\n          \"pl\": \"Całkowita liczba sprzątań\",\n          \"ru\": \"Общее количество уборок\",\n          \"ko\": \"총 청소 횟수\"\n        },\n        \"value\": 0,\n        \"attr\": {\n          \"min\": 0,\n          \"step\": 1\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device data\",\n      \"nl\": \"Apparaat data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"장치 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"error\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Error\",\n          \"nl\": \"Error\",\n          \"da\": \"Fejl\",\n          \"de\": \"Fehler\",\n          \"es\": \"Error\",\n          \"fr\": \"Erreur\",\n          \"it\": \"Errore\",\n          \"no\": \"Feil\",\n          \"sv\": \"Fel\",\n          \"pl\": \"Błąd\",\n          \"ru\": \"Ошибка\",\n          \"ko\": \"오류\"\n        },\n        \"value\": \"No error\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_max/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_max/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_max/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_miot/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/xiaomi.vacuum.b112gl\n// https://home.miot-spec.com/spec/xiaomi.vacuum.b106eu\n// https://home.miot-spec.com/spec/xiaomi.vacuum.b112\n// https://home.miot-spec.com/spec/xiaomi.vacuum.c101\n// https://home.miot-spec.com/spec/xiaomi.vacuum.c102gl // Xiaomi Robot Vacuum X20+\n\nconst mapping = {\n    'xiaomi.vacuum.b112gl': 'properties_default',\n    'xiaomi.vacuum.b106eu': 'properties_default',\n    'xiaomi.vacuum.b112': 'properties_default',\n    'xiaomi.vacuum.c101': 'properties_c101',\n    'xiaomi.vacuum.c102gl': 'properties_c102',\n    'xiaomi.vacuum.*': 'properties_default'\n};\n\nconst properties = {\n    properties_default: {\n        get_properties: [\n            { did: 'device_status', siid: 2, piid: 1 }, // vacuumcleaner_state\n            { did: 'device_fault', siid: 2, piid: 2 }, // settings.error\n            { did: 'mode', siid: 2, piid: 4 }, // vacuum_xiaomi_mop_mode\n            { did: 'battery', siid: 3, piid: 1 }, // measure_battery\n            { did: 'main_brush_life_level', siid: 7, piid: 10 }, // settings.main_brush_work_time\n            { did: 'side_brush_life_level', siid: 7, piid: 8 }, // settings.side_brush_work_time\n            { did: 'filter_life_level', siid: 7, piid: 12 }, // settings.filter_work_time\n            { did: 'total_clean_time', siid: 7, piid: 28 }, // settings.total_work_time\n            { did: 'total_clean_count', siid: 7, piid: 22 }, // settings.clean_count\n            { did: 'total_clean_area', siid: 7, piid: 29 } // settings.total_cleared_area\n        ],\n        set_properties: {\n            start_clean: { siid: 2, aiid: 1, did: 'call-2-1', in: [] },\n            stop_clean: { siid: 2, aiid: 2, did: 'call-2-2', in: [] },\n            find: { siid: 6, aiid: 6, did: 'call-6-6', in: [] },\n            home: { siid: 3, aiid: 1, did: 'call-3-1', in: [] },\n            mopmode: { siid: 2, piid: 4 }\n        },\n        error_codes: {\n            0: 'Everything-is-ok',\n            1: 'Left-wheel-error',\n            2: 'Right-wheel-error',\n            3: 'Cliff-error',\n            4: 'Low-battery-error',\n            5: 'Bump-error',\n            6: 'Main-brush-error',\n            7: 'Side-brush-error',\n            8: 'Fan-motor-error',\n            9: 'Dustbin-error',\n            10: 'Charging-error',\n            11: 'No-water-error',\n            12: 'Pick-up-error'\n        },\n        status_mapping: {\n            cleaning: [3, 5, 6, 7],\n            spot_cleaning: [],\n            docked: [0],\n            charging: [4],\n            stopped: [1, 2, 8],\n            stopped_error: []\n        }\n    },\n    properties_c101: {\n        get_properties: [\n            { did: 'device_status', siid: 2, piid: 1 }, // vacuumcleaner_state\n            { did: 'device_fault', siid: 2, piid: 2 }, // settings.error\n            { did: 'mode', siid: 2, piid: 4 }, // vacuum_xiaomi_mop_mode\n            { did: 'battery', siid: 3, piid: 1 }, // measure_battery\n            { did: 'main_brush_life_level', siid: 16, piid: 1 }, // settings.main_brush_work_time\n            { did: 'side_brush_life_level', siid: 17, piid: 1 }, // settings.side_brush_work_time\n            { did: 'filter_life_level', siid: 15, piid: 1 }, // settings.filter_work_time\n            { did: 'total_clean_time', siid: 7, piid: 28 }, // settings.total_work_time\n            { did: 'total_clean_count', siid: 7, piid: 22 }, // settings.clean_count\n            { did: 'total_clean_area', siid: 7, piid: 29 } // settings.total_cleared_area\n        ],\n        set_properties: {\n            start_clean: { siid: 2, aiid: 1, did: 'call-2-1', in: [] },\n            stop_clean: { siid: 2, aiid: 2, did: 'call-2-2', in: [] },\n            find: { siid: 6, aiid: 6, did: 'call-6-6', in: [] },\n            home: { siid: 3, aiid: 1, did: 'call-3-1', in: [] },\n            mopmode: { siid: 2, piid: 4 }\n        },\n        error_codes: {\n            0: 'No Error',\n            1: 'Left-wheel-error',\n            2: 'Right-wheel-error',\n            3: 'Cliff-error',\n            4: 'Low-battery-error',\n            5: 'Bump-error',\n            6: 'Main-brush-error',\n            7: 'Side-brush-error',\n            8: 'Fan-motor-error',\n            9: 'Dustbin-error',\n            10: 'Charging-error',\n            11: 'No-water-error',\n            0: 'Everything-is-ok',\n            12: 'Pick-up-error'\n        },\n        status_mapping: {\n            cleaning: [3, 5, 6, 7],\n            spot_cleaning: [],\n            docked: [0, 9, 10, 11, 12],\n            charging: [4],\n            stopped: [1, 2, 8],\n            stopped_error: []\n        }\n    },\n    properties_c102: {\n        get_properties: [\n            { did: 'device_status', siid: 2, piid: 1 }, // vacuumcleaner_state\n            { did: 'device_fault', siid: 2, piid: 2 }, // settings.error\n            { did: 'mode', siid: 2, piid: 3 }, // vacuum_xiaomi_mop_mode\n            { did: 'battery', siid: 3, piid: 1 }, // measure_battery\n            { did: 'main_brush_life_level', siid: 9, piid: 2 }, // settings.main_brush_work_level\n            { did: 'side_brush_life_level', siid: 10, piid: 2 }, // settings.side_brush_work_level\n            { did: 'filter_life_level', siid: 11, piid: 1 }, // settings.filter_work_level\n            { did: 'total_clean_time', siid: 12, piid: 2 }, // settings.total_work_time\n            { did: 'total_clean_count', siid: 12, piid: 3 }, // settings.clean_count\n            { did: 'total_clean_area', siid: 12, piid: 4 } // settings.total_cleared_area\n        ],\n        set_properties: {\n            start_clean: { siid: 2, aiid: 1, did: 'call-2-1', in: [] },\n            stop_clean: { siid: 2, aiid: 2, did: 'call-2-2', in: [] },\n            find: { siid: 7, aiid: 2, did: 'call-7-2', in: [] },\n            home: { siid: 3, aiid: 1, did: 'call-3-1', in: [] },\n            mopmode: { siid: 2, piid: 6 }\n        },\n        error_codes: {\n            0: 'Everything-is-ok',\n            1: 'Left-wheel-error',\n            2: 'Right-wheel-error',\n            3: 'Cliff-error',\n            4: 'Low-battery-error',\n            5: 'Bump-error',\n            6: 'Main-brush-error',\n            7: 'Side-brush-error',\n            8: 'Fan-motor-error',\n            9: 'Dustbin-error',\n            10: 'Charging-error',\n            11: 'No-water-error',\n            12: 'Pick-up-error'\n        },\n        status_mapping: {\n            cleaning: [1, 5, 7, 8, 9, 10, 12],\n            spot_cleaning: [],\n            docked: [0, 11, 13, 14, 19],\n            charging: [6],\n            stopped: [2, 3, 21, 22, 23],\n            stopped_error: [4]\n        }\n    }\n};\n\nclass XiaomiVacuumMiotDevice extends Device {\n    async onInit() {\n        try {\n            if (!this.util) this.util = new Util({ homey: this.homey });\n\n            // GENERIC DEVICE INIT ACTIONS\n            this.bootSequence();\n\n            // ADD/REMOVE DEVICES DEPENDANT CAPABILITIES\n\n            // Device-specific logic - currently for xiaomi.vacuum.c102gl only as generic logic is using slighly different calcalutions\n            if (this.getStoreValue('model') === 'xiaomi.vacuum.c102gl') {\n                this.log('Using custom vacuumTotals and custom vacuumConsumables method for xiaomi.vacuum.c102gl');\n                this.vacuumTotals = this.customVacuumTotals; // Override method dynamically\n                this.vacuumConsumables = this.customVacuumConsumables; // Override method dynamically\n            }\n\n            // DEVICE VARIABLES\n            this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined ? properties[mapping[this.getStoreValue('model')]] : properties[mapping['xiaomi.vacuum.*']];\n\n            // RESET CONSUMABLE ALARMS\n            this.updateCapabilityValue('alarm_main_brush_work_time', false);\n            this.updateCapabilityValue('alarm_side_brush_work_time', false);\n            this.updateCapabilityValue('alarm_filter_work_time', false);\n\n            // DEVICE TOKENS\n            this.main_brush_lifetime_token = await this.homey.flow.createToken('main_brush_lifetime' + this.getData().id, { type: 'number', title: 'Main Brush Lifetime ' + this.getName() + ' (%)' }).catch((error) => {\n                this.error(error);\n            });\n            this.side_brush_lifetime_token = await this.homey.flow.createToken('side_brush_lifetime' + this.getData().id, { type: 'number', title: 'Side Brush Lifetime ' + this.getName() + ' (%)' }).catch((error) => {\n                this.error(error);\n            });\n            this.filter_lifetime_token = await this.homey.flow.createToken('filter_lifetime' + this.getData().id, { type: 'number', title: 'Filter LifeTime ' + this.getName() + ' (%)' }).catch((error) => {\n                this.error(error);\n            });\n            this.total_work_time_token = await this.homey.flow.createToken('total_work_time' + this.getData().id, { type: 'number', title: 'Total Work Time ' + this.getName() + ' h)' }).catch((error) => {\n                this.error(error);\n            });\n            this.total_cleared_area_token = await this.homey.flow.createToken('total_cleared_area' + this.getData().id, { type: 'number', title: 'Total Cleaned Area ' + this.getName() + ' (m2)' }).catch((error) => {\n                this.error(error);\n            });\n            this.total_clean_count_token = await this.homey.flow.createToken('total_clean_count' + this.getData().id, { type: 'number', title: 'Total Clean Count ' + this.getName() }).catch((error) => {\n                this.error(error);\n            });\n\n            // FLOW TRIGGER CARDS\n            this.homey.flow.getDeviceTriggerCard('alertVacuum');\n            this.homey.flow.getDeviceTriggerCard('statusVacuum');\n            // not implemented\n            //this.homey.flow.getDeviceTriggerCard('triggerVacuumRoomSegments');\n\n            // LISTENERS FOR UPDATING CAPABILITIES\n            this.registerCapabilityListener('onoff', async (value) => {\n                try {\n                    if (this.miio) {\n                        if (value) {\n                            return await this.miio.call('action', this.deviceProperties.set_properties.start_clean, { retries: 1 });\n                        } else {\n                            return await this.miio.call('action', this.deviceProperties.set_properties.stop_clean, { retries: 1 });\n                        }\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            this.registerCapabilityListener('vacuumcleaner_state', async (value) => {\n                try {\n                    if (this.miio) {\n                        switch (value) {\n                            case 'cleaning':\n                            case 'spot_cleaning':\n                                return await this.triggerCapabilityListener('onoff', true);\n                            case 'docked':\n                            case 'charging':\n                                return await this.miio.call('action', this.deviceProperties.set_properties.home, { retries: 1 });\n                            case 'stopped':\n                                return await this.triggerCapabilityListener('onoff', false);\n                        }\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            /* vacuumcleaner dreame fanspeed */\n            this.registerCapabilityListener('vacuum_dreame_fanspeed', async (value) => {\n                try {\n                    if (this.miio) {\n                        return await this.miio.call('set_properties', [{ siid: this.deviceProperties.set_properties.fanspeed.siid, piid: this.deviceProperties.set_properties.fanspeed.piid, value: Number(value) }], { retries: 1 });\n                    } else {\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n\n            /* vacuumcleaner xiaomi mop mode */\n            this.registerCapabilityListener('vacuum_xiaomi_mop_mode', async (value) => {\n                try {\n                    // Existing code, do not remove:\n                    const numericValue = Number(value); // Ensure value is treated as a number\n                    this.log(`Received mop mode value: ${value} (type: ${typeof value}), Converted: ${numericValue}`);\n\n                    // Default to original numeric value for non-c102gl models\n                    let adjustedValue = numericValue;\n\n                    // Outbound (setting to the vacuum) mapping ONLY if model is xiaomi.vacuum.c102gl\n                    if (this.getStoreValue('model') === 'xiaomi.vacuum.c102gl') {\n                        // Example: device sees 0 => Mop & Sweep, 1 => Mop, 2 => Sweep\n                        // but our JSON is 0 => Sweep, 1 => Sweep & Mop, 2 => Mop\n                        // We'll invert them as needed. \n                        const mapOutboundMopMode = (homeyValue) => {\n                            switch (homeyValue) {\n                                case 0: // Homey 0 => \"Sweep\"\n                                    return 2; // Device wants 2 => \"Sweep\"\n                                case 1: // Homey 1 => \"Sweep & Mop\"\n                                    return 0; // Device wants 0 => \"Sweep & Mop\"\n                                case 2: // Homey 2 => \"Mop\"\n                                    return 1; // Device wants 1 => \"Mop\"\n                                default:\n                                    return 2; // fallback, or pick something safe\n                            }\n                        };\n                        const mapped = mapOutboundMopMode(numericValue);\n                        this.log(`(c102gl) Outbound remap: Homey value=${numericValue} => deviceValue=${mapped}`);\n                        adjustedValue = mapped;\n                    }\n\n                    if (this.miio) {\n                        return await this.miio.call(\n                            'set_properties',\n                            [\n                                {\n                                    siid: this.deviceProperties.set_properties.mopmode.siid,\n                                    piid: this.deviceProperties.set_properties.mopmode.piid,\n                                    value: adjustedValue\n                                }\n                            ],\n                            { retries: 1 }\n                        );\n                    } else {\n                        // Handle device unreachable scenario\n                        this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                            this.error(error);\n                        });\n                        this.createDevice();\n                        return Promise.reject('Device unreachable, please try again ...');\n                    }\n                } catch (error) {\n                    this.error(error);\n                    return Promise.reject(error);\n                }\n            });\n        } catch (error) {\n            this.error(error);\n        }\n    }\n\n    async retrieveDeviceData() {\n        try {\n            const result = await this.miio.call('get_properties', this.deviceProperties.get_properties, { retries: 1 });\n            if (!this.getAvailable()) {\n                await this.setAvailable();\n            }\n\n            // debug purposes only\n            //this.log('Raw property data:', result);\n\n            //temporary debug !!!\n            //const resultmop = await this.miio.call('get_properties', [{ siid: 2, piid: 6 }], { retries: 1 });\n            //this.log('Supported mop mode values:', resultmop);\n            //this.log('Device Properties:', this.deviceProperties);\n            //this.log('Status Mapping:', this.deviceProperties.status_mapping);\n            //this.log('Device Status Value:', device_status.value);\n\n            //temporary debug !!!\n            /*\n            try {\n                this.log('Starting full property scan...');\n    \n                const results = [];\n                \n                // Iterate over a reasonable range of SIIDs and PIIDs\n                for (let siid = 1; siid <= 18; siid++) {\n                    for (let piid = 1; piid <= 50; piid++) {\n                        try {\n                            // Attempt to fetch property for the current SIID and PIID\n                            const response = await this.miio.call('get_properties', [{ siid, piid }], { retries: 1 });\n                            \n                            // Log successful responses and add them to results\n                            if (response && response.length > 0 && response[0].code === 0) {\n                                this.log(`Fetched property SIID ${siid}, PIID ${piid}:`, JSON.stringify(response[0]));\n                                results.push(response[0]);\n                            }\n                        } catch (error) {\n                            // Ignore errors for invalid SIID/PIID combinations\n                            this.log(`SIID ${siid}, PIID ${piid} not accessible.`);\n                        }\n                    }\n                }\n    \n                // Log all successfully fetched properties\n                this.log('Complete property scan result:', JSON.stringify(results, null, 2));\n    \n            } catch (error) {\n                this.error('Error during full property scan:', error);\n            } */\n\n            /* data */\n            const device_status = result.find((obj) => obj.did === 'device_status');\n            const mop_mode = result.find((obj) => obj.did === 'mode');\n            const battery = result.find((obj) => obj.did === 'battery');\n            const fan_speed = result.find((obj) => obj.did === 'fan_speed');\n            const main_brush_life_level = result.find((obj) => obj.did === 'main_brush_life_level');\n            const side_brush_life_level = result.find((obj) => obj.did === 'side_brush_life_level');\n            const filter_life_level = result.find((obj) => obj.did === 'filter_life_level');\n            const total_clean_time = result.find((obj) => obj.did === 'total_clean_time');\n            const total_clean_count = result.find((obj) => obj.did === 'total_clean_count');\n            const total_clean_area = result.find((obj) => obj.did === 'total_clean_area');\n            const device_fault = result.find((obj) => obj.did === 'device_fault');\n\n            const consumables = [\n                {\n                    main_brush_work_time: main_brush_life_level.value,\n                    side_brush_work_time: side_brush_life_level.value,\n                    filter_work_time: filter_life_level.value\n                }\n            ];\n\n            const totals = {\n                clean_time: total_clean_time.value,\n                clean_count: total_clean_count.value,\n                clean_area: total_clean_area.value\n            };\n\n            /* onoff & vacuumcleaner_state */\n            let matched = false;\n\n            for (let key in this.deviceProperties.status_mapping) {\n                if (this.deviceProperties.status_mapping[key].includes(device_status.value)) {\n                    matched = true;\n                    if (this.getCapabilityValue('measure_battery') === 100 && (key === 'stopped' || key === 'charging')) {\n                        this.vacuumCleanerState('docked');\n                    } else {\n                        this.vacuumCleanerState(key);\n                    }\n                    break; // Exit the loop once a match is found - it was causing errors previously\n                }\n            }\n\n            if (!matched) {\n                this.log('Not a valid vacuumcleaner_state (driver level)', device_status.value);\n            }\n\n            /* measure_battery & alarm_battery */\n            await this.updateCapabilityValue('measure_battery', battery.value);\n            await this.updateCapabilityValue('alarm_battery', battery.value <= 20 ? true : false);\n\n            /* vacuum_dreame_fanspeed */\n            if (fan_speed !== undefined && this.hasCapability('vacuum_dreame_fanspeed')) {\n                await this.updateCapabilityValue('vacuum_dreame_fanspeed', fan_speed.value.toString());\n            }\n\n            /* vacuum_xiaomi_mop_mode */\n            // Original code\n            let finalMopModeValue = mop_mode.value;\n\n            // Inbound (getting status from Vacuum) mapping ONLY if model is c102gl\n            if (this.getStoreValue('model') === 'xiaomi.vacuum.c102gl') {\n                const deviceVal = device_status.value;\n                const mapInboundMopMode = (statusVal) => {\n                    switch (statusVal) {\n                        case 1: // Sweeping\n                            return 0; // Homey’s \"0\" => Sweep\n                        case 7: // Mopping\n                            return 2; // Homey’s \"2\" => Mop\n                        case 12: // Sweeping & Mopping\n                            return 1; // Homey’s \"1\" => Sweep & Mop\n                        default:\n                            // fallback: pick \"0\" => Sweep if unknown\n                            return 0;\n                    }\n                };\n\n                finalMopModeValue = mapInboundMopMode(deviceVal);\n                this.log(`(c102gl) inbound statusVal=${deviceVal}, mapped to Homey mop mode=${finalMopModeValue}`);\n            }\n\n            // Now set the capability with finalMopModeValue\n            await this.updateCapabilityValue('vacuum_xiaomi_mop_mode', finalMopModeValue.toString());\n            \n            /* consumable settings */\n            this.vacuumConsumables(consumables);\n\n            /* totals */\n            this.vacuumTotals(totals);\n\n            /* settings device error */\n            const error = this.deviceProperties.error_codes[device_fault.value];\n            // If the lookup failed, error is undefined. Provide a fallback string:\n            let safeError = typeof error === 'string' ? error : 'Unknown Error';\n            if (this.getSetting('error') !== error) {\n                await this.setSettings({ error: error });\n                if (error !== 0) {\n                    await this.homey.flow\n                        .getDeviceTriggerCard('statusVacuum')\n                        .trigger(this, { status: safeError })\n                        .catch((error) => {\n                            this.error(error);\n                        });\n                }\n            }\n        } catch (error) {\n            this.homey.clearInterval(this.pollingInterval);\n\n            if (this.getAvailable()) {\n                this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((error) => {\n                    this.error(error);\n                });\n            }\n\n            this.homey.setTimeout(() => {\n                this.createDevice();\n            }, 60000);\n\n            this.error(error.message);\n        }\n    }\n\n    /* Custom vacuumTotals for xiaomi.vacuum.c102gl */\n    async customVacuumTotals(totals) {\n        try {\n            let worktime = 0;\n            let cleared_area = 0;\n            let clean_count = 0;\n\n            // Use correct properties for the totals\n            if (totals.hasOwnProperty('clean_time')) {\n                worktime = totals.clean_time;\n                cleared_area = totals.clean_area;\n                clean_count = totals.clean_count;\n            } else {\n                worktime = totals[0];\n                cleared_area = totals[1];\n                clean_count = totals[2];\n            }\n\n            /* Corrected total_work_time calculation */\n            const total_work_time_value = Math.round(worktime / 60); // Convert minutes to hours\n            const total_work_time = total_work_time_value + ' h';\n            if (this.getSetting('total_work_time') !== total_work_time) {\n                await this.setSettings({ total_work_time: total_work_time });\n                await this.total_work_time_token.setValue(total_work_time_value);\n            }\n\n            /* Corrected total_cleared_area calculation */\n            const total_cleared_area_value = cleared_area; // Already in m²\n            const total_cleared_area = total_cleared_area_value + ' m2';\n            if (this.getSetting('total_cleared_area') !== total_cleared_area) {\n                await this.setSettings({ total_cleared_area: total_cleared_area });\n                await this.total_cleared_area_token.setValue(total_cleared_area_value);\n            }\n\n            /* Corrected total_clean_count */\n            if (this.getSetting('total_clean_count') !== clean_count) {\n                await this.setSettings({ total_clean_count: String(clean_count) });\n                await this.total_clean_count_token.setValue(clean_count);\n            }\n\n            /* Initial token updates */\n            if (!this.initialTokenTotal || this.initialTokenTotal == undefined) {\n                await this.total_work_time_token.setValue(total_work_time_value);\n                await this.total_cleared_area_token.setValue(total_cleared_area_value);\n                await this.total_clean_count_token.setValue(clean_count);\n                this.initialTokenTotal = true;\n            }\n        } catch (error) {\n            this.error('Custom vacuumTotals error:', error);\n        }\n    }\n\n    /* Custom VacuumConsumables for xiaomi.vacuum.c102gl */\n\n    async customVacuumConsumables(consumables) {\n        try {\n            let main_brush_remaining_value = 0;\n            let side_brush_remaining_value = 0;\n            let filter_remaining_value = 0;\n\n            // debug purposes only\n            // this.log('Consumables input:', JSON.stringify(consumables));\n\n            if (Array.isArray(consumables) && consumables.length > 0) {\n                const data = consumables[0];\n\n                /* main_brush_work_time */\n                if (data.hasOwnProperty('main_brush_work_time')) {\n                    main_brush_remaining_value = data.main_brush_work_time;\n                    const main_brush_remaining = main_brush_remaining_value + '%';\n\n                    if (this.getSetting('main_brush_work_time') !== main_brush_remaining) {\n                        await this.setSettings({ main_brush_work_time: main_brush_remaining });\n                        await this.main_brush_lifetime_token.setValue(main_brush_remaining_value);\n                    }\n\n                    if (main_brush_remaining_value < this.getSetting('alarm_threshold') && !this.getCapabilityValue('alarm_main_brush_work_time')) {\n                        this.log('Triggering alarm for main brush...');\n                        await this.updateCapabilityValue('alarm_main_brush_work_time', true);\n                        await this.homey.flow\n                            .getDeviceTriggerCard('alertVacuum')\n                            .trigger(this, { consumable: 'Main Brush', value: main_brush_remaining })\n                            .catch((error) => this.error('Error triggering alert for main brush:', error));\n                    } else if (main_brush_remaining_value > this.getSetting('alarm_threshold') && this.getCapabilityValue('alarm_main_brush_work_time')) {\n                        this.log('Clearing alarm for main brush...');\n                        this.updateCapabilityValue('alarm_main_brush_work_time', false);\n                    }\n                } else {\n                    this.log('main_brush_work_time not found in consumables.');\n                }\n\n                /* side_brush_work_time */\n                if (data.hasOwnProperty('side_brush_work_time')) {\n                    side_brush_remaining_value = data.side_brush_work_time;\n                    const side_brush_remaining = side_brush_remaining_value + '%';\n\n                    if (this.getSetting('side_brush_work_time') !== side_brush_remaining) {\n                        await this.setSettings({ side_brush_work_time: side_brush_remaining });\n                        await this.side_brush_lifetime_token.setValue(side_brush_remaining_value);\n                    }\n\n                    if (side_brush_remaining_value < this.getSetting('alarm_threshold') && !this.getCapabilityValue('alarm_side_brush_work_time')) {\n                        this.log('Triggering alarm for side brush...');\n                        await this.updateCapabilityValue('alarm_side_brush_work_time', true);\n                        await this.homey.flow\n                            .getDeviceTriggerCard('alertVacuum')\n                            .trigger(this, { consumable: 'Side Brush', value: side_brush_remaining })\n                            .catch((error) => this.error('Error triggering alert for side brush:', error));\n                    } else if (side_brush_remaining_value > this.getSetting('alarm_threshold') && this.getCapabilityValue('alarm_side_brush_work_time')) {\n                        this.log('Clearing alarm for side brush...');\n                        this.updateCapabilityValue('alarm_side_brush_work_time', false);\n                    }\n                } else {\n                    this.log('side_brush_work_time not found in consumables.');\n                }\n\n                /* filter_work_time */\n                if (data.hasOwnProperty('filter_work_time')) {\n                    filter_remaining_value = data.filter_work_time;\n                    const filter_remaining = filter_remaining_value + '%';\n\n                    if (this.getSetting('filter_work_time') !== filter_remaining) {\n                        await this.setSettings({ filter_work_time: filter_remaining });\n                        await this.filter_lifetime_token.setValue(filter_remaining_value);\n                    }\n\n                    if (filter_remaining_value < this.getSetting('alarm_threshold') && !this.getCapabilityValue('alarm_filter_work_time')) {\n                        this.log('Triggering alarm for filter...');\n                        await this.updateCapabilityValue('alarm_filter_work_time', true);\n                        await this.homey.flow\n                            .getDeviceTriggerCard('alertVacuum')\n                            .trigger(this, { consumable: 'Filter', value: filter_remaining })\n                            .catch((error) => this.error('Error triggering alert for filter:', error));\n                    } else if (filter_remaining_value > this.getSetting('alarm_threshold') && this.getCapabilityValue('alarm_filter_work_time')) {\n                        this.log('Clearing alarm for filter...');\n                        this.updateCapabilityValue('alarm_filter_work_time', false);\n                    }\n                } else {\n                    this.log('filter_work_time not found in consumables.');\n                }\n\n                /* initial update tokens */\n                if (!this.initialTokenConsumable || this.initialTokenConsumable === undefined) {\n                    await this.main_brush_lifetime_token.setValue(main_brush_remaining_value);\n                    await this.side_brush_lifetime_token.setValue(side_brush_remaining_value);\n                    await this.filter_lifetime_token.setValue(filter_remaining_value);\n                    this.initialTokenConsumable = true;\n                }\n            } else {\n                this.log('Consumables array is empty or invalid.');\n            }\n        } catch (error) {\n            this.error('Error in customVacuumConsumables:', error);\n        }\n    }\n}\n\nmodule.exports = XiaomiVacuumMiotDevice;\n"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Xiaomi Vacuum Cleaner MIoT (WiFi)\",\n    \"nl\": \"Xiaomi stofzuiger MIoT (WiFi)\",\n    \"da\": \"Xiaomi Støvsuger MIoT (WiFi)\",\n    \"de\": \"Xiaomi Staubsauger MIoT (WiFi)\",\n    \"es\": \"Aspiradora Xiaomi MIoT (WiFi)\",\n    \"fr\": \"Aspirateur Xiaomi MIoT (WiFi)\",\n    \"it\": \"Aspirapolvere Xiaomi MIoT (WiFi)\",\n    \"no\": \"Xiaomi Støvsuger MIoT (WiFi)\",\n    \"sv\": \"Xiaomi Dammsugare MIoT (WiFi)\",\n    \"pl\": \"Odkurzacz Xiaomi MIoT (WiFi)\",\n    \"ru\": \"Пылесос Xiaomi MIoT (WiFi)\",\n    \"ko\": \"샤오미 진공 청소기 MIoT (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/vacuum_xiaomi_vacuum_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/vacuum_xiaomi_vacuum_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"vacuumcleaner\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"vacuumcleaner_state\",\n    \"vacuum_xiaomi_mop_mode\",\n    \"measure_battery\",\n    \"alarm_battery\",\n    \"alarm_main_brush_work_time\",\n    \"alarm_side_brush_work_time\",\n    \"alarm_filter_work_time\"\n  ],\n  \"energy\": {\n    \"batteries\": [\n      \"INTERNAL\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass XiaomiVacuumMiotDriver extends Driver {}\n\nmodule.exports = XiaomiVacuumMiotDriver;"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Consumables\",\n      \"nl\": \"Verbruiksartikelen\",\n      \"da\": \"Forbrugsvarer\",\n      \"de\": \"Verbrauchsmaterialien\",\n      \"es\": \"Consumibles\",\n      \"fr\": \"Consommables\",\n      \"it\": \"Consumabili\",\n      \"no\": \"Forbruksvarer\",\n      \"sv\": \"Förbrukningsvaror\",\n      \"pl\": \"Materiały eksploatacyjne\",\n      \"ru\": \"Расходные материалы\",\n      \"ko\": \"소모품\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_threshold\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Alarm threshold\",\n          \"nl\": \"Alarm ondergrens\",\n          \"da\": \"Alarmgrænse\",\n          \"de\": \"Alarmschwelle\",\n          \"es\": \"Umbral de alarma\",\n          \"fr\": \"Seuil d'alarme\",\n          \"it\": \"Soglia di allarme\",\n          \"no\": \"Alarm terskel\",\n          \"sv\": \"Alarmtröskel\",\n          \"pl\": \"Próg alarmowy\",\n          \"ru\": \"Порог тревоги\",\n          \"ko\": \"알람 임계 값\"\n        },\n        \"hint\": {\n          \"en\": \"Threshold below which the alarm will be activated.\",\n          \"nl\": \"Ondergrens voor het triggeren van het alarm\",\n          \"da\": \"Grænse under hvilken alarmen aktiveres.\",\n          \"de\": \"Schwelle, unter der der Alarm aktiviert wird.\",\n          \"es\": \"Umbral por debajo del cual se activará la alarma.\",\n          \"fr\": \"Seuil en dessous duquel l'alarme sera activée.\",\n          \"it\": \"Soglia al di sotto della quale l'allarme verrà attivato.\",\n          \"no\": \"Grensen under hvilken alarmen blir aktivert.\",\n          \"sv\": \"Tröskeln under vilken larmet aktiveras.\",\n          \"pl\": \"Próg, poniżej którego alarm zostanie aktywowany.\",\n          \"ru\": \"Порог, ниже которого будет активирована тревога.\",\n          \"ko\": \"알람이 활성화되는 임계 값\"\n        },\n        \"value\": 20,\n        \"attr\": {\n          \"min\": 1,\n          \"max\": 90\n        }\n      },\n      {\n        \"id\": \"main_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Main brush remaining (%)\",\n          \"nl\": \"Hoofdborstel over (%)\",\n          \"da\": \"Hovedbørste tilbage (%)\",\n          \"de\": \"Verbleibende Hauptbürste (%)\",\n          \"es\": \"Cepillo principal restante (%)\",\n          \"fr\": \"Brosse principale restante (%)\",\n          \"it\": \"Spazzola principale rimanente (%)\",\n          \"no\": \"Hovedbørste gjenstår (%)\",\n          \"sv\": \"Huvudborste återstående (%)\",\n          \"pl\": \"Pozostało głównej szczotki (%)\",\n          \"ru\": \"Осталось главной щетки (%)\",\n          \"ko\": \"남은 주요 브러시 (%)\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"side_brush_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Side brush remaining\",\n          \"nl\": \"Zijborstel over\",\n          \"da\": \"Sidebørste tilbage\",\n          \"de\": \"Verbleibende Seitenbürste\",\n          \"es\": \"Cepillo lateral restante\",\n          \"fr\": \"Brosse latérale restante\",\n          \"it\": \"Spazzola laterale rimanente\",\n          \"no\": \"Sidebørste gjenstår\",\n          \"sv\": \"Sidoborste återstående\",\n          \"pl\": \"Pozostało szczotki bocznej\",\n          \"ru\": \"Осталось боковой щетки\",\n          \"ko\": \"남은 사이드 브러시\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"filter_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Filter remaining\",\n          \"nl\": \"Filter over\",\n          \"da\": \"Filter tilbage\",\n          \"de\": \"Verbleibender Filter\",\n          \"es\": \"Filtro restante\",\n          \"fr\": \"Filtre restant\",\n          \"it\": \"Filtro rimanente\",\n          \"no\": \"Filter gjenstår\",\n          \"sv\": \"Filter kvar\",\n          \"pl\": \"Pozostało filtra\",\n          \"ru\": \"Осталось фильтра\",\n          \"ko\": \"남은 필터\"\n        },\n        \"value\": \"0%\"\n      },\n      {\n        \"id\": \"total_work_time\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total work time\",\n          \"nl\": \"Totale gebruikstijd\",\n          \"da\": \"Samlet arbejdstid\",\n          \"de\": \"Gesamtarbeitszeit\",\n          \"es\": \"Tiempo total de trabajo\",\n          \"fr\": \"Temps de travail total\",\n          \"it\": \"Tempo di lavoro totale\",\n          \"no\": \"Total arbeidstid\",\n          \"sv\": \"Total arbetstid\",\n          \"pl\": \"Całkowity czas pracy\",\n          \"ru\": \"Общее время работы\",\n          \"ko\": \"총 작업 시간\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"total_cleared_area\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total cleaned area\",\n          \"nl\": \"Totaal geschoont\",\n          \"da\": \"Samlet rengjort område\",\n          \"de\": \"Gesamt gereinigte Fläche\",\n          \"es\": \"Área total limpia\",\n          \"fr\": \"Surface totale nettoyée\",\n          \"it\": \"Area totale pulita\",\n          \"no\": \"Totalt rengjort område\",\n          \"sv\": \"Totalt rengjort område\",\n          \"pl\": \"Całkowita oczyszczona powierzchnia\",\n          \"ru\": \"Общая очищенная площадь\",\n          \"ko\": \"총 청소 면적\"\n        },\n        \"value\": \"0\"\n      },\n      {\n        \"id\": \"total_clean_count\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Total clean count\",\n          \"nl\": \"Totaal aantal opschoningen\",\n          \"da\": \"Samlet rengøringsantal\",\n          \"de\": \"Gesamt Reinigungsanzahl\",\n          \"es\": \"Conteo total de limpiezas\",\n          \"fr\": \"Nombre total de nettoyages\",\n          \"it\": \"Conteggio totale pulizie\",\n          \"no\": \"Total rengjøringsteller\",\n          \"sv\": \"Totalstädningsräkning\",\n          \"pl\": \"Całkowita liczba sprzątań\",\n          \"ru\": \"Общее количество уборок\",\n          \"ko\": \"총 청소 횟수\"\n        },\n        \"value\": \"0\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device data\",\n      \"nl\": \"Apparaat data\",\n      \"da\": \"Enhedsdata\",\n      \"de\": \"Gerätedaten\",\n      \"es\": \"Datos del dispositivo\",\n      \"fr\": \"Données de l'appareil\",\n      \"it\": \"Dati del dispositivo\",\n      \"no\": \"Enhetsdata\",\n      \"sv\": \"Enhetsdata\",\n      \"pl\": \"Dane urządzenia\",\n      \"ru\": \"Данные устройства\",\n      \"ko\": \"장치 데이터\"\n    },\n    \"children\": [\n      {\n        \"id\": \"error\",\n        \"type\": \"label\",\n        \"label\": {\n          \"en\": \"Error\",\n          \"nl\": \"Error\",\n          \"da\": \"Fejl\",\n          \"de\": \"Fehler\",\n          \"es\": \"Error\",\n          \"fr\": \"Erreur\",\n          \"it\": \"Errore\",\n          \"no\": \"Feil\",\n          \"sv\": \"Fel\",\n          \"pl\": \"Błąd\",\n          \"ru\": \"Ошибка\",\n          \"ko\": \"오류\"\n        },\n        \"value\": \"No error\"\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/vacuum_xiaomi_vacuum_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/vibration_sensor/device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst Device = require('../subdevice_device.js');\n\nclass VibrationSensorDevice extends Device {\n\n  async onEventFromGateway(device) {\n    try {\n      if (!this.getAvailable()) { this.setAvailable(); }\n\n      /* measure_battery & alarm_battery */\n      if (device.data.voltage) {\n        const battery = (device.data.voltage - 2800) / 5;\n        await this.updateCapabilityValue(\"measure_battery\", this.util.clamp(battery, 0, 100));\n        await this.updateCapabilityValue(\"alarm_battery\", battery <= 20 ? true : false);\n      }\n\n      /* alarm_tamper */\n      if (device.data.status === \"vibrate\") {\n        await this.updateCapabilityValue(\"alarm_tamper\", true);\n\n        if (this.timeoutAlarmTamper) { this.homey.clearTimeout(this.timeoutAlarmTamper); }\n\n        this.timeoutAlarmTamper = setTimeout(async () => {\n          await this.updateCapabilityValue(\"alarm_tamper\", false);\n        }, this.getSetting('alarm_duration_number') * 1000);\n      }\n\n      /* alarm_motion.tilt */\n      if (device.data.status === \"tilt\") {\n        await this.updateCapabilityValue(\"alarm_motion.tilt\", true);\n        await this.homey.flow.getDeviceTriggerCard('triggerVibrationTiltAlarm').trigger(this).catch(error => { this.error(error) });\n\n        if (this.timeoutAlarmTilt) { this.homey.clearTimeout(this.timeoutAlarmTilt); }\n\n        this.timeoutAlarmTilt = setTimeout(async () => {\n          await this.updateCapabilityValue(\"alarm_motion.tilt\", false);\n        }, this.getSetting('alarm_duration_number') * 1000);\n      }\n  \n      /* alarm_motion.freefall */\n      if (device.data.status === \"free_fall\") {\n        await this.updateCapabilityValue(\"alarm_motion.freefall\", true);\n        await this.homey.flow.getDeviceTriggerCard('triggerVibrationFreeFallAlarm').trigger(this).catch(error => { this.error(error) });\n\n        if (this.timeoutAlarmFall) { this.homey.clearTimeout(this.timeoutAlarmFall); }\n\n        this.timeoutAlarmFall = setTimeout(async () => {\n          await this.updateCapabilityValue(\"alarm_motion.freefall\", false);\n        }, this.getSetting('alarm_duration_number') * 1000);\n      }\n  \n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = VibrationSensorDevice;"
  },
  {
    "path": "drivers/vibration_sensor/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Vibration Sensor (Gateway)\",\n    \"nl\": \"Vibration Sensor (Gateway)\",\n    \"da\": \"Vibrationssensor (Gateway)\",\n    \"de\": \"Vibrationssensor (Gateway)\",\n    \"es\": \"Sensor de Vibración (Gateway)\",\n    \"fr\": \"Capteur de Vibration (Passerelle)\",\n    \"it\": \"Sensore di Vibrazione (Gateway)\",\n    \"no\": \"Vibrasjonssensor (Gateway)\",\n    \"sv\": \"Vibrationssensor (Gateway)\",\n    \"pl\": \"Czujnik Wibracji (Gateway)\",\n    \"ru\": \"Датчик Вибрации (Шлюз)\",\n    \"ko\": \"진동 센서 (게이트웨이)\"\n  },\n  \"images\": {\n    \"large\": \"/drivers/vibration_sensor/assets/images/large.jpg\",\n    \"small\": \"/drivers/vibration_sensor/assets/images/small.jpg\"\n  },\n  \"class\": \"sensor\",\n  \"$extends\": [\n    \"defaults_subdevice\"\n  ],\n  \"capabilities\": [\n    \"alarm_tamper\",\n    \"alarm_motion.tilt\",\n    \"alarm_motion.freefall\",\n    \"measure_battery\",\n    \"alarm_battery\"\n  ],\n  \"capabilitiesOptions\": {\n    \"alarm_tamper\": {\n      \"title\": {\n        \"en\": \"Vibrate\",\n        \"nl\": \"Vibratie\",\n        \"da\": \"Vibrering\",\n        \"de\": \"Vibrieren\",\n        \"es\": \"Vibrar\",\n        \"fr\": \"Vibrer\",\n        \"it\": \"Vibrare\",\n        \"no\": \"Vibrere\",\n        \"sv\": \"Vibrera\",\n        \"pl\": \"Wibracja\",\n        \"ru\": \"Вибрация\",\n        \"ko\": \"진동\"\n      }\n    },\n    \"alarm_motion.tilt\": {\n      \"title\": {\n        \"en\": \"Tilt\",\n        \"nl\": \"Tilt\",\n        \"da\": \"Vip\",\n        \"de\": \"Neigung\",\n        \"es\": \"Inclinación\",\n        \"fr\": \"Inclinaison\",\n        \"it\": \"Inclinazione\",\n        \"no\": \"Vippe\",\n        \"sv\": \"Lutning\",\n        \"pl\": \"Przechylenie\",\n        \"ru\": \"Наклон\",\n        \"ko\": \"기울기\"\n      }\n    },\n    \"alarm_motion.freefall\": {\n      \"title\": {\n        \"en\": \"Free fall\",\n        \"nl\": \"Vrije val\",\n        \"da\": \"Frit fald\",\n        \"de\": \"Freier Fall\",\n        \"es\": \"Caída libre\",\n        \"fr\": \"Chute libre\",\n        \"it\": \"Caduta libera\",\n        \"no\": \"Fritt fall\",\n        \"sv\": \"Fritt fall\",\n        \"pl\": \"Upadek swobodny\",\n        \"ru\": \"Свободное падение\",\n        \"ko\": \"자유 낙하\"\n      }\n    }\n  },\n  \"energy\": {\n    \"batteries\": [\n      \"CR2032\"\n    ]\n  }\n}"
  },
  {
    "path": "drivers/vibration_sensor/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../subdevice_driver.js');\nconst Util = require('../../lib/util.js');\n\nclass VibrationSensorDriver extends Driver {\n\n  async onInit() {\n\n    if (!this.util) this.util = new Util({homey: this.homey});\n\n    this.homey.flow.getDeviceTriggerCard('triggerVibrationTiltAlarm');\n    this.homey.flow.getDeviceTriggerCard('triggerVibrationFreeFallAlarm');\n\n    this.config = {\n      model: [\"vibration\"]\n    }\n  }\n\n}\n\nmodule.exports = VibrationSensorDriver;"
  },
  {
    "path": "drivers/vibration_sensor/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Duration of the sensor alarm\",\n      \"nl\": \"Duur van het sensor alarm\",\n      \"da\": \"Varighed af sensoralarmen\",\n      \"de\": \"Dauer des Sensoralarms\",\n      \"es\": \"Duración de la alarma del sensor\",\n      \"fr\": \"Durée de l'alarme du capteur\",\n      \"it\": \"Durata dell'allarme del sensore\",\n      \"no\": \"Varighet av sensoralarmen\",\n      \"sv\": \"Varaktighet för sensorlarmet\",\n      \"pl\": \"Czas trwania alarmu czujnika\",\n      \"ru\": \"Длительность сигнализации датчика\",\n      \"ko\": \"센서 알람 지속 시간\"\n    },\n    \"children\": [\n      {\n        \"id\": \"alarm_duration_number\",\n        \"type\": \"number\",\n        \"label\": {\n          \"en\": \"Disable after\",\n          \"nl\": \"Uitschakelen na\",\n          \"da\": \"Deaktiver efter\",\n          \"de\": \"Deaktivieren nach\",\n          \"es\": \"Desactivar después de\",\n          \"fr\": \"Désactiver après\",\n          \"it\": \"Disattiva dopo\",\n          \"no\": \"Deaktiver etter\",\n          \"sv\": \"Avaktivera efter\",\n          \"pl\": \"Wyłącz po\",\n          \"ru\": \"Отключить после\",\n          \"ko\": \"이후 비활성화\"\n        },\n        \"value\": 60,\n        \"attr\": {\n          \"min\": 60,\n          \"max\": 86400\n        }\n      }\n    ]\n  },\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"deviceSid\",\n        \"$extends\": \"deviceSid\"\n      },\n      {\n        \"id\": \"model\",\n        \"$extends\": \"model\"\n      },\n      {\n        \"id\": \"modelCode\",\n        \"$extends\": \"modelCode\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/wifi_device.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst miio = require('miio');\nconst tinycolor = require('tinycolor2');\n\nclass MiWifiDeviceDevice extends Homey.Device {\n    async onInit() {}\n\n    async bootSequence() {\n        try {\n            // VARIABLES GENERIC\n            this.deviceFailures = 0;\n\n            // CREATE DEVICE\n            this.homey.setTimeout(() => {\n                this.createDevice();\n            }, this.util.getRandomTimeout(10));\n\n            // LOG DEVICE INFO\n            this.homey.setTimeout(() => {\n                this.getDeviceInfo();\n            }, 120000 + this.util.getRandomTimeout(10));\n\n            // INITIAL REFRESH DEVICE\n            this.homey.setTimeout(() => {\n                this.refreshDevice();\n            }, this.util.getRandomTimeout(600));\n\n            this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                this.error(error);\n            });\n        } catch (error) {\n            this.error(error);\n        }\n    }\n\n    async onDeleted() {\n        try {\n            this.homey.clearInterval(this.pollingInterval);\n            this.homey.clearInterval(this.refreshInterval);\n            this.homey.clearTimeout(this.recreateTimeout);\n            if (this.miio) {\n                try {\n                    this.miio?.destroy();\n                } catch (e) {\n                    /* ignore double-close */\n                }\n                this.miio = null;\n            }\n        } catch (error) {\n            this.error(error);\n        }\n    }\n\n    async onUninit() {\n        try {\n            this.homey.clearInterval(this.pollingInterval);\n            this.homey.clearInterval(this.refreshInterval);\n            this.homey.clearTimeout(this.recreateTimeout);\n            if (this.miio) {\n                try {\n                    this.miio?.destroy();\n                } catch (e) {\n                    /* ignore double-close */\n                }\n                this.miio = null;\n            }\n        } catch (error) {\n            this.error(error);\n        }\n    }\n    // UPDATE DEVICE SETTINGS, CAN BE OVERWRITTEN ON DEVICE LEVEL\n    async onSettings({ oldSettings, newSettings, changedKeys }) {\n        if (changedKeys.includes('address') || changedKeys.includes('token') || changedKeys.includes('polling')) {\n            this.refreshDevice();\n        }\n        /* always resolve so Homey closes the settings view */\n        return true;\n    }\n\n    // GENERIC CAPABILITY LISTENERS\n\n    /* onoff */\n    async onCapabilityOnoff(value, opts) {\n        try {\n            if (this.miio && typeof this.miio.setPower === 'function') {\n                return await this.miio.setPower(value);\n            } else {\n                this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                    this.error(error);\n                });\n                this.createDevice();\n                return Promise.reject('Device unreachable, please try again ...');\n            }\n        } catch (error) {\n            this.error(error);\n            return Promise.reject(error);\n        }\n    }\n\n    /* dim */\n    async onCapabilityDim(value, opts) {\n        try {\n            if (this.miio && typeof this.miio.setBrightness === 'function') {\n                const brightness = value * 100;\n                return await this.miio.setBrightness(brightness);\n            } else {\n                this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                    this.error(error);\n                });\n                this.createDevice();\n                return Promise.reject('Device unreachable, please try again ...');\n            }\n        } catch (error) {\n            this.error(error);\n            return Promise.reject(error);\n        }\n    }\n\n    /* vacuumcleaner onoff */\n    async onCapabilityOnoffVacuumcleaner(value, opts) {\n        try {\n            if (this.miio) {\n                if (value) {\n                    await this.miio.clean();\n                    return await this.setCapabilityValue('vacuumcleaner_state', 'cleaning');\n                } else {\n                    await this.miio.stop();\n                    return this.setCapabilityValue('vacuumcleaner_state', 'stopped');\n                }\n            } else {\n                this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                    this.error(error);\n                });\n                this.createDevice();\n                return Promise.reject('Device unreachable, please try again ...');\n            }\n        } catch (error) {\n            this.error(error);\n            return Promise.reject(error);\n        }\n    }\n\n    /* vacuumcleaner_state */\n    async onCapabilityVacuumcleanerState(value, opts) {\n        try {\n            if (this.miio) {\n                switch (value) {\n                    case 'cleaning':\n                        await this.miio.clean();\n                        await this.setCapabilityValue('onoff', true);\n                        break;\n                    case 'spot_cleaning':\n                        await this.miio.spotClean();\n                        await this.setCapabilityValue('onoff', true);\n                        break;\n                    case 'stopped':\n                        await this.miio.stop();\n                        await this.setCapabilityValue('onoff', false);\n                        break;\n                    case 'docked':\n                    case 'charging':\n                        await this.miio.stop();\n                        await this.miio.activateCharging();\n                        await this.setCapabilityValue('onoff', false);\n                        break;\n                    default:\n                        this.error('Not a valid vacuumcleaner_state (wifi_device)');\n                }\n                return Promise.resolve();\n            } else {\n                this.setUnavailable(`${this.homey.__('unreachable')}: Device unreachable`).catch((error) => {\n                    this.error(error);\n                });\n                this.createDevice();\n                return Promise.reject('Device unreachable, please try again ...');\n            }\n        } catch (error) {\n            this.error(error);\n            return Promise.reject(error);\n        }\n    }\n\n    /* vacuumcleaner mop intensity */\n    async onCapabilityVacuumMopIntensity(value, opts) {\n        try {\n            if (this.miio) {\n                return await this.miio.call('set_water_box_custom_mode', [Number(value)], { retries: 1 });\n            } else {\n                this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                    this.error(error);\n                });\n                this.createDevice();\n                return Promise.reject('Device unreachable, please try again ...');\n            }\n        } catch (error) {\n            this.error(error);\n            return Promise.reject(error);\n        }\n    }\n\n    /* button.consumables */\n    async onCapabilityButtonConsumable(value, opts) {\n        try {\n            if (this.miio) {\n                return await this.miio.call('reset_consumable', ['main_brush_work_time', 'side_brush_work_time', 'filter_work_time', 'sensor_dirty_time'], { retries: 1 });\n            } else {\n                this.setUnavailable(this.homey.__('unreachable')).catch((error) => {\n                    this.error(error);\n                });\n                this.createDevice();\n                return Promise.reject('Device unreachable, please try again ...');\n            }\n        } catch (error) {\n            this.error(error);\n            return Promise.reject(error);\n        }\n    }\n\n    // HELPER FUNCTIONS\n\n    /* updating capabilities */\n    async updateCapabilityValue(capability, value) {\n        try {\n            if (this.hasCapability(capability)) {\n                if (value !== this.getCapabilityValue(capability) && value !== null && value !== 'null' && value !== 'undefined' && value !== undefined) {\n                    await this.setCapabilityValue(capability, value);\n                }\n            } else {\n                if (!this.miio || typeof this.miio.matches !== 'function' || !this.miio.matches('cap:children')) {\n                    this.log('adding capability ' + capability + ' to ' + this.getData().id + ' as the device seems to have values for this capability ...');\n                    await this.addCapability(capability);\n                    await this.setCapabilityValue(capability, value);\n                }\n            }\n        } catch (error) {\n            this.error('Trying to update or add capability', capability, 'with value', value, 'for device', this.getName(), 'with device id', this.getData().id);\n            this.error(error);\n        }\n    }\n\n    /* updating settings */\n    async updateSettingValue(setting, value) {\n        try {\n            if (this.getSetting(setting) !== undefined) {\n                if (this.getSetting(setting) !== value) {\n                    // Fix: Use dynamic key name instead of literal \"setting\"\n                    const settingsUpdate = {};\n                    settingsUpdate[setting] = value;\n                    await this.setSettings(settingsUpdate);\n                }\n            }\n        } catch (error) {\n            this.error('Trying to update setting', setting, 'with value', value, 'for device', this.getName(), 'with device id', this.getData().id);\n            this.error(error);\n        }\n    }\n\n    /* create device instance and start polling */\n    async createDevice() {\n        try {\n            // stop any previous timers/loops\n            this.homey.clearInterval(this.pollingInterval);\n            this.homey.clearTimeout(this.recreateTimeout);\n\n            // dispose of an old miio instance safely\n            try {\n                this.miio?.destroy();\n            } catch (e) {\n                /* ignore */\n            }\n            this.miio = null;\n\n            this.miio = await miio.device({\n                address: this.getSetting('address'),\n                token: this.getSetting('token')\n            });\n            if (!this.miio) {\n                throw new Error('miio.device returned null');\n            }\n\n            // device came back, clear failure counter\n            this.deviceFailures = 0;\n\n            if (!this.getAvailable()) await this.setAvailable();\n\n            this.startCapabilityListeners();\n            this.pollDevice();\n        } catch (error) {\n            // mark unavailable\n            this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((err) => this.error(err));\n\n            // exponential back-off: 10 s up to 9 tries, then 10 min\n            this.deviceFailures = (this.deviceFailures || 0) + 1;\n            const delay = this.deviceFailures <= 9 ? 10_000 : 600_000;\n\n            this.recreateTimeout = this.homey.setTimeout(() => this.createDevice(), delay);\n            this.miio = null;\n            this.error(error.message);\n        }\n    }\n\n    /* refresh device instance on regular interval */\n    async refreshDevice() {\n        try {\n            this.homey.clearInterval(this.refreshInterval);\n            this.refreshInterval = this.homey.setInterval(() => {\n                if (this.miio) {\n                    try {\n                        this.miio?.destroy();\n                    } catch (e) {\n                        /* ignore double-close */\n                    }\n                    this.miio = null;\n                }\n                this.homey.setTimeout(() => {\n                    this.createDevice();\n                }, 2000);\n            }, 3600000 + this.util.getRandomTimeout(600));\n        } catch (error) {\n            this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((error) => {\n                this.error(error);\n            });\n            this.deviceFailures++;\n            this.miio = null;\n            this.createDevice();\n            this.error(error.message);\n        }\n    }\n\n    /* log device info */\n    async getDeviceInfo() {\n        try {\n            this.log('WiFi Device Init: ' + this.getName() + ' and model ' + this.getStoreValue('model') + ' with ip ' + this.getSetting('address') + ' and capabilities ' + this.getCapabilities().toString());\n            if (this.miio && typeof this.miio.matches === 'function') {\n                if (this.miio.matches('cap:state')) {\n                    const states = await this.miio.state();\n                    for (const state in states) {\n                        await this.setStoreValue(state, states[state]);\n                    }\n                }\n            }\n        } catch (error) {\n            this.error(error);\n        }\n    }\n\n    /* poll interval */\n    async pollDevice() {\n        try {\n            this.homey.clearInterval(this.pollingInterval);\n            this.homey.setTimeout(() => {\n                this.retrieveDeviceData();\n            }, this.util.getRandomTimeout(5));\n            let interval = this.getSetting('polling') || 60;\n            this.pollingInterval = this.homey.setInterval(() => {\n                this.retrieveDeviceData();\n            }, 1000 * interval);\n        } catch (error) {\n            this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((error) => {\n                this.error(error);\n            });\n            this.deviceFailures++;\n            this.createDevice();\n            this.error(error);\n        }\n    }\n\n    /* RETRIEVE DEVICE DATA THROUGH POLLING */\n    async retrieveDeviceData() {\n        try {\n            if (!this.miio) {\n                this.setUnavailable(this.homey.__('device.unreachable')).catch((error) => this.error(error));\n                this.createDevice();\n                return;\n            }\n\n            const supports = (capability) => typeof this.miio?.matches === 'function' && this.miio.matches(capability);\n\n            // CAPABILITIES\n\n            /* onoff */\n            if (supports('cap:power')) {\n                const power = await this.miio.power();\n                this.updateCapabilityValue('onoff', power);\n            }\n\n            /* measure_power */\n            if (supports('cap:power-load')) {\n                const watt = await this.miio.powerLoad();\n                this.updateCapabilityValue('measure_power', watt);\n            }\n\n            /* meter_power */\n            if (supports('cap:power-consumed')) {\n                const wh = await this.miio.powerConsumed();\n                const kwh = wh / 1000;\n                this.updateCapabilityValue('meter_power', kwh);\n            }\n\n            /* measure_battery */\n            if (supports('cap:battery-level')) {\n                const battery = await this.miio.batteryLevel();\n                this.updateCapabilityValue('measure_battery', this.util.clamp(battery, 0, 100));\n            }\n\n            /* measure_temperature */\n            if (supports('cap:temperature')) {\n                const temp = await this.miio.temperature();\n                this.updateCapabilityValue('measure_temperature', temp.value);\n            }\n\n            /* measure_humidity */\n            if (supports('cap:relative-humidity')) {\n                const rh = await this.miio.relativeHumidity();\n                this.updateCapabilityValue('measure_humidity', rh);\n            }\n\n            /* measure_pm25 */\n            if (supports('cap:pm2.5')) {\n                const aqi = await this.miio.pm2_5();\n                this.updateCapabilityValue('measure_pm25', aqi);\n            }\n\n            /* measure_waterlevel */\n            if (supports('cap:depth')) {\n                const depth = await this.miio.depth();\n                const waterlevel = this.util.clamp(Math.round(depth), 0, 100);\n                if (this.getCapabilityValue('measure_waterlevel') !== waterlevel) {\n                    const previous_waterlevel = await this.getCapabilityValue('measure_waterlevel');\n                    await this.setCapabilityValue('measure_waterlevel', waterlevel);\n                    await this.homey.flow\n                        .getDeviceTriggerCard('humidifier2Waterlevel')\n                        .trigger(this, { waterlevel: waterlevel, previous_waterlevel: previous_waterlevel })\n                        .catch((error) => {\n                            this.error(error);\n                        });\n                }\n            }\n\n            /* dim */\n            if (supports('cap:brightness')) {\n                const brightness = await this.miio.brightness();\n                const dim = brightness / 100;\n                this.updateCapabilityValue('dim', dim);\n            }\n\n            /* measure_luminance */\n            if (supports('cap:illuminance')) {\n                const luminance = await this.miio.illuminance();\n                this.updateCapabilityValue('measure_luminance', luminance.value);\n            }\n\n            /* light_temperature */\n            // not clear on how to set light_temperature from polling\n\n            /* light_hue & light_saturation for child device */\n            if (supports('cap:children') && typeof this.miio.child === 'function') {\n                const lightChild = this.miio.child('light');\n                if (lightChild && typeof lightChild.matches === 'function' && lightChild.matches('cap:colorable') && typeof lightChild.color === 'function') {\n                    const color = await lightChild.color();\n\n                    const colorChanged = tinycolor({ r: color.values[0], g: color.values[1], b: color.values[2] });\n                    const hsv = colorChanged.toHsv();\n                    const hue = Math.round(hsv.h) / 360;\n                    const saturation = Math.round(hsv.s);\n\n                    this.updateCapabilityValue('light_hue', hue);\n                    this.updateCapabilityValue('light_saturation', saturation);\n                }\n            }\n\n            // STORE VALUES\n\n            /* mode */\n            if (supports('cap:mode')) {\n                const mode = await this.miio.mode();\n                this.handleModeEvent(mode);\n                if (this.getStoreValue('mode') !== mode && mode !== null) {\n                    this.setStoreValue('mode', mode);\n                }\n            }\n\n            /* state */\n            if (supports('cap:state')) {\n                const states = await this.miio.state();\n                for (const state in states) {\n                    await this.setStoreValue(state, states[state]);\n                }\n            }\n\n            /* fanspeed */\n            if (supports('cap:fan-speed')) {\n                const fanspeed = await this.miio.getState('fanSpeed');\n                if (this.getStoreValue('fanspeed') !== fanspeed) {\n                    await this.setStoreValue('fanspeed', fanspeed);\n                }\n            }\n\n            /* roll */\n            if (supports('cap:roll-angle')) {\n                const angle = await this.miio.getState('roll');\n                if (this.getStoreValue('angle') !== angle) {\n                    await this.setStoreValue('angle', angle);\n                }\n            }\n\n            /* adjustable-roll-angle */\n            if (supports('cap:adjustable-roll-angle')) {\n                const roll_angle = await this.miio.getState('roll_angle');\n                if (this.getStoreValue('roll_angle') !== Number(roll_angle)) {\n                    await this.setStoreValue('roll_angle', Number(roll_angle));\n                }\n            }\n\n            /* switchable-child-lock */\n            if (supports('cap:switchable-child-lock')) {\n                const child_lock = await this.miio.getState('child_lock');\n                if (this.getStoreValue('child_lock') !== child_lock) {\n                    await this.setStoreValue('child_lock', child_lock);\n                }\n            }\n\n            /* eyecare */\n            if (supports('cap:eyecare')) {\n                const eyecare = await this.miio.eyeCare();\n                if (this.getStoreValue('eyecare') !== eyecare) {\n                    await this.setStoreValue('eyecare', eyecare);\n                }\n            }\n\n            // DEVICE TYPE SPECIFIC\n\n            /* multifunction air monitor */\n            if (this.getStoreValue('model') === 'cgllc.airmonitor.b1') {\n                const data = await this.miio.call('get_air_data', []);\n                data.co2 = data.co2e;\n                ['temperature', 'humidity', 'pm25', 'tvoc', 'co2'].forEach((capability) => {\n                    this.updateCapabilityValue(`measure_${capability}`, data[capability]);\n                });\n            }\n\n            if (!this.getAvailable()) {\n                await this.setAvailable();\n            }\n        } catch (error) {\n            this.homey.clearInterval(this.pollingInterval);\n\n            if (this.getAvailable()) {\n                this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((error) => this.error(error));\n            }\n\n            /* RETRY AFTER 60 s - **now tracked so onDeleted/onUninit can clear it** */\n            this.recreateTimeout = this.homey.setTimeout(() => {\n                this.createDevice();\n            }, 60000);\n            this.miio = null;\n\n            this.error(error);\n        }\n    }\n\n    /* START CAPABILITY LISTENERS */\n    async startCapabilityListeners() {\n        try {\n            if (!this.miio) {\n                return;\n            }\n            /* avoid piling up listeners after reconnects */\n            this.miio.removeAllListeners?.();\n\n            // debugging\n            // this.miio.on('stateChanged', (change) => {\n            //   this.log(JSON.stringify(change));\n            // });\n\n            /* onoff */\n            this.miio.on('powerChanged', (onoff) => {\n                this.updateCapabilityValue('onoff', onoff);\n            });\n\n            /* measure_power */\n            this.miio.on('powerLoadChanged', (watt) => {\n                this.updateCapabilityValue('measure_power', watt);\n            });\n\n            /* meter_power */\n            this.miio.on('powerConsumedChanged', (wh) => {\n                const kwh = wh / 1000;\n                this.updateCapabilityValue('meter_power', kwh);\n            });\n\n            /* measure_battery */\n            this.miio.on('batteryLevelChanged', (battery) => {\n                this.updateCapabilityValue('measure_battery', this.util.clamp(battery, 0, 100));\n            });\n\n            /* measure_temperature */\n            this.miio.on('temperatureChanged', (temp) => {\n                this.updateCapabilityValue('measure_temperature', temp.value);\n            });\n\n            /* measure_humidity */\n            this.miio.on('relativeHumidityChanged', (humidity) => {\n                this.updateCapabilityValue('measure_humidity', humidity);\n            });\n\n            /* measure_pm25 */\n            this.miio.on('pm2.5Changed', (aqi) => {\n                this.updateCapabilityValue('measure_pm25', aqi);\n            });\n\n            /* measure_waterlevel */\n            this.miio.on('depthChanged', (depth) => {\n                const waterlevel = this.util.clamp(Math.round(depth), 0, 100);\n                this.updateCapabilityValue('measure_waterlevel', waterlevel);\n            });\n\n            /* measure_luminance */\n            this.miio.on('illuminanceChanged', (illuminance) => {\n                this.updateCapabilityValue('measure_luminance', illuminance.value);\n            });\n\n            /* light_temperature */\n            this.miio.on('colorChanged', (c) => {\n                const light_temperature = this.util.normalize(c.values[0], 3000, 5700);\n                this.updateCapabilityValue('light_temperature', light_temperature);\n            });\n\n            /* light_hue & light_saturation for child device */\n            if (typeof this.miio?.matches === 'function' && this.miio.matches('cap:children') && typeof this.miio.child === 'function') {\n                const lightChild = this.miio.child('light');\n                lightChild?.on?.('colorChanged', (c) => {\n                    const colorChanged = tinycolor({ r: c.rgb.red, g: c.rgb.green, b: c.rgb.blue });\n                    const hsv = colorChanged.toHsv();\n                    const hue = Math.round(hsv.h) / 360;\n                    const saturation = Math.round(hsv.s);\n\n                    this.updateCapabilityValue('light_hue', hue);\n                    this.updateCapabilityValue('light_saturation', saturation);\n                });\n\n                /* dim */\n                lightChild?.on?.('brightnessChanged', (brightness) => {\n                    const dim = brightness / 100;\n                    this.updateCapabilityValue('dim', dim);\n                });\n            }\n\n            /* mode */\n            this.miio.on('modeChanged', (mode) => {\n                this.handleModeEvent(mode);\n            });\n        } catch (error) {\n            this.log(error);\n        }\n    }\n\n    /* HANDLE MODE EVENTS, CAN BE OVERWRITTEN ON DEVICE LEVEL */\n    async handleModeEvent(mode) {\n        try {\n            /* device with mode implemented as capability */\n            if (this.hasCapability('airpurifier_mode')) {\n                const previous_mode = this.getCapabilityValue('airpurifier_mode');\n                if (previous_mode !== mode) {\n                    this.setCapabilityValue('airpurifier_mode', mode);\n                    this.homey.flow\n                        .getDeviceTriggerCard('triggerModeChanged')\n                        .trigger(this, { new_mode: mode, previous_mode: previous_mode })\n                        .catch((error) => {\n                            this.error(error);\n                        });\n                }\n            }\n\n            if (this.hasCapability('humidifier_zhimi_mode')) {\n                const previous_mode = this.getCapabilityValue('humidifier_zhimi_mode');\n                if (previous_mode !== mode) {\n                    this.setCapabilityValue('humidifier_zhimi_mode', mode);\n                    this.homey.flow\n                        .getDeviceTriggerCard('triggerModeChanged')\n                        .trigger(this, { new_mode: mode, previous_mode: previous_mode.toString() })\n                        .catch((error) => {\n                            this.error(error);\n                        });\n                }\n            }\n        } catch (error) {\n            this.error(error);\n        }\n    }\n\n    /* HANDLE DEVICE SETTINGS, NEED TO OVERWRITTEN ON DEVICE LEVEL */\n    async handleDeviceSettings() {}\n\n    /* VACUUMCLEANER STATE, CAN BE OVERWRITTEN ON DEVICE LEVEL */\n    async vacuumCleanerState(state) {\n        try {\n            switch (state) {\n                case 'cleaning':\n                    if (this.getCapabilityValue('vacuumcleaner_state') !== 'cleaning') {\n                        await this.updateCapabilityValue('vacuumcleaner_state', 'cleaning');\n                        await this.updateCapabilityValue('onoff', true);\n                        await this.homey.flow\n                            .getDeviceTriggerCard('statusVacuum')\n                            .trigger(this, { status: 'cleaning' })\n                            .catch((error) => {\n                                this.error(error);\n                            });\n                    }\n                    break;\n                case 'spot_cleaning':\n                    if (this.getCapabilityValue('vacuumcleaner_state') !== 'spot_cleaning') {\n                        await this.updateCapabilityValue('vacuumcleaner_state', 'spot_cleaning');\n                        await this.updateCapabilityValue('onoff', true);\n                        await this.homey.flow\n                            .getDeviceTriggerCard('statusVacuum')\n                            .trigger(this, { status: 'spot_cleaning' })\n                            .catch((error) => {\n                                this.error(error);\n                            });\n                    }\n                    break;\n                case 'stopped':\n                    if (this.getCapabilityValue('vacuumcleaner_state') !== 'stopped') {\n                        await this.updateCapabilityValue('vacuumcleaner_state', 'stopped');\n                        await this.updateCapabilityValue('onoff', false);\n                        await this.homey.flow\n                            .getDeviceTriggerCard('statusVacuum')\n                            .trigger(this, { status: 'stopped' })\n                            .catch((error) => {\n                                this.error(error);\n                            });\n                    }\n                    break;\n                case 'docked':\n                    if (this.getCapabilityValue('vacuumcleaner_state') !== 'docked') {\n                        await this.updateCapabilityValue('vacuumcleaner_state', 'docked');\n                        await this.updateCapabilityValue('onoff', false);\n                        await this.homey.flow\n                            .getDeviceTriggerCard('statusVacuum')\n                            .trigger(this, { status: 'docked' })\n                            .catch((error) => {\n                                this.error(error);\n                            });\n                    }\n                    break;\n                case 'charging':\n                    if (this.getCapabilityValue('vacuumcleaner_state') !== 'charging') {\n                        await this.updateCapabilityValue('vacuumcleaner_state', 'charging');\n                        await this.updateCapabilityValue('onoff', false);\n                        await this.homey.flow\n                            .getDeviceTriggerCard('statusVacuum')\n                            .trigger(this, { status: 'charging' })\n                            .catch((error) => {\n                                this.error(error);\n                            });\n                    }\n                    break;\n                case 'stopped_error':\n                    await this.updateCapabilityValue('vacuumcleaner_state', 'stopped');\n                    await this.updateCapabilityValue('onoff', false);\n                    await this.homey.flow\n                        .getDeviceTriggerCard('statusVacuum')\n                        .trigger(this, { status: 'error' })\n                        .catch((error) => {\n                            this.error(error);\n                        });\n                    break;\n                default:\n                    break;\n            }\n        } catch (error) {\n            this.error(error);\n        }\n    }\n\n    /* VACUUMCLEANER CONSUMABLES, CAN BE OVERWRITTEN ON DEVICE LEVEL */\n    async vacuumConsumables(consumables) {\n        try {\n            let main_brush_remaining_value = 0;\n            let side_brush_remaining_value = 0;\n            let filter_remaining_value = 0;\n            let sensor_dirty_remaining_value = 0;\n\n            /* main_brush_work_time */\n            if (consumables[0].hasOwnProperty('main_brush_work_time')) {\n                main_brush_remaining_value = 100 - Math.ceil((consumables[0]['main_brush_work_time'] / 1080000) * 100);\n                const main_brush_remaining = main_brush_remaining_value + '%';\n                if (this.getSetting('main_brush_work_time') !== main_brush_remaining) {\n                    await this.setSettings({ main_brush_work_time: main_brush_remaining });\n                    await this.main_brush_lifetime_token.setValue(main_brush_remaining_value);\n                }\n                if (main_brush_remaining_value < this.getSetting('alarm_threshold') && !this.getCapabilityValue('alarm_main_brush_work_time')) {\n                    await this.updateCapabilityValue('alarm_main_brush_work_time', true);\n                    await this.homey.flow\n                        .getDeviceTriggerCard('alertVacuum')\n                        .trigger(this, { consumable: 'Main Brush', value: main_brush_remaining })\n                        .catch((error) => {\n                            this.error(error);\n                        });\n                } else if (main_brush_remaining_value > this.getSetting('alarm_threshold') && this.getCapabilityValue('alarm_main_brush_work_time')) {\n                    this.updateCapabilityValue('alarm_main_brush_work_time', false);\n                }\n            }\n\n            /* side_brush_work_time */\n            if (consumables[0].hasOwnProperty('side_brush_work_time')) {\n                side_brush_remaining_value = 100 - Math.ceil((consumables[0]['side_brush_work_time'] / 720000) * 100);\n                const side_brush_remaining = side_brush_remaining_value + '%';\n                if (this.getSetting('side_brush_work_time') !== side_brush_remaining) {\n                    await this.setSettings({ side_brush_work_time: side_brush_remaining });\n                    await this.side_brush_lifetime_token.setValue(side_brush_remaining_value);\n                }\n                if (side_brush_remaining_value < this.getSetting('alarm_threshold') && !this.getCapabilityValue('alarm_side_brush_work_time')) {\n                    await this.updateCapabilityValue('alarm_side_brush_work_time', true);\n                    await this.homey.flow\n                        .getDeviceTriggerCard('alertVacuum')\n                        .trigger(this, { consumable: 'Side Brush', value: side_brush_remaining })\n                        .catch((error) => {\n                            this.error(error);\n                        });\n                } else if (side_brush_remaining_value > this.getSetting('alarm_threshold') && this.getCapabilityValue('alarm_side_brush_work_time')) {\n                    this.updateCapabilityValue('alarm_side_brush_work_time', false);\n                }\n            }\n\n            /* filter_work_time */\n            if (consumables[0].hasOwnProperty('filter_work_time')) {\n                filter_remaining_value = 100 - Math.ceil((consumables[0]['filter_work_time'] / 540000) * 100);\n                const filter_remaining = filter_remaining_value + '%';\n                if (this.getSetting('filter_work_time') !== filter_remaining) {\n                    await this.setSettings({ filter_work_time: filter_remaining });\n                    await this.filter_lifetime_token.setValue(filter_remaining_value);\n                }\n                if (filter_remaining_value < this.getSetting('alarm_threshold') && !this.getCapabilityValue('alarm_filter_work_time')) {\n                    await this.updateCapabilityValue('alarm_filter_work_time', true);\n                    await this.homey.flow\n                        .getDeviceTriggerCard('alertVacuum')\n                        .trigger(this, { consumable: 'Filter', value: filter_remaining })\n                        .catch((error) => {\n                            this.error(error);\n                        });\n                } else if (filter_remaining_value > this.getSetting('alarm_threshold') && this.getCapabilityValue('alarm_filter_work_time')) {\n                    this.updateCapabilityValue('alarm_filter_work_time', false);\n                }\n            }\n\n            /* sensor_dirty_work_time */\n            if (consumables[0].hasOwnProperty('sensor_dirty_time')) {\n                sensor_dirty_remaining_value = 100 - Math.ceil((consumables[0]['sensor_dirty_time'] / 108000) * 100);\n                const sensor_dirty_remaining = sensor_dirty_remaining_value + '%';\n                if (this.getSetting('sensor_dirty_time') !== sensor_dirty_remaining) {\n                    await this.setSettings({ sensor_dirty_time: sensor_dirty_remaining });\n                    await this.sensor_dirty_lifetime_token.setValue(sensor_dirty_remaining_value);\n                }\n                if (sensor_dirty_remaining_value < this.getSetting('alarm_threshold') && !this.getCapabilityValue('alarm_sensor_dirty_time')) {\n                    await this.updateCapabilityValue('alarm_sensor_dirty_time', true);\n                    await this.homey.flow\n                        .getDeviceTriggerCard('alertVacuum')\n                        .trigger(this, { consumable: 'Sensor', value: sensor_dirty_remaining })\n                        .catch((error) => {\n                            this.error(error);\n                        });\n                } else if (sensor_dirty_remaining_value > this.getSetting('alarm_threshold') && this.getCapabilityValue('alarm_sensor_dirty_time')) {\n                    this.updateCapabilityValue('alarm_sensor_dirty_time', false);\n                }\n            }\n\n            /* initial update tokens */\n            if (!this.initialTokenConsumable || this.initialTokenConsumable == undefined) {\n                await this.main_brush_lifetime_token.setValue(main_brush_remaining_value);\n                await this.side_brush_lifetime_token.setValue(side_brush_remaining_value);\n                await this.filter_lifetime_token.setValue(filter_remaining_value);\n                await this.sensor_dirty_lifetime_token.setValue(sensor_dirty_remaining_value);\n                this.initialTokenConsumable = true;\n            }\n        } catch (error) {\n            this.error(error);\n        }\n    }\n\n    /* VACUUMCLEANER TOTALS, CAN BE OVERWRITTEN ON DEVICE LEVEL */\n    async vacuumTotals(totals) {\n        try {\n            let worktime = 0;\n            let cleared_area = 0;\n            let clean_count = 0;\n\n            // different models use different values\n            if (totals.hasOwnProperty('clean_time')) {\n                worktime = totals.clean_time;\n                cleared_area = totals.clean_area;\n                clean_count = totals.clean_count;\n            } else {\n                worktime = totals[0];\n                cleared_area = totals[1];\n                clean_count = totals[2];\n            }\n\n            /* total_work_time */\n            const total_work_time_value = Math.round(worktime / 3600);\n            const total_work_time = total_work_time_value + ' h';\n            if (this.getSetting('total_work_time') !== total_work_time) {\n                await this.setSettings({ total_work_time: total_work_time });\n                await this.total_work_time_token.setValue(total_work_time_value);\n            }\n\n            /* total_cleared_area */\n            const total_cleared_area_value = Math.round(cleared_area / 1000000);\n            const total_cleared_area = total_cleared_area_value + ' m2';\n            if (this.getSetting('total_cleared_area') !== total_cleared_area) {\n                await this.setSettings({ total_cleared_area: total_cleared_area });\n                await this.total_cleared_area_token.setValue(total_cleared_area_value);\n            }\n\n            /* total_clean_count */\n            if (this.getSetting('total_clean_count') !== clean_count) {\n                await this.setSettings({ total_clean_count: String(clean_count) });\n                await this.total_clean_count_token.setValue(clean_count);\n            }\n\n            /* initial update tokens */\n            if (!this.initialTokenTotal || this.initialTokenTotal == undefined) {\n                await this.total_work_time_token.setValue(total_work_time_value);\n                await this.total_cleared_area_token.setValue(total_cleared_area_value);\n                await this.total_clean_count_token.setValue(clean_count);\n                this.initialTokenTotal = true;\n            }\n        } catch (error) {\n            this.error(error);\n        }\n    }\n}\n\nmodule.exports = MiWifiDeviceDevice;\n"
  },
  {
    "path": "drivers/wifi_driver.js",
    "content": "'use strict';\n\nconst Homey = require('homey');\nconst miio = require('miio');\nconst Util = require('../lib/util.js');\n\nclass MiHomeWifiDriver extends Homey.Driver {\n\n  onInit() {\n    if (!this.util) this.util = new Util({homey: this.homey});\n  }\n\n  onPair(session) {\n\n    let deviceObject = {};\n\n    session.setHandler('test_connection', async (data) => {\n      try {\n        const device = await miio.device({ address: data.address, token: data.token });\n        const model = await device.miioModel;\n        const name = await this.util.getFriendlyNameWiFi(model) || 'Unknown model';\n        const device_name = name + ' ('+ model +')';\n\n        deviceObject = {\n          name: device_name,\n          data: {\n            id: data.token\n          },\n          settings: {\n            address: data.address,\n            token: data.token,\n            polling: data.polling\n          },\n          store: {\n            model: model\n          }\n        }\n        return Promise.resolve(deviceObject);\n      } catch (error) {\n        this.error(error);\n        return Promise.reject(error);\n      }\n    });\n\n    session.setHandler('add_device', async () => {\n      try {\n        return Promise.resolve(deviceObject);\n      } catch (error) {\n        this.error(error);\n        return Promise.reject(error);\n      }\n    });\n\n  }\n\n}\n\nmodule.exports = MiHomeWifiDriver;"
  },
  {
    "path": "drivers/yeelink_light_ceil43_miot/device.js",
    "content": "'use strict';\n\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\nconst tinycolor = require('tinycolor2');\n\n/* supported devices */\n// https://home.miot-spec.com/spec/yeelink.light.ceil43 // Yeelight Arwen Ceiling Light D\n\nconst COLOR_TEMPERATURE_MIN = 2700;\nconst COLOR_TEMPERATURE_MAX = 6500;\nconst MIOT_MODE_DAY = 0;\nconst MIOT_MODE_NIGHT = 1;\nconst MIOT_MODE_COLOR = 2;\nconst MIOT_MODE_FLOW = 3;\n\nconst mapping = {\n  'yeelink.light.ceil43': 'mapping_default',\n  'yeelink.light.*': 'mapping_default'\n};\n\nconst properties = {\n  mapping_default: {\n    get_properties: [\n      { did: 'power', siid: 2, piid: 1 },\n      { did: 'mode', siid: 2, piid: 2 },\n      { did: 'brightness', siid: 2, piid: 3 },\n      { did: 'color', siid: 2, piid: 4 },\n      { did: 'color_temperature', siid: 2, piid: 5 },\n      { did: 'ambient_power', siid: 3, piid: 1 },\n      { did: 'ambient_brightness', siid: 3, piid: 3 },\n      { did: 'ambient_color_temperature', siid: 3, piid: 4 },\n      { did: 'ambient_color', siid: 3, piid: 5 }\n    ],\n    set_properties: {\n      power: { siid: 2, piid: 1 },\n      mode: { siid: 2, piid: 2 },\n      brightness: { siid: 2, piid: 3 },\n      color: { siid: 2, piid: 4 },\n      color_temperature: { siid: 2, piid: 5 },\n      ambient_power: { siid: 3, piid: 1 },\n      ambient_brightness: { siid: 3, piid: 3 },\n      ambient_color_temperature: { siid: 3, piid: 4 },\n      ambient_color: { siid: 3, piid: 5 }\n    }\n  }\n};\n\nclass YeelightArwenCeilingLightDDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({ homey: this.homey });\n\n      this.bootSequence();\n\n      this.deviceProperties = properties[mapping[this.getStoreValue('model')]] !== undefined\n        ? properties[mapping[this.getStoreValue('model')]]\n        : properties[mapping['yeelink.light.*']];\n\n      await this.ensureCapability('light_mode');\n      await this.ensureCapability('light_mode.ambient');\n      await this.ensureCapability('yeelight_ceil43_mode');\n\n      this.registerCapabilityListener('onoff', (value) => this.setMiotProperty('power', value));\n\n      this.registerCapabilityListener('onoff.ambient', (value) => this.setMiotProperty('ambient_power', value));\n\n      this.registerMultipleCapabilityListener(\n        ['dim', 'light_temperature', 'light_hue', 'light_saturation', 'light_mode', 'yeelight_ceil43_mode'],\n        this.onMainLightCapabilities.bind(this),\n        500\n      );\n\n      this.registerMultipleCapabilityListener(\n        ['dim.ambient', 'light_temperature.ambient', 'light_hue.ambient', 'light_saturation.ambient', 'light_mode.ambient'],\n        this.onAmbientLightCapabilities.bind(this),\n        500\n      );\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n  async ensureCapability(capability) {\n    if (!this.hasCapability(capability)) {\n      await this.addCapability(capability);\n    }\n  }\n\n  async setMiotProperty(property, value) {\n    try {\n      if (!this.miio) {\n        this.setUnavailable(this.homey.__('unreachable')).catch((error) => { this.error(error); });\n        this.createDevice();\n        return Promise.reject('Device unreachable, please try again ...');\n      }\n\n      const definition = this.deviceProperties.set_properties[property];\n      const payload = [{ siid: definition.siid, piid: definition.piid, value }];\n      const result = await this.miio.call('set_properties', payload, { retries: 1 });\n      this.log(`Yeelight ceil43 set ${property}: ${JSON.stringify(payload)} -> ${JSON.stringify(result)}`);\n      return result;\n    } catch (error) {\n      this.error(`Yeelight ceil43 failed to set ${property} to ${JSON.stringify(value)}`);\n      this.error(error);\n      return Promise.reject(error);\n    }\n  }\n\n  async onMainLightCapabilities(valueObj) {\n    if (typeof valueObj.dim !== 'undefined') {\n      const brightness = Math.round(this.util.clamp(valueObj.dim * 100, 1, 100));\n      await this.setMiotProperty('brightness', brightness);\n    }\n\n    if (typeof valueObj.yeelight_ceil43_mode !== 'undefined') {\n      await this.setMiotProperty('mode', Number(valueObj.yeelight_ceil43_mode));\n      await this.updateCapabilityValue('light_mode', this.toHomeyLightMode(valueObj.yeelight_ceil43_mode));\n    } else if (valueObj.light_mode === 'color' || typeof valueObj.light_hue !== 'undefined' || typeof valueObj.light_saturation !== 'undefined') {\n      await this.setMiotProperty('mode', MIOT_MODE_COLOR);\n      await this.updateCapabilityValue('light_mode', 'color');\n      await this.updateCapabilityValue('yeelight_ceil43_mode', String(MIOT_MODE_COLOR));\n    } else if (valueObj.light_mode === 'temperature' || typeof valueObj.light_temperature !== 'undefined') {\n      await this.setMiotProperty('mode', MIOT_MODE_DAY);\n      await this.updateCapabilityValue('light_mode', 'temperature');\n      await this.updateCapabilityValue('yeelight_ceil43_mode', String(MIOT_MODE_DAY));\n    }\n\n    if (typeof valueObj.light_temperature !== 'undefined') {\n      await this.setMiotProperty('color_temperature', this.toMiotColorTemperature(valueObj.light_temperature));\n    }\n\n    if (typeof valueObj.light_hue !== 'undefined' || typeof valueObj.light_saturation !== 'undefined') {\n      const color = this.getRgbIntFromCapabilities(valueObj, 'light_hue', 'light_saturation');\n      await this.setMiotProperty('color', color);\n    }\n  }\n\n  async onAmbientLightCapabilities(valueObj) {\n    if (typeof valueObj['dim.ambient'] !== 'undefined') {\n      const brightness = Math.round(this.util.clamp(valueObj['dim.ambient'] * 100, 1, 100));\n      await this.setMiotProperty('ambient_brightness', brightness);\n    }\n\n    if (valueObj['light_mode.ambient'] === 'color' || typeof valueObj['light_hue.ambient'] !== 'undefined' || typeof valueObj['light_saturation.ambient'] !== 'undefined') {\n      await this.updateCapabilityValue('light_mode.ambient', 'color');\n    } else if (valueObj['light_mode.ambient'] === 'temperature' || typeof valueObj['light_temperature.ambient'] !== 'undefined') {\n      await this.updateCapabilityValue('light_mode.ambient', 'temperature');\n    }\n\n    if (typeof valueObj['light_temperature.ambient'] !== 'undefined') {\n      await this.setMiotProperty('ambient_color_temperature', this.toMiotColorTemperature(valueObj['light_temperature.ambient']));\n    }\n\n    if (typeof valueObj['light_hue.ambient'] !== 'undefined' || typeof valueObj['light_saturation.ambient'] !== 'undefined') {\n      const color = this.getRgbIntFromCapabilities(valueObj, 'light_hue.ambient', 'light_saturation.ambient');\n      await this.setMiotProperty('ambient_color', color);\n    }\n  }\n\n  getRgbIntFromCapabilities(valueObj, hueCapability, saturationCapability) {\n    const hue = typeof valueObj[hueCapability] !== 'undefined'\n      ? valueObj[hueCapability]\n      : this.getCapabilityValue(hueCapability);\n    const saturation = typeof valueObj[saturationCapability] !== 'undefined'\n      ? valueObj[saturationCapability]\n      : this.getCapabilityValue(saturationCapability);\n    const color = tinycolor({ h: this.toCapabilityValue(hue, 0) * 360, s: this.toCapabilityValue(saturation, 1), v: 1 });\n\n    return parseInt(color.toHex(), 16);\n  }\n\n  toCapabilityValue(value, fallback) {\n    return value === undefined || value === null ? fallback : value;\n  }\n\n  toHomeyLightMode(mode) {\n    return Number(mode) === MIOT_MODE_COLOR || Number(mode) === MIOT_MODE_FLOW ? 'color' : 'temperature';\n  }\n\n  toHomeyColorTemperature(value) {\n    const normalized = (COLOR_TEMPERATURE_MAX - value) / (COLOR_TEMPERATURE_MAX - COLOR_TEMPERATURE_MIN);\n    return this.util.clamp(Number(normalized.toFixed(2)), 0, 1);\n  }\n\n  toMiotColorTemperature(value) {\n    const colorTemperature = COLOR_TEMPERATURE_MAX - (this.util.clamp(value, 0, 1) * (COLOR_TEMPERATURE_MAX - COLOR_TEMPERATURE_MIN));\n    return Math.round(this.util.clamp(colorTemperature, COLOR_TEMPERATURE_MIN, COLOR_TEMPERATURE_MAX));\n  }\n\n  async updateColorCapabilities(colorValue, hueCapability, saturationCapability) {\n    if (colorValue === undefined || colorValue === null) return;\n\n    const hexValue = Number(colorValue).toString(16).padStart(6, '0');\n    const color = tinycolor(`#${hexValue}`);\n    const hsv = color.toHsv();\n\n    await this.updateCapabilityValue(hueCapability, this.util.clamp(Number((hsv.h / 360).toFixed(4)), 0, 1));\n    await this.updateCapabilityValue(saturationCapability, this.util.clamp(Number(hsv.s.toFixed(4)), 0, 1));\n  }\n\n  async retrieveDeviceData() {\n    try {\n      const result = await this.miio.call('get_properties', this.deviceProperties.get_properties, { retries: 1 });\n      if (!this.getAvailable()) { await this.setAvailable(); }\n\n      const property = (did) => {\n        const found = result.find((obj) => obj.did === did);\n        if (!found) {\n          this.log(`Yeelight ceil43 missing MIOT property ${did}; received: ${JSON.stringify(result)}`);\n        }\n        return found;\n      };\n\n      const onoff = property('power');\n      const brightness = property('brightness');\n      const mode = property('mode');\n      const color = property('color');\n      const colorTemperature = property('color_temperature');\n      const ambientOnoff = property('ambient_power');\n      const ambientBrightness = property('ambient_brightness');\n      const ambientColorTemperature = property('ambient_color_temperature');\n      const ambientColor = property('ambient_color');\n\n      await this.updateCapabilityValue('onoff', onoff.value);\n      await this.updateCapabilityValue('dim', brightness.value / 100);\n      await this.updateCapabilityValue('light_mode', this.toHomeyLightMode(mode.value));\n      await this.updateCapabilityValue('yeelight_ceil43_mode', String(mode.value));\n      await this.updateCapabilityValue('light_temperature', this.toHomeyColorTemperature(colorTemperature.value));\n      await this.updateColorCapabilities(color.value, 'light_hue', 'light_saturation');\n\n      await this.updateCapabilityValue('onoff.ambient', ambientOnoff.value);\n      await this.updateCapabilityValue('dim.ambient', ambientBrightness.value / 100);\n      if (this.getCapabilityValue('light_mode.ambient') === null) {\n        await this.updateCapabilityValue('light_mode.ambient', 'temperature');\n      }\n      await this.updateCapabilityValue('light_temperature.ambient', this.toHomeyColorTemperature(ambientColorTemperature.value));\n      await this.updateColorCapabilities(ambientColor.value, 'light_hue.ambient', 'light_saturation.ambient');\n\n    } catch (error) {\n      this.homey.clearInterval(this.pollingInterval);\n\n      if (this.getAvailable()) {\n        this.setUnavailable(this.homey.__('device.unreachable') + error.message).catch((error) => { this.error(error); });\n      }\n\n      this.homey.setTimeout(() => { this.createDevice(); }, 60000);\n\n      this.error(error.message);\n    }\n  }\n\n}\n\nmodule.exports = YeelightArwenCeilingLightDDevice;\n"
  },
  {
    "path": "drivers/yeelink_light_ceil43_miot/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Yeelight Arwen Ceiling Light D (WiFi)\",\n    \"nl\": \"Yeelight Arwen Plafondlamp D (WiFi)\",\n    \"da\": \"Yeelight Arwen Loftslampe D (WiFi)\",\n    \"de\": \"Yeelight Arwen Deckenleuchte D (WiFi)\",\n    \"es\": \"Luz de techo Yeelight Arwen D (WiFi)\",\n    \"fr\": \"Plafonnier Yeelight Arwen D (WiFi)\",\n    \"it\": \"Plafoniera Yeelight Arwen D (WiFi)\",\n    \"no\": \"Yeelight Arwen Taklampe D (WiFi)\",\n    \"sv\": \"Yeelight Arwen Taklampa D (WiFi)\",\n    \"pl\": \"Lampa sufitowa Yeelight Arwen D (WiFi)\",\n    \"ru\": \"Потолочный светильник Yeelight Arwen D (WiFi)\",\n    \"ko\": \"Yeelight Arwen 천장 조명 D (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/yeelink_light_ceil43_miot/assets/images/large.jpg\",\n    \"small\": \"drivers/yeelink_light_ceil43_miot/assets/images/small.jpg\"\n  },\n  \"class\": \"light\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\",\n    \"dim\",\n    \"light_mode\",\n    \"yeelight_ceil43_mode\",\n    \"light_temperature\",\n    \"light_hue\",\n    \"light_saturation\",\n    \"onoff.ambient\",\n    \"dim.ambient\",\n    \"light_mode.ambient\",\n    \"light_temperature.ambient\",\n    \"light_hue.ambient\",\n    \"light_saturation.ambient\"\n  ],\n  \"capabilitiesOptions\": {\n    \"dim\": {\n      \"min\": 0.01\n    },\n    \"onoff.ambient\": {\n      \"title\": {\n        \"en\": \"Ambient Light\",\n        \"nl\": \"Sfeerverlichting\",\n        \"da\": \"Stemningslys\",\n        \"de\": \"Ambiente-Licht\",\n        \"es\": \"Luz ambiental\",\n        \"fr\": \"Lumière d'ambiance\",\n        \"it\": \"Luce ambientale\",\n        \"no\": \"Stemningslys\",\n        \"sv\": \"Stämningsljus\",\n        \"pl\": \"Swiatlo otoczenia\",\n        \"ru\": \"Фоновая подсветка\",\n        \"ko\": \"무드등\"\n      }\n    },\n    \"dim.ambient\": {\n      \"title\": {\n        \"en\": \"Ambient Brightness\"\n      },\n      \"min\": 0.01\n    },\n    \"light_mode.ambient\": {\n      \"title\": {\n        \"en\": \"Ambient Mode\"\n      }\n    },\n    \"light_temperature.ambient\": {\n      \"title\": {\n        \"en\": \"Ambient Temperature\"\n      }\n    },\n    \"light_hue.ambient\": {\n      \"title\": {\n        \"en\": \"Ambient Hue\"\n      }\n    },\n    \"light_saturation.ambient\": {\n      \"title\": {\n        \"en\": \"Ambient Saturation\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "drivers/yeelink_light_ceil43_miot/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass YeelightArwenCeilingLightDDriver extends Driver {}\n\nmodule.exports = YeelightArwenCeilingLightDDriver;\n"
  },
  {
    "path": "drivers/yeelink_light_ceil43_miot/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\",\n      \"ja\": \"デバイス設定\",\n      \"zh\": \"设备设置\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]\n"
  },
  {
    "path": "drivers/yeelink_light_ceil43_miot/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/yeelink_light_ceil43_miot/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/yeelink_light_ceil43_miot/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "drivers/zhimi-fan/device.js",
    "content": "\"use strict\";\n\nconst Homey = require('homey');\nconst Device = require('../wifi_device.js');\nconst Util = require('../../lib/util.js');\n\nclass ZhiMiFanDevice extends Device {\n\n  async onInit() {\n    try {\n      if (!this.util) this.util = new Util({homey: this.homey});\n      \n      // GENERIC DEVICE INIT ACTIONS\n      this.bootSequence();\n\n      // LISTENERS FOR UPDATING CAPABILITIES\n      this.registerCapabilityListener(\"onoff\", this.onCapabilityOnoff.bind(this));\n\n    } catch (error) {\n      this.error(error);\n    }\n  }\n\n}\n\nmodule.exports = ZhiMiFanDevice;"
  },
  {
    "path": "drivers/zhimi-fan/driver.compose.json",
    "content": "{\n  \"name\": {\n    \"en\": \"Basic Smartmi/ZhiMi Fan (WiFi)\",\n    \"nl\": \"Basis Smartmi/ZhiMi Fan (WiFi)\",\n    \"da\": \"Basis Smartmi/ZhiMi Fan (WiFi)\",\n    \"de\": \"Basis Smartmi/ZhiMi Fan (WiFi)\",\n    \"es\": \"Ventilador Básico Smartmi/ZhiMi (WiFi)\",\n    \"fr\": \"Ventilateur Smartmi/ZhiMi de base (WiFi)\",\n    \"it\": \"Ventilatore Smartmi/ZhiMi Base (WiFi)\",\n    \"no\": \"Grunnleggende Smartmi/ZhiMi Vifte (WiFi)\",\n    \"sv\": \"Grundläggande Smartmi/ZhiMi Fläkt (WiFi)\",\n    \"pl\": \"Podstawowy wentylator Smartmi/ZhiMi (WiFi)\",\n    \"ru\": \"Базовый вентилятор Smartmi/ZhiMi (WiFi)\",\n    \"ko\": \"기본 Smartmi/ZhiMi 팬 (WiFi)\"\n  },\n  \"images\": {\n    \"large\": \"drivers/zhimi-fan/assets/images/large.jpg\",\n    \"small\": \"drivers/zhimi-fan/assets/images/small.jpg\"\n  },\n  \"class\": \"fan\",\n  \"$extends\": [\n    \"defaults\"\n  ],\n  \"capabilities\": [\n    \"onoff\"\n  ]\n}"
  },
  {
    "path": "drivers/zhimi-fan/driver.js",
    "content": "'use strict';\n\nconst Driver = require('../wifi_driver.js');\n\nclass ZhiMiFanDriver extends Driver {}\n\nmodule.exports = ZhiMiFanDriver;"
  },
  {
    "path": "drivers/zhimi-fan/driver.settings.compose.json",
    "content": "[\n  {\n    \"type\": \"group\",\n    \"label\": {\n      \"en\": \"Device Settings\",\n      \"nl\": \"Apparaat instellingen\",\n      \"da\": \"Enhedsindstillinger\",\n      \"de\": \"Geräteeinstellungen\",\n      \"es\": \"Configuración del dispositivo\",\n      \"fr\": \"Paramètres de l'appareil\",\n      \"it\": \"Impostazioni del dispositivo\",\n      \"no\": \"Enhetsinnstillinger\",\n      \"sv\": \"Enhetsinställningar\",\n      \"pl\": \"Ustawienia urządzenia\",\n      \"ru\": \"Настройки устройства\",\n      \"ko\": \"장치 설정\"\n    },\n    \"children\": [\n      {\n        \"id\": \"address\",\n        \"$extends\": \"address\"\n      },\n      {\n        \"id\": \"token\",\n        \"$extends\": \"token\"\n      },\n      {\n        \"id\": \"polling\",\n        \"$extends\": \"polling\"\n      }\n    ]\n  }\n]"
  },
  {
    "path": "drivers/zhimi-fan/pair/add_device.html",
    "content": "<script type=\"text/javascript\">\n  try {\n    Homey.emit('add_device', {})\n      .then(result => {\n        Homey.createDevice(result);\n        Homey.done();\n      })\n  } catch (error) {\n    Homey.alert(error);\n    Homey.done();\n  }\n</script>\n"
  },
  {
    "path": "drivers/zhimi-fan/pair/pair.html",
    "content": "<script type=\"text/javascript\">\n\nHomey.setTitle( __('pair.title') );\n\n$(function() {\n  $('#test-connection').click(function() {\n    $('.mi-device-test').hide();\n    $('.mi-device-error').hide();\n    $('.mi-device-ok').hide();\n\n\t\tlet inputaddress = $('#address').val();\n\t\tlet inputtoken = $('#token').val();\n    let inputpolling = Number($('#polling').val()) || 60;\n\n    if( inputaddress != '' && inputtoken != '' && inputpolling != '') {\n      let device_data = {\n        address: inputaddress,\n        token: inputtoken,\n        polling: inputpolling\n      };\n\n      Homey.emit('test_connection', device_data)\n        .then(result => {\n          $('.mi-device-test').show();\n          $('#connect').prop('disabled', false);\n        }).catch(error => {\n          $('.mi-device-error').show();\n          $('.mi-device-error-msg').html(error.message || error.toString());\n        });\n\n    } else {\n      $('.mi-device-error').show();\n      $('.mi-device-error-msg').html( __('pair.nosettings') );\n    }\n\n\t});\n\n  $('#connect').click(function() {\n    Homey.showView('add_device');\n\t});\n\n})\n</script>\n\n<style type=\"text/css\">\n  .form-group {\n    width: 100%;\n    display: block;\n    margin-bottom: 12px;\n  }\n  .form-group label {\n    display: block;\n  }\n  .mi-device-test, .mi-device-error {\n\t\tdisplay: none;\n\t}\n  .shelly-info {\n    margin-top: 10px;\n    font-size: 12px;\n  }\n  .buttons, .messages {\n    padding-top: 14px;\n  }\n  .button {\n    font-weight: 700;\n  }\n  .button:disabled {\n    color: #ccc;\n  }\n  .button:enabled {\n    color: #fff !important;\n  }\n  #test-connection:enabled {\n    background-color: #1875cf !important;\n  }\n  #connect:enabled {\n    background-color: #00c139 !important;\n  }\n</style>\n\n<p data-i18n=\"pair.intro\">Enter the details of your Mi Home device.</p>\n<div class=\"mi-device-pairing\">\n  <div class=\"form-group\">\n    <label for=\"address\" data-i18n=\"pair.address\">IP address</label>\n    <input type=\"text\" class=\"form-control\" id=\"address\" placeholder=\"192.168.0.100\">\n  </div>\n  <div class=\"form-group\">\n  \t<label for=\"token\" data-i18n=\"pair.token\">Token (32 characters of numbers and letters)</label>\n  \t<input type=\"text\" class=\"form-control\" id=\"token\" pattern=\"[a-zA-Z0-9]{32}\" placeholder=\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\">\n  </div>\n  <div class=\"form-group\">\n    <label for=\"polling\" data-i18n=\"pair.polling\">Polling Frequency</label>\n    <input type=\"number\" class=\"form-control\" id=\"polling\" min=\"30\" max=\"3600\" placeholder=\"60\">\n  </div>\n  <input type=\"hidden\" id=\"fanspeed\" value=\"\">\n  <input type=\"hidden\" id=\"state\" value=\"\">\n  <div class=\"form-group buttons\">\n    <button id=\"test-connection\" class=\"button\" data-i18n=\"pair.test\">Test Connection</button>\n    <button id=\"connect\" class=\"button\" data-i18n=\"pair.connect\" disabled>Connect</button>\n  </div>\n</div>\n\n<div class=\"messages\">\n  <p class=\"mi-device-status mi-device-test\" style=\"color: #008C23;\"><i class=\"fa fa-check\"></i> <span data-i18n=\"pair.testResult\">Connection test successful, you can now connect the device with Homey.</span></p>\n  <p class=\"mi-device-status mi-device-error\" style=\"color: #ff6300;\"><i class=\"fa fa-times\"></i> <span class=\"mi-device-error-msg\"></span></p>\n</div>\n"
  },
  {
    "path": "drivers/zhimi-fan/pair/start.html",
    "content": "<script type=\"text/javascript\">\n  Homey.setTitle( __('pair.title') );\n</script>\n\n<style type=\"text/css\">.hy-tmpl-start{height:100%;display:flex;flex-direction:column;align-items:center}.hy-tmpl-start-form{position:relative;width:100%}.hy-tmpl-start-logo{display:block;position:relative;width:25vw;height:25vw;margin:20vw auto;background-position:center center;background-repeat:no-repeat;background-size:contain}.hy-tmpl-start-row{margin-bottom:1em}</style>\n\n<div class=\"hy-view .hy-tmpl-start\" data-id=\"start\">\n  <div class=\"hy-tmpl-start-logo\" style=\"background-image: url('../../../assets/xiaomi-logo.png');\"></div>\n  <div class=\"hy-tmpl-start-row row\" data-i18n=\"pair.startpairing\">For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.</div>\n</div>\n"
  },
  {
    "path": "lib/MiHub.js",
    "content": "const EventEmitter = require(\"events\");\nconst MiGateway = require(\"mimorelinks\");\n\nclass MiHub extends EventEmitter {\n  constructor(opts) {\n    super();\n    this.setMaxListeners(150);\n    this.log = opts.log;\n    this.homey = opts.homey;\n    this.hubs;\n    this.hubsList = this.homey.settings.get(\"gatewaysList\") || [];\n    this.MiInitialize(this.hubsList);\n    this.gateways;\n  }\n\n  MiInitialize(gateways) {\n    var that = this;\n    if (gateways.length > 0) {\n      this.gatewaysList = [];\n      gateways.forEach(gateway => {\n        this.log(gateway);\n        let data = {\n          sid: gateway.mac.toLowerCase(),\n          password: gateway.password.toUpperCase()\n        };\n        this.gatewaysList.push(data);\n      });\n      if (MiGateway._start) {\n        MiGateway.stop();\n        this.log(\"Stop running Mi Gateway!\");\n      }\n      MiGateway.create(this.gatewaysList, {\n        onMessage(msg) {\n          that.devicesReport(msg);\n        }\n      });\n      MiGateway.start();\n      this.gateways = MiGateway._miAqara.gatewayHelper.gateways;\n      this.hubs = true;\n    } else {\n      this.log(\"Please insert gateway mac address and password in settings on Manager Settings\");\n      if (MiGateway._start) {\n        MiGateway.stop();\n        this.log(\"Mi Hub stopped!!!\");\n      }\n      this.hubs = false;\n    }\n  }\n\n  async getDevice(sid) {\n    const device = MiGateway.getDeviceBySid(sid);\n    return device;\n  }\n\n  async getDevicesByModel(modelTypes) {\n    const devices = MiGateway.getDeviceList();\n    return devices.filter(device => modelTypes.includes(device.model));\n  }\n\n  async getGatewayByModel(modelTypes) {\n    const gateways = MiGateway.getGatewayList();\n    return gateways.filter(gateway => modelTypes.includes(gateway.model));\n  }\n\n  updateGateways(gateways) {\n    this.log(\"updateGateways: \", gateways);\n    this.MiInitialize(gateways);\n  }\n\n  devicesReport(data) {\n    const devices = MiGateway.getDeviceList();\n    const gateways = MiGateway.getGatewayList();\n\n    if (data.cmd == \"report\") {\n      devices.forEach(device => {\n        if (data.sid == device.sid) {\n          this.emit(`${device.sid}`, device);\n        }\n      });\n    } else if (data.cmd == \"read_ack\") {\n      devices.forEach(device => {\n        if (data.sid == device.sid) {\n          this.emit(`${device.sid}`, device);\n        }\n      });\n\n      gateways.forEach(gateway => {\n        if (data.sid == gateway.sid) {\n          this.emit(`${gateway.sid}`, data);\n        }\n      });\n    }\n  }\n\n  async sendWrite(sid, data) {\n    MiGateway.change({ sid: sid, data: data });\n  }\n\n  async sendWriteCmd(sid, data) {\n    MiGateway.writeCmd(sid, data);\n  }\n\n  async controlLightHLS(sid, hue, saturation, brightness) {\n    MiGateway.controlLightHLS({\n      sid: sid,\n      hue: hue,\n      saturation: saturation,\n      brightness: brightness\n    });\n  }\n\n  async controlLightRGB(sid, rgb) {\n    MiGateway.controlLightRGB({ sid: sid, rgb: rgb });\n  }\n\n  async controlLightPower(sid, power) {\n    MiGateway.controlLightPower({ sid: sid, power: power });\n  }\n\n  async controlMid(sid, mid, vol) {\n    MiGateway.controlMid({ sid: sid, mid: mid, vol: vol });\n  }\n\n  getGateways() {\n    return this.gatewaysList;\n  }\n}\n\nmodule.exports = MiHub;\n"
  },
  {
    "path": "lib/util.js",
    "content": "'use strict';\n\nclass Util {\n\n  static modelToFriendlyNameWiFi = {\n    'zhimi.airmonitor.v1': 'Mi Air Quality Monitor',\n    'cgllc.airmonitor.b1': 'Mi Air Quality Monitor gen2',\n    'cgllc.airmonitor.s1': 'Mi ClearGrass Air Detector',\n\n    'zhimi.airpurifier.v1': 'Air Purifier',\n    'zhimi.airpurifier.v2': 'Air Purifier v2',\n    'zhimi.airpurifier.v3': 'Air Purifier v3',\n    'zhimi.airpurifier.v5': 'Air Purifier v5',\n    'zhimi.airpurifier.v6': 'Air Purifier Pro',\n    'zhimi.airpurifier.v7': 'Air Purifier Pro v7',\n    'zhimi.airpurifier.m1': 'Air Purifier 2 Mini',\n    'zhimi.airpurifier.m2': 'Air Purifier Mini',\n    'zhimi.airpurifier.ma1': 'Air Purifier 2S',\n    'zhimi.airpurifier.ma2': 'Air Purifier 2S',\n    'zhimi.airpurifier.sa1': 'Air Purifier Super/Max',\n    'zhimi.airpurifier.sa2': 'Air Purifier Super/Max 2',\n    'zhimi.airpurifier.mc1': 'Air Purifier 2S',\n    'zhimi.airpurifier.mc2': 'Air Purifier 2H',\n\n    'zhimi.airpurifier.ma4': 'Air Purifier 3',\n    'zhimi.airpurifier.mb3': 'Air Purifier 3H',\n    'zhimi.airpurifier.mb3a': 'Air Purifier 3H',\n    'zhimi.airp.mb3a': 'Air Purifier 3H',\n    'zhimi.airpurifier.va1': 'Airpurifier Pro H',\n    'zhimi.airpurifier.vb2': 'Airpurifier Pro H',\n    'zhimi.airpurifier.mb4': 'Air Purifier 3C',\n    'zhimi.airp.mb4a': 'Air Purifier 3C',\n    'zhimi.airp.mb5': 'Air Purifier 4',\n    'zhimi.airp.mb5a': 'Air Purifier 4',\n    'zhimi.airp.va2': 'Air Purifier 4 Pro',\n    'zhimi.airp.va4': 'Air Purifier 4 Pro',\n    'zhimi.airp.vb4': 'Air Purifier 4 Pro',\n    'zhimi.airpurifier.rma1': 'Air Purifier 4 Lite',\n    'zhimi.airp.rmb1': 'Air Purifier 4 Lite',\n    'zhimi.airpurifier.za1': 'Smartmi Air Purifier',\n    'zhimi.airp.meb1': 'Xiaomi Smart Air Purifier Elite',\n    'xiaomi.airp.cpa4': 'Xiaomi Smart Air Purifier 4 Compact',\n\n    'zhimi.airfresh.va2': 'Smartmi Fresh Air System VA2',\n    'zhimi.airfresh.va4': 'Smartmi Fresh Air System VA4',\n\n    'zhimi.airfresh.ua1': 'Mi Fresh Air Ventilator C1-80',\n\n    'airdog.airpurifier.x3': 'Airdog X3 Air Purifier',\n    'airdog.airpurifier.x5': 'Airdog X5 Air Purifier',\n    'airdog.airpurifier.x7sm': 'Airdog X7s Air Purifier',\n\n    'dmaker.airfresh.t2017': 'Mi Air Purifier (MJXFJ-300-G1)',\n    'dmaker.airfresh.a1': 'Mi Air Purifier (MJXFJ-150-A1)',\n\n    'zhimi.humidifier.v1': 'Smartmi Humidifier',\n    'zhimi.humidifier.ca1': 'Smartmi Evaporative Humidifier',\n    'zhimi.humidifier.cb1': 'Smartmi Evaporative Humidifier',\n    'zhimi.humidifier.cb2': 'Smartmi Evaporative Humidifier',\n    'zhimi.humidifier.ca4': 'Smartmi Evaporative Humidifier v2',\n    'zhimi.humidifier.ca6': 'Smartmi Evaporative Humidifier 3',\n    'zhimi.humidifier.jd1': 'Smartmi Humidifier Rainforest',\n\n    'xiaomi.humidifier.airmx': 'Mijia Mistless Humidifier 3 Pro',\n    'xiaomi.humidifier.600ek': 'Mijia Smart Evaporative Humidifier Pro',\n    'xiaomi.humidifier.3lite': 'Xiaomi Smart Humidifier 3 Lite',\n\n    'deerma.humidifier.jsq': 'Mijia Smart Sterilization Humidifier JSQ',\n    'deerma.humidifier.jsq1': 'Mijia Pure Smart Humidifier JSQ1',\n    'deerma.humidifier.mjjsq': 'Mijia Smart Sterilization Humidifier MJJSQ',\n    'deerma.humidifier.jsq4': 'Mi Smart Antibacterial Humidifier JSQ4',\n    'deerma.humidifier.jsq5': 'Mi Smart Antibacterial Humidifier JSQ5',\n    'deerma.humidifier.jsqs': 'Mi Smart Antibacterial Humidifier JSQS',\n    'deerma.humidifier.jsq2w': 'Mi Smart Antibacterial Humidifier JSQ2W',\n\n    'leshow.humidifier.jsq1': 'Xiaomi Humidifier Pro',\n    'shuii.humidifier.jsq001': 'Humidifier JSQ001',\n    'xwhzp.diffuser.xwxfj': 'Mijia Smart Scent Diffuser',\n\n    'dmaker.derh.22ht': 'Xiaomi Smart Dehumidifier',\n    'xiaomi.derh.lite': 'Xiaomi Smart Dehumidifier Lite',\n    'xiaomi.derh.13l': 'Mijia Smart Dehumidifier 13L',\n\n    'dmaker.fan.p5': 'DMaker Fan X1',\n    'dmaker.fan.p9': 'Mi Smart Tower Fan',\n    'dmaker.fan.p10': 'Mi Smart Standing Fan 2',\n    'dmaker.fan.p11': 'Mi Smart Standing Fan Pro',\n    'dmaker.fan.p15': 'Mi Smart Standing Fan Pro EU',\n    'dmaker.fan.p18': 'Mi Smart Fan 2',\n    'dmaker.fan.p33': 'Mi Smart Standing Fan 2 Pro',\n    'dmaker.fan.p44': 'Mi Smart Evaporative Cooling Fan',\n    'dmaker.fan.1c': 'Mi Smart Standing Fan 2 Lite',\n\n    'zhimi.fan.v2': 'Smartmi DC Pedestal Fan v2',\n    'zhimi.fan.v3': 'Smartmi DC Pedestal Fan v3',\n    'zhimi.fan.sa1': 'Smartmi Standing Fan',\n    'zhimi.fan.za1': 'Smartmi Inverter Pedestal Fan',\n    'zhimi.fan.za3': 'Smartmi Standing Fan 2',\n    'zhimi.fan.za4': 'Smartmi Standing Fan 2S',\n    'zhimi.fan.za5': 'Smartmi Standing Fan 3',\n    \"xiaomi.fan.p45\": \"Xiaomi Smart Tower Fan 2\",\n\n    'zhimi.heater.mc2': 'Smart Space Heater S',\n    'zhimi.heater.za2': 'Smart Space Heater 1S',\n    'leshow.heater.bs1s': 'Smart Space Heater BS1S',\n    'zhimi.heater.nb1': 'Smartmi Smart Fan Heater',\n    'zhimi.heater.zb1a': 'Smartmi Smart Convector Heater 1S',\n\n    'hyd.airer.znlyj4': 'Mijia Smart Clothes Drying Rack',\n\n    'rockrobo.vacuum.v1': 'Roborock Vacuum v1',\n    'roborock.vacuum.c1': 'Roborock Vacuum S5 Max',\n    'rockrobo.vacuum.1s': 'Roborock Vacuum 1S',\n    'roborock.vacuum.e2': 'Roborock Vacuum E2',\n    'roborock.vacuum.s4': 'Roborock Vacuum S4',\n    'roborock.vacuum.s5': 'Roborock Vacuum S5',\n    'roborock.vacuum.s5e': 'Roborock Vacuum S5e',\n    'roborock.vacuum.s6': 'Roborock Vacuum S6',\n    'roborock.vacuum.t4': 'Roborock Vacuum T4',\n    'roborock.vacuum.t6': 'Roborock Vacuum T6',\n    'roborock.vacuum.a08': 'Roborock Vacuum S6 Pure',\n    'roborock.vacuum.a09': 'Roborock Vacuum T7 Pro',\n    'roborock.vacuum.a10': 'Roborock Vacuum S6 MaxV',\n    'roborock.vacuum.a11': 'Roborock Vacuum T7',\n    'roborock.vacuum.a14': 'Roborock Vacuum T7S',\n    'roborock.vacuum.a15': 'Roborock Vacuum S7',\n    'roborock.vacuum.a19': 'Roborock Vacuum S4 Max',\n    'roborock.vacuum.a23': 'Roborock Vacuum T7S Plus',\n    'roborock.vacuum.a26': 'Roborock Vacuum G10S Pro',\n    'roborock.vacuum.a27': 'Roborock Vacuum S7 MaxV Ultra',\n    'roborock.vacuum.a29': 'Roborock Vacuum G10',\n    'roborock.vacuum.a34': 'Roborock Vacuum Q5',\n    'roborock.vacuum.a38': 'Roborock Vacuum Q7 Max',\n    'roborock.vacuum.a40': 'Roborock Vacuum Q7',\n    'roborock.vacuum.a46': 'Roborock Vacuum G10S',\n    'roborock.vacuum.a51': 'Roborock Vacuum S8',\n    'roborock.vacuum.a62': 'Roborock Vacuum S7 Pro Ultra',\n    'roborock.vacuum.a65': 'Roborock Vacuum S7 Max Ultra',\n    'roborock.vacuum.a70': 'Roborock S8 Ultra Pro',\n    'roborock.vacuum.a72': 'Roborock Q5 Pro',\n    'roborock.vacuum.a73': 'Roborock Vacuum Q8 Max',\n    'roborock.vacuum.a75': 'Roborock Revo Q',\n    'roborock.vacuum.p5': 'Roborock Vacuum P5',\n    'roborock.vacuum.m1s': 'Mijia Vacuum M1S',\n\n    'dreame.vacuum.mc1808': 'Mijia Vacuum 1C',\n    'dreame.vacuum.p2008': 'Dreame Robot Vacuum-Mop F9',\n    'dreame.vacuum.p2009': 'Dreame Robot Vacuum D9',\n    'dreame.vacuum.p2027': 'Dreame Bot W10 Pro',\n    'dreame.vacuum.p2028': 'Dreame Bot Z10 Pro',\n    'dreame.vacuum.p2041o': 'Mi Robot Vacuum-Mop 2 Pro+',\n    'dreame.vacuum.p2150a': 'Mi Robot Vacuum-Mop 2 Ultra',\n    'dreame.vacuum.p2150o': 'Mi Robot Vacuum-Mop 2 Ultra',\n    'dreame.vacuum.p2029': 'Dreame Bot L10 Pro',\n    'dreame.vacuum.p2041': 'Xiaomi Vacuum 1T',\n    'dreame.vacuum.r2205': 'Dreame Bot D10 Plus',\n    'dreame.vacuum.r2228o': 'Dreame Bot L10s Ultra',\n    'dreame.vacuum.r2209': 'Xiaomi/Dreame Robot Vacuum X10',\n    'dreame.vacuum.p2114a': 'Xiaomi/Dreame Robot Vacuum X10+',\n    'dreame.vacuum.r2211o': 'Xiaomi/Dreame Robot Vacuum S10+',\n    'dreame.vacuum.r2232c': 'Dreame Bot L10s Prime',\n    'dreame.vacuum.r2338a': 'Dreame L10s Pro Ultra',\n    'dreame.vacuum.r2416': 'Dreame X40 Ultra',\n    'dreame.vacuum.r2449': 'Dreame X40 Ultra Complete',\n\n    'mijia.vacuum.v1': 'Xiaomi Mijia G1 Robot Vacuum Mop v1',\n    'mijia.vacuum.v2': 'Xiaomi Mijia G1 Robot Vacuum Mop v2',\n    'mijia.vacuum.v3': 'Mi Robot Vacuum-Mop Essential',\n    'mijia.vacuum.b108za': 'Mi Robot Vacuum-Mop 2S',\n    'mijia.vacuum.b108zb': 'Mi Robot Vacuum-Mop 3S',\n\n    'xiaomi.vacuum.b112gl': 'Xiaomi Robot Vacuum E12',\n    'xiaomi.vacuum.b106eu': 'Xiaomi Robot Vacuum S12',\n    'xiaomi.vacuum.b112': 'Xiaomi Robot Vacuum E10',\n    'xiaomi.vacuum.c101': 'Xiaomi Self-Cleaning Vacuum Robot 2 C101',\n    'xiaomi.vacuum.c102gl': 'Xiaomi Robot Vacuum X20+',\n    'xiaomi.vacuum.d109gl': 'Xiaomi Robot Vacuum X20 Max',\n    'xiaomi.vacuum.d102gl': 'Xiaomi Robot Vacuum X20 Pro',\n    'xiaomi.vacuum.d101': 'Xiaomi Robot Vacuum H40',\n    'xiaomi.vacuum.d101gl': 'Xiaomi Robot Vacuum H40 (CN)',\n    'xiaomi.vacuum.ov51gl': 'Xiaomi Robot Vacuum H40 (EU)',\n    'xiaomi.vacuum.b108gl': 'Xiaomi Robot Vacuum S20+',\n\n    'ijai.vacuum.v1': 'Mi Robot Vacuum-Mop Pro',\n    'ijai.vacuum.v2': 'Mi Robot Vacuum-Mop 2',\n    'ijai.vacuum.v3': 'Mi Robot Vacuum-Mop 2 Pro',\n    'ijai.vacuum.v10': 'Mi Robot Vacuum-Mop 2 Lite',\n    'ijai.vacuum.v13': 'Mi Robot Vacuum-Mop 2 Pro',\n    'ijai.vacuum.v14': 'Mi Robot Vacuum-Mop G1',\n    'ijai.vacuum.v15': 'Mi Robot Vacuum-Mop 2 Pro',\n    'ijai.vacuum.v16': 'Mi Robot Vacuum-Mop 2i',\n    'ijai.vacuum.v17': 'Xiaomi Robot Vacuum S10',\n    'ijai.vacuum.v18': 'Mi Robot Vacuum-Mop 3C',\n    'ijai.vacuum.v19': 'Mi Robot Vacuum-Mop 2S',\n\n    'viomi.vacuum.v7': 'Mi Robot Vacuum-Mop P v7',\n    'viomi.vacuum.v8': 'Mi Robot Vacuum-Mop P v8',\n\n    'roidmi.vacuum.v60': 'Roidmi Eve',\n    'roidmi.vacuum.v66': 'Roidmi Eva',\n\n    'chuangmi.plug.m1': 'Mi Smart Plug WiFi',\n    'chuangmi.plug.m2': 'Mi Smart Plug WiFi',\n    'chuangmi.plug.m3': 'Mi Smart Plug WiFi',\n    'chuangmi.plug.v1': 'Mi Smart Plug With USB WiFi',\n    'chuangmi.plug.v2': 'Mi Smart Plug With 2 USB WiFi',\n    'chuangmi.plug.v3': 'Mi Smart Plug With 2 USB WiFi',\n    'chuangmi.plug.hmi206': 'Mi Smart Plug WiFi',\n    'qmi.powerstrip.v1': 'Mi Power Strip v1',\n    'zimi.powerstrip.v2': 'Mi Power Strip v2',\n    'cuco.plug.v2eur': 'Xiaomi Smart Plug 2',\n\n    'philips.light.sread1': 'Eyecare Lamp 2',\n    'philips.light.bulb': 'Philips Light Bulb',\n    'philips.light.candle': 'Philips Candle',\n    'philips.light.candle2': 'Philips Candle',\n    'philips.light.ceiling': 'Philips Ceiling Light',\n    'philips.light.zyceiling': 'Philips Ceiling Light',\n    'philips.light.mono1': 'Philips Light Bulb',\n    'philips.light.downlight': 'Philips Down Light',\n    'philips.light.strip5': 'Philips / Xiaomi Smart Lightstrip Pro',\n    'yeelink.light.ceil43': 'Yeelight Arwen Ceiling Light D',\n\n    'lumi.gateway.v2': 'Xiaomi Gateway v1',\n    'lumi.gateway.v3': 'Xiaomi Gateway v2',\n    'lumi.gateway.mcn001': 'Xiaomi Smart Home Hub 2',\n    'lumi.acpartner.v1': 'Aqara Gateway v1',\n    'lumi.acpartner.v2': 'Aqara Gateway v2',\n    'lumi.acpartner.v3': 'Aqara Gateway v3',\n    'chuangmi.remote.v2': 'Universal Intelligent IR Remote Controller',\n\n    'mmgg.pet_waterer.s1': 'Xiaowan Smart Pet Water Dispenser',\n    'mmgg.pet_waterer.s4': 'Xiaowan Smart Pet Water Dispenser',\n    'mmgg.pet_waterer.wi11': 'Xiaomi Smart Pet Fountain',\n    'xiaomi.pet_waterer.iv02': 'Xiaomi Smart Pet Fountain 2',\n\n    'mmgg.feeder.fi1': 'Xiaomi Smart Pet Food Feeder',\n    'mmgg.feeder.inland': 'Xiaomi Smart Pet Food Feeder',\n    'mmgg.feeder.spec': 'Xiaowan Smart Pet Feeder',\n    'xiaomi.feeder.pi2001': 'Xiaomi Smart Pet Food Feeder 2',\n    'xiaomi.feeder.iv2001': 'Mi Smart Pet Feeder 2 CN',\n\n    'careli.fryer.maf05a': 'Xiaomi Smart Air Fryer Pro 4L',\n    'careli.fryer.ybaf04': 'KitchenMi Smart Air Fryer 6007WAB',\n    'careli.fryer.ybaf03': 'KitchenMi Smart Air Fryer 6007WA',\n    'careli.fryer.maf02c': 'Mi Smart Air Fryer (3.5L)',\n    'careli.fryer.maf07': 'Mi Smart Air Fryer (3.5L)',\n    'careli.fryer.maf02': 'Mi Smart Air Fryer (3.5L)'\n  }\n\n  static modelToFriendlyNameSubdevice = {\n    'remote.b186acn01': 'Aqara Wireless Wall Single Switch (Advanced)',\n    'remote.b286acn01': 'Aqara Wireless Wall Double Switch (Advanced)',\n    '86sw1': 'Aqara Wireless Wall Single Switch',\n    '86sw2': 'Aqara Wireless Wall Double Switch',\n    'sensor_switch.aq2': 'Aqara Wireless Button',\n    'sensor_switch.aq3': 'Aqara Wireless Button (Advanced)',\n    'sensor_switch': 'Aqara Wireless Button',\n    'remote.b1acn01': 'Aqara Wireless Button',\n    'ctrl_ln1.aq1': 'Aqara Smart Wall Single Switch With Neutral',\n    'switch_b1nacn02': 'Aqara Smart Wall Single Switch With Neutral',\n    'ctrl_ln1.aq2': 'Aqara Smart Wall Double Switch With Neutral',\n    'switch_b2nacn02': 'Aqara Smart Wall Double Switch With Neutral',\n    'ctrl_neutral1': 'Aqara Smart Wall Single Switch No Neutral',\n    'switch_b1lacn02': 'Aqara Smart Wall Single Switch No Neutral',\n    'ctrl_neutral2': 'Aqara Smart Wall Double Switch No Neutral',\n    'switch_b2lacn02': 'Aqara Smart Wall Double Switch No Neutral',\n    'curtain': 'Aqara Curtain Motor',\n    'curtain.hagl04': 'Aqara Curtain Motor',\n    'curtain.aq2': 'Aqara Roller Shade Controller',\n    'sensor_magnet.aq2': 'Aqara Magnet Sensor',\n    'sensor_motion.aq2': 'Aqara Motion Sensor',\n    'weather.v1': 'Aqara Temperature & Humidity Sensor',\n    'sensor_wleak.aq1': 'Aqara Waterleak Sensor',\n    'cube': 'Mi Aqara Cube',\n    'sensor_cube.aqgl01': 'Mi Aqara Cube',\n    'sensor_cube': 'Mi Aqara Cube',\n    'switch': 'Mi Wireless Button',\n    'magnet': 'Mi Magnet Sensor',\n    'motion': 'Mi Motion Sensor',\n    'sensor_ht': 'Mi Temperature & Humidity Sensor',\n    'natgas': 'Miia Gas Leak Detector',\n    'sensor_natgas': 'Miia Gas Leak Detector',\n    'ctrl_86plug.aq1': 'Aqara Wall Outlet',\n    'lumi.ctrl_86plug.aq1': 'Aqara Wall Outlet',\n    'lumi.ctrl_86plug': 'Aqara Wall Outlet',\n    'lock.aq1': 'Aqara Lock',\n    'relay.c2acn01': 'Aqara 2 Channel Relay',\n    'lumi.relay.c2acn01': 'Aqara 2 Channel Relay',\n    'vibration': 'Vibration Sensor',\n    'plug': 'Mi Smart Plug'\n  }\n\n  constructor(opts) {\n    this.homey = opts.homey;\n  }\n\n  getFriendlyNameWiFi(model) {\n    return Util.modelToFriendlyNameWiFi[model];\n  }\n\n  getFriendlyNameSubdevice(model) {\n    return Util.modelToFriendlyNameSubdevice[model];\n  }\n\n\tnormalize(value, min, max) {\n    var normalized = (value - min) / (max - min);\n    return Number(normalized.toFixed(2));\n  }\n\n  denormalize(normalized, min, max) {\n    var denormalized = ((1 - normalized) * (max - min) + min);\n    return Number(denormalized.toFixed(0));\n  }\n\n  getRandomTimeout(max) {\n    return ((Math.floor(Math.random() * Math.floor(max)) * 1000) + 2000);\n  }\n\n  clamp(value, min, max) {\n    return Math.min(Math.max(value, min), max);\n  }\n\n  sleep(ms) {\n  \treturn new Promise(resolve => setTimeout(resolve, ms));\n  }\n\n}\n\nmodule.exports = Util;\n"
  },
  {
    "path": "locales/da.json",
    "content": "{\n  \"pair\": {\n    \"title\": \"Tilføj Mi Home enhed\",\n    \"startpairing\": \"For at Homey kan kommunikere med enheder over miIO protokollen, skal der opnås en unik enheds-token. Teknisk viden er nødvendig for at hente disse tokens. Hvis du ikke er så teknisk kyndig, kan det være udfordrende at bruge denne app. Se instruktionerne i supportemnet på community forumet om at hente enheds-tokens.\",\n    \"nosettings\": \"Udfyld venligst alle felterne.\",\n    \"intro\": \"Indtast detaljerne for din Mi Home enhed.\",\n    \"address\": \"IP-adresse\",\n    \"token\": \"Token (32 tegn af numre og bogstaver)\",\n    \"polling\": \"Polling-frekvens\",\n    \"test\": \"Test forbindelse\",\n    \"testResult\": \"Forbindelsestest var succesfuld, du kan nu tilslutte enheden til Homey.\",\n    \"connect\": \"Tilslut\",\n    \"unknownerror\": \"Ukendt fejl, er du sikker på, at du har indtastet den korrekte IP-adresse og token, og at Homey er på samme netværk som Mi Home enheden? Kontrollér venligst dine indstillinger og prøv igen.\",\n    \"state\": \"Status:\",\n    \"battery\": \"Batteriniveau:\",\n    \"fanspeed\": \"Ventilatorhastighed:\",\n    \"no_devices_found\": \"Ingen enheder fundet.\",\n    \"no_gateways\": \"Ingen gateways fundet. \\n\\n Før du tilføjer enheder, skal du åbne plugin-indstillingerne og tilføje din Xiaomi gateway.\\n Aqara gateway understøttes endnu ikke.\"\n  },\n  \"device\": {\n    \"unreachable\": \"Enheden er utilgængelig: \",\n    \"noupdates\": \"Enheden har endnu ikke modtaget nogen opdateringer\"\n  }\n}"
  },
  {
    "path": "locales/de.json",
    "content": "{\n  \"pair\": {\n    \"title\": \"Mi Home Gerät hinzufügen\",\n    \"startpairing\": \"Damit Homey mit Geräten über das miIO-Protokoll kommunizieren kann, muss ein einzigartiger Gerätetoken abgerufen werden. Technisches Wissen ist erforderlich, um diese Tokens zu erhalten. Wenn du nicht sehr technisch versiert bist, könnte die Nutzung dieser App herausfordernd sein. Sieh dir die Anweisungen im Support-Thema im Community-Forum zum Abrufen von Gerätetokens an.\",\n    \"nosettings\": \"Bitte fülle alle Felder aus.\",\n    \"intro\": \"Gib die Details deines Mi Home Geräts ein.\",\n    \"address\": \"IP-Adresse\",\n    \"token\": \"Token (32 Zeichen aus Zahlen und Buchstaben)\",\n    \"polling\": \"Abfragehäufigkeit\",\n    \"test\": \"Verbindung testen\",\n    \"testResult\": \"Verbindungstest erfolgreich, du kannst das Gerät jetzt mit Homey verbinden.\",\n    \"connect\": \"Verbinden\",\n    \"unknownerror\": \"Unbekannter Fehler, bist du sicher, dass du die richtige IP-Adresse und den richtigen Token eingegeben hast und dass Homey im selben Netzwerk wie das Mi Home Gerät ist? Bitte überprüfe deine Einstellungen und versuche es erneut.\",\n    \"state\": \"Status:\",\n    \"battery\": \"Batteriestand:\",\n    \"fanspeed\": \"Lüftergeschwindigkeit:\",\n    \"no_devices_found\": \"Keine Geräte gefunden.\",\n    \"no_gateways\": \"Keine Gateways gefunden. \\n\\n Bevor du Geräte hinzufügst, öffne bitte die Plug-in-Einstellungen und füge dein Xiaomi Gateway hinzu.\\n Aqara Gateway wird noch nicht unterstützt.\"\n  },\n  \"device\": {\n    \"unreachable\": \"Gerät ist nicht erreichbar: \",\n    \"noupdates\": \"Gerät hat noch keine Updates erhalten\"\n  }\n}"
  },
  {
    "path": "locales/en.json",
    "content": "{\n  \"pair\": {\n    \"title\": \"Add Mi Home device\",\n    \"startpairing\": \"For Homey to be able to communicate with devices over the miIO protocol a unique device token needs to be obtained. Technical knowledge is needed for retrieving these tokens. If your are not to tech-savvy using this app might be challenging. See the instructions in the support topic on the community forum on retrieving device tokens.\",\n    \"nosettings\": \"Please fill in all the fields.\",\n    \"intro\": \"Enter the details of your Mi Home device.\",\n    \"address\": \"IP Address\",\n    \"token\": \"Token (32 characters of numbers and letters)\",\n    \"polling\": \"Polling Frequency\",\n    \"test\": \"Test Connection\",\n    \"testResult\": \"Connection test successful, you can now connect the device with Homey.\",\n    \"connect\": \"Connect\",\n    \"unknownerror\": \"Unknown error, are you sure you have entered the correct IP address and token and that Homey is on the same network as the Mi Home device? Please check your settings and try again.\",\n    \"state\": \"State:\",\n    \"battery\": \"Batterylevel:\",\n    \"fanspeed\": \"Fanspeed:\",\n    \"no_devices_found\": \"No devices found.\",\n    \"no_gateways\": \"No gateways found. \\n\\n Before adding devices, please open the plugin settings and add your Xiaomi gateway.\\n Aqara gateway is not yet supported.\"\n  },\n  \"device\": {\n    \"unreachable\": \"Device is unreachable: \",\n    \"noupdates\": \"Device has not received any updates yet\"\n  }\n}\n"
  },
  {
    "path": "locales/es.json",
    "content": "{\n  \"pair\": {\n    \"title\": \"Agregar dispositivo Mi Home\",\n    \"startpairing\": \"Para que Homey pueda comunicarse con los dispositivos a través del protocolo miIO, es necesario obtener un token único del dispositivo. Se necesita conocimiento técnico para obtener estos tokens. Si no eres muy conocedor de la tecnología, usar esta aplicación puede ser un desafío. Ve las instrucciones en el tema de soporte del foro de la comunidad sobre cómo obtener los tokens de los dispositivos.\",\n    \"nosettings\": \"Por favor, completa todos los campos.\",\n    \"intro\": \"Ingresa los detalles de tu dispositivo Mi Home.\",\n    \"address\": \"Dirección IP\",\n    \"token\": \"Token (32 caracteres de números y letras)\",\n    \"polling\": \"Frecuencia de Polling\",\n    \"test\": \"Probar Conexión\",\n    \"testResult\": \"Prueba de conexión exitosa, ahora puedes conectar el dispositivo con Homey.\",\n    \"connect\": \"Conectar\",\n    \"unknownerror\": \"Error desconocido, ¿estás seguro de haber ingresado la dirección IP y el token correctos y de que Homey está en la misma red que el dispositivo Mi Home? Por favor, revisa tu configuración e inténtalo de nuevo.\",\n    \"state\": \"Estado:\",\n    \"battery\": \"Nivel de batería:\",\n    \"fanspeed\": \"Velocidad del ventilador:\",\n    \"no_devices_found\": \"No se encontraron dispositivos.\",\n    \"no_gateways\": \"No se encontraron gateways. \\n\\n Antes de agregar dispositivos, por favor abres la configuración del plugin y agregues tu gateway Xiaomi.\\n El gateway Aqara aún no es compatible.\"\n  },\n  \"device\": {\n    \"unreachable\": \"El dispositivo está inaccesible: \",\n    \"noupdates\": \"El dispositivo aún no ha recibido ninguna actualización\"\n  }\n}"
  },
  {
    "path": "locales/fr.json",
    "content": "{\n  \"pair\": {\n    \"title\": \"Ajouter un appareil Mi Home\",\n    \"startpairing\": \"Pour que Homey puisse communiquer avec des appareils via le protocole miIO, un token unique doit être obtenu. Des connaissances techniques sont nécessaires pour obtenir ces tokens. Si vous n'êtes pas très à l'aise avec la technologie, utiliser cette application pourrait être un défi. Consultez les instructions sur le sujet de support sur le forum communautaire pour obtenir des tokens d'appareil.\",\n    \"nosettings\": \"Veuillez remplir tous les champs.\",\n    \"intro\": \"Entrez les détails de votre appareil Mi Home.\",\n    \"address\": \"Adresse IP\",\n    \"token\": \"Token (32 caractères de chiffres et lettres)\",\n    \"polling\": \"Fréquence de sondage\",\n    \"test\": \"Tester la connexion\",\n    \"testResult\": \"Test de connexion réussi, vous pouvez maintenant connecter l'appareil avec Homey.\",\n    \"connect\": \"Connecter\",\n    \"unknownerror\": \"Erreur inconnue, êtes-vous sûr d'avoir entré la bonne adresse IP et le bon token et que Homey est sur le même réseau que l'appareil Mi Home ? Veuillez vérifier vos paramètres et réessayer.\",\n    \"state\": \"État :\",\n    \"battery\": \"Niveau de batterie :\",\n    \"fanspeed\": \"Vitesse du ventilateur :\",\n    \"no_devices_found\": \"Aucun appareil trouvé.\",\n    \"no_gateways\": \"Aucune passerelle trouvée. \\n\\n Avant d'ajouter des appareils, veuillez ouvrir les paramètres du plugin et ajouter votre passerelle Xiaomi.\\n La passerelle Aqara n'est pas encore prise en charge.\"\n  },\n  \"device\": {\n    \"unreachable\": \"Appareil injoignable : \",\n    \"noupdates\": \"L'appareil n'a pas encore reçu de mises à jour\"\n  }\n}"
  },
  {
    "path": "locales/it.json",
    "content": "{\n  \"pair\": {\n    \"title\": \"Aggiungi dispositivo Mi Home\",\n    \"startpairing\": \"Per permettere a Homey di comunicare con i dispositivi tramite il protocollo miIO è necessario ottenere un token dispositivo unico. È richiesta una conoscenza tecnica per recuperare questi token. Se non sei molto esperto in tecnologia, usare questa app potrebbe essere una sfida. Consulta le istruzioni nell'argomento di supporto sul forum della community per recuperare i token dei dispositivi.\",\n    \"nosettings\": \"Per favore, compila tutti i campi.\",\n    \"intro\": \"Inserisci i dettagli del tuo dispositivo Mi Home.\",\n    \"address\": \"Indirizzo IP\",\n    \"token\": \"Token (32 caratteri di numeri e lettere)\",\n    \"polling\": \"Frequenza di Polling\",\n    \"test\": \"Testa Connessione\",\n    \"testResult\": \"Connessione riuscita, ora puoi connettere il dispositivo con Homey.\",\n    \"connect\": \"Connetti\",\n    \"unknownerror\": \"Errore sconosciuto, sei sicuro di aver inserito l'indirizzo IP e il token corretti e che Homey sia sulla stessa rete del dispositivo Mi Home? Controlla le tue impostazioni e prova di nuovo.\",\n    \"state\": \"Stato:\",\n    \"battery\": \"Livello batteria:\",\n    \"fanspeed\": \"Velocità ventola:\",\n    \"no_devices_found\": \"Nessun dispositivo trovato.\",\n    \"no_gateways\": \"Nessun gateway trovato. \\n\\n Prima di aggiungere dispositivi, per favore apri le impostazioni del plugin e aggiungi il tuo gateway Xiaomi.\\n Il gateway Aqara non è ancora supportato.\"\n  },\n  \"device\": {\n    \"unreachable\": \"Dispositivo non raggiungibile: \",\n    \"noupdates\": \"Il dispositivo non ha ancora ricevuto aggiornamenti\"\n  }\n}"
  },
  {
    "path": "locales/ko.json",
    "content": "{\n  \"pair\": {\n    \"title\": \"Mi Home 장치 추가\",\n    \"startpairing\": \"Homey가 miIO 프로토콜을 통해 장치와 통신할 수 있도록 하기 위해서는 고유 장치 토큰을 얻어야 합니다. 이 토큰을 얻기 위해서는 기술적인 지식이 필요합니다. 기술 지식이 부족하다면 이 앱을 사용하는 데 어려움이 있을 수 있습니다. 장치 토큰 얻는 방법에 대한 지침은 커뮤니티 포럼의 지원 주제를 참조하세요.\",\n    \"nosettings\": \"모든 필드를 입력해 주세요.\",\n    \"intro\": \"Mi Home 장치의 세부 정보를 입력하세요.\",\n    \"address\": \"IP 주소\",\n    \"token\": \"토큰 (32자의 숫자와 문자)\",\n    \"polling\": \"폴링 주기\",\n    \"test\": \"연결 테스트\",\n    \"testResult\": \"연결 테스트 성공! 이제 장치를 Homey와 연결할 수 있습니다.\",\n    \"connect\": \"연결\",\n    \"unknownerror\": \"알 수 없는 오류입니다. 입력한 IP 주소와 토큰이 올바른지, Homey가 Mi Home 장치와 동일한 네트워크에 있는지 확인해 주세요. 설정을 확인하고 다시 시도해 주세요.\",\n    \"state\": \"상태:\",\n    \"battery\": \"배터리 수준:\",\n    \"fanspeed\": \"팬 속도:\",\n    \"no_devices_found\": \"장치를 찾을 수 없습니다.\",\n    \"no_gateways\": \"게이트웨이를 찾을 수 없습니다. \\n\\n 장치를 추가하기 전에 플러그인 설정을 열고 Xiaomi 게이트웨이를 추가해 주세요.\\n Aqara 게이트웨이는 아직 지원되지 않습니다.\"\n  },\n  \"device\": {\n    \"unreachable\": \"장치에 접근할 수 없습니다: \",\n    \"noupdates\": \"장치가 아직 업데이트를 받지 않았습니다\"\n  }\n}"
  },
  {
    "path": "locales/nl.json",
    "content": "{\n  \"pair\": {\n    \"title\": \"Mi Home apparaat toevoegen\",\n    \"startpairing\": \"Om Homey in staat te stellen om te communiceren met apparaten via het miIO-protocol, moet een uniek apparaatstoken worden verkregen. Technische kennis is nodig om deze tokens te verkrijgen. Als je niet zo technisch bent, kan het gebruik van deze app uitdagend zijn. Zie de instructies in het support topic op het communityforum voor het verkrijgen van apparaatstokens.\",\n    \"nosettings\": \"Vul a.u.b. alle velden in.\",\n    \"intro\": \"Vul de details van je Mi Home apparaat in.\",\n    \"address\": \"IP adres\",\n    \"token\": \"Token (minimum van 32 karakters in cijfers en letters)\",\n    \"polling\": \"Polling frequentie\",\n    \"test\": \"Test verbinding\",\n    \"testResult\": \"Connectie test succesvol, je kan het apparaat nu met Homey verbinden.\",\n    \"connect\": \"Verbind\",\n    \"unknownerror\": \"Onbekende fout, weet je zeker dat je het juist IP adres en token hebt opgegeven en dat het Mi Home apparaat op hetzelfde netwerk zit als Homey? Controleer a.u.b. je instellingen en probeer het nog eens.\",\n    \"state\": \"Status:\",\n    \"battery\": \"Battery niveau:\",\n    \"fanspeed\": \"Ventilator snelheid:\",\n    \"no_devices_found\": \"Geen apparaten gevonden.\",\n    \"no_gateways\": \"Geen gateways gevonden. Open voordat u apparaten toevoegt de plug-ininstellingen en voeg uw Xiaomi-gateway toe. Aqara gateway wordt nog niet ondersteund.\"\n  },\n  \"device\": {\n    \"unreachable\": \"Apparaat is onbereikbaar: \",\n    \"noupdates\": \"Apparaat heeft nog geen updates ontvangen\"\n  }\n}\n"
  },
  {
    "path": "locales/no.json",
    "content": "{\n  \"pair\": {\n    \"title\": \"Legg til Mi Home-enhet\",\n    \"startpairing\": \"For at Homey skal kunne kommunisere med enheter via miIO-protokollen, må en unik enhetstoken hentes. Teknisk kunnskap er nødvendig for å hente disse tokenene. Hvis du ikke er så teknisk anlagt, kan det være utfordrende å bruke denne appen. Se instruksjonene på støttesiden i samfunnsforumet for å hente enhetstokens.\",\n    \"nosettings\": \"Vennligst fyll ut alle feltene.\",\n    \"intro\": \"Skriv inn detaljene for din Mi Home-enhet.\",\n    \"address\": \"IP-adresse\",\n    \"token\": \"Token (32 tegn med tall og bokstaver)\",\n    \"polling\": \"Spørrefrekvens\",\n    \"test\": \"Test tilkobling\",\n    \"testResult\": \"Tilkoblingstest vellykket, du kan nå koble enheten til Homey.\",\n    \"connect\": \"Koble til\",\n    \"unknownerror\": \"Ukjent feil, er du sikker på at du har skrevet inn riktig IP-adresse og token, og at Homey er på samme nettverk som Mi Home-enheten? Vennligst sjekk innstillingene dine og prøv igjen.\",\n    \"state\": \"Status:\",\n    \"battery\": \"Batterinivå:\",\n    \"fanspeed\": \"Viftehastighet:\",\n    \"no_devices_found\": \"Ingen enheter funnet.\",\n    \"no_gateways\": \"Ingen gateways funnet. \\n\\n Før du legger til enheter, vennligst åpne plugin-innstillingene og legg til Xiaomi-gatewayen din.\\n Aqara-gateway støttes ennå ikke.\"\n  },\n  \"device\": {\n    \"unreachable\": \"Enheten er utilgjengelig: \",\n    \"noupdates\": \"Enheten har ikke mottatt noen oppdateringer ennå\"\n  }\n}"
  },
  {
    "path": "locales/pl.json",
    "content": "{\n  \"pair\": {\n    \"title\": \"Dodaj urządzenie Mi Home\",\n    \"startpairing\": \"Aby Homey mógł komunikować się z urządzeniami za pomocą protokołu miIO, należy uzyskać unikalny token urządzenia. Wymagana jest wiedza techniczna do pozyskania tych tokenów. Jeśli nie jesteś zaawansowany technicznie, korzystanie z tej aplikacji może być trudne. Zobacz instrukcje w temacie wsparcia na forum społeczności, jak uzyskać tokeny urządzenia.\",\n    \"nosettings\": \"Proszę wypełnić wszystkie pola.\",\n    \"intro\": \"Wprowadź dane swojego urządzenia Mi Home.\",\n    \"address\": \"Adres IP\",\n    \"token\": \"Token (32 znaki cyfr i liter)\",\n    \"polling\": \"Częstotliwość odpytywania\",\n    \"test\": \"Testuj połączenie\",\n    \"testResult\": \"Test połączenia zakończony sukcesem, możesz teraz połączyć urządzenie z Homey.\",\n    \"connect\": \"Połącz\",\n    \"unknownerror\": \"Nieznany błąd, czy na pewno wprowadziłeś poprawny adres IP i token oraz czy Homey jest w tej samej sieci co urządzenie Mi Home? Sprawdź swoje ustawienia i spróbuj ponownie.\",\n    \"state\": \"Stan:\",\n    \"battery\": \"Poziom baterii:\",\n    \"fanspeed\": \"Prędkość wentylatora:\",\n    \"no_devices_found\": \"Nie znaleziono urządzeń.\",\n    \"no_gateways\": \"Nie znaleziono bramek. \\n\\n Przed dodaniem urządzeń, otwórz ustawienia wtyczki i dodaj swoją bramkę Xiaomi. \\n Bramka Aqara nie jest jeszcze obsługiwana.\"\n  },\n  \"device\": {\n    \"unreachable\": \"Urządzenie jest niedostępne: \",\n    \"noupdates\": \"Urządzenie nie otrzymało jeszcze żadnych aktualizacji\"\n  }\n}"
  },
  {
    "path": "locales/ru.json",
    "content": "{\n  \"pair\": {\n    \"title\": \"Добавить устройство Mi Home\",\n    \"startpairing\": \"Для того чтобы Homey мог общаться с устройствами по протоколу miIO, необходимо получить уникальный токен устройства. Для получения этих токенов требуется техническое знание. Если вы не очень разбираетесь в технике, использование этого приложения может быть сложным. Ознакомьтесь с инструкциями в теме поддержки на форуме сообщества о получении токенов устройств.\",\n    \"nosettings\": \"Пожалуйста, заполните все поля.\",\n    \"intro\": \"Введите данные вашего устройства Mi Home.\",\n    \"address\": \"IP-адрес\",\n    \"token\": \"Токен (32 символа: цифры и буквы)\",\n    \"polling\": \"Частота опроса\",\n    \"test\": \"Тест соединения\",\n    \"testResult\": \"Тест соединения успешен, вы можете подключить устройство к Homey.\",\n    \"connect\": \"Подключить\",\n    \"unknownerror\": \"Неизвестная ошибка, уверены ли вы, что ввели правильный IP-адрес и токен, и что Homey находится в той же сети, что и устройство Mi Home? Проверьте свои настройки и попробуйте снова.\",\n    \"state\": \"Состояние:\",\n    \"battery\": \"Уровень заряда батареи:\",\n    \"fanspeed\": \"Скорость вентилятора:\",\n    \"no_devices_found\": \"Устройства не найдены.\",\n    \"no_gateways\": \"Шлюзы не найдены. \\n\\n Перед добавлением устройств, пожалуйста, откройте настройки плагина и добавьте ваш шлюз Xiaomi.\\n Шлюз Aqara пока не поддерживается.\"\n  },\n  \"device\": {\n    \"unreachable\": \"Устройство недоступно: \",\n    \"noupdates\": \"Устройство ещё не получило обновлений\"\n  }\n}"
  },
  {
    "path": "locales/sv.json",
    "content": "{\n  \"pair\": {\n    \"title\": \"Lägg till Mi Home-enhet\",\n    \"startpairing\": \"För att Homey ska kunna kommunicera med enheter via miIO-protokollet behöver en unik enhetstoken erhållas. Teknisk kunskap krävs för att hämta dessa tokens. Om du inte är så tekniskt kunnig kan det vara utmanande att använda den här appen. Se instruktionerna i supportämnet på communityforumet om hur du hämtar enhetens tokens.\",\n    \"nosettings\": \"Fyll i alla fält.\",\n    \"intro\": \"Ange detaljerna för din Mi Home-enhet.\",\n    \"address\": \"IP-adress\",\n    \"token\": \"Token (32 tecken av siffror och bokstäver)\",\n    \"polling\": \"Förfrågningsfrekvens\",\n    \"test\": \"Testa anslutning\",\n    \"testResult\": \"Anslutningstesten lyckades, du kan nu ansluta enheten till Homey.\",\n    \"connect\": \"Anslut\",\n    \"unknownerror\": \"Okänt fel, är du säker på att du har skrivit in rätt IP-adress och token och att Homey är på samma nätverk som Mi Home-enheten? Kontrollera dina inställningar och försök igen.\",\n    \"state\": \"Status:\",\n    \"battery\": \"Batterinivå:\",\n    \"fanspeed\": \"Fläkthastighet:\",\n    \"no_devices_found\": \"Inga enheter hittades.\",\n    \"no_gateways\": \"Inga gateways hittades. \\n\\n Innan du lägger till enheter, öppna plugin-inställningarna och lägg till din Xiaomi gateway.\\n Aqara gateway stöds ännu inte.\"\n  },\n  \"device\": {\n    \"unreachable\": \"Enheten är oåtkomlig: \",\n    \"noupdates\": \"Enheten har ännu inte fått några uppdateringar\"\n  }\n}"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"com.xiaomi-miio\",\n  \"version\": \"3.3.0\",\n  \"main\": \"app.js\",\n  \"scripts\": {},\n  \"devDependencies\": {\n    \"@tsconfig/node12\": \"^12.1.5\",\n    \"@types/homey\": \"npm:homey-apps-sdk-v3-types@^0.3.12\",\n    \"@types/node\": \"^24.9.1\"\n  },\n  \"dependencies\": {\n    \"@thingbound/discovery\": \"github:thingbound/discovery\",\n    \"abstract-things\": \"github:shaarkys/abstract-things-react-native\",\n    \"miio\": \"github:shaarkys/miio\",\n    \"mimorelinks\": \"^1.2.1\",\n    \"tinkerhub-discovery\": \"^0.6.0\",\n    \"tinycolor2\": \"^1.6.0\"\n  },\n  \"overrides\": {\n    \"miio\": {\n      \"yargs\": \"^17.7.1\"\n    }\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/shaarkys/com.xiaomi-miio.git\"\n  },\n  \"keywords\": [\n    \"xiaomi\",\n    \"homey\",\n    \"mi\"\n  ],\n  \"author\": \"Jelger Haanstra\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/shaarkys/com.xiaomi-miio/issues\"\n  },\n  \"homepage\": \"https://github.com/shaarkys/com.xiaomi-miio#readme\"\n}\n"
  },
  {
    "path": "settings/index.html",
    "content": "<script type=\"text/javascript\" src=\"/homey.js\" data-origin=\"settings\"></script>\n<meta charset=\"UTF-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n<meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\" />\n<title>Xiaomi Mi Home</title>\n<link type=\"text/css\" rel=\"stylesheet\" href=\"../assets/bootstrap.min.css\" />\n<link type=\"text/css\" rel=\"stylesheet\" href=\"../assets/bootstrap-vue.min.css\" />\n<script src=\"../assets/vue.min.js\"></script>\n<script src=\"../assets/bootstrap-vue.min.js\"></script>\n\n<div id=\"miHome\">\n  <b-modal id=\"modalWelcomeScreen\" hide-header-close no-close-on-backdrop hide-header scrollable>\n    <template v-slot:default=\"{ hide }\">\n      <div class=\"text-center\">\n        <div class=\"pt-5 pb-3\">\n          <img\n            style=\"width:100px\"\n            alt=\"logo\"\n            src=\"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjUsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAxMzAgMTQ2LjIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEzMCAxNDYuMjsiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCgkuc3Qwe2ZpbGwtcnVsZTpldmVub2RkO2NsaXAtcnVsZTpldmVub2RkO2ZpbGw6I0ZGNjcwMDt9DQo8L3N0eWxlPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTTEyOSw4MS4zdi0yOGwtNS40LDIuM2wtMTguNyw4djE3LjZ2MS41bDAsMGMwLDAuMywwLDAuNy0wLjEsMWMtMS4zLDIwLjktMTguNywzNy40LTM5LjgsMzcuNA0KCWMtMTYuNywwLTMwLjktMTAuMi0zNi45LTI0LjdsLTIyLjIsOS41YzkuNiwyMy4xLDMyLjUsMzkuNCw1OS4xLDM5LjRjMzQuNSwwLDYyLjctMjcuMyw2My45LTYxLjZDMTI5LDgyLjksMTI5LDgyLjEsMTI5LDgxLjMgTTEsMQ0KCXYyNS4zdjU0LjljMCwwLjgsMCwxLjYsMCwyLjRjMC4xLDIuMiwwLjMsNC40LDAuNiw2LjZMMTcsODMuN2w4LjEtMy41di00OXYtNC45bDQuMiwxLjhMNjUuOSw0NGwzNC45LTE1LjhsNC4xLTEuOXY0Ljl2MTQuOQ0KCWwxMC40LTQuNGwxMy43LTUuOXYtOS41VjFoLTI0aC0wLjFsLTM5LDE2LjNMMjUuMiwxaC0wLjFIMXoiLz4NCjwvc3ZnPg0K\"\n          />\n        </div>\n        <h1 class=\"font-weight-bold\" style=\"font-size: 35px\">Welcome to Xiaomi Mi Home App</h1>\n        <b-container class=\"bv-example-row bv-example-row-flex-cols\">\n          <b-row class=\"pb-3\">\n            <b-col align-self=\"center\" cols=\"3\">\n              <img\n                class=\"float-right\"\n                style=\"width:32px;\"\n                alt=\"Xiaomi Mi Home\"\n                src=\"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBoZWlnaHQ9IjUxMnB4IiB2aWV3Qm94PSItNzYgMSA1MTEgNTExLjk5ODYzIiB3aWR0aD0iNTEycHgiPjxnPjxwYXRoIGQ9Im0xNzAuNDg0Mzc1IDEzMC4wMzEyNWMwIDUuNTE5NTMxIDQuNDgwNDY5IDEwIDEwIDEwczEwLTQuNDgwNDY5IDEwLTEwLTQuNDgwNDY5LTEwLTEwLTEwLTEwIDQuNDgwNDY5LTEwIDEwem0wIDAiIGRhdGEtb3JpZ2luYWw9IiMwMDAwMDAiIGNsYXNzPSJhY3RpdmUtcGF0aCIgZGF0YS1vbGRfY29sb3I9IiMwMDAwMDAiIGZpbGw9IiNGRjY3MDAiLz48cGF0aCBkPSJtMTgwLjQ4NDM3NSA0MTYuMDA3ODEyYy01LjUxOTUzMSAwLTEwIDQuNDgwNDY5LTEwIDEwIDAgNS41MTk1MzIgNC40ODA0NjkgMTAgMTAgMTBzMTAtNC40ODA0NjggMTAtMTBjMC01LjUxOTUzMS00LjQ4MDQ2OS0xMC0xMC0xMHptMCAwIiBkYXRhLW9yaWdpbmFsPSIjMDAwMDAwIiBjbGFzcz0iYWN0aXZlLXBhdGgiIGRhdGEtb2xkX2NvbG9yPSIjMDAwMDAwIiBmaWxsPSIjRkY2NzAwIi8+PHBhdGggZD0ibTMwNC45NDE0MDYgMjA0LjQxMDE1NmMtMzMuNDEwMTU2LTE1LjcyNjU2Mi03Ny42MDkzNzUtMjQuMzgyODEyLTEyNC40NTcwMzEtMjQuMzgyODEycy05MS4wNDY4NzUgOC42NTYyNS0xMjQuNDU3MDMxIDI0LjM4MjgxMmMtMzUuODA4NTk0IDE2Ljg1MTU2My01NS41MjczNDQgNDAuMTUyMzQ0LTU1LjUyNzM0NCA2NS42MDkzNzV2MTUxLjk4ODI4MWMwIDI1LjQ1NzAzMiAxOS43MTg3NSA0OC43NTc4MTMgNTUuNTI3MzQ0IDY1LjYwOTM3NiAzMy40MTAxNTYgMTUuNzIyNjU2IDc3LjYwOTM3NSAyNC4zODI4MTIgMTI0LjQ1NzAzMSAyNC4zODI4MTJzOTEuMDQ2ODc1LTguNjYwMTU2IDEyNC40NTcwMzEtMjQuMzgyODEyYzM1LjgwODU5NC0xNi44NTE1NjMgNTUuNTI3MzQ0LTQwLjE1MjM0NCA1NS41MjczNDQtNjUuNjA5Mzc2di0xNTEuOTg4MjgxYzAtMjUuNDU3MDMxLTE5LjcxODc1LTQ4Ljc1NzgxMi01NS41MjczNDQtNjUuNjA5Mzc1em0tMjQwLjM5ODQzNyAxOC4wOTM3NWMzMC44MDA3ODEtMTQuNDk2MDk0IDcxLjk3NjU2Mi0yMi40ODA0NjggMTE1Ljk0MTQwNi0yMi40ODA0NjhzODUuMTQwNjI1IDcuOTg0Mzc0IDExNS45NDE0MDYgMjIuNDgwNDY4YzI3Ljk5MjE4OCAxMy4xNzE4NzUgNDQuMDQ2ODc1IDMwLjQ5MjE4OCA0NC4wNDY4NzUgNDcuNTE1NjI1IDAgMTcuMDIzNDM4LTE2LjA1NDY4NyAzNC4zNDM3NS00NC4wNDY4NzUgNDcuNTE1NjI1LTMwLjgwMDc4MSAxNC40OTYwOTQtNzEuOTc2NTYyIDIyLjQ4MDQ2OS0xMTUuOTQxNDA2IDIyLjQ4MDQ2OXMtODUuMTQwNjI1LTcuOTg0Mzc1LTExNS45NDE0MDYtMjIuNDgwNDY5Yy0yNy45OTIxODgtMTMuMTcxODc1LTQ0LjA0Njg3NS0zMC40OTIxODctNDQuMDQ2ODc1LTQ3LjUxNTYyNSAwLTE3LjAyMzQzNyAxNi4wNTQ2ODctMzQuMzQzNzUgNDQuMDQ2ODc1LTQ3LjUxNTYyNXptMjc1LjkyOTY4NyAxOTkuNTAzOTA2YzAgMTcuMDIzNDM4LTE2LjA1NDY4NyAzNC4zMzk4NDQtNDQuMDQ2ODc1IDQ3LjUxNTYyNi0zMC44MDA3ODEgMTQuNDk2MDkzLTcxLjk3NjU2MiAyMi40NzY1NjItMTE1Ljk0MTQwNiAyMi40NzY1NjJzLTg1LjE0MDYyNS03Ljk4MDQ2OS0xMTUuOTQxNDA2LTIyLjQ3NjU2MmMtMjcuOTkyMTg4LTEzLjE3NTc4Mi00NC4wNDY4NzUtMzAuNDkyMTg4LTQ0LjA0Njg3NS00Ny41MTU2MjZ2LTM4LjM3ODkwNmM1Ljk1MzEyNSA2LjE5OTIxOSAxMy4xNzE4NzUgMTIuMTA5Mzc1IDIxLjU3MDMxMiAxNy42MDkzNzUgMjUuNTcwMzEzIDE2LjczNDM3NSA2MC4xNDQ1MzIgMjguMjY5NTMxIDk3LjM1NTQ2OSAzMi40ODQzNzUuMzgyODEzLjA0Mjk2OS43NjE3MTkuMDYyNSAxLjEzNjcxOS4wNjI1IDUuMDE5NTMxIDAgOS4zNDc2NTYtMy43Njk1MzEgOS45MjU3ODEtOC44NzUuNjIxMDk0LTUuNDg0Mzc1LTMuMzI0MjE5LTEwLjQzNzUtOC44MTI1LTExLjA1ODU5NC03NC44NDc2NTYtOC40NzY1NjItMTIxLjE3NTc4MS00NC45Mjk2ODctMTIxLjE3NTc4MS03My44Mzk4NDN2LTI3LjkyNTc4MWM5LjAwMzkwNiA4LjcyNjU2MiAyMC45Mjk2ODcgMTYuNjcxODc0IDM1LjUzMTI1IDIzLjU0Mjk2OCAzMy40MTAxNTYgMTUuNzIyNjU2IDc3LjYwOTM3NSAyNC4zODI4MTMgMTI0LjQ1NzAzMSAyNC4zODI4MTMgNDYuODQzNzUgMCA5MS4wNDI5NjktOC42NjAxNTcgMTI0LjQ1NzAzMS0yNC4zODI4MTMgMTQuNjAxNTYzLTYuODc1IDI2LjUyMzQzOC0xNC44MTY0MDYgMzUuNTI3MzQ0LTIzLjU0Mjk2OHYyNy45MjU3ODFjMCAyOC45MTAxNTYtNDYuMzI4MTI1IDY1LjM2MzI4MS0xMjEuMTc1NzgxIDczLjgzOTg0My01LjQ4NDM3NS42MTcxODgtOS40Mjk2ODggNS41NzAzMTMtOC44MDg1OTQgMTEuMDU4NTk0LjU3ODEyNSA1LjEwNTQ2OSA0LjkwNjI1IDguODc1IDkuOTIxODc1IDguODc1LjM3NSAwIC43NTc4MTItLjAxOTUzMSAxLjEzNjcxOS0uMDYyNSAzNy4yMTA5MzctNC4yMTQ4NDQgNzEuNzg5MDYyLTE1Ljc1IDk3LjM1NTQ2OS0zMi40ODQzNzUgOC40MDIzNDMtNS41IDE1LjYyMTA5My0xMS40MTAxNTYgMjEuNTcwMzEyLTE3LjYwOTM3NXYzOC4zNzg5MDZ6bTAgMCIgZGF0YS1vcmlnaW5hbD0iIzAwMDAwMCIgY2xhc3M9ImFjdGl2ZS1wYXRoIiBkYXRhLW9sZF9jb2xvcj0iIzAwMDAwMCIgZmlsbD0iI0ZGNjcwMCIvPjxwYXRoIGQ9Im0xODAuNDg0Mzc1IDMyMC4wMTU2MjVjNS41MjM0MzcgMCAxMC00LjQ3NjU2MyAxMC0xMHYtNzkuOTkyMTg3YzAtNS41MjM0MzgtNC40NzY1NjMtMTAtMTAtMTBzLTEwIDQuNDc2NTYyLTEwIDEwdjc5Ljk5MjE4N2MwIDUuNTIzNDM3IDQuNDc2NTYzIDEwIDEwIDEwem0wIDAiIGRhdGEtb3JpZ2luYWw9IiMwMDAwMDAiIGNsYXNzPSJhY3RpdmUtcGF0aCIgZGF0YS1vbGRfY29sb3I9IiMwMDAwMDAiIGZpbGw9IiNGRjY3MDAiLz48cGF0aCBkPSJtMjMwLjQ4MDQ2OSAzMDAuMDE1NjI1YzUuNTIzNDM3IDAgMTAtNC40NzY1NjMgMTAtOS45OTYwOTR2LTQwYzAtNS41MTk1MzEtNC40NzY1NjMtOS45OTYwOTMtMTAtOS45OTYwOTMtNS41MjM0MzggMC0xMCA0LjQ3NjU2Mi0xMCA5Ljk5NjA5M3Y0MGMwIDUuNTE5NTMxIDQuNDc2NTYyIDkuOTk2MDk0IDEwIDkuOTk2MDk0em0wIDAiIGRhdGEtb3JpZ2luYWw9IiMwMDAwMDAiIGNsYXNzPSJhY3RpdmUtcGF0aCIgZGF0YS1vbGRfY29sb3I9IiMwMDAwMDAiIGZpbGw9IiNGRjY3MDAiLz48cGF0aCBkPSJtMTMwLjQ4ODI4MSAzMDAuMDE1NjI1YzUuNTIzNDM4IDAgMTAtNC40NzY1NjMgMTAtOS45OTYwOTR2LTQwYzAtNS41MTk1MzEtNC40NzY1NjItOS45OTYwOTMtMTAtOS45OTYwOTMtNS41MjM0MzcgMC0xMCA0LjQ3NjU2Mi0xMCA5Ljk5NjA5M3Y0MGMwIDUuNTE5NTMxIDQuNDc2NTYzIDkuOTk2MDk0IDEwIDkuOTk2MDk0em0wIDAiIGRhdGEtb3JpZ2luYWw9IiMwMDAwMDAiIGNsYXNzPSJhY3RpdmUtcGF0aCIgZGF0YS1vbGRfY29sb3I9IiMwMDAwMDAiIGZpbGw9IiNGRjY3MDAiLz48cGF0aCBkPSJtMjE3LjgyODEyNSAxMDMuMTc1NzgxYzIuODM5ODQ0LTQuNzM0Mzc1IDEuMzAwNzgxLTEwLjg3ODkwNi0zLjQzMzU5NC0xMy43MTg3NS0yMC45Mjk2ODctMTIuNTUwNzgxLTQ2LjkxNzk2OS0xMi41NDY4NzUtNjcuODI0MjE5LjAwMzkwNy00LjczNDM3NCAyLjg0Mzc1LTYuMjY5NTMxIDguOTg0Mzc0LTMuNDI1NzgxIDEzLjcxODc1IDIuODQzNzUgNC43MzQzNzQgOC45ODgyODEgNi4yNjk1MzEgMTMuNzE4NzUgMy40MjU3ODEgMTQuNTYyNS04Ljc0MjE4OCAzMi42NjQwNjMtOC43MzgyODEgNDcuMjQ2MDk0LjAwMzkwNiA0Ljc1NzgxMyAyLjg1MTU2MyAxMC44OTA2MjUgMS4yODUxNTYgMTMuNzE4NzUtMy40MzM1OTR6bTAgMCIgZGF0YS1vcmlnaW5hbD0iIzAwMDAwMCIgY2xhc3M9ImFjdGl2ZS1wYXRoIiBkYXRhLW9sZF9jb2xvcj0iIzAwMDAwMCIgZmlsbD0iI0ZGNjcwMCIvPjxwYXRoIGQ9Im0yNTcuMTEzMjgxIDQ1LjczMDQ2OWM0LjU5NzY1NyAzLjA2MjUgMTAuODA0Njg4IDEuODE2NDA2IDEzLjg2NzE4OC0yLjc3NzM0NCAzLjA2MjUtNC41OTc2NTYgMS44MTY0MDYtMTAuODA0Njg3LTIuNzc3MzQ0LTEzLjg2NzE4N2wtNi43MDcwMzEtNC40NjQ4NDRjLTQ5LjIxNDg0NC0zMi44MjQyMTktMTEyLjgwNDY4OC0zMi44MjgxMjUtMTYxLjk5NjA5NC0uMDE1NjI1bC02LjczMDQ2OSA0LjQ4MDQ2OWMtNC41OTc2NTYgMy4wNTg1OTMtNS44NDM3NSA5LjI2NTYyNC0yLjc4MTI1IDEzLjg2MzI4MSAzLjA1MDc4MSA0LjU4MjAzMSA5LjI1IDUuODUxNTYyIDEzLjg2MzI4MSAyLjc4MTI1bDYuNzM4MjgyLTQuNDg0Mzc1YzQyLjQ1NzAzMS0yOC4zMjAzMTMgOTcuMzM1OTM3LTI4LjMxNjQwNiAxMzkuODE2NDA2LjAxNTYyNXptMCAwIiBkYXRhLW9yaWdpbmFsPSIjMDAwMDAwIiBjbGFzcz0iYWN0aXZlLXBhdGgiIGRhdGEtb2xkX2NvbG9yPSIjMDAwMDAwIiBmaWxsPSIjRkY2NzAwIi8+PHBhdGggZD0ibTIzMC40MjU3ODEgNzYuMDA3ODEyYzQuNjA1NDY5IDMuMDgyMDMyIDEwLjgxMjUgMS44MjAzMTMgMTMuODY3MTg4LTIuNzU3ODEyIDMuMDcwMzEyLTQuNTg5ODQ0IDEuODM1OTM3LTEwLjgwMDc4MS0yLjc1NzgxMy0xMy44NjcxODhsLTIuMjM4MjgxLTEuNDk2MDkzYy0zNS43MjY1NjMtMjMuODEyNS04MS44OTQ1MzEtMjMuODEyNS0xMTcuNjMyODEzLjAwMzkwNmwtMi4yMzA0NjggMS40OTIxODdjLTQuNTg5ODQ0IDMuMDY2NDA3LTUuODI0MjE5IDkuMjc3MzQ0LTIuNzU3ODEzIDEzLjg2NzE4OCAzLjA3MDMxMyA0LjU5Mzc1IDkuMjgxMjUgNS44MjgxMjUgMTMuODcxMDk0IDIuNzU3ODEybDIuMjE4NzUtMS40ODA0NjhjMjguOTkyMTg3LTE5LjMyMDMxMyA2Ni40NTMxMjUtMTkuMzIwMzEzIDk1LjQyOTY4Ny0uMDA3ODEzem0wIDAiIGRhdGEtb3JpZ2luYWw9IiMwMDAwMDAiIGNsYXNzPSJhY3RpdmUtcGF0aCIgZGF0YS1vbGRfY29sb3I9IiMwMDAwMDAiIGZpbGw9IiNGRjY3MDAiLz48L2c+IDwvc3ZnPgo=\"\n              />\n            </b-col>\n            <b-col align-self=\"center\" class=\"text-left\">\n              <h1 style=\"padding-bottom: 0; margin: 0;\">Xiaomi Gateway</h1>\n              <small>You can add Xiaomi Gateway's and child devices.</small>\n            </b-col>\n          </b-row>\n        </b-container>\n      </div>\n    </template>\n\n    <template v-slot:modal-footer>\n      <b-button block variant=\"success\" style=\"color: #fff; background-color: #007bff; border-color: #007bff; padding: 10px;\" @click=\"firstTimeLaunchConfirm\">\n        Continue\n      </b-button>\n    </template>\n  </b-modal>\n\n  <b-container fluid class=\"mt-3\">\n    <div v-if=\"loading\" class=\"d-flex justify-content-center mt-5\">\n      <b-spinner style=\"width: 5rem; height: 5rem;\" variant=\"primary\" label=\"Large Spinner\"></b-spinner>\n    </div>\n    <div v-if=\"mainPage\">\n      <div class=\"text-center\">\n        <b-list-group horizontal>\n          <b-list-group-item :active=\"gatewaysPage\" href=\"#\" @click.prevent=\"showPageFromListGroup('gatewaysPage')\">Gateways</b-list-group-item>\n          <b-list-group-item :active=\"irDevicesPage\" href=\"#\" @click.prevent=\"showPageFromListGroup('irDevicesPage')\">IR devices</b-list-group-item>\n        </b-list-group>\n      </div>\n      <!-- Gateway page -->\n      <div v-if=\"gatewaysPage\">\n        <div :class=\"setGatewaysPageMargin\"></div>\n        <div class=\"d-flex justify-content-center pt-2\">\n          <b-button style=\"color: #28a728; background-color: #fff; border: 1px solid transparent; border-color: #28a728; padding: .375rem .75rem;\" @click.prevent=\"showHelpModal\">Instructions</b-button>\n        </div>\n        <b-modal id=\"modalHowToStart\" hide-header-close no-close-on-backdrop hide-header scrollable>\n          <template v-slot:default\n            ><div>\n              <div class=\"text-center\">\n                <h4 style=\"color: rgb(255, 30, 30);\">Note: Aqara gateways not supported.</h4>\n              </div>\n              <div class=\"d-flex justify-content-center m-2 pt-5\"><h6>Add gateway using MAC and password:</h6></div>\n              <div class=\"d-flex justify-content-center\"><img src=\"https://raw.githubusercontent.com/jghaanstra/com.xiaomi-miio/master/docs/MAC_PASSWORD.gif\" alt=\"placeholder 960\" class=\"img-responsive\" /></div>\n              <div class=\"d-flex justify-content-center m-2 pt-5\"><h6>Add gateway using IP and Token:</h6></div>\n              <div class=\"d-flex justify-content-center pb-5\">\n                <img src=\"https://raw.githubusercontent.com/jghaanstra/com.xiaomi-miio/master/docs/IP_TOKEN_GENERATE.gif\" alt=\"placeholder 960\" class=\"img-responsive\" />\n              </div>\n            </div>\n          </template>\n\n          <template v-slot:modal-footer=\"{ ok }\">\n            <b-button variant=\"success\" @click=\"ok()\">OK</b-button>\n          </template>\n        </b-modal>\n        <div class=\"container pt-2 pb-2\" v-for=\"(gateway, index) in gateways\" :key=\"index\">\n          <div class=\"card\">\n            <div class=\"card-body \">\n              <div class=\"message\">\n                <h4 class=\"card-text text-muted\">GATEWAY</h4>\n                <small>MAC: {{ gateway.mac }}</small><br>\n                <small>PASSWORD: {{ gateway.password.toUpperCase() }}</small><br>\n                <small>CONNECTED DEVICES: {{ getGateway(gateway.mac) }}</small>\n              </div>\n              <div class=\"actions float-right mt-3\">\n                <b-button variant=\"outline-success\" style=\"color: #28a728; background-color: #fff; border: 1px solid transparent; border-color: #28a728; padding: .375rem .75rem;\" @click.prevent=\"edit(gateway, index, 'gateway')\">Modify</b-button>\n                <b-button variant=\"outline-danger\" style=\"color: #dc3545; background-color: #fff; border: 1px solid transparent; border-color: #dc3545; padding: .375rem .75rem;\" @click.prevent=\"deleteDevice(gateway, index, 'gateway')\">Delete</b-button>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n      <!-- IR devices page -->\n      <div v-if=\"irDevicesPage\">\n        <div :class=\"setIrDevicesPageMargin\"></div>\n        <div class=\"container pt-2 pb-2\" v-for=\"(device, index) in irDevices\" :key=\"index\">\n          <div class=\"card\">\n            <div class=\"card-body \">\n              <div class=\"message\">\n                <h4 class=\"card-text text-muted\">{{ device.ip }}</h4>\n                <h6 class=\"card-text text-muted\">{{ device.token }}</h6>\n              </div>\n              <div class=\"actions float-right mt-3\">\n                <b-button\n                  variant=\"outline-success\"\n                  style=\"color: #28a728; background-color: #fff; border: 1px solid transparent; border-color: #28a728; padding: .375rem .75rem;\"\n                  @click.prevent=\"edit(device, index, 'irDevice')\"\n                  >Modify</b-button\n                >\n                <b-button\n                  variant=\"outline-danger\"\n                  style=\"color: #dc3545; background-color: #fff; border: 1px solid transparent; border-color: #dc3545; padding: .375rem .75rem;\"\n                  @click.prevent=\"deleteDevice(device, index, 'irDevice')\"\n                  >Delete</b-button\n                >\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n      <!-- Add devices button -->\n      <div>\n        <b-button block variant=\"primary\" style=\"color: #fff; background-color: #007bff; border-color: #007bff; padding: .375rem .75rem; position: fixed; bottom: 10px; width: 85%;\" @click.prevent=\"addGatewayModalShow\">Add</b-button>\n      </div>\n      <!-- Add devices modal -->\n      <b-modal id=\"modalAddDevices\" hide-header-close no-close-on-backdrop hide-header scrollable>\n        <template v-slot:default>\n          <div>\n            <div class=\"text-center mt-5 mb-5\" v-if=\"selectAddDeviceTypePage\">\n              <h1 class=\"pb-3\">Select device type</h1>\n              <b-list-group>\n                <b-list-group-item button @click.prevent=\"chooseAddDeviceTypePage('gatewayMethod')\" style=\"padding: .75rem 1.25rem; background-color: white; border: 1px solid rgba(0,0,0,.125); border-top-left-radius: .25rem; border-top-right-radius: .25rem; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; margin-bottom: -1px;\">\n                  Gateway\n                </b-list-group-item>\n                <b-list-group-item button @click.prevent=\"chooseAddDeviceTypePage('irDevice')\" style=\"padding: .75rem 1.25rem; background-color: white; border: 1px solid rgba(0,0,0,.125); border-top-left-radius: .25rem; border-top-right-radius: .25rem; border-top-left-radius: 0px; border-top-right-radius: 0px; margin-bottom: -1px;\">\n                  IR device\n                </b-list-group-item>\n              </b-list-group>\n            </div>\n            <div class=\"text-center mt-5 mb-5\" v-if=\"chooseGatewayAddMethodPage\">\n              <h1 class=\"pb-3\">Choose add method</h1>\n              <b-list-group>\n                <b-list-group-item button @click.prevent=\"chooseAddDeviceTypePage('gateway')\" style=\"padding: .75rem 1.25rem; background-color: white; border: 1px solid rgba(0,0,0,.125); border-top-left-radius: .25rem; border-top-right-radius: .25rem; border-top-right-radius: .25rem; border-bottom-left-radius: 0px; margin-bottom: -1px;\">\n                  MAC and Password\n                </b-list-group-item>\n                <b-list-group-item button @click.prevent=\"chooseAddDeviceTypePage('generatePassword')\" style=\"padding: .75rem 1.25rem; background-color: white; border: 1px solid rgba(0,0,0,.125); border-top-left-radius: .25rem; border-top-right-radius: .25rem; border-top-left-radius: 0px; border-top-right-radius: 0px; margin-bottom: -1px;\">\n                  IP and Token (for generate password)\n                </b-list-group-item>\n              </b-list-group>\n            </div>\n            <div v-if=\"gatewayAddViaMacPage\">\n              <div role=\"group\">\n                <label class=\"font-weight-bold\" for=\"input-live\">MAC:</label>\n                <b-form-input id=\"input-live\" v-model=\"mac\" :state=\"macRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter mac address\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                <b-form-invalid-feedback id=\"input-live-feedback\">{{ macRuleMessage }}.</b-form-invalid-feedback>\n                <b-form-text id=\"input-live-help\">You can add a MAC address two points or without it. Upper and lower case is also not important.</b-form-text>\n              </div>\n              <div role=\"group\" class=\"mt-3\">\n                <label class=\"font-weight-bold\" for=\"input-live\">Password:</label>\n                <b-form-input id=\"input-live\" v-model=\"password\" :state=\"passwordRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter password\" trim style=\"border: 1px solid #ced4da;  padding: 10px;\"></b-form-input>\n                <b-form-invalid-feedback id=\"input-live-feedback\">Wrong password.</b-form-invalid-feedback>\n                <b-form-text id=\"input-live-help\">Upper and lower case is also not important.</b-form-text>\n              </div>\n              <div role=\"group\">\n                <label class=\"font-weight-bold\" for=\"input-live\">IP:</label>\n                <b-form-input id=\"input-live\" v-model=\"ip\" :state=\"ipRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter IP address\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                <b-form-invalid-feedback id=\"input-live-feedback\">{{ ipRuleMessage }}</b-form-invalid-feedback>\n                <b-form-text id=\"input-live-help\">Gateway IP address.</b-form-text>\n              </div>\n              <div role=\"group\" class=\"mt-3\">\n                <label class=\"font-weight-bold\" for=\"input-live\">Token:</label>\n                <b-form-input id=\"input-live\" v-model=\"token\" :state=\"tokenRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter token\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                <b-form-invalid-feedback id=\"input-live-feedback\">{{ tokenRuleMessage }}</b-form-invalid-feedback>\n                <b-form-text id=\"input-live-help\">Gateway token.</b-form-text>\n              </div>\n            </div>\n            <!-- Generate MAC and Password from IP and Token -->\n            <div v-if=\"gatewayAddViaGeneratePage\">\n              <div v-if=\"generatePasswordLoading\">\n                <div class=\"d-flex justify-content-center mt-5\">\n                  <b-spinner style=\"width: 5rem; height: 5rem;\" variant=\"primary\" label=\"Large Spinner\"></b-spinner>\n                </div>\n                <div class=\"text-center m-5\">\n                  <h1 v-if=\"gatewayAddViaGeneratePage\">Generating...</h1>\n                </div>\n              </div>\n              <div v-if=\"!generatePasswordLoading\">\n                <div role=\"group\">\n                  <label class=\"font-weight-bold\" for=\"input-live\">IP:</label>\n                  <b-form-input id=\"input-live\" v-model=\"ip\" :state=\"ipRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter IP address\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                  <b-form-invalid-feedback id=\"input-live-feedback\">{{ ipRuleMessage }}</b-form-invalid-feedback>\n                  <b-form-text id=\"input-live-help\">Gateway IP address.</b-form-text>\n                </div>\n                <div role=\"group\" class=\"mt-3\">\n                  <label class=\"font-weight-bold\" for=\"input-live\">Token:</label>\n                  <b-form-input id=\"input-live\" v-model=\"token\" :state=\"tokenRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter token\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                  <b-form-invalid-feedback id=\"input-live-feedback\">{{ tokenRuleMessage }}</b-form-invalid-feedback>\n                  <b-form-text id=\"input-live-help\">Gateway token.</b-form-text>\n                </div>\n                <div class=\"m-3 text-center\" v-if=\"generatingResult\" style=\"color: #28a745;\">{{ generatingResultMessage }}</div>\n                <div class=\"m-3 text-center\" v-if=\"generatingResult\" style=\"color: #28a745;\">MAC is: {{ mac }}</div>\n                <div class=\"m-3 text-center\" v-if=\"generatingResult\" style=\"color: #28a745;\">Generated password is: {{ password }}</div>\n                <div class=\"mt-3\">\n                  <b-button block variant=\"success\" style=\"color: #fff; background-color: #28a745; border-color: #28a745; padding: 10px;\" @click=\"generatePassword\" :disabled=\"generatePasswordLoading\">\n                    Generate and Add\n                  </b-button>\n                </div>\n              </div>\n            </div>\n            <div v-if=\"irDeviceAddPage\">\n              <div v-if=\"checkConnectionLoading\">\n                <div class=\"d-flex justify-content-center mt-5\">\n                  <b-spinner style=\"width: 5rem; height: 5rem;\" variant=\"primary\" label=\"Large Spinner\"></b-spinner>\n                </div>\n                <div class=\"text-center m-5\">\n                  <h1 v-if=\"irDeviceAddPage\">Connecting...</h1>\n                </div>\n              </div>\n              <div v-if=\"!checkConnectionLoading\">\n                <div role=\"group\">\n                  <label class=\"font-weight-bold\" for=\"input-live\">IP:</label>\n                  <b-form-input id=\"input-live\" v-model=\"ip\" :state=\"ipRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter IP address\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                  <b-form-invalid-feedback id=\"input-live-feedback\">{{ ipRuleMessage }}</b-form-invalid-feedback>\n                  <b-form-text id=\"input-live-help\">Device IP address.</b-form-text>\n                </div>\n                <div role=\"group\" class=\"mt-3\">\n                  <label class=\"font-weight-bold\" for=\"input-live\">Token:</label>\n                  <b-form-input id=\"input-live\" v-model=\"token\" :state=\"tokenRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter token\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                  <b-form-invalid-feedback id=\"input-live-feedback\">{{ tokenRuleMessage }}</b-form-invalid-feedback>\n                  <b-form-text id=\"input-live-help\">Device token.</b-form-text>\n                </div>\n                <div class=\"m-3 text-center\" v-if=\"connectionTest\" style=\"color: #28a745;\">{{ connectionTestMessage }}</div>\n                <div class=\"mt-3\">\n                  <b-button block variant=\"outline-success\" style=\"color: #28a728; background-color: #fff; border: 1px solid transparent; border-color: #28a728; padding: 10px;\" @click=\"checkConnection\" :disabled=\"checkConnectionLoading\">\n                    Check to connect\n                  </b-button>\n                </div>\n              </div>\n            </div>\n          </div>\n        </template>\n\n        <template v-slot:modal-footer>\n          <b-button variant=\"success\" style=\"color: #fff; background-color: #6c757d; border-color: #6c757d; padding: .375rem .75rem;\" @click=\"modalAddDevicesClose\">\n            Cancel\n          </b-button>\n          <b-button v-if=\"addDeviceButton\" variant=\"success\" style=\"color: #fff; background-color: #007bff; border-color: #007bff; padding: .375rem .75rem;\" @click=\"addDevice\">\n            Add {{ addDeviceType }}\n          </b-button>\n        </template>\n      </b-modal>\n      <!-- edit devices modal -->\n      <b-modal id=\"modalEditDevices\" hide-header-close no-close-on-backdrop hide-header scrollable>\n        <template v-slot:default>\n          <div>\n            <div v-if=\"gatewayEditPage\">\n              <div role=\"group\">\n                <label class=\"font-weight-bold\" for=\"input-live\">MAC:</label>\n                <b-form-input id=\"input-live\" v-model=\"mac\" :state=\"macEditRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter mac address\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                <b-form-invalid-feedback id=\"input-live-feedback\"> {{ macRuleMessage }} </b-form-invalid-feedback>\n                <b-form-text id=\"input-live-help\">You can add a MAC address two points or without it. Upper and lower case is also not important.</b-form-text>\n              </div>\n              <div role=\"group\" class=\"mt-3\">\n                <label class=\"font-weight-bold\" for=\"input-live\">Password:</label>\n                <b-form-input id=\"input-live\" v-model=\"password\" :state=\"passwordEditRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter password\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                <b-form-invalid-feedback id=\"input-live-feedback\"> {{ passwordRuleMessage }} </b-form-invalid-feedback>\n                <b-form-text id=\"input-live-help\">Upper and lower case is also not important.</b-form-text>\n              </div>\n              <div role=\"group\">\n                <label class=\"font-weight-bold\" for=\"input-live\">IP:</label>\n                <b-form-input id=\"input-live\" v-model=\"ip\" :state=\"ipEditRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter IP address\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                <b-form-invalid-feedback id=\"input-live-feedback\">{{ ipRuleMessage }}</b-form-invalid-feedback>\n                <b-form-text id=\"input-live-help\">Gateway IP address.</b-form-text>\n              </div>\n              <div role=\"group\" class=\"mt-3\">\n                <label class=\"font-weight-bold\" for=\"input-live\">Token:</label>\n                <b-form-input id=\"input-live\" v-model=\"token\" :state=\"tokenEditRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter token\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                <b-form-invalid-feedback id=\"input-live-feedback\">{{ tokenRuleMessage }}</b-form-invalid-feedback>\n                <b-form-text id=\"input-live-help\">Gateway token.</b-form-text>\n              </div>\n            </div>\n            <div v-if=\"irDeviceEditPage\">\n              <div v-if=\"checkConnectionLoading\">\n                <div class=\"d-flex justify-content-center mt-5\">\n                  <b-spinner style=\"width: 5rem; height: 5rem;\" variant=\"primary\" label=\"Large Spinner\"></b-spinner>\n                </div>\n                <div class=\"text-center m-5\">\n                  <h1 v-if=\"irDeviceAddPage\">Connecting...</h1>\n                </div>\n              </div>\n              <div v-if=\"!checkConnectionLoading\">\n                <div role=\"group\">\n                  <label class=\"font-weight-bold\" for=\"input-live\">IP:</label>\n                  <b-form-input id=\"input-live\" v-model=\"ip\" :state=\"ipEditRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter IP address\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                  <b-form-invalid-feedback id=\"input-live-feedback\">{{ ipRuleMessage }}</b-form-invalid-feedback>\n                  <b-form-text id=\"input-live-help\">Device IP address.</b-form-text>\n                </div>\n                <div role=\"group\" class=\"mt-3\">\n                  <label class=\"font-weight-bold\" for=\"input-live\">Token:</label>\n                  <b-form-input id=\"input-live\" v-model=\"token\" :state=\"tokenEditRule\" aria-describedby=\"input-live-help input-live-feedback\" placeholder=\"Enter token\" trim style=\"border: 1px solid #ced4da; padding: 10px;\"></b-form-input>\n                  <b-form-invalid-feedback id=\"input-live-feedback\">{{ tokenRuleMessage }}</b-form-invalid-feedback>\n                  <b-form-text id=\"input-live-help\">Device token.</b-form-text>\n                </div>\n                <div class=\"mt-3\">\n                  <b-button block variant=\"outline-success\" style=\"color: #28a728; background-color: #fff; border: 1px solid transparent; border-color: #28a728; padding: .375rem .75rem;\" @click=\"checkConnection\" :disabled=\"checkConnectionLoading\">\n                    Connect to check\n                  </b-button>\n                </div>\n              </div>\n            </div>\n          </div>\n        </template>\n\n        <template v-slot:modal-footer>\n          <b-button variant=\"success\" style=\"color: #fff; background-color: #6c757d; border-color: #6c757d; padding: .375rem .75rem;\" @click=\"modalAddDevicesClose\">Cancel</b-button>\n          <b-button variant=\"success\" style=\"color: #fff; background-color: #007bff; border-color: #007bff; padding: .375rem .75rem;\" @click=\"save\">Save</b-button>\n        </template>\n      </b-modal>\n    </div>\n  </b-container>\n</div>\n\n<script type=\"text/javascript\">\n  function onHomeyReady(Homey) {\n    Homey.ready();\n    new Vue({\n      el: \"#miHome\",\n      data() {\n        return {\n          gateways: [],\n          irDevices: [],\n          gatewaysObject: {},\n          currentPage: \"gateways\",\n          loading: true,\n          mainPage: false,\n          gatewaysPage: true,\n          irDevicesPage: false,\n          addDeviceType: null,\n          selectAddDeviceTypePage: true,\n          chooseGatewayAddMethodPage: false,\n          gatewayAddViaMacPage: false,\n          gatewayAddViaGeneratePage: false,\n          irDeviceAddPage: false,\n          mac: \"\",\n          macRule: null,\n          macRuleMessage: \"\",\n          password: \"\",\n          passwordRule: null,\n          passwordRuleMessage: \"\",\n          ip: \"\",\n          ipRule: null,\n          ipRuleMessage: \"\",\n          token: \"\",\n          tokenRule: null,\n          tokenRuleMessage: \"\",\n          addDeviceButton: false,\n          generatePasswordLoading: false,\n          generatingResult: false,\n          generatingResultMessage: \"\",\n          checkConnectionLoading: false,\n          gatewayEditPage: false,\n          irDeviceEditPage: false,\n          editIndex: 0,\n          saveDeviceType: \"\",\n          connectionTest: false,\n          connectionTestMessage: \"\"\n        };\n      },\n      mounted() {\n        this.checkFirstTimeLaunch();\n        this.getDevices();\n        this.getGatewayDeviceAction();\n      },\n      methods: {\n        checkFirstTimeLaunch() {\n          Homey.get(\"firstTimeLaunch\", (error, firstTimeLaunch) => {\n            if (error) return Homey.alert(error);\n            if (firstTimeLaunch == null) {\n              this.$bvModal.show(\"modalWelcomeScreen\");\n            } else {\n              this.loading = false;\n              this.mainPage = true;\n            }\n          });\n        },\n        firstTimeLaunchConfirm() {\n          this.$bvModal.hide(\"modalWelcomeScreen\");\n          this.loading = false;\n          this.mainPage = true;\n          Homey.set(\"firstTimeLaunch\", \"launched\", error => {\n            if (error) return Homey.alert(error);\n            this.$bvModal.hide(\"modalWelcomeScreen\");\n            this.loading = false;\n            this.mainPage = true;\n          });\n        },\n        getDevices() {\n          Homey.get(\"gatewaysList\", (error, list) => {\n            if (error) return Homey.alert(error);\n\n            this.gateways = list || [];\n          });\n\n          Homey.get(\"irDevicesList\", (error, list) => {\n            if (error) return Homey.alert(error);\n\n            this.irDevices = list || [];\n          });\n        },\n        showPageFromListGroup(page) {\n          if (page == \"gatewaysPage\") {\n            this.gatewaysPage = true;\n            this.irDevicesPage = false;\n          } else if (page == \"irDevicesPage\") {\n            this.irDevicesPage = true;\n            this.gatewaysPage = false;\n          }\n        },\n        addGatewayModalShow() {\n          this.$bvModal.show(\"modalAddDevices\");\n        },\n        addDevice(update = \"add\") {\n          if (this.mac.length == 12) {\n            if (this.mac.match(/\\b[0-9A-Fa-f]{12}\\b/g)) {\n              this.macRule = true;\n            } else {\n              this.macRule = false;\n              this.macRuleMessage = \"Wrong MAC address\";\n            }\n          } else if (this.mac.length == 17) {\n            if (this.mac.match(/^[0-9a-f]{1,2}([:])[0-9a-f]{1,2}(?:\\1[0-9a-f]{1,2}){4}$/i)) {\n              this.macRule = true;\n            } else {\n              this.macRule = false;\n              this.macRuleMessage = \"Wrong MAC address\";\n            }\n          } else {\n            this.macRule = false;\n            this.macRuleMessage = \"Wrong MAC address\";\n          }\n\n          if (this.password.length == 16) {\n            if (this.password.match(/\\b[0-9A-Fa-f]{16}\\b/g)) {\n              this.passwordRule = true;\n            } else {\n              this.passwordRule = false;\n              this.passwordRuleMessage = \"Wrong password\";\n            }\n          } else {\n            this.passwordRule = false;\n            this.passwordRuleMessage = \"Wrong password\";\n          }\n\n          if (this.ip.match(/^(?:(?:2[0-4]\\d|25[0-5]|1\\d{2}|[1-9]?\\d)\\.){3}(?:2[0-4]\\d|25[0-5]|1\\d{2}|[1-9]?\\d)(?:\\:(?:\\d|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5]))?$/)) {\n            this.ipRule = true;\n          } else {\n            this.ipRule = false;\n            this.ipRuleMessage = \"Wrong IP address.\";\n          }\n\n          if (this.token.length == 32) {\n            if (this.token.match(/\\b[0-9A-Fa-f]{32}\\b/g)) {\n              this.tokenRule = true;\n            } else {\n              this.tokenRule = false;\n              this.tokenRuleMessage = \"Wrong token.\";\n            }\n          } else {\n            this.tokenRule = false;\n            this.tokenRuleMessage = \"Wrong token.\";\n          }\n\n          if (this.macRule && this.passwordRule && update != \"generate\") {\n            if (this.gateways.filter(gateway => gateway.mac == this.mac).length != 0) {\n              this.macRule = false;\n              this.macRuleMessage = \"This mac address already exists\";\n            } else {\n              this.gateways.push({ mac: this.mac.split(\":\").join(\"\"), password: this.password });\n\n              Homey.set(\"gatewaysList\", this.gateways, (error, settings) => {\n                if (error) return Homey.alert(error);\n              });\n              this.modalAddDevicesClose();\n              this.showPageFromListGroup(\"gatewaysPage\");\n            }\n          } else if (this.ipRule && this.tokenRule && update != \"generate\") {\n            if (this.irDevices.filter(device => device.ip == this.ip).length != 0) {\n              let irDevicesMacs = this.irDevices.map(device => device.ip);\n              let indexDevice = irDevicesMacs.indexOf(this.ip);\n              this.irDevices[indexDevice].token = this.token;\n\n              Homey.set(\"irDevicesList\", this.irDevices, (error, settings) => {\n                if (error) return Homey.alert(error);\n              });\n              this.showPageFromListGroup(\"irDevicesPage\");\n\n              this.modalAddDevicesClose();\n            } else {\n              this.irDevices.push({ ip: this.ip, token: this.token });\n\n              Homey.set(\"irDevicesList\", this.irDevices, (error, settings) => {\n                if (error) return Homey.alert(error);\n              });\n              this.showPageFromListGroup(\"irDevicesPage\");\n\n              this.modalAddDevicesClose();\n            }\n          } else if (update == \"generate\") {\n            if (this.gateways.length == 0) {\n              this.addDevice();\n            } else {\n              this.mac = this.mac.toLowerCase();\n              let gatewayMacs = this.gateways.map(gateway => gateway.mac);\n              let indexDevice = gatewayMacs.indexOf(this.mac);\n              if (indexDevice < 0) {\n                this.addDevice();\n              } else {\n                this.gateways[indexDevice].password = this.password;\n                this.gateways.sort();\n                Homey.set(\"gatewaysList\", this.gateways, (error, settings) => {\n                  if (error) return Homey.alert(error);\n                });\n                this.modalAddDevicesClose();\n                this.showPageFromListGroup(\"gatewaysPage\");\n              }\n            }\n          }\n        },\n        chooseAddDeviceTypePage(page) {\n          this.selectAddDeviceTypePage = false;\n          if (page == \"gateway\") {\n            this.addDeviceType = \"gateway\";\n            this.addDeviceButton = true;\n            this.gatewayAddViaMacPage = true;\n            this.gatewayAddViaGeneratePage = false;\n            this.irDeviceAddPage = false;\n            this.chooseGatewayAddMethodPage = false;\n          } else if (page == \"gatewayMethod\") {\n            this.chooseGatewayAddMethodPage = true;\n            this.gatewayAddViaGeneratePage = false;\n            this.gatewayAddViaMacPage = false;\n            this.irDeviceAddPage = false;\n          } else if (page == \"generatePassword\") {\n            this.addDeviceType = \"gateway\";\n            this.gatewayAddViaGeneratePage = true;\n            this.chooseGatewayAddMethodPage = false;\n            this.gatewayAddViaMacPage = false;\n            this.irDeviceAddPage = false;\n          } else if (page == \"irDevice\") {\n            this.addDeviceType = \"ir device\";\n            this.irDeviceAddPage = true;\n            this.addDeviceButton = true;\n            this.gatewayAddViaGeneratePage = false;\n            this.gatewayAddViaMacPage = false;\n          }\n        },\n        modalAddDevicesClose() {\n          this.$bvModal.hide(\"modalAddDevices\");\n          this.$bvModal.hide(\"modalEditDevices\");\n\n          setTimeout(() => {\n            this.selectAddDeviceTypePage = true;\n            this.chooseGatewayAddMethodPage = false;\n            this.gatewayAddViaMacPage = false;\n            this.irDeviceAddPage = false;\n            this.gatewayAddViaGeneratePage = false;\n            this.addDeviceType = null;\n            this.addDeviceButton = false;\n            this.mac = \"\";\n            this.macRule = null;\n            this.macRuleMessage = \"Wrong MAC address\";\n            this.ip = \"\";\n            this.ipRule = null;\n            this.ipRuleMessage = \"Wrong IP address\";\n            this.password = \"\";\n            this.passwordRule = null;\n            this.passwordRuleMessage = \"Wrong password\";\n            this.token = \"\";\n            this.tokenRule = null;\n            this.tokenRuleMessage = \"Wrong token\";\n            this.connectionTest = false;\n            this.connectionTestMessage = \"\";\n            this.checkConnectionLoading = false;\n            this.generatingResult = false;\n            this.generatingResultMessage = \"\";\n            this.generatePasswordLoading = false;\n          }, 150);\n        },\n        generatePassword() {\n          this.generatePasswordLoading = true;\n          this.ipRule = null;\n          this.ipRuleMessage = \"\";\n          this.tokenRule = null;\n          this.tokenRuleMessage = \"\";\n\n          Homey.api('POST', '/generate', { ip: this.ip, token: this.token })\n            .then(result => {\n              if (result.status == \"OK\") {\n                this.generatingResult = true;\n                this.generatePasswordLoading = false;\n                this.generatingResultMessage = \"Successfully generated\";\n                this.mac = result.mac;\n                this.password = result.password;\n\n                setTimeout(() => {\n                  this.checkConnectionLoading = false;\n                  this.generatingResult = false;\n                  this.generatingResultMessage = \"\";\n                  this.addDevice(\"generate\");\n                  setTimeout(() => {\n                    this.getGatewayDeviceAction();\n                  }, 1000);\n                }, 1500);\n              }\n            })\n            .catch(error => {\n              this.generatingResult = true;\n              this.generatePasswordLoading = false;\n              this.generatingResultMessage = error.message;\n\n              if (error.message == \"Could not connect to device, handshake timeout\") {\n                this.ipRule = false;\n                this.ipRuleMessage = \"Wrong IP address or device offline\";\n              } else if (error.message == \"Could not connect to device, token might be wrong\") {\n                this.tokenRule = false;\n                this.tokenRuleMessage = \"Wrong token\";\n              }\n            });\n        },\n        checkConnection() {\n          this.checkConnectionLoading = true;\n          Homey.api('POST', '/testConnection', { ip: this.ip, token: this.token })\n            .then(result => {\n              if (result.token == this.token) {\n                this.checkConnectionLoading = false;\n                this.generatePasswordLoading = false;\n                this.connectionTest = true;\n                this.connectionTestMessage = \"Successfully connected\";\n              }\n            })\n            .catch(error => {\n              this.connectionTest = true;\n              this.checkConnectionLoading = false;\n              this.connectionTestMessage = error.message;\n\n              if (error.message == \"Could not connect to device, handshake timeout\") {\n                this.ipRule = false;\n                this.ipRuleMessage = \"Wrong IP address or device offline\";\n              } else if (error.message == \"Could not connect to device, token might be wrong\") {\n                this.tokenRule = false;\n                this.tokenRuleMessage = \"Wrong token\";\n              }\n            });\n        },\n        edit(device, index, type) {\n          if (type == \"gateway\") {\n            this.gatewayEditPage = true;\n            this.irDeviceEditPage = false;\n            this.mac = device.mac;\n            this.password = device.password;\n            this.ip = device.ip || \"0.0.0.0\";\n            this.token = device.token || \"00000000000000000000000000000000\";\n          } else if (type == \"irDevice\") {\n            this.irDeviceEditPage = true;\n            this.gatewayEditPage = false;\n            this.ip = device.ip;\n            this.token = device.token;\n          }\n          this.editIndex = index;\n          this.saveDeviceType = type;\n          this.$bvModal.show(\"modalEditDevices\");\n        },\n        deleteDevice(device, index, type) {\n          if (type == \"gateway\") {\n            this.gateways.splice(index, 1);\n            Homey.set(\"gatewaysList\", this.gateways, (error, settings) => {\n              if (error) return Homey.alert(error);\n            });\n          } else if (type == \"irDevice\") {\n            this.irDevices.splice(index, 1);\n            Homey.set(\"irDevicesList\", this.irDevices, (error, settings) => {\n              if (error) return Homey.alert(error);\n            });\n          }\n        },\n        save() {\n          if (this.saveDeviceType == \"gateway\") {\n            this.gateways[this.editIndex] = { mac: this.mac.split(\":\").join(\"\"), password: this.password, ip: this.ip, token: this.token };\n            this.gateways.sort();\n            Homey.set(\"gatewaysList\", this.gateways, (error, settings) => {\n              if (error) return Homey.alert(error);\n            });\n            this.modalAddDevicesClose();\n          } else if (this.saveDeviceType == \"irDevice\") {\n            this.irDevices[this.editIndex] = { ip: this.ip, token: this.token };\n            this.irDevices.sort();\n            Homey.set(\"irDevicesList\", this.irDevices, (error, settings) => {\n              if (error) return Homey.alert(error);\n            });\n            this.modalAddDevicesClose();\n          }\n        },\n        showHelpModal() {\n          this.$bvModal.show(\"modalHowToStart\");\n        },\n        getGatewayDeviceAction() {\n          Homey.api('GET', '/getGateways', {})\n            .then(result => { this.gatewaysObject = result; })\n            .catch(error => { return error; });\n        },\n        getGateway(sid) {\n          if (this.gatewaysObject[sid] && this.gatewaysObject[sid].childDevices) {\n            return this.gatewaysObject[sid].childDevices.length;\n          } else {\n            return null;\n          }\n        }\n      },\n      computed: {\n        macEditRule() {\n          if (this.mac.length == 12) {\n            if (this.mac.match(/\\b[0-9A-Fa-f]{12}\\b/g)) {\n              return true;\n            } else {\n              this.macRuleMessage = \"Wrong MAC address\";\n              return false;\n            }\n          } else if (this.mac.length == 17) {\n            if (this.mac.match(/^[0-9a-f]{1,2}([:])[0-9a-f]{1,2}(?:\\1[0-9a-f]{1,2}){4}$/i)) {\n              return true;\n            } else {\n              this.macRuleMessage = \"Wrong MAC address\";\n              return false;\n            }\n          } else if (this.mac.length == 0) {\n            this.macRuleMessage = \"This field should not be empty\";\n            return false;\n          } else {\n            this.macRuleMessage = \"Wrong MAC address\";\n            return false;\n          }\n        },\n        passwordEditRule() {\n          if (this.password.length == 16) {\n            if (this.password.match(/\\b[0-9A-Fa-f]{16}\\b/g)) {\n              return true;\n            } else {\n              this.passwordRuleMessage = \"Wrong password\";\n              return false;\n            }\n          } else if (this.password.length == 0) {\n            this.passwordRuleMessage = \"This field should not be empty\";\n            return false;\n          } else {\n            this.passwordRuleMessage = \"Wrong password\";\n            return false;\n          }\n        },\n        ipEditRule() {\n          if (this.ip.match(/^(?:(?:2[0-4]\\d|25[0-5]|1\\d{2}|[1-9]?\\d)\\.){3}(?:2[0-4]\\d|25[0-5]|1\\d{2}|[1-9]?\\d)(?:\\:(?:\\d|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5]))?$/)) {\n            return true;\n          } else if (this.ip.length == 0) {\n            this.ipRuleMessage = \"This field should not be empty\";\n            return false;\n          } else {\n            this.ipRuleMessage = \"Wrong IP address\";\n            return false;\n          }\n        },\n        tokenEditRule() {\n          if (this.token.length == 32) {\n            if (this.token.match(/\\b[0-9A-Fa-f]{32}\\b/g)) {\n              return true;\n            } else {\n              this.tokenRuleMessage = \"Wrong token\";\n              return false;\n            }\n          } else if (this.token.length == 0) {\n            this.tokenRuleMessage = \"This field should not be empty\";\n            return false;\n          } else {\n            this.tokenRuleMessage = \"Wrong token\";\n            return false;\n          }\n        },\n        setGatewaysPageMargin() {\n          return this.gateways.length == 0 ? \"m-5\" : null;\n        },\n        setIrDevicesPageMargin() {\n          return this.irDevices.length == 0 ? \"m-5\" : null;\n        }\n      }\n    });\n  }\n</script>"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"extends\": \"@tsconfig/node12/tsconfig.json\",\n  \"compilerOptions\": {\n    \"allowJs\": true,\n    \"outDir\": \".homeybuild/\"\n  }\n}"
  }
]