UNPKG

iobroker.vw-connect

Version:
309 lines (298 loc) 14.5 kB
<html> <head> <!-- Load ioBroker scripts and styles--> <link rel="stylesheet" type="text/css" href="../../css/adapter.css" /> <link rel="stylesheet" type="text/css" href="../../lib/css/materialize.css" /> <script type="text/javascript" src="../../lib/js/jquery-3.2.1.min.js"></script> <script type="text/javascript" src="../../socket.io/socket.io.js"></script> <script type="text/javascript" src="../../js/translate.js"></script> <script type="text/javascript" src="../../lib/js/materialize.js"></script> <script type="text/javascript" src="../../js/adapter-settings.js"></script> <!-- Load our own files --> <link rel="stylesheet" type="text/css" href="style.css" /> <script type="text/javascript" src="words.js"></script> <script type="text/javascript"> // This will be called by the admin adapter when the settings page loads function load(settings, onChange) { // example: select elements with id=key and class=value and insert value if (!settings) return; $(".value").each(function () { var $key = $(this); var id = $key.attr("id"); if ($key.attr("type") === "checkbox") { // do not call onChange direct, because onChange could expect some arguments $key.prop("checked", settings[id]).on("change", () => onChange()); } else { // do not call onChange direct, because onChange could expect some arguments $key .val(settings[id]) .on("change", () => onChange()) .on("keyup", () => onChange()); } }); onChange(false); // reinitialize all the Materialize labels on the page if you are dynamically adding inputs: if (M) M.updateTextFields(); } // This will be called by the admin adapter when the user presses the save button function save(callback) { // example: select elements with class=value and build settings object var obj = {}; $(".value").each(function () { var $this = $(this); if ($this.attr("type") === "checkbox") { obj[$this.attr("id")] = $this.prop("checked"); } else { obj[$this.attr("id")] = $this.val(); } }); callback(obj); } </script> </head> <body> <div class="m adapter-container"> <div class="row"> <div class="col s12 m4 l2"> <img src="vw-connect.png" class="logo" /> </div> </div> <!-- Put your content here --> <!-- For example columns with settings: --> <div class="row"> <div class="col s6 input-field"> <input type="text" class="value" id="user" /> <label for="user" class="translate">Connect App Email</label> </div> </div> <div class="row"> <div class="col s6 input-field"> <input type="password" class="value" id="password" /> <label for="password" class="translate">Connect App Password</label> </div> </div> <div class="row"> <div class="col s2 input-field"> <select id="type" class="value"> <option value="id">VW ID / Volkswagen App (nur EU Data Act)</option> <option value="skodae">MyŠKODA</option> <option value="audi">Audi</option> <option value="audietron">Audi E-tron</option> <option value="seatcupra">My CUPRA (nur EU Data Act)</option> <option value="go">VW Connect Go</option> <option value="seatelli">Seat Elli Cupra Wallbox</option> <option value="skodapower">ŠKODA Powerpass</option> <option value="audidata">Audi DataPlug</option> <option value="skoda">ŠKODA Alt</option> <option value="seat">My SEAT (nur EU Data Act)</option> </select> <label for="type" class="translate">Type</label> </div> <div class="col s10"> <span class="helper-text translate"> <b>VW ID / CUPRA / SEAT:</b> klassischer Login geht nicht mehr. <b>Tibber ist aktuell die beste Wahl</b> (unten konfigurierbar, brand-unabhängig). EU Data Act läuft automatisch sobald im Portal eingerichtet. </span> </div> </div> <div class="row"> <div class="col s2 input-field"> <input type="number" class="value" id="interval" /> <label for="interval" class="translate">Update interval in minutes</label> </div> </div> <div class="row"> <div class="col s2 input-field"> <input type="password" class="value" id="pin" /> <label for="pin" class="translate">S-Pin</label> </div> </div> <div class="row"> <div class="col s6 input-field"> <input type="number" class="value" id="forceinterval" /> <label for="forceinterval" class="translate" >Status Update erzwingen. (Interval in Minuten, 0 = Aus). Anzahl Updates zwischen Zündungen ist limitiert, unter 360min nicht zu empfehlen!</label > </div> </div> <div class="row"> <div class="col s6 input-field"> <input type="number" class="value" id="historyLimit" /> <label for="historyLimit" class="translate">Limit Wallbox History. Set to -1 to disable.</label> </div> </div> <div class="row"> <div class="col s6 input-field"> <input type="checkbox" id="lastTrips" class="value" /> <span for="lastTrips" class="translate">Nur den letzten Trip laden</span> </div> </div> <div class="row"> <div class="col s6 input-field"> <input type="checkbox" id="tripShortTerm" class="value" /><label for="tripShortTerm" class="translate" >Ab Start/Kurz</label > <input type="checkbox" id="tripLongTerm" class="value" /><label for="tripLongTerm" class="translate" >Langzeit</label > <input type="checkbox" id="tripCyclic" class="value" /><label for="tripCyclic" class="translate" >Ab Tanken</label > <span class="helper-text future-tooltip translate" >Auswahl der kompletten abzurufenden Fahrdaten (Trips)</span > </div> <div class="col s6 input-field"> <select id="numberOfTrips" class="value"> <option value="1">1</option> <option value="10">10</option> <option value="50">50</option> <option value="100">100</option> <option value="0">alle</option> </select> <label for="numberOfTrips" class="translate" >Anzahl der Fahrdaten (Trips), die als State gespeichert werdne sollen. Achtung! "Alle Fahrdaten" können eine enorme Anzahl sein, die den ioBroker sehr langsam machen.</label > </div> <div class="col s6 input-field"> <input type="number" class="value" id="lastTripDays" /> <label for="lastTripDays" class="translate" >Letzen X Tage der Fahrdaten (Trips) abrufen. Mehr als 30 Tage ist dauerhaft nicht empfohlen.</label > </div> </div> <div class="row"> <div class="col s6 input-field"> <input type="checkbox" id="rights" class="value" /> <span for="rights" class="translate">Lizenzinformationen laden</span> </div> </div> <div class="row"> <div class="col s6 input-field"> <input type="checkbox" id="reversePos" class="value" /> <span for="reversePos" class="translate" >Position in Adresse umwandeln (nur Auswählen, wenn es genutzt wird)</span > </div> </div> <div class="row"> <div class="col s6 input-field"> <input type="checkbox" id="rawJson" class="value" /> <span for="rawJson" class="translate">Rohe JSON speichern</span> </div> </div> <div class="row"> <div class="col s12"> <h6 class="translate">Tibber Data API (empfohlen, brand-unabhängig)</h6> <span class="helper-text translate"> Aktuell die <b>beste Datenquelle</b> für VW ID, CUPRA und SEAT (klassischer Login dort deaktiviert). Funktioniert für jedes Fahrzeug, das im Tibber-Account verbunden ist — unabhängig vom oben gewählten Type. <br><br> <b>Voraussetzungen:</b> <ol> <li>Tibber-Account anlegen (geht NUR über die Tibber-App, nicht über die Webseite). Ein Tibber-Stromvertrag ist NICHT nötig.</li> <li>In der Tibber-App das Fahrzeug verbinden (Connect Vehicle).</li> <li>Im Browser <a href="https://data-api.tibber.com/clients/manage" target="_blank">https://data-api.tibber.com/clients/manage</a> öffnen, mit dem gleichen Tibber-Account einloggen, OAuth2-Client anlegen mit: <ul> <li>Name: frei wählbar (z.B. "ioBroker"); darf NICHT mit "tibber" beginnen.</li> <li>Scopes: <b>alle anhaken</b> (Tibber verlangt mindestens einen zusätzlichen Scope; alles ankreuzen ist sicher).</li> <li>Redirect URI: <b><code>http://localhost/</code></b> (mit Slash am Ende, exakte Schreibweise!).</li> </ul> </li> <li>Client ID und Client Secret hier unten einfügen.</li> <li>Den Adapter speichern. Im Adapter erscheint dann oben ein Authorize-Link — diesen im Browser öffnen, mit Tibber einloggen, auf der Berechtigungs-Seite alle Häkchen lassen und unten <b>"Yes, allow"</b> klicken. Nach dem Klick landest du auf einer leeren <code>http://localhost/?code=...&amp;state=...</code>-Seite (Browser zeigt Fehler — egal). Die <b>komplette URL aus der Adressleiste</b> (mit allem nach dem ?) hier ins "Tibber Authorize Callback-URL"-Feld einfügen und nochmal speichern.</li> <li>Adapter tauscht den Code gegen einen Refresh-Token, der danach automatisch rotiert. Bei Loginproblem vw-connect.0.info.tibberRefreshToken löschen</li> </ol> </span> </div> </div> <div class="row"> <div class="col s6 input-field"> <input type="text" class="value" id="tibberClientId" /> <label for="tibberClientId" class="translate">Tibber Client ID</label> </div> <div class="col s6 input-field"> <input type="password" class="value" id="tibberClientSecret" /> <label for="tibberClientSecret" class="translate">Tibber Client Secret</label> </div> </div> <div class="row"> <div class="col s12"> <span class="helper-text translate" id="tibberAuthHint"> Authorize-URL erscheint hier sobald die Client ID oben eingetragen ist. </span> <a id="tibberAuthLink" href="#" target="_blank" style="display:none; word-break:break-all;"></a> </div> </div> <div class="row"> <div class="col s6 input-field"> <input type="text" class="value" id="tibberCode" placeholder="http://localhost/?code=...&amp;state=iobroker&amp;... (komplett einfügen)" /> <label for="tibberCode" class="translate">Tibber Authorize Callback-URL (komplett einfügen, einmalig, wird beim ersten Start verbraucht)</label> </div> <div class="col s6 input-field"> <input type="number" class="value" id="tibberInterval" min="1" /> <label for="tibberInterval" class="translate">Tibber Update-Interval (Minuten, Default 5)</label> </div> </div> <script> // Tibber Authorize URL builder. Uses a fixed PKCE challenge baked // into lib/tibber.js so the URL can be assembled in pure JS without // a backend roundtrip. Verifier is the secret known to the adapter. (function () { var TIBBER_AUTH_URL = "https://thewall.tibber.com/connect/authorize"; var TIBBER_REDIRECT = "http://localhost/"; var TIBBER_SCOPES = [ "openid", "profile", "email", "offline_access", "data-api-user-read", "data-api-homes-read", "data-api-vehicles-read", "data-api-chargers-read", "data-api-energy-systems-read", "data-api-thermostats-read", "data-api-inverters-read", ].join(" "); var TIBBER_CHALLENGE = "Oey1jcnhbUa_fxI9A2NtdVrIk-QxD-9ARobHcVpOj7A"; function refresh() { var idEl = document.getElementById("tibberClientId"); var hint = document.getElementById("tibberAuthHint"); var link = document.getElementById("tibberAuthLink"); if (!idEl || !hint || !link) return; var cid = (idEl.value || "").trim(); if (!cid) { link.style.display = "none"; hint.textContent = "Authorize-URL erscheint hier sobald die Client ID oben eingetragen ist."; return; } var url = TIBBER_AUTH_URL + "?response_type=code" + "&client_id=" + encodeURIComponent(cid) + "&redirect_uri=" + encodeURIComponent(TIBBER_REDIRECT) + "&scope=" + encodeURIComponent(TIBBER_SCOPES) + "&state=iobroker" + "&code_challenge=" + TIBBER_CHALLENGE + "&code_challenge_method=S256"; link.href = url; link.textContent = url; link.style.display = "inline"; hint.textContent = "Klick auf den Link, mit Tibber einloggen, 'Yes, allow' klicken. " + "Browser zeigt 'Connection refused' o.ä. — egal. Die komplette URL aus " + "der Adressleiste (http://localhost/?code=...&state=...&...) kopieren " + "und unten in das Feld einfügen."; } document.addEventListener("DOMContentLoaded", function () { var idEl = document.getElementById("tibberClientId"); if (idEl) { idEl.addEventListener("input", refresh); idEl.addEventListener("change", refresh); // Re-render once after the load() handler has filled the // value from settings. setTimeout(refresh, 100); } }); })(); </script> </div> </body> </html>