Skip to content
  • Home
  • Recent
  • Tags
  • 0 Unread 0
  • Categories
  • Unreplied
  • Popular
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. JavaScript
  5. [Vorlage] Xiaomi Airpurifier 3H u.a. inkl. Token auslesen.

NEWS

  • Monatsrückblick Januar/Februar 2026 ist online!
    BluefoxB
    Bluefox
    17
    1
    541

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    17
    1
    5.4k

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    1.4k

[Vorlage] Xiaomi Airpurifier 3H u.a. inkl. Token auslesen.

Scheduled Pinned Locked Moved JavaScript
474 Posts 50 Posters 110.6k Views 41 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Siggi0904S Offline
    Siggi0904S Offline
    Siggi0904
    wrote on last edited by
    #461

    Ich bin auch stark daran interessiert, dass ich meine drei Xiaomi-Geräte auch wieder auslesen und steuern könnte.

    Vielleicht bekommt es @tobasium ja, hin die gemeldeten Themen anzugehen.

    @haselchen könntest du vielleicht mal beschreiben, wie das mit dem Windows-Tool funktioniert?

    Danke im Voraus.

    1 Reply Last reply
    0
    • crunchipC Away
      crunchipC Away
      crunchip
      Forum Testing Most Active
      wrote on last edited by crunchip
      #462

      hab mich mal auch auf die schnelle daran versucht, Datenpunkte werden angelegt, sollte funktionieren, hab hier nur mal meinen 3H eingetragen

      const SkriptVersion = "0.3.4-fixed"; // vom 14.11.2025 - LOKALE STEUERUNG MIT TOKENS - MIoT STRUKTUR - REORGANISIERT - Power read-only
      
      const mihome = require('node-mihome');
      
      // ============================================
      // 🔑 KONFIGURATION - TOKENS & LOKALE IPs
      // ============================================
      // Token-Auslesen: https://github.com/PiotrMachowski/Xiaomi-cloud-tokens-extractor
      
      const devices = [
         {
             name: "Mi Air Purifier 3/3H",
             model: "zhimi.airpurifier.mb3",
             did: "xxxxxxxxx",
             localip: "10.1.1.92",
             token: "xxxxxxxxxxxxxxxxxxxxxxxxx",
             enabled: true
         }
      ];
      
      const praefix0 = "javascript.0.MiHomeDE";
      const refresh = 10000;
      const logging = true;
      
      // ============================================
      // DEVICE DEFINITIONS - MIoT STRUKTUR - REORGANISIERT
      // ============================================
      
      const DefineDevice = [];
      
      // Luftreiniger MB3 (3H)
      DefineDevice[0] = {
         model: "zhimi.airpurifier.mb3",
         description: "Purifier 3H",
         setter: {
             "air-purifier.mode": async function (obj, val) { 
                 try { 
                     await device[obj].setMode(val);
                     log("✅ Mode set to: " + val);
                 } catch(e) { 
                     log("❌ setMode error: " + e.message, "error"); 
                 } 
             },
             "air-purifier.fan-level": async function (obj, val) { 
                 try { 
                     await device[obj].setFanLevel(val);
                     log("✅ Fan level set to: " + val);
                 } catch(e) { 
                     log("❌ setFanLevel error: " + e.message, "error"); 
                 } 
             },
             "motor-speed.favorite-fan-level": async function (obj, val) { 
                 try { 
                     await device[obj].setFavLevel(val);
                     log("✅ Favorite level set to: " + val);
                 } catch(e) { 
                     log("❌ setFavLevel error: " + e.message, "error"); 
                 } 
             },
             "indicator-light.on": async function (obj, val) { 
                 try { 
                     await device[obj].setLcdBrightness(val ? 2 : 0);
                     log("✅ Indicator light set to: " + (val ? 'on' : 'off'));
                 } catch(e) { 
                     log("❌ setLcdBrightness error: " + e.message, "error"); 
                 } 
             },
             "physical-controls-locked.physical-controls-locked": async function (obj, val) { 
                 try { 
                     await device[obj].setChildLock(val);
                     log("✅ Child lock set to: " + val);
                 } catch(e) { 
                     log("❌ setChildLock error: " + e.message, "error"); 
                 } 
             }
         },
         control: [
             { name: "air-purifier.on", type: "boolean", role: "switch", read: true, write: false },
             { name: "air-purifier.mode", type: "number", read: true, write: true, min: 0, max: 3, states: { 0: "auto", 1: "sleep", 2: "favorite", 3: "fanset" } },
             { name: "air-purifier.fan-level", type: "number", read: true, write: true, min: 1, max: 3 },
             { name: "motor-speed.favorite-fan-level", type: "number", read: true, write: true, min: 0, max: 14 },
             { name: "indicator-light.on", type: "boolean", role: "switch", read: true, write: true },
             { name: "physical-controls-locked.physical-controls-locked", type: "boolean", role: "switch", read: true, write: true }
         ],
         sensor: [
             { name: "alarm.alarm", type: "boolean", role: "switch", read: true, write: false },
             { name: "indicator-light.brightness", type: "number", read: true, write: false, min: 0, max: 2 },
             { name: "environment.temperature", type: "number", role: "value.temperature", read: true, write: false, unit: "°C" },
             { name: "motor-speed.motor-speed", type: "number", read: true, write: false, unit: "rpm" },
             { name: "use-time.use-time", type: "number", read: true, write: false, unit: "h" },
             { name: "environment.relative-humidity", type: "number", role: "value.humidity", read: true, write: false, unit: "%" },
             { name: "environment.pm2_5-density", type: "number", read: true, write: false, unit: "μg/m³" },
             { name: "filter.filter-life-level", type: "number", read: true, write: false, unit: "%" },
             { name: "filter.filter-used-time", type: "number", read: true, write: false, unit: "h" }
         ]
      };
      
      // ============================================
      // AB HIER NICHT ÄNDERN
      // ============================================
      
      let device = [];
      const States = [];
      let DpCount = 0;
      let GenericDpRefreshIntervalObj;
      const DefineDeviceInfo = [
         { id: "localip", name: "IP Address", type: "string", read: true, write: false },
         { id: "token", name: "Token", type: "string", read: true, write: false },
         { id: "did", name: "Device ID", type: "string", read: true, write: false },
         { id: "model", name: "Model", type: "string", read: true, write: false },
         { id: "isOnline", name: "Is Online", type: "boolean", read: true, write: false }
      ];
      
      log("Starting AllMyMi V." + SkriptVersion);
      log("Devices configured: " + devices.length);
      
      function CorrectChannelId(cid) {
         let temp = cid;
         if (typeof temp !== "string") {
             temp = JSON.stringify(cid);
         }
         temp = cid.replace(/\./g, "-");
         temp = cid.replace(/:/g, ".");
         return temp;
      }
      
      function PrepareGenericDps(did) {
         if (logging) log("Preparing generic DPs for: " + did);
         
         for (let y in DefineDeviceInfo) {
             States[DpCount] = {
                 id: praefix0 + "." + did + ".info." + DefineDeviceInfo[y].id,
                 initial: "",
                 forceCreation: false,
                 common: {
                     read: DefineDeviceInfo[y].read,
                     write: DefineDeviceInfo[y].write,
                     name: DefineDeviceInfo[y].name,
                     type: DefineDeviceInfo[y].type,
                     role: "value",
                     unit: DefineDeviceInfo[y].unit || ""
                 }
             };
             DpCount++;
         }
      }
      
      function PrepareDeviceDps(did, model) {
         if (logging) log("Preparing device DPs for model: " + model);
         
         for (let x in DefineDevice) {
             if (DefineDevice[x].model === model) {
                 // Control Datenpunkte
                 if (DefineDevice[x].control) {
                     for (let y in DefineDevice[x].control) {
                         let channelId = CorrectChannelId(DefineDevice[x].control[y].name);
                         States[DpCount] = {
                             id: praefix0 + "." + did + ".control." + channelId,
                             initial: "",
                             forceCreation: false,
                             common: DefineDevice[x].control[y]
                         };
                         DpCount++;
                     }
                 }
                 
                 // Sensor Datenpunkte
                 if (DefineDevice[x].sensor) {
                     for (let y in DefineDevice[x].sensor) {
                         let channelId = CorrectChannelId(DefineDevice[x].sensor[y].name);
                         States[DpCount] = {
                             id: praefix0 + "." + did + ".sensor." + channelId,
                             initial: "",
                             forceCreation: false,
                             common: DefineDevice[x].sensor[y]
                         };
                         DpCount++;
                     }
                 }
             }
         }
      }
      
      function CreateStates() {
         if (logging) log("Creating States...");
         let numStates = States.length;
         log("Total states to create: " + numStates);
      
         if (numStates === 0) {
             log("❌ No states to create! Check device configuration.", "error");
             return;
         }
      
         States.forEach(function (state) {
             createState(state.id, state.initial, state.forceCreation, state.common, function () {
                 numStates--;
                 if (numStates === 0) {
                     log("✅ " + States.length + " States created!");
                     
                     setObject(praefix0, { 
                         type: 'channel', 
                         common: { name: "MiHome Local Control" }, 
                         native: {} 
                     });
                     
                     for (let i = 0; i < devices.length; i++) {
                         if (devices[i].enabled) {
                             setObject(praefix0 + "." + devices[i].did, {
                                 type: 'device',
                                 common: { name: devices[i].name },
                                 native: {}
                             });
                             
                             setObject(praefix0 + "." + devices[i].did + ".control", {
                                 type: 'channel',
                                 common: { name: "Control" },
                                 native: {}
                             });
                             
                             setObject(praefix0 + "." + devices[i].did + ".sensor", {
                                 type: 'channel',
                                 common: { name: "Sensor" },
                                 native: {}
                             });
                         }
                     }
                     
                     Init();
                 }
             });
         });
      }
      
      async function Init() {
         log("🚀 Initializing local device connections...");
      
         mihome.miioProtocol.init();
      
         let deviceCount = 0;
         
         for (let i = 0; i < devices.length; i++) {
             if (!devices[i].enabled) {
                 if (logging) log("Device " + devices[i].name + " is disabled, skipping");
                 continue;
             }
      
             try {
                 log("Connecting to: " + devices[i].name + " (" + devices[i].localip + ")");
                 
                 device[deviceCount] = mihome.device({
                     id: devices[i].did,
                     model: devices[i].model,
                     address: devices[i].localip,
                     token: devices[i].token,
                     refresh: refresh
                 });
      
                 device[deviceCount].model = devices[i].model;
                 device[deviceCount].deviceConfig = devices[i];
                 device[deviceCount].deviceIndex = i;
                 device[deviceCount].isOnline = false;
                 device[deviceCount].data = {};
      
                 device[deviceCount].on('properties', (data) => {
                     if (typeof data !== "undefined" && Object.keys(data).length > 0) {
                         RefreshDps(deviceCount, data);
                     }
                 });
      
                 device[deviceCount].on('connected', () => {
                     log("✅ Device connected: " + devices[i].name);
                     device[deviceCount].isOnline = true;
                     setState(praefix0 + "." + devices[i].did + ".info.isOnline", true, true);
                 });
      
                 device[deviceCount].on('disconnected', () => {
                     log("⚠️ Device disconnected: " + devices[i].name);
                     device[deviceCount].isOnline = false;
                     setState(praefix0 + "." + devices[i].did + ".info.isOnline", false, true);
                 });
      
                 await device[deviceCount].init();
                 log("✅ Device initialized: " + devices[i].name);
      
                 // Set device info
                 setState(praefix0 + "." + devices[i].did + ".info.did", devices[i].did, true);
                 setState(praefix0 + "." + devices[i].did + ".info.model", devices[i].model, true);
                 setState(praefix0 + "." + devices[i].did + ".info.localip", devices[i].localip, true);
                 setState(praefix0 + "." + devices[i].did + ".info.isOnline", true, true);
      
                 CreateDpTrigger(deviceCount);
      
                 deviceCount++;
      
             } catch (e) {
                 log("❌ Error connecting to " + devices[i].name + ": " + e.message, "error");
             }
         }
      
         log("✅ Initialization complete! " + deviceCount + " devices connected.");
      
         GenericDpRefreshIntervalObj = setInterval(function () {
             RefreshGenericDpsTicker();
         }, refresh);
      }
      
      async function RefreshGenericDpsTicker() {
         // Periodical status updates
         for (let i = 0; i < device.length; i++) {
             if (device[i]) {
                 setState(praefix0 + "." + device[i].deviceConfig.did + ".info.isOnline", device[i].isOnline, true);
             }
         }
      }
      
      function RefreshDps(deviceIndex, data) {
         let deviceId = device[deviceIndex].deviceConfig.did;
         let model = device[deviceIndex].model;
      
         if (logging) log("Updating properties for: " + device[deviceIndex].deviceConfig.name);
      
         for (let x in DefineDevice) {
             if (DefineDevice[x].model === model) {
                 // Control Datenpunkte
                 if (DefineDevice[x].control) {
                     for (let y in DefineDevice[x].control) {
                         let propName = DefineDevice[x].control[y].name;
                         let propType = DefineDevice[x].control[y].type;
                         let channelId = CorrectChannelId(propName);
                         
                         if (data[propName] !== undefined) {
                             let value = data[propName];
                             
                             // TYPE CONVERSION
                             if (propType === "boolean") {
                                 if (typeof value === "string") {
                                     value = (value === "true" || value === "on" || value === "1" || value === true || value === 1);
                                 } else {
                                     value = !!value;
                                 }
                             } 
                             else if (propType === "number") {
                                 if (typeof value === "string") {
                                     value = parseFloat(value) || 0;
                                 } else if (typeof value !== "number") {
                                     value = Number(value) || 0;
                                 }
                             }
      
                             setState(praefix0 + "." + deviceId + ".control." + channelId, value, true);
                             
                             if (logging) log("Set control." + propName + " = " + value);
                         }
                     }
                 }
                 
                 // Sensor Datenpunkte
                 if (DefineDevice[x].sensor) {
                     for (let y in DefineDevice[x].sensor) {
                         let propName = DefineDevice[x].sensor[y].name;
                         let propType = DefineDevice[x].sensor[y].type;
                         let channelId = CorrectChannelId(propName);
                         
                         if (data[propName] !== undefined) {
                             let value = data[propName];
                             
                             // TYPE CONVERSION
                             if (propType === "boolean") {
                                 if (typeof value === "string") {
                                     value = (value === "true" || value === "on" || value === "1" || value === true || value === 1);
                                 } else {
                                     value = !!value;
                                 }
                             } 
                             else if (propType === "number") {
                                 if (typeof value === "string") {
                                     value = parseFloat(value) || 0;
                                 } else if (typeof value !== "number") {
                                     value = Number(value) || 0;
                                 }
                             }
      
                             setState(praefix0 + "." + deviceId + ".sensor." + channelId, value, true);
                             
                             if (logging) log("Set sensor." + propName + " = " + value);
                         }
                     }
                 }
             }
         }
      }
      
      function CreateDpTrigger(deviceIndex) {
         let deviceId = device[deviceIndex].deviceConfig.did;
         let model = device[deviceIndex].model;
      
         for (let x in DefineDevice) {
             if (DefineDevice[x].model === model) {
                 // Nur Control Datenpunkte sind steuerbar
                 if (DefineDevice[x].control) {
                     for (let y in DefineDevice[x].control) {
                         if (DefineDevice[x].control[y].write) {
                             let propName = DefineDevice[x].control[y].name;
                             let channelId = CorrectChannelId(propName);
                             let dpPath = praefix0 + "." + deviceId + ".control." + channelId;
      
                             on({ id: dpPath, change: "ne", ack: false }, function (dp) {
                                 if (logging) log("Command received: " + propName + " = " + dp.state.val);
                                 
                                 if (DefineDevice[x].setter[propName]) {
                                     DefineDevice[x].setter[propName](deviceIndex, dp.state.val);
                                 }
                             });
                         }
                     }
                 }
             }
         }
      }
      
      onStop(function () {
         log("Stopping script...");
         for (let x in device) {
             if (device[x]) {
                 try {
                     device[x].destroy();
                 } catch(e) {
                     log("Error destroying device: " + e.message);
                 }
             }
         }
         if (GenericDpRefreshIntervalObj) {
             clearInterval(GenericDpRefreshIntervalObj);
         }
      }, 10);
      
      // ============================================
      // SCRIPT START
      // ============================================
      log("Configuration:");
      log("- Devices: " + devices.length);
      log("- Refresh: " + refresh + "ms");
      log("- Root path: " + praefix0);
      
      // Prepare datapoints
      for (let i = 0; i < devices.length; i++) {
         if (devices[i].enabled) {
             log("📝 Preparing DPs for: " + devices[i].name);
             PrepareGenericDps(devices[i].did);
             PrepareDeviceDps(devices[i].did, devices[i].model);
         }
      }
      
      log("🔍 Total datapoints prepared: " + DpCount);
      
      CreateStates();
      

      Edit:
      hab das Script jetzt nochmal angepasst, vom einfachen miIO-Protocol wieder auf die Original MIoT-Struktur
      Steuerung funktioniert wieder, Sensordaten werden allerdings nicht ausgelesen

      umgestiegen von Proxmox auf Unraid

      haselchenH 1 Reply Last reply
      1
      • crunchipC crunchip

        hab mich mal auch auf die schnelle daran versucht, Datenpunkte werden angelegt, sollte funktionieren, hab hier nur mal meinen 3H eingetragen

        const SkriptVersion = "0.3.4-fixed"; // vom 14.11.2025 - LOKALE STEUERUNG MIT TOKENS - MIoT STRUKTUR - REORGANISIERT - Power read-only
        
        const mihome = require('node-mihome');
        
        // ============================================
        // 🔑 KONFIGURATION - TOKENS & LOKALE IPs
        // ============================================
        // Token-Auslesen: https://github.com/PiotrMachowski/Xiaomi-cloud-tokens-extractor
        
        const devices = [
           {
               name: "Mi Air Purifier 3/3H",
               model: "zhimi.airpurifier.mb3",
               did: "xxxxxxxxx",
               localip: "10.1.1.92",
               token: "xxxxxxxxxxxxxxxxxxxxxxxxx",
               enabled: true
           }
        ];
        
        const praefix0 = "javascript.0.MiHomeDE";
        const refresh = 10000;
        const logging = true;
        
        // ============================================
        // DEVICE DEFINITIONS - MIoT STRUKTUR - REORGANISIERT
        // ============================================
        
        const DefineDevice = [];
        
        // Luftreiniger MB3 (3H)
        DefineDevice[0] = {
           model: "zhimi.airpurifier.mb3",
           description: "Purifier 3H",
           setter: {
               "air-purifier.mode": async function (obj, val) { 
                   try { 
                       await device[obj].setMode(val);
                       log("✅ Mode set to: " + val);
                   } catch(e) { 
                       log("❌ setMode error: " + e.message, "error"); 
                   } 
               },
               "air-purifier.fan-level": async function (obj, val) { 
                   try { 
                       await device[obj].setFanLevel(val);
                       log("✅ Fan level set to: " + val);
                   } catch(e) { 
                       log("❌ setFanLevel error: " + e.message, "error"); 
                   } 
               },
               "motor-speed.favorite-fan-level": async function (obj, val) { 
                   try { 
                       await device[obj].setFavLevel(val);
                       log("✅ Favorite level set to: " + val);
                   } catch(e) { 
                       log("❌ setFavLevel error: " + e.message, "error"); 
                   } 
               },
               "indicator-light.on": async function (obj, val) { 
                   try { 
                       await device[obj].setLcdBrightness(val ? 2 : 0);
                       log("✅ Indicator light set to: " + (val ? 'on' : 'off'));
                   } catch(e) { 
                       log("❌ setLcdBrightness error: " + e.message, "error"); 
                   } 
               },
               "physical-controls-locked.physical-controls-locked": async function (obj, val) { 
                   try { 
                       await device[obj].setChildLock(val);
                       log("✅ Child lock set to: " + val);
                   } catch(e) { 
                       log("❌ setChildLock error: " + e.message, "error"); 
                   } 
               }
           },
           control: [
               { name: "air-purifier.on", type: "boolean", role: "switch", read: true, write: false },
               { name: "air-purifier.mode", type: "number", read: true, write: true, min: 0, max: 3, states: { 0: "auto", 1: "sleep", 2: "favorite", 3: "fanset" } },
               { name: "air-purifier.fan-level", type: "number", read: true, write: true, min: 1, max: 3 },
               { name: "motor-speed.favorite-fan-level", type: "number", read: true, write: true, min: 0, max: 14 },
               { name: "indicator-light.on", type: "boolean", role: "switch", read: true, write: true },
               { name: "physical-controls-locked.physical-controls-locked", type: "boolean", role: "switch", read: true, write: true }
           ],
           sensor: [
               { name: "alarm.alarm", type: "boolean", role: "switch", read: true, write: false },
               { name: "indicator-light.brightness", type: "number", read: true, write: false, min: 0, max: 2 },
               { name: "environment.temperature", type: "number", role: "value.temperature", read: true, write: false, unit: "°C" },
               { name: "motor-speed.motor-speed", type: "number", read: true, write: false, unit: "rpm" },
               { name: "use-time.use-time", type: "number", read: true, write: false, unit: "h" },
               { name: "environment.relative-humidity", type: "number", role: "value.humidity", read: true, write: false, unit: "%" },
               { name: "environment.pm2_5-density", type: "number", read: true, write: false, unit: "μg/m³" },
               { name: "filter.filter-life-level", type: "number", read: true, write: false, unit: "%" },
               { name: "filter.filter-used-time", type: "number", read: true, write: false, unit: "h" }
           ]
        };
        
        // ============================================
        // AB HIER NICHT ÄNDERN
        // ============================================
        
        let device = [];
        const States = [];
        let DpCount = 0;
        let GenericDpRefreshIntervalObj;
        const DefineDeviceInfo = [
           { id: "localip", name: "IP Address", type: "string", read: true, write: false },
           { id: "token", name: "Token", type: "string", read: true, write: false },
           { id: "did", name: "Device ID", type: "string", read: true, write: false },
           { id: "model", name: "Model", type: "string", read: true, write: false },
           { id: "isOnline", name: "Is Online", type: "boolean", read: true, write: false }
        ];
        
        log("Starting AllMyMi V." + SkriptVersion);
        log("Devices configured: " + devices.length);
        
        function CorrectChannelId(cid) {
           let temp = cid;
           if (typeof temp !== "string") {
               temp = JSON.stringify(cid);
           }
           temp = cid.replace(/\./g, "-");
           temp = cid.replace(/:/g, ".");
           return temp;
        }
        
        function PrepareGenericDps(did) {
           if (logging) log("Preparing generic DPs for: " + did);
           
           for (let y in DefineDeviceInfo) {
               States[DpCount] = {
                   id: praefix0 + "." + did + ".info." + DefineDeviceInfo[y].id,
                   initial: "",
                   forceCreation: false,
                   common: {
                       read: DefineDeviceInfo[y].read,
                       write: DefineDeviceInfo[y].write,
                       name: DefineDeviceInfo[y].name,
                       type: DefineDeviceInfo[y].type,
                       role: "value",
                       unit: DefineDeviceInfo[y].unit || ""
                   }
               };
               DpCount++;
           }
        }
        
        function PrepareDeviceDps(did, model) {
           if (logging) log("Preparing device DPs for model: " + model);
           
           for (let x in DefineDevice) {
               if (DefineDevice[x].model === model) {
                   // Control Datenpunkte
                   if (DefineDevice[x].control) {
                       for (let y in DefineDevice[x].control) {
                           let channelId = CorrectChannelId(DefineDevice[x].control[y].name);
                           States[DpCount] = {
                               id: praefix0 + "." + did + ".control." + channelId,
                               initial: "",
                               forceCreation: false,
                               common: DefineDevice[x].control[y]
                           };
                           DpCount++;
                       }
                   }
                   
                   // Sensor Datenpunkte
                   if (DefineDevice[x].sensor) {
                       for (let y in DefineDevice[x].sensor) {
                           let channelId = CorrectChannelId(DefineDevice[x].sensor[y].name);
                           States[DpCount] = {
                               id: praefix0 + "." + did + ".sensor." + channelId,
                               initial: "",
                               forceCreation: false,
                               common: DefineDevice[x].sensor[y]
                           };
                           DpCount++;
                       }
                   }
               }
           }
        }
        
        function CreateStates() {
           if (logging) log("Creating States...");
           let numStates = States.length;
           log("Total states to create: " + numStates);
        
           if (numStates === 0) {
               log("❌ No states to create! Check device configuration.", "error");
               return;
           }
        
           States.forEach(function (state) {
               createState(state.id, state.initial, state.forceCreation, state.common, function () {
                   numStates--;
                   if (numStates === 0) {
                       log("✅ " + States.length + " States created!");
                       
                       setObject(praefix0, { 
                           type: 'channel', 
                           common: { name: "MiHome Local Control" }, 
                           native: {} 
                       });
                       
                       for (let i = 0; i < devices.length; i++) {
                           if (devices[i].enabled) {
                               setObject(praefix0 + "." + devices[i].did, {
                                   type: 'device',
                                   common: { name: devices[i].name },
                                   native: {}
                               });
                               
                               setObject(praefix0 + "." + devices[i].did + ".control", {
                                   type: 'channel',
                                   common: { name: "Control" },
                                   native: {}
                               });
                               
                               setObject(praefix0 + "." + devices[i].did + ".sensor", {
                                   type: 'channel',
                                   common: { name: "Sensor" },
                                   native: {}
                               });
                           }
                       }
                       
                       Init();
                   }
               });
           });
        }
        
        async function Init() {
           log("🚀 Initializing local device connections...");
        
           mihome.miioProtocol.init();
        
           let deviceCount = 0;
           
           for (let i = 0; i < devices.length; i++) {
               if (!devices[i].enabled) {
                   if (logging) log("Device " + devices[i].name + " is disabled, skipping");
                   continue;
               }
        
               try {
                   log("Connecting to: " + devices[i].name + " (" + devices[i].localip + ")");
                   
                   device[deviceCount] = mihome.device({
                       id: devices[i].did,
                       model: devices[i].model,
                       address: devices[i].localip,
                       token: devices[i].token,
                       refresh: refresh
                   });
        
                   device[deviceCount].model = devices[i].model;
                   device[deviceCount].deviceConfig = devices[i];
                   device[deviceCount].deviceIndex = i;
                   device[deviceCount].isOnline = false;
                   device[deviceCount].data = {};
        
                   device[deviceCount].on('properties', (data) => {
                       if (typeof data !== "undefined" && Object.keys(data).length > 0) {
                           RefreshDps(deviceCount, data);
                       }
                   });
        
                   device[deviceCount].on('connected', () => {
                       log("✅ Device connected: " + devices[i].name);
                       device[deviceCount].isOnline = true;
                       setState(praefix0 + "." + devices[i].did + ".info.isOnline", true, true);
                   });
        
                   device[deviceCount].on('disconnected', () => {
                       log("⚠️ Device disconnected: " + devices[i].name);
                       device[deviceCount].isOnline = false;
                       setState(praefix0 + "." + devices[i].did + ".info.isOnline", false, true);
                   });
        
                   await device[deviceCount].init();
                   log("✅ Device initialized: " + devices[i].name);
        
                   // Set device info
                   setState(praefix0 + "." + devices[i].did + ".info.did", devices[i].did, true);
                   setState(praefix0 + "." + devices[i].did + ".info.model", devices[i].model, true);
                   setState(praefix0 + "." + devices[i].did + ".info.localip", devices[i].localip, true);
                   setState(praefix0 + "." + devices[i].did + ".info.isOnline", true, true);
        
                   CreateDpTrigger(deviceCount);
        
                   deviceCount++;
        
               } catch (e) {
                   log("❌ Error connecting to " + devices[i].name + ": " + e.message, "error");
               }
           }
        
           log("✅ Initialization complete! " + deviceCount + " devices connected.");
        
           GenericDpRefreshIntervalObj = setInterval(function () {
               RefreshGenericDpsTicker();
           }, refresh);
        }
        
        async function RefreshGenericDpsTicker() {
           // Periodical status updates
           for (let i = 0; i < device.length; i++) {
               if (device[i]) {
                   setState(praefix0 + "." + device[i].deviceConfig.did + ".info.isOnline", device[i].isOnline, true);
               }
           }
        }
        
        function RefreshDps(deviceIndex, data) {
           let deviceId = device[deviceIndex].deviceConfig.did;
           let model = device[deviceIndex].model;
        
           if (logging) log("Updating properties for: " + device[deviceIndex].deviceConfig.name);
        
           for (let x in DefineDevice) {
               if (DefineDevice[x].model === model) {
                   // Control Datenpunkte
                   if (DefineDevice[x].control) {
                       for (let y in DefineDevice[x].control) {
                           let propName = DefineDevice[x].control[y].name;
                           let propType = DefineDevice[x].control[y].type;
                           let channelId = CorrectChannelId(propName);
                           
                           if (data[propName] !== undefined) {
                               let value = data[propName];
                               
                               // TYPE CONVERSION
                               if (propType === "boolean") {
                                   if (typeof value === "string") {
                                       value = (value === "true" || value === "on" || value === "1" || value === true || value === 1);
                                   } else {
                                       value = !!value;
                                   }
                               } 
                               else if (propType === "number") {
                                   if (typeof value === "string") {
                                       value = parseFloat(value) || 0;
                                   } else if (typeof value !== "number") {
                                       value = Number(value) || 0;
                                   }
                               }
        
                               setState(praefix0 + "." + deviceId + ".control." + channelId, value, true);
                               
                               if (logging) log("Set control." + propName + " = " + value);
                           }
                       }
                   }
                   
                   // Sensor Datenpunkte
                   if (DefineDevice[x].sensor) {
                       for (let y in DefineDevice[x].sensor) {
                           let propName = DefineDevice[x].sensor[y].name;
                           let propType = DefineDevice[x].sensor[y].type;
                           let channelId = CorrectChannelId(propName);
                           
                           if (data[propName] !== undefined) {
                               let value = data[propName];
                               
                               // TYPE CONVERSION
                               if (propType === "boolean") {
                                   if (typeof value === "string") {
                                       value = (value === "true" || value === "on" || value === "1" || value === true || value === 1);
                                   } else {
                                       value = !!value;
                                   }
                               } 
                               else if (propType === "number") {
                                   if (typeof value === "string") {
                                       value = parseFloat(value) || 0;
                                   } else if (typeof value !== "number") {
                                       value = Number(value) || 0;
                                   }
                               }
        
                               setState(praefix0 + "." + deviceId + ".sensor." + channelId, value, true);
                               
                               if (logging) log("Set sensor." + propName + " = " + value);
                           }
                       }
                   }
               }
           }
        }
        
        function CreateDpTrigger(deviceIndex) {
           let deviceId = device[deviceIndex].deviceConfig.did;
           let model = device[deviceIndex].model;
        
           for (let x in DefineDevice) {
               if (DefineDevice[x].model === model) {
                   // Nur Control Datenpunkte sind steuerbar
                   if (DefineDevice[x].control) {
                       for (let y in DefineDevice[x].control) {
                           if (DefineDevice[x].control[y].write) {
                               let propName = DefineDevice[x].control[y].name;
                               let channelId = CorrectChannelId(propName);
                               let dpPath = praefix0 + "." + deviceId + ".control." + channelId;
        
                               on({ id: dpPath, change: "ne", ack: false }, function (dp) {
                                   if (logging) log("Command received: " + propName + " = " + dp.state.val);
                                   
                                   if (DefineDevice[x].setter[propName]) {
                                       DefineDevice[x].setter[propName](deviceIndex, dp.state.val);
                                   }
                               });
                           }
                       }
                   }
               }
           }
        }
        
        onStop(function () {
           log("Stopping script...");
           for (let x in device) {
               if (device[x]) {
                   try {
                       device[x].destroy();
                   } catch(e) {
                       log("Error destroying device: " + e.message);
                   }
               }
           }
           if (GenericDpRefreshIntervalObj) {
               clearInterval(GenericDpRefreshIntervalObj);
           }
        }, 10);
        
        // ============================================
        // SCRIPT START
        // ============================================
        log("Configuration:");
        log("- Devices: " + devices.length);
        log("- Refresh: " + refresh + "ms");
        log("- Root path: " + praefix0);
        
        // Prepare datapoints
        for (let i = 0; i < devices.length; i++) {
           if (devices[i].enabled) {
               log("📝 Preparing DPs for: " + devices[i].name);
               PrepareGenericDps(devices[i].did);
               PrepareDeviceDps(devices[i].did, devices[i].model);
           }
        }
        
        log("🔍 Total datapoints prepared: " + DpCount);
        
        CreateStates();
        

        Edit:
        hab das Script jetzt nochmal angepasst, vom einfachen miIO-Protocol wieder auf die Original MIoT-Struktur
        Steuerung funktioniert wieder, Sensordaten werden allerdings nicht ausgelesen

        haselchenH Offline
        haselchenH Offline
        haselchen
        Most Active
        wrote on last edited by haselchen
        #463

        @crunchip

        Was hast Du am Skript verändert?
        Außer dem Datenpunkt.

        Synology DS218+ & 2 x Fujitsu Esprimo (VM/Container) + FritzBox7590 + 2 AVM 3000 Repeater & Homematic & HUE & Osram & Xiaomi, NPM 10.9.4, Nodejs 22.21.0 ,JS Controller 7.0.7 ,Admin 7.7.19

        crunchipC 1 Reply Last reply
        0
        • haselchenH haselchen

          @crunchip

          Was hast Du am Skript verändert?
          Außer dem Datenpunkt.

          crunchipC Away
          crunchipC Away
          crunchip
          Forum Testing Most Active
          wrote on last edited by crunchip
          #464

          @haselchen was meinst du mit nur dem Datenpunkt.
          Habe das ursprüngliche Script hergekommen und so wie @tobasium mittels perplexity ein neues erstellen lassen

          Probleme waren

          • Xiaomi hat ihre APIs mehrfach geändert

          • Authentifizierungsmethoden sind nicht mehr aktuell

          • 2FA könnte blockierend sein

          Problem Lösung
          Session ungültig ✅await mihome.miCloudProtocol.logout()vor Login
          Fehler wird ignoriert ✅ Proper Exception Handling mitloginSuccessFlag
          Keine Fehlerbehandlung ✅ Aussagekräftige Error-Messages
          Script läuft weiter ✅returnnach Login-Fehler

          Was der neue Code macht:
          ✅ Zeigt genau, wo der Login fehlschlägt

          ✅ Gibt die Credentials an (für Debugging)

          ✅ Zeigt ob node-mihome korrekt geladen ist

          ✅ Listet eine Fehlerbeseitungs-Checkliste auf

          ✅ Gibt komplette Error-Details aus

          ⚠️ Wichtig - Häufige Fehler:
          ❌ Token zu kurz/lang → Muss exakt 32 Zeichen sein
          ❌ IP falsch → Muss die lokale IP sein (z.B. 192.168.x.x), nicht die Cloud-ID
          ❌ Model falsch → Aus Extractor kopieren, exakt!
          ❌ Gerät offline → Device muss erreichbar sein

          umgestiegen von Proxmox auf Unraid

          haselchenH 1 Reply Last reply
          1
          • crunchipC crunchip

            @haselchen was meinst du mit nur dem Datenpunkt.
            Habe das ursprüngliche Script hergekommen und so wie @tobasium mittels perplexity ein neues erstellen lassen

            Probleme waren

            • Xiaomi hat ihre APIs mehrfach geändert

            • Authentifizierungsmethoden sind nicht mehr aktuell

            • 2FA könnte blockierend sein

            Problem Lösung
            Session ungültig ✅await mihome.miCloudProtocol.logout()vor Login
            Fehler wird ignoriert ✅ Proper Exception Handling mitloginSuccessFlag
            Keine Fehlerbehandlung ✅ Aussagekräftige Error-Messages
            Script läuft weiter ✅returnnach Login-Fehler

            Was der neue Code macht:
            ✅ Zeigt genau, wo der Login fehlschlägt

            ✅ Gibt die Credentials an (für Debugging)

            ✅ Zeigt ob node-mihome korrekt geladen ist

            ✅ Listet eine Fehlerbeseitungs-Checkliste auf

            ✅ Gibt komplette Error-Details aus

            ⚠️ Wichtig - Häufige Fehler:
            ❌ Token zu kurz/lang → Muss exakt 32 Zeichen sein
            ❌ IP falsch → Muss die lokale IP sein (z.B. 192.168.x.x), nicht die Cloud-ID
            ❌ Model falsch → Aus Extractor kopieren, exakt!
            ❌ Gerät offline → Device muss erreichbar sein

            haselchenH Offline
            haselchenH Offline
            haselchen
            Most Active
            wrote on last edited by
            #465

            @crunchip

            Dann hast Du nicht sein Skript genommen?!
            Okay , dann muss ich eure Beiden vergleichen , wo die Unterschiede sind .

            Synology DS218+ & 2 x Fujitsu Esprimo (VM/Container) + FritzBox7590 + 2 AVM 3000 Repeater & Homematic & HUE & Osram & Xiaomi, NPM 10.9.4, Nodejs 22.21.0 ,JS Controller 7.0.7 ,Admin 7.7.19

            crunchipC 1 Reply Last reply
            0
            • haselchenH haselchen

              @crunchip

              Dann hast Du nicht sein Skript genommen?!
              Okay , dann muss ich eure Beiden vergleichen , wo die Unterschiede sind .

              crunchipC Away
              crunchipC Away
              crunchip
              Forum Testing Most Active
              wrote on last edited by
              #466

              @haselchen sagte in [Vorlage] Xiaomi Airpurifier 3H u.a. inkl. Token auslesen.:

              Dann hast Du nicht sein Skript genommen?!

              nein, ist ein neues

              umgestiegen von Proxmox auf Unraid

              Siggi0904S 2 Replies Last reply
              0
              • haselchenH Offline
                haselchenH Offline
                haselchen
                Most Active
                wrote on last edited by
                #467

                @siggi0904

                https://github.com/PiotrMachowski/Xiaomi-cloud-tokens-extractor

                50691538-45b6-4283-9bfa-7d2ad716c43f-grafik.png

                Dort gibst Du in dem DOS Fenster Deine Login Daten ein.
                Dann erscheint ein Link.
                Den kopierst Du in den Browser und loggst Dich im Browser nochmal in Deinen Xiaomi Account ein.
                Im DOS Fenster gibst Du dann Dein Land ein (sollte bei Dir wohl "de" sein)
                Und dann werden Dir die Geräte mit allen Infos angezeigt.
                Und die Daten übernimmst Du ins Skript.

                Synology DS218+ & 2 x Fujitsu Esprimo (VM/Container) + FritzBox7590 + 2 AVM 3000 Repeater & Homematic & HUE & Osram & Xiaomi, NPM 10.9.4, Nodejs 22.21.0 ,JS Controller 7.0.7 ,Admin 7.7.19

                1 Reply Last reply
                1
                • crunchipC crunchip

                  @haselchen sagte in [Vorlage] Xiaomi Airpurifier 3H u.a. inkl. Token auslesen.:

                  Dann hast Du nicht sein Skript genommen?!

                  nein, ist ein neues

                  Siggi0904S Offline
                  Siggi0904S Offline
                  Siggi0904
                  wrote on last edited by
                  #468

                  @crunchip danke für die Anpassung des Skriptes.

                  Aber was ist did: "xxxxxxxxx" in deiner Gerätebeschreibung in deinem Skript ?

                  Dank dir.

                  crunchipC 1 Reply Last reply
                  0
                  • crunchipC crunchip

                    @haselchen sagte in [Vorlage] Xiaomi Airpurifier 3H u.a. inkl. Token auslesen.:

                    Dann hast Du nicht sein Skript genommen?!

                    nein, ist ein neues

                    Siggi0904S Offline
                    Siggi0904S Offline
                    Siggi0904
                    wrote on last edited by
                    #469

                    @crunchip Ich hätte folgende drei Geräte wo ich deine Unterstützung bei der MIoT-Struktur bräuchte:

                       {
                           name: Ventilator
                           id: xxxxx
                           // MAC: xxxxx
                           localip: 192.168.178.80
                           token: xxxxx
                           model: dmaker.fan.p15
                           enabled: true
                       },
                       {
                           name: Luftreiniger
                           id: xxxxx
                           // MAC: xxxxx
                           localip: 192.168.178.78
                           token: xxxxx
                           model: zhimi.airpurifier.mb3
                           enabled: true
                       },
                       {
                           name: John
                           id: xxxxx
                           // MAC: xxxxx
                           localip: 192.168.178.60
                           token: xxxxx
                           model: roborock.vacuum.s5
                           enabled: true
                       }
                    

                    Wie trenne ich die einzelnen Geräte von einander? Ist das Komma da richtig gesetzt?

                    crunchipC 1 Reply Last reply
                    0
                    • Siggi0904S Siggi0904

                      @crunchip danke für die Anpassung des Skriptes.

                      Aber was ist did: "xxxxxxxxx" in deiner Gerätebeschreibung in deinem Skript ?

                      Dank dir.

                      crunchipC Away
                      crunchipC Away
                      crunchip
                      Forum Testing Most Active
                      wrote on last edited by
                      #470

                      @siggi0904 ist die ID

                      umgestiegen von Proxmox auf Unraid

                      1 Reply Last reply
                      0
                      • Siggi0904S Siggi0904

                        @crunchip Ich hätte folgende drei Geräte wo ich deine Unterstützung bei der MIoT-Struktur bräuchte:

                           {
                               name: Ventilator
                               id: xxxxx
                               // MAC: xxxxx
                               localip: 192.168.178.80
                               token: xxxxx
                               model: dmaker.fan.p15
                               enabled: true
                           },
                           {
                               name: Luftreiniger
                               id: xxxxx
                               // MAC: xxxxx
                               localip: 192.168.178.78
                               token: xxxxx
                               model: zhimi.airpurifier.mb3
                               enabled: true
                           },
                           {
                               name: John
                               id: xxxxx
                               // MAC: xxxxx
                               localip: 192.168.178.60
                               token: xxxxx
                               model: roborock.vacuum.s5
                               enabled: true
                           }
                        

                        Wie trenne ich die einzelnen Geräte von einander? Ist das Komma da richtig gesetzt?

                        crunchipC Away
                        crunchipC Away
                        crunchip
                        Forum Testing Most Active
                        wrote on last edited by
                        #471

                        @siggi0904 theoretisch ja, hab es allerdings mit anderen Geräten noch nicht getestet.
                        Funktonale Datenpunkte sind Geräte und Firmware Versions abhängig.

                        umgestiegen von Proxmox auf Unraid

                        Siggi0904S 1 Reply Last reply
                        0
                        • crunchipC crunchip

                          @siggi0904 theoretisch ja, hab es allerdings mit anderen Geräten noch nicht getestet.
                          Funktonale Datenpunkte sind Geräte und Firmware Versions abhängig.

                          Siggi0904S Offline
                          Siggi0904S Offline
                          Siggi0904
                          wrote on last edited by
                          #472

                          @crunchip Sollte das Skript trotzdem die Daten holen können?
                          Also aus der node-mihome bzw. der js-Datei die dort liegt?

                          1 Reply Last reply
                          0
                          • Siggi0904S Offline
                            Siggi0904S Offline
                            Siggi0904
                            wrote on last edited by
                            #473

                            Mein Ventilator sieht in den Datenpunkten so aus:
                            f5ee96e9-384d-4658-bebc-519563adf990-grafik.png

                            Und mein Luftreiniger so:
                            aac6a68f-af87-4494-9b58-71016468815a-grafik.png

                            Leider alles ohne aktuelle Werte.

                            crunchipC 1 Reply Last reply
                            0
                            • Siggi0904S Siggi0904

                              Mein Ventilator sieht in den Datenpunkten so aus:
                              f5ee96e9-384d-4658-bebc-519563adf990-grafik.png

                              Und mein Luftreiniger so:
                              aac6a68f-af87-4494-9b58-71016468815a-grafik.png

                              Leider alles ohne aktuelle Werte.

                              crunchipC Away
                              crunchipC Away
                              crunchip
                              Forum Testing Most Active
                              wrote on last edited by
                              #474

                              @siggi0904 sagte in [Vorlage] Xiaomi Airpurifier 3H u.a. inkl. Token auslesen.:

                              Leider alles ohne aktuelle Werte.

                              @crunchip sagte in [Vorlage] Xiaomi Airpurifier 3H u.a. inkl. Token auslesen.:

                              Sensordaten werden allerdings nicht ausgelesen

                              umgestiegen von Proxmox auf Unraid

                              1 Reply Last reply
                              0
                              Reply
                              • Reply as topic
                              Log in to reply
                              • Oldest to Newest
                              • Newest to Oldest
                              • Most Votes


                              Support us

                              ioBroker
                              Community Adapters
                              Donate

                              320

                              Online

                              32.7k

                              Users

                              82.5k

                              Topics

                              1.3m

                              Posts
                              Community
                              Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                              ioBroker Community 2014-2025
                              logo
                              • Login

                              • Don't have an account? Register

                              • Login or register to search.
                              • First post
                                Last post
                              0
                              • Home
                              • Recent
                              • Tags
                              • Unread 0
                              • Categories
                              • Unreplied
                              • Popular
                              • GitHub
                              • Docu
                              • Hilfe