text: const SkriptVersion = "0.2.12"; //vom 15.04.2021 / Link zu Git: https://github.com/Pittini/iobroker-nodemihome / Forum: https://forum.iobroker.net/topic/39388/vorlage-xiaomi-airpurifier-3h-u-a-inkl-token-auslesen
  
  const mihome = require('node-mihome');
  
  // Logindaten für Xiaomi Cloud:
  const username = '';
  const password = '';
  const options = { country: 'de' }; // 'ru', 'us', 'tw', 'sg', 'cn', 'de' (Default: 'cn');
  const refresh = 10000;
  
  const praefix0 = "javascript.0.MiHomeAll"; //Root für Skriptdatenpunkte
  
  const logging = false; //Logging aktivieren/deaktivieren
  
  //Ab hier nix mehr ändern!
  /*
  1. Xiaomi Cloudlogin
  2. Alle dort gelisteten Geräte und deren Basicdaten abrufen
  3. Für alle abgerufenen Geräte Basic Channel/Datenpunkte anlegen
  4. Prüfen welche supporteten Geräte in der Auflistung vorhanden sind und die entsprechenden spezifischen Datenpunkte erstellen
  5. Basic Channels mit Daten füllen / einlesen
  6. devicearray erstellen via node-mihome und die Gerätespezifischen Werte einlesen
  
  
  */
  // ######### TESTBEREICH ################
  //const axios = require('axios');
  
  //let miotDefinition= getMiotData('https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-mb3:2');
  
  async function getMiotData(url) {
      if (logging) log("Reaching MiotUrlConstructor");
      try {
          const response = await axios.get(url, { timeout: 10000 });
          log("resp:" + JSON.stringify(response.data));
          for (let z in Object.keys(response.data.services)) {
              log("Keys=" + Object.keys(response.data.services[z]))
              log(JSON.stringify(response.data.services[z]))
          }
  
          return response.data;
      } catch (error) {
          console.error(error);
      }
  }
  
  function MiotUrlConstructor(miotdevice) {
      if (logging) log("Reaching MiotUrlConstructor");
      let BaseUrl = "https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:" + miotdevice;
      return BaseUrl;
  }
  
  // ################ ENDE TESTBEREICH ####################
  
  
  
  const DeviceData = [];
  let AllDevicesRaw = [];
  
  let device = [];
  
  const States = [];
  let DpCount = 0;
  log("Starting AllMyMi V." + SkriptVersion);
  
  Init();
  
  const DefineDevice = [];
  
  // ***************************** Device Definitions *************************
  
  // ***************************** Airpurifiers ********************************
  
  
  DefineDevice[0] = { // Tested and working
      info: {},
      model: "zhimi.airpurifier.mb3",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-mb3:2
      description: "Purifier 3H",
      setter: {
          "air-purifier.on": async function (obj, val) { await device[obj].setPower(val) },
          "air-purifier.mode": async function (obj, val) { await device[obj].setMode(val) },
          "motor-speed.favorite-fan-level": async function (obj, val) { await device[obj].setFavLevel(val) },
          "air-purifier.fan-level": async function (obj, val) { await device[obj].setFanLevel(val) },
          "alarm.alarm": async function (obj, val) { await device[obj].setBuzzer(val) },
          "indicator-light.brightness": async function (obj, val) { await device[obj].setLcdBrightness(val) },
          "physical-controls-locked.physical-controls-locked": async function (obj, val) { await device[obj].setChildLock(val) }
      },
      common:
          [{ name: "air-purifier.on", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "air-purifier.fault", type: "number", read: true, write: false, min: 0, max: 5, states: { 0: "No faults", 1: "m1_run", 2: "m1_stuck", 3: "no_sensor", 4: "error_hum", 5: "error_temp", 6: "timer_error1", 7: "timer_error2" } },
          { 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: "alarm.alarm", type: "boolean", read: true, write: true },
          { name: "indicator-light.brightness", type: "number", read: true, write: true, min: 0, max: 2 },
          { name: "indicator-light.on", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "environment.temperature", type: "number", role: "value.temperature", read: true, write: false, min: -40, max: 125, unit: "°C" },
          { name: "motor-speed.motor-speed", type: "number", read: true, write: false, min: 0, max: 3000, unit: "rpm" },
          { name: "motor-speed.motor-set-speed", type: "number", read: true, write: false, min: 0, max: 3000, unit: "rpm" },
          { name: "motor-speed.favorite-fan-level", type: "number", read: true, write: true, min: 0, max: 14 },
          { name: "use-time.use-time", type: "number", read: true, write: false },
          { name: "environment.relative-humidity", type: "number", role: "value.humidity", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "environment.pm2_5-density", type: "number", read: true, write: false, min: 0, max: 600, unit: "μg/m³" },
          { name: "filter.filter-life-level", type: "number", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "filter.filter-used-time", type: "number", read: true, write: false, unit: "h" },
          { name: "physical-controls-locked.physical-controls-locked", type: "boolean", role: "switch", read: true, write: true, min: false, max: true }]
  };
  
  DefineDevice[8] = {  // Tested and working - https://github.com/Pittini/iobroker-nodemihome/issues/6
      info: {},
      model: "zhimi.airpurifier.mc2",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-mc2:1
      description: "Purifier 2H",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val) },
          "mode": async function (obj, val) { await device[obj].setMode(val) },
          "favorite_level": async function (obj, val) { await device[obj].setFavoriteLevel(val) },
          "led": async function (obj, val) { await device[obj].setLed(val) },
          "led_b": async function (obj, val) { await device[obj].setLedB(val) },
          "buzzer": async function (obj, val) { await device[obj].setBuzzer(val) },
          "child_lock": async function (obj, val) { await device[obj].setChildLock(val) }
      },
      common:
          [{ name: "power", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "mode", type: "string", role: "state", read: true, write: true, states: { "auto": "auto", "silent": "silent", "favorite": "favorite" } },
          { name: "favorite_level", type: "number", role: "state", read: true, write: true, min: 0, max: 16 },
          { name: "temp_dec", type: "number", role: "value.temperature", read: true, write: false, min: -40.0, max: 525.0, unit: "°C" },
          { name: "humidity", type: "number", role: "value.humidity", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "aqi", type: "number", role: "value", read: true, write: false, min: 0, max: 600, unit: "μg/m³" },
          { name: "average_aqi", type: "number", role: "value", read: true, write: false, min: 0, max: 600, unit: "μg/m³" },
          { name: "led", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "led_b", type: "number", role: "state", read: true, write: true, min: 0, max: 2, states: { 0: "bright", 1: "dim", 2: "off" } },
          { name: "buzzer", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "filter1_life", type: "number", role: "value", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "f1_hour", type: "number", role: "value", read: true, write: false, unit: "h" },
          { name: "f1_hour_used", type: "number", role: "value", read: true, write: false, unit: "h" },
          { name: "motor1_speed", type: "number", role: "value", read: true, write: false, unit: "rpm" },
          { name: "child_lock", type: "boolean", role: "switch", read: true, write: true, min: false, max: true }]
  };
  
  DefineDevice[13] = { // Tested and working
      info: {},
      model: "zhimi.airpurifier.vb2",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-vb2:1
      description: "Mi Air Purifier Pro H",
      setter: {
          "air-purifier.on": async function (obj, val) { await device[obj].setPower(val) },
          "air-purifier.mode": async function (obj, val) { await device[obj].setMode(val) },
          "motor-speed.favorite-level": async function (obj, val) { await device[obj].setFavLevel(val) },
          "air-purifier.fan-level": async function (obj, val) { await device[obj].setFanLevel(val) },
          "alarm.volume": async function (obj, val) { await device[obj].setBuzzer(val) },
          "indicator-light.brightness": async function (obj, val) { await device[obj].setLcdBrightness(val) },
          "physical-controls-locked.physical-controls-locked": async function (obj, val) { await device[obj].setChildLock(val) }
      },
      common:
          [{ name: "air-purifier.on", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "air-purifier.fault", type: "number", read: true, write: false, min: 0, max: 5, states: { 0: "No faults", 1: "m1_run", 2: "m1_stuck", 3: "no_sensor", 4: "error_hum", 5: "error_temp", 6: "timer_error1", 7: "timer_error2" } },
          { 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: "alarm.volume", type: "number", read: true, write: true, min: 0, max: 100 },
          { name: "indicator-light.brightness", type: "number", read: true, write: true, min: 0, max: 2 },
          { name: "indicator-light.on", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "environment.temperature", type: "number", role: "value.temperature", read: true, write: false, min: -40, max: 125, unit: "°C" },
          { name: "motor-speed.motor1-speed", type: "number", read: true, write: false, min: 0, max: 3000, unit: "rpm" },
          { name: "motor-speed.motor1-set-speed", type: "number", read: true, write: false, min: 0, max: 3000, unit: "rpm" },
          { name: "motor-speed.favorite-level", type: "number", read: true, write: true, min: 0, max: 14 },
          { name: "use-time.use-time", type: "number", read: true, write: false },
          { name: "environment.relative-humidity", type: "number", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "environment.pm2_5-density", type: "number", read: true, write: false, min: 0, max: 600, unit: "μg/m³" },
          { name: "filter.filter-life-level", type: "number", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "filter.filter-used-time", type: "number", read: true, write: false, unit: "h" },
          { name: "physical-controls-locked.physical-controls-locked", type: "boolean", role: "switch", read: true, write: true, min: false, max: true }]
  };
  
  DefineDevice[14] = { // Tested and working - https://github.com/Pittini/iobroker-nodemihome/issues/6
      info: {},
      model: "zhimi.airpurifier.v7",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-v7:1
      description: "Mi Air Purifier",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val) },
          "mode": async function (obj, val) { await device[obj].setFanLevel(val) },
          "led": async function (obj, val) { await device[obj].setDisplay(val) },
          "child_lock": async function (obj, val) { await device[obj].setChildLock(val) }
      },
      common:
          [{ name: "power", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "mode", type: "string", read: true, write: true, states: { "auto": "auto", "silent": "silent", "favorite": "favorite" } },
          { name: "favorite_level", type: "number", read: true, write: false, min: 0, max: 16 },
          { name: "temp_dec", type: "number", role: "value.temperature", read: true, write: false },
          { name: "humidity", type: "number", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "aqi", type: "number", read: true, write: false, unit: "μg/m³" },
          { name: "average_aqi", type: "number", read: true, write: false, unit: "μg/m³" },
          { name: "led", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "bright", type: "number", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "volume", type: "number", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "filter1_life", type: "number", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "f1_hour", type: "number", read: true, write: false },
          { name: "f1_hour_used", type: "number", read: true, write: false },
          { name: "motor1_speed", type: "number", read: true, write: false, unit: "rpm" },
          { name: "motor2_speed", type: "number", read: true, write: false, unit: "rpm" },
          { name: "child_lock", type: "boolean", role: "switch", read: true, write: true, min: false, max: true }]
  };
  
  DefineDevice[15] = { // Tested and working
      info: {},
      model: "zhimi.airpurifier.mb4",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-mb4:2
      description: "Purifier 3C",
      setter: {
          "air-purifier.on": async function (obj, val) { await device[obj].setPower(val) },
          "air-purifier.mode": async function (obj, val) { await device[obj].setMode(val) },
          "custom-service.favorite-speed": async function (obj, val) { await device[obj].setFavSpeed(val) },
          "alarm.alarm": async function (obj, val) { await device[obj].setBuzzer(val) },
          "screen.brightness": async function (obj, val) { await device[obj].setLcdBrightness(val) },
          "physical-controls-locked.physical-controls-locked": async function (obj, val) { await device[obj].setChildLock(val) }
      },
      common:
          [{ name: "air-purifier.on", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "air-purifier.fault", type: "string", 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: "alarm.alarm", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "screen.brightness", type: "number", read: true, write: true, min: 0, max: 8 },
          { name: "environment.pm2_5-density", type: "number", read: true, write: false, min: 0, max: 600, unit: "μg/m³" },
          { name: "custom-service.moto-speed-rpm", type: "number", read: true, write: false, min: 0, max: 65535, unit: "rpm" },
          { name: "custom-service.favorite-speed", type: "number", read: true, write: true, min: 300, max: 2300, unit: "rpm" },
          { name: "filter.filter-life-level", type: "number", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "filter.filter-used-time", type: "number", read: true, write: false, unit: "h" },
          { name: "physical-controls-locked.physical-controls-locked", type: "boolean", role: "switch", read: true, write: true, min: false, max: true }]
  };
  
  // ***************************** Fans *********************************
  //  TODO https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:fan:0000A005:zhimi-sa1:1
  
  DefineDevice[1] = { // untested
      info: {},
      model: "leshow.fan.ss4",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:fan:0000A005:leshow-ss4:1  
      description: "Leshow Fan",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val ? 'on' : 'off') },
          "blow": async function (obj, val) { await device[obj].setFanLevel(val) },
          "yaw": async function (obj, val) { await device[obj].setFanSwing(val ? 'on' : 'off') },
          "mode": async function (obj, val) { await device[obj].setSleepMode(val) },
          "sound": async function (obj, val) { await device[obj].setBuzzer(val ? 'on' : 'off') },
          "timer": async function (obj, val) { await device[obj].setTimer(val) }
      },
      common:
          [{ name: "power", type: "boolean", role: "switch", read: true, write: true },
          { name: "blow", type: "number", read: true, write: true, min: 1, max: 100 },
          { name: "yaw", type: "boolean", role: "switch", read: true, write: true },
          { name: "mode", type: "boolean", role: "switch", read: true, write: true },
          { name: "sound", type: "boolean", role: "switch", read: true, write: true },
          { name: "timer", type: "number", read: true, write: true, min: 0, max: 540, unit: "m" }]
  };
  
  DefineDevice[9] = { // untested
      info: {},
      model: "zhimi.fan.za4",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:fan:0000A005:zhimi-za4:1  
      description: "Mi Fan 2S",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val) },
          "angle": async function (obj, val) { await device[obj].setFanLevel(val) },
          "angle_enable": async function (obj, val) { await device[obj].setSwing(val ? 'on' : 'off') },
          "fan_level": async function (obj, val) { await device[obj].setFanLevel(val) },
          "buzzer": async function (obj, val) { await device[obj].setBuzzer(val ? 'on' : 'off') },
          "child_lock": async function (obj, val) { await device[obj].setChildLock(val ? 'on' : 'off') },
          "led_b": async function (obj, val) { await device[obj].setLcdBrightness(val) },
          "speed_level": async function (obj, val) { await device[obj].setSleepMode(val) },
          "poweroff_time": async function (obj, val) { await device[obj].setTimer(val) }
      },
      common:
          [{ name: "power", type: "boolean", role: "switch", read: true, write: true },
          { name: "angle", type: "number", read: true, write: true, min: 1, max: 120 },
          { name: "angle_enable", type: "boolean", role: "switch", read: true, write: true },
          { name: "fan_level", type: "number", read: true, write: true, min: 1, max: 4 },
          { name: "buzzer", type: "boolean", role: "switch", read: true, write: true },
          { name: "child_lock", type: "boolean", role: "switch", read: true, write: true },
          { name: "led_b", type: "boolean", role: "switch", read: true, write: true },
          { name: "speed_level", type: "number", read: true, write: true, min: 1, max: 4 },
          { name: "poweroff_time", type: "number", read: true, write: true, min: 0, max: 540, unit: "m" }]
  };
  
  // ***************************** Lights *********************************
  
  DefineDevice[2] = { // Tested and ok except setting color
      info: {},
      model: "yeelink.light.strip2",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:light:0000A001:yeelink-color2:1    
      description: "Yeelight Lightstrip Plus",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val ? 'on' : 'off') },
          "bright": async function (obj, val) { await device[obj].setBrightness(val) },
          "hue": async function (obj, val) { await device[obj].setColorHSV(val) },
          "color_mode": async function (obj, val) { await device[obj].setColorMode(val) },
          "ct": async function (obj, val) { await device[obj].setCt(val) }
      },
      common:
          [{ name: "power", type: "boolean", role: "switch", read: true, write: true },
          { name: "bright", type: "number", read: true, write: true, min: 1, max: 100 },
          { name: "hue", type: "number", read: true, write: true, min: 0, max: 16777215 },
          { name: "sat", type: "number", read: true, write: true, min: 0, max: 100 },
          { name: "color_mode", type: "number", read: true, write: true, min: 1, max: 2 },
          { name: "ct", type: "number", read: true, write: true, min: 1700, max: 6500 }]
  };
  
  DefineDevice[5] = { // Tested and working
      info: {},
      model: "yeelink.light.ct2",//     http://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:light:0000A001:yeelink-ct2:1
      description: "Yeelight LED Bulb (Tunable)",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val ? 'on' : 'off') },
          "bright": async function (obj, val) { await device[obj].setBrightness(val) },
          "ct": async function (obj, val) { await device[obj].setColorTemperature(val) }
      },
      common:
          [{ name: "power", type: "boolean", role: "switch", read: true, write: true },
          { name: "bright", type: "number", read: true, write: true, min: 1, max: 100 },
          { name: "ct", type: "number", read: true, write: true, min: 1700, max: 6500 }]
  };
  
  DefineDevice[6] = { // Tested and working except color setting
      info: {},
      model: "yeelink.light.color2",//    https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:light:0000A001:yeelink-color2:1
      description: "Yeelight LED Bulb (Color)",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val ? 'on' : 'off') },
          "bright": async function (obj, val) { await device[obj].setBrightness(val) },
          "rgb": async function (obj, val) { await device[obj].setColorRgb(val) },
          "color_mode": async function (obj, val) { await device[obj].setColorMode(val) },
          "ct": async function (obj, val) { await device[obj].setCt(val) }
      },
      common:
          [{ name: "power", type: "boolean", role: "switch", read: true, write: true },
          { name: "bright", type: "number", read: true, write: true, min: 1, max: 100 },
          { name: "rgb", type: "number", read: true, write: true, min: 1, max: 16777215 },
          { name: "color_mode", type: "number", read: true, write: true, min: 1, max: 2 },
          { name: "ct", type: "number", read: true, write: true, min: 1700, max: 6500 }]
  };
  DefineDevice[10] = { // untested
      info: {},
      model: "yeelink.light.ceiling3",//    https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:light:0000A001:yeelink-ceiling3:1
      description: "Yeelight LED Ceiling Light",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val ? 'on' : 'off') },
          "bright": async function (obj, val) { await device[obj].setBrightness(val) },
          "nl_br": async function (obj, val) { await device[obj].setBrightness(val) },
          "night_mode": async function (obj, val) { await device[obj].setSleepMode(val) },
          "ct": async function (obj, val) { await device[obj].setCt(val) }
      },
      common:
          [{ name: "power", type: "boolean", role: "switch", read: true, write: true },
          { name: "bright", type: "number", read: true, write: true, min: 1, max: 100 },
          { name: "nl_br", type: "number", read: true, write: true, min: 1, max: 100 },
          { name: "night_mode", type: "boolean", role: "switch", read: true, write: true },
          { name: "ct", type: "number", read: true, write: true, min: 1700, max: 6500 }]
  };
  DefineDevice[11] = { // untested
      info: {},
      model: "yeelink.light.ceiling1",//    https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:light:0000A001:yeelink-ceiling1:1
      description: "Yeelight Crystal Pedestal Light",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val ? 'on' : 'off') },
          "bright": async function (obj, val) { await device[obj].setBrightness(val) },
          "nl_br": async function (obj, val) { await device[obj].setBrightness(val) },
          "night_mode": async function (obj, val) { await device[obj].setSleepMode(val) },
          "ct": async function (obj, val) { await device[obj].setCt(val) }
      },
      common:
          [{ name: "power", type: "boolean", role: "switch", read: true, write: true },
          { name: "bright", type: "number", read: true, write: true, min: 1, max: 100 },
          { name: "nl_br", type: "number", read: true, write: true, min: 1, max: 100 },
          { name: "night_mode", type: "boolean", read: true, write: true },
          { name: "ct", type: "number", read: true, write: true, min: 1700, max: 6500 }]
  };
  
  DefineDevice[16] = { // untested
      info: {},
      model: "yeelink.light.lamp4",//    https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:light:0000A001:yeelink-lamp4:1
      description: "Mi LED Desk Lamp 1S",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val) },
          "bright": async function (obj, val) { await device[obj].setBrightness(val) },
          "ct": async function (obj, val) { await device[obj].setColorTemperature(val) }
      },
      common:
          [{ name: "power", type: "boolean", role: "switch", read: true, write: true },
          { name: "bright", type: "number", read: true, write: true, min: 1, max: 100 },
          { name: "ct", type: "number", read: true, write: true, min: 1700, max: 6500 }]
  };
  
  // ***************************** Humidifier *********************************
  
  DefineDevice[3] = { // Tested and working
      info: {},
      model: "zhimi.humidifier.cb1",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:humidifier:0000A00E:zhimi-cb1:1
      description: "Smartmi Evaporative Humidifier",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val) },
          "buzzer": async function (obj, val) { await device[obj].setBuzzer(val ? 'on' : 'off') },
          "mode": async function (obj, val) { await device[obj].setFanLevel(val) },
          "limit_hum": async function (obj, val) { await device[obj].setTargetHumidity(val) },
          "led": async function (obj, val) { await device[obj].setLedBrightness(val) },
          "child_lock": async function (obj, val) { await device[obj].setChildLock(val ? 'on' : 'off') },
          "dry": async function (obj, val) { await device[obj].setMode(val ? 'dry' : 'humidify') }
      },
      common:
          [{ name: "power", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "depth", type: "number", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "limit_hum", type: "number", read: true, write: true, min: 0, max: 100, unit: "%", states: { 30: "30%", 40: "40%", 50: "50%", 60: "60%", 70: "70%", 80: "80%" } },
          { name: "led", type: "number", read: true, write: true, min: 0, max: 2, states: { 0: "bright", 1: "dim", 2: "off" } },
          { name: "buzzer", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "temperature", type: "number", role: "value.temperature", read: true, write: false, min: -40, max: 125, unit: "°C" },
          { name: "humidity", type: "number", role: "value.humidity", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "child_lock", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "dry", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "mode", type: "string", read: true, write: true, states: { "auto": "auto", "silent": "silent", "medium": "medium", "high": "high" } }]
  };
  DefineDevice[4] = { // untested
      info: {},
      model: "deerma.humidifier.jsq",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:humidifier:0000A00E:deerma-jsq:1
      description: "Mi Smart Antibacterial Humidifier",
      setter: {
          "humidifier.on": async function (obj, val) { await device[obj].setPower(val) },
          "humidifier.fan-level": async function (obj, val) { await device[obj].setFanLevel(val) },
          "alarm.alarm": async function (obj, val) { await device[obj].setBuzzer(val) },
          "physical-controls-locked.physical-controls-locked": async function (obj, val) { await device[obj].setChildLock(val) }
      },
      common:
          [{ name: "humidifier.on", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "humidifier.fan-level", type: "number", read: true, write: true, min: 0, max: 3, states: { 0: "auto", 1: "level1", 2: "level2", 3: "level3" } },
          { name: "humidifier.water-level", type: "number", read: true, write: false, min: 0, max: 127 },
          { name: "alarm.alarm", type: "boolean", read: true, write: true, min: false, max: true },
          { name: "environment.temperature", type: "number", role: "value.temperature", read: true, write: false, min: -40, max: 125, unit: "°C" },
          { name: "environment.relative-humidity", type: "number", role: "value.humidity", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "physical-controls-locked.physical-controls-locked", type: "boolean", role: "switch", read: true, write: true, min: false, max: true }]
  };
  DefineDevice[12] = { // untested
      info: {},
      model: "zhimi.humidifier.ca4",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:humidifier:0000A00E:zhimi-ca4:1
      description: "Smartmi Evaporative Humidifier",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val ? 'on' : 'off') },
          "buzzer": async function (obj, val) { await device[obj].setBuzzer(val ? 'on' : 'off') },
          "mode": async function (obj, val) { await device[obj].setFanLevel(val) },
          "limit_hum": async function (obj, val) { await device[obj].setTargetHumidity(val) },
          "led": async function (obj, val) { await device[obj].setLedBrightness(val) },
          "child_lock": async function (obj, val) { await device[obj].setChildLock(val ? 'on' : 'off') },
          "dry": async function (obj, val) { await device[obj].setMode(val ? 'dry' : 'humidify') }
      },
      common:
          [{ name: "power", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "depth", type: "number", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "limit_hum", type: "number", read: true, write: true, min: 0, max: 100, unit: "%", states: { 30: "30%", 40: "40%", 50: "50%", 60: "60%", 70: "70%", 80: "80%" } },
          { name: "led", type: "number", read: true, write: true, min: 0, max: 2, states: { 0: "bright", 1: "dim", 2: "off" } },
          { name: "buzzer", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "temperature", type: "number", role: "value.temperature", read: true, write: false, min: -40, max: 125, unit: "°C" },
          { name: "humidity", type: "number", role: "value.humidity", read: true, write: false, min: 0, max: 100, unit: "%" },
          { name: "child_lock", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "dry", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
          { name: "mode", type: "string", read: true, write: true, states: { "auto": "auto", "silent": "silent", "medium": "medium", "high": "high" } }]
  };
  
  // ***************************** Divers *********************************
  // TODO https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:coffee-machine:0000A049:scishare-s1102:1
  // TODO https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:camera:0000A01C:mijia-v1:1
  // TODO https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:plant-monitor:0000A030:hhcc-v1:1
  // TODO https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:heater:0000A01A:zhimi-mc2:1
  
  DefineDevice[7] = { // In arbeit - unvollständig
      info: {},
      model: "lumi.gateway.v3",//    https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:gateway:0000A019:lumi-v3:1
      description: "Xiaomi RGB Gateway",
      setter: {
          "power": async function (obj, val) { await device[obj].setPower(val) },
          "doorbell_push": async function (obj, val) { await device[obj].setBrightness(val) },
          "toggle_light": async function (obj, val) { await device[obj].setLightPower(val) },
      },
      common:
          [{ name: 'illumination', role: 'value.lux', write: false, read: true, type: 'number', unit: 'lux' },
          { name: 'rgb', role: 'level.color.rgb', write: true, read: true, type: 'string' },
          { name: 'nightlight_rgb', role: 'level.color.rgb', write: true, read: true, type: 'string' },
          { name: "mute", type: "boolean", read: true, write: true },
          { name: 'toggle_light', role: 'switch', write: true, read: true, type: 'boolean' },
          { name: 'light.dimmer', role: 'level.dimmer', write: true, read: true, type: 'number', unit: '%', min: 0, max: 100 },
          { name: 'gateway_volume', role: 'level.volume', write: true, read: true, type: 'number', unit: '%', min: 0, max: 100 },
          { name: 'doorbell_volume', role: 'level.volume', write: true, read: true, type: 'number', unit: '%', min: 0, max: 100 },
          { name: 'alarming_volume', role: 'level.volume', write: true, read: true, type: 'number', unit: '%', min: 0, max: 100 },
          { name: "doorbell_push", type: "boolean", read: true, write: true },
          { name: "arming", type: "boolean", read: true, write: true },
          { name: "arming_time", type: "number", read: true, write: true },
          { name: 'music_ID', role: 'state', write: true, read: false, type: 'number', desc: '10000 - stop, 10005 - custom ringtone' },
          { name: 'proto_version', role: 'info', write: false, read: true, type: 'string' },
          { name: 'join_permission', role: 'state', write: true, read: true, type: 'string' },
          { name: 'remove_device', role: 'state', write: true, read: true, type: 'string' },     // Removing a subdevice (device sid)
          { name: 'connected', role: 'indicator.reachable', write: false, read: true, type: 'boolean', desc: 'Will be set to false if no packets received in 20 seconds' }]
  };
  
  /*
     gateway:          {type: 'gateway',            fullName: 'Xiaomi RGB Gateway', ClassName: Gateway, states: {
            +  illumination:   {name: 'Illumination',    role: 'value.lux',         write: false, read: true,  type: 'number', unit: 'lux'},
            +  rgb:            {name: 'RGB',             role: 'level.color.rgb',   write: true,  read: true,  type: 'string'},
              on:             {name: 'Light',           role: 'switch',            write: true,  read: true,  type: 'boolean'},
              dimmer:         {name: 'Light',           role: 'level.dimmer',      write: true,  read: true,  type: 'number', unit: '%', min: 0, max: 100},
              volume:         {name: 'Volume',          role: 'level.volume',      write: true,  read: true,  type: 'number', unit: '%', min: 0, max: 100},
              mid:            {name: 'Music ID',        role: 'state',             write: true,  read: false, type: 'number', desc: '10000 - stop, 10005 - custom ringtone'},
              proto_version:  {name: 'Proto Version',   role: 'info',              write: false, read: true,  type: 'string'},
              join_permission:{name: 'Add device',      role: 'state',             write: true, read: true,  type: 'string'},     // Permission to add subdevices (yes / no)
              remove_device:  {name: 'Remove device',   role: 'state',             write: true, read: true,  type: 'string'},     // Removing a subdevice (device sid)
              connected:      {name: 'Is gateway connected', role: 'indicator.reachable', write: false, read: true, type: 'boolean', desc: 'Will be set to false if no packets received in 20 seconds'}
          }
  */
  
  for (let x in DefineDevice) { //An alle Devicedefinitionen die generischen Datenpunkte anhängen
      DefineDevice[x].info = [
          { id: "localip", initial: "", forceCreation: false, common: { read: true, write: true, name: "Ip Adress", type: "string", role: "value", def: "" } },
          { id: "token", initial: "", forceCreation: false, common: { read: true, write: true, name: "Token", type: "string", role: "value", def: "" } },
          { id: "did", initial: "", forceCreation: false, common: { read: true, write: true, name: "Device Id", type: "string", role: "value", def: "" } },
          { id: "model", initial: "", forceCreation: false, common: { read: true, write: true, name: "Model", type: "string", role: "value", def: "" } },
          { id: "rssi", initial: 0, forceCreation: false, common: { read: true, write: false, name: "rssi", type: "number", role: "value.rssi", def: 0 } },
          { id: "name", initial: "", forceCreation: false, common: { read: true, write: true, name: "Name", type: "string", role: "value", def: "" } },
          { id: "isOnline", initial: false, forceCreation: false, common: { read: true, write: true, name: "Is online", type: "boolean", role: "value", def: false } }]
  
  }
  
  function PrepareDeviceDps(did, model) {
      if (logging) log("Reaching PrepareDeviceDps, did=" + did + " model=" + model);
      for (let x in DefineDevice) { //Alle definierten Model durchgehen
          if (DefineDevice[x].model == model) { //bei Model match
              for (let y in DefineDevice[x].common) { //Alle common propertys des models durchgehen und Var zusammensetzen
                  States[DpCount] = { id: praefix0 + "." + did + "." + DefineDevice[x].common[y].name, common: DefineDevice[x].common[y] }; // 
                  DpCount++;
              };
          };
      };
  }
  
  function PrepareGenericDps(did) {  //GenericDps
      // if (logging) log("Reaching PrepareGenericDps(did)");
      for (let y in DefineDevice[0].info) { //Alle info propertys des models durchgehen und Var zusammensetzen
          // log("DefineDevice[0].info[y]=" + JSON.stringify(DefineDevice[0].info[y].common.name))
          States[DpCount] = { id: praefix0 + "." + did + ".info." + DefineDevice[0].info[y].id, common: DefineDevice[0].info[y].common }; // 
          DpCount++;
      };
  }
  
  function CreateStates() {
      if (logging) log("Reaching CreateStates()");
  
      //Alle States anlegen, Main aufrufen wenn fertig
      let numStates = States.length;
      States.forEach(function (state) {
          createState(state.id, state.initial, state.forceCreation, state.common, function () {
              numStates--;
              if (numStates === 0) {
                  if (logging) log(States.length + " States created, now setting up channels!");
                  setObject(praefix0, { type: 'channel', common: { name: "" }, native: {} }); //Root zum Channel machen
                  for (let x = 0; x < AllDevicesRaw.length; x++) {
                      setObject(praefix0 + "." + AllDevicesRaw[x].did, { type: 'device', common: { name: AllDevicesRaw[x].name }, native: {} }); //DeviceChannels machen
                      // if (logging) log("AllDevicesRaw[x]=" +JSON.stringify (AllDevicesRaw[x]))
                  };
                  main();
              };
          });
      });
  }
  
  async function main() {
      if (logging) log("Reaching main");
      await WriteGenericDpValues();
      await CreateDevices();
      CreateDpTrigger();
  }
  
  function WriteGenericDpValues() { //Alle vorhandenen generischen Werte einlesen und in Dps schreiben
      if (logging) log("Reaching WriteGenericDpValues()");
      for (let x in AllDevicesRaw) { //Alle vorhandenen Xiaomi Devices durchgehen
          for (let y in DefineDevice[0].info) { //Nimm ersten Eintrag aus DefineDevices da die Generics bei allen gleich sind
              setState(praefix0 + "." + AllDevicesRaw[x].did + ".info." + DefineDevice[0].info[y].id, AllDevicesRaw[x][DefineDevice[0].info[y].id]);
              // log("DefineDevice[" + 0 + "].info[" + y + "]=" + JSON.stringify(DefineDevice[0].info[y]));
              // log("" + praefix0 + "." + AllDevicesRaw[x].did + ".Info." + DefineDevice[0].info[y].id)
              // log(AllDevicesRaw[x][DefineDevice[0].info[y].id])
          };
      };
      return true;
  }
  
  //################################################
  
  //Step 1 - Einloggen in die Cloud und abrufen aller Gerätedaten, dann vorbereiten der allgemeinen und devicespezifischen Datenpunkte mit anschließendem anlegen derselben
  async function Init() { //Cloudlogin und auslesen der gesamten Clouddaten
      if (logging) log("Reaching init");
  
      mihome.miioProtocol.init();// local miIO
  
      try {// cloud MIoT Login
          await mihome.miCloudProtocol.login(username, password); //Versuch einzuloggen
      }
      catch {
          log("You are already logged in, login canceled"); //Wenn schon eingeloggt
      };
      log("Retrieving your in " + options.country + " registered MiHome Devices");
      AllDevicesRaw = await mihome.miCloudProtocol.getDevices(null, options); //Gibt alle vorhandenen Devices zurück und weist die Werte einem lokalen Array zu
      log("Found " + AllDevicesRaw.length + " MiHome Devices, those are:");
  
      for (let x = 0; x < AllDevicesRaw.length; x++) { //Alle beim User vorhandenen Xiaomi Devices durchgehen
          log(AllDevicesRaw[x].name);
          await PrepareGenericDps(AllDevicesRaw[x].did); //und allgemeine generische Infos Dps vorbereiten
      };
      log("Now searching for supported Devices...");
      let NoDeviceMatch = true;
      for (let x = 0; x < AllDevicesRaw.length; x++) { //Jetzt erneut alle beim User vorhandenen Xiaomi Devices durchgehen
          for (let y = 0; y < DefineDevice.length; y++) { //und abgleichen mit von Skript und node-mihome unterstützten Geräten
              if (AllDevicesRaw[x].model == DefineDevice[y].model) { //Bei match Devicespezifische DPs vorbereiten
                  log("Device " + AllDevicesRaw[x].name + " is supported, creating DataPoints");
                  await PrepareDeviceDps(AllDevicesRaw[x].did, AllDevicesRaw[x].model);
                  NoDeviceMatch = false;
              };
          };
      };
      if (NoDeviceMatch) {
          log("No supported Devices found!", "warn");
      }
      CreateStates();
  }
  
  //################################################
  
  //Step 2 - Deviceobjekte anlegen, Trigger erzeugen und Datenpunktrefresh initieren
  async function CreateDevices() {
      if (logging) log("Reaching CreateDevices ");
      let z = 0;
  
      for (let x in AllDevicesRaw) { //Alle beim User gefundenen Geräte durchlaufen
          for (let y in DefineDevice) { //Alle vom Skript unterstützten und definierten Devices durchlaufen
              if (AllDevicesRaw[x].model == DefineDevice[y].model) { //Wenn die beiden matchen
                  log("Now creating device for " + AllDevicesRaw[x].model + " / " + AllDevicesRaw[x].did + " / " + AllDevicesRaw[x].localip + " / " + AllDevicesRaw[x].token + " / " + refresh);
  
                  device[z] = mihome.device({
                      id: AllDevicesRaw[x].did, // required, device id
                      model: AllDevicesRaw[x].model, // required, device model "zhimi.airpurifier.mb3"
                      address: AllDevicesRaw[x].localip, // miio-device option, local ip address
                      token: AllDevicesRaw[x].token, // miio-device option, device token 4ff8a96292d0451c5148142a0a851e4f
                      refresh: refresh // miio-device option, device properties refresh interval in ms
                  });
                  device[z].model = AllDevicesRaw[x].model;
                  device[z].setter = DefineDevice[y].setter;
                  device[z].definition = DefineDevice[y];
                  device[z].firstrun = true;
                  log("Created device " + JSON.stringify(device[z]) + " now fetching data");
                  await device[z].init(); // connect to device and poll for properties
                  log("Init Device# " + z + " - device=" + JSON.stringify(device[z].model));
                  z++;
              };
          };
      };
  
      for (let i in device) { //Datenabruf zyklisch entsprechend refresh
          log("Setting trigger #" + i + " for " + device[i].model);
          device[i].on('properties', (data) => {
              if (typeof data != "undefined" && data != {}) {
                  if (JSON.stringify(device[i].data) !== JSON.stringify(data)) {//Prüfen ob Datenänderung pro device
                      //if (logging) log(data)
                      if (typeof device[i].data == "undefined") {
                          device[i].data = data;
                      };
                      RefreshDps(i, data);
                  };
              } else {
                  log("Data was empty (undefined), aborting refresh", "warn");
              };
          });
      };
  
      onStop(function () { //Bei Scriptende alle Devices löschen
          for (let x in device) {
              device[x].destroy();
          };
          unsubscribe('properties');
      }, 10);
  }
  
  
  function RefreshDps(DeviceIndex, NewData) {
      // if (logging) log("Reaching RefreshDps at " + device[DeviceIndex].definition.description);
  
      for (let x in device[DeviceIndex].data) { //Alle properties des Devices durchgehen
          for (let i in NewData) {//Alle properties des Datenblocks durchgehen
              if ((NewData[i] !== device[DeviceIndex].data[x] || device[DeviceIndex].firstrun == true) && i === x) { //Überprüfen ob Datenänderung im property bei propertymatch, firstrun immer refreshen
  
                  if (logging) log("New Data at " + device[DeviceIndex].model + " " + i + " oldvalue=" + device[DeviceIndex].data[x] + " newvalue=" + NewData[i] + " path=" + praefix0 + "." + device[DeviceIndex].id + "." + CorrectChannelId(x));
                  device[DeviceIndex].data[x] = NewData[i]; //Geänderten Wert ins Objekt schreiben
  
                  for (let y in device[DeviceIndex].definition.common) { //Alle Definitionsproperties durchgehen um ChannelId zu suchen
                      if (device[DeviceIndex].definition.common[y].name == CorrectChannelId(x)) { //Wenn match
                          if (typeof device[DeviceIndex].data[x] == 'undefined' || typeof device[DeviceIndex].id == 'undefined') { //Wenn kein Pfad oder keine Daten
                              log("Empty packet for " + device[DeviceIndex].definition.common[y].name + ", skipping refresh", 'warn');
                              //return false;
                          } else {
                              //Prüfung auf bestimmte keys
                              switch (device[DeviceIndex].definition.common[y].name) {
                                  case 'temp_dec': //Umwandlung von 10tel Grad auf Grad beim Dp schreiben. data muß unverändert bleiben da im Trigger mit origdaten abgeglichen wird
                                      setState(praefix0 + "." + device[DeviceIndex].id + "." + CorrectChannelId(x), parseInt(device[DeviceIndex].data[x]) / 10, true);
                                      break;
                                  default: //Wenn kein Treffer jetzt Prüfung auf bestimmte Daten
                                      switch (device[DeviceIndex].data[x]) {
                                          case 'on':
                                              setState(praefix0 + "." + device[DeviceIndex].id + "." + CorrectChannelId(x), true, true);
                                              break;
                                          case 'off':
                                              setState(praefix0 + "." + device[DeviceIndex].id + "." + CorrectChannelId(x), false, true);
                                              break;
                                          default:
                                              setState(praefix0 + "." + device[DeviceIndex].id + "." + CorrectChannelId(x), device[DeviceIndex].data[x], true);
                                      };
                              };
                          };
                          if (logging) log("Refreshing " + praefix0 + "." + device[DeviceIndex].id + "." + CorrectChannelId(x) + " / value=" + device[DeviceIndex].data[x] + " / read=" + device[DeviceIndex].definition.common[y].read + " write=" + device[DeviceIndex].definition.common[y].write);
                      };
                  };
              };
          };
      };
      device[DeviceIndex].firstrun = false;
      //if (logging) log(DeviceData[DeviceIndex])
      return true;
  }
  
  async function SetDevice(i, key, keyvalue) {
      if (logging) log("Reaching SetDevice - i=" + i + " key=" + key + " keyvalue=" + keyvalue);
      if (device[i].definition.common[key].name == 'rgb') { //Block wandelt Farb Hewwerte in Dezimalwert um
          keyvalue = ConvertHexToDezi(keyvalue);
          keyvalue = String(keyvalue);
      }
      if (device[i].definition.common[key].name == 'hue') { //Block kombiniert bei Änderungen von hue oder sat jweils die beiden Werte zu Array für übergabe an Funktion
          keyvalue = [keyvalue, device[i].data['sat']];
      } else if (device[i].definition.common[key].name == 'sat') {
          keyvalue = [device[i].data['hue'], keyvalue];
          for (let x in device[i].definition.common) {
              if (device[i].definition.common[x].name == 'hue') {
                  key = x;
              };
          };
      };
      log("Keyvalue=" + keyvalue + " key=" + key)
      if (logging) log("Reaching SetDevice i=" + i);
      // log("Setting Device " + device[i].model + " to value " + keyvalue + " at " + device[i].definition.common[key].name)
      // log("Setting Device " + device[i].model + " to value " + keyvalue + " at " + device[i].setter[device[i].definition.common[key].name])
      log(device[i].setter[device[i].definition.common[key].name](i, keyvalue)); //Diese Zeile nicht entfernen, Funktionsaufruf!!!
  }
  
  function CreateDpTrigger() {
      if (logging) log("Reaching CreateDpTrigger");
  
      for (let i in device) {
          if (logging) log("Setting DataPointTrigger #" + i + " for " + device[i].model);
  
          for (let x in device[i].definition.common) { //Alle properties der Devicedefinition durchgehen
              if (device[i].definition.common[x].write) {
                  //  log(praefix0 + "." + device[i].id + "." + device[i].definition.common[x].name)
                  on({ id: praefix0 + "." + device[i].id + "." + device[i].definition.common[x].name, change: "ne", ack: false }, function (dp) { //Bei Statusänderung
                      if (logging) log("Triggered i=" + i + " x=" + x + " ack=" + dp.state.ack);
                      SetDevice(i, x, dp.state.val);
                  });
                  if (logging) log("Setting Datapoint Trigger for " + praefix0 + "." + device[i].id + "." + device[i].definition.common[x].name + " / read=" + device[i].definition.common[x].read + " write=" + device[i].definition.common[x].write);
              } else {
                  if (logging) log("No Datapoint Trigger set for " + device[i].definition.common[x].name + " because its readonly.");
              };
          };
      };
  }
  
  //***************** U T I L S *********************** */
  
  function CorrectChannelId(cid) { //Erzeugt eine iobroker taugliche channelid. Punkte werden zu unterstrichen gewandelt, Doppelpunkte zu Punkten
      let temp = cid;
      if (typeof temp == "object") {
          temp = JSON.stringify(cid);
      };
      cid = temp.replace(".", '_'); //Erstmal alle potentiellen Punkte im channelnamen entfernen
      temp = cid.replace(/:/g, "."); //Jetzt alle Doppelpunkte durch Punkte ersetzen
      return temp;
  }
  
  function ConvertDeziToHex(DeziValue) {
      DeziValue = toInt(DeziValue)
      //log(typeof DeziValue)
      if (typeof DeziValue == "number") {
          return "#" + DeziValue.toString(16)
      };
  }
  
  function ConvertHexToDezi(HexValue) {
  
      if (typeof HexValue == "string") {
          if (HexValue.indexOf('#') != -1) {
              HexValue = HexValue.substr(1).toLowerCase()
          } else {
              HexValue = HexValue.toLowerCase()
          };
      };
  
      var i, j, digits = [0], carry;
      for (i = 0; i < HexValue.length; i += 1) {
          carry = parseInt(HexValue.charAt(i), 16);
          for (j = 0; j < digits.length; j += 1) {
              digits[j] = digits[j] * 16 + carry;
              carry = digits[j] / 10 | 0;
              digits[j] %= 10;
          }
          while (carry > 0) {
              digits.push(carry % 10);
              carry = carry / 10 | 0;
          }
      }
      return digits.reverse().join('');
  }
  
  /*
   * Converts an RGB color value to HSL. Conversion formula
   * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
   * Assumes r, g, and b are contained in the set [0, 255] and
   * returns h, s, and l in the set [0, 1].
   *
   * @param   {number}  r       The red color value
   * @param   {number}  g       The green color value
   * @param   {number}  b       The blue color value
   * @return  {Array}           The HSL representation
   */
  function rgbToHsl(hex) {
      var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  
      var r = parseInt(result[1], 16);
      var g = parseInt(result[2], 16);
      var b = parseInt(result[3], 16);
  
      r /= 255, g /= 255, b /= 255;
      var max = Math.max(r, g, b),
          min = Math.min(r, g, b);
      var h, s, l = (max + min) / 2;
  
      if (max == min) {
          h = s = 0; // achromatic
      } else {
          var d = max - min;
          s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
          switch (max) {
              case r:
                  h = (g - b) / d + (g < b ? 6 : 0);
                  break;
              case g:
                  h = (b - r) / d + 2;
                  break;
              case b:
                  h = (r - g) / d + 4;
                  break;
          }
          h /= 6;
      }
  
      return [Math.round(h * 360), Math.round(s * 100)];
  }
  
  
  