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

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Tester
  4. Test Adapter Midea Dimstal Klimaanlagen v0.0.x

NEWS

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

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

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

Test Adapter Midea Dimstal Klimaanlagen v0.0.x

Geplant Angeheftet Gesperrt Verschoben Tester
mideadimstalnethomenethome plus
368 Beiträge 65 Kommentatoren 86.7k Aufrufe 62 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.
  • Thomas BraunT Thomas Braun

    @markus-8

    So ein paar Satzzeichen, Absätze usw. würden den ganzen Sermon vielleicht besser lesbar machen...

    M Offline
    M Offline
    Markus 8
    schrieb am zuletzt editiert von
    #338

    @thomas-braun Habt Mitleid mit mir ich poste eigendlich nie was Ich bin zeitalter C64

    Thomas BraunT 1 Antwort Letzte Antwort
    0
    • M Markus 8

      @thomas-braun Habt Mitleid mit mir ich poste eigendlich nie was Ich bin zeitalter C64

      Thomas BraunT Online
      Thomas BraunT Online
      Thomas Braun
      Most Active
      schrieb am zuletzt editiert von
      #339

      @markus-8 Und damals gab es keine Satzzeichen?

      Linux-Werkzeugkasten:
      https://forum.iobroker.net/topic/42952/der-kleine-iobroker-linux-werkzeugkasten
      NodeJS Fixer Skript:
      https://forum.iobroker.net/topic/68035/iob-node-fix-skript
      iob_diag: curl -sLf -o diag.sh https://iobroker.net/diag.sh && bash diag.sh

      M 1 Antwort Letzte Antwort
      0
      • Thomas BraunT Thomas Braun

        @markus-8 Und damals gab es keine Satzzeichen?

        M Offline
        M Offline
        Markus 8
        schrieb am zuletzt editiert von
        #340

        @thomas-braun Meine Fresse sind wir im rechtschreibkurs das kotzt mich an bin dan mal raus

        Thomas BraunT 1 Antwort Letzte Antwort
        0
        • M Markus 8

          @thomas-braun Meine Fresse sind wir im rechtschreibkurs das kotzt mich an bin dan mal raus

          Thomas BraunT Online
          Thomas BraunT Online
          Thomas Braun
          Most Active
          schrieb am zuletzt editiert von
          #341

          @markus-8 Tschüss!

          Linux-Werkzeugkasten:
          https://forum.iobroker.net/topic/42952/der-kleine-iobroker-linux-werkzeugkasten
          NodeJS Fixer Skript:
          https://forum.iobroker.net/topic/68035/iob-node-fix-skript
          iob_diag: curl -sLf -o diag.sh https://iobroker.net/diag.sh && bash diag.sh

          1 Antwort Letzte Antwort
          0
          • M Markus 8

            @bananajoe OK stelle die frage mal anders :Dimstal Klimanlage die In medion und Alexa vorhanden ist wie bekomme ich dise auch in den IOT.= adapter unter Smarthomegeräte das versteht man glaube ich besser.

            BananaJoeB Offline
            BananaJoeB Offline
            BananaJoe
            Most Active
            schrieb am zuletzt editiert von
            #342

            @markus-8 sagte in Test Adapter Midea Dimstal Klimaanlagen v0.0.x:

            @bananajoe OK stelle die frage mal anders :Dimstal Klimanlage die In medion und Alexa vorhanden ist wie bekomme ich dise auch in den IOT.= adapter unter Smarthomegeräte das versteht man glaube ich besser.

            Du meinst den iobroker.iot Adapter oder und was genau in dem Adapter ich nutze den Adapter eigentlich nur um beliebiges als Gerät in Alexa / des Echos darzustellen denn du kannst dir ja einen belieben Datenpunkt vom Typ "Logikwert" anlegen, z.B. 0_userdata.0.Wohnzimmer.Klimaanlage und diesen dann im iot-Adapter als Alexa-Gerät darstellen und dann machts du ein Skript was auf den Datenpunkt reagiert was also die eigentliche Arbeit macht aber warum denn überhaupt den iot.0 denn die Klimaanlagen können doch nativ Alexa (oder Google) und ja, wenn du alles immer in einem Satz schreibst ist es schwer zu lesen und zu verstehen denn auch ich finde ein paar mal Enter/Return würde schon helfen.

            ioBroker@Ubuntu 24.04 LTS (VMware) für: >260 Geräte, 5 Switche, 7 AP, 9 IP-Cam, 1 NAS 42TB, 1 ESXi 15TB, 4 Proxmox 1TB, 1 Hyper-V 48TB, 14 x Echo, 5x FireTV, 5 x Tablett/Handy VIS || >=160 Tasmota/Shelly || >=95 ZigBee || PV 8.1kW / Akku 14kWh || 2x USV 750W kaskadiert || Creality CR-10 SE 3D-Drucker

            1 Antwort Letzte Antwort
            0
            • BananaJoeB Offline
              BananaJoeB Offline
              BananaJoe
              Most Active
              schrieb am zuletzt editiert von BananaJoe
              #343

              Ich habe hier mal ein Update zur Steuerung meiner Dimstal-Anlage. Die kann ich mit diesem Adapter (oder über den HAM-Weg) zwar abrufen, aber nicht steuern.
              Und zwar habe ich noch eine andere CLI-gefunden welche erheblich(!) schneller reagiert als die midea-beautiful-air-cli die ich in einem Beitrag weiter oben erwähnt (und modifiziert habe):

              https://pypi.org/project/msmart-ng/

              lässt ebenfalls einfach per pip installieren:

              pip install msmart-ng
              

              Ein

              msmart-ng discover
              

              findet auch die Geräte im lokalen Netzwerk. Da diese CLI ohne Zugansdaten zur Cloud auskommt, sieht man in der Ausgabe dann halt keine Gerätenamen. Statt des Discover (welches das wohl auch immer ein neues Token + Key erzeugt) kann man auch die Daten nehmen die man schon von der midea-beautiful-air-cli nutzt.

              Die Steuerung ist ggf. etwas rudimentär, wenn man das in ein eigenes Python-Skript einbindet geht ggf. mehr.
              Ich habe jedenfalls 20 Minuten im Quellcode herumgesucht bis ich den simplen "Power On" bzw. "Power Off" Mechanismus gefunden habe.

              Ich selbe brauche nicht viel mehr als Ein- und Aus, das ginge mit

              msmart-ng control --token c19a404c808656a83c...08f19efc0b6a5 --key d714e6c7ad56...ea32d44776474fb --id 534971451351917 -d 192.168.1.30 power_state=True
              

              oder eben power_state=False

              Temperatur ginge mit

              msmart-ng control --token c19a404c808656a83c...08f19efc0b6a5 --key d714e6c7ad56...ea32d44776474fb --id 534971451351917 -d 192.168.1.30 target_temperature=23
              

              mehrere Parameter lassen sich verbinden.

              Weitere Parameter stehen in den Beispielen auf der Webseite bzw. habe ich mir (wie den korrekten Namen der Power-Funktion) aus dem Quellcode gesucht (ab Zeile 75): https://github.com/mill1000/midea-msmart/blob/main/msmart/device/AC/device.py

              Der Befehl kann auch den Status abfragen, leider ist die Rückgabe vom Format her ein ziemlicher Müll:

              INFO:msmart.lan:Creating new connection to 192.168.1.29:6444.
              INFO:msmart.lan:Authenticating with 192.168.1.29:6444.
              INFO:msmart.lan:Authentication with 192.168.1.29:6444 successful. Expiration: 2024-08-01T23:18:52+00:00, Local key: 95193cc436284c72a20aefd9411d299320e9e6a963e140a8f1f17028d141c83b
              INFO:msmart.cli:Querying device state.
              INFO:msmart.cli:{'ip': '192.168.1.29', 'port': 6444, 'id': 534971917145135, 'online': True, 'supported': True, 'type': <DeviceType.AIR_CONDITIONER: 172>, 'name': None, 'sn': None, 'key': '37c4b...24a16', 'token': '0cfd4e93fdec...9943c49', 'power': False, 'mode': <OperationalMode.COOL: 2>, 'fan_speed': <FanSpeed.AUTO: 102>, 'swing_mode': <SwingMode.BOTH: 15>, 'horizontal_swing_angle': <SwingAngle.OFF: 0>, 'vertical_swing_angle': <SwingAngle.OFF: 0>, 'target_temperature': 22.0, 'indoor_temperature': 25.0, 'outdoor_temperature': 29.2, 'target_humidity': 0, 'indoor_humidity': None, 'eco': False, 'turbo': False, 'freeze_protection': False, 'sleep': False, 'display_on': True, 'beep': False, 'fahrenheit': False, 'filter_alert': False, 'follow_me': False, 'purifier': False, 'self_clean': False, 'total_energy_usage': None, 'current_energy_usage': None, 'real_time_power_usage': None}
              

              Also kein richtiges JSON mit den ' und <> etc, per Suchen und ersetzen habe ich da jedenfalls kein sauberes JSON draus gezaubert.

              Es gäbe - statt der Angabe von --token, --key und --id auch die Möglichkeit einfach --auto anzugeben, dann macht der aber jedes mal ein disovery für die Daten was die Ausführung wieder verzögert.

              ioBroker@Ubuntu 24.04 LTS (VMware) für: >260 Geräte, 5 Switche, 7 AP, 9 IP-Cam, 1 NAS 42TB, 1 ESXi 15TB, 4 Proxmox 1TB, 1 Hyper-V 48TB, 14 x Echo, 5x FireTV, 5 x Tablett/Handy VIS || >=160 Tasmota/Shelly || >=95 ZigBee || PV 8.1kW / Akku 14kWh || 2x USV 750W kaskadiert || Creality CR-10 SE 3D-Drucker

              1 Antwort Letzte Antwort
              0
              • G Offline
                G Offline
                Greenhorn
                schrieb am zuletzt editiert von
                #344

                Hallo,
                vielleicht ließt ja noch jemand mit ;-)
                Ich habe eine Midea Wärmepumpe die mittels Midea SmartHome-App steuerbar ist. Soweit so gut. Ich hätte sie aber gerne im IoBroker, in der Hoffnung dort ein paar mehr Werte zu sehen.
                Nun habe ich den Adapter installiert und mich dort mit UID und Passwort angemeldet aber leider zeigt das log "Login failed, Konto existiert nicht" (?) Die eingebenen Daten sind aber richtig...
                Vielleicht hat jemand einen Tipp woran es liegen könnte?
                Viele Grüße

                BananaJoeB 1 Antwort Letzte Antwort
                0
                • G Greenhorn

                  Hallo,
                  vielleicht ließt ja noch jemand mit ;-)
                  Ich habe eine Midea Wärmepumpe die mittels Midea SmartHome-App steuerbar ist. Soweit so gut. Ich hätte sie aber gerne im IoBroker, in der Hoffnung dort ein paar mehr Werte zu sehen.
                  Nun habe ich den Adapter installiert und mich dort mit UID und Passwort angemeldet aber leider zeigt das log "Login failed, Konto existiert nicht" (?) Die eingebenen Daten sind aber richtig...
                  Vielleicht hat jemand einen Tipp woran es liegen könnte?
                  Viele Grüße

                  BananaJoeB Offline
                  BananaJoeB Offline
                  BananaJoe
                  Most Active
                  schrieb am zuletzt editiert von
                  #345

                  @greenhorn Der Adapter ist für Klimaanlagen, also die "Midea Air" App. Das werden ganz andere Server sein.
                  Also falscher Adapter dafür

                  ioBroker@Ubuntu 24.04 LTS (VMware) für: >260 Geräte, 5 Switche, 7 AP, 9 IP-Cam, 1 NAS 42TB, 1 ESXi 15TB, 4 Proxmox 1TB, 1 Hyper-V 48TB, 14 x Echo, 5x FireTV, 5 x Tablett/Handy VIS || >=160 Tasmota/Shelly || >=95 ZigBee || PV 8.1kW / Akku 14kWh || 2x USV 750W kaskadiert || Creality CR-10 SE 3D-Drucker

                  G 1 Antwort Letzte Antwort
                  0
                  • BananaJoeB BananaJoe

                    @greenhorn Der Adapter ist für Klimaanlagen, also die "Midea Air" App. Das werden ganz andere Server sein.
                    Also falscher Adapter dafür

                    G Offline
                    G Offline
                    Greenhorn
                    schrieb am zuletzt editiert von
                    #346

                    @bananajoe
                    OK, schade, aber trotzdem danke :+1:

                    1 Antwort Letzte Antwort
                    0
                    • BananaJoeB Offline
                      BananaJoeB Offline
                      BananaJoe
                      Most Active
                      schrieb am zuletzt editiert von BananaJoe
                      #347

                      @bananajoe sagte in Test Adapter Midea Dimstal Klimaanlagen v0.0.x:

                      Ich habe hier mal ein Update zur Steuerung meiner Dimstal-Anlage. Die kann ich mit diesem Adapter (oder über den HAM-Weg) zwar abrufen, aber nicht steuern.
                      Und zwar habe ich noch eine andere CLI-gefunden welche erheblich(!) schneller reagiert als die midea-beautiful-air-cli die ich in einem Beitrag weiter oben erwähnt (und modifiziert habe):

                      https://pypi.org/project/msmart-ng/

                      Ich spiel hier mal den Totengräber für meinen eigenen Beitrag:
                      Es gibt eine neuere Version von msmart-ng
                      Beim testen habe ich festgestellt das mein Beispielaufruf falsch ist, das -d ist überflüssig bzw. aktiviert nur den Debug-Modus. Der (vor-)letzte Parameter muss immer die IP-Adresse sein, richtig wäre also:

                      msmart-ng control --token c19a404c808656a83c...08f19efc0b6a5 --key d714e6c7ad56...ea32d44776474fb --id 534971451351917 -192.168.1.30 power_state=True
                      

                      Zudem habe ich entdeckt, das die eingebaute Hilfe mehr bietet als gedacht:

                      msmart-ng query -h
                      

                      liefert die ganzen Parameter für die Abfrage:

                      usage: msmart-ng query [-h] [-d] [--region {DE,KR,US}] [--account ACCOUNT] [--password PASSWORD] [--capabilities] [--auto] [--id DEVICE_ID] [--token TOKEN] [--key KEY] host
                      
                      Query information from a device on the local network.
                      
                      positional arguments:
                        host                 Hostname or IP address of device.
                      
                      options:
                        -h, --help           show this help message and exit
                        -d, --debug          Enable debug logging.
                        --region {DE,KR,US}  Country/region for built-in cloud credential selection.
                        --account ACCOUNT    Manually specify a username for cloud authentication.
                        --password PASSWORD  Manually specify a password for cloud authentication.
                        --capabilities       Query device capabilities instead of state.
                        --auto               Automatically authenticate V3 devices.
                        --id DEVICE_ID       Device ID for V3 devices.
                        --token TOKEN        Authentication token for V3 devices.
                        --key KEY            Authentication key for V3 devices.
                      

                      Dementsprechend liefert

                      msmart-ng control -h
                      

                      die Anleitung zur Steuerung:

                      usage: msmart-ng control [-h] [-d] [--region {DE,KR,US}] [--account ACCOUNT] [--password PASSWORD] [--capabilities] [--auto] [--id DEVICE_ID] [--token TOKEN] [--key KEY]
                                               host setting=value [setting=value ...]
                      
                      Control a device on the local network.
                      
                      positional arguments:
                        host                 Hostname or IP address of device.
                        setting=value        Space separated key-value pairs of settings to control.
                      
                      options:
                        -h, --help           show this help message and exit
                        -d, --debug          Enable debug logging.
                        --region {DE,KR,US}  Country/region for built-in cloud credential selection.
                        --account ACCOUNT    Manually specify a username for cloud authentication.
                        --password PASSWORD  Manually specify a password for cloud authentication.
                        --capabilities       Query device capabilities before sending commands.
                        --auto               Automatically authenticate V3 devices.
                        --id DEVICE_ID       Device ID for V3 devices.
                        --token TOKEN        Authentication token for V3 devices.
                        --key KEY            Authentication key for V3 devices.
                      

                      Da ich das ganze aus ioBroker-Skripts heraus startet, habe ich dafür ein eigenes Environment für den Benutzer ioBroker eingerichtet, in der Bash per SSH:
                      Zum Benutzer ioBroker wechseln:

                      sudo -u iobroker /usr/bin/bash
                      

                      In das Home-Verzeichnis des Benutzers ioBroker wechseln

                      cd ~
                      

                      Python Environment anlegen (falls noch nicht vorhanden):

                      python3 -m venv python-venv
                      

                      und in die Umgebung wechseln:

                      source python-venv/bin/activate
                      

                      Jetzt kann man per pip das Modul installieren

                      pip install msmart-ng
                      

                      und dann per

                      msmart-ng
                      

                      Nutzen. Vor der Nutzung muss dann aber immer erst das Envirtonment geladen werden.
                      Intelligenter weise wird das in den nachinstallierten Python-Modulen gleich richtig hinterlegt:

                      which msmart-ng
                      

                      Ausgabe:

                      /home/iobroker/python-venv/bin/msmart-ng
                      

                      Inhalt:

                      cat /home/iobroker/python-venv/bin/msmart-ng
                      

                      Die erste Zeile ist

                      #!/home/iobroker/python-venv/bin/python3
                      

                      Womit die richtige Umgebung genutzt wird.
                      In euren ioBroker Skripten müsst Ihr dann z.B. im Exec Block von Blockly beim Befehl Parameter den ganzen Pfad aufrufen:

                      /home/iobroker/python-venv/bin/msmart-ng
                      

                      ioBroker@Ubuntu 24.04 LTS (VMware) für: >260 Geräte, 5 Switche, 7 AP, 9 IP-Cam, 1 NAS 42TB, 1 ESXi 15TB, 4 Proxmox 1TB, 1 Hyper-V 48TB, 14 x Echo, 5x FireTV, 5 x Tablett/Handy VIS || >=160 Tasmota/Shelly || >=95 ZigBee || PV 8.1kW / Akku 14kWh || 2x USV 750W kaskadiert || Creality CR-10 SE 3D-Drucker

                      1 Antwort Letzte Antwort
                      0
                      • U Offline
                        U Offline
                        uweabc
                        schrieb am zuletzt editiert von Homoran
                        #348

                        Ich habe vor einiger Zeit mal ein JavaScript für msmart-ng gebastelt. Dies habe ich mit den Erkenntnissen von BananaJoe neu überarbeitet. Anbei das JavaScript. midea.js

                        Steuert eine Midea-Klimaanlage direkt über das Python-Programm 'msmart-ng' lokal im WLAN.

                        Das Gerät wurde einmalig mit der Android-App in das WLAN integriert.
                        Anschließend wurde der Internetzugang für diese Gerät über die FritzBox deaktiviert, um eine Fremdsteuerung zu unterbinden.
                        Keine Cloud erforderlich für dieses JavaScript!

                        Dieses JavaScript übernimmt folgende Funktionen:
                        - Es liest die aktuellen Werte des Geräts im lokalen Netzwerk ab, siehe dazu Variable 'mideaPortaSplit'.
                        Variable 'mideaPortaSplit' muss entsprechend geändert werden. Dazu id, ip, token und key entsprechend ändern.
                        - Es erstellt eigenständig die passenden Objekte in ioBroker (unter javascript.0.midea.*).
                        - Wird ein schreibbares Objekt geändert, so schreibt das JavaScript die Änderung direkt ins Gerät,
                        indem es die Befehle über 'msmart-ng' sendet.
                        Gültige Werte für FanSpeed / OperationalMode / SwingMode / SwingAngle / RateSelect / BreezeMode / AuxHeatMode
                        siehe Variable 'AirConditioner'.
                        - Der Loglevel (javascript.0.media.loglevel) kann während der Laufzeit des Skripts angepasst werden.
                        Mögliche Werte sind 0=aus, 1=minimal, 2=alles.

                        BananaJoeB HomoranH 2 Antworten Letzte Antwort
                        0
                        • U uweabc

                          Ich habe vor einiger Zeit mal ein JavaScript für msmart-ng gebastelt. Dies habe ich mit den Erkenntnissen von BananaJoe neu überarbeitet. Anbei das JavaScript. midea.js

                          Steuert eine Midea-Klimaanlage direkt über das Python-Programm 'msmart-ng' lokal im WLAN.

                          Das Gerät wurde einmalig mit der Android-App in das WLAN integriert.
                          Anschließend wurde der Internetzugang für diese Gerät über die FritzBox deaktiviert, um eine Fremdsteuerung zu unterbinden.
                          Keine Cloud erforderlich für dieses JavaScript!

                          Dieses JavaScript übernimmt folgende Funktionen:
                          - Es liest die aktuellen Werte des Geräts im lokalen Netzwerk ab, siehe dazu Variable 'mideaPortaSplit'.
                          Variable 'mideaPortaSplit' muss entsprechend geändert werden. Dazu id, ip, token und key entsprechend ändern.
                          - Es erstellt eigenständig die passenden Objekte in ioBroker (unter javascript.0.midea.*).
                          - Wird ein schreibbares Objekt geändert, so schreibt das JavaScript die Änderung direkt ins Gerät,
                          indem es die Befehle über 'msmart-ng' sendet.
                          Gültige Werte für FanSpeed / OperationalMode / SwingMode / SwingAngle / RateSelect / BreezeMode / AuxHeatMode
                          siehe Variable 'AirConditioner'.
                          - Der Loglevel (javascript.0.media.loglevel) kann während der Laufzeit des Skripts angepasst werden.
                          Mögliche Werte sind 0=aus, 1=minimal, 2=alles.

                          BananaJoeB Offline
                          BananaJoeB Offline
                          BananaJoe
                          Most Active
                          schrieb am zuletzt editiert von
                          #349

                          @uweabc

                          ist die Verwendung von Apostophen statt Hochkommas Absicht?
                          Zeile 163 und folgend,
                          Zeile 173
                          Zeile 196
                          ???

                          ioBroker@Ubuntu 24.04 LTS (VMware) für: >260 Geräte, 5 Switche, 7 AP, 9 IP-Cam, 1 NAS 42TB, 1 ESXi 15TB, 4 Proxmox 1TB, 1 Hyper-V 48TB, 14 x Echo, 5x FireTV, 5 x Tablett/Handy VIS || >=160 Tasmota/Shelly || >=95 ZigBee || PV 8.1kW / Akku 14kWh || 2x USV 750W kaskadiert || Creality CR-10 SE 3D-Drucker

                          U 1 Antwort Letzte Antwort
                          0
                          • U uweabc

                            Ich habe vor einiger Zeit mal ein JavaScript für msmart-ng gebastelt. Dies habe ich mit den Erkenntnissen von BananaJoe neu überarbeitet. Anbei das JavaScript. midea.js

                            Steuert eine Midea-Klimaanlage direkt über das Python-Programm 'msmart-ng' lokal im WLAN.

                            Das Gerät wurde einmalig mit der Android-App in das WLAN integriert.
                            Anschließend wurde der Internetzugang für diese Gerät über die FritzBox deaktiviert, um eine Fremdsteuerung zu unterbinden.
                            Keine Cloud erforderlich für dieses JavaScript!

                            Dieses JavaScript übernimmt folgende Funktionen:
                            - Es liest die aktuellen Werte des Geräts im lokalen Netzwerk ab, siehe dazu Variable 'mideaPortaSplit'.
                            Variable 'mideaPortaSplit' muss entsprechend geändert werden. Dazu id, ip, token und key entsprechend ändern.
                            - Es erstellt eigenständig die passenden Objekte in ioBroker (unter javascript.0.midea.*).
                            - Wird ein schreibbares Objekt geändert, so schreibt das JavaScript die Änderung direkt ins Gerät,
                            indem es die Befehle über 'msmart-ng' sendet.
                            Gültige Werte für FanSpeed / OperationalMode / SwingMode / SwingAngle / RateSelect / BreezeMode / AuxHeatMode
                            siehe Variable 'AirConditioner'.
                            - Der Loglevel (javascript.0.media.loglevel) kann während der Laufzeit des Skripts angepasst werden.
                            Mögliche Werte sind 0=aus, 1=minimal, 2=alles.

                            HomoranH Nicht stören
                            HomoranH Nicht stören
                            Homoran
                            Global Moderator Administrators
                            schrieb am zuletzt editiert von
                            #350

                            @uweabc bitte das Script nicht als Datei/Link posten.
                            Hier in code-tags einstellen!

                            kein Support per PN! - Fragen im Forum stellen - es gibt fast nichts, was nicht auch für andere interessant ist.

                            Benutzt das Voting rechts unten im Beitrag wenn er euch geholfen hat.

                            der Installationsfixer: curl -fsL https://iobroker.net/fix.sh | bash -

                            U 1 Antwort Letzte Antwort
                            0
                            • HomoranH Homoran

                              @uweabc bitte das Script nicht als Datei/Link posten.
                              Hier in code-tags einstellen!

                              U Offline
                              U Offline
                              uweabc
                              schrieb am zuletzt editiert von uweabc
                              #351

                              @homoran
                              Danke für den Hinweis. Ich bin da vorsichtig. Leider ändert der code-tag den Sourcecode an manchen Stellen, also der gibt den Code nicht 1:1 wieder der eingeben wurde.

                              1 Antwort Letzte Antwort
                              0
                              • BananaJoeB BananaJoe

                                @uweabc

                                ist die Verwendung von Apostophen statt Hochkommas Absicht?
                                Zeile 163 und folgend,
                                Zeile 173
                                Zeile 196
                                ???

                                U Offline
                                U Offline
                                uweabc
                                schrieb am zuletzt editiert von uweabc
                                #352

                                @bananajoe
                                @BananaJoe
                                Ja, das ist die normale Formatierung bei JavaScript mit Variablen.
                                Zur Sicherheit nochmal hier den Code mit leichten Verbesserungen (leider ändert der code-tag den Sourcecode, also die {1} ignorieren!):

                                /*
                                    Steuert eine Midea-Klimaanlage direkt über das Python-Programm 'msmart-ng' (siehe unten Installation 'msmart-ng') lokal im WLAN.
                                    
                                    Das Gerät wurde einmalig mit der Android-App in das WLAN integriert. 
                                    Anschließend wurde der Internetzugang für diese Gerät über die FritzBox deaktiviert, um eine Fremdsteuerung zu unterbinden.
                                    Keine Cloud erforderlich für dieses JavaScript!
                                
                                    Dieses JavaScript übernimmt folgende Funktionen:  
                                    - Es liest die aktuellen Werte des Geräts im lokalen Netzwerk ab, siehe dazu Variable 'mideaPortaSplit'.  
                                      Variable 'mideaPortaSplit' muss entsprechend geändert werden. Dazu id, ip, token und key entsprechend ändern.
                                    - Es erstellt eigenständig die passenden Objekte in ioBroker (unter javascript.0.midea.*).  
                                    - Wird ein schreibbares Objekt geändert, so schreibt das JavaScript die Änderung direkt ins Gerät, 
                                      indem es die Befehle über 'msmart-ng' sendet.
                                      Gültige Werte für FanSpeed / OperationalMode / SwingMode / SwingAngle / RateSelect / BreezeMode / AuxHeatMode
                                      siehe Variable 'AirConditioner'.
                                    - Der Loglevel (javascript.0.media.loglevel) kann während der Laufzeit des Skripts angepasst werden. 
                                      Mögliche Werte sind 0=aus, 1=minimal, 2=alles.
                                
                                    Idee abgeleitet aus den Beitrag: https://forum.iobroker.net/topic/33198/test-adapter-midea-dimstal-klimaanlagen-v0-0-x/346?lang=de
                                
                                    Installation 'msmart-ng':
                                    =========================
                                    Zum Benutzer ioBroker wechseln:
                                        sudo -u iobroker /usr/bin/bash
                                    In das Home-Verzeichnis des Benutzers ioBroker wechseln
                                        cd ~
                                    Python Environment anlegen (falls noch nicht vorhanden):
                                        python3 -m venv python-venv
                                    und in die Umgebung wechseln:
                                        source python-venv/bin/activate
                                    Jetzt kann man per pip das Modul installieren
                                        pip install msmart-ng
                                    und dann per
                                        msmart-ng
                                    Nutzen. Vor der Nutzung muss dann aber immer erst das Envirtonment geladen werden.
                                    Intelligenter weise wird das in den nachinstallierten Python-Modulen gleich richtig hinterlegt:
                                        which msmart-ng
                                    Ausgabe:
                                        /home/iobroker/python-venv/bin/msmart-ng
                                    Inhalt:
                                        cat /home/iobroker/python-venv/bin/msmart-ng
                                    Die erste Zeile ist
                                        #!/home/iobroker/python-venv/bin/python3
                                    Womit die richtige Umgebung genutzt wird.
                                    In ioBroker Skripten den ganzen Pfad aufrufen:
                                        /home/iobroker/python-venv/bin/msmart-ng
                                */
                                
                                // id + token + key ermittelbar über 'msmart-ng query --region DE --auto 192.168.178.205'
                                const mideaPortaSplit = { 
                                    ip: '192.168.178.205',
                                    id: '999832117233304',
                                    token: 'BadBad132c05bab57aad3833ce247729d2f880e6fd5b8e1d2ca0eec82395d7edb85cf70d339faf7d0c8baf3b8275d86b183d430347bae6eba4a009cb38d1147f',
                                    key: 'BadBadc06c854aa6ba7b200174327ed7fc9fb0fd0032407992403b9e4104c1d3',
                                    controlSettings: [], // temp. Speicher für alle änderbaren Objekte, für on({id: device.controlSettings, change: 'any'}...
                                };
                                
                                const basePath = 'javascript.0.midea'; // Basis-Objektpfad
                                var LOGLEVEL = 2; // 0=aus, 1=minimal, 2=alles
                                const msmartLoglevel = basePath + '.loglevel';
                                const region = 'DE'; // --region {DE,KR,US}
                                const msmart_ng = '/home/iobroker/python-venv/bin/msmart-ng';
                                
                                // enums siehe https://github.com/mill1000/midea-msmart/blob/main/msmart/device/AC/device.py
                                class AirConditioner {
                                    static FanSpeed = {
                                        AUTO: 102,
                                        MAX: 100,
                                        HIGH: 80,
                                        MEDIUM: 60,
                                        LOW: 40,
                                        SILENT: 20,
                                        DEFAULT: 102
                                    };
                                
                                    static OperationalMode = {
                                        AUTO: 1,
                                        COOL: 2,
                                        DRY: 3,
                                        HEAT: 4,
                                        FAN_ONLY: 5,
                                        SMART_DRY: 6,
                                        DEFAULT: 5
                                    };
                                
                                    static SwingMode = {
                                        OFF: 0x0,
                                        VERTICAL: 0xC,
                                        HORIZONTAL: 0x3,
                                        BOTH: 0xF,
                                        DEFAULT: 0
                                    };
                                
                                    static SwingAngle = {
                                        OFF: 0,
                                        POS_1: 1,
                                        POS_2: 25,
                                        POS_3: 50,
                                        POS_4: 75,
                                        POS_5: 100,
                                        DEFAULT: 0
                                    };
                                
                                    static RateSelect = {
                                        OFF: 100,
                                        GEAR_50: 50,
                                        GEAR_75: 75,
                                        LEVEL_1: 1,
                                        LEVEL_2: 20,
                                        LEVEL_3: 40,
                                        LEVEL_4: 60,
                                        LEVEL_5: 80,
                                        DEFAULT: 100
                                    };
                                
                                    static BreezeMode = {
                                        OFF: 1,
                                        BREEZE_AWAY: 2,
                                        BREEZE_MILD: 3,
                                        BREEZELESS: 4,
                                        DEFAULT: 1
                                    };
                                
                                    static AuxHeatMode = {
                                        OFF: 0,
                                        AUX_HEAT: 1,
                                        AUX_ONLY: 2,
                                        DEFAULT: 0
                                    };
                                }
                                
                                function convertToValidJSON(str) {
                                    str = str.replace(/<[^>]*:\s*(\d+)>/g, '$1'); // Entfernt alles in <...>, Zahl nach : bleibt erhalten
                                    str = str.replace(/\bNone\b/g, 'null'); // Ersetzt 'None' durch null
                                    str = str.replace(/'/g, '"'); // Optional: Ersetze einzelne Anführungszeichen durch doppelte
                                    str = str.replace(/\bTrue\b/g, 'true').replace(/\bFalse\b/g, 'false'); // Ersetze True/False durch true/false
                                    str = str.replace('"power"', '"power_state"'); // Korrektur power control
                                    return str;
                                }
                                
                                function extractJsonFromLine(line) {
                                    const index = line.indexOf('{');
                                    if (index !== -1) {
                                        try {
                                            const jsonStr = convertToValidJSON(line.substring(index));
                                            if (LOGLEVEL > 1) log(jsonStr);
                                            return JSON.parse(jsonStr);
                                        } catch (e) {
                                            console.error('JSON konnte nicht geparst werden' + e);
                                            return null;
                                        }
                                    }
                                    return null;
                                }
                                
                                // msmart-ng query 
                                // usage: msmart-ng query [-h] [-d] [--region {DE,KR,US}] [--account ACCOUNT] [--password PASSWORD] [--capabilities] 
                                //                        [--auto] 
                                //                        [--id DEVICE_ID] [--token TOKEN] [--key KEY]
                                //                        host
                                function queryDevice(device) {
                                    const queryMsmart = msmart_ng +
                                        ' query' + 
                                        ` --region ${region}` +
                                        ` --token ${device.token}` +
                                        ` --key ${device.key}` +
                                        ` --id ${device.id}` +
                                        ` ${device.ip}`;
                                
                                    if (LOGLEVEL > 1) log(queryMsmart);
                                
                                    exec(queryMsmart, (error, stdout, stderr) => {
                                        if (error) {
                                            console.error(`Fehler beim Ausführen: ${error}`);
                                            return;
                                        }
                                
                                        // Funktion, um nach JSON zu suchen
                                        [stdout, stderr].forEach(output => {
                                            const lines = output.split('\n');
                                            for (let line of lines) {
                                                if (line.includes('INFO:msmart.cli:')) {
                                                    const data = extractJsonFromLine(line);
                                                    if (data) {
                                                        handleData(device, data);
                                                        break; // nur die erste gefundene JSON-Zeile
                                                    }
                                                }
                                            }
                                        });
                                    });
                                }
                                
                                function handleData(device, data) {
                                    const installOnControlSettings = (device.controlSettings.length == 0);
                                    const id = data.id ? data.id.toString() : 'device';
                                    const devicePath = `${basePath}.${id}`;
                                
                                    Object.keys(data).forEach(key => {
                                        var keyL = key.toLowerCase();
                                        if (keyL === 'id') return;
                                        if (keyL === 'sn') return;
                                        if (keyL === 'key') return;
                                        if (keyL === 'token') return;
                                        
                                        const value = data[key];
                                        const statePath = `${devicePath}.${key}`;
                                
                                        // Konfiguration für createState
                                        var isControl = true;
                                        if ((keyL === 'ip') ||
                                            (keyL === 'online') ||
                                            (keyL === 'port') ||
                                            (keyL === 'type') ||
                                            (keyL === 'name')) {
                                            isControl = false;
                                        }
                                        const stateOptions = {
                                            type: typeof value,
                                            name: key,
                                            read: true,
                                        };
                                
                                        // Zusätzliche Eigenschaften basierend auf dem Schlüssel
                                        if (typeof value !== 'boolean') {
                                            if (keyL.includes('temperature')) {
                                                stateOptions.unit = '°C';
                                                stateOptions.role = 'value.temperature';
                                                stateOptions.type = 'number';
                                                if (!keyL.includes('target_'))
                                                    isControl = false;
                                            } else if (keyL.includes('humidity')) {
                                                stateOptions.unit = '%';
                                                stateOptions.role = 'value.humidity';
                                                stateOptions.min = 0;
                                                stateOptions.max = 100;
                                                stateOptions.type = 'number';
                                                if (!keyL.includes('target_'))
                                                    isControl = false;
                                            } else if (keyL.includes('energy')) {
                                                stateOptions.unit = 'Wh';
                                                stateOptions.min = 0;
                                                stateOptions.max = 999999999;
                                                stateOptions.type = 'number';
                                                isControl = false;
                                            } else if (keyL.includes('power')) {
                                                stateOptions.unit = 'W';
                                                stateOptions.role = 'value.power';
                                                stateOptions.min = 0;
                                                stateOptions.max = 4000;
                                                stateOptions.type = 'number';
                                                isControl = false;
                                            }
                                        }
                                        stateOptions.write = isControl;
                                        if (value != null) stateOptions.def = value;
                                
                                        // State erstellen, falls nicht vorhanden
                                        createState(statePath, stateOptions, () => {
                                            // Nach Erstellung Wert holen und ggf aktualisieren
                                            getState(statePath, (err, state) => {
                                                if (err || !state) {
                                                    setState(statePath, value, true);
                                                } else {
                                                    if (state.val !== value) {
                                                        if (LOGLEVEL > 1) log(`${statePath}:${value}`);
                                                        setState(statePath, value, true);
                                                    }
                                                }
                                            });
                                        });
                                        if (installOnControlSettings && 
                                            stateOptions.write && 
                                            !device.controlSettings.includes(statePath)) {
                                            device.controlSettings.push(statePath);
                                        }
                                    });
                                    if (installOnControlSettings) {
                                        // Events
                                        on({id: device.controlSettings, change: 'any'}, function (obj) {
                                            if (obj.state.ack) return; // Diese Änderung wurde vom Skript selbst gemacht, ignorieren
                                            if (LOGLEVEL > 0) log(`geändert ${obj.id} auf ${obj.state.val}`);
                                            var parts = obj.id.split('.');
                                            controlDevice(device, parts[4] ,obj.state.val);
                                        });
                                    }
                                }
                                
                                // msmart-ng control
                                // usage: msmart-ng control [-h] [-d] [--region {DE,KR,US}] [--account ACCOUNT] [--password PASSWORD] 
                                //                          [--capabilities] 
                                //                          [--auto] 
                                //                          [--id DEVICE_ID] [--token TOKEN] [--key KEY]
                                //                          host setting=value [setting=value ...]
                                function controlDevice(device, setting, value) {
                                    if (LOGLEVEL > 0) log(`control ${device.id}, setting ${setting}=${value}`);
                                
                                    var pyValue = value;
                                    if (typeof pyValue == 'boolean') {
                                        pyValue = value == true ? 'True':'False';
                                    }
                                
                                    const controlMsmart = msmart_ng +
                                        ' control' +
                                        ` --region ${region}` +
                                        ` --token ${device.token}` +
                                        ` --key ${device.key}` +
                                        ` --id ${device.id}` +
                                        ` ${device.ip}` +
                                        ` ${setting}=${pyValue}`;
                                
                                    if (LOGLEVEL > 1) log(controlMsmart);
                                
                                    exec(controlMsmart, (error, stdout, stderr) => {
                                        if (error) {
                                            console.error(`Fehler beim Ausführen: ${error}`);
                                            return;
                                        }
                                
                                        // Funktion, um nach JSON zu suchen
                                        [stdout, stderr].forEach(output => {
                                            if (output.includes('ERROR:')) {
                                                console.error(`Fehler beim Ausführen: ${output}`);
                                            }
                                        });
                                    });
                                }
                                
                                function initVar() {
                                    createState(msmartLoglevel, undefined, false, {
                                        name: 'Loglevel',
                                        type: 'number',
                                        def: LOGLEVEL,
                                        role: 'state'
                                    });
                                    LOGLEVEL = getState(msmartLoglevel).val;
                                }
                                
                                // Main:
                                initVar();
                                queryDevice(mideaPortaSplit);
                                schedule("*/5 * * * *", function () { // alle 5 Minuten
                                    queryDevice(mideaPortaSplit); 
                                });
                                
                                // Events:
                                on({id: msmartLoglevel, change: 'any'}, function (obj) {
                                    // Loglevel geändert
                                    log(`msmartLoglevel ist ${obj.state.val}`);
                                    LOGLEVEL = obj.state.val;
                                });
                                
                                
                                BananaJoeB 1 Antwort Letzte Antwort
                                0
                                • U uweabc

                                  @bananajoe
                                  @BananaJoe
                                  Ja, das ist die normale Formatierung bei JavaScript mit Variablen.
                                  Zur Sicherheit nochmal hier den Code mit leichten Verbesserungen (leider ändert der code-tag den Sourcecode, also die {1} ignorieren!):

                                  /*
                                      Steuert eine Midea-Klimaanlage direkt über das Python-Programm 'msmart-ng' (siehe unten Installation 'msmart-ng') lokal im WLAN.
                                      
                                      Das Gerät wurde einmalig mit der Android-App in das WLAN integriert. 
                                      Anschließend wurde der Internetzugang für diese Gerät über die FritzBox deaktiviert, um eine Fremdsteuerung zu unterbinden.
                                      Keine Cloud erforderlich für dieses JavaScript!
                                  
                                      Dieses JavaScript übernimmt folgende Funktionen:  
                                      - Es liest die aktuellen Werte des Geräts im lokalen Netzwerk ab, siehe dazu Variable 'mideaPortaSplit'.  
                                        Variable 'mideaPortaSplit' muss entsprechend geändert werden. Dazu id, ip, token und key entsprechend ändern.
                                      - Es erstellt eigenständig die passenden Objekte in ioBroker (unter javascript.0.midea.*).  
                                      - Wird ein schreibbares Objekt geändert, so schreibt das JavaScript die Änderung direkt ins Gerät, 
                                        indem es die Befehle über 'msmart-ng' sendet.
                                        Gültige Werte für FanSpeed / OperationalMode / SwingMode / SwingAngle / RateSelect / BreezeMode / AuxHeatMode
                                        siehe Variable 'AirConditioner'.
                                      - Der Loglevel (javascript.0.media.loglevel) kann während der Laufzeit des Skripts angepasst werden. 
                                        Mögliche Werte sind 0=aus, 1=minimal, 2=alles.
                                  
                                      Idee abgeleitet aus den Beitrag: https://forum.iobroker.net/topic/33198/test-adapter-midea-dimstal-klimaanlagen-v0-0-x/346?lang=de
                                  
                                      Installation 'msmart-ng':
                                      =========================
                                      Zum Benutzer ioBroker wechseln:
                                          sudo -u iobroker /usr/bin/bash
                                      In das Home-Verzeichnis des Benutzers ioBroker wechseln
                                          cd ~
                                      Python Environment anlegen (falls noch nicht vorhanden):
                                          python3 -m venv python-venv
                                      und in die Umgebung wechseln:
                                          source python-venv/bin/activate
                                      Jetzt kann man per pip das Modul installieren
                                          pip install msmart-ng
                                      und dann per
                                          msmart-ng
                                      Nutzen. Vor der Nutzung muss dann aber immer erst das Envirtonment geladen werden.
                                      Intelligenter weise wird das in den nachinstallierten Python-Modulen gleich richtig hinterlegt:
                                          which msmart-ng
                                      Ausgabe:
                                          /home/iobroker/python-venv/bin/msmart-ng
                                      Inhalt:
                                          cat /home/iobroker/python-venv/bin/msmart-ng
                                      Die erste Zeile ist
                                          #!/home/iobroker/python-venv/bin/python3
                                      Womit die richtige Umgebung genutzt wird.
                                      In ioBroker Skripten den ganzen Pfad aufrufen:
                                          /home/iobroker/python-venv/bin/msmart-ng
                                  */
                                  
                                  // id + token + key ermittelbar über 'msmart-ng query --region DE --auto 192.168.178.205'
                                  const mideaPortaSplit = { 
                                      ip: '192.168.178.205',
                                      id: '999832117233304',
                                      token: 'BadBad132c05bab57aad3833ce247729d2f880e6fd5b8e1d2ca0eec82395d7edb85cf70d339faf7d0c8baf3b8275d86b183d430347bae6eba4a009cb38d1147f',
                                      key: 'BadBadc06c854aa6ba7b200174327ed7fc9fb0fd0032407992403b9e4104c1d3',
                                      controlSettings: [], // temp. Speicher für alle änderbaren Objekte, für on({id: device.controlSettings, change: 'any'}...
                                  };
                                  
                                  const basePath = 'javascript.0.midea'; // Basis-Objektpfad
                                  var LOGLEVEL = 2; // 0=aus, 1=minimal, 2=alles
                                  const msmartLoglevel = basePath + '.loglevel';
                                  const region = 'DE'; // --region {DE,KR,US}
                                  const msmart_ng = '/home/iobroker/python-venv/bin/msmart-ng';
                                  
                                  // enums siehe https://github.com/mill1000/midea-msmart/blob/main/msmart/device/AC/device.py
                                  class AirConditioner {
                                      static FanSpeed = {
                                          AUTO: 102,
                                          MAX: 100,
                                          HIGH: 80,
                                          MEDIUM: 60,
                                          LOW: 40,
                                          SILENT: 20,
                                          DEFAULT: 102
                                      };
                                  
                                      static OperationalMode = {
                                          AUTO: 1,
                                          COOL: 2,
                                          DRY: 3,
                                          HEAT: 4,
                                          FAN_ONLY: 5,
                                          SMART_DRY: 6,
                                          DEFAULT: 5
                                      };
                                  
                                      static SwingMode = {
                                          OFF: 0x0,
                                          VERTICAL: 0xC,
                                          HORIZONTAL: 0x3,
                                          BOTH: 0xF,
                                          DEFAULT: 0
                                      };
                                  
                                      static SwingAngle = {
                                          OFF: 0,
                                          POS_1: 1,
                                          POS_2: 25,
                                          POS_3: 50,
                                          POS_4: 75,
                                          POS_5: 100,
                                          DEFAULT: 0
                                      };
                                  
                                      static RateSelect = {
                                          OFF: 100,
                                          GEAR_50: 50,
                                          GEAR_75: 75,
                                          LEVEL_1: 1,
                                          LEVEL_2: 20,
                                          LEVEL_3: 40,
                                          LEVEL_4: 60,
                                          LEVEL_5: 80,
                                          DEFAULT: 100
                                      };
                                  
                                      static BreezeMode = {
                                          OFF: 1,
                                          BREEZE_AWAY: 2,
                                          BREEZE_MILD: 3,
                                          BREEZELESS: 4,
                                          DEFAULT: 1
                                      };
                                  
                                      static AuxHeatMode = {
                                          OFF: 0,
                                          AUX_HEAT: 1,
                                          AUX_ONLY: 2,
                                          DEFAULT: 0
                                      };
                                  }
                                  
                                  function convertToValidJSON(str) {
                                      str = str.replace(/<[^>]*:\s*(\d+)>/g, '$1'); // Entfernt alles in <...>, Zahl nach : bleibt erhalten
                                      str = str.replace(/\bNone\b/g, 'null'); // Ersetzt 'None' durch null
                                      str = str.replace(/'/g, '"'); // Optional: Ersetze einzelne Anführungszeichen durch doppelte
                                      str = str.replace(/\bTrue\b/g, 'true').replace(/\bFalse\b/g, 'false'); // Ersetze True/False durch true/false
                                      str = str.replace('"power"', '"power_state"'); // Korrektur power control
                                      return str;
                                  }
                                  
                                  function extractJsonFromLine(line) {
                                      const index = line.indexOf('{');
                                      if (index !== -1) {
                                          try {
                                              const jsonStr = convertToValidJSON(line.substring(index));
                                              if (LOGLEVEL > 1) log(jsonStr);
                                              return JSON.parse(jsonStr);
                                          } catch (e) {
                                              console.error('JSON konnte nicht geparst werden' + e);
                                              return null;
                                          }
                                      }
                                      return null;
                                  }
                                  
                                  // msmart-ng query 
                                  // usage: msmart-ng query [-h] [-d] [--region {DE,KR,US}] [--account ACCOUNT] [--password PASSWORD] [--capabilities] 
                                  //                        [--auto] 
                                  //                        [--id DEVICE_ID] [--token TOKEN] [--key KEY]
                                  //                        host
                                  function queryDevice(device) {
                                      const queryMsmart = msmart_ng +
                                          ' query' + 
                                          ` --region ${region}` +
                                          ` --token ${device.token}` +
                                          ` --key ${device.key}` +
                                          ` --id ${device.id}` +
                                          ` ${device.ip}`;
                                  
                                      if (LOGLEVEL > 1) log(queryMsmart);
                                  
                                      exec(queryMsmart, (error, stdout, stderr) => {
                                          if (error) {
                                              console.error(`Fehler beim Ausführen: ${error}`);
                                              return;
                                          }
                                  
                                          // Funktion, um nach JSON zu suchen
                                          [stdout, stderr].forEach(output => {
                                              const lines = output.split('\n');
                                              for (let line of lines) {
                                                  if (line.includes('INFO:msmart.cli:')) {
                                                      const data = extractJsonFromLine(line);
                                                      if (data) {
                                                          handleData(device, data);
                                                          break; // nur die erste gefundene JSON-Zeile
                                                      }
                                                  }
                                              }
                                          });
                                      });
                                  }
                                  
                                  function handleData(device, data) {
                                      const installOnControlSettings = (device.controlSettings.length == 0);
                                      const id = data.id ? data.id.toString() : 'device';
                                      const devicePath = `${basePath}.${id}`;
                                  
                                      Object.keys(data).forEach(key => {
                                          var keyL = key.toLowerCase();
                                          if (keyL === 'id') return;
                                          if (keyL === 'sn') return;
                                          if (keyL === 'key') return;
                                          if (keyL === 'token') return;
                                          
                                          const value = data[key];
                                          const statePath = `${devicePath}.${key}`;
                                  
                                          // Konfiguration für createState
                                          var isControl = true;
                                          if ((keyL === 'ip') ||
                                              (keyL === 'online') ||
                                              (keyL === 'port') ||
                                              (keyL === 'type') ||
                                              (keyL === 'name')) {
                                              isControl = false;
                                          }
                                          const stateOptions = {
                                              type: typeof value,
                                              name: key,
                                              read: true,
                                          };
                                  
                                          // Zusätzliche Eigenschaften basierend auf dem Schlüssel
                                          if (typeof value !== 'boolean') {
                                              if (keyL.includes('temperature')) {
                                                  stateOptions.unit = '°C';
                                                  stateOptions.role = 'value.temperature';
                                                  stateOptions.type = 'number';
                                                  if (!keyL.includes('target_'))
                                                      isControl = false;
                                              } else if (keyL.includes('humidity')) {
                                                  stateOptions.unit = '%';
                                                  stateOptions.role = 'value.humidity';
                                                  stateOptions.min = 0;
                                                  stateOptions.max = 100;
                                                  stateOptions.type = 'number';
                                                  if (!keyL.includes('target_'))
                                                      isControl = false;
                                              } else if (keyL.includes('energy')) {
                                                  stateOptions.unit = 'Wh';
                                                  stateOptions.min = 0;
                                                  stateOptions.max = 999999999;
                                                  stateOptions.type = 'number';
                                                  isControl = false;
                                              } else if (keyL.includes('power')) {
                                                  stateOptions.unit = 'W';
                                                  stateOptions.role = 'value.power';
                                                  stateOptions.min = 0;
                                                  stateOptions.max = 4000;
                                                  stateOptions.type = 'number';
                                                  isControl = false;
                                              }
                                          }
                                          stateOptions.write = isControl;
                                          if (value != null) stateOptions.def = value;
                                  
                                          // State erstellen, falls nicht vorhanden
                                          createState(statePath, stateOptions, () => {
                                              // Nach Erstellung Wert holen und ggf aktualisieren
                                              getState(statePath, (err, state) => {
                                                  if (err || !state) {
                                                      setState(statePath, value, true);
                                                  } else {
                                                      if (state.val !== value) {
                                                          if (LOGLEVEL > 1) log(`${statePath}:${value}`);
                                                          setState(statePath, value, true);
                                                      }
                                                  }
                                              });
                                          });
                                          if (installOnControlSettings && 
                                              stateOptions.write && 
                                              !device.controlSettings.includes(statePath)) {
                                              device.controlSettings.push(statePath);
                                          }
                                      });
                                      if (installOnControlSettings) {
                                          // Events
                                          on({id: device.controlSettings, change: 'any'}, function (obj) {
                                              if (obj.state.ack) return; // Diese Änderung wurde vom Skript selbst gemacht, ignorieren
                                              if (LOGLEVEL > 0) log(`geändert ${obj.id} auf ${obj.state.val}`);
                                              var parts = obj.id.split('.');
                                              controlDevice(device, parts[4] ,obj.state.val);
                                          });
                                      }
                                  }
                                  
                                  // msmart-ng control
                                  // usage: msmart-ng control [-h] [-d] [--region {DE,KR,US}] [--account ACCOUNT] [--password PASSWORD] 
                                  //                          [--capabilities] 
                                  //                          [--auto] 
                                  //                          [--id DEVICE_ID] [--token TOKEN] [--key KEY]
                                  //                          host setting=value [setting=value ...]
                                  function controlDevice(device, setting, value) {
                                      if (LOGLEVEL > 0) log(`control ${device.id}, setting ${setting}=${value}`);
                                  
                                      var pyValue = value;
                                      if (typeof pyValue == 'boolean') {
                                          pyValue = value == true ? 'True':'False';
                                      }
                                  
                                      const controlMsmart = msmart_ng +
                                          ' control' +
                                          ` --region ${region}` +
                                          ` --token ${device.token}` +
                                          ` --key ${device.key}` +
                                          ` --id ${device.id}` +
                                          ` ${device.ip}` +
                                          ` ${setting}=${pyValue}`;
                                  
                                      if (LOGLEVEL > 1) log(controlMsmart);
                                  
                                      exec(controlMsmart, (error, stdout, stderr) => {
                                          if (error) {
                                              console.error(`Fehler beim Ausführen: ${error}`);
                                              return;
                                          }
                                  
                                          // Funktion, um nach JSON zu suchen
                                          [stdout, stderr].forEach(output => {
                                              if (output.includes('ERROR:')) {
                                                  console.error(`Fehler beim Ausführen: ${output}`);
                                              }
                                          });
                                      });
                                  }
                                  
                                  function initVar() {
                                      createState(msmartLoglevel, undefined, false, {
                                          name: 'Loglevel',
                                          type: 'number',
                                          def: LOGLEVEL,
                                          role: 'state'
                                      });
                                      LOGLEVEL = getState(msmartLoglevel).val;
                                  }
                                  
                                  // Main:
                                  initVar();
                                  queryDevice(mideaPortaSplit);
                                  schedule("*/5 * * * *", function () { // alle 5 Minuten
                                      queryDevice(mideaPortaSplit); 
                                  });
                                  
                                  // Events:
                                  on({id: msmartLoglevel, change: 'any'}, function (obj) {
                                      // Loglevel geändert
                                      log(`msmartLoglevel ist ${obj.state.val}`);
                                      LOGLEVEL = obj.state.val;
                                  });
                                  
                                  
                                  BananaJoeB Offline
                                  BananaJoeB Offline
                                  BananaJoe
                                  Most Active
                                  schrieb am zuletzt editiert von
                                  #353

                                  @uweabc sagte in Test Adapter Midea Dimstal Klimaanlagen v0.0.x:

                                  Ja, das ist die normale Formatierung bei JavaScript mit Variablen.

                                  Also ich sehe das zum ersten mal so ... hab das halt bisher getrennt verbunden, erst den Text, dann die Variable.

                                  ioBroker@Ubuntu 24.04 LTS (VMware) für: >260 Geräte, 5 Switche, 7 AP, 9 IP-Cam, 1 NAS 42TB, 1 ESXi 15TB, 4 Proxmox 1TB, 1 Hyper-V 48TB, 14 x Echo, 5x FireTV, 5 x Tablett/Handy VIS || >=160 Tasmota/Shelly || >=95 ZigBee || PV 8.1kW / Akku 14kWh || 2x USV 750W kaskadiert || Creality CR-10 SE 3D-Drucker

                                  1 Antwort Letzte Antwort
                                  0
                                  • JollyJ Offline
                                    JollyJ Offline
                                    Jolly
                                    schrieb am zuletzt editiert von
                                    #354

                                    Hallo, vielen Dank für die Anleitung.
                                    ich versuche meine Klimananlage mit folgendem Befehl zu steuern.

                                    msmart-ng control --account meineEmail --password meinPasswort --auto -d 192.168.1.34 power_state=false
                                    

                                    Funktioniert aber leider nicht, es kommt folgender Error

                                    ERROR:msmart.discover:Failed to login to cloud. Error: Code: 3102, Message: Account or password incorrect, please re-enter
                                    ERROR:msmart.discover:Could not establish cloud connection.
                                    
                                    
                                    

                                    Mit dem Befehler "discover" erhalte ich diese Rückmeldung

                                    (python-venv) jolly@iobroker:~$ msmart-ng discover
                                    INFO:msmart.cli:Discovering all devices on local network.
                                    INFO:msmart.cloud:Using Midea cloud server: https://mp-prod.appsmb.com (China: False).
                                    ERROR:msmart.discover:Failed to login to cloud. Error: Code: 3102, Message: Account or password incorrect, please re-enter
                                    ERROR:msmart.discover:Could not establish cloud connection.
                                    INFO:msmart.cli:Found 1 devices.
                                    INFO:msmart.cli:Found device:
                                    {'ip': '192.168.1.34', 'port': 6444, 'id': 152832117239990, 'online': False, 'supported': False, 'type': <DeviceType.AIR_CONDITIONER: 172>, 'name': 'net_ac_2190', 'sn': '000000P0000000Q1C084FF7421900000', 'key': None, 'token': None}
                                    

                                    Bedeutet das meine Klimaanlage ist nicht unterstützt? Weil ich die Rückmeldung 'supported': 'False' bekomme.
                                    Oder an was könnte es sonst liegen? Benutzername und Passwort sind zu 100% richtig, selbes nutze ich auch für die Midea Air bzw. NetHome Plus App.

                                    Vielen Dank

                                    U 2 Antworten Letzte Antwort
                                    0
                                    • JollyJ Jolly

                                      Hallo, vielen Dank für die Anleitung.
                                      ich versuche meine Klimananlage mit folgendem Befehl zu steuern.

                                      msmart-ng control --account meineEmail --password meinPasswort --auto -d 192.168.1.34 power_state=false
                                      

                                      Funktioniert aber leider nicht, es kommt folgender Error

                                      ERROR:msmart.discover:Failed to login to cloud. Error: Code: 3102, Message: Account or password incorrect, please re-enter
                                      ERROR:msmart.discover:Could not establish cloud connection.
                                      
                                      
                                      

                                      Mit dem Befehler "discover" erhalte ich diese Rückmeldung

                                      (python-venv) jolly@iobroker:~$ msmart-ng discover
                                      INFO:msmart.cli:Discovering all devices on local network.
                                      INFO:msmart.cloud:Using Midea cloud server: https://mp-prod.appsmb.com (China: False).
                                      ERROR:msmart.discover:Failed to login to cloud. Error: Code: 3102, Message: Account or password incorrect, please re-enter
                                      ERROR:msmart.discover:Could not establish cloud connection.
                                      INFO:msmart.cli:Found 1 devices.
                                      INFO:msmart.cli:Found device:
                                      {'ip': '192.168.1.34', 'port': 6444, 'id': 152832117239990, 'online': False, 'supported': False, 'type': <DeviceType.AIR_CONDITIONER: 172>, 'name': 'net_ac_2190', 'sn': '000000P0000000Q1C084FF7421900000', 'key': None, 'token': None}
                                      

                                      Bedeutet das meine Klimaanlage ist nicht unterstützt? Weil ich die Rückmeldung 'supported': 'False' bekomme.
                                      Oder an was könnte es sonst liegen? Benutzername und Passwort sind zu 100% richtig, selbes nutze ich auch für die Midea Air bzw. NetHome Plus App.

                                      Vielen Dank

                                      U Offline
                                      U Offline
                                      uweabc
                                      schrieb am zuletzt editiert von
                                      #355

                                      @jolly
                                      Die "Midea cloud" ist bei mir gesperrt, also ohne email & pw (war nur zum WLAN einrichten nötig).
                                      Ich habe es so gemacht:
                                      msmart-ng query --region DE --auto 192.168.1.34

                                      dann bekommst du ein token, key und id

                                      mit diesen dann control aufrufen:

                                      msmart-ng control --region DE --token abcabcabcc05bab57aad3833ce247729d2f880e6fd5b8e1d2ca0eec82395d7edb85cf70d339faf7d0c8baf3b8275d86b183d430347bae6eba4a009cb38d1147f --key abcabcabcd854aa6ba7b200174327ed7fc9fb0fd0032407992403b9e4104c1d3 --id 999832117233304 192.168.1.34 power_state=False

                                      Gruß Uwe

                                      JollyJ 1 Antwort Letzte Antwort
                                      0
                                      • JollyJ Jolly

                                        Hallo, vielen Dank für die Anleitung.
                                        ich versuche meine Klimananlage mit folgendem Befehl zu steuern.

                                        msmart-ng control --account meineEmail --password meinPasswort --auto -d 192.168.1.34 power_state=false
                                        

                                        Funktioniert aber leider nicht, es kommt folgender Error

                                        ERROR:msmart.discover:Failed to login to cloud. Error: Code: 3102, Message: Account or password incorrect, please re-enter
                                        ERROR:msmart.discover:Could not establish cloud connection.
                                        
                                        
                                        

                                        Mit dem Befehler "discover" erhalte ich diese Rückmeldung

                                        (python-venv) jolly@iobroker:~$ msmart-ng discover
                                        INFO:msmart.cli:Discovering all devices on local network.
                                        INFO:msmart.cloud:Using Midea cloud server: https://mp-prod.appsmb.com (China: False).
                                        ERROR:msmart.discover:Failed to login to cloud. Error: Code: 3102, Message: Account or password incorrect, please re-enter
                                        ERROR:msmart.discover:Could not establish cloud connection.
                                        INFO:msmart.cli:Found 1 devices.
                                        INFO:msmart.cli:Found device:
                                        {'ip': '192.168.1.34', 'port': 6444, 'id': 152832117239990, 'online': False, 'supported': False, 'type': <DeviceType.AIR_CONDITIONER: 172>, 'name': 'net_ac_2190', 'sn': '000000P0000000Q1C084FF7421900000', 'key': None, 'token': None}
                                        

                                        Bedeutet das meine Klimaanlage ist nicht unterstützt? Weil ich die Rückmeldung 'supported': 'False' bekomme.
                                        Oder an was könnte es sonst liegen? Benutzername und Passwort sind zu 100% richtig, selbes nutze ich auch für die Midea Air bzw. NetHome Plus App.

                                        Vielen Dank

                                        U Offline
                                        U Offline
                                        uweabc
                                        schrieb am zuletzt editiert von uweabc
                                        #356

                                        @bananajoe
                                        mit der neuen Version von
                                        msmart-ng -v
                                        Ausgabe: msmart-ng version: 2025.7.0
                                        werden auch die Energiewerte im ioBroker gefüllt.
                                        Hier die neue Version des JavaScripts (vorher die alten midea-Objekte, den ganzen Baum, löschen):

                                        /*
                                            Version 06.07.2025 Add option to CLI to request energy information
                                                               ID & Token & Key for msmart-ng are automatically determined
                                            
                                            Steuert eine Midea-Klimaanlage direkt über das Python-Programm 'msmart-ng' (siehe unten Installation 'msmart-ng') lokal im WLAN.
                                            
                                            Das Gerät wurde einmalig mit der Android-App in das WLAN integriert. 
                                            Anschließend wurde der Internetzugang für diese Gerät über die FritzBox deaktiviert, um eine Fremdsteuerung zu unterbinden.
                                            Keine Cloud erforderlich für dieses JavaScript!
                                        
                                            Dieses JavaScript übernimmt folgende Funktionen:  
                                            - Es liest die aktuellen Werte des Geräts im lokalen Netzwerk ab, siehe dazu Variable 'mideaPortaSplit'.  
                                              IP in Variable 'mideaPortaSplit' muss entsprechend geändert werden. 
                                              ID + Token + Key werden über 'msmart-ng query --region DE --auto <ip>' automatisch ermittelt.
                                            - Es erstellt eigenständig die passenden Objekte in ioBroker (unter javascript.0.midea.*).  
                                            - Wird ein schreibbares Objekt geändert, so schreibt das JavaScript die Änderung direkt ins Gerät, 
                                              indem es die Befehle über 'msmart-ng' sendet.
                                              Gültige Werte für FanSpeed / OperationalMode / SwingMode / SwingAngle / RateSelect / BreezeMode / AuxHeatMode
                                              siehe Variable 'AirConditioner'.
                                            - Der Loglevel (javascript.0.media.loglevel) kann während der Laufzeit des Skripts angepasst werden. 
                                              Mögliche Werte sind 0=aus, 1=minimal, 2=alles.
                                        
                                            Idee abgeleitet aus den Beitrag: https://forum.iobroker.net/topic/33198/test-adapter-midea-dimstal-klimaanlagen-v0-0-x/346?lang=de
                                        
                                            Installation 'msmart-ng':
                                            =========================
                                            Zum Benutzer ioBroker wechseln:
                                                sudo -u iobroker /usr/bin/bash
                                            In das Home-Verzeichnis des Benutzers ioBroker wechseln
                                                cd ~
                                            Python Environment anlegen (falls noch nicht vorhanden):
                                                python3 -m venv python-venv
                                            und in die Umgebung wechseln:
                                                source python-venv/bin/activate
                                            Jetzt kann man per pip das Modul installieren
                                                pip install msmart-ng
                                            und dann Version anzeigen:
                                                msmart-ng -v
                                            Ausgabe:        
                                                msmart-ng version: 2025.7.0
                                            Vor der Nutzung muss dann aber immer erst das Envirtonment geladen werden.
                                            Intelligenter weise wird das in den nachinstallierten Python-Modulen gleich richtig hinterlegt:
                                                which msmart-ng
                                            Ausgabe:
                                                /home/iobroker/python-venv/bin/msmart-ng
                                            Inhalt:
                                                cat /home/iobroker/python-venv/bin/msmart-ng
                                            Die erste Zeile ist
                                                #!/home/iobroker/python-venv/bin/python3
                                            Womit die richtige Umgebung genutzt wird.
                                            In ioBroker Skripten den ganzen Pfad aufrufen:
                                                /home/iobroker/python-venv/bin/msmart-ng
                                        */
                                        
                                        // id + token + key ermittelbar über 'msmart-ng query --region DE --auto 192.168.178.205'
                                        const mideaPortaSplit = { 
                                            ip: '192.168.178.205',
                                            id: null, // Temporary storage, ID for msmart-ng is automatically determined
                                            token: null, // Temporary storage, token for msmart-ng is automatically determined
                                            key: null, // Temporary storage, key for msmart-ng is automatically determined
                                            controlSettings: [], // Temporary storage for all modifiable objects, used in on({id: mideaPortaSplit.controlSettings, change: 'any'}...
                                        };
                                        let controlListener;
                                        
                                        const basePath = 'javascript.0.midea'; // Base object path
                                        var LOGLEVEL = 2; // 0=off, 1=minimal, 2=all
                                        const msmartLoglevel = basePath + '.loglevel';
                                        const region = 'DE'; // --region {DE,KR,US}
                                        const msmart_ng = '/home/iobroker/python-venv/bin/msmart-ng';
                                        
                                        // Enums see https://github.com/mill1000/midea-msmart/blob/main/msmart/device/AC/device.py
                                        // Note: The above link is for reference; it contains enum definitions for the device.
                                        class AirConditioner {
                                            static FanSpeed = {
                                                AUTO: 102,
                                                MAX: 100,
                                                HIGH: 80,
                                                MEDIUM: 60,
                                                LOW: 40,
                                                SILENT: 20,
                                                DEFAULT: 102
                                            };
                                        
                                            static OperationalMode = {
                                                AUTO: 1,
                                                COOL: 2,
                                                DRY: 3,
                                                HEAT: 4,
                                                FAN_ONLY: 5,
                                                SMART_DRY: 6,
                                                DEFAULT: 5
                                            };
                                        
                                            static SwingMode = {
                                                OFF: 0,
                                                VERTICAL: 12,
                                                HORIZONTAL: 3,
                                                BOTH: 15,
                                                DEFAULT: 0
                                            };
                                        
                                            static SwingAngle = {
                                                OFF: 0,
                                                POS_1: 1,
                                                POS_2: 25,
                                                POS_3: 50,
                                                POS_4: 75,
                                                POS_5: 100,
                                                DEFAULT: 0
                                            };
                                        
                                            static RateSelect = {
                                                OFF: 100,
                                                GEAR_50: 50,
                                                GEAR_75: 75,
                                                LEVEL_1: 1,
                                                LEVEL_2: 20,
                                                LEVEL_3: 40,
                                                LEVEL_4: 60,
                                                LEVEL_5: 80,
                                                DEFAULT: 100
                                            };
                                        
                                            static BreezeMode = {
                                                OFF: 1,
                                                BREEZE_AWAY: 2,
                                                BREEZE_MILD: 3,
                                                BREEZELESS: 4,
                                                DEFAULT: 1
                                            };
                                        
                                            static AuxHeatMode = {
                                                OFF: 0,
                                                AUX_HEAT: 1,
                                                AUX_ONLY: 2,
                                                DEFAULT: 0
                                            };
                                        }
                                        
                                        function convertToValidJSON(str) {
                                            return str
                                                .replace(/<[^>]*:\s*(\d+)>/g, '$1') // Remove everything in <...>, keep number after :
                                                .replace(/\bNone\b/g, 'null') // Replace 'None' with null
                                                .replace(/'/g, '"') // Optional: replace single quotes with double quotes
                                                .replace(/\bTrue\b/g, 'true').replace(/\bFalse\b/g, 'false') // Convert True/False to true/false
                                                .replace('"power"', '"power_state"') // name correction for power control
                                                .replace('"mode"', '"operational_mode"'); // name correction for operational mode control
                                        }
                                        
                                        function extractJsonFromLine(line) {
                                            const index = line.indexOf('{');
                                            if (index !== -1) {
                                                try {
                                                    const jsonStr = convertToValidJSON(line.substring(index));
                                                    if (LOGLEVEL > 1) log(jsonStr);
                                                    return JSON.parse(jsonStr);
                                                } catch (e) {
                                                    console.error(`Could not parse JSON ${e}`);
                                                    return null;
                                                }
                                            }
                                            return null;
                                        }
                                        
                                        // msmart-ng query 
                                        // usage: msmart-ng query [-h] [-d] [--region {DE,KR,US}] [--account ACCOUNT] [--password PASSWORD] [--capabilities] 
                                        //                        [--auto] [--energy]
                                        //                        [--id DEVICE_ID] [--token TOKEN] [--key KEY]
                                        //                        host
                                        function queryDevice(device) {
                                            const auto = (device.token == null); // query with --auto is slow, login with token,key&id it is faster
                                            const login = auto ? 
                                                ' --auto' : 
                                                ` --region ${region}` +
                                                ` --token ${device.token}` +
                                                ` --key ${device.key}` +
                                                ` --id ${device.id}`;
                                            const queryMsmart = msmart_ng +
                                                ' query' + login +
                                                ' --energy' +
                                                ` ${device.ip}`;
                                        
                                            if (LOGLEVEL > 1) log(queryMsmart);
                                            const devicePath = `${basePath}.${device.id}`;
                                            exec(queryMsmart, (error, stdout, stderr) => {
                                                if (error) {
                                                    var s = `${error}`;
                                                    if (s.includes('Connect failed') || s.includes('Connect timeout')) {
                                                        if (getState(`${devicePath}.online`).val) {
                                                            log(`${devicePath}.online=false`);
                                                            setState(`${devicePath}.online`, false, true);
                                                        }
                                                    } else {
                                                        console.error(`Error executing query: ${error}`);
                                                    }
                                                    return;
                                                }
                                        
                                                // Function to search for JSON in output
                                                [stdout, stderr].forEach(output => {
                                                    const lines = output.split('\n');
                                                    for (let line of lines) {
                                                        if (line.includes('INFO:msmart.cli:')) {
                                                            const data = extractJsonFromLine(line);
                                                            if (data) {
                                                                handleData(device, data);
                                                                break; // only the first found JSON line
                                                            }
                                                        }
                                                    }
                                                });
                                            });
                                        }
                                        
                                        /*
                                        const stateName = [
                                            {control: true,  key: 'eco', name: 'Energy Saving Mode'},
                                            {control: true,  key: 'power_save', name: 'Power Saving'},
                                            {control: true,  key: 'swing_mode', name: 'Airflow Direction'},
                                            {control: true,  key: 'fan_speed', name: 'Fan Speed'},
                                            {control: true,  key: 'operational_mode', name: 'Operating Mode'},
                                            {control: true,  key: 'power_state', name: 'On/Off'},
                                            {control: false, key: 'indoor_temperature', name: 'Indoor Temperature'},
                                            {control: false, key: 'outdoor_temperature', name: 'Outdoor Temperature'},
                                            {control: true,  key: 'target_temperature', name: 'Target Temperature'},
                                            {control: true,  key: 'fahrenheit', name: 'Temperature Unit'},
                                            {control: true,  key: 'target_humidity', name: 'Target Humidity'},
                                            {control: true,  key: 'horizontal_swing_angle', name: 'Horizontal Swing Angle'},
                                            {control: false, key: 'indoor_humidity', name: 'Indoor Humidity'},
                                            {control: true,  key: 'vertical_swing_angle', name: 'Vertical Swing Angle'},
                                            {control: true,  key: 'turbo', name: 'Turbo Mode'},
                                            {control: true,  key: 'freeze_protection', name: 'Frost Protection'},
                                            {control: true,  key: 'sleep', name: 'Sleep Mode'},
                                            {control: true,  key: 'display_on', name: 'Display On/Off'},
                                            {control: true,  key: 'beep', name: 'Beep Sound'},
                                            {control: false, key: 'filter_alert', name: 'Filter Warning'},
                                            {control: true,  key: 'follow_me', name: 'Follow Me'},
                                            {control: true,  key: 'purifier', name: 'Air Purifier'},
                                            {control: true,  key: 'self_clean', name: 'Self-Cleaning'},
                                            {control: false, key: 'total_energy_usage', name: 'Total Energy Usage'},
                                            {control: false, key: 'current_energy_usage', name: 'Current Energy Usage'},
                                            {control: false, key: 'real_time_power_usage', name: 'Real-Time Power Usage'},
                                            {control: true,  key: 'rate_select', name: 'Performance Level'},
                                            {control: true,  key: 'aux_mode', name: 'Auxiliary Mode'},
                                            {control: false, key: 'ip', name: 'IP Address'},
                                            {control: false, key: 'name', name: 'Device Name'},
                                            {control: false, key: 'supported', name: 'Supported Features'},
                                            {control: false, key: 'type', name: 'Device Type'},
                                            {control: false, key: 'online', name: 'Connection Status'},
                                            {control: false, key: 'port', name: 'Port'},
                                            {control: false, key: 'cascade_mode', name: 'Cascade Control'},   
                                            {control: false, key: 'sn', name: 'Serial Number'},   
                                        ];
                                        */
                                        const stateName = [
                                            {control: true,  key: 'eco', name: 'Energiesparmodus'},
                                            {control: true,  key: 'power_save', name: 'Energiesparen'},
                                            {control: true,  key: 'swing_mode', name: 'Luftstromrichtung'},
                                            {control: true,  key: 'fan_speed', name: 'Lüftergeschwindigkeit'},
                                            {control: true,  key: 'operational_mode', name: 'Betriebsmodus'},
                                            {control: true,  key: 'power_state', name: 'Ein/Aus'},
                                            {control: false, key: 'indoor_temperature', name: 'Innentemperatur'},
                                            {control: false, key: 'outdoor_temperature', name: 'Außentemperatur'},
                                            {control: true,  key: 'target_temperature', name: 'Zieltemperatur'},
                                            {control: true,  key: 'fahrenheit', name: 'Temperatureinheit'},
                                            {control: true,  key: 'target_humidity', name: 'Zielfeuchtigkeit'},
                                            {control: true,  key: 'horizontal_swing_angle', name: 'Horizontaler Schwenkwinkel'},
                                            {control: false, key: 'indoor_humidity', name: 'Raumluftfeuchtigkeit'},
                                            {control: true,  key: 'vertical_swing_angle', name: 'Vertikaler Schwenkwinkel'},
                                            {control: true,  key: 'turbo', name: 'Turbomodus'},
                                            {control: true,  key: 'freeze_protection', name: 'Frostschutz'},
                                            {control: true,  key: 'sleep', name: 'Schlafmodus'},
                                            {control: true,  key: 'display_on', name: 'Display Ein/Aus'},
                                            {control: true,  key: 'beep', name: 'Signalton'},
                                            {control: false, key: 'filter_alert', name: 'Filterwarnung'},
                                            {control: true,  key: 'follow_me', name: 'Follow Me'},
                                            {control: true,  key: 'purifier', name: 'Luftreiniger'},
                                            {control: true,  key: 'self_clean', name: 'Selbstreinigung'},
                                            {control: false, key: 'total_energy_usage', name: 'Gesamtenergieverbrauch'},
                                            {control: false, key: 'current_energy_usage', name: 'Aktueller Energieverbrauch'},
                                            {control: false, key: 'real_time_power_usage', name: 'Echtzeitleistung'},
                                            {control: true,  key: 'rate_select', name: 'Leistungsstufe'},
                                            {control: true,  key: 'aux_mode', name: 'Zusatzmodus'},
                                            {control: false, key: 'ip', name: 'IP-Adresse'},
                                            {control: false, key: 'name', name: 'Gerätename'},
                                            {control: false, key: 'supported', name: 'Unterstützt'},
                                            {control: false, key: 'type', name: 'Gerätetyp'},
                                            {control: false, key: 'online', name: 'Verbindungsstatus'},
                                            {control: false, key: 'port', name: 'Port'},
                                            {control: false, key: 'cascade_mode', name: 'Kaskadensteuerung'},   
                                            {control: false, key: 'sn', name: 'Seriennummer'},   
                                        ];
                                        
                                        function initControlSettings(device) {
                                            device.controlSettings = [];
                                            const devicePath = `${basePath}.${device.id}`;
                                            const controlStates = stateName.filter(state => state.control);
                                            controlStates.forEach(state => {
                                                const statePath = `${devicePath}.${state.key}`;
                                                device.controlSettings.push(statePath);
                                            });
                                            log('initControlSettings() device.controlSettings.length=' + device.controlSettings.length);
                                        }
                                        
                                        function handleData(device, data) {
                                            const id = data.id ? data.id.toString() : 'device';
                                            const devicePath = `${basePath}.${id}`;
                                        
                                            Object.keys(data).forEach(key => {
                                                const value = data[key];
                                                var keyL = key.toLowerCase();
                                                if (keyL === 'id') {
                                                    if (device.id == null) device.id = value;
                                                    return;
                                                } else if (keyL === 'key') {
                                                    if (device.key == null) device.key = value;
                                                    return;
                                                } else if (keyL === 'token') {
                                                    if (device.token == null) device.token = value;
                                                    return;
                                                }       
                                                if (['sn', 'name'].includes(keyL) && (value == null)) {
                                                    return;
                                                }
                                                const statePath = `${devicePath}.${key}`;
                                        
                                                // Configuration for createState
                                                const stateOptions = {
                                                    type: typeof value,
                                                    name: stateName.find(item => item.key === keyL)?.name || key,
                                                    write: stateName.find(item => item.key === keyL)?.control || false,
                                                    read: true,
                                                };
                                                if (value != null) stateOptions.def = value;
                                        
                                                // Additional properties based on the key
                                                if (typeof value !== 'boolean') {
                                                    if (keyL.includes('temperature')) {
                                                        stateOptions.unit = '°C';
                                                        stateOptions.role = 'value.temperature';
                                                        stateOptions.type = 'number';
                                                    } else if (keyL.includes('humidity')) {
                                                        stateOptions.unit = '%';
                                                        stateOptions.role = 'value.humidity';
                                                        stateOptions.min = 0;
                                                        stateOptions.max = 100;
                                                        stateOptions.type = 'number';
                                                    } else if (keyL.includes('energy')) {
                                                        stateOptions.unit = 'Wh';
                                                        stateOptions.min = 0;
                                                        stateOptions.max = 999999999;
                                                        stateOptions.type = 'number';
                                                    } else if (keyL.includes('power')) {
                                                        stateOptions.unit = 'W';
                                                        stateOptions.role = 'value.power';
                                                        stateOptions.min = 0;
                                                        stateOptions.max = 4000;
                                                        stateOptions.type = 'number';
                                                    }
                                                }
                                        
                                                // Create state if it does not exist
                                                createState(statePath, stateOptions, () => {
                                                    // After creation, get the value and update if necessary
                                                    getState(statePath, (err, state) => {
                                                        if (err || !state) {
                                                            setState(statePath, value, true);
                                                        } else {
                                                            if (state.val !== value) {
                                                                if (LOGLEVEL > 1) log(`Updating ${statePath} to ${value}`);
                                                                setState(statePath, value, true);
                                                            }
                                                        }
                                                    });
                                                });
                                            });
                                            if ((device.controlSettings.length == 0) && (device.id != null)) {
                                                initControlSettings(device);
                                                if (controlListener && typeof controlListener === 'function') controlListener(); // remove old listener
                                                controlListener = on({id: mideaPortaSplit.controlSettings, change: 'any'}, function (obj) {
                                                    var parts = obj.id.split('.');
                                                    var setting = parts[4];
                                                    if ((setting == 'online') && obj.state.val) powerStateOnRepeat = -1;
                                                    if (obj.state.ack) return; // change was made by script, ignore
                                                    if (LOGLEVEL > 0) log(`Changed ${obj.id} to ${obj.state.val}`);
                                                    controlDevice(mideaPortaSplit, setting ,obj.state.val);
                                                });        
                                            }
                                        }
                                        
                                        // msmart-ng control
                                        // usage: msmart-ng control [-h] [-d] [--region {DE,KR,US}] [--account ACCOUNT] [--password PASSWORD] 
                                        //                          [--capabilities] 
                                        //                          [--auto] 
                                        //                          [--id DEVICE_ID] [--token TOKEN] [--key KEY]
                                        //                          host setting=value [setting=value ...]
                                        var powerStateOnRepeat = -1;
                                        function controlDevice(device, setting, value) {
                                            if (LOGLEVEL) log(`Controlling device ${device.id}, setting ${setting}=${value}`);
                                        
                                            const stateEntry = stateName.find(entry => entry.key === setting);    
                                            if (!stateEntry || stateEntry.control === false) {
                                                if (LOGLEVEL > 1) log(`${setting} is not controllable!`);
                                                return;
                                            }
                                        
                                            if ((setting == 'power_state') && (value == false)) {
                                                powerStateOnRepeat = -1;
                                                setTimeout(function () {
                                                    queryDevice(device);
                                                    setTimeout(function () {
                                                        queryDevice(device);
                                                    }, 30 * 1000);   
                                                }, 30 * 1000);   
                                            }
                                        
                                            var pyValue = value;
                                            if (typeof pyValue == 'boolean') {
                                                pyValue = value == true ? 'True':'False';
                                            }
                                        
                                            const controlMsmart = msmart_ng +
                                                ' control' +
                                                ` --region ${region}` +
                                                ` --token ${device.token}` +
                                                ` --key ${device.key}` +
                                                ` --id ${device.id}` +
                                                ` ${device.ip}` +
                                                ` ${setting}=${pyValue}`;
                                        
                                            if (LOGLEVEL > 1) log(controlMsmart);
                                            const devicePath = `${basePath}.${device.id}`;
                                            exec(controlMsmart, (error, stdout, stderr) => {
                                                if (error) {
                                                    var s = `${error}`;
                                                    if (s.includes('Connect failed') || s.includes('Connect timeout')) {
                                                        if (getState(`${devicePath}.online`).val) {
                                                            log(`${devicePath}.online=false`);
                                                            setState(`${devicePath}.online`, false, true);
                                                        }
                                                        if ((setting == 'power_state') && (powerStateOnRepeat < (25 * 1000))) {
                                                            setTimeout(function () {
                                                                log('Repeating control: power_state=True');
                                                                controlDevice(device, setting, value);
                                                                powerStateOnRepeat += 2 * 1000;
                                                            }, 2 * 1000);                    
                                                        }
                                                    } else {
                                                        console.error(`Error executing control: ${error}`);
                                                    }
                                                    return;
                                                }
                                                powerStateOnRepeat = -1;
                                                // Funktion, um nach JSON zu suchen
                                                [stdout, stderr].forEach(output => {
                                                    if (output.length) {
                                                        if (output.includes('ERROR:')) {
                                                            console.error(`Error during execution: ${output}`);
                                                            if (getState(`${devicePath}.online`).val)
                                                                setState(`${devicePath}.online`, false, true);
                                                        } else {
                                                            if (LOGLEVEL > 1) log(output);
                                                            if (getState(`${devicePath}.online`).val == false)
                                                                setState(`${devicePath}.online`, true, true);
                                                        }
                                                    }
                                                });
                                            });
                                        }
                                        
                                        function initVar() {
                                            createState(msmartLoglevel, undefined, false, {
                                                name: 'Loglevel',
                                                type: 'number',
                                                def: LOGLEVEL,
                                                role: 'state'
                                            });
                                            LOGLEVEL = getState(msmartLoglevel).val;
                                        }
                                        
                                        // Main:
                                        initVar();
                                        queryDevice(mideaPortaSplit);
                                        schedule("*/2 * * * *", function () { // every 2 minutes
                                            queryDevice(mideaPortaSplit); 
                                        });
                                        
                                        // Events:
                                        on({id: msmartLoglevel, change: 'any'}, function (obj) {
                                            // Log level changed
                                            log(`msmartLoglevel is now ${obj.state.val}`);
                                            LOGLEVEL = obj.state.val;
                                        });
                                        

                                        Die generierten Objekte im ioBroker sehen dann so aus:
                                        ksnip_20250706-122153.png
                                        Und in meiner smartVisu (ja, ich benutze smartVisu!) sieht das so aus:
                                        Handy:
                                        photo_2025-07-06_12-15-56.jpg
                                        photo_2025-07-06_12-07-46.jpg
                                        photo_2025-07-06_12-08-18.jpg
                                        photo_2025-07-06_12-13-42.jpg
                                        Tablet:
                                        ksnip_20250706-123230.png

                                        BananaJoeB 1 Antwort Letzte Antwort
                                        0
                                        • U uweabc

                                          @bananajoe
                                          mit der neuen Version von
                                          msmart-ng -v
                                          Ausgabe: msmart-ng version: 2025.7.0
                                          werden auch die Energiewerte im ioBroker gefüllt.
                                          Hier die neue Version des JavaScripts (vorher die alten midea-Objekte, den ganzen Baum, löschen):

                                          /*
                                              Version 06.07.2025 Add option to CLI to request energy information
                                                                 ID & Token & Key for msmart-ng are automatically determined
                                              
                                              Steuert eine Midea-Klimaanlage direkt über das Python-Programm 'msmart-ng' (siehe unten Installation 'msmart-ng') lokal im WLAN.
                                              
                                              Das Gerät wurde einmalig mit der Android-App in das WLAN integriert. 
                                              Anschließend wurde der Internetzugang für diese Gerät über die FritzBox deaktiviert, um eine Fremdsteuerung zu unterbinden.
                                              Keine Cloud erforderlich für dieses JavaScript!
                                          
                                              Dieses JavaScript übernimmt folgende Funktionen:  
                                              - Es liest die aktuellen Werte des Geräts im lokalen Netzwerk ab, siehe dazu Variable 'mideaPortaSplit'.  
                                                IP in Variable 'mideaPortaSplit' muss entsprechend geändert werden. 
                                                ID + Token + Key werden über 'msmart-ng query --region DE --auto <ip>' automatisch ermittelt.
                                              - Es erstellt eigenständig die passenden Objekte in ioBroker (unter javascript.0.midea.*).  
                                              - Wird ein schreibbares Objekt geändert, so schreibt das JavaScript die Änderung direkt ins Gerät, 
                                                indem es die Befehle über 'msmart-ng' sendet.
                                                Gültige Werte für FanSpeed / OperationalMode / SwingMode / SwingAngle / RateSelect / BreezeMode / AuxHeatMode
                                                siehe Variable 'AirConditioner'.
                                              - Der Loglevel (javascript.0.media.loglevel) kann während der Laufzeit des Skripts angepasst werden. 
                                                Mögliche Werte sind 0=aus, 1=minimal, 2=alles.
                                          
                                              Idee abgeleitet aus den Beitrag: https://forum.iobroker.net/topic/33198/test-adapter-midea-dimstal-klimaanlagen-v0-0-x/346?lang=de
                                          
                                              Installation 'msmart-ng':
                                              =========================
                                              Zum Benutzer ioBroker wechseln:
                                                  sudo -u iobroker /usr/bin/bash
                                              In das Home-Verzeichnis des Benutzers ioBroker wechseln
                                                  cd ~
                                              Python Environment anlegen (falls noch nicht vorhanden):
                                                  python3 -m venv python-venv
                                              und in die Umgebung wechseln:
                                                  source python-venv/bin/activate
                                              Jetzt kann man per pip das Modul installieren
                                                  pip install msmart-ng
                                              und dann Version anzeigen:
                                                  msmart-ng -v
                                              Ausgabe:        
                                                  msmart-ng version: 2025.7.0
                                              Vor der Nutzung muss dann aber immer erst das Envirtonment geladen werden.
                                              Intelligenter weise wird das in den nachinstallierten Python-Modulen gleich richtig hinterlegt:
                                                  which msmart-ng
                                              Ausgabe:
                                                  /home/iobroker/python-venv/bin/msmart-ng
                                              Inhalt:
                                                  cat /home/iobroker/python-venv/bin/msmart-ng
                                              Die erste Zeile ist
                                                  #!/home/iobroker/python-venv/bin/python3
                                              Womit die richtige Umgebung genutzt wird.
                                              In ioBroker Skripten den ganzen Pfad aufrufen:
                                                  /home/iobroker/python-venv/bin/msmart-ng
                                          */
                                          
                                          // id + token + key ermittelbar über 'msmart-ng query --region DE --auto 192.168.178.205'
                                          const mideaPortaSplit = { 
                                              ip: '192.168.178.205',
                                              id: null, // Temporary storage, ID for msmart-ng is automatically determined
                                              token: null, // Temporary storage, token for msmart-ng is automatically determined
                                              key: null, // Temporary storage, key for msmart-ng is automatically determined
                                              controlSettings: [], // Temporary storage for all modifiable objects, used in on({id: mideaPortaSplit.controlSettings, change: 'any'}...
                                          };
                                          let controlListener;
                                          
                                          const basePath = 'javascript.0.midea'; // Base object path
                                          var LOGLEVEL = 2; // 0=off, 1=minimal, 2=all
                                          const msmartLoglevel = basePath + '.loglevel';
                                          const region = 'DE'; // --region {DE,KR,US}
                                          const msmart_ng = '/home/iobroker/python-venv/bin/msmart-ng';
                                          
                                          // Enums see https://github.com/mill1000/midea-msmart/blob/main/msmart/device/AC/device.py
                                          // Note: The above link is for reference; it contains enum definitions for the device.
                                          class AirConditioner {
                                              static FanSpeed = {
                                                  AUTO: 102,
                                                  MAX: 100,
                                                  HIGH: 80,
                                                  MEDIUM: 60,
                                                  LOW: 40,
                                                  SILENT: 20,
                                                  DEFAULT: 102
                                              };
                                          
                                              static OperationalMode = {
                                                  AUTO: 1,
                                                  COOL: 2,
                                                  DRY: 3,
                                                  HEAT: 4,
                                                  FAN_ONLY: 5,
                                                  SMART_DRY: 6,
                                                  DEFAULT: 5
                                              };
                                          
                                              static SwingMode = {
                                                  OFF: 0,
                                                  VERTICAL: 12,
                                                  HORIZONTAL: 3,
                                                  BOTH: 15,
                                                  DEFAULT: 0
                                              };
                                          
                                              static SwingAngle = {
                                                  OFF: 0,
                                                  POS_1: 1,
                                                  POS_2: 25,
                                                  POS_3: 50,
                                                  POS_4: 75,
                                                  POS_5: 100,
                                                  DEFAULT: 0
                                              };
                                          
                                              static RateSelect = {
                                                  OFF: 100,
                                                  GEAR_50: 50,
                                                  GEAR_75: 75,
                                                  LEVEL_1: 1,
                                                  LEVEL_2: 20,
                                                  LEVEL_3: 40,
                                                  LEVEL_4: 60,
                                                  LEVEL_5: 80,
                                                  DEFAULT: 100
                                              };
                                          
                                              static BreezeMode = {
                                                  OFF: 1,
                                                  BREEZE_AWAY: 2,
                                                  BREEZE_MILD: 3,
                                                  BREEZELESS: 4,
                                                  DEFAULT: 1
                                              };
                                          
                                              static AuxHeatMode = {
                                                  OFF: 0,
                                                  AUX_HEAT: 1,
                                                  AUX_ONLY: 2,
                                                  DEFAULT: 0
                                              };
                                          }
                                          
                                          function convertToValidJSON(str) {
                                              return str
                                                  .replace(/<[^>]*:\s*(\d+)>/g, '$1') // Remove everything in <...>, keep number after :
                                                  .replace(/\bNone\b/g, 'null') // Replace 'None' with null
                                                  .replace(/'/g, '"') // Optional: replace single quotes with double quotes
                                                  .replace(/\bTrue\b/g, 'true').replace(/\bFalse\b/g, 'false') // Convert True/False to true/false
                                                  .replace('"power"', '"power_state"') // name correction for power control
                                                  .replace('"mode"', '"operational_mode"'); // name correction for operational mode control
                                          }
                                          
                                          function extractJsonFromLine(line) {
                                              const index = line.indexOf('{');
                                              if (index !== -1) {
                                                  try {
                                                      const jsonStr = convertToValidJSON(line.substring(index));
                                                      if (LOGLEVEL > 1) log(jsonStr);
                                                      return JSON.parse(jsonStr);
                                                  } catch (e) {
                                                      console.error(`Could not parse JSON ${e}`);
                                                      return null;
                                                  }
                                              }
                                              return null;
                                          }
                                          
                                          // msmart-ng query 
                                          // usage: msmart-ng query [-h] [-d] [--region {DE,KR,US}] [--account ACCOUNT] [--password PASSWORD] [--capabilities] 
                                          //                        [--auto] [--energy]
                                          //                        [--id DEVICE_ID] [--token TOKEN] [--key KEY]
                                          //                        host
                                          function queryDevice(device) {
                                              const auto = (device.token == null); // query with --auto is slow, login with token,key&id it is faster
                                              const login = auto ? 
                                                  ' --auto' : 
                                                  ` --region ${region}` +
                                                  ` --token ${device.token}` +
                                                  ` --key ${device.key}` +
                                                  ` --id ${device.id}`;
                                              const queryMsmart = msmart_ng +
                                                  ' query' + login +
                                                  ' --energy' +
                                                  ` ${device.ip}`;
                                          
                                              if (LOGLEVEL > 1) log(queryMsmart);
                                              const devicePath = `${basePath}.${device.id}`;
                                              exec(queryMsmart, (error, stdout, stderr) => {
                                                  if (error) {
                                                      var s = `${error}`;
                                                      if (s.includes('Connect failed') || s.includes('Connect timeout')) {
                                                          if (getState(`${devicePath}.online`).val) {
                                                              log(`${devicePath}.online=false`);
                                                              setState(`${devicePath}.online`, false, true);
                                                          }
                                                      } else {
                                                          console.error(`Error executing query: ${error}`);
                                                      }
                                                      return;
                                                  }
                                          
                                                  // Function to search for JSON in output
                                                  [stdout, stderr].forEach(output => {
                                                      const lines = output.split('\n');
                                                      for (let line of lines) {
                                                          if (line.includes('INFO:msmart.cli:')) {
                                                              const data = extractJsonFromLine(line);
                                                              if (data) {
                                                                  handleData(device, data);
                                                                  break; // only the first found JSON line
                                                              }
                                                          }
                                                      }
                                                  });
                                              });
                                          }
                                          
                                          /*
                                          const stateName = [
                                              {control: true,  key: 'eco', name: 'Energy Saving Mode'},
                                              {control: true,  key: 'power_save', name: 'Power Saving'},
                                              {control: true,  key: 'swing_mode', name: 'Airflow Direction'},
                                              {control: true,  key: 'fan_speed', name: 'Fan Speed'},
                                              {control: true,  key: 'operational_mode', name: 'Operating Mode'},
                                              {control: true,  key: 'power_state', name: 'On/Off'},
                                              {control: false, key: 'indoor_temperature', name: 'Indoor Temperature'},
                                              {control: false, key: 'outdoor_temperature', name: 'Outdoor Temperature'},
                                              {control: true,  key: 'target_temperature', name: 'Target Temperature'},
                                              {control: true,  key: 'fahrenheit', name: 'Temperature Unit'},
                                              {control: true,  key: 'target_humidity', name: 'Target Humidity'},
                                              {control: true,  key: 'horizontal_swing_angle', name: 'Horizontal Swing Angle'},
                                              {control: false, key: 'indoor_humidity', name: 'Indoor Humidity'},
                                              {control: true,  key: 'vertical_swing_angle', name: 'Vertical Swing Angle'},
                                              {control: true,  key: 'turbo', name: 'Turbo Mode'},
                                              {control: true,  key: 'freeze_protection', name: 'Frost Protection'},
                                              {control: true,  key: 'sleep', name: 'Sleep Mode'},
                                              {control: true,  key: 'display_on', name: 'Display On/Off'},
                                              {control: true,  key: 'beep', name: 'Beep Sound'},
                                              {control: false, key: 'filter_alert', name: 'Filter Warning'},
                                              {control: true,  key: 'follow_me', name: 'Follow Me'},
                                              {control: true,  key: 'purifier', name: 'Air Purifier'},
                                              {control: true,  key: 'self_clean', name: 'Self-Cleaning'},
                                              {control: false, key: 'total_energy_usage', name: 'Total Energy Usage'},
                                              {control: false, key: 'current_energy_usage', name: 'Current Energy Usage'},
                                              {control: false, key: 'real_time_power_usage', name: 'Real-Time Power Usage'},
                                              {control: true,  key: 'rate_select', name: 'Performance Level'},
                                              {control: true,  key: 'aux_mode', name: 'Auxiliary Mode'},
                                              {control: false, key: 'ip', name: 'IP Address'},
                                              {control: false, key: 'name', name: 'Device Name'},
                                              {control: false, key: 'supported', name: 'Supported Features'},
                                              {control: false, key: 'type', name: 'Device Type'},
                                              {control: false, key: 'online', name: 'Connection Status'},
                                              {control: false, key: 'port', name: 'Port'},
                                              {control: false, key: 'cascade_mode', name: 'Cascade Control'},   
                                              {control: false, key: 'sn', name: 'Serial Number'},   
                                          ];
                                          */
                                          const stateName = [
                                              {control: true,  key: 'eco', name: 'Energiesparmodus'},
                                              {control: true,  key: 'power_save', name: 'Energiesparen'},
                                              {control: true,  key: 'swing_mode', name: 'Luftstromrichtung'},
                                              {control: true,  key: 'fan_speed', name: 'Lüftergeschwindigkeit'},
                                              {control: true,  key: 'operational_mode', name: 'Betriebsmodus'},
                                              {control: true,  key: 'power_state', name: 'Ein/Aus'},
                                              {control: false, key: 'indoor_temperature', name: 'Innentemperatur'},
                                              {control: false, key: 'outdoor_temperature', name: 'Außentemperatur'},
                                              {control: true,  key: 'target_temperature', name: 'Zieltemperatur'},
                                              {control: true,  key: 'fahrenheit', name: 'Temperatureinheit'},
                                              {control: true,  key: 'target_humidity', name: 'Zielfeuchtigkeit'},
                                              {control: true,  key: 'horizontal_swing_angle', name: 'Horizontaler Schwenkwinkel'},
                                              {control: false, key: 'indoor_humidity', name: 'Raumluftfeuchtigkeit'},
                                              {control: true,  key: 'vertical_swing_angle', name: 'Vertikaler Schwenkwinkel'},
                                              {control: true,  key: 'turbo', name: 'Turbomodus'},
                                              {control: true,  key: 'freeze_protection', name: 'Frostschutz'},
                                              {control: true,  key: 'sleep', name: 'Schlafmodus'},
                                              {control: true,  key: 'display_on', name: 'Display Ein/Aus'},
                                              {control: true,  key: 'beep', name: 'Signalton'},
                                              {control: false, key: 'filter_alert', name: 'Filterwarnung'},
                                              {control: true,  key: 'follow_me', name: 'Follow Me'},
                                              {control: true,  key: 'purifier', name: 'Luftreiniger'},
                                              {control: true,  key: 'self_clean', name: 'Selbstreinigung'},
                                              {control: false, key: 'total_energy_usage', name: 'Gesamtenergieverbrauch'},
                                              {control: false, key: 'current_energy_usage', name: 'Aktueller Energieverbrauch'},
                                              {control: false, key: 'real_time_power_usage', name: 'Echtzeitleistung'},
                                              {control: true,  key: 'rate_select', name: 'Leistungsstufe'},
                                              {control: true,  key: 'aux_mode', name: 'Zusatzmodus'},
                                              {control: false, key: 'ip', name: 'IP-Adresse'},
                                              {control: false, key: 'name', name: 'Gerätename'},
                                              {control: false, key: 'supported', name: 'Unterstützt'},
                                              {control: false, key: 'type', name: 'Gerätetyp'},
                                              {control: false, key: 'online', name: 'Verbindungsstatus'},
                                              {control: false, key: 'port', name: 'Port'},
                                              {control: false, key: 'cascade_mode', name: 'Kaskadensteuerung'},   
                                              {control: false, key: 'sn', name: 'Seriennummer'},   
                                          ];
                                          
                                          function initControlSettings(device) {
                                              device.controlSettings = [];
                                              const devicePath = `${basePath}.${device.id}`;
                                              const controlStates = stateName.filter(state => state.control);
                                              controlStates.forEach(state => {
                                                  const statePath = `${devicePath}.${state.key}`;
                                                  device.controlSettings.push(statePath);
                                              });
                                              log('initControlSettings() device.controlSettings.length=' + device.controlSettings.length);
                                          }
                                          
                                          function handleData(device, data) {
                                              const id = data.id ? data.id.toString() : 'device';
                                              const devicePath = `${basePath}.${id}`;
                                          
                                              Object.keys(data).forEach(key => {
                                                  const value = data[key];
                                                  var keyL = key.toLowerCase();
                                                  if (keyL === 'id') {
                                                      if (device.id == null) device.id = value;
                                                      return;
                                                  } else if (keyL === 'key') {
                                                      if (device.key == null) device.key = value;
                                                      return;
                                                  } else if (keyL === 'token') {
                                                      if (device.token == null) device.token = value;
                                                      return;
                                                  }       
                                                  if (['sn', 'name'].includes(keyL) && (value == null)) {
                                                      return;
                                                  }
                                                  const statePath = `${devicePath}.${key}`;
                                          
                                                  // Configuration for createState
                                                  const stateOptions = {
                                                      type: typeof value,
                                                      name: stateName.find(item => item.key === keyL)?.name || key,
                                                      write: stateName.find(item => item.key === keyL)?.control || false,
                                                      read: true,
                                                  };
                                                  if (value != null) stateOptions.def = value;
                                          
                                                  // Additional properties based on the key
                                                  if (typeof value !== 'boolean') {
                                                      if (keyL.includes('temperature')) {
                                                          stateOptions.unit = '°C';
                                                          stateOptions.role = 'value.temperature';
                                                          stateOptions.type = 'number';
                                                      } else if (keyL.includes('humidity')) {
                                                          stateOptions.unit = '%';
                                                          stateOptions.role = 'value.humidity';
                                                          stateOptions.min = 0;
                                                          stateOptions.max = 100;
                                                          stateOptions.type = 'number';
                                                      } else if (keyL.includes('energy')) {
                                                          stateOptions.unit = 'Wh';
                                                          stateOptions.min = 0;
                                                          stateOptions.max = 999999999;
                                                          stateOptions.type = 'number';
                                                      } else if (keyL.includes('power')) {
                                                          stateOptions.unit = 'W';
                                                          stateOptions.role = 'value.power';
                                                          stateOptions.min = 0;
                                                          stateOptions.max = 4000;
                                                          stateOptions.type = 'number';
                                                      }
                                                  }
                                          
                                                  // Create state if it does not exist
                                                  createState(statePath, stateOptions, () => {
                                                      // After creation, get the value and update if necessary
                                                      getState(statePath, (err, state) => {
                                                          if (err || !state) {
                                                              setState(statePath, value, true);
                                                          } else {
                                                              if (state.val !== value) {
                                                                  if (LOGLEVEL > 1) log(`Updating ${statePath} to ${value}`);
                                                                  setState(statePath, value, true);
                                                              }
                                                          }
                                                      });
                                                  });
                                              });
                                              if ((device.controlSettings.length == 0) && (device.id != null)) {
                                                  initControlSettings(device);
                                                  if (controlListener && typeof controlListener === 'function') controlListener(); // remove old listener
                                                  controlListener = on({id: mideaPortaSplit.controlSettings, change: 'any'}, function (obj) {
                                                      var parts = obj.id.split('.');
                                                      var setting = parts[4];
                                                      if ((setting == 'online') && obj.state.val) powerStateOnRepeat = -1;
                                                      if (obj.state.ack) return; // change was made by script, ignore
                                                      if (LOGLEVEL > 0) log(`Changed ${obj.id} to ${obj.state.val}`);
                                                      controlDevice(mideaPortaSplit, setting ,obj.state.val);
                                                  });        
                                              }
                                          }
                                          
                                          // msmart-ng control
                                          // usage: msmart-ng control [-h] [-d] [--region {DE,KR,US}] [--account ACCOUNT] [--password PASSWORD] 
                                          //                          [--capabilities] 
                                          //                          [--auto] 
                                          //                          [--id DEVICE_ID] [--token TOKEN] [--key KEY]
                                          //                          host setting=value [setting=value ...]
                                          var powerStateOnRepeat = -1;
                                          function controlDevice(device, setting, value) {
                                              if (LOGLEVEL) log(`Controlling device ${device.id}, setting ${setting}=${value}`);
                                          
                                              const stateEntry = stateName.find(entry => entry.key === setting);    
                                              if (!stateEntry || stateEntry.control === false) {
                                                  if (LOGLEVEL > 1) log(`${setting} is not controllable!`);
                                                  return;
                                              }
                                          
                                              if ((setting == 'power_state') && (value == false)) {
                                                  powerStateOnRepeat = -1;
                                                  setTimeout(function () {
                                                      queryDevice(device);
                                                      setTimeout(function () {
                                                          queryDevice(device);
                                                      }, 30 * 1000);   
                                                  }, 30 * 1000);   
                                              }
                                          
                                              var pyValue = value;
                                              if (typeof pyValue == 'boolean') {
                                                  pyValue = value == true ? 'True':'False';
                                              }
                                          
                                              const controlMsmart = msmart_ng +
                                                  ' control' +
                                                  ` --region ${region}` +
                                                  ` --token ${device.token}` +
                                                  ` --key ${device.key}` +
                                                  ` --id ${device.id}` +
                                                  ` ${device.ip}` +
                                                  ` ${setting}=${pyValue}`;
                                          
                                              if (LOGLEVEL > 1) log(controlMsmart);
                                              const devicePath = `${basePath}.${device.id}`;
                                              exec(controlMsmart, (error, stdout, stderr) => {
                                                  if (error) {
                                                      var s = `${error}`;
                                                      if (s.includes('Connect failed') || s.includes('Connect timeout')) {
                                                          if (getState(`${devicePath}.online`).val) {
                                                              log(`${devicePath}.online=false`);
                                                              setState(`${devicePath}.online`, false, true);
                                                          }
                                                          if ((setting == 'power_state') && (powerStateOnRepeat < (25 * 1000))) {
                                                              setTimeout(function () {
                                                                  log('Repeating control: power_state=True');
                                                                  controlDevice(device, setting, value);
                                                                  powerStateOnRepeat += 2 * 1000;
                                                              }, 2 * 1000);                    
                                                          }
                                                      } else {
                                                          console.error(`Error executing control: ${error}`);
                                                      }
                                                      return;
                                                  }
                                                  powerStateOnRepeat = -1;
                                                  // Funktion, um nach JSON zu suchen
                                                  [stdout, stderr].forEach(output => {
                                                      if (output.length) {
                                                          if (output.includes('ERROR:')) {
                                                              console.error(`Error during execution: ${output}`);
                                                              if (getState(`${devicePath}.online`).val)
                                                                  setState(`${devicePath}.online`, false, true);
                                                          } else {
                                                              if (LOGLEVEL > 1) log(output);
                                                              if (getState(`${devicePath}.online`).val == false)
                                                                  setState(`${devicePath}.online`, true, true);
                                                          }
                                                      }
                                                  });
                                              });
                                          }
                                          
                                          function initVar() {
                                              createState(msmartLoglevel, undefined, false, {
                                                  name: 'Loglevel',
                                                  type: 'number',
                                                  def: LOGLEVEL,
                                                  role: 'state'
                                              });
                                              LOGLEVEL = getState(msmartLoglevel).val;
                                          }
                                          
                                          // Main:
                                          initVar();
                                          queryDevice(mideaPortaSplit);
                                          schedule("*/2 * * * *", function () { // every 2 minutes
                                              queryDevice(mideaPortaSplit); 
                                          });
                                          
                                          // Events:
                                          on({id: msmartLoglevel, change: 'any'}, function (obj) {
                                              // Log level changed
                                              log(`msmartLoglevel is now ${obj.state.val}`);
                                              LOGLEVEL = obj.state.val;
                                          });
                                          

                                          Die generierten Objekte im ioBroker sehen dann so aus:
                                          ksnip_20250706-122153.png
                                          Und in meiner smartVisu (ja, ich benutze smartVisu!) sieht das so aus:
                                          Handy:
                                          photo_2025-07-06_12-15-56.jpg
                                          photo_2025-07-06_12-07-46.jpg
                                          photo_2025-07-06_12-08-18.jpg
                                          photo_2025-07-06_12-13-42.jpg
                                          Tablet:
                                          ksnip_20250706-123230.png

                                          BananaJoeB Offline
                                          BananaJoeB Offline
                                          BananaJoe
                                          Most Active
                                          schrieb am zuletzt editiert von
                                          #357

                                          @uweabc cool, unterstützt mein Modell leider nicht, hier die Query-Abfrage (Tokens, Ids etc sind geändert)

                                          {'ip': '192.168.1.29', 'port': 6444, 'id': 133402613440365, 'online': True, 'supported': True, 'type': <DeviceType.AIR_CONDITIONER: 172>, 'name': None, 'sn': None, 'key': 'a5409a86c04b3d1834ed59ead3e083349fa8b6537878443d0ac794351b818a4f', 'token': '86389f141a1fe5188cad648496607d0e1ca032530a74c267909fff5f3237e73c77cf363c2bf6d4509cd0bb5ec9173ee7e479136f8667ef8a0563ae1bd894c712', 'power': False, 'mode': <OperationalMode.COOL: 2>, 'fan_speed': <FanSpeed.AUTO: 102>, 'swing_mode': <SwingMode.BOTH: 15>, 'horizontal_swing_angle': <SwingAngle.OFF: 0>, 'vertical_swing_angle': <SwingAngle.OFF: 0>, 'cascade_mode': <CascadeMode.OFF: 0>, 'target_temperature': 22.0, 'indoor_temperature': 26.3, 'outdoor_temperature': 26.0, 'target_humidity': 0, 'indoor_humidity': None, 'eco': False, 'turbo': False, 'freeze_protection': False, 'sleep': False, 'display_on': True, 'beep': False, 'fahrenheit': False, 'filter_alert': False, 'follow_me': False, 'purifier': False, 'self_clean': False, 'total_energy_usage': None, 'current_energy_usage': None, 'real_time_power_usage': None, 'rate_select': <RateSelect.OFF: 100>, 'aux_mode': <AuxHeatMode.OFF: 0>}
                                          

                                          ioBroker@Ubuntu 24.04 LTS (VMware) für: >260 Geräte, 5 Switche, 7 AP, 9 IP-Cam, 1 NAS 42TB, 1 ESXi 15TB, 4 Proxmox 1TB, 1 Hyper-V 48TB, 14 x Echo, 5x FireTV, 5 x Tablett/Handy VIS || >=160 Tasmota/Shelly || >=95 ZigBee || PV 8.1kW / Akku 14kWh || 2x USV 750W kaskadiert || Creality CR-10 SE 3D-Drucker

                                          U 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

                                          647

                                          Online

                                          32.4k

                                          Benutzer

                                          81.5k

                                          Themen

                                          1.3m

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

                                          • Du hast noch kein Konto? Registrieren

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