Pi-Hole Integration

There is an existing BIND DDNS that is working nicely with my local DHCP and gets the dynamic updates.
I am too lazy to configure the embedded FTL DNS of PiHole to replace my BIND :slight_smile:

I didn’t even check if FTL DNS supports dynamic updates… in theory it does

Finally, I placed PiHole between my LAN and External DNS and it works fine (with the disadvantage of listing only localhost as the client :slight_smile:)

Hi kubawolani,

thanks for your post. I want to know if you have an idea, why it doesn’t work in my environment.
I configure it step by step but I can’t see anything in the Sitemap … in the openHAB shell every pi hole item are NULL …
btw: it’s my first http binding

If I change from

Number PiHole_QueriesCached "Queries cached [%d]" <wind> (gPiHole) {http="<[pihole:100000:JSONPATH($.queries_cached)]"}

to

Number PiHole_QueriesCached "Queries cached [%d]" <wind> (gPiHole) {http="<[<url>:100000:JSONPATH($.queries_cached)]"}

everthing works, have someone an Idea?

Thank you for this valuable tutorial

I would like to ask community about their practical usages of connecting Pi-hole with openHAB?

Good point. My PiHole simply runs independently of anything else. Frankly I totally forgot about it for months now.
Really rarely I’ve disabled it for a few minutes to check if a website is unintentionally blocked or to demonstrate the difference / advantages of PiHole to friends.
Then it is just convenient to have the controls and statistics in the same environment as the home automation.
Automated interaction with light switch, weather data or user presence? Not really imho.

Thanks for the implementation, I have been using it for months now. I have extended a bit. There are more info available from the API:

Number  PiHole_DomainsBeingBlocked  "Domains being blocked [%d]"        <pihole>    (gPiHole)   {http="<[pihole:100000:JSONPATH($.domains_being_blocked)]"}

Number  PiHole_DnsQueriesToday      "DNS queries today [%d]"            <chart>     (gPiHole)   {http="<[pihole:100000:JSONPATH($.dns_queries_today)]"}

Number  PiHole_AdsBlockedToday      "Ads blocked today [%d]"            <keyring>   (gPiHole)   {http="<[pihole:100000:JSONPATH($.ads_blocked_today)]"}

Number  PiHole_AdsPercentageToday   "Ads percentage today [%.2f %%]"    <keyring>   (gPiHole)   {http="<[pihole:100000:JSONPATH($.ads_percentage_today)]"}

Number  PiHole_UniqueDomains        "Unique domains [%d]"               <network>   (gPiHole)   {http="<[pihole:100000:JSONPATH($.unique_domains)]"}

Number  PiHole_QueriesForwarded     "Queries forwarded [%d]"            <chart>     (gPiHole)   {http="<[pihole:100000:JSONPATH($.queries_forwarded)]"}

Number  PiHole_QueriesCached        "Queries cached [%d]"               <wind>      (gPiHole)   {http="<[pihole:100000:JSONPATH($.queries_cached)]"}

Number  PiHole_ClientsEverSeen      "Clients ever seen [%d]"            <screen>    (gPiHole)   {http="<[pihole:100000:JSONPATH($.clients_ever_seen)]"}

Number  PiHole_UniqueClients        "Unique clients [%d]"               <screen>    (gPiHole)   {http="<[pihole:100000:JSONPATH($.unique_clients)]"}

Number  PiHole_DnsQueriesAllTypes   "DNS queries All Type [%d]"         <chart>     (gPiHole)   { http="<[pihole:100000:JSONPATH($.dns_queries_all_types)]" }

Number  PiHole_ReplyNoData          "Reply No Data [%d]"                <wind>      (gPiHole)   { http="<[pihole:100000:JSONPATH($.reply_NODATA)]" }

Number  PiHole_ReplyNxDomain        "Reply NXDomain [%d]"               <wind>      (gPiHole)   { http="<[pihole:100000:JSONPATH($.reply_NXDOMAIN)]" }

Number  PiHole_ReplyCName           "Reply CName [%d]"                  <wind>      (gPiHole)   { http="<[pihole:100000:JSONPATH($.reply_CNAME)]" }

Number  PiHole_ReplyIP              "Reply IP [%d]"                     <wind>      (gPiHole)   { http="<[pihole:100000:JSONPATH($.reply_IP)]" }

String  PiHole_UpdatedDays                                              <time>      (gPihole)   { http="<[pihole:100000:JSONPATH($.gravity_last_updated.relative.days)]" }

String  PiHole_UpdatedHours                                             <time>      (gPiHole)   { http="<[pihole:100000:JSONPATH($.gravity_last_updated.relative.hours)]" }

