Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot read property 'forEach' of undefined #59

Open
w-marco opened this issue May 14, 2022 · 25 comments
Open

Cannot read property 'forEach' of undefined #59

w-marco opened this issue May 14, 2022 · 25 comments

Comments

@w-marco
Copy link

w-marco commented May 14, 2022

Moin, erstmal tolles Skript. leider scheitert meine Einrichtung des Mi Smartfan 2.
Ich hab die Def Datei eingefuegt und ioBroker neugestartet. Er findet diese auch, aber bekommt dann den Error aus dem Title.

Hier mal ein Log:

18:53:55.718	info	javascript.0 (31346) Start javascript script.js.common.MiHomeAll
18:53:56.952	info	javascript.0 (31346) script.js.common.MiHomeAll: Starting AllMyMi V.0.2.29
18:53:56.957	info	javascript.0 (31346) script.js.common.MiHomeAll: Reaching init
18:53:57.144	info	javascript.0 (31346) script.js.common.MiHomeAll: registered 0 subscriptions and 0 schedules
18:53:58.274	info	javascript.0 (31346) script.js.common.MiHomeAll: Retrieving your in de registered MiHome Devices
18:53:58.431	info	javascript.0 (31346) script.js.common.MiHomeAll: Found 1 MiHome Devices, those are:
18:53:58.432	info	javascript.0 (31346) script.js.common.MiHomeAll: Mi Smart Standing Fan 2
18:53:58.433	info	javascript.0 (31346) script.js.common.MiHomeAll: Now searching for supported Devices...
18:53:58.434	info	javascript.0 (31346) script.js.common.MiHomeAll: Device Mi Smart Standing Fan 2 is supported, creating DataPoints if necessary
18:53:58.435	info	javascript.0 (31346) script.js.common.MiHomeAll: Reaching PrepareDeviceDps, did=ID model=dmaker.fan.p18
18:53:58.437	info	javascript.0 (31346) script.js.common.MiHomeAll: Reaching CreateStates()
18:53:58.616	info	javascript.0 (31346) script.js.common.MiHomeAll: 17 States created, now setting up channels!
18:53:58.618	info	javascript.0 (31346) script.js.common.MiHomeAll: Reaching main
18:53:58.619	info	javascript.0 (31346) script.js.common.MiHomeAll: Reaching WriteGenericDpValues()
18:53:58.620	info	javascript.0 (31346) script.js.common.MiHomeAll: Reaching CreateDevices
18:53:58.621	info	javascript.0 (31346) script.js.common.MiHomeAll: Now creating device for dmaker.fan.p18 / 409699151 / 192.168.30.27 / TOKEN / 10000
18:53:58.624	info	javascript.0 (31346) script.js.common.MiHomeAll: Created device {"_events":{},"_eventsCount":0,"_maxListeners":100,"id":"ID","address":"192.168.30.27","token":"TOKEN","protocol":"local","refresh":10000,"_properties":{},"_propertiesToMonitor":["fan:on","fan:mode","fan:fan-level","fan:horizontal-swing","fan:horizontal-angle","fan:status","alarm:alarm","motor-controller:motor-control","physical-controls-locked:physical-controls-locked","off-delay-time:off-delay-time"],"_miotSpec":null,"_miotSpecType":"urn:miot-spec-v2:device:fan:0000A005:dmaker-p18:1","model":"dmaker.fan.p18","setter":{},"definition":{"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}}],"model":"dmaker.fan.p18","description":"Mi Smart Standing Fan 2","setter":{},"common":[{"name":"fan.on","type":"boolean","role":"switch","read":true,"write":true},{"name":"fan.mode","type":"number","role":"switch","read":true,"write":true,"min":0,"max":1,"states":{"0":"Straight Wind","1":"Natural Wind"}},{"name":"fan.fan-level","type":"number","role":"switch","read":true,"write":true,"min":1,"max":4,"states":{"1":"Slow","2":"Middle","3":"High","4":"Turbo"}},{"name":"fan.horizontal-swing","type":"boolean","role":"switch","read":true,"write":true},{"name":"fan.horizontal-angle","type":"number","role":"switch","read":true,"write":true,"min":30,"max":140,"unit":"°","states":{"30":"30°","60":"60°","90":"90°","120":"120°","140":"140°"}},{"name":"fan.status","type":"number","role":"indicator","read":true,"write":false,"min":1,"max":100},{"name":"alarm.alarm","type":"boolean","role":"switch","read":true,"write":true},{"name":"motor-controller.motor-control","type":"number","role":"switch","read":false,"write":true,"min":0,"max":2,"states":{"0":"None","1":"Left","2":"Right"}},{"name":"physical-controls-locked.physical-controls-locked","type":"boolean","role":"switch","read":true,"write":true,"min":false,"max":true},{"name":"off-delay-time.off-delay-time","type":"number","role":"switch","read":true,"write":true,"min":0,"max":480,"unit":"m"}]},"firstrun":true,"rssi":0,"isOnline":true} now fetching data
18:53:59.095	error	javascript.0 (31346) script.js.common.MiHomeAll: TypeError: Cannot read property 'forEach' of undefined
18:53:59.100	error	javascript.0 (31346) at CreateDevices (script.js.common.MiHomeAll:924:17)
18:53:59.101	error	javascript.0 (31346) at main (script.js.common.MiHomeAll:842:5)

Leider erschließt sich mir nicht wieso das passiert.

@Pittini
Copy link
Owner

Pittini commented May 15, 2022

Nach dem einfügen der Datei auch den JS Adapter neu gestartet?

@w-marco
Copy link
Author

w-marco commented May 15, 2022

Sicher, auch versucht komplett ioBroker neu zu starten. Hat beides nicht geholfen.

@Pittini
Copy link
Owner

Pittini commented May 15, 2022

Für mich grad nicht wirklich nachvollziehbar. Kanns auch nicht testen, hab das Ding ja nicht. Aber setz Dich doch mal mit dem ersteller der Def Datei in Verbindung, evtl. weis der was: #37

@w-marco
Copy link
Author

w-marco commented May 18, 2022

Ich hab es in dem Issue mal versucht, eine Email oder sowas von ihm konnte ich nicht finden.
Trotzdem seltsam dieser Fehler, ich verstehe aber auch nicht an welcher Stelle es kaputt geht, hast du da keine Idee ? ich hab das Teil ja hier, also wenn es Ideen zum testen gibt kann ich gerne dabei helfen.

@Pittini
Copy link
Owner

Pittini commented May 19, 2022

Ich hab es in dem Issue mal versucht, eine Email oder sowas von ihm konnte ich nicht finden. Trotzdem seltsam dieser Fehler, ich verstehe aber auch nicht an welcher Stelle es kaputt geht, hast du da keine Idee ? ich hab das Teil ja hier, also wenn es Ideen zum testen gibt kann ich gerne dabei helfen.

Du kannst versuchen die Def Datei erstmal auf was sicheres wie on/off zu reduzieren und dann nach und nach wieder Funktionen dazuzunehmen bis Du wieder den Fehler hast, dann weiste was das Problem verursacht. Also den Teil:

    this._propertiesToMonitor = [
      'fan:on',
      'fan:mode',
      'fan:fan-level',
      'fan:horizontal-swing',
      'fan:horizontal-angle',
      'fan:status',
      'alarm:alarm',
      'motor-controller:motor-control',
      'physical-controls-locked:physical-controls-locked',
      'off-delay-time:off-delay-time'
      ];

ändern zu:

    this._propertiesToMonitor = [
      'fan:on'
      ];

Danach nicht vergessen den JS Controller nach jeder Änderung neuzustarten.

Wennde den Fehler schon bei on/off haben solltest, liegts an was anderem, was Du aber nicht testen kannst weil Du scheinbar nur das eine Xiaomi Gerät hast.

@w-marco
Copy link
Author

w-marco commented May 19, 2022

Ich hab das mal getan und weiterhin den selben Fehler.
Ich hab dann aber mal mit python-miio versucht mit dem Ventilator zu reden und das geht, also liegt es nicht am Netzwerk oder dem Gerät. Ich konnte ihn damit auch steuern.

Der Fehler muss also im Script oder der Def Datei liegen. Vielleicht hilft das ja weil es das Debugging sehr einschränkt und es kein äußerer Fehler ist.
Wie gesagt, ich stehe gerne (auch im Discord oder sowas) zum testen bereit.

@cacherwolf
Copy link

Hallo,
Danke für das tolle Skript.

Ich habe auch den Mi Smart Fan 2 und genau die gleiche Fehlermeldung.

Gibt es inzwischen schon eine Lösung?

@ChristopherGier
Copy link

Hey, die Lösung ist relativ einfach: in dem device File vom importierten Modul ist ein Fehler. Wenn die Attribute nicht gefüllt sind checkt er nicht ob das Ding leer ist sondern versucht gleich drüber zu interieren - das führt zu besagtem Problem. Kann man mit optional chaining lösen. Also quasi Variable?.forEach start Variable.forEach
Das hat's bei mir gelöst. Dazu noch ein paar Veränderungen an dem Schema, da das nicht in Ganze zu passen scheint
Ich kann morgen Mal genauer schreiben falls es euch interessiert, bin gerade noch unterwegs

@cacherwolf
Copy link

Das wäre super wenn du das machen würdest, vielen Dank :-)

@ChristopherGier
Copy link

Sehr gern, hoffe es klappt bei dir dann auch.
Als erstes schau dir Mal die folgende Zeile bei dir in den Modemodules an:
https://github.com/maxinminax/node-mihome/blob/e60c287d9bb2d9ba9123543d92ec481be5a62b5e/lib/device-miio.js#L101

Wenn du die änderst in:
props?.forEach((prop, i) => {
Sollte der Fehler nicht mehr auftauchen und das an/ausschalten sollte funktionieren.
Kannst du ja vielleicht Mal testen. Falls es klappt kannst du die anderen Bedienungsmöglichkeiten Mal durchtesten und sagen welche klappen und welche nicht - bin mir nicht ganz sicher ob das nur bei mir nicht funktioniert hatte

@cacherwolf
Copy link

Vielen Dank für deine Mühe, aber leider hat es nicht geklappt.
Ich habe die Änderungen in Zeile 101 gemacht, leider kommt die gleiche Fehlermeldung wie vorher und das an/ausschalten funktioniert auch nicht.
Es werden zwar die Datenpunkte angelegt aber danach nicht mehr aktualisiert.

2022-07-31 12:53:42.254 - error: javascript.0 (1414) script.js.Xiaomi_Home_: TypeError: Cannot read properties of undefined (reading 'forEach')

2022-07-31 12:53:42.255 - error: javascript.0 (1414) at /opt/iobroker/node_modules/iobroker.javascript/node_modules/node-mihome/lib/device-miio.js:192:18
2022-07-31 12:53:42.255 - error: javascript.0 (1414) at Array.forEach ()
2022-07-31 12:53:42.255 - error: javascript.0 (1414) at module.exports.miotFetchSpec (/opt/iobroker/node_modules/iobroker.javascript/node_modules/node-mihome/lib/device-miio.js:190:14)
2022-07-31 12:53:42.256 - error: javascript.0 (1414) at runMicrotasks ()
2022-07-31 12:53:42.256 - error: javascript.0 (1414) at processTicksAndRejections (node:internal/process/task_queues:96:5)
2022-07-31 12:53:42.256 - error: javascript.0 (1414) at module.exports.init (/opt/iobroker/node_modules/iobroker.javascript/node_modules/node-mihome/lib/device-miio.js:43:7)
2022-07-31 12:53:42.257 - error: javascript.0 (1414) at CreateDevices (script.js.Xiaomi_Home_:922:17)
2022-07-31 12:53:42.257 - error: javascript.0 (1414) at main (script.js.Xiaomi_Home_:840:5)

@ChristopherGier
Copy link

Das sollte eig nicht passieren.. ich schau es mir nochmal an und Versuch es Mal zu reproduzieren. Ist der Code denn noch wie verändert und hast du den Adapter neugestartet?
Problem ist momentan eh das bei jedem Update etc die customizings überschrieben werden - vermutlich auch die device Schemas

@cacherwolf
Copy link

cacherwolf commented Jul 31, 2022

Ja, der ist noch verändert und ich habe sowohl den JS Adapter als auch IOB neu gestartet.

Ich habe jetzt in der Datei dmaker.fan.p18.js die Zeile "this._miotSpecType = 'urn:miot-spec-v2:device:fan:0000A005:dmaker-p18:1';" entfernt. Jetzt läuft das Skript durch, allerdings kann ich den Ventilator immer noch nicht an/ausschalten und die Datenpunkte werden auch nicht aktualiesiert.

@ChristopherGier
Copy link

Komisch.. ich schau es mir Mal in Ruhe morgen an - falls ich es nicht nachstellen kann, können wir es uns ja ggf. Mal über discord zusammen anschauen

@cacherwolf
Copy link

Super, vielen Dank

@ChristopherGier
Copy link

Okay, doof von mir.. Falsche Line. Müsste Line 192 sein:

properties.forEach(property => {

Zu:

properties?.forEach(property => {

@cacherwolf
Copy link

Super von Dir, es war die Line 192
Vielen Dank für die Hilfe.

Bei mir funktionieren jetzt
fan-level, horizontal-angle, horizontal-swing, mode, on und physical-controls-locked

Allerdings funktioniert die Rückmeldung nicht. Wenn ich im in der App oder am Gerät etwas ändere (z.B. den Ventilator einschalte) wir die Änderung nicht in den IOB übertragen. Hast du dafür auch eine Lösung?

@ChristopherGier
Copy link

Der Rest ist leider falsch gemapped.. muss man in den device files und im Skript anpassen.
Das war leider etwas fummelig aber ich schick nachher Mal die Veränderungen die ich gemacht habe (ohne Garantie auf Richtigkeit) :D

Um den aktuellen Status hatte ich mich nicht gekümmert, wollte das Gerät nur über Alexa schalten können ohne das es in die China Cloud kommuniziert, deshalb hatte ich mir den Rest nicht mehr angeschaut :/

@ChristopherGier
Copy link

Im Script selber habe ich das entsprechende DefineDevice geändert zu:

{ // Tested and working
    info: {},
    model: "dmaker.fan.p18",// https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:fan:0000A005:dmaker-p18:1  
    description: "Mi Smart Standing Fan 2",
    setter: {
        "fan.on": async function (obj, val) { await device[obj].setPower(val) },
        "fan.mode": async function (obj, val) { await device[obj].setMode(val) },
        "fan.fan-level": async function (obj, val) { await device[obj].setFanLevel(val) },
        "fan.horizontal-swing": async function (obj, val) { await device[obj].setHorizontalSwing(val) },
        "fan.horizontal-angle": async function (obj, val) { await device[obj].setHorizontalAngle(val) },
        "fan.alarm": async function (obj, val) { await device[obj].setAlarm(val) },
        "fan.motor-control": async function (obj, val) { await device[obj].setMotorController(val) },
        "physical-controls-locked.physical-controls-locked": async function (obj, val) { await device[obj].setChildLock(val) },
        "fan.off-delay-time": async function (obj, val) { await device[obj].setOffDelayTime(val) },
        "fan.brightness": async function (obj, val) { await device[obj].setBrightness(val) }
    },
    common:
        [{ name: "fan.on", type: "boolean", role: "switch", read: true, write: true },
        { name: "fan.mode", type: "number", role: "switch", read: true, write: true, min: 0, max: 1, states: { 0: "Straight Wind", 1: "Natural Wind" } },
        { name: "fan.fan-level", type: "number", role: "switch", read: true, write: true, min: 1, max: 4, states: { 1: "Slow", 2: "Middle", 3: "High", 4: "Turbo" } },
        { name: "fan.horizontal-swing", type: "boolean", role: "switch", read: true, write: true },
        { name: "fan.horizontal-angle", type: "number", role: "switch", read: true, write: true, min: 30, max: 140, unit: "°", states: { 30: "30°", 60: "60°", 90: "90°", 120: "120°", 140: "140°" } },
        { name: "fan.status", type: "number", role: "indicator", read: true, write: false, min: 1, max: 100 },
        { name: "fan.alarm", type: "boolean", role: "switch", read: true, write: true },
        { name: "fan.motor-control", type: "number", role: "switch", read: false, write: true, min: 0, max: 2, states: { 0: "None", 1: "Left", 2: "Right" } },
        { name: "physical-controls-locked.physical-controls-locked", type: "boolean", role: "switch", read: true, write: true, min: false, max: true },
        { name: "fan.off-delay-time", type: "number", role: "switch", read: true, write: true, min: 0, max: 480, unit: "m" },
        { name: "fan.brightness", type: "boolean", role: "switch", read: true, write: true }
        ]
};

Zusätzlich im entsprechenden Device File:

const Device = require('../device-miio');

module.exports = class extends Device {

  static model = 'dmaker.fan.p18';
  static name = 'Mi Smart Standing Fan 2';
  static image = 'http://static.home.mi.com/app/image/get/file/developer_1541408255kg3xtr1j.png';

  constructor(opts) {
    super(opts);

    this._miotSpecType = 'urn:miot-spec-v2:device:fan:0000A005:dmaker-p18:1';
    this._propertiesToMonitor = [
      'fan:on',
      'fan:mode',
      'fan:fan-level',
      'fan:horizontal-swing',
      'fan:horizontal-angle',
      'fan:status',
      'fan:brightness',
      'fan:alarm',
      'fan:motor-control',
      'physical-controls-locked:physical-controls-locked',
      'fan:off-delay-time'
    ];
  }

  getPower() {
    power = this.properties['fan:on'];
    if (power === 1) return true;
    if (power === 0) return false;
    return undefined;
  }

  getFanLevel() {
    const fanLevel = parseInt(this.properties['fan:fan-level'], 10);
    if (fanLevel > 0) return fanLevel;
    return undefined;
  }

  getMode() {
    return this.properties['fan:mode'];
  }

  getBrightness() {
    return this.properties['fan:brightness'];
  }

  getHorizontalSwing() {
    return this.properties['fan:horizontal-swing'];
  }

  setHorizontalAngle() {
    return this.properties['fan:horizontal-angle'];
  }

  getAlarm() {
    return this.properties['fan:alarm'];
  }

  getMotorController() {
    return this.properties['fan:motor-control'];
  }

  getChildLock() {
    return this.properties['physical-controls-locked:physical-controls-locked'];
  }

  getOffDelayTime() {
    return this.properties['fan:off-delay-time'];
  }


  setPower(v) {
    return this.miotSetProperty('fan:on', v);
  }

  setMode(v) {
    return this.miotSetProperty('fan:mode', v);
  }
 
  setFanLevel(v) {
    return this.miotSetProperty('fan:fan-level', v);
  }

  setHorizontalSwing(v) {
    return this.miotSetProperty('fan:horizontal-swing', v);
  }

  setHorizontalAngle(v) {
    return this.miotSetProperty('fan:horizontal-angle', v);
  }

  setBrightness(v) {
    return this.miotSetProperty('fan:brightness', v);
  }

  setAlarm(v) {
    return this.miotSetProperty('fan:alarm', v);
  }

  setMotorController(v) {
    return this.miotSetProperty('fan:motor-control', v);
  }

  setChildLock(v) {
    return this.miotSetProperty('physical-controls-locked:physical-controls-locked', v);
  }

  setOffDelayTime(v) {
    return this.miotSetProperty('fan:off-delay-time', v);
  }
};

@Pittini
Copy link
Owner

Pittini commented Aug 2, 2022

Sehr toll, dass Ihr hier eine Lösung gefunden habt. Wäre super nett wenn (wenn keine Fehler in den Tests auftreten) @ChristopherGier daraus nen PullRequest machen könnte.

@Tableautin
Copy link

Hi. Ich hatte im ioBroker Forum auch schon mal das Problem gemeldet und bin gerade dazu gekommen, es nach dem Thread hier zu testen.

Inzwischen habe ich beim Ausführen des Scripts keine Fehler mehr, die Datenpunkte werden korrekt angelegt, aber leider stehen alle Datenpunkte in "Fan" auf "NULL". Ich bekomme also keine Rückmeldung vom Gerät zum Status, und auch das Steuern funktioniert bei mir nicht. IP Adresse, Name etc funktionier

Ich hoffe ich habe alle Änderungen korrekt dem Textverlauf entnommen und eingebaut. Habe ich da noch was vergessen?

@CyrussM
Copy link

CyrussM commented Aug 17, 2022

Mit dem Fix von ChristopherGier geht es so halb, ich kann den Fan steuern und bekomme die Werte unter "Info" angezeigt (IP, Name etc.).
Leider fehlen alle Status Meldungen. Die Abfrage funktioniert einfach nicht. Das An und Aus schalten per setzten von true oder false unter dem on Objekt, wird aber ausgeführt. Fehler Meldungen hab ich nicht. Steuer ich also mit der App, bekommt iobroker davon nichts mit.
Jemand ne Idee?

@Pittini
Copy link
Owner

Pittini commented Aug 17, 2022

Jemand ne Idee?

Nicht wirklich. Aber ich kann zumindest mal erklären warum IP, Name etc da sind aber sonst nix. Diese "statischen" Infos wie IP, kommen für alle Geräte bei der Anmeldung am Xiaomi Server für alle Geräte in Deinem Besitz. Jetzt guggt im zweiten Schritt, das Skript, welche Geräte davon, vom Skript unterstützt werden und legt dafür die DAtenpunkte an und erstellt ein Object dass normaler weise dann regelmäßig Datenupdates erhält. Und genau das scheint nicht zu klappen. Warum weis ich nicht wirklich.

@cacherwolf
Copy link

Ich habe im Device File alle Anweisung gelöscht und nach und nach wieder eingeführt. Das hat dann auch geklappt.
Bin gerade im Urlaub und habe keinen Zugriff auf die Datei, werde sie nächste Woche hier einstellen.

@Fritzelspitze
Copy link

Gibts da inzwischen eine Lösung für?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants