Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. JavaScript
    5. UNIFI API Voucher Skript

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    UNIFI API Voucher Skript

    This topic has been deleted. Only users with topic management privileges can see it.
    • P
      paulkerl last edited by

      Hallo zusammen,

      ich habe mal GEMINI bemüht mir ein Voucher Skript für die Unifi API zu bauen, das in IOBROKER läuft. Vielleicht kanns wer brauchen.

      Funktionen deines WLAN-Voucher-Generierungs-Skripts

      Dieses ioBroker-Skript ist dein persönlicher Assistent zur automatischen Erstellung und Verwaltung von WLAN-Vouchern für dein UniFi-Netzwerk, direkt aus deiner ioBroker-Steuerungsoberfläche (VIS) heraus.


      Was das Skript macht:

      1. Vorbereitung und Einrichtung:

        • Beim Start sorgt das Skript dafür, dass alle notwendigen "Schalter" und "Anzeigefelder" in ioBroker existieren. Diese findest du unter 0_userdata.0.WIFIVoucher. Dazu gehören Felder, um einzustellen, wie viele Nutzer einen Voucher verwenden dürfen (max_users) und wie lange er gültig ist (valid_days), sowie ein "Start"-Knopf (generate) und ein Feld, das dir den fertigen Code anzeigt (actual_voucher).
      2. WLAN-Voucher generieren:

        • Wenn du in deiner ioBroker-Ansicht den "Start"-Knopf (0_userdata.0.WIFIVoucher.generate) betätigst, tritt das Skript in Aktion.
        • Es liest deine zuvor eingestellten Werte für die maximale Nutzerzahl und die Gültigkeitsdauer aus den entsprechenden Feldern.
        • Mit diesen Informationen sendet das Skript eine verschlüsselte und authentifizierte Anfrage an deine UniFi-Hardware (den UniFi Controller, z.B. deine USG Max). Dies geschieht direkt und sicher, ohne Umwege über externe Programme wie curl.
        • Deine UniFi-Hardware erstellt daraufhin einen neuen WLAN-Voucher.
      3. Voucher-Code anzeigen und formatieren:

        • Sobald der neue Voucher von UniFi generiert wurde, empfängt das Skript den Voucher-Code.
        • Es formatiert diesen Code sofort, sodass er leichter zu lesen ist – beispielsweise wird aus "1234567890" ein "12345-67890".
        • Der so formatierte Code wird dann in deinem ioBroker-Anzeigefeld (0_userdata.0.WIFIVoucher.actual_voucher) dargestellt, sodass du ihn direkt ablesen und weitergeben kannst.
      4. Automatische Code-Anzeige und Zurücksetzung:

        • Nachdem der Voucher-Code angezeigt wurde, startet das Skript einen 5-minütigen Countdown.
        • Während dieser Zeit bleibt der Code sichtbar. Wenn die 5 Minuten abgelaufen sind, wird der angezeigte Voucher-Code automatisch durch eine Reihe von Nullen ("00000-00000") ersetzt. Das sorgt dafür, dass nicht dauerhaft alte Codes sichtbar bleiben und du immer den aktuellen Code im Blick hast.
        • Wichtig: Solltest du einen neuen Voucher generieren, während der alte Code noch angezeigt wird, wird der Countdown sofort zurückgesetzt und ein neuer 5-Minuten-Zeitraum für den neuen Code gestartet. So wird sichergestellt, dass immer der aktuellste Code für 5 Minuten sichtbar ist.
      5. Bereitschaft für den nächsten Voucher:

        • Nachdem der Generierungsprozess abgeschlossen ist (egal ob erfolgreich oder mit einem Problem), setzt das Skript den "Start"-Knopf (0_userdata.0.WIFIVoucher.generate) in ioBroker automatisch wieder auf seine Ausgangsposition zurück. So ist er bereit für die nächste Voucher-Erstellung.
      // Direkte Nutzung des HTTPS-Moduls für API-Anfragen
      const https = require('https');
      
      // --- Konfiguration ---
      // API-Endpunkt für deine UniFi USG MAX und spezifische Site-ID
      const API_URL_BASE = "https://192.168.xxx.xxx/proxy/network/integration/v1/sites/*site-id*";
      // Dein UniFi API-Schlüssel
      const API_KEY = "*API Token*";
      // Fester Name für automatisch generierte Voucher im UniFi Controller
      const VOUCHER_NAME = "autogen";
      
      // --- Datenpunkte definieren ---
      const DP_BASE = "0_userdata.0.WIFIVoucher";
      const DP_GENERATE = DP_BASE + ".generate";       // Boolean: TRUE zum Generieren eines Vouchers
      const DP_ACTUAL_VOUCHER = DP_BASE + ".actual_voucher"; // String: Speichert den generierten Voucher-Code
      const DP_MAX_USERS = DP_BASE + ".max_users";     // Number: Maximale Nutzer pro Voucher
      const DP_VALID_DAYS = DP_BASE + ".valid_days";   // Number: Gültigkeitsdauer in Tagen
      
      // --- Timer-Variable für das automatische Überschreiben ---
      let voucherTimeout = null;
      
      // --- Funktion zum Erstellen oder Aktualisieren von Datenpunkten ---
      async function createDataPoints() {
          log("Prüfe und erstelle Datenpunkte...", "info");
      
          // Datenpunkt zum Triggern der Voucher-Generierung
          await createStateAsync(DP_GENERATE, false, {
              name: "WLAN Voucher generieren",
              desc: "Setzen Sie auf TRUE, um einen neuen WLAN Voucher zu generieren.",
              type: "boolean",
              role: "button",
              read: true,
              write: true
          });
      
          // Datenpunkt zum Speichern des generierten Voucher-Codes
          await createStateAsync(DP_ACTUAL_VOUCHER, "", {
              name: "Aktueller WLAN Voucher Code",
              desc: "Der zuletzt generierte WLAN Voucher Code.",
              type: "string",
              role: "value",
              read: true,
              write: false // Nur lesbar durch VIS, geschrieben vom Skript
          });
      
          // Datenpunkt für die maximale Anzahl der Nutzer pro Voucher
          await createStateAsync(DP_MAX_USERS, 1, { // Standardwert: 1 Nutzer
              name: "Max. Nutzer pro Voucher",
              desc: "Die maximale Anzahl von Geräten, die den Voucher nutzen können (UniFi-Max: 10).",
              type: "number",
              role: "value",
              read: true,
              write: true,
              min: 1,
              max: 10 // Übliches Maximum in UniFi für Guest Limit
          });
      
          // Datenpunkt für die Gültigkeitsdauer in Tagen
          // Beachte: UniFi API hat ein internes Limit für timeLimitMinutes (z.B. 43200 Stunden = 1800 Tage).
          // Ein höherer Wert wird vom Controller wahrscheinlich auf sein internes Maximum begrenzt.
          await createStateAsync(DP_VALID_DAYS, 1, { // Standardwert: 1 Tag
              name: "Gültigkeit des Vouchers (Tage)",
              desc: "Die Gültigkeitsdauer des Vouchers in Tagen (UniFi-Limit beachten).",
              type: "number",
              role: "value",
              read: true,
              write: true,
              min: 1,
              max: 128000 // Maximalwert laut deiner Anforderung
          });
      
          log("Datenpunkte geprüft/erstellt.", "info");
      }
      
      // --- Funktion zum Formatieren des Voucher-Codes (5 Ziffern - 5 Ziffern) ---
      function formatVoucherCode(code) {
          if (typeof code !== 'string' || code.length !== 10) {
              return code; // Gib den Code unverändert zurück, wenn er nicht 10 Ziffern lang ist
          }
          return code.substring(0, 5) + '-' + code.substring(5, 10);
      }
      
      // --- Funktion zum Zurücksetzen des Voucher-Codes nach Timeout ---
      function resetVoucherCode() {
          log("Setze Voucher-Code auf '00000-00000' zurück.", "info");
          setState(DP_ACTUAL_VOUCHER, "00000-00000", true); // Bestätigen, dass der Wert geschrieben wurde
      }
      
      // --- Hauptfunktion zum Generieren eines einzelnen Vouchers ---
      async function generateVoucher() {
          log("Starte Voucher-Generierung...", "info");
      
          // **WICHTIG:** Alten Timer stoppen, falls vorhanden
          if (voucherTimeout) {
              clearTimeout(voucherTimeout);
              log("Vorherigen Voucher-Timeout gestoppt.", "debug");
          }
      
          // Lese die aktuellen Werte aus den Datenpunkten
          const maxUsersState = await getStateAsync(DP_MAX_USERS);
          const validDaysState = await getStateAsync(DP_VALID_DAYS);
      
          // Prüfe, ob die Datenpunkte gültige Werte liefern
          if (!maxUsersState || maxUsersState.val === null || !validDaysState || validDaysState.val === null) {
              log("Fehler: Datenpunkte für max. Nutzer oder Gültigkeit konnten nicht gelesen werden.", "warn");
              setState(DP_GENERATE, false); // Setze Schalter zurück, da keine gültigen Daten
              return;
          }
      
          const maxUsers = maxUsersState.val;
          const validDays = validDaysState.val;
          // Umrechnung von Tagen in Minuten, wie von der UniFi API erwartet
          const timeLimitMinutes = validDays * 24 * 60;
      
          // Erstelle das JSON-Objekt für den POST-Request-Body
          const postDataObj = {
              name: VOUCHER_NAME,
              authorizedGuestLimit: maxUsers,
              timeLimitMinutes: timeLimitMinutes
          };
          const postData = JSON.stringify(postDataObj); // Konvertiere Objekt in JSON-String
      
          // Manuelle URL-Zerlegung für das https-Modul
          const fullUrl = API_URL_BASE + '/hotspot/vouchers';
          const parts = fullUrl.match(/^https?:\/\/([^/:]+)(:\d+)?(.*)$/);
      
          if (!parts) {
              log(`Fehler: Ungültige URL-Formatierung für ${fullUrl}. Bitte URL prüfen.`, "error");
              setState(DP_GENERATE, false);
              return;
          }
      
          const hostname = parts[1];
          const port = parts[2] ? parseInt(parts[2].substring(1)) : 443; // Standard-HTTPS-Port 443
          const path = parts[3];
      
          // Optionen für den HTTPS-Request
          const options = {
              hostname: hostname,
              port: port,
              path: path,
              method: 'POST',
              headers: {
                  'Content-Type': 'application/json',
                  'Content-Length': Buffer.byteLength(postData), // Notwendig für POST-Requests
                  'Accept': 'application/json',
                  'X-API-Key': API_KEY // Dein API-Schlüssel zur Authentifizierung
              },
              rejectUnauthorized: false // Wichtig: Deaktiviert die Zertifikatsprüfung für selbstsignierte UniFi-Zertifikate
          };
      
          log(`Sende HTTP POST-Request an: ${fullUrl}`, "debug");
          log(`Post-Daten: ${postData}`, "debug");
      
          try {
              const responseData = await new Promise((resolve, reject) => {
                  const req = https.request(options, (res) => {
                      let data = '';
      
                      res.on('data', (chunk) => {
                          data += chunk;
                      });
      
                      res.on('end', () => {
                          if (res.statusCode >= 200 && res.statusCode < 300) {
                              resolve(data);
                          } else {
                              reject(new Error(`Server responded with status code ${res.statusCode}: ${data}`));
                          }
                      });
                  });
      
                  req.on('error', (e) => {
                      reject(e);
                  });
      
                  req.write(postData);
                  req.end();
              });
      
              // Verarbeitung der erfolgreichen API-Antwort
              log("API-Antwort erhalten: " + responseData, "debug");
              const result = JSON.parse(responseData);
      
              if (result && Array.isArray(result.vouchers) && result.vouchers.length > 0) {
                  const rawVoucherCode = result.vouchers[0].code;
                  const formattedVoucherCode = formatVoucherCode(rawVoucherCode); // Voucher-Code formatieren
      
                  log(`Neuer Voucher erfolgreich generiert: ${formattedVoucherCode}`, "info");
                  // Speichere den formatierten Code im ioBroker Datenpunkt
                  setState(DP_ACTUAL_VOUCHER, formattedVoucherCode, true); // Bestätigen, dass der Wert geschrieben wurde
      
                  // **Neuer Timer starten**
                  voucherTimeout = setTimeout(resetVoucherCode, 5 * 60 * 1000); // 5 Minuten = 5 * 60 * 1000 ms
                  log("Timeout für Voucher-Rücksetzung gestartet (5 Minuten).", "debug");
      
              } else {
                  log("Unerwartete API-Antwort Struktur bei Voucher-Generierung: " + responseData, "warn");
                  if (result && result.statusCode) {
                      log(`API Fehler-Code: ${result.statusCode}, Nachricht: ${result.message || 'Keine Nachricht'}`, "error");
                  }
              }
      
          } catch (e) {
              log(`Ausnahme beim Generieren des Vouchers: ${e.message}. Stack: ${e.stack}`, "error");
          } finally {
              setState(DP_GENERATE, false, true); // Setzt den Trigger-Datenpunkt immer auf FALSE zurück
          }
      }
      
      // --- Skriptstart und Trigger-Definitionen ---
      
      // Dieser Listener sorgt dafür, dass die Datenpunkte initialisiert werden,
      // wenn das Skript aktiviert oder neu gestartet wird.
      on({ id: "javascript.0.scriptEnabled.script.js." + instance + ".WLAN_Voucher_Generator", change: "ne" }, async function (obj) {
          if (obj.state.val === true) {
              log("Skript gestartet. Datenpunkte werden initialisiert.", "info");
              await createDataPoints();
          }
      });
      
      // Dieser Trigger reagiert auf Änderungen des "generate"-Datenpunkts.
      // Wenn dieser auf TRUE gesetzt wird, startet die Voucher-Generierung.
      on({ id: DP_GENERATE, change: "ne", val: true }, async function (obj) {
          log("Datenpunkt " + DP_GENERATE + " auf TRUE gesetzt. Starte Voucher-Generierung...", "info");
          await generateVoucher();
      });
      
      // Initialer Aufruf zum Erstellen der Datenpunkte beim Skriptstart
      createDataPoints();
      
      1 Reply Last reply Reply Quote 0
      • First post
        Last post

      Support us

      ioBroker
      Community Adapters
      Donate

      881
      Online

      31.8k
      Users

      80.0k
      Topics

      1.3m
      Posts

      1
      1
      50
      Loading More Posts
      • Oldest to Newest
      • Newest to Oldest
      • Most Votes
      Reply
      • Reply as topic
      Log in to reply
      Community
      Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
      The ioBroker Community 2014-2023
      logo