Skip to content
  • 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
  1. ioBroker Community Home
  2. Deutsch
  3. Tester
  4. Neuer Adapter pi-hole2 für pihole>=V6

NEWS

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

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

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

Neuer Adapter pi-hole2 für pihole>=V6

Geplant Angeheftet Gesperrt Verschoben Tester
36 Beiträge 7 Kommentatoren 2.8k Aufrufe 12 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.
  • OliverIOO Offline
    OliverIOO Offline
    OliverIO
    schrieb am zuletzt editiert von OliverIO
    #17

    Neue Version 0.2.3

    • Kleine Fehlerbehebung in der Dokumentation
    • Benutzeragent anpassen und Informationen zur Fehlerbehebung "too many seats" hinzufügen
    • Visualisierungsbeispiel für Versions hinzugefügt
    • Visualisierungsbeispiel für Summary hinzugefügt

    Meine Adapter und Widgets
    TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
    Links im Profil

    1 Antwort Letzte Antwort
    1
    • OliverIOO Offline
      OliverIOO Offline
      OliverIO
      schrieb am zuletzt editiert von OliverIO
      #18

      Neue Version 0.3.0

      • Übersetzungsdateien hinzugefügt
      • Aktualisierungslogik und Refreshzeiten an Pihole angepasst
      • Passwort verschlüsselt (Passwort muss bei Aktualisierung erneut eingegeben werden)
      • Ausgewählte Detail-Datenpunkte für Summary und Version hinzugefügt.

      591cfbc7-8506-444b-8702-9371c40d9eb3-image.png

      Meine Adapter und Widgets
      TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
      Links im Profil

      1 Antwort Letzte Antwort
      0
      • OliverIOO Offline
        OliverIOO Offline
        OliverIO
        schrieb am zuletzt editiert von
        #19

        Neue Version 0.4.0

        • Die Extraktion von Detailwerten für Version/Summary kann deaktiviert werden.

        Meine Adapter und Widgets
        TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
        Links im Profil

        1 Antwort Letzte Antwort
        0
        • OliverIOO OliverIO
          Aktuelle Test Version 0.0.1
          Veröffentlichungsdatum Juni 2025
          Github Link https://github.com/oweitman/ioBroker.pi-hole2

          Nach dem der alte Adapter ab pihole v6 nicht mehr funktioniert, habe ich mich da mal dran gemacht. vgl auch forum.iobroker.net/topic/79939/pihole-adapter-ohne-funktion-nach-pi-hole-update-auf-v6

          Hier Adapter Beschreibung, Changelog etc.

          Funktionen

          Blockierung aktivieren oder deaktivieren

          Um die Werbung zu blockieren oder die Blockierung zu deaktivieren, kannst du einfach den Schalter im Datenpunkt Blocking verwenden.
          Der Datenpunkt BlockingTime ist dafür gedacht, die Blockierung vorübergehend zu deaktivieren – nach Ablauf der Zeit wird sie automatisch wieder eingeschaltet.
          Wenn du die Blockierung manuell aktivierst, passiert das sofort.

          Detaillierte Informationen – Übersicht

          Einige Informationen aus der Übersicht („Summary“) werden als eigene Datenpunkte unter Data.Summary angezeigt.
          Du kannst in der Adapterkonfiguration festlegen, ob diese Funktion aktiviert oder deaktiviert ist.
          Wenn sie aktiv ist, werden die entsprechenden Datenpunkte grün markiert – andernfalls rot.

          Detaillierte Informationen – Version

          Auch einige Daten aus dem Bereich „Version“ werden als einzelne Datenpunkte unter Data.Version bereitgestellt.
          Ob diese angezeigt werden, kannst du ebenfalls in der Konfiguration einstellen.
          Aktivierte Datenpunkte sind grün hervorgehoben, deaktivierte rot.

          Allgemeine sendTo-Funktion

          Mit der sendTo-Funktion kannst du Befehle direkt an dein Pi-hole-Gerät senden.
          Wenn du die API lokal ausprobieren möchtest, rufe einfach die Seite http://pi.hole/api/docs/# auf, gib dein Passwort ein und klicke auf den „Login“-Button.

          Weiteres

          Wer weitere Vorschläge zur Integration wichtiger Informationen machen möchte, kann gerne in seiner piholev6 installation die folgende Seite aufrufen: http://pi.hole/api/docs/, trägt dann oben sein Passwort ein und kann dann alle API-Endpunkte durchprobieren.

          gerne kann der adapter nun aus dem beta channel installiert werden.

          Fehler, Ideen, Anregungen dann bitte hier.

          Test nach Release im Beta bearbeitet

          NegaleinN Offline
          NegaleinN Offline
          Negalein
          Global Moderator
          schrieb am zuletzt editiert von
          #20

          @oliverio sagte in Neuer Adapter pi-hole2 für pihole>=V6:

          Fehler, Ideen, Anregungen dann bitte hier.

          Hallo Oliver

          Ist das Grau so gewollt?

          6da702df-e619-4046-99d0-f6336343b3ce-image.png

          ° Node.js: 20.17.0 NPM: 10.8.2
          ° Proxmox, Ubuntu 22.04.3 LTS
          ° Fixer ---> iob fix

          OliverIOO 1 Antwort Letzte Antwort
          0
          • NegaleinN Negalein

            @oliverio sagte in Neuer Adapter pi-hole2 für pihole>=V6:

            Fehler, Ideen, Anregungen dann bitte hier.

            Hallo Oliver

            Ist das Grau so gewollt?

            6da702df-e619-4046-99d0-f6336343b3ce-image.png

            OliverIOO Offline
            OliverIOO Offline
            OliverIO
            schrieb am zuletzt editiert von
            #21

            @negalein

            ah, danke. habe nicht mit hellem hintergrund getestet.
            hatte aber einen ähnlichen effekt bei dunkel.
            ist leider ein automatismus des admin.
            muss mir für hell dann eine anderen grünton suchen, bei rot ist es ja ok.
            der admin prüft den kontrast der farbe und schaltet dann halt einen anderen grünton dazu.

            Meine Adapter und Widgets
            TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
            Links im Profil

            1 Antwort Letzte Antwort
            1
            • OliverIOO Offline
              OliverIOO Offline
              OliverIO
              schrieb am zuletzt editiert von OliverIO
              #22

              Neue Version 0.4.1

              • Das Problem mit der Farbgebung bei grünen Datenpunkten wurde behoben.

              Meine Adapter und Widgets
              TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
              Links im Profil

              SBorgS 1 Antwort Letzte Antwort
              1
              • OliverIOO OliverIO

                Neue Version 0.4.1

                • Das Problem mit der Farbgebung bei grünen Datenpunkten wurde behoben.
                SBorgS Offline
                SBorgS Offline
                SBorg
                Forum Testing Most Active
                schrieb am zuletzt editiert von
                #23

                @oliverio
                Danke, wollte die Tage schon die API per NodeRED Flow abfragen 😊
                Pi-hole.png

                Richtet sich eher an den "Unbedarften":


                sendTo(
                "pi-hole2.0",
                "piholeapi",
                {
                method: "GET",
                endpoint: "/stats/summary"
                },
                function (data) {
                console.log(data.queries.percent_blocked);
                },
                );

                const json=getState('pi-hole2.0.Summary').val;
                const obj = JSON.parse(json);

                console.log(obj.queries.percent_blocked);


                Blockly.png

                Man sieht, man kommt auch so relativ einfach an die gewünschten Daten heran. Von daher sehe ich nicht unbedingt eine Notwendigkeit alles als Datenpunkt anbieten zu müssen.

                LG SBorg ( SBorg auf GitHub)
                Projekte: Lebensmittelwarnung.de | WLAN-Wetterstation | PimpMyStation

                OliverIOO 2 Antworten Letzte Antwort
                0
                • SBorgS SBorg

                  @oliverio
                  Danke, wollte die Tage schon die API per NodeRED Flow abfragen 😊
                  Pi-hole.png

                  Richtet sich eher an den "Unbedarften":


                  sendTo(
                  "pi-hole2.0",
                  "piholeapi",
                  {
                  method: "GET",
                  endpoint: "/stats/summary"
                  },
                  function (data) {
                  console.log(data.queries.percent_blocked);
                  },
                  );

                  const json=getState('pi-hole2.0.Summary').val;
                  const obj = JSON.parse(json);

                  console.log(obj.queries.percent_blocked);


                  Blockly.png

                  Man sieht, man kommt auch so relativ einfach an die gewünschten Daten heran. Von daher sehe ich nicht unbedingt eine Notwendigkeit alles als Datenpunkt anbieten zu müssen.

                  OliverIOO Offline
                  OliverIOO Offline
                  OliverIO
                  schrieb am zuletzt editiert von
                  #24

                  @sborg

                  Wenn es eine hohe Nachfrage gibt, dann ist es kein Problem datenpunkte noch hinzuzunehmen.
                  Daher auch meine Frage oben
                  Bisher kam aber noch nicht soviel Anforderungen.
                  Gut der Adapter ist jung und es ist Sommer.

                  Summary wird halt im Standard jede Sekunde abgefragt und ich wollte im Standard jetzt nicht so hohe Last auf den iobroker legen.
                  Gut den Abfrage Intervall kann man ggfs. auch in der Konfiguration senken, ich habe daher die Konfiguration auch etwas detaillierter aufgedröselt.

                  Meine Adapter und Widgets
                  TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
                  Links im Profil

                  1 Antwort Letzte Antwort
                  0
                  • SBorgS SBorg

                    @oliverio
                    Danke, wollte die Tage schon die API per NodeRED Flow abfragen 😊
                    Pi-hole.png

                    Richtet sich eher an den "Unbedarften":


                    sendTo(
                    "pi-hole2.0",
                    "piholeapi",
                    {
                    method: "GET",
                    endpoint: "/stats/summary"
                    },
                    function (data) {
                    console.log(data.queries.percent_blocked);
                    },
                    );

                    const json=getState('pi-hole2.0.Summary').val;
                    const obj = JSON.parse(json);

                    console.log(obj.queries.percent_blocked);


                    Blockly.png

                    Man sieht, man kommt auch so relativ einfach an die gewünschten Daten heran. Von daher sehe ich nicht unbedingt eine Notwendigkeit alles als Datenpunkt anbieten zu müssen.

                    OliverIOO Offline
                    OliverIOO Offline
                    OliverIO
                    schrieb am zuletzt editiert von
                    #25

                    @sborg

                    Du hast nur 5% geblockt?
                    Bei mir ist der Anteil bei über 50%
                    Microsoft, Amazon,Samsung und Netflix telefonieren schon viel nach Hause.

                    Meine Adapter und Widgets
                    TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
                    Links im Profil

                    SBorgS 1 Antwort Letzte Antwort
                    0
                    • OliverIOO OliverIO

                      @sborg

                      Du hast nur 5% geblockt?
                      Bei mir ist der Anteil bei über 50%
                      Microsoft, Amazon,Samsung und Netflix telefonieren schon viel nach Hause.

                      SBorgS Offline
                      SBorgS Offline
                      SBorg
                      Forum Testing Most Active
                      schrieb am zuletzt editiert von
                      #26

                      @oliverio
                      Meine Blocklist wurde offenbar nicht mehr geupdated. Habe ich aber nicht bemerkt, da ich fast nur mit meinem Laptop im Internet unterwegs bin. Da filtert der FF alles aus. Geladen habe ich den ganzen Kram natürlich dann aber doch, da ist das blocken per Pi-hole wesentlich effizienter. Dafür habe ich ihn ja auch.

                      LG SBorg ( SBorg auf GitHub)
                      Projekte: Lebensmittelwarnung.de | WLAN-Wetterstation | PimpMyStation

                      1 Antwort Letzte Antwort
                      -1
                      • OliverIOO Offline
                        OliverIOO Offline
                        OliverIO
                        schrieb am zuletzt editiert von OliverIO
                        #27

                        Der Adapter müsste nun im beta auftauchen

                        • Der erste Post wurde aufgrund dessen überarbeitet
                        • Um eine fertige Version zu signalisieren wurde eine V1.0.0 released

                        Meine Adapter und Widgets
                        TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
                        Links im Profil

                        1 Antwort Letzte Antwort
                        1
                        • OliverIOO Offline
                          OliverIOO Offline
                          OliverIO
                          schrieb am zuletzt editiert von OliverIO
                          #28

                          Neue Version 1.1.0

                          • Unter Data/Versions wurden Update Indikatoren hinzugefügt, um mittels true/false anzuzeigen, das ein Update für die einzelne Komponente vorliegt.

                          Meine Adapter und Widgets
                          TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
                          Links im Profil

                          L OliverIOO 2 Antworten Letzte Antwort
                          0
                          • OliverIOO OliverIO

                            Neue Version 1.1.0

                            • Unter Data/Versions wurden Update Indikatoren hinzugefügt, um mittels true/false anzuzeigen, das ein Update für die einzelne Komponente vorliegt.
                            L Offline
                            L Offline
                            Labersack
                            schrieb am zuletzt editiert von Labersack
                            #29

                            @oliverio
                            Habe den Adapter heute auch mal installiert.
                            Was soll ich sagen... Ich finde, der Adapter ist ein Pi-Loch! lol
                            Pi-Loch.jpg

                            OliverIOO 1 Antwort Letzte Antwort
                            -1
                            • L Labersack

                              @oliverio
                              Habe den Adapter heute auch mal installiert.
                              Was soll ich sagen... Ich finde, der Adapter ist ein Pi-Loch! lol
                              Pi-Loch.jpg

                              OliverIOO Offline
                              OliverIOO Offline
                              OliverIO
                              schrieb am zuletzt editiert von
                              #30

                              @labersack

                              Ja sowas, die automatische Übersetzung.

                              Danke fürs Bescheid geben.

                              Meine Adapter und Widgets
                              TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
                              Links im Profil

                              1 Antwort Letzte Antwort
                              0
                              • OliverIOO OliverIO

                                Neue Version 1.1.0

                                • Unter Data/Versions wurden Update Indikatoren hinzugefügt, um mittels true/false anzuzeigen, das ein Update für die einzelne Komponente vorliegt.
                                OliverIOO Offline
                                OliverIOO Offline
                                OliverIO
                                schrieb am zuletzt editiert von
                                #31

                                Neue Version 1.1.1

                                • Die Übersetzung wurde optimiert

                                Meine Adapter und Widgets
                                TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
                                Links im Profil

                                S 1 Antwort Letzte Antwort
                                0
                                • OliverIOO OliverIO

                                  Neue Version 1.1.1

                                  • Die Übersetzung wurde optimiert
                                  S Offline
                                  S Offline
                                  sol21
                                  schrieb am zuletzt editiert von
                                  #32

                                  @oliverio
                                  Könnte man den Adapter in auf "stable" setzen?

                                  Ich benutze normalerwiese auf nur die "stable" Versionen. Für den pi-hole2 habe ich bisher gezwungenermassen eine Ausnahme gemacht. Die 1.1.1 scheint ja recht gut zu laufen. Wenn man ihn nun auf "stable" setzt würde, würde er auch bei Leuten wie mir die nur das "stable"-Repository angewählt haben angezeigt.

                                  PS: Aber grundsätzlich vielen Dank für die neue Version. Die hat mein IOBroker-PiHole Problem gelöst!

                                  OliverIOO 1 Antwort Letzte Antwort
                                  0
                                  • S sol21

                                    @oliverio
                                    Könnte man den Adapter in auf "stable" setzen?

                                    Ich benutze normalerwiese auf nur die "stable" Versionen. Für den pi-hole2 habe ich bisher gezwungenermassen eine Ausnahme gemacht. Die 1.1.1 scheint ja recht gut zu laufen. Wenn man ihn nun auf "stable" setzt würde, würde er auch bei Leuten wie mir die nur das "stable"-Repository angewählt haben angezeigt.

                                    PS: Aber grundsätzlich vielen Dank für die neue Version. Die hat mein IOBroker-PiHole Problem gelöst!

                                    OliverIOO Offline
                                    OliverIOO Offline
                                    OliverIO
                                    schrieb am zuletzt editiert von OliverIO
                                    #33

                                    @sol21
                                    Normalerweise wird nach 15 Tagen automatisch ein issue eröffnet, aufgrund dessen ich dann die Versionen auf Stable setze.
                                    Kam wohl diesmal nicht. Eventuell sind für manche Adapter die Regeln anderst oder es hat mit den github Problemen zu tun.

                                    Meine Adapter und Widgets
                                    TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
                                    Links im Profil

                                    mcm1957M 1 Antwort Letzte Antwort
                                    0
                                    • OliverIOO OliverIO

                                      @sol21
                                      Normalerweise wird nach 15 Tagen automatisch ein issue eröffnet, aufgrund dessen ich dann die Versionen auf Stable setze.
                                      Kam wohl diesmal nicht. Eventuell sind für manche Adapter die Regeln anderst oder es hat mit den github Problemen zu tun.

                                      mcm1957M Online
                                      mcm1957M Online
                                      mcm1957
                                      schrieb am zuletzt editiert von mcm1957
                                      #34

                                      @oliverio
                                      Nö 15 Tage Erinnering kommt nur bei existierenden Adapter u mind 5% der User spätestens aber nach 30 Tagen.

                                      Die Regeln f eine Erinnerung sind immer gleich. 🙂

                                      An eine ERST Aufnahme wird erst nach 30 Tagen erinnert.

                                      Kannst den Stable Request aber jederzeit stellen. Erinnerung dazu ist keine Erfordernis.

                                      Entwicklung u Betreuung: envertech-pv, hoymiles-ms, ns-client, pid, snmp Adapter;
                                      Support Repositoryverwaltung.

                                      Wer Danke sagen will, kann nen Kaffee spendieren: https://paypal.me/mcm1957atiobroker

                                      LESEN - gute Forenbeitrage

                                      1 Antwort Letzte Antwort
                                      0
                                      • OliverIOO Offline
                                        OliverIOO Offline
                                        OliverIO
                                        schrieb am zuletzt editiert von OliverIO
                                        #35

                                        pi-hole2 v1.1.1 befindet sich nun im stable repository

                                        Meine Adapter und Widgets
                                        TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
                                        Links im Profil

                                        1 Antwort Letzte Antwort
                                        1
                                        • OliverIOO Offline
                                          OliverIOO Offline
                                          OliverIO
                                          schrieb am zuletzt editiert von OliverIO
                                          #36

                                          Hier mal ein größerer Anwendungsfall für den pihole2 Adapter.
                                          Bitte um Rückmeldungen, positive wie negative Erfahrungen.
                                          Evtl baue ich das dann als widgets in den Adapter ein.

                                          Bitte auch die Verwendung des Adapters vis-jsontemplate 4.1.3 weiter unten beachten
                                          https://forum.iobroker.net/topic/31521/test-widget-json-template/32?_=1762189668521


                                          Ich habe immer wieder den folgenden Anwendungsfall, der sich mit pihole Bordmitteln nicht so einfach lösen lässt.

                                          Ich habe immer wieder mal Seiten, die aufgrund eines pihole Blocks nicht funktionieren. Darüber hinaus funken hier mehrere Geräte wirklich sehr oft nach Hause, deren requests durch pihole geblockt werden. Dies verhindert leider effizient die Suche nach den betroffenen domains des blocks, der wieder aufgehoben werden soll, da das logfile relativ voll ist.

                                          Auch interessiert mich immer wieder mal, wer hier so nach Hause telefoniert.
                                          Diejenigen domains, die ich aber schon mal geprüft habe will ich nicht erneut prüfen.

                                          Daher nun der folgende Versuch einer Lösung mittels 2er Widgets die ich mit dem jsontemplate Adapter erstellt habe.

                                          Widget 1

                                          listet alle domains absteigend nach vorkommen über alle clients dar.
                                          jede einzelne domain kann dann auf die Merkliste gesetzt werden.
                                          die Liste kann nach einem Suchbegriff oder Regex gefiltert werden.
                                          Mehrere Sichtbare domains können über ein Sammel-Checkbox ebenfalls in einem Schritt gemerkt werden.
                                          Das widfget besteht 2 Reitern, einmal alle gemerkten domains, sowie alle die Nicht gemerkt worden sind.

                                          2b733665-5606-4cb2-915a-a319c511ef3c-image.png

                                          Die Konfiguration erfolgt im ersten Abschnitt des Templates

                                          // config area
                                          // adapter instance
                                          const pihole_adapter_instance = 0; //Nummer der Instanz
                                          const domain_count=200;  //maximale Anzahl der abzufragenden domains
                                          const domain_blocked=true; //Abfrage der geblockten Domains im standard, Alternativ geht das auch mit den nicht geblockten domänen
                                          

                                          Das Template muss im entsprechenden Feld eingetragen werden. Zusätzlich muss noch ein Datenpunkt vom typ String angelegt werden und wie hier verknüpft werden.
                                          Darin werden die bekannten domänen gespeichert.
                                          9cf63a60-9a51-458d-b42a-c7a063d0b1aa-image.png

                                          Template

                                          <%
                                          // config area
                                          // adapter instance
                                          const pihole_adapter_instance = 0;
                                          const domain_count=200;
                                          const domain_blocked=true;
                                          %>
                                          <%
                                          //javascript code der per ejs interpretiert wird
                                          const knownDP = Object.keys(dp)[0] || "";
                                          const knownValue = dp[knownDP] || "[]";
                                          const knownValueSet = new Set(JSON.parse(knownValue));
                                          const adapterinstance = "pi-hole2."+pihole_adapter_instance;
                                          //debugger;
                                          const cookieKey = widgetID+"selectedTab";
                                          const selectedTab = localStorage.getItem(cookieKey)||"tab-all";
                                          
                                          // Abruf der Daten vom pihole2 adapter
                                          const apiresult = await getTopDomains(domain_count,domain_blocked); 
                                          
                                          // Aufbau Index
                                          const domainCountMap = new Map((apiresult.domains || []).map(d => [d.domain, d.count]));
                                          
                                          // Aufbau der Tabellendaten knownDomains
                                          const savedList = [...knownValueSet].map(domain => ({
                                           domain,
                                           count: domainCountMap.get(domain) || 0
                                          }));
                                          // Hilfsfunktion für async SendTo
                                          async function sendToAsync(instance, command, sendData) {
                                          return new Promise((resolve, reject) => {
                                           try {
                                               vis.conn.sendTo(instance, command, sendData, function (receiveData) {
                                                   resolve(receiveData);
                                               });
                                           } catch (error) {
                                               reject(error);
                                           }
                                          });
                                          }
                                          //Hilfsfunktion Abruf der TopDomains blocked/not blocked 
                                          async function getTopDomains(count,blocked) {
                                          const blockedText = blocked ? "true":"false";
                                          return await sendToAsync(adapterinstance,"piholeapi", {
                                             method: 'GET',
                                             endpoint: "/stats/top_domains?count="+count+"&blocked="+blockedText,
                                          });
                                          };
                                          %>
                                          
                                          <style>
                                          .pihole.select .tabs {
                                             display: flex;
                                             gap: .1rem;
                                          }
                                          
                                          .pihole.select .tabs button {
                                             padding: .4rem .8rem;
                                             border: 1px solid #ccc;
                                             background: #f7f7f7;
                                             cursor: pointer;
                                          }
                                          
                                          .pihole.select .tabs button.active {
                                             background: #e9eefc;
                                             border-color: #8aa3ff;
                                          }
                                          
                                          .pihole.select .tabpanel {
                                             display: none;
                                          }
                                          
                                          .pihole.select .tabpanel.active {
                                             display: block;
                                          }
                                          
                                          .pihole.select table {
                                             width: 100%;
                                             border-collapse: collapse;
                                          }
                                          
                                          .pihole.select th,
                                          .pihole.select td {
                                             padding: .3rem .4rem;
                                             xborder-bottom: 1px solid #eee;
                                          }
                                          
                                          .pihole.select .check {
                                             text-align: center;
                                             width: 10%;
                                          }
                                          .pihole.select .domain {
                                             text-align: left;
                                             xwidth: 70%;
                                             display: flex;
                                             align-items: center;
                                             gap: .4rem;            /* optional */	
                                          }
                                          .pihole.select .domain .filter-all {
                                           flex: 1;               /* <-- restliche Breite */
                                           min-width: 0;          /* wichtig für Firefox/Edge */
                                           box-sizing: border-box;
                                          }
                                          
                                          .pihole.select .count {
                                             text-align: end;
                                             width: 20%;
                                          }
                                          
                                          .muted {
                                             color: #888;
                                             font-size: .9em;
                                          }
                                          .pihole.select th .filter {
                                             display:block; margin-top:.25rem;
                                          }
                                          .pihole.select th .filter input {
                                             width:100%; 
                                             box-sizing:border-box; 
                                             padding:.25rem .35rem;
                                             border:1px solid #ccc; 
                                             border-radius:4px; 
                                             font-size:.9rem;
                                          }
                                          .pihole.select th .filter small { 
                                             color:#666; 
                                          }
                                          </style>
                                          
                                          <div class="pihole select">
                                           <div class="tabs" role="tablist">
                                             <button type="button" role="tab" aria-controls="tab-all" class="tabbtn <%= selectedTab=="tab-all"?"active":""%>">Alle Domains</button>
                                             <button type="button" role="tab" aria-controls="tab-saved" class="tabbtn <%= selectedTab=="tab-saved"?"active":""%>">Gemerkte Domains</button>
                                           </div>
                                          
                                           <div id="tab-all" class="tabpanel <%= selectedTab=="tab-all"?"active":""%>" role="tabpanel" aria-label="Alle Domains">
                                             <table data-table="all">
                                               <thead>
                                                 <tr>
                                                   <th class="check">
                                                     <span><input class="bulk" type="checkbox" data-action="check" checked></span>
                                                   </th>
                                                   <th class="domain">
                                                     <span>domain</span>
                                                     <input type="text" autofocus value="" class="filter-all">
                                                   </th>
                                                   <th class="count"><span>#</span></th>
                                                 </tr>
                                               </thead>
                                               <tbody>
                                                 <% (apiresult.domains || []).forEach(domain => { 
                                                      if (!knownValueSet.has(domain.domain)) { %>
                                                   <tr data-domain="<%= domain.domain %>">
                                                     <td class="check">
                                                       <input type="checkbox" data-id="<%= domain.domain %>">
                                                     </td>
                                                     <td class="domain"><%= domain.domain %></td>
                                                     <td class="count"><%= domain.count %></td>
                                                   </tr>
                                                 <% } }) %>
                                               </tbody>
                                             </table>
                                           </div>
                                          
                                           <div id="tab-saved" class="tabpanel <%= selectedTab=="tab-saved"?"active":""%>" role="tabpanel" aria-label="Gemerkte Domains">
                                             <table data-table="saved">
                                               <thead>
                                                 <tr>
                                                   <th class="check">
                                                     <input class="bulk" type="checkbox" data-action="uncheck">
                                                   </th>
                                                   <th class="domain">
                                                     <span>domain</span>
                                                     <input type="text" autofocus value="" class="filter-all">
                                                   </th>
                                                   <th class="count">#</th>
                                                 </tr>
                                               </thead>
                                               <tbody>
                                                 <% savedList.forEach(item => { %>
                                                   <tr data-domain="<%= item.domain %>">
                                                     <td class="check">
                                                       <input type="checkbox" data-id="<%= item.domain %>" checked>
                                                     </td>
                                                     <td class="domain">
                                                       <%= item.domain %>
                                                       <% if (!domainCountMap.has(item.domain)) { %>
                                                         <span class="muted">(derzeit nicht in Liste)</span>
                                                       <% } %>
                                                     </td>
                                                     <td class="count"><%= item.count %></td>
                                                   </tr>
                                                 <% }) %>
                                               </tbody>
                                             </table>
                                           </div>
                                          </div>
                                          
                                          <script>
                                          //Javascript code der im browser läuft
                                          (async () => {
                                           // Funktionen für Tabs umschalten
                                           const cookieKey = "<%= widgetID %>selectedTab";
                                           const selectedTab = localStorage.getItem(cookieKey)||"tab-all";
                                           const $tabs = $(".tabbtn");
                                           const $panels = $(".tabpanel");
                                           $tabs.on("click", function() {
                                           //debugger;
                                             $tabs.removeClass("active");
                                             $(this).addClass("active");
                                             const id = $(this).attr("aria-controls");
                                             $panels.removeClass("active");
                                             $("#"+id).addClass("active");
                                             localStorage.setItem(cookieKey,id);
                                           });
                                          
                                           // Daten aus den Datenpunkt wird ins Skriptn übernommen
                                          //debugger;
                                           const knownDP   = "<%- knownDP %>";
                                           const initial   = JSON.parse(atob("<%= btoa(knownValue) %>"));
                                           const knownSet  = new Set(initial);
                                          
                                           // Helpers
                                           function writeDP() {
                                             //debugger;
                                             vis.setValue(knownDP, JSON.stringify(Array.from(knownSet)));
                                           }
                                           function makeRow(domain, count, checked=true) {
                                             return $(`
                                               <tr data-domain="${domain}">
                                                 <td class="check"><input type="checkbox" data-id="${domain}" ${checked ? "checked":""}></td>
                                                 <td class="domain">${domain}</td>
                                                 <td class="count">${Number.isFinite(count) ? count : 0}</td>
                                               </tr>
                                             `);
                                           }
                                          
                                           // Eventhandler Merken einer Domain bzw auch wieder entfernen
                                           $('.pihole').on("change", 'tbody .check input', function(evt) {
                                             const id = $(evt.target).data("id");
                                             const isChecked = $(evt.target).is(":checked");
                                             const $row = $(evt.target).closest('tr');
                                          
                                             //hinzufügen oder entfernen der gewählten informationen
                                             if (isChecked) {
                                               // nach "saved" verschieben
                                               knownSet.add(id);
                                               // Count aus aktueller Zeile holen
                                               const cnt = parseInt($row.find('.count').text(), 10) || 0;
                                               // In saved hinzufügen, falls noch nicht vorhanden
                                               if ($('[data-table="saved"] tr[data-domain="'+id+'"]').length === 0) {
                                                 $('[data-table="saved"] tbody').append(makeRow(id, cnt, true));
                                               } else {
                                                 // sicherstellen, dass dort gecheckt ist
                                                 $('[data-table="saved"] tr[data-domain="'+id+'"] input[type="checkbox"]').prop('checked', true);
                                               }
                                               // Falls Änderung aus "all" kam: Zeile dort entfernen (weil nun gemerkt)
                                               if ($row.closest('table').attr('data-table') === 'all') {
                                                 $row.remove();
                                               }
                                             } else {
                                               // -> zurück nach "all" verschieben
                                               knownSet.delete(id);
                                               // Count aus aktueller Zeile holen
                                               const cnt = parseInt($row.find('.count').text(), 10) || 0;
                                               // In all hinzufügen, falls noch nicht vorhanden
                                               if ($('[data-table="all"] tr[data-domain="'+id+'"]').length === 0) {
                                                 $('[data-table="all"] tbody').append(makeRow(id, cnt, false));
                                               } else {
                                                 // sicherstellen, dass dort ungecheckt ist
                                                 $('[data-table="all"] tr[data-domain="'+id+'"] input[type="checkbox"]').prop('checked', false);
                                               }
                                               // Falls Änderung aus "saved" kam: Zeile dort entfernen
                                               if ($row.closest('table').attr('data-table') === 'saved') {
                                                 $row.remove();
                                               }
                                             }
                                             writeDP();
                                           });
                                          
                                           // Ereignishandler zum hinzufügen/entfernen aller sichtbaren Elemente
                                           $('.pihole').on('click', 'thead .bulk', function() {
                                           //debugger;
                                             const action = $(this).data('action'); // "check" | "uncheck"
                                             const $table = $(this).closest('table');
                                             const ids = $table.find('tbody tr:visible .check input').map((_,el)=>$(el).data('id')).get();
                                             //debugger;
                                             if (!ids.length) return;
                                             if (action === 'check') {
                                               ids.forEach(id => knownSet.add(id));
                                             } else {
                                               ids.forEach(id => knownSet.delete(id));
                                             }
                                             writeDP();
                                           });
                                           
                                           // Domain Filter
                                           const filterKey = "<%= widgetID %>filterAll";
                                           const $filter   = $('.filter-all');
                                           const $rowsAll  = $('[data-table="all"] tbody tr');
                                           const $visCount = $('#all-visible-count');
                                          
                                           //Funktion zum filtern
                                           function applyAllFilter(qRaw,table) {
                                             //debugger;
                                             const q = (qRaw || '').trim();
                                             let shown = 0;
                                          
                                             // Modus erkennen: /regex/ oder Wildcards
                                             let isRegex = false, re = null;
                                             if (q.startsWith('/') && q.endsWith('/') && q.length > 2) {
                                                 try {
                                                     re = new RegExp(q.slice(1, -1), 'i'); 
                                                     isRegex = true;
                                                 } catch(e) { 
                                                     /* fallback unten */ 
                                                 }
                                             }
                                             if (!isRegex) {
                                               // * als Wildcard; rest escapen
                                               const esc = q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\\\*/g, '.*');
                                               re = new RegExp(esc, 'i');
                                             }
                                          
                                             $('[data-table="'+table+'"] tbody tr').each((_, tr) => {
                                               const dom = tr.getAttribute('data-domain') || tr.querySelector('.domain')?.textContent || '';
                                               const match = q === '' ? true : re.test(dom);
                                               tr.style.display = match ? '' : 'none';
                                               if (match) shown++;
                                             });
                                          
                                             $visCount.text(shown);
                                           }
                                          
                                           // Entprellen der Eingabe 
                                           let fto;
                                           $filter.on('input', function() {
                                             const v = this.value;
                                             clearTimeout(fto);
                                             const table = $(this.closest("table")).data("table");
                                             fto = setTimeout(() => {
                                               localStorage.setItem(filterKey, v);
                                               applyAllFilter(v,table);
                                             }, 120);
                                           });
                                          
                                           // Beim Umschalten auf den Tab „Alle“ Filter erneut anwenden (falls DOM neu geändert wurde)
                                           $('.tabbtn[aria-controls="tab-all"]').on('click', () => applyAllFilter($filter.val()));
                                          
                                           // Persistierten Filter laden & anwenden
                                           const initialFilter = localStorage.getItem(filterKey) || "";
                                           $filter.val(initialFilter);
                                           applyAllFilter(initialFilter);
                                           
                                          })();
                                          </script>
                                          
                                          

                                          Widget2

                                          Dieses Widget zeigt alle geblockten requests an. Auch hier können ein paar Konfigurationen vorgenommen werden.
                                          Aufgrund dieser Lösung wurde noch ein kleiner glitch im jsontemplate entdeckt. Daher muss hier die Version 4.1.3 verwendet werden, ansonsten werden im 2.widget die Liste nicht korrekt dargestellt.

                                          d6c55515-a712-475f-80b8-2f417be28632-image.png
                                          Das Template muss im entsprechenden Feld eingetragen werden. Zusätzlich muss noch ein Datenpunkt vom typ String angelegt werden und wie hier verknüpft werden.
                                          Darin werden die bekannten domänen gespeichert.

                                          <%
                                          // config area
                                          // adapter instance
                                          const pihole_adapter_instance = 0;  //Adapter Instanz
                                          const blocked = true;  //Wie oben, ob geblockte oder nicht geblockte requests abgerufen werden soll
                                          const request_count=500;  // Anzahl der letzten requests, also ab dem jetzigen Zeitpunkt die letzten 500 requests.
                                          %>
                                          

                                          943fa6bf-e513-494e-a836-249b47749fb1-image.png

                                          Template

                                          <%
                                          // config area
                                          // adapter instance
                                          const pihole_adapter_instance = 0;
                                          const blocked = true;
                                          const request_count=500;
                                          %>
                                          <%
                                          const knownDP = Object.keys(dp)[0] || "";
                                          const knownValue = dp[knownDP] || "[]";
                                          %>
                                          
                                          <style>
                                          .pihole.requests {
                                             font-size: 0.8em;
                                          }
                                          .pihole.requests .col {
                                             text-align: left;
                                          }
                                          .pihole.requests .col.time {
                                             width: 15%;
                                          }
                                          .pihole.requests .col.status {
                                             width: 5%;
                                          }
                                          .pihole.requests .col.type {
                                             width: 5%;
                                          }
                                          .pihole.requests .col.domain {
                                             width: 20%;
                                          }
                                          .pihole.requests .col.client_name {
                                             width: 20%;
                                          }
                                          .pihole.requests .col.client_ip {
                                             width: 10%;
                                          }
                                          
                                          </style>
                                          <div class="pihole requests">
                                             <div>
                                                 <select class="clientsb" name="clients">
                                                       <option value="">no Clients</option>
                                                 </select>
                                             </div>
                                             <table data-table="all">
                                             	<thead>
                                             		<tr>
                                             			<th class="col time">Time</th>
                                             			<th class="col status">Status</th>
                                             			<th class="col type">Type</th>
                                             			<th class="col domain">Domain</th>
                                             			<th class="col client_name">Client Name</th>
                                             			<th class="col client_ip">Client IP</th>
                                             		</tr>
                                             	</thead>
                                             	<tbody>
                                                 </tbody>
                                             </table>
                                          </div>
                                          <script>
                                          //Javascript code der im browser läuft
                                          (async () => {
                                             const pihole_adapter_instance = 0;
                                             const adapterinstance = "pi-hole2."+pihole_adapter_instance;
                                             const blocked = <%- blocked %>;
                                             const request_count=<%- request_count %>;
                                          
                                             const knownDP   = "<%- knownDP %>";
                                             const knownValue = atob("<%= btoa(knownValue) %>");
                                             const knownValueSet = new Set(JSON.parse(knownValue));
                                          
                                             let fto;    
                                             let $table=$(".pihole.requests tbody");
                                          
                                             await fillClients();
                                          
                                             function fillTable() {
                                                 let table=$(".pihole.requests tbody"); 
                                             }
                                             async function fillClients() {
                                          
                                               const key = "<%= widgetID %>selectedclient";
                                               const selectedClient = localStorage.getItem(key)||"";
                                             
                                                 let clients = await getClients();
                                                 let $clientselect = $(".pihole.requests .clientsb");
                                          
                                                 const clientlist = Object.entries(clients.clients)
                                                   .map(([ip, v]) => ({
                                                     ip, ...v
                                                   }))
                                                   .sort((a, b) => b.total - a.total);
                                                 $clientselect.empty();
                                                 $clientselect.append($('<option value="" '+isSelected(selectedClient,"")+'>nothing selected</option>'));
                                                 clientlist.map(el=>$clientselect.append($('<option value="'+el.ip+'" '+isSelected(selectedClient,el.ip)+'>'+el.name+'/'+el.ip+'</option>')));
                                                 let that=this;
                                                 $clientselect.on('change', function() {
                                                   const v = this.value;
                                                   clearTimeout(fto);
                                                   fto = setTimeout(() => {
                                                     localStorage.setItem(key, v);
                                                     applySelect(v);
                                                   }, 120);
                                                 });
                                          
                                                 if (selectedClient) {
                                                     applySelect(selectedClient);
                                                 }
                                                 async function applySelect(client) {
                                                     let requests =  await getFilteredRequests(client /*"192.168.1.232"*/,request_count);
                                                     $table.empty();
                                                     requests.queries
                                                       .filter(req=>!knownValueSet.has(req.domain))
                                                       .map(req=>$table.append(makeRow(req)));
                                                 }
                                             }
                                             function findIPv4(adresses) {
                                                 let ips = adresses||[];
                                             
                                                 return (adresses||"").split(",").filter(ip=>ip.split(".").length-1)[0]||"";
                                             }
                                             function isSelected(v1,v2) {
                                                 return (v1==v2) ? "selected":"";
                                             }
                                             function makeRow(item) {
                                                 return $(`
                                                     <tr>
                                                         <td class="col time">`+         formatDate(item.time)+`</th>
                                                         <td class="col status">`+       item.status+`</th>
                                                         <td class="col type">`+         item.type+`</th>
                                                         <td class="col domain">`+       item.domain+`</th>
                                                         <td class="col client_name">`+  item.client.name+`</th>
                                                         <td class="col client_ip">`+    item.client.ip+`</th>
                                                     </tr>
                                                 `);
                                             }
                                             async function getData(client) {
                                                 if (!client) {
                                                     client = clients[0];
                                                 }
                                                 return await getFilteredRequests(client /*"192.168.1.232"*/,request_count);
                                             }
                                             async function sendToAsync(instance, command, sendData) {
                                                 return new Promise((resolve, reject) => {
                                                     try {
                                                         vis.conn.sendTo(instance, command, sendData, function (receiveData) {
                                                         resolve(receiveData);
                                                     });
                                                     } catch (error) {
                                                         reject(error);
                                                     }
                                                 });
                                             }
                                             async function getClients() {
                                                 return await sendToAsync(adapterinstance,"piholeapi", {
                                                     method: 'GET',
                                                     endpoint: "/history/clients?N=200",
                                                 });
                                             };
                                             async function getFilteredRequests(client_ip,count) {
                                                 return await sendToAsync(adapterinstance,"piholeapi", {
                                                     method: 'GET',
                                                     endpoint: "/queries?client_ip="+client_ip+"&upstream=blocklist&order%5B0%5D%5Bdir%5D=desc&start=0&length="+count,
                                                 });
                                             };
                                             function formatDate(ts) {
                                                 const date = new Date(ts * 1000);
                                                 return date.toISOString();
                                             }
                                          
                                          })();
                                          </script>
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          
                                          

                                          Meine Adapter und Widgets
                                          TVProgram, SqueezeboxRPC, OpenLiga, RSSFeed, MyTime,, pi-hole2, vis-json-template, skiinfo, vis-mapwidgets, vis-2-widgets-rssfeed
                                          Links im Profil

                                          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

                                          539

                                          Online

                                          32.4k

                                          Benutzer

                                          81.4k

                                          Themen

                                          1.3m

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

                                          • Du hast noch kein Konto? Registrieren

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