Skip to content
  • 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
  1. ioBroker Community Home
  2. Deutsch
  3. Tester
  4. Test Dreame Home Adapter

NEWS

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    8.2k

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    13
    1
    1.9k

  • Neues Video "KI im Smart Home" - ioBroker plus n8n
    BluefoxB
    Bluefox
    15
    1
    2.2k

Test Dreame Home Adapter

Geplant Angeheftet Gesperrt Verschoben Tester
241 Beiträge 39 Kommentatoren 49.0k Aufrufe 44 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.
  • wawyoW wawyo

    @michael-ladstätter Ich habe festgestellt, dass beim Kopieren des Codes auf die Plattform einige Teile des Codes unterhalb der Zeile 917 gelöscht wurden. Dies hat zu Problemen bei der Ausführung des Codes geführt.

    Um sicherzustellen, dass der Code korrekt funktioniert, habe ich den vollständigen und funktionierenden Code bereitgestellt. Bitte lade den folgenden Code herunter und ersetze die beschädigte Version auf der Plattform 😉 Download; main.js

    Michael LadstätterM Offline
    Michael LadstätterM Offline
    Michael Ladstätter
    schrieb am zuletzt editiert von
    #28

    @wawyo

    Super danke hat ohne Probleme funktioniert 😄

    wawyoW 1 Antwort Letzte Antwort
    0
    • Michael LadstätterM Michael Ladstätter

      @wawyo

      Super danke hat ohne Probleme funktioniert 😄

      wawyoW Offline
      wawyoW Offline
      wawyo
      Developer
      schrieb am zuletzt editiert von
      #29

      @michael-ladstätter Super 😉

      ich benötige jetzt Unterstützung von Beobachtern und Analysten, um unser Ziel zu erreichen: eine Karte aus den Koordinaten zu erstellen. Der Prozess gestaltet sich als komplex, und ich kann mir vorstellen, dass im dekomprimierten Code möglicherweise weitere wertvolle Daten enthalten sind. Es wäre eine Verschwendung, nur die Header zu entfernen, um an die JSON-Daten zu gelangen, ohne das gesamte Potenzial der Daten zu nutzen.

      Der aktuelle Stand ist folgender:

      1. Die Dekompression des Codes hat möglicherweise zusätzliche Daten ans Licht gebracht, die für unser Projekt nützlich sein könnten.
      2. Das bloße Entfernen der Header könnte uns wichtige Informationen vorenthalten, die wir für eine umfassende Analyse und das Erstellen der Karte benötigen.

      Da ich alleine Schwierigkeiten habe, alle relevanten Informationen aus dem Code zu extrahieren und die Daten vollständig zu verstehen, würde ich mich über eure Unterstützung sehr freuen. Eure Hilfe beim Beobachten und Analysieren der Daten wäre sehr wertvoll, um unser Ziel effizient zu erreichen.

      1 Antwort Letzte Antwort
      0
      • wawyoW wawyo

        Hallo zusammen,
        ich habe mich intensiv mit dem Adapter beschäftigt, da mich der "dreame.0..status.map-data" Objekt interessiert hat. Dabei konnte ich den Adapter so anpassen, dass ich neue Baum-Objekte hinzufügen konnte (dreame.0..map) . Dies ermöglichte es mir, eine Fülle von Daten über die Position des Saugroboters (L20) zu sammeln. Es scheint, als ob noch viele weitere Daten vorhanden sind. Unter "Clean Set" sind alle Räume mit den entsprechenden Einstellungen vorhanden.

        Um das Ziel zu erreichen, den Saugroboter in Echtzeit zu verfolgen, benötige ich nun Unterstützung von weiteren Personen. Unten finden Sie den modifizierten Code für eine detaillierte Ansicht.
        DreameMap.png

        'use strict';
        
        /*
         * Created with @iobroker/create-adapter v2.6.3
         */
        
        // The adapter-core module gives you access to the core ioBroker functions
        // you need to create an adapter
        const utils = require('@iobroker/adapter-core');
        const axios = require('axios').default;
        const Json2iob = require('json2iob');
        const crypto = require('crypto');
        const mqtt = require('mqtt');
        const zlib = require("node:zlib");
        
        class Dreame extends utils.Adapter {
          /**
           * @param {Partial<utils.AdapterOptions>} [options={}]
           */
          constructor(options) {
            super({
              ...options,
              name: 'dreame',
            });
            this.on('ready', this.onReady.bind(this));
            this.on('stateChange', this.onStateChange.bind(this));
            this.on('unload', this.onUnload.bind(this));
            this.deviceArray = [];
            this.states = {};
            this.json2iob = new Json2iob(this);
            this.requestClient = axios.create({
              withCredentials: true,
              timeout: 3 * 60 * 1000, //3min client timeout
            });
        
            this.remoteCommands = {};
            this.specStatusDict = {};
            this.specPropsToIdDict = {};
            this.specActiosnToIdDict = {};
          }
        
          /**
           * Is called when databases are connected and adapter received configuration.
           */
          async onReady() {
            this.setState('info.connection', false, true);
            if (this.config.interval < 0.5) {
              this.log.info('Set interval to minimum 0.5');
              this.config.interval = 0.5;
            }
            if (this.config.interval > 2147483647) {
              this.log.info('Set interval to maximum 2147483647');
              this.config.interval = 2147483647;
            }
            if (!this.config.username || !this.config.password) {
              this.log.error('Please set username and password in the instance settings');
              return;
            }
        
            this.updateInterval = null;
            this.reLoginTimeout = null;
            this.refreshTokenTimeout = null;
            this.session = {};
            this.subscribeStates('*.remote.*');
        
            this.log.info('Login to Dreame Cloud...');
            await this.login();
        
            if (this.session.access_token) {
              await this.getDeviceList();
              await this.fetchSpecs();
              await this.createRemotes();
              await this.updateDevicesViaSpec();
              await this.connectMqtt();
              this.updateInterval = setInterval(
                async () => {
                  await this.updateDevicesViaSpec();
                },
                this.config.interval * 60 * 1000,
              );
              this.refreshTokenInterval = setInterval(
                async () => {
                  await this.refreshToken();
                },
                (this.session.expires_in - 100 || 3500) * 1000,
              );
            }
          }
        
          async login() {
            await this.requestClient({
              method: 'post',
              url: 'https://eu.iot.dreame.tech:13267/dreame-auth/oauth/token',
              headers: {
                'user-agent': 'Dart/3.2 (dart:io)',
                'dreame-meta': 'cv=i_829',
                'dreame-rlc': '1a9bb36e6b22617cf465363ba7c232fb131899d593e8d1a1-1',
                'tenant-id': '000000',
                host: 'eu.iot.dreame.tech:13267',
                authorization: 'Basic ZHJlYW1lX2FwcHYxOkFQXmR2QHpAU1FZVnhOODg=',
                'content-type': 'application/x-www-form-urlencoded',
                'dreame-auth': 'bearer',
              },
              data: {
                grant_type: 'password',
                scope: 'all',
                platform: 'IOS',
                type: 'account',
                username: this.config.username,
                password: crypto
                  .createHash('md5')
                  .update(this.config.password + 'RAylYC%fmSKp7%Tq')
                  .digest('hex'),
                country: 'DE',
                lang: 'de',
              },
            })
              .then((response) => {
                this.log.debug('Login response: ' + JSON.stringify(response.data));
                this.session = response.data;
                this.setState('info.connection', true, true);
              })
              .catch((error) => {
                this.log.error('Login error: ' + error);
                error.response && this.log.error('Login error response: ' + JSON.stringify(error.response.data));
                this.setState('info.connection', false, true);
              });
          }
          async getDeviceList() {
            await this.requestClient({
              method: 'post',
              maxBodyLength: Infinity,
              url: 'https://eu.iot.dreame.tech:13267/dreame-user-iot/iotuserbind/device/listV2',
              headers: {
                'user-agent': 'Dart/3.2 (dart:io)',
                'dreame-meta': 'cv=i_829',
                'dreame-rlc': '1a9bb36e6b22617cf465363ba7c232fb131899d593e8d1a1-1',
                'tenant-id': '000000',
                host: 'eu.iot.dreame.tech:13267',
                authorization: 'Basic ZHJlYW1lX2FwcHYxOkFQXmR2QHpAU1FZVnhOODg=',
                'content-type': 'application/json',
                'dreame-auth': 'bearer ' + this.session.access_token,
              },
              data: {
                sharedStatus: 1,
                current: 1,
                size: 100,
                lang: 'de',
                timestamp: Date.now(),
              },
            })
              .then(async (response) => {
                /*
                example response:
                {
            "code": 0,
            "success": true,
            "data": {
                "page": {
                    "records": [
                        {
                            "id": "xxx",
                            "did": "xxxx",
                            "model": "dreame.vacuum.r2449k",
                            "ver": "4.3.9_1252",
                            "customName": "",
                            "property": "{\"iotId\":\"xxxxxxxx\",\"lwt\":1,\"mac\":\"\"}",
                            "mac": "7",
                            "vendor": "ali",
                            "master": true,
                            "masterUid": "",
                            "masterUid2UUID": null,
                            "masterName": null,
                            "permissions": "",
                            "bindDomain": "10000.mt.eu.iot.dreame.tech:19973",
                            "sharedTimes": 0,
                            "sharedStatus": 1,
                            "calltag": null,
                            "updateTime": "2024-06-07 12:03:09",
                            "lang": null,
                            "deviceInfo": {
                                "productId": "10279",
                                "categoryPath": "/lifeapps/vacuum",
                                "model": "dreame.vacuum.r2449k",
                                "remark": "",
                                "feature": "video_ali,fastCommand",
                                "videoDynamicVendor": true,
                                "defaultVendors": [
                                    "ali"
                                ],
                                "scType": "WIFI",
                                "extendScType": [
                                    "QR_CODE"
                                ],
                                "status": "Live",
                                "mainImage": {
                                    "as": "1",
                                    "caption": "1",
                                    "height": 0,
                                    "width": 0,
                                    "imageUrl": "https://oss.iot.dreame.tech/pub/pic/000000/ali_dreame/dreame.vacuum.r2449k/9acf24adb5ca3d15341fd869f2aa985f20240311084500.png",
                                    "smallImageUrl": ""
                                },
                                "popup": {
                                    "as": "1",
                                    "caption": "1",
                                    "height": 0,
                                    "width": 0,
                                    "imageUrl": "https://oss.iot.dreame.tech/pub/pic/000000/ali_dreame/dreame.vacuum.r2449k/9acf24adb5ca3d15341fd869f2aa985f20240311084500.png",
                                    "smallImageUrl": ""
                                },
                                "icon": {
                                    "as": "1",
                                    "caption": "1",
                                    "height": 0,
                                    "width": 0,
                                    "imageUrl": "https://oss.iot.dreame.tech/pub/pic/000000/ali_dreame/dreame.vacuum.r2449k/9acf24adb5ca3d15341fd869f2aa985f20240311084500.png",
                                    "smallImageUrl": ""
                                },
                                "overlook": {
                                    "as": "1",
                                    "caption": "1",
                                    "height": 0,
                                    "width": 0,
                                    "imageUrl": "https://oss.iot.dreame.tech/pub/pic/000000/ali_dreame/dreame.vacuum.r2449k/9acf24adb5ca3d15341fd869f2aa985f20240311084500.png",
                                    "smallImageUrl": ""
                                },
                                "images": [],
                                "extensionId": "1228",
                                "updatedAt": "1711721850712",
                                "createdAt": "1705565151025",
                                "releaseAt": "1710848634605",
                                "quickConnectStatus": -1,
                                "quickConnects": {},
                                "permit": "video",
                                "firmwareDevelopType": "SINGLE_PLATFORM",
                                "bindType": "",
                                "displayName": "X40 Ultra Complete",
                                "liveKeyDefine": {},
                                "qaKeyDefine": {}
                            },
                            "online": true,
                            "latestStatus": 21,
                            "battery": 100,
                            "videoStatus": "{\"operType\":\"end\",\"operation\":\"monitor\",\"result\":0,\"status\":0}",
                            "region": null,
                            "featureCode": -1,
                            "featureCode2": 31,
                            "keyDefine": {
                                "ver": 1,
                                "url": "https://cnbj2.fds.api.xiaomi.com/000000-public/file/54587b0364cdd763deba93a974ef5aa05cbe7dcc_dreame.vacuum.r2449k_iotKeyValue_translate_1.json"
                            }
                        }
                    ],
                    "total": "1",
                    "size": "100",
                    "current": "1",
                    "orders": [],
                    "optimizeCountSql": true,
                    "hitCount": false,
                    "searchCount": true,
                    "pages": "1"
                }
            },
            "msg": "操作成功"
        }
                */
                this.log.debug('Device list response: ' + JSON.stringify(response.data));
        
                if (
                  response.data.code == '0' &&
                  response.data &&
                  response.data.data &&
                  response.data.data.page &&
                  response.data.data.page.records
                ) {
                  this.deviceArray = response.data.data.page.records;
                  for (const device of this.deviceArray) {
                    await this.extendObject(device.did, {
                      type: 'device',
                      common: {
                        name: device.customName || device.deviceInfo.displayName || device.model,
                      },
                      native: {},
                    });
                    if (device.keyDefine) {
                      const iotKeyValue = await this.requestClient({
                        method: 'get',
                        url: device.keyDefine.url,
                      })
                        .then((response) => {
                          this.log.debug('iotKeyValue response: ' + JSON.stringify(response.data));
                          return response.data;
                        })
                        .catch((error) => {
                          this.log.error('iotKeyValue error: ' + error);
                          error.response &&
                            this.log.error('iotKeyValue error response: ' + JSON.stringify(error.response.data));
                        });
                      /*{
                    "keyDefine": {
                      "2.1": {
                        "de": {
                          "1": "Reinigung"}},
                    "ver": 1,
                    "model": "dreame.vacuum.r2449k",
                    "hash": "54587b0364cdd763deba93a974ef5aa05cbe7dcc"
                  }*/
        
                      if (iotKeyValue && iotKeyValue.keyDefine) {
                        //replace dot in id with - and select en language
        
                        for (const key in iotKeyValue.keyDefine) {
                          if (Object.hasOwnProperty.call(iotKeyValue.keyDefine, key)) {
                            const element = iotKeyValue.keyDefine[key];
                            if (element['en'] && element['en'] !== 'null') {
                              this.states[device.did][key.replace(/\./g, '-')] = element['en'];
                            }
                          }
                        }
                      }
                    }
                    this.json2iob.parse(device.did + '.general', device, {
                      states: { latestStatus: this.states[device.did] },
                      channelName: 'General Updated at Start',
                    });
                  }
                } else {
                  this.log.error('No Devices found: ' + JSON.stringify(response.data));
                }
              })
              .catch((error) => {
                this.log.error('Device list error: ' + error);
                error.response && this.log.error('Device list error response: ' + JSON.stringify(error.response.data));
              });
          }
        
          async fetchSpecs() {
            this.log.info('Fetching Specs');
            const allDevices = await this.requestClient({
              url: 'https://miot-spec.org/miot-spec-v2/instances?status=all',
            }).catch((error) => {
              this.log.error('failing to get all devices');
              this.log.error(error);
              error.response && this.log.error(JSON.stringify(error.response.data));
            });
        
            const specs = [];
            for (const device of this.deviceArray) {
              const type = allDevices.data.instances
                .filter((obj) => {
                  return obj.model === device.model && obj.status === 'released';
                })
                .map((obj) => {
                  return obj.type;
                });
              if (type.length === 0) {
                this.log.info(`No spec found for ${device.model} set to default spec type`);
                type[0] = 'urn:miot-spec-v2:device:vacuum:0000A006:dreame-r2320:1';
              }
              device.spec_type = type[0];
              specs.push(type[0]);
            }
            await this.requestClient({
              method: 'post',
              url: 'https://miot-spec.org/miot-spec-v2/instance',
              data: {
                urns: specs,
              },
            })
              .then(async (res) => {
                this.specs = res.data;
              })
              .catch((error) => {
                this.log.error(error);
                error.response && this.log.error(JSON.stringify(error.response.data));
              });
          }
          async createRemotes() {
            for (const device of this.deviceArray) {
              if (this.specs[device.spec_type]) {
                this.log.debug(JSON.stringify(this.specs[device.spec_type]));
                await this.extractRemotesFromSpec(device);
              }
              const remoteArray = this.remoteCommands[device.model] || [];
              for (const remote of remoteArray) {
                await this.extendObject(device.did + '.remotePlugins', {
                  type: 'channel',
                  common: {
                    name: 'Remote Controls extracted from Plugin definition',
                    desc: 'Not so reliable alternative remotes',
                  },
                  native: {},
                });
                this.setObjectNotExists(device.did + '.remotePlugins.customCommand', {
                  type: 'state',
                  common: {
                    name: 'Send Custom command via Plugin',
                    type: 'mixed',
                    role: 'state',
                    def: 'set_level_favorite,16',
                    write: true,
                    read: true,
                  },
                  native: {},
                });
                let name = remote;
                let params = '';
                if (typeof remote === 'object') {
                  name = remote.type;
                  params = remote.params;
                }
                try {
                  this.setObjectNotExists(device.did + '.remotePlugins.' + name, {
                    type: 'state',
                    common: {
                      name: name + ' ' + params || '',
                      type: 'mixed',
                      role: 'state',
                      def: false,
                      write: true,
                      read: true,
                    },
                    native: {},
                  });
                } catch (error) {
                  this.log.error(error);
                }
              }
            }
          }
          async extractRemotesFromSpec(device) {
            const spec = this.specs[device.spec_type];
            this.log.info(`Extracting remotes from spec for ${device.model} ${spec.description}`);
            this.log.info(
              'You can detailed information about status and remotes here: http://www.merdok.org/miotspec/?model=' +
                device.model,
            );
            let siid = 0;
            this.specStatusDict[device.did] = [];
        
            this.specActiosnToIdDict[device.did] = {};
            this.specPropsToIdDict[device.did] = {};
            for (const service of spec.services) {
              if (service.iid) {
                siid = service.iid;
              } else {
                siid++;
              }
              const typeArray = service.type.split(':');
              if (typeArray[3] === 'device-information') {
                continue;
              }
              if (!service.properties) {
                this.log.warn(`No properties for ${device.model} ${service.description} cannot extract information`);
                continue;
              }
        
              try {
                let piid = 0;
                for (const property of service.properties) {
                  if (property.iid) {
                    piid = property.iid;
                  } else {
                    piid++;
                  }
                  const remote = {
                    siid: siid,
                    piid: piid,
                    did: device.did,
                    model: device.model,
                    name: service.description + ' ' + property.description + ' ' + service.iid + '-' + property.iid,
                    type: property.type,
                    access: property.access,
                  };
                  const typeName = property.type.split(':')[3];
                  let path = 'status';
                  let write = false;
        
                  if (property.access.includes('write')) {
                    path = 'remote';
                    write = true;
                  }
        
                  const [type, role] = this.getRole(property.format, write, property['value-range']);
                  this.log.debug(`Found remote for ${device.model} ${service.description} ${property.description}`);
        
                  await this.extendObject(device.did + '.' + path, {
                    type: 'channel',
                    common: {
                      name: path + ' extracted from Spec definition',
                    },
                    native: {},
                  });
                  if (path === 'remote') {
                    await this.extendObject(device.did + '.' + path + '.customCommand', {
                      type: 'state',
                      common: {
                        name: 'Send Custom command via Spec',
                        type: 'string',
                        role: 'json',
                        def: `{
                    "aiid": 9,
                    "in": [
                        {
                            "order": 4,
                            "region": [
                                1
                            ],
                            "type": "order"
                        }
                    ],
                    "siid": 5
                }`,
                        write: true,
                        read: true,
                      },
                      native: {},
                    });
                  }
                  const states = {};
                  if (property['value-list']) {
                    for (const value of property['value-list']) {
                      states[value.value] = value.description;
                    }
                  }
                  let unit;
                  if (property.unit && property.unit !== 'none') {
                    unit = property.unit;
                  }
                  await this.extendObject(device.did + '.' + path + '.' + typeName, {
                    type: 'state',
                    common: {
                      name: remote.name || '',
                      type: type,
                      role: role,
                      unit: unit,
                      min: property['value-range'] ? property['value-range'][0] : undefined,
                      max: property['value-range'] ? property['value-range'][1] : undefined,
                      states: property['value-list'] ? states : undefined,
                      write: write,
                      read: true,
                    },
                    native: {
                      siid: siid,
                      piid: piid,
                      did: device.did,
                      model: device.model,
                      name: service.description + ' ' + property.description,
                      type: property.type,
                      access: property.access,
                    },
                  });
        
                  if (property.access.includes('notify')) {
                    this.specStatusDict[device.did].push({
                      did: device.did,
                      siid: remote.siid,
                      code: 0,
                      piid: remote.piid,
                      updateTime: 0,
                    });
                  }
                  this.specPropsToIdDict[device.did][remote.siid + '-' + remote.piid] =
                    device.did + '.' + path + '.' + typeName;
                }
                //extract actions
                let aiid = 0;
                if (service.actions) {
                  for (const action of service.actions) {
                    if (action.iid) {
                      aiid = action.iid;
                    } else {
                      aiid++;
                    }
                    const remote = {
                      siid: siid,
                      aiid: aiid,
                      did: device.did,
                      model: device.model,
                      name: service.description + ' ' + action.description + ' ' + service.iid + '-' + action.iid,
                      type: action.type,
                      access: action.access,
                    };
                    const typeName = action.type.split(':')[3];
        
                    const path = 'remote';
                    const write = true;
        
                    let [type, role] = this.getRole(action.format, write, action['value-range']);
                    this.log.debug(`Found actions for ${device.model} ${service.description} ${action.description}`);
        
                    await this.extendObject(device.did + '.' + path, {
                      type: 'channel',
                      common: {
                        name: 'Remote Controls extracted from Spec definition',
                      },
                      native: {},
                    });
                    const states = {};
                    if (action['value-list']) {
                      for (const value of action['value-list']) {
                        states[value.value] = value.description;
                      }
                    }
                    let def = '[]';
                    if (action.in.length) {
                      remote.name = remote.name + ' in[';
        
                      for (const inParam of action.in) {
                        type = 'string';
                        role = 'text';
                        def = JSON.stringify(action.in);
                        const prop = service.properties.filter((obj) => {
                          return obj.iid === inParam;
                        });
                        if (prop.length > 0) {
                          remote.name = remote.name + prop[0].description + '';
                        }
                        if (action.in.indexOf(inParam) !== action.in.length - 1) {
                          remote.name = remote.name + ',';
                        }
                      }
        
                      remote.name = remote.name + ']';
                    }
        
                    if (action.out.length) {
                      remote.name = remote.name + ' out[';
        
                      for (const outParam of action.out) {
                        const prop = service.properties.filter((obj) => {
                          return obj.iid === outParam;
                        });
                        if (prop.length > 0) {
                          remote.name = remote.name + prop[0].description;
                        }
                        if (action.out.indexOf(outParam) !== action.out.length - 1) {
                          remote.name = remote.name + ',';
                        }
                      }
                      remote.name = remote.name + ']';
                    }
                    let unit;
                    if (action.unit && action.unit !== 'none') {
                      unit = action.unit;
                    }
                    await this.extendObject(device.did + '.' + path + '.' + typeName, {
                      type: 'state',
                      common: {
                        name: remote.name || '',
                        type: type,
                        role: role,
                        unit: unit,
                        min: action['value-range'] ? action['value-range'][0] : undefined,
                        max: action['value-range'] ? action['value-range'][1] : undefined,
                        states: action['value-list'] ? states : undefined,
                        write: write,
                        read: true,
                        def: def != null ? def : undefined,
                      },
                      native: {
                        siid: siid,
                        aiid: aiid,
                        did: device.did,
                        model: device.model,
                        in: action.in,
                        out: action.out,
                        name: service.description + ' ' + action.description,
                        type: action.type,
                        access: action.access,
                      },
                    });
                    this.specActiosnToIdDict[device.did][service.iid + '-' + action.iid] =
                      device.did + '.' + path + '.' + typeName;
                  }
                }
              } catch (error) {
                this.log.error('Error while extracting spec for ' + device.model);
                this.log.error(error);
                this.log.error(error.stack);
                this.log.info(JSON.stringify(service));
              }
            }
          }
          async updateDevicesViaSpec() {
            for (const device of this.deviceArray) {
              if (this.specStatusDict[device.did]) {
                //split array in chunks of 50
                const chunkSize = 50;
                for (let i = 0; i < this.specStatusDict[device.did].length; i += chunkSize) {
                  const chunk = this.specStatusDict[device.did].slice(i, i + chunkSize);
        
                  const requestId = Math.floor(Math.random() * 9000) + 1000;
                  const data = {
                    did: device.did,
                    id: requestId,
                    data: {
                      did: device.did,
                      id: requestId,
                      method: 'get_properties',
                      params: chunk,
                      from: 'XXXXXX',
                    },
                  };
                  await this.requestClient({
                    method: 'post',
                    url: 'https://eu.iot.dreame.tech:13267/dreame-iot-com-10000/device/sendCommand',
                    headers: {
                      'user-agent': 'Dart/3.2 (dart:io)',
                      'dreame-meta': 'cv=i_829',
                      'dreame-rlc': '1a9bb36e6b22617cf465363ba7c232fb131899d593e8d1a1-1',
                      'tenant-id': '000000',
                      host: 'eu.iot.dreame.tech:13267',
                      authorization: 'Basic ZHJlYW1lX2FwcHYxOkFQXmR2QHpAU1FZVnhOODg=',
                      'content-type': 'application/json',
                      'dreame-auth': 'bearer ' + this.session.access_token,
                    },
                    data: data,
                  })
                    .then(async (res) => {
                      if (res.data.code !== 0) {
                        if (res.data.code === -8) {
                          this.log.debug(
                            `Error getting spec update for ${device.name} (${device.did}) with ${JSON.stringify(data)}`,
                          );
        
                          this.log.debug(JSON.stringify(res.data));
                          return;
                        }
                        this.log.info(
                          `Error getting spec update for ${device.name} (${device.did}) with ${JSON.stringify(data)}`,
                        );
                        this.log.debug(JSON.stringify(res.data));
                        return;
                      }
                      this.log.debug(JSON.stringify(res.data));
                      for (const element of res.data.data.result) {
                        const path = this.specPropsToIdDict[device.did][element.siid + '-' + element.piid];
        				  this.log.info(' Update: ' + path);
                        if (path) {
                          this.log.debug(`Set ${path} to ${element.value}`);
                          if (element.value != null) {
                            this.setState(path, element.value, true);
                          }
                        }
                      }
                    })
                    .catch((error) => {
                      if (error.response) {
                        if (error.response.status === 401) {
                          error.response && this.log.debug(JSON.stringify(error.response.data));
                          this.log.info(' receive 401 error. Refresh Token in 60 seconds');
                          this.refreshTokenTimeout && clearTimeout(this.refreshTokenTimeout);
                          this.refreshTokenTimeout = setTimeout(() => {
                            this.refreshToken();
                          }, 1000 * 60);
        
                          return;
                        }
        
                        this.log.error(error);
                        error.stack && this.log.error(error.stack);
                        error.response && this.log.error(JSON.stringify(error.response.data));
                        return;
                      }
        
                      this.log.debug(error);
                      this.log.debug(JSON.stringify(error));
                    });
                }
              }
            }
          }
          getRole(element, write, valueRange) {
            if (!element) {
              return ['string', 'json'];
            }
            if (element === 'bool' && !write) {
              return ['boolean', 'indicator'];
            }
            if (element === 'bool' && write) {
              return ['boolean', 'switch'];
            }
            if ((element.indexOf('int') !== -1 || valueRange) && !write) {
              return ['number', 'value'];
            }
            if ((element.indexOf('int') !== -1 || valueRange) && write) {
              return ['number', 'level'];
            }
        
            return ['string', 'text'];
          }
          async connectMqtt() {
            if (this.mqttClient) {
              this.mqttClient.end();
            }
            const url = this.deviceArray[0].bindDomain || 'app.mt.eu.iot.dreame.tech:19973';
            this.mqttClient = mqtt.connect('mqtts://' + url, {
              clientId: 'p_' + crypto.randomBytes(8).toString('hex'),
              username: this.session.uid,
              password: this.session.access_token,
              rejectUnauthorized: false,
              reconnectPeriod: 10000,
            });
        
            this.mqttClient.on('connect', () => {
              this.log.info('Connected to MQTT');
              for (const device of this.deviceArray) {
                this.mqttClient.subscribe(`/status/${device.did}/${this.session.uid}/${device.model}/eu/`);
              }
            });
            this.mqttClient.on('message', async (topic, message) => {
              // message is Buffer
              this.log.debug(topic.toString());
              this.log.debug(message.toString());
              /*
              {"id":92,"did":XXXXXX,"data":{"id":92,"method":"properties_changed","params":[{"did":"XXXXX","siid":2,"piid":6,"value":1},{"did":"XXXXX","siid":4,"piid":23,"value":5121}]}}
              */
              try {
                message = JSON.parse(message.toString());
        		  	//this.log.info(' Get Message:' + JSON.stringify(message));
              } catch (error) {
                this.log.error(error);
                return;
              }
              if (message.data && message.data.method === 'properties_changed') {
        
                for (const element of message.data.params) {
                  if (!this.specPropsToIdDict[element.did]) {
                    this.log.debug(`No spec found for ${element.did}`);
                    continue;
                  }
        
        		  if (JSON.stringify(element.siid) === '6' && JSON.stringify(element.piid) === '1') {
        		     this.log.info(' Map data:' + JSON.stringify(element.value));
        			  let encode = JSON.stringify(element.value);
        			  let mappath = `${element.did}` + '.map.';
        			  this.uncompress(encode, mappath);
        		  }
        		  //this.log.info(' Map data:' + JSON.stringify(element.siid) + ' => ' + JSON.stringify(element.piid));
        
                  let path = this.specPropsToIdDict[element.did][element.siid + '-' + element.piid];
                  if (!path) {
                    this.log.debug(`No path found for ${element.did} ${element.siid}-${element.piid}`);
        
                    path = `${element.did}.status.${element.siid}-${element.piid}`;
        
                    await this.extendObject(path, {
                      type: 'state',
                      common: {
                        name: path,
                        type: 'mixed',
                        role: 'state',
                        write: false,
                        read: true,
                      },
                      native: {},
                    });
                    this.setState(path, JSON.stringify(element.value), true);
                    path = `${element.did}.remote.${element.siid}-${element.piid}`;
        			this.log.info(' Update: SIID:' + element.siid + ' PIID: ' + element.piid);
                    await this.extendObject(path, {
                      type: 'state',
                      common: {
                        name: path,
                        type: 'mixed',
                        role: 'state',
                        write: true,
                        read: true,
                      },
                      native: {},
                    });
                  }
                  if (path) {
                    this.log.debug(`Set ${path} to ${element.value}`);
                    if (element.value != null) {
                      // this.setState(path, JSON.stringify(element.value), true);
                      this.json2iob.parse(path, JSON.stringify(element));
                    }
                  }
                }
              }
            });
            this.mqttClient.on('error', async (error) => {
              this.log.error(error);
              if (error.message && error.message.includes('Not authorized')) {
                this.log.error('Not authorized to connect to MQTT');
                this.setState('info.connection', false, true);
                await this.refreshToken();
              }
            });
            this.mqttClient.on('close', () => {
              this.log.info('MQTT Connection closed');
            });
          }
        
        async uncompress(In_Compressed, In_path){
            var input_Raw = In_Compressed.replace(/-/g, '+').replace(/_/g, '/');
        	var encodedData = Buffer.from(input_Raw, 'base64');
            var decode = zlib.inflateSync(encodedData);
        	/*csvar mapHeader = decode.toString().split("{");
            let GetHeader = mapHeader[0];
        	this.log.info(' decode Header 1: ' + GetHeader);
        	try {
        		var encodedDataH = Buffer.from(GetHeader, 'base64');
        		this.log.info(' Base64 decode Header : ' + encodedDataH);
        		var decodeHeader = zlib.inflateSync(encodedDataH);
        		} catch (e) {
                this.log.info(' Error decode Header 2: ' + e);
                } finally {
                this.log.info(' decode Header 2: ' + decodeHeader);
                }
            */
        
        	var jsondecode = decode.toString().match(/[{\[]{1}([,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]|".*?")+[}\]]{1}/gis);
        	const jsonread = JSON.parse(jsondecode);
        
        	for (var [key, value] of Object.entries(jsonread)) {
               this.log.info(' decode Map JSON:' + `${key}: ${value}`);
        
        	    if(Object.prototype.toString.call(value) !== '[object Object]'){
        	      if (value != null) {
        			let pathMap = In_path + key;
        			await this.extendObject(pathMap, {
                      type: 'state',
                      common: {
                        name: pathMap,
                        type: 'mixed',
                        role: 'state',
                        write: false,
                        read: true,
                      },
                      native: {},
                    });
        
        			this.setState(pathMap, value, true);
        		  }
        	    }
        
        	   if (typeof value === 'object' && value !== null){
        		   if(Object.prototype.toString.call(value) === '[object Object]'){
        		       for (var [Subkey, Subvalue] of Object.entries(value)) {
                          this.log.info(' decode subkey ' + key + ' ==> ' + `${Subkey}: ${Subvalue}`);
        				  if (value != null) {
        					  let pathMap = In_path + key + '.' + Subkey;
        					  await this.extendObject(pathMap, {
        						type: 'state',
                                common: {
                                name: pathMap,
        						type: 'mixed',
                                role: 'state',
                                write: false,
                                read: true,
                                },
                                native: {},
                             });
        
        			         this.setState(pathMap, Subvalue, true);
        		          }
        		       }
                    }
        	   }
        
        	}
        }
        
          async refreshToken() {
            await this.requestClient({
              method: 'post',
              url: 'https://eu.iot.dreame.tech:13267/dreame-auth/oauth/token',
              headers: {
                'user-agent': 'Dart/3.2 (dart:io)',
                'dreame-meta': 'cv=i_829',
                'dreame-rlc': '1a9bb36e6b22617cf465363ba7c232fb131899d593e8d1a1-1',
                'tenant-id': '000000',
                host: 'eu.iot.dreame.tech:13267',
                authorization: 'Basic ZHJlYW1lX2FwcHYxOkFQXmR2QHpAU1FZVnhOODg=',
                'content-type': 'application/x-www-form-urlencoded',
              },
              data: {
                grant_type: 'refresh_token',
                refresh_token: this.session.refresh_token,
              },
            })
              .then((response) => {
                this.log.debug('Login response: ' + JSON.stringify(response.data));
                this.session = response.data;
                this.setState('info.connection', true, true);
                //reconnect mqtt
                this.connectMqtt();
              })
              .catch((error) => {
                this.log.error('Refresh Token  error: ' + error);
                error.response && this.log.error('Refresh Token error response: ' + JSON.stringify(error.response.data));
                this.setState('info.connection', false, true);
              });
          }
        
        
          /**
           * Is called when adapter shuts down - callback has to be called under any circumstances!
           * @param {() => void} callback
           */
          onUnload(callback) {
            try {
              callback();
            } catch (e) {
              callback();
            }
          }
        
          /**
           * Is called if a subscribed state changes
           * @param {string} id
           * @param {ioBroker.State | null | undefined} state
           */
          async onStateChange(id, state) {
            if (state) {
              if (!state.ack) {
                const deviceId = id.split('.')[2];
                const folder = id.split('.')[3];
                let command = id.split('.')[4];
                this.log.debug(`Receive command ${command} for ${deviceId} in folder ${folder} with value ${state.val} `);
                // let type;
                if (command) {
                  // type = command.split("-")[1];
                  command = command.split('-')[0];
                }
                if (id.split('.')[4] === 'Refresh') {
                  this.updateDevicesViaSpec();
                  return;
                }
                //{"id":0,"method":"app_start","params":[{"clean_mop":0}]}
        
                const stateObject = await this.getObjectAsync(id);
        
                const requestId = Math.floor(Math.random() * 9000) + 1000;
        
                const data = {
                  did: deviceId,
                  id: requestId,
                  data: {
                    did: deviceId,
                    id: requestId,
                    method: 'action',
                    params: {},
                    from: 'XXXXXX',
                  },
                };
                if (stateObject && stateObject.native.piid) {
                  data.data.params = {
                    did: deviceId,
                    siid: stateObject.native.siid,
                    piid: stateObject.native.piid,
                    value: state.val,
                  };
                }
                if (stateObject && stateObject.native.aiid) {
                  data.data.params = { did: deviceId, siid: stateObject.native.siid, aiid: stateObject.native.aiid };
                  if (typeof state.val !== 'boolean') {
                    try {
                      data.data.params['in'] = JSON.parse(state.val);
                    } catch (error) {
                      this.log.error(error);
                      return;
                    }
                  }
        
                  const device = this.deviceArray.filter((obj) => {
                    return obj.did === deviceId;
                  })[0];
                  if (device && device.model.includes('mower')) {
                    data.data.params.siid += 3;
                  }
        
                  // data.params.in = [];
                }
                if (command === 'customCommand') {
                  try {
                    data.data.params = JSON.parse(state.val);
                    data.data.params.did = deviceId;
                  } catch (error) {
                    this.log.error(error);
                    return;
                  }
                }
                this.log.info(`Send: ${JSON.stringify(data)} to ${deviceId}`);
        
                await this.requestClient({
                  method: 'post',
                  url: 'https://eu.iot.dreame.tech:13267/dreame-iot-com-10000/device/sendCommand',
                  headers: {
                    'user-agent': 'Dart/3.2 (dart:io)',
                    'dreame-meta': 'cv=i_829',
                    'dreame-rlc': '1a9bb36e6b22617cf465363ba7c232fb131899d593e8d1a1-1',
                    'tenant-id': '000000',
                    host: 'eu.iot.dreame.tech:13267',
                    authorization: 'Basic ZHJlYW1lX2FwcHYxOkFQXmR2QHpAU1FZVnhOODg=',
                    'content-type': 'application/json',
                    'dreame-auth': 'bearer ' + this.session.access_token,
                  },
                  data: data,
                })
                  .then(async (res) => {
                    if (res.data.code !== 0) {
                      this.log.error('Error setting device state');
                      this.log.error(JSON.stringify(res.data));
                      return;
                    }
                    if (res.data.result && res.data.result.length > 0) {
                      res.data = res.data.result[0];
                    }
                    this.log.info(JSON.stringify(res.data));
                    if (!res.data.result) {
                      return;
                    }
                    const result = res.data.result;
                    if (result.out) {
                      const path = this.specActiosnToIdDict[result.did][result.siid + '-' + result.aiid];
                      this.log.debug(path);
                      const stateObject = await this.getObjectAsync(path);
                      if (stateObject && stateObject.native.out) {
                        const out = stateObject.native.out;
                        for (const outItem of out) {
                          const index = out.indexOf(outItem);
                          const outPath = this.specPropsToIdDict[result.did][result.siid + '-' + outItem];
                          // await this.setState(outPath, result.out[index], true);
                          this.json2iob.parse(outPath, result.out[index]);
                          this.log.info('Set ' + outPath + ' to ' + result.out[index]);
                        }
                      } else {
                        this.log.info(JSON.stringify(result.out));
                      }
                    }
                  })
                  .catch(async (error) => {
                    this.log.error(error);
                    error.response && this.log.error(JSON.stringify(error.response.data));
                  });
                this.refreshTimeout = setTimeout(async () => {
                  this.log.info('Update devices');
                  await this.updateDevicesViaSpec();
                }, 10 * 1000);
              }
            }
          }
        }
        
        if (require.main !== module) {
          // Export the constructor in compact mode
          /**
           * @param {Partial<utils.AdapterOptions>} [options={}]
           */
          module.exports = (options) => new Dreame(options);
        } else {
          // otherwise start the instance directly
          new Dreame();
        }
        
        

        @SmartiSmart

        Mit dem folgenden Code kann ich dem Saugroboter über Alexa Befehle geben, um bestimmte Räume zu säubern. Beachten Sie, dass die Räume und das „Dreame“-Objekt zuvor angepasst werden mussten.

        on({ id: 'alexa2.0.History.summary' /* summary */, change: 'any' }, async (obj) => {
          let value = obj.state.val;
          let oldValue = obj.oldState.val;
          AlexaHistorysummary = getState('alexa2.0.History.summary').val;
          SearchClean = AlexaHistorysummary.lastIndexOf('sauber machen') + 1;
          SerachMoreClean = AlexaHistorysummary.lastIndexOf('sehr dreckig') + 1;
          ArrayRoom = ['schlafzimmer', 'toilette', 'abstellraum', 'kinderzimmer', 'esszimmer', 'arbeitszimmer','eingang', 'wohnzimmer', 'flur', 'küche', '];
          SerachRoomName = '';
          Room1 = false;
          Room2 = false;
          Room3 = false;
          Room4 = false;
          Room5 = false;
          Room6 = false;
          Room7 = false;
          Room8 = false;
          Room9 = false;
          Room10 = false;
          ResetRoomNumber = 0;
          FoundRoomState = false;
          StringToSend = '';
          CollectName = '';
          for (var i_index in ArrayRoom) {
            i = ArrayRoom[i_index];
            ResetRoomNumber = (typeof ResetRoomNumber === 'number' ? ResetRoomNumber : 0) + 1;
            SerachRoom = AlexaHistorysummary.lastIndexOf(i) + 1;
            if (parseFloat(SerachRoom) > 0) {
              if (parseFloat(SerachMoreClean) > 0) {
                SearchClean = 1;
                CleanSettings = ',3,3,3,1],';
              } else {
                CleanSettings = ',1,3,2,1],';
              }
              FoundRoomState = true;
              CollectName = [i,' und ',CollectName].join('');
              StringToSend = ['[',ResetRoomNumber,CleanSettings,StringToSend].join('');
            }
          }
          if (parseFloat(SearchClean) > 0) {
            CleanRoomCode = String(StringToSend) + String(StringToSend.slice(0, StripString - 1));
            CleanRoomCode = CleanRoomCode.slice(0, (CleanRoomCode.lastIndexOf(' und ') + 1) - 1);
            StringToSend = [' [{"piid": 1,"value": 18},{"piid": 10,"value": "{\\"selects\\": [',CleanRoomCode,']}"}]'].join('');
            console.log(('Now: ' + String(StringToSend)));
            CollectName = CollectName.slice(0, (CollectName.lastIndexOf(' und ') + 1) - 1);
            LastAlexa = getState('alexa2.0.History.serialNumber').val;
            if (FoundRoomState == true) {
              setStateDelayed((['alexa2.0.Echo-Devices.',LastAlexa,'.Commands.deviceStop'].join('')), true, false, parseInt(((0) || '').toString(), 10), true);
              setStateDelayed((['alexa2.0.Echo-Devices.',LastAlexa,'.Commands.deviceStop'].join('')), false, false, parseInt(((100) || '').toString(), 10), true);
              setStateDelayed((['alexa2.0.Echo-Devices.',LastAlexa,'.Commands.speak'].join('')), (['OK! ',CollectName,' sauber machen.'].join('')), false, parseInt(((0) || '').toString(), 10), true);
              setState('dreame.0.*********.remote.stop-clean' /* vacuum-extend stop-clean 4-2 */, '[ 1 ]');
              setStateDelayed('dreame.0.********.remote.start-clean' /* vacuum-extend start-clean 4-1 in[clean-extend-data,work-mode] */, StringToSend, 300, false);
            }
          }
        });
        
        S Offline
        S Offline
        SmartiSmart
        schrieb am zuletzt editiert von SmartiSmart
        #30

        OK, hat sich erledigt, jetzt habe ich es gefunden.

        Für alle die auch keinen Plan haben wie ich.

        1. Ein neues Java Script erstellen
        2. Dort reicht dann eine Zeile: setState ('dreame.0.***********.remote.start-sweep')
        3. Dieses Script kann dann einfach, z.B. über Blockly, aufgerufen werden.

        Damit startet einfach eine Reinigung. Über die Dreame App habe ich bei meinen Saugern "CleanGenius" ausgewählt und der Modus wird dadurch auch einfach gestartet.

        M 1 Antwort Letzte Antwort
        0
        • H Offline
          H Offline
          Heinz2100
          schrieb am zuletzt editiert von
          #31

          Hallo nochmal, hat schon jemand herausgefunden, wie/wo man die Stockwerke/Etage ändern kann, weil die Shortcuts je Stockwerk immer wieder von vorne mit 32 beginnen? Dankeschön

          1 Antwort Letzte Antwort
          0
          • H Offline
            H Offline
            Heinz2100
            schrieb am zuletzt editiert von
            #32

            value": "{"selects":[[X,1,3,2,1],[Y,1,3,2,1]]}

            Parameter 1 = Raum
            Parameter 2 = Wiederholungen
            Parameter 3 = Saugstärke (0-3)
            Parameter 4 = Wassermenge (1-3)
            Parameter 5 = Raumreinigungsreihenfolge

            Ist das korrekt? Wie kann ich den Roboter dann aber beispielsweise nur saugen lassen (ohne Wischen)?

            Danke

            H wawyoW 2 Antworten Letzte Antwort
            0
            • H Heinz2100

              value": "{"selects":[[X,1,3,2,1],[Y,1,3,2,1]]}

              Parameter 1 = Raum
              Parameter 2 = Wiederholungen
              Parameter 3 = Saugstärke (0-3)
              Parameter 4 = Wassermenge (1-3)
              Parameter 5 = Raumreinigungsreihenfolge

              Ist das korrekt? Wie kann ich den Roboter dann aber beispielsweise nur saugen lassen (ohne Wischen)?

              Danke

              H Offline
              H Offline
              hahne
              schrieb am zuletzt editiert von
              #33

              Ja das mit dem nur Saugen und nur Wischen würde mich auch interessieren.

              1 Antwort Letzte Antwort
              0
              • H Heinz2100

                value": "{"selects":[[X,1,3,2,1],[Y,1,3,2,1]]}

                Parameter 1 = Raum
                Parameter 2 = Wiederholungen
                Parameter 3 = Saugstärke (0-3)
                Parameter 4 = Wassermenge (1-3)
                Parameter 5 = Raumreinigungsreihenfolge

                Ist das korrekt? Wie kann ich den Roboter dann aber beispielsweise nur saugen lassen (ohne Wischen)?

                Danke

                wawyoW Offline
                wawyoW Offline
                wawyo
                Developer
                schrieb am zuletzt editiert von
                #34

                @heinz2100
                Array parameters:

                • Room ID: [X,2,1,2,0]

                • Repeats: [1,X,1,2,0] 1,2,3 list item

                • Suction Level: [1,2,X,2,0] 0: Quiet, 1: Standard, 2: Strong, 3: Turbo

                • Water Volume: [1,2,1,X,0] 2: Low, 3: Medium, 4:High

                • Cleaning Mode: [1,2,1,2,X] 0: Sweeping, 1: Mopping, 2: Sweeping and Mopping

                Laut der API sollte der Array so aufgebaut sein. Ich hoffe, dass alles funktioniert!

                H 1 Antwort Letzte Antwort
                1
                • S SmartiSmart

                  OK, hat sich erledigt, jetzt habe ich es gefunden.

                  Für alle die auch keinen Plan haben wie ich.

                  1. Ein neues Java Script erstellen
                  2. Dort reicht dann eine Zeile: setState ('dreame.0.***********.remote.start-sweep')
                  3. Dieses Script kann dann einfach, z.B. über Blockly, aufgerufen werden.

                  Damit startet einfach eine Reinigung. Über die Dreame App habe ich bei meinen Saugern "CleanGenius" ausgewählt und der Modus wird dadurch auch einfach gestartet.

                  M Offline
                  M Offline
                  MarcoGoldau
                  schrieb am zuletzt editiert von
                  #35

                  @smartismart Hey, kannst du mir weiterhelfen. Ich habe den Adapter installiert und mich erfolgreich eingeloggt.
                  Wie kann ich denn jetzt meinem Robi sagen, das er loslegen soll 😛
                  Ich habe in der Dreame App 3 Shortcuts
                  Saugen
                  Wischen
                  Leicht Wischen
                  Diese 3 würde ich einfach dann per VIS anwählen wollen.
                  Danke dir im voraus 🙂

                  H 1 Antwort Letzte Antwort
                  0
                  • M MarcoGoldau

                    @smartismart Hey, kannst du mir weiterhelfen. Ich habe den Adapter installiert und mich erfolgreich eingeloggt.
                    Wie kann ich denn jetzt meinem Robi sagen, das er loslegen soll 😛
                    Ich habe in der Dreame App 3 Shortcuts
                    Saugen
                    Wischen
                    Leicht Wischen
                    Diese 3 würde ich einfach dann per VIS anwählen wollen.
                    Danke dir im voraus 🙂

                    H Offline
                    H Offline
                    hahne
                    schrieb am zuletzt editiert von
                    #36

                    @marcogoldau
                    Oben im 1 Post wird beschrieben was man machen muss wenn man die Shortcuts nutzen möchte.

                    Wenn man die Shortcut ID hat, diese dann wie oben beschrieben in den Datenpunkt schreiben lassen (z.B . per Blockly)

                    1 Antwort Letzte Antwort
                    0
                    • wawyoW wawyo

                      @heinz2100
                      Array parameters:

                      • Room ID: [X,2,1,2,0]

                      • Repeats: [1,X,1,2,0] 1,2,3 list item

                      • Suction Level: [1,2,X,2,0] 0: Quiet, 1: Standard, 2: Strong, 3: Turbo

                      • Water Volume: [1,2,1,X,0] 2: Low, 3: Medium, 4:High

                      • Cleaning Mode: [1,2,1,2,X] 0: Sweeping, 1: Mopping, 2: Sweeping and Mopping

                      Laut der API sollte der Array so aufgebaut sein. Ich hoffe, dass alles funktioniert!

                      H Offline
                      H Offline
                      Heinz2100
                      schrieb am zuletzt editiert von Heinz2100
                      #37

                      @wawyo Ich habe den L10S Ultra Pro Heat.

                      Bei mir ist der erste Paramater RoomID und der fünfte Paramter RoomIndex (Raumreinigungsreihenfolge).

                      Die Paramter Repeats, Suction Level und Water Level ignoriert er komplett und nimmt dort die Raumeinstellungen aus der App. Wenn dort also für die Küche nur saugen auf Max eingestellt ist, dann macht er das auch, egal welche Parameter gesetzt sind.

                      Kann man das irgendwie umgehen? Gerade die Paramter wären super. Hab eigentlich keine Lust 300 verschiedene Shortcuts zu erstellen und zumal man dann ja immer nur einen Shortcut nach dem anderen starten kann.

                      H 1 Antwort Letzte Antwort
                      0
                      • H Heinz2100

                        @wawyo Ich habe den L10S Ultra Pro Heat.

                        Bei mir ist der erste Paramater RoomID und der fünfte Paramter RoomIndex (Raumreinigungsreihenfolge).

                        Die Paramter Repeats, Suction Level und Water Level ignoriert er komplett und nimmt dort die Raumeinstellungen aus der App. Wenn dort also für die Küche nur saugen auf Max eingestellt ist, dann macht er das auch, egal welche Parameter gesetzt sind.

                        Kann man das irgendwie umgehen? Gerade die Paramter wären super. Hab eigentlich keine Lust 300 verschiedene Shortcuts zu erstellen und zumal man dann ja immer nur einen Shortcut nach dem anderen starten kann.

                        H Offline
                        H Offline
                        hahne
                        schrieb am zuletzt editiert von
                        #38

                        @heinz2100 und außerdem bin ich der Meinung das nur eine Bestimmte Anzahl an Shortcuts erlaubt ist. Hatte damals mal für jeden Raum nur Wischen als Shortcut angelegt und das hatte nicht gereicht.

                        Ich hatte den Tag mal Probiert bei mir Passt das auch nicht so Recht mit den Parametern .
                        Werde nachher nochmal genauer berichten.
                        Habe aber nur nen L10S Ultra

                        H 1 Antwort Letzte Antwort
                        0
                        • H hahne

                          @heinz2100 und außerdem bin ich der Meinung das nur eine Bestimmte Anzahl an Shortcuts erlaubt ist. Hatte damals mal für jeden Raum nur Wischen als Shortcut angelegt und das hatte nicht gereicht.

                          Ich hatte den Tag mal Probiert bei mir Passt das auch nicht so Recht mit den Parametern .
                          Werde nachher nochmal genauer berichten.
                          Habe aber nur nen L10S Ultra

                          H Offline
                          H Offline
                          Heinz2100
                          schrieb am zuletzt editiert von
                          #39

                          @hahne Danke dir. Hab schon das ganze Internet abgesucht, aber nirgends wird etwas beschrieben. Immer nur die 5 Parameter, die bei unseren L10S Ultras aber anscheinend nicht funktionieren bzw. nicht das steuern, was wir wollen. Hab schon alle Varianten rauf und runter getestet, aber er fährt immer nur los und zieht sich die in der App konfigurierten Raumeinstellungen.

                          1 Antwort Letzte Antwort
                          0
                          • H Offline
                            H Offline
                            hahne
                            schrieb am zuletzt editiert von
                            #40

                            @Heinz2100 Kann ich nun bestätigen . Egal welche Parameter man angibt er nimmt sich die zuletzt eingestellten aus der App. Das einzige was Funktioniert ist der 1. Parameter.
                            Dabei ist es egal ob die "Benutzerdefinierte Reinigung" in der App Aktiviert oder Deaktiviert wurde.
                            Ich hab auch alle Datenpunkte Probiert um da den Reinigungsmodus zu ändern. Ohne erfolg.

                            1 Antwort Letzte Antwort
                            0
                            • H Offline
                              H Offline
                              hahne
                              schrieb am zuletzt editiert von
                              #41

                              Ich habe mal ein wenig rum geschaut,
                              Klick

                              Dort steht ein wenig was zu den Sachen geschrieben, aber funktionieren tut es trotzdem nicht 😄 vllt. findet sich wer der das besser versteht wie ich 😄

                              H 2 Antworten Letzte Antwort
                              0
                              • H hahne

                                Ich habe mal ein wenig rum geschaut,
                                Klick

                                Dort steht ein wenig was zu den Sachen geschrieben, aber funktionieren tut es trotzdem nicht 😄 vllt. findet sich wer der das besser versteht wie ich 😄

                                H Offline
                                H Offline
                                Heinz2100
                                schrieb am zuletzt editiert von
                                #42

                                @hahne Ja das habe ich auch schon mal gefunden. Wenn du dir mal das Update von wawyo holst (siehe 10.09.2024), dann hast du die Einstellungen der einzelnen Räume angezeigt und die nimmt er, wenn man den Reinigungsvorgang startet. Für unsere Modelle kommt wohl anscheind der Punkt "Some other dreame devices (e.g. Xiaomi Robot Vacuum X10+) separate the room configuration/selection" deines Links zum Tragen. Heißt für mich: Erst muss man in den Punkt 6.2 dreame.0.XXXXXXXXX.remote.update-map die gewünschten Einstellungen "customeClean" schreiben und dann erst die Reinigung starten. Hat das schon jemand etabliert?

                                1 Antwort Letzte Antwort
                                0
                                • H hahne

                                  Ich habe mal ein wenig rum geschaut,
                                  Klick

                                  Dort steht ein wenig was zu den Sachen geschrieben, aber funktionieren tut es trotzdem nicht 😄 vllt. findet sich wer der das besser versteht wie ich 😄

                                  H Offline
                                  H Offline
                                  Heinz2100
                                  schrieb am zuletzt editiert von Heinz2100
                                  #43

                                  @hahne Ich konnte tatsächlich mit folgendem Befehl beim Datenpunkt dreame.0.XXXXXXXXX.remote.update-map die Einstellungen für den Raum konfigurieren.

                                  [
                                    {
                                      "piid": 4,
                                      "value": "{\"customeClean\":[[1,1,1,1,1]]}"
                                    }
                                  ]
                                  

                                  Für mehrere Räume analog:

                                  [
                                    {
                                      "piid": 4,
                                      "value": "{\"customeClean\":[[1,1,1,1,1],[2,1,1,1,1]]}"
                                    }
                                  ]
                                  

                                  Die Parameter entsprechen dabei anscheinend den von wawyo am 29.09. beschriebenen, aber das teste ich morgen mal noch durch. Die unter Cleanset angezeigten Paramter je Raum aktualisieren sich wie bereits weiter oben immer erst, wenn der Roboter losgefahren ist.

                                  Heißt Parameter für den Raum setzen und danach den Saugroboter losschicken. So sollte es eigentlich (endlich) klappen.

                                  1 Antwort Letzte Antwort
                                  0
                                  • H Offline
                                    H Offline
                                    Heinz2100
                                    schrieb am zuletzt editiert von
                                    #44

                                    Was ich jetzt als einziges noch nicht hinbekommen habe ist:

                                    • Stockwerkwechsel per Remote anstoßen (ist aber nicht so schlimm, da es automatisch erkannt wird)

                                    • Nur Mop auswaschen. Laut Miot Specs müsste es doch hier den Steuerungspunkt SSID4, AIID4 (wash-mop) geben. Der ist bei mir unter Remote aber nicht zu finden.
                                      https://home.miot-spec.com/spec/dreame.vacuum.r2228z

                                    H 1 Antwort Letzte Antwort
                                    0
                                    • H Offline
                                      H Offline
                                      hahne
                                      schrieb am zuletzt editiert von
                                      #45

                                      @Heinz2100 Probiere ich nachher gleich mal aus. Ich hatte das gleiche probiert vor einigen Tagen habe es allerdings in den Falschen DP geschrieben :man-facepalming:
                                      "wash-mop" ist bei mir auch nicht zu sehen.

                                      1 Antwort Letzte Antwort
                                      0
                                      • H Heinz2100

                                        Was ich jetzt als einziges noch nicht hinbekommen habe ist:

                                        • Stockwerkwechsel per Remote anstoßen (ist aber nicht so schlimm, da es automatisch erkannt wird)

                                        • Nur Mop auswaschen. Laut Miot Specs müsste es doch hier den Steuerungspunkt SSID4, AIID4 (wash-mop) geben. Der ist bei mir unter Remote aber nicht zu finden.
                                          https://home.miot-spec.com/spec/dreame.vacuum.r2228z

                                        H Offline
                                        H Offline
                                        Heinz2100
                                        schrieb am zuletzt editiert von
                                        #46

                                        @heinz2100 So jetzt habe ich auch noch die Mopreinigung zum Laufen gebracht. Die main.js von von wawyo vom 10.09.2024 muss auf das Modell r2228z anpepasst werden. Dann erscheinen auch die fehlenden Datenpunkte.main.js

                                        Wenn man den neuen Datenpunkt wash-mop dann auf "true" setzt, wird gereinigt.

                                        Fehlt also nur noch die Stockwerkauswahl

                                        H 1 Antwort Letzte Antwort
                                        0
                                        • H Offline
                                          H Offline
                                          hahne
                                          schrieb am zuletzt editiert von
                                          #47

                                          So richtig verstanden hab ich's immer noch nicht 😄
                                          Hattest du die main.js aus deinem vorherigen Post schon geändert damit wash-mop erscheint?
                                          Ich habe diese genommen und bei mir erscheint der Datenpunkt nicht.

                                          Wieso ist das Array unter map/cleanset 6 Stellig? Wir geben doch nur 5 Parameter an?

                                          Stimmt das Array bei dir? Bei mir ist z.B. die 2te zahl nicht Repeat sondern Suction Level.

                                          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

                                          766

                                          Online

                                          32.4k

                                          Benutzer

                                          81.4k

                                          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
                                          • Aktuell
                                          • Tags
                                          • Ungelesen 0
                                          • Kategorien
                                          • Unreplied
                                          • Beliebt
                                          • GitHub
                                          • Docu
                                          • Hilfe