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

  1. ioBroker Community Home
  2. Deutsch
  3. Tester
  4. Adapter Hyundai (Bluelink) oder KIA (UVO)

NEWS

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

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

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

Adapter Hyundai (Bluelink) oder KIA (UVO)

Geplant Angeheftet Gesperrt Verschoben Tester
2.3k Beiträge 149 Kommentatoren 873.5k Aufrufe 139 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.
  • J Offline
    J Offline
    jwartenb
    schrieb am zuletzt editiert von
    #2090

    Hallo,
    bin neu bei iobroker.
    Nur zur Info, wenn schon bekannt oder nutzlos bitte einfach ignorieren.

    Auto: Hyundai IONIQ 6
    Adapterversion: 3.1.3

    Wie schon oben erwähnt, scheint Hyundai derzeit wild zu ändern. Bei evcc hat man sich damit geholfen, dass man auf den alten Login-Mechanismus zurückgegangen ist. Seitdem funktioniert es wieder.

    Ich habe in der Adapterkonfiguration als Sprache DE eingestellt. Im Log stand dann sinngemäß "DE ist not supportet ... available only ... de ...". Also zumindest bei DE case-sensitive.

    Ich habe dann mal auf EN umgestellt und seitdem bekomme ich Daten.

    VG
    Jochen

    arteckA 1 Antwort Letzte Antwort
    0
    • J jwartenb

      Hallo,
      bin neu bei iobroker.
      Nur zur Info, wenn schon bekannt oder nutzlos bitte einfach ignorieren.

      Auto: Hyundai IONIQ 6
      Adapterversion: 3.1.3

      Wie schon oben erwähnt, scheint Hyundai derzeit wild zu ändern. Bei evcc hat man sich damit geholfen, dass man auf den alten Login-Mechanismus zurückgegangen ist. Seitdem funktioniert es wieder.

      Ich habe in der Adapterkonfiguration als Sprache DE eingestellt. Im Log stand dann sinngemäß "DE ist not supportet ... available only ... de ...". Also zumindest bei DE case-sensitive.

      Ich habe dann mal auf EN umgestellt und seitdem bekomme ich Daten.

      VG
      Jochen

      arteckA Offline
      arteckA Offline
      arteck
      Developer Most Active
      schrieb am zuletzt editiert von
      #2091

      @jwartenb sagte in Adapter Hyundai (Bluelink) oder KIA (UVO):

      Ich habe dann mal auf EN umgestellt und seitdem bekomme ich Daten.

      interessant

      @ilovegym kannst das mal verifizieren ?

      zigbee hab ich, zwave auch, nuc's genauso und HA auch

      ilovegymI 1 Antwort Letzte Antwort
      0
      • arteckA arteck

        @jwartenb sagte in Adapter Hyundai (Bluelink) oder KIA (UVO):

        Ich habe dann mal auf EN umgestellt und seitdem bekomme ich Daten.

        interessant

        @ilovegym kannst das mal verifizieren ?

        ilovegymI Offline
        ilovegymI Offline
        ilovegym
        schrieb am zuletzt editiert von
        #2092

        @arteck sagte in Adapter Hyundai (Bluelink) oder KIA (UVO):

        @jwartenb sagte in Adapter Hyundai (Bluelink) oder KIA (UVO):

        Ich habe dann mal auf EN umgestellt und seitdem bekomme ich Daten.

        interessant

        @ilovegym kannst das mal verifizieren ?

        @jwartenb vielen Dank fuer den Tip!!

        @arteck bin zurueck auf die 3.1.6, Sprache auf EN, und siehe da, alle Werte vorhanden.. als waere nie was gewesen.. kein Fehler alles gut..

        Ioniq 5 N Hyundai...

        1 Antwort Letzte Antwort
        0
        • Peter V.P Peter V.

          Mit der nun aktuellen Version (3.1.19) bekomme ich folgenden Fehler:

          bluelink.0
          	2025-08-11 20:22:19.136	error	Cannot read properties of undefined (reading 'GeoCoord')
          bluelink.0
          	2025-08-11 20:22:19.136	error	Error on API-Request Status, ErrorCount:1
          bluelink.0
          	2025-08-11 20:22:18.516	debug	{"chassis":{"hoodOpen":false,"trunkOpen":false,"locked":true,"openDoors":{"frontRight":false,"frontLeft":false,"backLeft":false,"backRight":false},"tirePressureWarningLamp":{"rearLeft":false,"frontLeft":false,"frontRight":false,"rearRight":false,"all":false}},"climate":{"active":false,"steeringwheelHeat":false,"sideMirrorHeat":false,"rearWindowHeat":false,"defrost":false,"temperatureSetpoint":14,"temperatureUnit":0},"engine":{"ignition":false,"accessory":false,"rangeGas":266,"range":266,"plugedTo":0,"batteryCharge12v":86},"lastupdate":"2025-08-11T14:06:10.000Z"}
          bluelink.0
          	2025-08-11 20:22:18.516	debug	Set Status for U5YH5815GSL196934
          bluelink.0
          	2025-08-11 20:22:18.373	info	Error on fullStatus - new try with Status Request
          

          Daten kommen aber alle rein.
          Kia Ceed BJ2024 (Benzin)

          arteckA Offline
          arteckA Offline
          arteck
          Developer Most Active
          schrieb am zuletzt editiert von
          #2093

          @peter-v installiermal von GIT nochmal

          zigbee hab ich, zwave auch, nuc's genauso und HA auch

          Peter V.P 1 Antwort Letzte Antwort
          0
          • R Online
            R Online
            RISSN
            schrieb am zuletzt editiert von
            #2094
            
            bluelink.0
            2025-08-12 07:18:38.530	error	next auto login attempt in 1 hour or restart adapter manual
            
            bluelink.0
            2025-08-12 07:18:38.530	error	Server is not available or login credentials are wrong
            
            bluelink.0
            2025-08-12 07:18:38.530	error	Error: @EuropeController.login: Could not manage to get token: {"retId":"532d44c3-910c-46f0-8000-68c849590654","retCode":4000,"retMsg":"Bad Request","retSubMsg":"\"clientSecret is wrong. requested clientId=6d477c38-3ca4-4cf3-9557-2a1929a94654 requested clientSecret=secret\"","retValue":null}
            

            bei mir leider noch kein Login möglich beim Hyundai Tucson

            W 1 Antwort Letzte Antwort
            0
            • arteckA arteck

              @peter-v installiermal von GIT nochmal

              Peter V.P Offline
              Peter V.P Offline
              Peter V.
              schrieb am zuletzt editiert von
              #2095

              @arteck
              Danke, sah erst gut aus, nach einer aktualisierung kommt jetzt:

              bluelink.0
              	2025-08-12 18:28:20.363	error	Cannot read properties of undefined (reading 'Odometer')
              bluelink.0
              	2025-08-12 18:28:20.362	error	Error on API-Request Status, ErrorCount:1
              bluelink.0
              	2025-08-12 18:28:19.503	debug	{"chassis":{"hoodOpen":false,"trunkOpen":false,"locked":true,"openDoors":{"frontRight":false,"frontLeft":false,"backLeft":false,"backRight":false},"tirePressureWarningLamp":{"rearLeft":false,"frontLeft":false,"frontRight":false,"rearRight":false,"all":false}},"climate":{"active":false,"steeringwheelHeat":false,"sideMirrorHeat":false,"rearWindowHeat":false,"defrost":false,"temperatureSetpoint":14,"temperatureUnit":0},"engine":{"ignition":false,"accessory":false,"rangeGas":561,"range":561,"plugedTo":0,"batteryCharge12v":87},"lastupdate":"2025-08-12T12:14:53.000Z"}
              bluelink.0
              	2025-08-12 18:28:19.503	debug	Set Status for U5YH5815GSL196934
              bluelink.0
              	2025-08-12 18:28:19.378	info	Error on fullStatus - new try with Status Request
              bluelink.0
              	2025-08-12 18:28:16.826	debug	RAW {"vehicleLocation":{"coord":{"lat":47.973894,"lon":10.26625,"alt":0,"type":0},"head":290,"speed":{"value":0,"unit":0},"accuracy":{"hdop":0,"pdop":0},"time":"20250812141452"},"vehicleStatus":{"airCtrlOn":false,"engine":false,"doorLock":true,"doorOpen":{"frontLeft":0,"frontRight":0,"backLeft":0,"backRight":0},"trunkOpen":false,"airTemp":{"value":"00H","unit":0,"hvacTempType":1},"defrost":false,"lowFuelLight":false,"acc":false,"hoodOpen":false,"transCond":false,"steerWheelHeat":0,"sideBackWindowHeat":0,"dte":{"value":561,"unit":1},"tirePressureLamp":{"tirePressureLampAll":0,"tirePressureLampFL":0,"tirePressureLampFR":0,"tirePressureLampRL":0,"tirePressureLampRR":0},"seatHeaterVentState":{"frSeatHeatState":2,"flSeatHeatState":2,"rlSeatHeatState":2,"rrSeatHeatState":2},"battery":{"batSoc":87,"batState":0},"lampWireStatus":{"stopLamp":{"leftLamp":false,"rightLamp":false},"headLamp":{"headLampStatus":false,"leftLowLamp":false,"rightLowLamp":false,"leftHighLamp":false,"rightHighLamp":false,"leftBifuncLamp":false,"rightBifuncLamp":false},"turnSignalLamp":{"leftFrontLamp":false,"rightFrontLamp":false,"leftRearLamp":false,"rightRearLamp":false}},"windowOpen":{"frontLeft":0,"frontRight":0,"backLeft":0,"backRight":0},"smartKeyBatteryWarning":false,"fuelLevel":83,"washerFluidStatus":false,"breakOilStatus":false,"engineOilStatus":false,"sleepModeCheck":true,"time":"20250812141453","remoteWaitingTimeAlert":{"remoteControlAvailable":1,"remoteControlWaitingTime":168,"elapsedTime":"00:03:30"},"systemCutOffAlert":0,"tailLampStatus":0,"hazardStatus":0},"odometer":{"value":68115.2,"unit":1}}
              bluelink.0
              	2025-08-12 18:28:16.825	debug	Set fullStatus for U5YH5815GSL196934
              bluelink.0
              	2025-08-12 18:28:16.624	info	Read new update for U5YH5815GSL196934 from the server
              bluelink.0
              	2025-08-12 18:28:16.617	debug	Read new status from api for U5YH5815GSL196934
              bluelink.0
              	2025-08-12 18:28:16.260	debug	[{"vehicleConfig":{"nickname":"CEED","name":"CEED","regDate":"2024-07-22 16:25:33.470","brandIndicator":"H","id":"xxxxxxxxxxxxxxxxx","vin":"U5YH5815GSL196934","generation":"2025","ccuCCS2ProtocolSupport":false},"controller":{"userConfig":{"username":"xxxxxxxxxxxxxxxxx","password":"xxxxxxxxxxxx,"region":"EU","brand":"kia","autoLogin":true,"pin":"xxxx","vin":"","language":"de"},"session":{"accessToken":"Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","refreshToken":"xxxxxxxxxxxxxxxxx","deviceId":"xxxxxxxxxxxxxxxxxxx","tokenExpiresAt":1755019696,"controlTokenExpiresAt":0},"_environment":{"brand":"kia","host":"prd.eu-ccapi.kia.com:8080","baseUrl":"https://prd.eu-ccapi.kia.com:8080","clientId":"xxxxxxxxxxxxxxxxx","appId":"xxxxxxxxxxxxxxxxxx","endpoints":{"session":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/oauth2/authorize?response_type=code&state=test&client_id=xxxxxxxxxxxxxxxxx&redirect_uri=https://prd.eu-ccapi.kia.com:8080/api/v1/user/oauth2/redirect","login":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/signin","language":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/language","redirectUri":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/oauth2/redirect","token":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/oauth2/token","integration":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/integrationinfo","silentSignIn":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/silentsignin"},"basicToken":"Basic xxxxxxxxxxxxxxxxxxxxxxxxxxx==","GCMSenderID":"xxxxxxxxxxxxx"},"authStrategies":{"main":{"language":"de"},"fallback":{"language":"de"}}},"_fullStatus":null,"_status":null,"_location":null,"_odometer":null,"region":"EU","serverRates":{"max":-1,"current":-1}}]
              bluelink.0
              	2025-08-12 18:28:16.259	info	1 Vehicles found
              
              arteckA 1 Antwort Letzte Antwort
              0
              • Peter V.P Peter V.

                @arteck
                Danke, sah erst gut aus, nach einer aktualisierung kommt jetzt:

                bluelink.0
                	2025-08-12 18:28:20.363	error	Cannot read properties of undefined (reading 'Odometer')
                bluelink.0
                	2025-08-12 18:28:20.362	error	Error on API-Request Status, ErrorCount:1
                bluelink.0
                	2025-08-12 18:28:19.503	debug	{"chassis":{"hoodOpen":false,"trunkOpen":false,"locked":true,"openDoors":{"frontRight":false,"frontLeft":false,"backLeft":false,"backRight":false},"tirePressureWarningLamp":{"rearLeft":false,"frontLeft":false,"frontRight":false,"rearRight":false,"all":false}},"climate":{"active":false,"steeringwheelHeat":false,"sideMirrorHeat":false,"rearWindowHeat":false,"defrost":false,"temperatureSetpoint":14,"temperatureUnit":0},"engine":{"ignition":false,"accessory":false,"rangeGas":561,"range":561,"plugedTo":0,"batteryCharge12v":87},"lastupdate":"2025-08-12T12:14:53.000Z"}
                bluelink.0
                	2025-08-12 18:28:19.503	debug	Set Status for U5YH5815GSL196934
                bluelink.0
                	2025-08-12 18:28:19.378	info	Error on fullStatus - new try with Status Request
                bluelink.0
                	2025-08-12 18:28:16.826	debug	RAW {"vehicleLocation":{"coord":{"lat":47.973894,"lon":10.26625,"alt":0,"type":0},"head":290,"speed":{"value":0,"unit":0},"accuracy":{"hdop":0,"pdop":0},"time":"20250812141452"},"vehicleStatus":{"airCtrlOn":false,"engine":false,"doorLock":true,"doorOpen":{"frontLeft":0,"frontRight":0,"backLeft":0,"backRight":0},"trunkOpen":false,"airTemp":{"value":"00H","unit":0,"hvacTempType":1},"defrost":false,"lowFuelLight":false,"acc":false,"hoodOpen":false,"transCond":false,"steerWheelHeat":0,"sideBackWindowHeat":0,"dte":{"value":561,"unit":1},"tirePressureLamp":{"tirePressureLampAll":0,"tirePressureLampFL":0,"tirePressureLampFR":0,"tirePressureLampRL":0,"tirePressureLampRR":0},"seatHeaterVentState":{"frSeatHeatState":2,"flSeatHeatState":2,"rlSeatHeatState":2,"rrSeatHeatState":2},"battery":{"batSoc":87,"batState":0},"lampWireStatus":{"stopLamp":{"leftLamp":false,"rightLamp":false},"headLamp":{"headLampStatus":false,"leftLowLamp":false,"rightLowLamp":false,"leftHighLamp":false,"rightHighLamp":false,"leftBifuncLamp":false,"rightBifuncLamp":false},"turnSignalLamp":{"leftFrontLamp":false,"rightFrontLamp":false,"leftRearLamp":false,"rightRearLamp":false}},"windowOpen":{"frontLeft":0,"frontRight":0,"backLeft":0,"backRight":0},"smartKeyBatteryWarning":false,"fuelLevel":83,"washerFluidStatus":false,"breakOilStatus":false,"engineOilStatus":false,"sleepModeCheck":true,"time":"20250812141453","remoteWaitingTimeAlert":{"remoteControlAvailable":1,"remoteControlWaitingTime":168,"elapsedTime":"00:03:30"},"systemCutOffAlert":0,"tailLampStatus":0,"hazardStatus":0},"odometer":{"value":68115.2,"unit":1}}
                bluelink.0
                	2025-08-12 18:28:16.825	debug	Set fullStatus for U5YH5815GSL196934
                bluelink.0
                	2025-08-12 18:28:16.624	info	Read new update for U5YH5815GSL196934 from the server
                bluelink.0
                	2025-08-12 18:28:16.617	debug	Read new status from api for U5YH5815GSL196934
                bluelink.0
                	2025-08-12 18:28:16.260	debug	[{"vehicleConfig":{"nickname":"CEED","name":"CEED","regDate":"2024-07-22 16:25:33.470","brandIndicator":"H","id":"xxxxxxxxxxxxxxxxx","vin":"U5YH5815GSL196934","generation":"2025","ccuCCS2ProtocolSupport":false},"controller":{"userConfig":{"username":"xxxxxxxxxxxxxxxxx","password":"xxxxxxxxxxxx,"region":"EU","brand":"kia","autoLogin":true,"pin":"xxxx","vin":"","language":"de"},"session":{"accessToken":"Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","refreshToken":"xxxxxxxxxxxxxxxxx","deviceId":"xxxxxxxxxxxxxxxxxxx","tokenExpiresAt":1755019696,"controlTokenExpiresAt":0},"_environment":{"brand":"kia","host":"prd.eu-ccapi.kia.com:8080","baseUrl":"https://prd.eu-ccapi.kia.com:8080","clientId":"xxxxxxxxxxxxxxxxx","appId":"xxxxxxxxxxxxxxxxxx","endpoints":{"session":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/oauth2/authorize?response_type=code&state=test&client_id=xxxxxxxxxxxxxxxxx&redirect_uri=https://prd.eu-ccapi.kia.com:8080/api/v1/user/oauth2/redirect","login":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/signin","language":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/language","redirectUri":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/oauth2/redirect","token":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/oauth2/token","integration":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/integrationinfo","silentSignIn":"https://prd.eu-ccapi.kia.com:8080/api/v1/user/silentsignin"},"basicToken":"Basic xxxxxxxxxxxxxxxxxxxxxxxxxxx==","GCMSenderID":"xxxxxxxxxxxxx"},"authStrategies":{"main":{"language":"de"},"fallback":{"language":"de"}}},"_fullStatus":null,"_status":null,"_location":null,"_odometer":null,"region":"EU","serverRates":{"max":-1,"current":-1}}]
                bluelink.0
                	2025-08-12 18:28:16.259	info	1 Vehicles found
                
                arteckA Offline
                arteckA Offline
                arteck
                Developer Most Active
                schrieb am zuletzt editiert von arteck
                #2096

                @peter-v installier nochmal..immer diese Sonderlocken

                zigbee hab ich, zwave auch, nuc's genauso und HA auch

                Peter V.P 1 Antwort Letzte Antwort
                0
                • R RISSN
                  
                  bluelink.0
                  2025-08-12 07:18:38.530	error	next auto login attempt in 1 hour or restart adapter manual
                  
                  bluelink.0
                  2025-08-12 07:18:38.530	error	Server is not available or login credentials are wrong
                  
                  bluelink.0
                  2025-08-12 07:18:38.530	error	Error: @EuropeController.login: Could not manage to get token: {"retId":"532d44c3-910c-46f0-8000-68c849590654","retCode":4000,"retMsg":"Bad Request","retSubMsg":"\"clientSecret is wrong. requested clientId=6d477c38-3ca4-4cf3-9557-2a1929a94654 requested clientSecret=secret\"","retValue":null}
                  

                  bei mir leider noch kein Login möglich beim Hyundai Tucson

                  W Offline
                  W Offline
                  wm20320
                  schrieb am zuletzt editiert von
                  #2097

                  @rissn sagte in Adapter Hyundai (Bluelink) oder KIA (UVO):

                  
                  bluelink.0
                  2025-08-12 07:18:38.530	error	next auto login attempt in 1 hour or restart adapter manual
                  
                  bluelink.0
                  2025-08-12 07:18:38.530	error	Server is not available or login credentials are wrong
                  
                  bluelink.0
                  2025-08-12 07:18:38.530	error	Error: @EuropeController.login: Could not manage to get token: {"retId":"532d44c3-910c-46f0-8000-68c849590654","retCode":4000,"retMsg":"Bad Request","retSubMsg":"\"clientSecret is wrong. requested clientId=6d477c38-3ca4-4cf3-9557-2a1929a94654 requested clientSecret=secret\"","retValue":null}
                  

                  bei mir leider noch kein Login möglich beim Hyundai Tucson

                  Gleiches bei mir - Hyundai i10 Benziner

                  VG Marcus

                  arteckA 1 Antwort Letzte Antwort
                  0
                  • W wm20320

                    @rissn sagte in Adapter Hyundai (Bluelink) oder KIA (UVO):

                    
                    bluelink.0
                    2025-08-12 07:18:38.530	error	next auto login attempt in 1 hour or restart adapter manual
                    
                    bluelink.0
                    2025-08-12 07:18:38.530	error	Server is not available or login credentials are wrong
                    
                    bluelink.0
                    2025-08-12 07:18:38.530	error	Error: @EuropeController.login: Could not manage to get token: {"retId":"532d44c3-910c-46f0-8000-68c849590654","retCode":4000,"retMsg":"Bad Request","retSubMsg":"\"clientSecret is wrong. requested clientId=6d477c38-3ca4-4cf3-9557-2a1929a94654 requested clientSecret=secret\"","retValue":null}
                    

                    bei mir leider noch kein Login möglich beim Hyundai Tucson

                    Gleiches bei mir - Hyundai i10 Benziner

                    VG Marcus

                    arteckA Offline
                    arteckA Offline
                    arteck
                    Developer Most Active
                    schrieb am zuletzt editiert von arteck
                    #2098

                    @wm20320 dann geh zurück auf die 3.1.6 läufts dann... wenn ja dann lass laufen

                    zigbee hab ich, zwave auch, nuc's genauso und HA auch

                    W Meister MopperM 2 Antworten Letzte Antwort
                    0
                    • arteckA arteck

                      @wm20320 dann geh zurück auf die 3.1.6 läufts dann... wenn ja dann lass laufen

                      W Offline
                      W Offline
                      wm20320
                      schrieb am zuletzt editiert von
                      #2099

                      @arteck :+1: 3.1.6 läuft. Danke.

                      1 Antwort Letzte Antwort
                      1
                      • arteckA arteck

                        @wm20320 dann geh zurück auf die 3.1.6 läufts dann... wenn ja dann lass laufen

                        Meister MopperM Abwesend
                        Meister MopperM Abwesend
                        Meister Mopper
                        schrieb am zuletzt editiert von
                        #2100

                        @arteck

                        Jetzt haben sie offenbar an der Abfrage der Geo-Daten geschraubt. Diese API ist aktuell wirklich ein Graus.

                        bluelink.0	2025-08-13 15:58:00.349	error	Error on API-Request Status, ErrorCount:1
                        bluelink.0	2025-08-13 15:58:00.350	error	Cannot read properties of undefined (reading 'GeoCoord')
                        

                        Proxmox und HA

                        arteckA 1 Antwort Letzte Antwort
                        0
                        • arteckA arteck

                          @peter-v installier nochmal..immer diese Sonderlocken

                          Peter V.P Offline
                          Peter V.P Offline
                          Peter V.
                          schrieb am zuletzt editiert von
                          #2101

                          @arteck
                          Danke, werde es morgen mal testen, Kaffeespende ist schon mal unterwegs ;)

                          1 Antwort Letzte Antwort
                          1
                          • Meister MopperM Meister Mopper

                            @arteck

                            Jetzt haben sie offenbar an der Abfrage der Geo-Daten geschraubt. Diese API ist aktuell wirklich ein Graus.

                            bluelink.0	2025-08-13 15:58:00.349	error	Error on API-Request Status, ErrorCount:1
                            bluelink.0	2025-08-13 15:58:00.350	error	Cannot read properties of undefined (reading 'GeoCoord')
                            
                            arteckA Offline
                            arteckA Offline
                            arteck
                            Developer Most Active
                            schrieb am zuletzt editiert von
                            #2102

                            @meister-mopper hast du die neue von GIT geladen ?

                            zigbee hab ich, zwave auch, nuc's genauso und HA auch

                            Meister MopperM 1 Antwort Letzte Antwort
                            0
                            • arteckA arteck

                              @meister-mopper hast du die neue von GIT geladen ?

                              Meister MopperM Abwesend
                              Meister MopperM Abwesend
                              Meister Mopper
                              schrieb am zuletzt editiert von
                              #2103

                              @arteck sagte in Adapter Hyundai (Bluelink) oder KIA (UVO):

                              @meister-mopper hast du die neue von GIT geladen ?

                              Danke, mit v3.1.20 ist der Fehler weg.

                              Proxmox und HA

                              1 Antwort Letzte Antwort
                              1
                              • R Online
                                R Online
                                RISSN
                                schrieb am zuletzt editiert von
                                #2104

                                aber bei der Version 3.1.20 geht der Login beim Hyundai noch nicht? Ich bin ja von 3.1.19 auf 3.1.17 zurück, da geht es alles

                                ilovegymI arteckA 2 Antworten Letzte Antwort
                                0
                                • R RISSN

                                  aber bei der Version 3.1.20 geht der Login beim Hyundai noch nicht? Ich bin ja von 3.1.19 auf 3.1.17 zurück, da geht es alles

                                  ilovegymI Offline
                                  ilovegymI Offline
                                  ilovegym
                                  schrieb am zuletzt editiert von
                                  #2105

                                  @rissn

                                  bei mir ist die letzte die 3.1.16, alles was danach kam, geht nicht.. :)

                                  Und nein, @arteck ist nicht Merlin :) auch wenn er hier schon viel zaubert :)
                                  Ueberlegt mal, wieviel verschiedene Fahrzeugtypen es bei Hyundai/Kia gibt, mit zig verschiedenen Software und Hardware variationen..

                                  1 Antwort Letzte Antwort
                                  1
                                  • R RISSN

                                    aber bei der Version 3.1.20 geht der Login beim Hyundai noch nicht? Ich bin ja von 3.1.19 auf 3.1.17 zurück, da geht es alles

                                    arteckA Offline
                                    arteckA Offline
                                    arteck
                                    Developer Most Active
                                    schrieb am zuletzt editiert von
                                    #2106

                                    @rissn sagte in Adapter Hyundai (Bluelink) oder KIA (UVO):

                                    aber bei der Version 3.1.20 geht der Login beim Hyundai noch nicht? Ich bin ja von 3.1.19 auf 3.1.17 zurück, da geht es alles

                                    dann lass laufen .. hab schon mal gesagt.. es ändert sich nix an dem adapter ausser für KIA Fahrzeuge die mal wieder was anderes senden..
                                    wenn eine ältere Version geht (login funktioniert) dann nutze diese .. ich werde nicht eine alternative einbauen ala "welches login willst du haben neu oder alt" das ist zu viel Arbeit.. und so wie es aussieht passiert da gerade sehr viel in der API ..

                                    zigbee hab ich, zwave auch, nuc's genauso und HA auch

                                    ilovegymI 1 Antwort Letzte Antwort
                                    1
                                    • Peter V.P Offline
                                      Peter V.P Offline
                                      Peter V.
                                      schrieb am zuletzt editiert von
                                      #2107

                                      @arteck
                                      Danke für deine ganzen Mühen, Version 3.1.20 läuft bei Kia wieder ohne Fehlermeldungen und tut was es soll.
                                      Hoffen wir mal, das die an der Api/Servern nicht mehr zuviel rumschrauben.

                                      1 Antwort Letzte Antwort
                                      0
                                      • arteckA arteck

                                        @rissn sagte in Adapter Hyundai (Bluelink) oder KIA (UVO):

                                        aber bei der Version 3.1.20 geht der Login beim Hyundai noch nicht? Ich bin ja von 3.1.19 auf 3.1.17 zurück, da geht es alles

                                        dann lass laufen .. hab schon mal gesagt.. es ändert sich nix an dem adapter ausser für KIA Fahrzeuge die mal wieder was anderes senden..
                                        wenn eine ältere Version geht (login funktioniert) dann nutze diese .. ich werde nicht eine alternative einbauen ala "welches login willst du haben neu oder alt" das ist zu viel Arbeit.. und so wie es aussieht passiert da gerade sehr viel in der API ..

                                        ilovegymI Offline
                                        ilovegymI Offline
                                        ilovegym
                                        schrieb am zuletzt editiert von ilovegym
                                        #2108

                                        @arteck

                                        Hab mal meinen digitalen Codierknecht :robot_face: solange gequaelt, bis das hier rauskam:
                                        Screenshot 2025-08-16 at 15.03.35.png

                                        Ist n einfaches Dashboard, kann in jeder Vis (Vis, Vis-NG, MinuVis, Jarvis und was es noch so gibt) angezeigt werden, legt die Daten in einen State ab.
                                        Hier das Script dazu, das Hintergrundbild kann natuerlich angepasst werden, muss nich meins von der Nordschleife sein :)
                                        Eingebaut sind mir alle sinvoll vorgekommenen Werte des Adapters Bluelink, sowie von meiner Wallbox Go-E und ein paar selbst definierte (12V laedt), desweiteren eine Ladehistorie graphisch und tabellar.. :) - responsive Design, kann man auch aufm Smartphone ansehen

                                        /******************************************************
                                        * IONIQ 5 N – Bluelink Dashboard (HTML) for ioBroker
                                        * Version: 1.6.6  (SVG-Chart responsive, volle Kartenbreite & ~Tabelle-Höhe)
                                        * (c) 2025 Bernd / ilovegym – privat
                                        ******************************************************/
                                        
                                        /* =================== KONFIG =================== */
                                        const BLUELINK_INST = 'bluelink.0';
                                        let   VEHICLE_ID    = '';          // leer = Auto-Detect
                                        const OUT_HTML_DP   = '0_userdata.0.vis.IoniqDashboardHTML';
                                        
                                        // Eigene Zusatz-DPs
                                        const DP_12V_LADEN  = '0_userdata.0.Zaehler.Hyundai_12V';   // true = 12V lädt
                                        const DP_KM_YESTER  = '0_userdata.0.Zaehler.Hyundai_KM_';   // km gestern
                                        
                                        // Wallbox (go-e)
                                        const WB = {
                                         energy:  'go-e.0.loaded_energy_kwh',
                                         state:   'go-e.0.car',                // 1 Standby, 2 Laden, 3 Warten auf Auto, 4 Fertig
                                         power:   'go-e.0.energy.power',
                                         temp1:   'go-e.0.temperatures.temperature1',
                                         temp2:   'go-e.0.temperatures.temperature2',
                                         allow:   'go-e.0.allow_charging',
                                         amp:     'go-e.0.ampere'
                                        };
                                        const WB_STATE_TXT = {1:'Standby',2:'Laden',3:'Warte auf Auto',4:'Fertig'};
                                        
                                        // Ladehistorie (Samples werden hier gespeichert)
                                        const HIST_SAMPLES_DP = '0_userdata.0.Ioniq.History.samples';   // string (JSON Array: {t,soc,wb})
                                        const HIST_LAST_TS_DP = '0_userdata.0.Ioniq.History.lastSample'; // number (ms)
                                        const SAMPLE_INTERVAL_MS = 5 * 60 * 1000; // alle 5 Minuten
                                        const MAX_SAMPLES = 3000; // ~7 Tage bei 5-Minuten-Samples
                                        
                                        // Debug
                                        const DEBUG = false;
                                        
                                        /* =================== UTIL =================== */
                                        function ensureState(id, def = '', common = {name:'IONIQ 5 N Dashboard HTML', type:'string', role:'html', read:true, write:false}) {
                                         try { if (!existsObject(id)) createState(id, def, true, common); } catch (e) { log('ensureState error ' + e, 'warn'); }
                                        }
                                        function ensureDataPoint(id, def, common){ try{ if(!existsObject(id)) createState(id, def, true, common); }catch(e){} }
                                        function JP(...parts){ return parts.filter(p => p !== '' && p != null).join('.'); }
                                        function es(id){ try { return !!(id && existsState(id)); } catch(_) { return false; } }
                                        function gs(id){ try { return es(id)? getState(id).val:undefined; } catch(_) { return undefined; } }
                                        function ss(id, val){ try { setState(id, val, true); } catch(_){} }
                                        function firstExisting(paths){ if(!Array.isArray(paths)) return {path:null,val:undefined}; for(const p of paths){ if(es(p)){ const v=gs(p); if(v!==undefined && v!==null) return {path:p,val:v}; } } return {path:null,val:undefined}; }
                                        function P(...parts){ return JP(BLUELINK_INST, VEHICLE_ID, ...parts); }
                                        
                                        /* =================== VIN-AUTODETECT =================== */
                                        function detectVehicleId(){
                                         try{
                                           const rows = getObjectView('system','state',{ startkey: BLUELINK_INST+'.', endkey: BLUELINK_INST+'.\u9999' }).rows;
                                           const seen = {};
                                           for(const r of rows){
                                             const id = r.id || '';
                                             const seg = id.split('.');
                                             if(seg.length>=3){
                                               const veh = seg[2];
                                               if(veh && !['info','remote','vehicles'].includes(veh)) seen[veh]=true;
                                             }
                                           }
                                           const list = Object.keys(seen);
                                           return list.length ? list[0] : '';
                                         }catch(e){ log('VIN-Detect: '+e,'warn'); return ''; }
                                        }
                                        
                                        /* =================== KANDIDATEN =================== */
                                        function candidates(){
                                         return {
                                           // Identität / Fahrt
                                           carName: [ P('general.carName'), P('general.modelName') ],
                                           vin:     [ P('general.vin') ],
                                           odometer_km: [ P('odometer.value') ],
                                           speed:       [ P('vehicleLocation.speed') ],
                                        
                                           // Standort (mit Fallbacks)
                                           lat: [ P('vehicleLocation.lat'), P('location.coord.lat') ],
                                           lon: [ P('vehicleLocation.lon'), P('location.coord.lon') ],
                                           position_text: [ P('vehicleLocation.position_text'), P('location.formattedAddress') ],
                                           position_url:  [ P('vehicleLocation.position_url') ],
                                        
                                           // HV & 12V
                                           soc_pct:            [ P('vehicleStatus.battery.soc') ],
                                           charge_active:      [ P('vehicleStatus.battery.charge') ],
                                           minutes_to_charged: [ P('vehicleStatus.battery.minutes_to_charged') ],
                                           plugin_code:        [ P('vehicleStatus.battery.plugin') ],
                                           soc12v:             [ P('vehicleStatus.battery.soc-12V') ],
                                           state12v:           [ P('vehicleStatus.battery.state-12V') ],
                                           soh:                [ P('vehicleStatus.battery.soh') ],
                                           charge12v:          [ DP_12V_LADEN ],
                                        
                                           // Klima & Komfort
                                           hvacOn:     [ P('vehicleStatus.airCtrlOn') ],
                                           insideTemp: [ P('vehicleStatus.airTemp') ],
                                           airClean:   [ P('vehicleStatusRaw.vehicleStatus.airCleaning.airPurifierStatus') ],
                                           defrost:    [ P('vehicleStatusRaw.vehicleStatus.defrost') ],
                                           seatFL:     [ P('vehicleStatusRaw.vehicleStatus.seatHeaterVentState.flSeatHeatState') ],
                                           seatFR:     [ P('vehicleStatusRaw.vehicleStatus.seatHeaterVentState.frSeatHeatState') ],
                                           seatRL:     [ P('vehicleStatusRaw.vehicleStatus.seatHeaterVentState.rlSeatHeatState') ],
                                           seatRR:     [ P('vehicleStatusRaw.vehicleStatus.seatHeaterVentState.rrSeatHeatState') ],
                                           steerHeat:  [ P('vehicleStatus.steerWheelHeat') ],
                                        
                                           // Öffnungen / Fenster
                                           doorFL: [ P('vehicleStatus.doorOpen.frontLeft') ],
                                           doorFR: [ P('vehicleStatus.doorOpen.frontRight') ],
                                           doorRL: [ P('vehicleStatus.doorOpen.backLeft') ],
                                           doorRR: [ P('vehicleStatus.doorOpen.backRight') ],
                                           trunk:  [ P('vehicleStatus.trunkOpen') ],
                                           frunk:  [ P('vehicleStatus.hoodOpen') ],
                                           winFL:  [ P('vehicleStatusRaw.vehicleStatus.windowOpen.frontLeft') ],
                                           winFR:  [ P('vehicleStatusRaw.vehicleStatus.windowOpen.frontRight') ],
                                           winRL:  [ P('vehicleStatusRaw.vehicleStatus.windowOpen.backLeft') ],
                                           winRR:  [ P('vehicleStatusRaw.vehicleStatus.windowOpen.backRight') ],
                                        
                                           // Reifen-Warnlampen
                                           tireFL: [ P('vehicleStatusRaw.vehicleStatus.tirePressureLamp.tirePressureLampFL') ],
                                           tireFR: [ P('vehicleStatusRaw.vehicleStatus.tirePressureLamp.tirePressureLampFR') ],
                                           tireRL: [ P('vehicleStatusRaw.vehicleStatus.tirePressureLamp.tirePressureLampRL') ],
                                           tireRR: [ P('vehicleStatusRaw.vehicleStatus.tirePressureLamp.tirePressureLampRR') ],
                                        
                                           // Flüssigkeiten & Warnungen
                                           dte:        [ P('vehicleStatusRaw.vehicleStatus.dte.value') ],
                                           washer:     [ P('vehicleStatus.washerFluidStatus') ],         // false=OK, true=leer
                                           smartKeyBat:[ P('vehicleStatus.smartKeyBatteryWarning') ],     // true=Warnung
                                           breakOil:   [ P('vehicleStatus.breakOilStatus') ],             // false=OK, true=Niedrig
                                        
                                           // Wallbox
                                           wb_energy: [ WB.energy ],
                                           wb_state:  [ WB.state ],
                                           wb_power:  [ WB.power ],
                                           wb_temp1:  [ WB.temp1 ],
                                           wb_temp2:  [ WB.temp2 ],
                                           wb_allow:  [ WB.allow ],
                                           wb_amp:    [ WB.amp ],
                                        
                                           // Zeit / extra
                                           lastUpdate:  [ P('info.lastUpdate'), P('vehicleStatus.updatedAt') ],
                                           kmYesterday: [ DP_KM_YESTER ]
                                         };
                                        }
                                        
                                        /* =================== CSS =================== */
                                        function css(){ return `
                                        <style>
                                        :root{
                                         --bg:#0a0c10; --card:rgba(18,21,28,0.88); --muted:#8a93a6; --text:#e7ecf6;
                                         --ok:#33d17a; --warn:#ffbf3c; --err:#ff5c5c; --accent:#60a5fa; --chip:#1b2030; --chipText:#cfe0ff;
                                        }
                                        *{box-sizing:border-box}
                                        .wrap{
                                         font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,sans-serif;
                                         color:var(--text); padding:16px; min-height:100vh;
                                         background:url('http://10.1.1.2:8081/files/0_userdata.0/background/IMG_2721.jpeg') center/cover no-repeat fixed;
                                        }
                                        .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px;align-items:stretch}
                                        .card{background:var(--card);border-radius:12px;padding:12px;box-shadow:0 4px 14px rgba(0,0,0,.25);height:100%;display:flex;flex-direction:column}
                                        .row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
                                        .title{display:flex;align-items:center;gap:10px;font-weight:700;font-size:18px;margin-bottom:10px}
                                        .kpi{font-size:26px;font-weight:800}
                                        .sub{color:var(--muted);font-size:13px}
                                        .badge{background:#1b2030;color:#cfe0ff;padding:6px 12px;border-radius:10px;font-size:14px;display:inline-block;max-width:100%;white-space:normal;word-break:break-word;text-align:center}
                                        .stat{display:flex;justify-content:space-between;margin:4px 0;font-size:13px}
                                        .meter{height:10px;background:#0f1220;border-radius:8px;overflow:hidden}
                                        .meter>span{display:block;height:100%}
                                        .kv{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;margin-top:8px}
                                        .tile{background:#0f1220;border-radius:8px;padding:6px;font-size:12px;display:flex;align-items:center;gap:6px}
                                        .ok{color:var(--ok)} .warn{color:var(--warn)} .err{color:var(--err)} .acc{color:var(--accent)}
                                        .footer{margin-top:8px;color:var(--muted);font-size:12px;text-align:right}
                                        table{width:100%;border-collapse:collapse;font-size:12px}
                                        th,td{padding:6px 8px;border-bottom:1px solid #222}
                                        th{text-align:left;color:#cfe0ff}
                                        /* Chart Box: gleiche Höhe wie Tabelle (~280px), passt sich Breite an */
                                        .chartBox{width:100%;height:280px;display:block}
                                        .chartBox svg{width:100%;height:100%;display:block}
                                        </style>`; }
                                        
                                        /* =================== SVG CHART BUILDER =================== */
                                        function buildHistorySVG(labels, soc, kwh){
                                         // Basisgröße für viewBox (skaliert über CSS auf 100%x100% in .chartBox)
                                         const W=720, H=280; // größer als vorher
                                         const padL=44, padR=14, padT=14, padB=34;
                                         const x0=padL, y0=padT, x1=W-padR, y1=H-padB;
                                         const w=x1-x0, h=y1-y0;
                                         const n = Math.max(1, labels.length||1);
                                         const xAt = (i)=> x0 + (n<=1 ? 0 : (w * i/(n-1)));
                                         const ySoc = (v)=> y0 + (1 - (Math.max(0,Math.min(100, +v||0))/100)) * h;
                                        
                                         // Bars scale
                                         let maxK=0; for (let i=0;i<kwh.length;i++){ const v=+kwh[i]||0; if (v>maxK) maxK=v; }
                                         if (maxK<1) maxK=1;
                                         const barW = Math.max(8, Math.min(28, w / (n*1.8)));
                                         const bars = [];
                                         for (let i=0;i<n;i++){
                                           const xx = xAt(i);
                                           const kh = ( ( (+kwh[i]||0)/maxK ) * h );
                                           const x = xx - barW/2;
                                           const y = y1 - kh;
                                           const bw = barW;
                                           const bh = kh;
                                           bars.push(`<rect x="${x.toFixed(1)}" y="${y.toFixed(1)}" width="${bw.toFixed(1)}" height="${bh.toFixed(1)}" rx="2" fill="#60a5fa" />`);
                                         }
                                        
                                         // SOC path
                                         let d='';
                                         for (let i=0;i<n;i++){
                                           const xx = xAt(i), yy = ySoc(soc[i]||0);
                                           d += (i===0? 'M':' L') + xx.toFixed(1) + ' ' + yy.toFixed(1);
                                         }
                                         const points = soc.map((v,i)=>{
                                           const xx=xAt(i), yy=ySoc(v||0);
                                           return `<circle cx="${xx.toFixed(1)}" cy="${yy.toFixed(1)}" r="3" fill="#33d17a"/>`;
                                         }).join('');
                                        
                                         // grid & labels
                                         const grid=[];
                                         for (let gy=0; gy<=5; gy++){
                                           const yy = y0 + h*(gy/5);
                                           grid.push(`<line x1="${x0}" y1="${yy.toFixed(1)}" x2="${x1}" y2="${yy.toFixed(1)}" stroke="rgba(255,255,255,0.15)" stroke-width="1"/>`);
                                         }
                                         const ylab=[];
                                         for (let gy=0; gy<=5; gy++){
                                           const val = 100 - gy*20;
                                           const yy = y0 + h*(gy/5);
                                           ylab.push(`<text x="${x0-8}" y="${yy+4}" fill="#cfe0ff" font-size="12" text-anchor="end">${val}</text>`);
                                         }
                                         const xlab = labels.map((t,i)=>{
                                           const xx = xAt(i);
                                           return `<text x="${xx}" y="${y1+18}" fill="#cfe0ff" font-size="12" text-anchor="middle">${String(t)}</text>`;
                                         }).join('');
                                        
                                         return `
                                         <svg viewBox="0 0 ${W} ${H}" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Ladehistorie">
                                           <rect x="0" y="0" width="${W}" height="${H}" fill="transparent"/>
                                           <rect x="${x0}" y="${y0}" width="${w}" height="${h}" rx="6" fill="rgba(255,255,255,0.04)"/>
                                           ${grid.join('')}
                                           ${ylab.join('')}
                                           ${xlab}
                                           ${bars.join('')}
                                           <path d="${d}" fill="none" stroke="#33d17a" stroke-width="2.5"/>
                                           ${points}
                                           <!-- Legende -->
                                           <g>
                                             <rect x="${x0+6}" y="${y0+6}" width="12" height="3" fill="#33d17a"/><text x="${x0+24}" y="${y0+14}" font-size="13" fill="#cfe0ff">SOC %</text>
                                             <rect x="${x0+92}" y="${y0+6}" width="12" height="12" fill="#60a5fa"/><text x="${x0+110}" y="${y0+16}" font-size="13" fill="#cfe0ff">kWh/Tag</text>
                                           </g>
                                         </svg>`;
                                        }
                                        
                                        /* =================== RENDER =================== */
                                        function renderHTML(d, hist, lastSamples){
                                         if (!d || d.__noVin){
                                           return `${css()}<div class="wrap"><div class="card"><div class="kpi">Bluelink</div><div class="sub">Bitte VIN (VEHICLE_ID) setzen oder Auto-Detect abwarten.</div></div></div>`;
                                         }
                                        
                                         const hvColor = p=>p<75?'#ff5c5c':(p<80?'#ffbf3c':'#33d17a');
                                         const socBar = p => (p!=null ? `
                                           <div class="meter" style="height:14px;border-radius:7px;overflow:hidden">
                                             <span style="width:${Math.max(0,Math.min(100,p))}%;background:${hvColor(p)}"></span>
                                           </div>
                                           <div style="font-size:12px;text-align:right;margin-top:2px">${p}%</div>` : '–');
                                        
                                         const seatTxt = v => (v===1?'<span class="heatAnim">🔥 Heizen</span>':(v===0?'<span class="coolAnim">❄️ Kühlen</span>':'Aus'));
                                         const flag = (v, ok='geschlossen', bad='offen') => v===true?`<b class="err">${bad}</b>`:(v===false?`<b class="ok">${ok}</b>`:'–');
                                         const tireTxt = v => (v===true ? '<b class="warn">Warn</b>' : (v===false ? '<b class="ok">OK</b>' : '–'));
                                        
                                         const locStr = d.address || '–';
                                         const coords = (d.lat!=null && d.lon!=null) ? `${(+d.lat).toFixed(5)}, ${(+d.lon).toFixed(5)}` : '–';
                                         const wbStateTxt = (d.wb_stateNum!=null? (WB_STATE_TXT[d.wb_stateNum]||String(d.wb_stateNum)) : (d.wb_stateText||'–'));
                                        
                                         // Historie-Daten (letzte 7 Tage)
                                         const labels = hist.labels || ['Mo','Di','Mi','Do','Fr','Sa','So'];
                                         const socLine = hist.dailySoc || [0,0,0,0,0,0,0];
                                         const kwhBars = hist.dailyKwh || [0,0,0,0,0,0,0];
                                        
                                         // Tabelle der letzten 10 Einträge
                                         let tableRows = '';
                                         if (lastSamples && lastSamples.length){
                                           const last10 = lastSamples.slice(-10);
                                           tableRows = last10.map(s=>{
                                             const dt = new Date(s.t).toLocaleString();
                                             const soc = (typeof s.soc==='number') ? (Math.round(s.soc*10)/10)+' %' : '–';
                                             const wb  = (typeof s.wb ==='number') ? (Math.round(s.wb*100)/100).toFixed(2)+' kWh' : '–';
                                             return `<tr><td>${dt}</td><td>${soc}</td><td>${wb}</td></tr>`;
                                           }).join('');
                                         }
                                        
                                         const svgChart = buildHistorySVG(labels, socLine, kwhBars);
                                        
                                         return `
                                         ${css()}
                                         <div class="wrap">
                                           <div class="title"><span class="kpi">${d.carName||'IONIQ 5 N'}</span> <span class="badge">${d.vin||''}</span></div>
                                        
                                           <div class="grid">
                                             <!-- HV Akku -->
                                             <div class="card">
                                               <div class="row">🔋 <b>State of Charge</b></div>
                                               <div class="kpi" style="margin:6px 0">${d.soc!=null? d.soc+' %' : '–'}</div>
                                               ${socBar(d.soc)}
                                               <div class="stat"><span>Laden</span><span class="${d.charging?'chargeAnim':''}"><b>${d.charging===true?'aktiv':(d.charging===false?'nein':'–')}</b></span></div>
                                               <div class="stat"><span>Min. bis voll</span><span><b>${d.minToFull!=null? d.minToFull : '–'}</b></span></div>
                                               <div class="stat"><span>Reichweite</span><span><b>${d.dte!=null? d.dte+' km':'–'}</b></span></div>
                                             </div>
                                        
                                             <!-- 12V / SOH -->
                                             <div class="card">
                                               <div class="row">🔋 <b>12V & SOH</b></div>
                                               <div class="stat"><span>12V SoC</span><span style="flex:1;margin-left:10px">${socBar(d.soc12v)}</span></div>
                                               <div class="stat"><span>12V Status</span><span><b>${d.state12v ?? '–'}</b></span></div>
                                               <div class="stat"><span>12V lädt</span><span><b>${d.charge12v===true?'Ja':(d.charge12v===false?'Nein':'–')}</b></span></div>
                                               <div class="stat"><span>SOH (HV)</span><span><b>${d.soh!=null? d.soh+' %':'–'}</b></span></div>
                                             </div>
                                        
                                             <!-- Fahrzeug -->
                                             <div class="card">
                                               <div class="row">🚗 <b>Fahrzeug</b></div>
                                               <div class="stat"><span>Odometer</span><span><b>${d.odoKm!=null? d.odoKm+' km':'–'}</b></span></div>
                                               <div class="stat"><span>Gestern gefahren</span><span><b>${d.kmYesterday!=null? d.kmYesterday+' km':'–'}</b></span></div>
                                             </div>
                                        
                                             <!-- Standort -->
                                             <div class="card">
                                               <div class="row">📍 <b>Standort</b></div>
                                               <div class="badge">${locStr}</div>
                                               <div class="sub" style="margin-top:8px">Koordinaten: <b>${coords}</b></div>
                                             </div>
                                        
                                             <!-- Türen -->
                                             <div class="card">
                                               <div class="row">🚪 <b>Öffnungen</b></div>
                                               <div class="kv">
                                                 <div class="tile">VL: ${flag(d.doorFL)}</div>
                                                 <div class="tile">VR: ${flag(d.doorFR)}</div>
                                                 <div class="tile">HL: ${flag(d.doorRL)}</div>
                                                 <div class="tile">HR: ${flag(d.doorRR)}</div>
                                                 <div class="tile">Kofferraum: ${flag(d.trunk)}</div>
                                                 <div class="tile">Frunk: ${flag(d.frunk)}</div>
                                               </div>
                                               <div class="sub" style="margin-top:6px">Gesamt: ${ [d.doorFL,d.doorFR,d.doorRL,d.doorRR,d.trunk,d.frunk].some(v=>v===true) ? '<b class="err">offen</b>' : '<b class="ok">alle zu</b>' }</div>
                                             </div>
                                        
                                             <!-- Fenster -->
                                             <div class="card">
                                               <div class="row">🪟 <b>Fenster</b></div>
                                               <div class="kv">
                                                 <div class="tile">VL: ${flag(d.winFL,'zu','offen')}</div>
                                                 <div class="tile">VR: ${flag(d.winFR,'zu','offen')}</div>
                                                 <div class="tile">HL: ${flag(d.winRL,'zu','offen')}</div>
                                                 <div class="tile">HR: ${flag(d.winRR,'zu','offen')}</div>
                                               </div>
                                             </div>
                                        
                                             <!-- Reifen -->
                                             <div class="card">
                                               <div class="row">🛞 <b>Reifen</b></div>
                                               <div class="kv">
                                                 <div class="tile">VL: ${tireTxt(d.tireFL)}</div>
                                                 <div class="tile">VR: ${tireTxt(d.tireFR)}</div>
                                                 <div class="tile">HL: ${tireTxt(d.tireRL)}</div>
                                                 <div class="tile">HR: ${tireTxt(d.tireRR)}</div>
                                               </div>
                                             </div>
                                        
                                             <!-- Klima & Komfort -->
                                             <div class="card">
                                               <div class="row">❄️ <b>Klima & Komfort</b></div>
                                               <div class="stat"><span>Klima</span><span class="${d.hvacOn?'fanAnim':''}"><b>${d.hvacOn===true?'AN':(d.hvacOn===false?'AUS':'–')}</b></span></div>
                                               <div class="stat"><span>Innen</span><span><b>${d.tIn!=null? d.tIn+' °C':'–'}</b></span></div>
                                               <div class="stat"><span>Luftreiniger</span><span><b>${d.airClean===true?'AN':(d.airClean===false?'AUS':'–')}</b></span></div>
                                               <div class="stat"><span>Defrost</span><span><b>${d.defrost===true?'AN':(d.defrost===false?'AUS':'–')}</b></span></div>
                                               <div class="stat"><span>Lenkrad</span><span>${d.steerHeat===true?'<span class="heatAnim">🔥</span>':'AUS'}</span></div>
                                               <div class="sub" style="margin-top:6px">Sitze:</div>
                                               <div class="kv">
                                                 <div class="tile">VL: <b>${seatTxt(d.seatFL)}</b></div>
                                                 <div class="tile">VR: <b>${seatTxt(d.seatFR)}</b></div>
                                                 <div class="tile">HL: <b>${seatTxt(d.seatRL)}</b></div>
                                                 <div class="tile">HR: <b>${seatTxt(d.seatRR)}</b></div>
                                               </div>
                                             </div>
                                        
                                             <!-- Fahrzeugstatus -->
                                             <div class="card">
                                               <div class="row">ℹ️ <b>Fahrzeugstatus</b></div>
                                               <div class="kv">
                                                 <div class="tile">Wischerwasser: ${d.washer===true?'<b class="err">LEER</b>':(d.washer===false?'<b class="ok">OK</b>':'–')}</div>
                                                 <div class="tile">Bremsöl: ${d.breakOil===true?'<b class="err">NIEDRIG</b>':(d.breakOil===false?'<b class="ok">OK</b>':'–')}</div>
                                                 <div class="tile">Smartkey: ${d.smartKeyBat===true?'<b class="warn">WARNUNG</b>':(d.smartKeyBat===false?'<b class="ok">OK</b>':'–')}</div>
                                               </div>
                                             </div>
                                        
                                             <!-- Wallbox -->
                                             <div class="card">
                                               <div class="row">🔌 <b>Wallbox</b></div>
                                               <div class="kv">
                                                 <div class="tile">Status: <b>${wbStateTxt}</b></div>
                                                 <div class="tile">Leistung: <b>${d.wb_powerFmt || '–'}</b></div>
                                                 <div class="tile">Energie: <b>${d.wb_energyFmt || '–'} kWh</b></div>
                                                 <div class="tile">Ampere: <b>${d.wb_ampere!=null? d.wb_ampere+' A':'–'}</b></div>
                                                 <div class="tile">Freigabe: <b>${d.wb_allow===true?'Ja':(d.wb_allow===false?'Nein':'–')}</b></div>
                                                 <div class="tile">Temp1: <b>${d.wb_temp1!=null? d.wb_temp1+' °C':'–'}</b></div>
                                                 <div class="tile">Temp2: <b>${d.wb_temp2!=null? d.wb_temp2+' °C':'–'}</b></div>
                                               </div>
                                             </div>
                                        
                                             <!-- Ladehistorie (7 Tage) – reines SVG, volle Breite/Höhe -->
                                             <div class="card">
                                               <div class="row">📈 <b>Ladehistorie (7 Tage)</b></div>
                                               <div class="chartBox">
                                                 ${svgChart}
                                               </div>
                                             </div>
                                        
                                             <!-- Ladehistorie Tabelle (letzte 10 Samples) -->
                                             <div class="card">
                                               <div class="row">⚡ <b>Ladehistorie – letzte 10 Werte</b></div>
                                               ${ (lastSamples && lastSamples.length)
                                                   ? `<table><tr><th>Zeitpunkt</th><th>SOC</th><th>Wallbox</th></tr>${tableRows}</table>`
                                                   : `<div class="sub">Keine Daten vorhanden.</div>` }
                                             </div>
                                           </div>
                                        
                                           <div class="footer">Zuletzt aktualisiert: ${d.lastUpdate || new Date().toLocaleString()}</div>
                                         </div>`;
                                        }
                                        
                                        /* =================== HISTORIE: DPs + Verarbeitung =================== */
                                        function ensureHistoryDPs(){
                                         ensureDataPoint(HIST_SAMPLES_DP, '[]', {name:'Ioniq History Samples', type:'string', role:'json'});
                                         ensureDataPoint(HIST_LAST_TS_DP, 0,    {name:'Ioniq History Last Sample', type:'number', role:'value.time'});
                                        }
                                        function _normalizeSamples(arr){
                                         const now = Date.now();
                                         const twelveH = 12*3600*1000;
                                         return arr.map(s=>{
                                           if(!s) return null;
                                           let t = Number(s.t);
                                           if (!isFinite(t)) return null;
                                           if (t < 1e12) t = t * 1000; // Sekunden -> ms
                                           if (t > now + twelveH) return null; // Zukunft verwerfen
                                           const out = { t };
                                           if (typeof s.soc === 'number' && isFinite(s.soc)) out.soc = s.soc;
                                           if (typeof s.wb  === 'number' && isFinite(s.wb )) out.wb  = s.wb;
                                           return out;
                                         }).filter(Boolean);
                                        }
                                        function loadSamples(){
                                         try{
                                           const txt=gs(HIST_SAMPLES_DP);
                                           if(!txt) return [];
                                           const parsed = JSON.parse(txt);
                                           const arr = Array.isArray(parsed)? parsed : [];
                                           return _normalizeSamples(arr);
                                         }catch(_){ return []; }
                                        }
                                        function saveSamples(arr){
                                         try{
                                           if (arr.length>MAX_SAMPLES) arr = arr.slice(arr.length-MAX_SAMPLES);
                                           ss(HIST_SAMPLES_DP, JSON.stringify(arr));
                                         }catch(_){}
                                        }
                                        function trySample(nowMs, data){
                                         const lastTs = Number(gs(HIST_LAST_TS_DP) || 0);
                                         if (nowMs - lastTs < SAMPLE_INTERVAL_MS) return;
                                        
                                         const soc = data._hist_soc;
                                         const wb  = data._hist_wb_energy;
                                        
                                         if (soc==null && wb==null) {
                                           ss(HIST_LAST_TS_DP, nowMs);
                                           if (DEBUG) log('[IONIQ5N] Sample SKIP: keine Werte (soc/wb beide leer)', 'info');
                                           return;
                                         }
                                        
                                         let arr = loadSamples();
                                         arr.push({ t: nowMs, soc: soc, wb: wb });
                                         saveSamples(arr);
                                         ss(HIST_LAST_TS_DP, nowMs);
                                        
                                         if (DEBUG) {
                                           const socTxt = (soc==null)?'—':String(soc);
                                           const wbTxt  = (wb==null)?'—':String(wb);
                                           log(`[IONIQ5N] Sample OK @ ${new Date(nowMs).toLocaleString()} | SOC=${socTxt} | WB=${wbTxt}`, 'info');
                                         }
                                        }
                                        function computeDailyFromSamples(nowMs){
                                         const arr = loadSamples();
                                         // Labels & Tageskeys (letzte 7 Tage inkl. heute)
                                         const labels=[], dayKeys=[];
                                         for(let i=6;i>=0;i--){
                                           const d=new Date(nowMs - i*24*3600*1000);
                                           labels.push(d.toLocaleDateString(undefined,{weekday:'short'}));
                                           dayKeys.push(`${d.getFullYear()}-${('0'+(d.getMonth()+1)).slice(-2)}-${('0'+d.getDate()).slice(-2)}`);
                                         }
                                         if(!arr.length) return {labels, dailySoc:[0,0,0,0,0,0,0], dailyKwh:[0,0,0,0,0,0,0]};
                                         const byDay={};
                                         for(const s of arr){
                                           const d=new Date(s.t);
                                           const key=`${d.getFullYear()}-${('0'+(d.getMonth()+1)).slice(-2)}-${('0'+d.getDate()).slice(-2)}`;
                                           if(!byDay[key]) byDay[key]={soc:[], wb:[]};
                                           if(typeof s.soc==='number') byDay[key].soc.push(s.soc);
                                           if(typeof s.wb ==='number') byDay[key].wb.push(s.wb);
                                         }
                                         const dailySoc=[], dailyKwh=[];
                                         for(const key of dayKeys){
                                           const g=byDay[key];
                                           if(!g){ dailySoc.push(0); dailyKwh.push(0); continue; }
                                           const avgSoc = g.soc.length ? Math.round(g.soc.reduce((a,b)=>a+b,0)/g.soc.length) : 0;
                                           let kwh=0;
                                           if(g.wb.length){
                                             const mn=Math.min.apply(null,g.wb), mx=Math.max.apply(null,g.wb);
                                             kwh = mx-mn; if(!isFinite(kwh)||kwh<0) kwh=0;
                                             kwh = Math.round(kwh*100)/100;
                                           }
                                           dailySoc.push(avgSoc);
                                           dailyKwh.push(kwh);
                                         }
                                         return {labels, dailySoc, dailyKwh};
                                        }
                                        
                                        /* =================== DATEN SAMMELN =================== */
                                        function readAll(){
                                         const cand = candidates();
                                         const pick = (name, map=v=>v)=>{
                                           const {val} = firstExisting(cand[name]||[]);
                                           if (val===undefined) return undefined;
                                           try{
                                             if (typeof val === 'string' && !isNaN(val)) return map(Number(val));
                                             return map(val);
                                           }catch(_){ return val; }
                                         };
                                         const toBool = (v) => (typeof v==='boolean') ? v : (v!=null ? Number(v)>0 : undefined);
                                        
                                         // Fahrwerte
                                         const odoKm = (function(){
                                           const v = pick('odometer_km', x=>x);
                                           if (v===undefined) return undefined;
                                           const num = typeof v==='string' ? parseFloat(v.replace(/[^\d.,]/g,'').replace(',','.')) : Number(v);
                                           return isNaN(num) ? undefined : Math.round(num);
                                         })();
                                        
                                         // Wallbox Zahlen
                                         const wb_stateNum = pick('wb_state', Number);
                                         const wb_powerNum = pick('wb_power', Number);
                                         const wb_energyNum= pick('wb_energy', Number);
                                        
                                         const data = {
                                           // Kopf
                                           carName: pick('carName'),
                                           vin: pick('vin'),
                                        
                                           // HV / 12V
                                           soc: pick('soc_pct', v => Math.round(Number(v))),
                                           charging: pick('charge_active', toBool),
                                           minToFull: pick('minutes_to_charged', Number),
                                           soc12v: pick('soc12v', v => Math.round(Number(v))),
                                           state12v: pick('state12v'),
                                           soh: pick('soh', v => Math.round(Number(v))),
                                           charge12v: pick('charge12v', v => v === true || v === 'true' || Number(v) === 1),
                                        
                                           // Reichweite & Klima
                                           dte: pick('dte', v => Math.round(Number(v))),
                                           hvacOn: pick('hvacOn', toBool),
                                           tIn: pick('insideTemp', v => Math.round(Number(v)*10)/10),
                                           airClean: pick('airClean', toBool),
                                           defrost: pick('defrost', toBool),
                                           seatFL: pick('seatFL', Number),
                                           seatFR: pick('seatFR', Number),
                                           seatRL: pick('seatRL', Number),
                                           seatRR: pick('seatRR', Number),
                                           steerHeat: pick('steerHeat', toBool),
                                        
                                           // Öffnungen / Fenster
                                           doorFL: pick('doorFL', toBool),
                                           doorFR: pick('doorFR', toBool),
                                           doorRL: pick('doorRL', toBool),
                                           doorRR: pick('doorRR', toBool),
                                           trunk: pick('trunk', toBool),
                                           frunk: pick('frunk', toBool),
                                           winFL: pick('winFL', toBool),
                                           winFR: pick('winFR', toBool),
                                           winRL: pick('winRL', toBool),
                                           winRR: pick('winRR', toBool),
                                        
                                           // Reifenlampen
                                           tireFL: pick('tireFL', toBool),
                                           tireFR: pick('tireFR', toBool),
                                           tireRL: pick('tireRL', toBool),
                                           tireRR: pick('tireRR', toBool),
                                        
                                           // Flüssigkeiten & Warnungen
                                           washer: pick('washer', toBool),
                                           breakOil: pick('breakOil', toBool),
                                           smartKeyBat: pick('smartKeyBat', toBool),
                                        
                                           // Standort
                                           lat: pick('lat', Number),
                                           lon: pick('lon', Number),
                                           address: pick('position_text', String),
                                           positionUrl: pick('position_url', String),
                                        
                                           // Wallbox – formatierte Strings
                                           wb_stateNum,
                                           wb_stateText: (wb_stateNum!=null ? (WB_STATE_TXT[wb_stateNum] || String(wb_stateNum)) : undefined),
                                           wb_powerFmt:  (wb_powerNum!=null ? (wb_powerNum >= 1000 ? (Math.round(wb_powerNum/100)/10)+' kW' : Math.round(wb_powerNum)+' W') : undefined),
                                           wb_energyFmt: (wb_energyNum!=null ? wb_energyNum.toFixed(2) : undefined),
                                           wb_ampere: pick('wb_amp', v => Math.round(Number(v))),
                                           wb_allow: pick('wb_allow', toBool),
                                           wb_temp1: pick('wb_temp1', v => Math.round(Number(v))),
                                           wb_temp2: pick('wb_temp2', v => Math.round(Number(v))),
                                        
                                           // Zeit / extra
                                           lastUpdate: (function(){
                                             const raw = pick('lastUpdate');
                                             if (!raw) return '';
                                             try{ const d=new Date(raw); return isNaN(d)? String(raw) : d.toLocaleString(); }catch(_){ return String(raw); }
                                           })(),
                                           kmYesterday: pick('kmYesterday', v=> (v==null? undefined : Math.round(Number(v)))),
                                        
                                           // Rohwerte für Historie-Sampling
                                           _hist_soc: pick('soc_pct', Number),
                                           _hist_wb_energy: wb_energyNum,
                                        
                                           // Odometer
                                           odoKm
                                         };
                                        
                                         return data;
                                        }
                                        
                                        /* =================== MAIN =================== */
                                        ensureState(OUT_HTML_DP);
                                        ensureHistoryDPs();
                                        let vinAnnounced = false;
                                        
                                        function update(){
                                         try{
                                           const nowMs = Date.now();
                                        
                                           if (!VEHICLE_ID){
                                             VEHICLE_ID = detectVehicleId();
                                             if (VEHICLE_ID && !vinAnnounced){ log('[IONIQ5N] Auto-Detected VIN: '+VEHICLE_ID,'info'); vinAnnounced=true; }
                                           }
                                           if (!VEHICLE_ID){
                                             ss(OUT_HTML_DP, renderHTML({__noVin:true}, {labels:[],dailySoc:[],dailyKwh:[]}, []));
                                             return;
                                           }
                                        
                                           const data = readAll();
                                           trySample(nowMs, data);
                                           const hist = computeDailyFromSamples(nowMs);
                                           const lastSamples = loadSamples();
                                           const html = renderHTML(data, hist, lastSamples);
                                           ss(OUT_HTML_DP, html);
                                         }catch(e){ log('Update error: '+e, 'error'); }
                                        }
                                        
                                        // Initial + Intervall
                                        update();
                                        schedule('*/30 * * * * *', update);
                                        

                                        Wolfgang GaryW 1 Antwort Letzte Antwort
                                        4
                                        • ilovegymI ilovegym

                                          @arteck

                                          Hab mal meinen digitalen Codierknecht :robot_face: solange gequaelt, bis das hier rauskam:
                                          Screenshot 2025-08-16 at 15.03.35.png

                                          Ist n einfaches Dashboard, kann in jeder Vis (Vis, Vis-NG, MinuVis, Jarvis und was es noch so gibt) angezeigt werden, legt die Daten in einen State ab.
                                          Hier das Script dazu, das Hintergrundbild kann natuerlich angepasst werden, muss nich meins von der Nordschleife sein :)
                                          Eingebaut sind mir alle sinvoll vorgekommenen Werte des Adapters Bluelink, sowie von meiner Wallbox Go-E und ein paar selbst definierte (12V laedt), desweiteren eine Ladehistorie graphisch und tabellar.. :) - responsive Design, kann man auch aufm Smartphone ansehen

                                          /******************************************************
                                          * IONIQ 5 N – Bluelink Dashboard (HTML) for ioBroker
                                          * Version: 1.6.6  (SVG-Chart responsive, volle Kartenbreite & ~Tabelle-Höhe)
                                          * (c) 2025 Bernd / ilovegym – privat
                                          ******************************************************/
                                          
                                          /* =================== KONFIG =================== */
                                          const BLUELINK_INST = 'bluelink.0';
                                          let   VEHICLE_ID    = '';          // leer = Auto-Detect
                                          const OUT_HTML_DP   = '0_userdata.0.vis.IoniqDashboardHTML';
                                          
                                          // Eigene Zusatz-DPs
                                          const DP_12V_LADEN  = '0_userdata.0.Zaehler.Hyundai_12V';   // true = 12V lädt
                                          const DP_KM_YESTER  = '0_userdata.0.Zaehler.Hyundai_KM_';   // km gestern
                                          
                                          // Wallbox (go-e)
                                          const WB = {
                                           energy:  'go-e.0.loaded_energy_kwh',
                                           state:   'go-e.0.car',                // 1 Standby, 2 Laden, 3 Warten auf Auto, 4 Fertig
                                           power:   'go-e.0.energy.power',
                                           temp1:   'go-e.0.temperatures.temperature1',
                                           temp2:   'go-e.0.temperatures.temperature2',
                                           allow:   'go-e.0.allow_charging',
                                           amp:     'go-e.0.ampere'
                                          };
                                          const WB_STATE_TXT = {1:'Standby',2:'Laden',3:'Warte auf Auto',4:'Fertig'};
                                          
                                          // Ladehistorie (Samples werden hier gespeichert)
                                          const HIST_SAMPLES_DP = '0_userdata.0.Ioniq.History.samples';   // string (JSON Array: {t,soc,wb})
                                          const HIST_LAST_TS_DP = '0_userdata.0.Ioniq.History.lastSample'; // number (ms)
                                          const SAMPLE_INTERVAL_MS = 5 * 60 * 1000; // alle 5 Minuten
                                          const MAX_SAMPLES = 3000; // ~7 Tage bei 5-Minuten-Samples
                                          
                                          // Debug
                                          const DEBUG = false;
                                          
                                          /* =================== UTIL =================== */
                                          function ensureState(id, def = '', common = {name:'IONIQ 5 N Dashboard HTML', type:'string', role:'html', read:true, write:false}) {
                                           try { if (!existsObject(id)) createState(id, def, true, common); } catch (e) { log('ensureState error ' + e, 'warn'); }
                                          }
                                          function ensureDataPoint(id, def, common){ try{ if(!existsObject(id)) createState(id, def, true, common); }catch(e){} }
                                          function JP(...parts){ return parts.filter(p => p !== '' && p != null).join('.'); }
                                          function es(id){ try { return !!(id && existsState(id)); } catch(_) { return false; } }
                                          function gs(id){ try { return es(id)? getState(id).val:undefined; } catch(_) { return undefined; } }
                                          function ss(id, val){ try { setState(id, val, true); } catch(_){} }
                                          function firstExisting(paths){ if(!Array.isArray(paths)) return {path:null,val:undefined}; for(const p of paths){ if(es(p)){ const v=gs(p); if(v!==undefined && v!==null) return {path:p,val:v}; } } return {path:null,val:undefined}; }
                                          function P(...parts){ return JP(BLUELINK_INST, VEHICLE_ID, ...parts); }
                                          
                                          /* =================== VIN-AUTODETECT =================== */
                                          function detectVehicleId(){
                                           try{
                                             const rows = getObjectView('system','state',{ startkey: BLUELINK_INST+'.', endkey: BLUELINK_INST+'.\u9999' }).rows;
                                             const seen = {};
                                             for(const r of rows){
                                               const id = r.id || '';
                                               const seg = id.split('.');
                                               if(seg.length>=3){
                                                 const veh = seg[2];
                                                 if(veh && !['info','remote','vehicles'].includes(veh)) seen[veh]=true;
                                               }
                                             }
                                             const list = Object.keys(seen);
                                             return list.length ? list[0] : '';
                                           }catch(e){ log('VIN-Detect: '+e,'warn'); return ''; }
                                          }
                                          
                                          /* =================== KANDIDATEN =================== */
                                          function candidates(){
                                           return {
                                             // Identität / Fahrt
                                             carName: [ P('general.carName'), P('general.modelName') ],
                                             vin:     [ P('general.vin') ],
                                             odometer_km: [ P('odometer.value') ],
                                             speed:       [ P('vehicleLocation.speed') ],
                                          
                                             // Standort (mit Fallbacks)
                                             lat: [ P('vehicleLocation.lat'), P('location.coord.lat') ],
                                             lon: [ P('vehicleLocation.lon'), P('location.coord.lon') ],
                                             position_text: [ P('vehicleLocation.position_text'), P('location.formattedAddress') ],
                                             position_url:  [ P('vehicleLocation.position_url') ],
                                          
                                             // HV & 12V
                                             soc_pct:            [ P('vehicleStatus.battery.soc') ],
                                             charge_active:      [ P('vehicleStatus.battery.charge') ],
                                             minutes_to_charged: [ P('vehicleStatus.battery.minutes_to_charged') ],
                                             plugin_code:        [ P('vehicleStatus.battery.plugin') ],
                                             soc12v:             [ P('vehicleStatus.battery.soc-12V') ],
                                             state12v:           [ P('vehicleStatus.battery.state-12V') ],
                                             soh:                [ P('vehicleStatus.battery.soh') ],
                                             charge12v:          [ DP_12V_LADEN ],
                                          
                                             // Klima & Komfort
                                             hvacOn:     [ P('vehicleStatus.airCtrlOn') ],
                                             insideTemp: [ P('vehicleStatus.airTemp') ],
                                             airClean:   [ P('vehicleStatusRaw.vehicleStatus.airCleaning.airPurifierStatus') ],
                                             defrost:    [ P('vehicleStatusRaw.vehicleStatus.defrost') ],
                                             seatFL:     [ P('vehicleStatusRaw.vehicleStatus.seatHeaterVentState.flSeatHeatState') ],
                                             seatFR:     [ P('vehicleStatusRaw.vehicleStatus.seatHeaterVentState.frSeatHeatState') ],
                                             seatRL:     [ P('vehicleStatusRaw.vehicleStatus.seatHeaterVentState.rlSeatHeatState') ],
                                             seatRR:     [ P('vehicleStatusRaw.vehicleStatus.seatHeaterVentState.rrSeatHeatState') ],
                                             steerHeat:  [ P('vehicleStatus.steerWheelHeat') ],
                                          
                                             // Öffnungen / Fenster
                                             doorFL: [ P('vehicleStatus.doorOpen.frontLeft') ],
                                             doorFR: [ P('vehicleStatus.doorOpen.frontRight') ],
                                             doorRL: [ P('vehicleStatus.doorOpen.backLeft') ],
                                             doorRR: [ P('vehicleStatus.doorOpen.backRight') ],
                                             trunk:  [ P('vehicleStatus.trunkOpen') ],
                                             frunk:  [ P('vehicleStatus.hoodOpen') ],
                                             winFL:  [ P('vehicleStatusRaw.vehicleStatus.windowOpen.frontLeft') ],
                                             winFR:  [ P('vehicleStatusRaw.vehicleStatus.windowOpen.frontRight') ],
                                             winRL:  [ P('vehicleStatusRaw.vehicleStatus.windowOpen.backLeft') ],
                                             winRR:  [ P('vehicleStatusRaw.vehicleStatus.windowOpen.backRight') ],
                                          
                                             // Reifen-Warnlampen
                                             tireFL: [ P('vehicleStatusRaw.vehicleStatus.tirePressureLamp.tirePressureLampFL') ],
                                             tireFR: [ P('vehicleStatusRaw.vehicleStatus.tirePressureLamp.tirePressureLampFR') ],
                                             tireRL: [ P('vehicleStatusRaw.vehicleStatus.tirePressureLamp.tirePressureLampRL') ],
                                             tireRR: [ P('vehicleStatusRaw.vehicleStatus.tirePressureLamp.tirePressureLampRR') ],
                                          
                                             // Flüssigkeiten & Warnungen
                                             dte:        [ P('vehicleStatusRaw.vehicleStatus.dte.value') ],
                                             washer:     [ P('vehicleStatus.washerFluidStatus') ],         // false=OK, true=leer
                                             smartKeyBat:[ P('vehicleStatus.smartKeyBatteryWarning') ],     // true=Warnung
                                             breakOil:   [ P('vehicleStatus.breakOilStatus') ],             // false=OK, true=Niedrig
                                          
                                             // Wallbox
                                             wb_energy: [ WB.energy ],
                                             wb_state:  [ WB.state ],
                                             wb_power:  [ WB.power ],
                                             wb_temp1:  [ WB.temp1 ],
                                             wb_temp2:  [ WB.temp2 ],
                                             wb_allow:  [ WB.allow ],
                                             wb_amp:    [ WB.amp ],
                                          
                                             // Zeit / extra
                                             lastUpdate:  [ P('info.lastUpdate'), P('vehicleStatus.updatedAt') ],
                                             kmYesterday: [ DP_KM_YESTER ]
                                           };
                                          }
                                          
                                          /* =================== CSS =================== */
                                          function css(){ return `
                                          <style>
                                          :root{
                                           --bg:#0a0c10; --card:rgba(18,21,28,0.88); --muted:#8a93a6; --text:#e7ecf6;
                                           --ok:#33d17a; --warn:#ffbf3c; --err:#ff5c5c; --accent:#60a5fa; --chip:#1b2030; --chipText:#cfe0ff;
                                          }
                                          *{box-sizing:border-box}
                                          .wrap{
                                           font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,sans-serif;
                                           color:var(--text); padding:16px; min-height:100vh;
                                           background:url('http://10.1.1.2:8081/files/0_userdata.0/background/IMG_2721.jpeg') center/cover no-repeat fixed;
                                          }
                                          .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px;align-items:stretch}
                                          .card{background:var(--card);border-radius:12px;padding:12px;box-shadow:0 4px 14px rgba(0,0,0,.25);height:100%;display:flex;flex-direction:column}
                                          .row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
                                          .title{display:flex;align-items:center;gap:10px;font-weight:700;font-size:18px;margin-bottom:10px}
                                          .kpi{font-size:26px;font-weight:800}
                                          .sub{color:var(--muted);font-size:13px}
                                          .badge{background:#1b2030;color:#cfe0ff;padding:6px 12px;border-radius:10px;font-size:14px;display:inline-block;max-width:100%;white-space:normal;word-break:break-word;text-align:center}
                                          .stat{display:flex;justify-content:space-between;margin:4px 0;font-size:13px}
                                          .meter{height:10px;background:#0f1220;border-radius:8px;overflow:hidden}
                                          .meter>span{display:block;height:100%}
                                          .kv{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;margin-top:8px}
                                          .tile{background:#0f1220;border-radius:8px;padding:6px;font-size:12px;display:flex;align-items:center;gap:6px}
                                          .ok{color:var(--ok)} .warn{color:var(--warn)} .err{color:var(--err)} .acc{color:var(--accent)}
                                          .footer{margin-top:8px;color:var(--muted);font-size:12px;text-align:right}
                                          table{width:100%;border-collapse:collapse;font-size:12px}
                                          th,td{padding:6px 8px;border-bottom:1px solid #222}
                                          th{text-align:left;color:#cfe0ff}
                                          /* Chart Box: gleiche Höhe wie Tabelle (~280px), passt sich Breite an */
                                          .chartBox{width:100%;height:280px;display:block}
                                          .chartBox svg{width:100%;height:100%;display:block}
                                          </style>`; }
                                          
                                          /* =================== SVG CHART BUILDER =================== */
                                          function buildHistorySVG(labels, soc, kwh){
                                           // Basisgröße für viewBox (skaliert über CSS auf 100%x100% in .chartBox)
                                           const W=720, H=280; // größer als vorher
                                           const padL=44, padR=14, padT=14, padB=34;
                                           const x0=padL, y0=padT, x1=W-padR, y1=H-padB;
                                           const w=x1-x0, h=y1-y0;
                                           const n = Math.max(1, labels.length||1);
                                           const xAt = (i)=> x0 + (n<=1 ? 0 : (w * i/(n-1)));
                                           const ySoc = (v)=> y0 + (1 - (Math.max(0,Math.min(100, +v||0))/100)) * h;
                                          
                                           // Bars scale
                                           let maxK=0; for (let i=0;i<kwh.length;i++){ const v=+kwh[i]||0; if (v>maxK) maxK=v; }
                                           if (maxK<1) maxK=1;
                                           const barW = Math.max(8, Math.min(28, w / (n*1.8)));
                                           const bars = [];
                                           for (let i=0;i<n;i++){
                                             const xx = xAt(i);
                                             const kh = ( ( (+kwh[i]||0)/maxK ) * h );
                                             const x = xx - barW/2;
                                             const y = y1 - kh;
                                             const bw = barW;
                                             const bh = kh;
                                             bars.push(`<rect x="${x.toFixed(1)}" y="${y.toFixed(1)}" width="${bw.toFixed(1)}" height="${bh.toFixed(1)}" rx="2" fill="#60a5fa" />`);
                                           }
                                          
                                           // SOC path
                                           let d='';
                                           for (let i=0;i<n;i++){
                                             const xx = xAt(i), yy = ySoc(soc[i]||0);
                                             d += (i===0? 'M':' L') + xx.toFixed(1) + ' ' + yy.toFixed(1);
                                           }
                                           const points = soc.map((v,i)=>{
                                             const xx=xAt(i), yy=ySoc(v||0);
                                             return `<circle cx="${xx.toFixed(1)}" cy="${yy.toFixed(1)}" r="3" fill="#33d17a"/>`;
                                           }).join('');
                                          
                                           // grid & labels
                                           const grid=[];
                                           for (let gy=0; gy<=5; gy++){
                                             const yy = y0 + h*(gy/5);
                                             grid.push(`<line x1="${x0}" y1="${yy.toFixed(1)}" x2="${x1}" y2="${yy.toFixed(1)}" stroke="rgba(255,255,255,0.15)" stroke-width="1"/>`);
                                           }
                                           const ylab=[];
                                           for (let gy=0; gy<=5; gy++){
                                             const val = 100 - gy*20;
                                             const yy = y0 + h*(gy/5);
                                             ylab.push(`<text x="${x0-8}" y="${yy+4}" fill="#cfe0ff" font-size="12" text-anchor="end">${val}</text>`);
                                           }
                                           const xlab = labels.map((t,i)=>{
                                             const xx = xAt(i);
                                             return `<text x="${xx}" y="${y1+18}" fill="#cfe0ff" font-size="12" text-anchor="middle">${String(t)}</text>`;
                                           }).join('');
                                          
                                           return `
                                           <svg viewBox="0 0 ${W} ${H}" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Ladehistorie">
                                             <rect x="0" y="0" width="${W}" height="${H}" fill="transparent"/>
                                             <rect x="${x0}" y="${y0}" width="${w}" height="${h}" rx="6" fill="rgba(255,255,255,0.04)"/>
                                             ${grid.join('')}
                                             ${ylab.join('')}
                                             ${xlab}
                                             ${bars.join('')}
                                             <path d="${d}" fill="none" stroke="#33d17a" stroke-width="2.5"/>
                                             ${points}
                                             <!-- Legende -->
                                             <g>
                                               <rect x="${x0+6}" y="${y0+6}" width="12" height="3" fill="#33d17a"/><text x="${x0+24}" y="${y0+14}" font-size="13" fill="#cfe0ff">SOC %</text>
                                               <rect x="${x0+92}" y="${y0+6}" width="12" height="12" fill="#60a5fa"/><text x="${x0+110}" y="${y0+16}" font-size="13" fill="#cfe0ff">kWh/Tag</text>
                                             </g>
                                           </svg>`;
                                          }
                                          
                                          /* =================== RENDER =================== */
                                          function renderHTML(d, hist, lastSamples){
                                           if (!d || d.__noVin){
                                             return `${css()}<div class="wrap"><div class="card"><div class="kpi">Bluelink</div><div class="sub">Bitte VIN (VEHICLE_ID) setzen oder Auto-Detect abwarten.</div></div></div>`;
                                           }
                                          
                                           const hvColor = p=>p<75?'#ff5c5c':(p<80?'#ffbf3c':'#33d17a');
                                           const socBar = p => (p!=null ? `
                                             <div class="meter" style="height:14px;border-radius:7px;overflow:hidden">
                                               <span style="width:${Math.max(0,Math.min(100,p))}%;background:${hvColor(p)}"></span>
                                             </div>
                                             <div style="font-size:12px;text-align:right;margin-top:2px">${p}%</div>` : '–');
                                          
                                           const seatTxt = v => (v===1?'<span class="heatAnim">🔥 Heizen</span>':(v===0?'<span class="coolAnim">❄️ Kühlen</span>':'Aus'));
                                           const flag = (v, ok='geschlossen', bad='offen') => v===true?`<b class="err">${bad}</b>`:(v===false?`<b class="ok">${ok}</b>`:'–');
                                           const tireTxt = v => (v===true ? '<b class="warn">Warn</b>' : (v===false ? '<b class="ok">OK</b>' : '–'));
                                          
                                           const locStr = d.address || '–';
                                           const coords = (d.lat!=null && d.lon!=null) ? `${(+d.lat).toFixed(5)}, ${(+d.lon).toFixed(5)}` : '–';
                                           const wbStateTxt = (d.wb_stateNum!=null? (WB_STATE_TXT[d.wb_stateNum]||String(d.wb_stateNum)) : (d.wb_stateText||'–'));
                                          
                                           // Historie-Daten (letzte 7 Tage)
                                           const labels = hist.labels || ['Mo','Di','Mi','Do','Fr','Sa','So'];
                                           const socLine = hist.dailySoc || [0,0,0,0,0,0,0];
                                           const kwhBars = hist.dailyKwh || [0,0,0,0,0,0,0];
                                          
                                           // Tabelle der letzten 10 Einträge
                                           let tableRows = '';
                                           if (lastSamples && lastSamples.length){
                                             const last10 = lastSamples.slice(-10);
                                             tableRows = last10.map(s=>{
                                               const dt = new Date(s.t).toLocaleString();
                                               const soc = (typeof s.soc==='number') ? (Math.round(s.soc*10)/10)+' %' : '–';
                                               const wb  = (typeof s.wb ==='number') ? (Math.round(s.wb*100)/100).toFixed(2)+' kWh' : '–';
                                               return `<tr><td>${dt}</td><td>${soc}</td><td>${wb}</td></tr>`;
                                             }).join('');
                                           }
                                          
                                           const svgChart = buildHistorySVG(labels, socLine, kwhBars);
                                          
                                           return `
                                           ${css()}
                                           <div class="wrap">
                                             <div class="title"><span class="kpi">${d.carName||'IONIQ 5 N'}</span> <span class="badge">${d.vin||''}</span></div>
                                          
                                             <div class="grid">
                                               <!-- HV Akku -->
                                               <div class="card">
                                                 <div class="row">🔋 <b>State of Charge</b></div>
                                                 <div class="kpi" style="margin:6px 0">${d.soc!=null? d.soc+' %' : '–'}</div>
                                                 ${socBar(d.soc)}
                                                 <div class="stat"><span>Laden</span><span class="${d.charging?'chargeAnim':''}"><b>${d.charging===true?'aktiv':(d.charging===false?'nein':'–')}</b></span></div>
                                                 <div class="stat"><span>Min. bis voll</span><span><b>${d.minToFull!=null? d.minToFull : '–'}</b></span></div>
                                                 <div class="stat"><span>Reichweite</span><span><b>${d.dte!=null? d.dte+' km':'–'}</b></span></div>
                                               </div>
                                          
                                               <!-- 12V / SOH -->
                                               <div class="card">
                                                 <div class="row">🔋 <b>12V & SOH</b></div>
                                                 <div class="stat"><span>12V SoC</span><span style="flex:1;margin-left:10px">${socBar(d.soc12v)}</span></div>
                                                 <div class="stat"><span>12V Status</span><span><b>${d.state12v ?? '–'}</b></span></div>
                                                 <div class="stat"><span>12V lädt</span><span><b>${d.charge12v===true?'Ja':(d.charge12v===false?'Nein':'–')}</b></span></div>
                                                 <div class="stat"><span>SOH (HV)</span><span><b>${d.soh!=null? d.soh+' %':'–'}</b></span></div>
                                               </div>
                                          
                                               <!-- Fahrzeug -->
                                               <div class="card">
                                                 <div class="row">🚗 <b>Fahrzeug</b></div>
                                                 <div class="stat"><span>Odometer</span><span><b>${d.odoKm!=null? d.odoKm+' km':'–'}</b></span></div>
                                                 <div class="stat"><span>Gestern gefahren</span><span><b>${d.kmYesterday!=null? d.kmYesterday+' km':'–'}</b></span></div>
                                               </div>
                                          
                                               <!-- Standort -->
                                               <div class="card">
                                                 <div class="row">📍 <b>Standort</b></div>
                                                 <div class="badge">${locStr}</div>
                                                 <div class="sub" style="margin-top:8px">Koordinaten: <b>${coords}</b></div>
                                               </div>
                                          
                                               <!-- Türen -->
                                               <div class="card">
                                                 <div class="row">🚪 <b>Öffnungen</b></div>
                                                 <div class="kv">
                                                   <div class="tile">VL: ${flag(d.doorFL)}</div>
                                                   <div class="tile">VR: ${flag(d.doorFR)}</div>
                                                   <div class="tile">HL: ${flag(d.doorRL)}</div>
                                                   <div class="tile">HR: ${flag(d.doorRR)}</div>
                                                   <div class="tile">Kofferraum: ${flag(d.trunk)}</div>
                                                   <div class="tile">Frunk: ${flag(d.frunk)}</div>
                                                 </div>
                                                 <div class="sub" style="margin-top:6px">Gesamt: ${ [d.doorFL,d.doorFR,d.doorRL,d.doorRR,d.trunk,d.frunk].some(v=>v===true) ? '<b class="err">offen</b>' : '<b class="ok">alle zu</b>' }</div>
                                               </div>
                                          
                                               <!-- Fenster -->
                                               <div class="card">
                                                 <div class="row">🪟 <b>Fenster</b></div>
                                                 <div class="kv">
                                                   <div class="tile">VL: ${flag(d.winFL,'zu','offen')}</div>
                                                   <div class="tile">VR: ${flag(d.winFR,'zu','offen')}</div>
                                                   <div class="tile">HL: ${flag(d.winRL,'zu','offen')}</div>
                                                   <div class="tile">HR: ${flag(d.winRR,'zu','offen')}</div>
                                                 </div>
                                               </div>
                                          
                                               <!-- Reifen -->
                                               <div class="card">
                                                 <div class="row">🛞 <b>Reifen</b></div>
                                                 <div class="kv">
                                                   <div class="tile">VL: ${tireTxt(d.tireFL)}</div>
                                                   <div class="tile">VR: ${tireTxt(d.tireFR)}</div>
                                                   <div class="tile">HL: ${tireTxt(d.tireRL)}</div>
                                                   <div class="tile">HR: ${tireTxt(d.tireRR)}</div>
                                                 </div>
                                               </div>
                                          
                                               <!-- Klima & Komfort -->
                                               <div class="card">
                                                 <div class="row">❄️ <b>Klima & Komfort</b></div>
                                                 <div class="stat"><span>Klima</span><span class="${d.hvacOn?'fanAnim':''}"><b>${d.hvacOn===true?'AN':(d.hvacOn===false?'AUS':'–')}</b></span></div>
                                                 <div class="stat"><span>Innen</span><span><b>${d.tIn!=null? d.tIn+' °C':'–'}</b></span></div>
                                                 <div class="stat"><span>Luftreiniger</span><span><b>${d.airClean===true?'AN':(d.airClean===false?'AUS':'–')}</b></span></div>
                                                 <div class="stat"><span>Defrost</span><span><b>${d.defrost===true?'AN':(d.defrost===false?'AUS':'–')}</b></span></div>
                                                 <div class="stat"><span>Lenkrad</span><span>${d.steerHeat===true?'<span class="heatAnim">🔥</span>':'AUS'}</span></div>
                                                 <div class="sub" style="margin-top:6px">Sitze:</div>
                                                 <div class="kv">
                                                   <div class="tile">VL: <b>${seatTxt(d.seatFL)}</b></div>
                                                   <div class="tile">VR: <b>${seatTxt(d.seatFR)}</b></div>
                                                   <div class="tile">HL: <b>${seatTxt(d.seatRL)}</b></div>
                                                   <div class="tile">HR: <b>${seatTxt(d.seatRR)}</b></div>
                                                 </div>
                                               </div>
                                          
                                               <!-- Fahrzeugstatus -->
                                               <div class="card">
                                                 <div class="row">ℹ️ <b>Fahrzeugstatus</b></div>
                                                 <div class="kv">
                                                   <div class="tile">Wischerwasser: ${d.washer===true?'<b class="err">LEER</b>':(d.washer===false?'<b class="ok">OK</b>':'–')}</div>
                                                   <div class="tile">Bremsöl: ${d.breakOil===true?'<b class="err">NIEDRIG</b>':(d.breakOil===false?'<b class="ok">OK</b>':'–')}</div>
                                                   <div class="tile">Smartkey: ${d.smartKeyBat===true?'<b class="warn">WARNUNG</b>':(d.smartKeyBat===false?'<b class="ok">OK</b>':'–')}</div>
                                                 </div>
                                               </div>
                                          
                                               <!-- Wallbox -->
                                               <div class="card">
                                                 <div class="row">🔌 <b>Wallbox</b></div>
                                                 <div class="kv">
                                                   <div class="tile">Status: <b>${wbStateTxt}</b></div>
                                                   <div class="tile">Leistung: <b>${d.wb_powerFmt || '–'}</b></div>
                                                   <div class="tile">Energie: <b>${d.wb_energyFmt || '–'} kWh</b></div>
                                                   <div class="tile">Ampere: <b>${d.wb_ampere!=null? d.wb_ampere+' A':'–'}</b></div>
                                                   <div class="tile">Freigabe: <b>${d.wb_allow===true?'Ja':(d.wb_allow===false?'Nein':'–')}</b></div>
                                                   <div class="tile">Temp1: <b>${d.wb_temp1!=null? d.wb_temp1+' °C':'–'}</b></div>
                                                   <div class="tile">Temp2: <b>${d.wb_temp2!=null? d.wb_temp2+' °C':'–'}</b></div>
                                                 </div>
                                               </div>
                                          
                                               <!-- Ladehistorie (7 Tage) – reines SVG, volle Breite/Höhe -->
                                               <div class="card">
                                                 <div class="row">📈 <b>Ladehistorie (7 Tage)</b></div>
                                                 <div class="chartBox">
                                                   ${svgChart}
                                                 </div>
                                               </div>
                                          
                                               <!-- Ladehistorie Tabelle (letzte 10 Samples) -->
                                               <div class="card">
                                                 <div class="row">⚡ <b>Ladehistorie – letzte 10 Werte</b></div>
                                                 ${ (lastSamples && lastSamples.length)
                                                     ? `<table><tr><th>Zeitpunkt</th><th>SOC</th><th>Wallbox</th></tr>${tableRows}</table>`
                                                     : `<div class="sub">Keine Daten vorhanden.</div>` }
                                               </div>
                                             </div>
                                          
                                             <div class="footer">Zuletzt aktualisiert: ${d.lastUpdate || new Date().toLocaleString()}</div>
                                           </div>`;
                                          }
                                          
                                          /* =================== HISTORIE: DPs + Verarbeitung =================== */
                                          function ensureHistoryDPs(){
                                           ensureDataPoint(HIST_SAMPLES_DP, '[]', {name:'Ioniq History Samples', type:'string', role:'json'});
                                           ensureDataPoint(HIST_LAST_TS_DP, 0,    {name:'Ioniq History Last Sample', type:'number', role:'value.time'});
                                          }
                                          function _normalizeSamples(arr){
                                           const now = Date.now();
                                           const twelveH = 12*3600*1000;
                                           return arr.map(s=>{
                                             if(!s) return null;
                                             let t = Number(s.t);
                                             if (!isFinite(t)) return null;
                                             if (t < 1e12) t = t * 1000; // Sekunden -> ms
                                             if (t > now + twelveH) return null; // Zukunft verwerfen
                                             const out = { t };
                                             if (typeof s.soc === 'number' && isFinite(s.soc)) out.soc = s.soc;
                                             if (typeof s.wb  === 'number' && isFinite(s.wb )) out.wb  = s.wb;
                                             return out;
                                           }).filter(Boolean);
                                          }
                                          function loadSamples(){
                                           try{
                                             const txt=gs(HIST_SAMPLES_DP);
                                             if(!txt) return [];
                                             const parsed = JSON.parse(txt);
                                             const arr = Array.isArray(parsed)? parsed : [];
                                             return _normalizeSamples(arr);
                                           }catch(_){ return []; }
                                          }
                                          function saveSamples(arr){
                                           try{
                                             if (arr.length>MAX_SAMPLES) arr = arr.slice(arr.length-MAX_SAMPLES);
                                             ss(HIST_SAMPLES_DP, JSON.stringify(arr));
                                           }catch(_){}
                                          }
                                          function trySample(nowMs, data){
                                           const lastTs = Number(gs(HIST_LAST_TS_DP) || 0);
                                           if (nowMs - lastTs < SAMPLE_INTERVAL_MS) return;
                                          
                                           const soc = data._hist_soc;
                                           const wb  = data._hist_wb_energy;
                                          
                                           if (soc==null && wb==null) {
                                             ss(HIST_LAST_TS_DP, nowMs);
                                             if (DEBUG) log('[IONIQ5N] Sample SKIP: keine Werte (soc/wb beide leer)', 'info');
                                             return;
                                           }
                                          
                                           let arr = loadSamples();
                                           arr.push({ t: nowMs, soc: soc, wb: wb });
                                           saveSamples(arr);
                                           ss(HIST_LAST_TS_DP, nowMs);
                                          
                                           if (DEBUG) {
                                             const socTxt = (soc==null)?'—':String(soc);
                                             const wbTxt  = (wb==null)?'—':String(wb);
                                             log(`[IONIQ5N] Sample OK @ ${new Date(nowMs).toLocaleString()} | SOC=${socTxt} | WB=${wbTxt}`, 'info');
                                           }
                                          }
                                          function computeDailyFromSamples(nowMs){
                                           const arr = loadSamples();
                                           // Labels & Tageskeys (letzte 7 Tage inkl. heute)
                                           const labels=[], dayKeys=[];
                                           for(let i=6;i>=0;i--){
                                             const d=new Date(nowMs - i*24*3600*1000);
                                             labels.push(d.toLocaleDateString(undefined,{weekday:'short'}));
                                             dayKeys.push(`${d.getFullYear()}-${('0'+(d.getMonth()+1)).slice(-2)}-${('0'+d.getDate()).slice(-2)}`);
                                           }
                                           if(!arr.length) return {labels, dailySoc:[0,0,0,0,0,0,0], dailyKwh:[0,0,0,0,0,0,0]};
                                           const byDay={};
                                           for(const s of arr){
                                             const d=new Date(s.t);
                                             const key=`${d.getFullYear()}-${('0'+(d.getMonth()+1)).slice(-2)}-${('0'+d.getDate()).slice(-2)}`;
                                             if(!byDay[key]) byDay[key]={soc:[], wb:[]};
                                             if(typeof s.soc==='number') byDay[key].soc.push(s.soc);
                                             if(typeof s.wb ==='number') byDay[key].wb.push(s.wb);
                                           }
                                           const dailySoc=[], dailyKwh=[];
                                           for(const key of dayKeys){
                                             const g=byDay[key];
                                             if(!g){ dailySoc.push(0); dailyKwh.push(0); continue; }
                                             const avgSoc = g.soc.length ? Math.round(g.soc.reduce((a,b)=>a+b,0)/g.soc.length) : 0;
                                             let kwh=0;
                                             if(g.wb.length){
                                               const mn=Math.min.apply(null,g.wb), mx=Math.max.apply(null,g.wb);
                                               kwh = mx-mn; if(!isFinite(kwh)||kwh<0) kwh=0;
                                               kwh = Math.round(kwh*100)/100;
                                             }
                                             dailySoc.push(avgSoc);
                                             dailyKwh.push(kwh);
                                           }
                                           return {labels, dailySoc, dailyKwh};
                                          }
                                          
                                          /* =================== DATEN SAMMELN =================== */
                                          function readAll(){
                                           const cand = candidates();
                                           const pick = (name, map=v=>v)=>{
                                             const {val} = firstExisting(cand[name]||[]);
                                             if (val===undefined) return undefined;
                                             try{
                                               if (typeof val === 'string' && !isNaN(val)) return map(Number(val));
                                               return map(val);
                                             }catch(_){ return val; }
                                           };
                                           const toBool = (v) => (typeof v==='boolean') ? v : (v!=null ? Number(v)>0 : undefined);
                                          
                                           // Fahrwerte
                                           const odoKm = (function(){
                                             const v = pick('odometer_km', x=>x);
                                             if (v===undefined) return undefined;
                                             const num = typeof v==='string' ? parseFloat(v.replace(/[^\d.,]/g,'').replace(',','.')) : Number(v);
                                             return isNaN(num) ? undefined : Math.round(num);
                                           })();
                                          
                                           // Wallbox Zahlen
                                           const wb_stateNum = pick('wb_state', Number);
                                           const wb_powerNum = pick('wb_power', Number);
                                           const wb_energyNum= pick('wb_energy', Number);
                                          
                                           const data = {
                                             // Kopf
                                             carName: pick('carName'),
                                             vin: pick('vin'),
                                          
                                             // HV / 12V
                                             soc: pick('soc_pct', v => Math.round(Number(v))),
                                             charging: pick('charge_active', toBool),
                                             minToFull: pick('minutes_to_charged', Number),
                                             soc12v: pick('soc12v', v => Math.round(Number(v))),
                                             state12v: pick('state12v'),
                                             soh: pick('soh', v => Math.round(Number(v))),
                                             charge12v: pick('charge12v', v => v === true || v === 'true' || Number(v) === 1),
                                          
                                             // Reichweite & Klima
                                             dte: pick('dte', v => Math.round(Number(v))),
                                             hvacOn: pick('hvacOn', toBool),
                                             tIn: pick('insideTemp', v => Math.round(Number(v)*10)/10),
                                             airClean: pick('airClean', toBool),
                                             defrost: pick('defrost', toBool),
                                             seatFL: pick('seatFL', Number),
                                             seatFR: pick('seatFR', Number),
                                             seatRL: pick('seatRL', Number),
                                             seatRR: pick('seatRR', Number),
                                             steerHeat: pick('steerHeat', toBool),
                                          
                                             // Öffnungen / Fenster
                                             doorFL: pick('doorFL', toBool),
                                             doorFR: pick('doorFR', toBool),
                                             doorRL: pick('doorRL', toBool),
                                             doorRR: pick('doorRR', toBool),
                                             trunk: pick('trunk', toBool),
                                             frunk: pick('frunk', toBool),
                                             winFL: pick('winFL', toBool),
                                             winFR: pick('winFR', toBool),
                                             winRL: pick('winRL', toBool),
                                             winRR: pick('winRR', toBool),
                                          
                                             // Reifenlampen
                                             tireFL: pick('tireFL', toBool),
                                             tireFR: pick('tireFR', toBool),
                                             tireRL: pick('tireRL', toBool),
                                             tireRR: pick('tireRR', toBool),
                                          
                                             // Flüssigkeiten & Warnungen
                                             washer: pick('washer', toBool),
                                             breakOil: pick('breakOil', toBool),
                                             smartKeyBat: pick('smartKeyBat', toBool),
                                          
                                             // Standort
                                             lat: pick('lat', Number),
                                             lon: pick('lon', Number),
                                             address: pick('position_text', String),
                                             positionUrl: pick('position_url', String),
                                          
                                             // Wallbox – formatierte Strings
                                             wb_stateNum,
                                             wb_stateText: (wb_stateNum!=null ? (WB_STATE_TXT[wb_stateNum] || String(wb_stateNum)) : undefined),
                                             wb_powerFmt:  (wb_powerNum!=null ? (wb_powerNum >= 1000 ? (Math.round(wb_powerNum/100)/10)+' kW' : Math.round(wb_powerNum)+' W') : undefined),
                                             wb_energyFmt: (wb_energyNum!=null ? wb_energyNum.toFixed(2) : undefined),
                                             wb_ampere: pick('wb_amp', v => Math.round(Number(v))),
                                             wb_allow: pick('wb_allow', toBool),
                                             wb_temp1: pick('wb_temp1', v => Math.round(Number(v))),
                                             wb_temp2: pick('wb_temp2', v => Math.round(Number(v))),
                                          
                                             // Zeit / extra
                                             lastUpdate: (function(){
                                               const raw = pick('lastUpdate');
                                               if (!raw) return '';
                                               try{ const d=new Date(raw); return isNaN(d)? String(raw) : d.toLocaleString(); }catch(_){ return String(raw); }
                                             })(),
                                             kmYesterday: pick('kmYesterday', v=> (v==null? undefined : Math.round(Number(v)))),
                                          
                                             // Rohwerte für Historie-Sampling
                                             _hist_soc: pick('soc_pct', Number),
                                             _hist_wb_energy: wb_energyNum,
                                          
                                             // Odometer
                                             odoKm
                                           };
                                          
                                           return data;
                                          }
                                          
                                          /* =================== MAIN =================== */
                                          ensureState(OUT_HTML_DP);
                                          ensureHistoryDPs();
                                          let vinAnnounced = false;
                                          
                                          function update(){
                                           try{
                                             const nowMs = Date.now();
                                          
                                             if (!VEHICLE_ID){
                                               VEHICLE_ID = detectVehicleId();
                                               if (VEHICLE_ID && !vinAnnounced){ log('[IONIQ5N] Auto-Detected VIN: '+VEHICLE_ID,'info'); vinAnnounced=true; }
                                             }
                                             if (!VEHICLE_ID){
                                               ss(OUT_HTML_DP, renderHTML({__noVin:true}, {labels:[],dailySoc:[],dailyKwh:[]}, []));
                                               return;
                                             }
                                          
                                             const data = readAll();
                                             trySample(nowMs, data);
                                             const hist = computeDailyFromSamples(nowMs);
                                             const lastSamples = loadSamples();
                                             const html = renderHTML(data, hist, lastSamples);
                                             ss(OUT_HTML_DP, html);
                                           }catch(e){ log('Update error: '+e, 'error'); }
                                          }
                                          
                                          // Initial + Intervall
                                          update();
                                          schedule('*/30 * * * * *', update);
                                          

                                          Wolfgang GaryW Offline
                                          Wolfgang GaryW Offline
                                          Wolfgang Gary
                                          schrieb am zuletzt editiert von
                                          #2109

                                          Hallo, ich habe einen Kia EV6 und Hyundai Kona.
                                          Mit 3.1.20 funktioniert die Anzeige des EV6, aber Login beim Kona schlägt fehl.
                                          Mit der Version 3.1.6 geht das Login für den Kona aber dafür für den EV6 nicht.
                                          Kann ich 2 unterschiedliche Instanzen installieren?
                                          danke & mfg Wolfgang

                                          ilovegymI 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.4k

                                          Themen

                                          1.3m

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

                                          • Du hast noch kein Konto? Registrieren

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