Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • 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

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
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

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    14
    1
    166

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    12
    1
    569

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    24
    1
    1.8k

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

Geplant Angeheftet Gesperrt Verschoben JavaScript
474 Beiträge 50 Kommentatoren 102.2k Aufrufe 41 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • crunchipC Abwesend
    crunchipC Abwesend
    crunchip
    Forum Testing Most Active
    schrieb am zuletzt editiert von 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 Antwort Letzte Antwort
    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
      schrieb am zuletzt editiert von 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 Antwort Letzte Antwort
      0
      • haselchenH haselchen

        @crunchip

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

        crunchipC Abwesend
        crunchipC Abwesend
        crunchip
        Forum Testing Most Active
        schrieb am zuletzt editiert von 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 Antwort Letzte Antwort
        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
          schrieb am zuletzt editiert von
          #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 Antwort Letzte Antwort
          0
          • haselchenH haselchen

            @crunchip

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

            crunchipC Abwesend
            crunchipC Abwesend
            crunchip
            Forum Testing Most Active
            schrieb am zuletzt editiert von
            #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 Antworten Letzte Antwort
            0
            • haselchenH Offline
              haselchenH Offline
              haselchen
              Most Active
              schrieb am zuletzt editiert von
              #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 Antwort Letzte Antwort
              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
                schrieb am zuletzt editiert von
                #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 Antwort Letzte Antwort
                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
                  schrieb am zuletzt editiert von
                  #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 Antwort Letzte Antwort
                  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 Abwesend
                    crunchipC Abwesend
                    crunchip
                    Forum Testing Most Active
                    schrieb am zuletzt editiert von
                    #470

                    @siggi0904 ist die ID

                    umgestiegen von Proxmox auf Unraid

                    1 Antwort Letzte Antwort
                    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 Abwesend
                      crunchipC Abwesend
                      crunchip
                      Forum Testing Most Active
                      schrieb am zuletzt editiert von
                      #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 Antwort Letzte Antwort
                      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
                        schrieb am zuletzt editiert von
                        #472

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

                        1 Antwort Letzte Antwort
                        0
                        • Siggi0904S Offline
                          Siggi0904S Offline
                          Siggi0904
                          schrieb am zuletzt editiert von
                          #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 Antwort Letzte Antwort
                          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 Abwesend
                            crunchipC Abwesend
                            crunchip
                            Forum Testing Most Active
                            schrieb am zuletzt editiert von
                            #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 Antwort Letzte Antwort
                            0
                            Antworten
                            • In einem neuen Thema antworten
                            Anmelden zum Antworten
                            • Älteste zuerst
                            • Neuste zuerst
                            • Meiste Stimmen


                            Support us

                            ioBroker
                            Community Adapters
                            Donate

                            692

                            Online

                            32.5k

                            Benutzer

                            81.8k

                            Themen

                            1.3m

                            Beiträge
                            Community
                            Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                            ioBroker Community 2014-2025
                            logo
                            • Anmelden

                            • Du hast noch kein Konto? Registrieren

                            • Anmelden oder registrieren, um zu suchen
                            • Erster Beitrag
                              Letzter Beitrag
                            0
                            • Home
                            • Aktuell
                            • Tags
                            • Ungelesen 0
                            • Kategorien
                            • Unreplied
                            • Beliebt
                            • GitHub
                            • Docu
                            • Hilfe