String  PiHole_UpdatedMinutes                                           <time>      (gPiHole)   { http="<[pihole:100000:JSONPATH($.gravity_last_updated.relative.minutes)]" }

Also built a rule, so that you can disable (temporary) Pi-hole blocking from openHAB:

val String filename = "PiHole.rules"
val String WEBPASS = "YOUR WEBPASS"

rule "Disable Pi-Hole"
when
    Item PiHole_Disable received command
then
    logInfo(filename, "Started: Disable Pi-Hole - State: " + PiHole_Disable.state.toString)
    if(receivedCommand == ON) {
        sendHttpGetRequest("http://<PIHOLE IP>/admin/api.php?disable=300&auth=" + WEBPASS, 2000)
    }
    else if(receivedCommand == OFF) {
        sendHttpGetRequest("http://<PIHOLE IP>/admin/api.php?enable&auth=" + WEBPASS, 2000)
    }
end

You can find the Webpass in the Pi-hole config file, that is needed for this rule to work. You can specify seconds after “disable=” for how many seconds you want to disable the blocking.

4 Likes

Thanks, that is great. Now i can disable pihole with my openhab.

I have an additional item:

String   PiHole_Status                "Status [%s]"                     <status>    (gPiHole)   {http="<[pihole:100000:JSONPATH($.status)]"}

But this always gives me “enabled”, even the pihole is temporarly disabled ?! Any idea?

I also have that :slight_smile: Just forgot to include in my post.
I don’t know why it always shows enabled. Are you sure that the specified updateInterval ran after you disabled it?
Try disabling Pi-hole and open the http://“Pi-Hole address”/admin/api.php endpoint in your browser and look there if it shows disabled or not.

For me it works as it should. It shows disabled if I turn off blocking. Doesn’t matter if it is temporary or not.

Inside the api endpoint i can see “disabled”.

After some time now this changed inside openhab also.

I think, i have no real time display of the pihole values, there is an update interval included:

{ http="<[pihole:100000:JSONPATH

100000 = 100 seconds?

Yes this will never be ‘real time’, because it is just polling that http endpoint.

If I’m right this value is the Refresh Interval, you can set the Update Interval in the http.cfg. If you used the tutorial in the original post, it is set to 10 minutes poll time.

What are you doing with the UpdatedDays …Hours …Minutes items?

Are you building a combined string with this 3 values for a better view or do you display this values on 3 places in your sitemap?

Like 20 - 10:30 for example (20 days, 10 hours, 30 minutes)?

Yes, exactly I’m combining these items into one String that I can view on my sitemap.
Like last update was “2 days 14:54 ago”…

Can you post your rule for this? Too lazy right now to code it myself :innocent:

Sure!
If you click on the reply button on my post or tag my name in your reply, I will get a notification, so I can reply faster :slight_smile:

Here is the rule:

rule "Last Gravity Update PiHole"
when
    Item PiHole_UpdatedDays changed or
    Item PiHole_UpdatedHours changed or
    Item PiHole_UpdatedMinutes changed
then
    logInfo(filename, "Started: Last Gravity Update for PiHole")
    val output = PiHole_UpdatedDays.state.toString + " day(s) " + PiHole_UpdatedHours.state.toString + ":" + PiHole_UpdatedMinutes.state.toString
    PiHole_DateOut.postUpdate(output)
end
1 Like

Excellent Rule Kristof, just (as a non developer) I am puzzled how you extract the values of the Days, Hours and Minutes using JSONPATH out of the return from the API call to …/admin/api.php? As the values are stored in ‘sub’ values a direct JSONPATH call like:

{http="<[pihole:100000:JSONPATH($.updated_days)]"}

doesn’t work.
Thanks!

Use it like this:

{ http="<[pihole:100000:JSONPATH($.gravity_last_updated.relative.days)]" }

Getting this error when using this rule, so the items are not being listed for the last updates. Any input?
An error occurred during the script execution: index=1, size=1

I think your item definition might be wrong, thus these items stay NULL and that’s why the rule fails to work.

The items looks like this;

String  PiHole_UpdatedDays                                              <time>      (Pihole)   {http=" <[pihole:100000:JSONPATH($.gravity_last_updated.relative.days)]"}
String  PiHole_UpdatedHours                                             <time>      (PiHole)   {http="<[pihole:100000:JSONPATH($.gravity_last_updated.relative.hours)]"}
String  PiHole_UpdatedMinutes                                           <time>      (PiHole)   {http="<[pihole:100000:JSONPATH($.gravity_last_updated.relative.minutes)]"}

Is this wrong?

You have an extra space in the first line after the http=" …
I don’t know if this causes any trouble… Try adding these items to a sitemap and see if you get any readable output