I think that was just something that happened when i was posting here, i checked and have no extra spaces in my .items file. Still a no go tho.
@kubawolanin awesome tutorial! Thank you for sharing it.
I’ve made a small adjustement in the formating to make the larger number easier to read.
"Domains being blocked [%,d\n]"
This format will allow to have thousand separators.
Could anyone help me to get this running in Openhab 3 with the HTTP binding 3.0?
I’ve created a new thing for the Pihole which is online:
Thing http:url:pihole "Pihole" @ "Systeme" [ baseURL="http://192.168.xxx.xxx/admin/api.php", refresh=60 ]
But i don’t get the right syntax for the items. For the HTTP binding v1 it was:
{http="<[pihole:100000:JSONPATH($.domains_being_blocked)]"}
for the v2 binding it has to start with channel="http:url:pihole...."
Any hint?
Greetings and thanks,
Huaba
I did the integration via the UI, but maybe this is of some help for you
Here is my Thing-Code
UID: http:url:pihole
label: pihole
thingTypeUID: http:url
configuration:
authMode: BASIC
ignoreSSLErrors: false
baseURL: http://<YOUR-PIHOLE-IP/admin/api.php
refresh: 30
commandMethod: GET
contentType: application/json
timeout: 3000
channels:
- id: domains_being_blocked
channelTypeUID: http:string
label: Domains being blocked
description: ""
configuration: {}
- id: dns_queries_today
channelTypeUID: http:string
label: DNS Queries today
description: ""
configuration: {}
- id: ads_blocked_today
channelTypeUID: http:string
label: Ads blocked today
description: ""
configuration: {}
- id: ads_percentage_today
channelTypeUID: http:string
label: Ads percentage today
description: ""
configuration: {}
- id: unique_domains
channelTypeUID: http:string
label: Unique Domains
description: ""
configuration: {}
- id: queries_forwarded
channelTypeUID: http:string
label: Queries forwarded
description: ""
configuration: {}
- id: queries_cached
channelTypeUID: http:string
label: Queries cached
description: ""
configuration: {}
- id: clients_ever_seen
channelTypeUID: http:string
label: Clients ever seen
description: ""
configuration: {}
- id: unique_clients
channelTypeUID: http:string
label: Unique Clients
description: ""
configuration: {}
- id: Pihole_Status
channelTypeUID: http:string
label: PI-Hole Status
description: ""
configuration: {}
And adding an Item looks like this:
Very late to this party, but here’s my working pihole integration in OH3 using configuration files:
Things
//THING
Thing http:url:pihole1 "Pihole1" [
baseURL = "http://YOUR_IP_HERE/admin/api.php",
refresh = "120",
timeout ="5000",
ignoreSSLErrors = "true"
]
{
Channels:
Type number : domains_being_blocked [
mode = "READONLY",
stateTransformation = "JSONPATH:$.domains_being_blocked"
]
Type number : dns_queries_today [
mode = "READONLY",
stateTransformation = "JSONPATH:$.dns_queries_today"
]
Type number : ads_blocked_today [
mode = "READONLY",
stateTransformation = "JSONPATH:$.ads_blocked_today"
]
Type number : ads_percentage_today [
mode = "READONLY",
stateTransformation = "JSONPATH:$.ads_percentage_today"
]
Type number : unique_domains [
mode = "READONLY",
stateTransformation = "JSONPATH:$.unique_domains"
]
Type number : queries_forwarded [
mode = "READONLY",
stateTransformation = "JSONPATH:$.queries_forwarded"
]
Type number : queries_cached [
mode = "READONLY",
stateTransformation = "JSONPATH:$.queries_cached"
]
Type number : clients_ever_seen [
mode = "READONLY",
stateTransformation = "JSONPATH:$.clients_ever_seen"
]
Type number : unique_clients [
mode = "READONLY",
stateTransformation = "JSONPATH:$.unique_clients"
]
Type number : dns_queries_all_types [
mode = "READONLY",
stateTransformation = "JSONPATH:$.dns_queries_all_types"
]
Type number : reply_NODATA [
mode = "READONLY",
stateTransformation = "JSONPATH:$.reply_NODATA"
]
Type number : reply_NXDOMAIN [
mode = "READONLY",
stateTransformation = "JSONPATH:$.reply_NXDOMAIN"
]
Type number : reply_CNAME [
mode = "READONLY",
stateTransformation = "JSONPATH:$.reply_CNAME"
]
Type number : reply_IP [
mode = "READONLY",
stateTransformation = "JSONPATH:$.reply_IP"
]
Type number : privacy_level [
mode = "READONLY",
stateTransformation = "JSONPATH:$.privacy_level"
]
Type switch : status [
mode = "READONLY",
stateTransformation = "JSONPATH:$.status",
onValue = "enabled",
offValue = "disabled"
]
Type switch : enable_disable [
mode = "WRITEONLY",
commandExtension = "?%2$s&auth=YOUR_API_KEY_HERE",
onValue = "enable",
offValue = "disable"
]
//GRAVITY LAST UPDATED
Type string : file_exists [
mode = "READONLY",
stateTransformation = "JSONPATH:$.gravity_last_updated.file_exists"
]
//ABSOLUTE TIME OF LAST UPDATE
Type number : absolute [
mode = "READONLY",
stateTransformation = "JSONPATH:$.gravity_last_updated.absolute"
]
//RELATIVE TIME OF LAST UPDATE
Type number : days [
mode = "READONLY",
stateTransformation = "JSONPATH:$.gravity_last_updated.relative.days"
]
Type number : hours [
mode = "READONLY",
stateTransformation = "JSONPATH:$.gravity_last_updated.relative.hours"
]
Type number : minutes [
mode = "READONLY",
stateTransformation = "JSONPATH:$.gravity_last_updated.relative.minutes"
]
}
Items
Number nPihole1_domains_being_blocked { channel="http:url:pihole1:domains_being_blocked" }
Number nPihole1_dns_queries_today { channel="http:url:pihole1:dns_queries_today" }
Number nPihole1_ads_blocked_today { channel="http:url:pihole1:ads_blocked_today" }
Number nPihole1_ads_percentage_today { channel="http:url:pihole1:ads_percentage_today" }
Number nPihole1_unique_domains { channel="http:url:pihole1:unique_domains" }
Number nPihole1_queries_forwarded { channel="http:url:pihole1:queries_forwarded" }
Number nPihole1_queries_cached { channel="http:url:pihole1:queries_cached" }
Number nPihole1_clients_ever_seen { channel="http:url:pihole1:clients_ever_seen" }
Number nPihole1_unique_clients { channel="http:url:pihole1:unique_clients" }
Number nPihole1_dns_queries_all_types { channel="http:url:pihole1:dns_queries_all_types" }
Number nPihole1_reply_NODATA { channel="http:url:pihole1:reply_NODATA" }
Number nPihole1_reply_NXDOMAIN { channel="http:url:pihole1:reply_NXDOMAIN" }
Number nPihole1_reply_CNAME { channel="http:url:pihole1:reply_CNAME" }
Number nPihole1_reply_IP { channel="http:url:pihole1:reply_IP" }
Number nPihole1_privacy_level { channel="http:url:pihole1:privacy_level" }
Switch sPihole1_status { channel="http:url:pihole1:status" }
Switch sPihole1_enable_disable { channel="http:url:pihole1:enable_disable", channel="http:url:pihole1:status" }
String strPihole1_file_exists { channel="http:url:pihole1:file_exists" }
Number nPihole1_absolute { channel="http:url:pihole1:absolute" }
Number nPihole1_days { channel="http:url:pihole1:days" }
Number nPihole1_hours { channel="http:url:pihole1:hours" }
Number nPihole1_minutes { channel="http:url:pihole1:minutes" }
This configuration provides a Switch Item sPihole1_enable_disable
which you can use to enable and disable pihole from within openHAB. This switch Item is also linked to the status
Channel, so it will update if pihole is enabled/disabled by another source too.
I cut most of my Pi-Hole integration (I wasn’t ever looking at it) and just kept the switch for enabling/disabling. However, the thing I use most is a browser bookmark to the Pi-Hole API that disables it for five minutes.
http://SERVER/admin/api.php?disable=300&auth=xxxxxxxx
Can you share the images and code as well @kjknauss very appreciated:)
Not much to it. Just a bunch of label cards with F7 icons. Last card is a switch that when toggled fires a rule similar to the one @rkrisi contributed above. Just update with your items…
config:
label: PiHole
sidebar: false
blocks:
- component: oh-block
config: {}
slots:
default:
- component: oh-grid-row
config: {}
slots:
default:
- component: oh-grid-col
config:
width: "25"
slots:
default:
- component: oh-label-card
config:
background: green
fontSize: 34px
fontWeight: bold
icon: f7:globe
item:
title: Total Queries
- component: oh-grid-col
config:
width: "25"
slots:
default:
- component: oh-label-card
config:
background: aqua
fontSize: 34px
fontWeight: bold
icon: f7:hand_raised_slash
item:
title: Queries Blocked
- component: oh-grid-col
config:
width: "25"
slots:
default:
- component: oh-label-card
config:
background: orange
fontSize: 34px
fontWeight: bold
icon: f7:chart_pie
item:
title: Percent Blocked
- component: oh-grid-col
config:
width: "25"
slots:
default:
- component: oh-label-card
config:
background: red
fontSize: 34px
fontWeight: bold
icon: f7:list_dash
item:
title: Domains on Blocklist
- component: oh-block
config: {}
slots:
default:
- component: oh-grid-row
config: {}
slots:
default:
- component: oh-grid-col
config:
width: "25"
slots:
default:
- component: oh-label-card
config:
action: analyzer
actionAnalyzerItems:
-
background: green
fontSize: 34px
fontWeight: bold
item:
title: Gravity Update Days
trendItem:
- component: oh-grid-col
config:
width: "25"
slots:
default:
- component: oh-label-card
config:
action: analyzer
actionAnalyzerItems:
-
background: aqua
fontSize: 34px
fontWeight: bold
item:
title: Queries Cached
trendItem:
- component: oh-grid-col
config:
width: "25"
slots:
default:
- component: oh-label-card
config:
action: analyzer
actionAnalyzerItems:
-
background: orange
fontSize: 34px
fontWeight: bold
item:
title: Unique Domains
trendItem:
- component: oh-grid-col
config:
width: "25"
slots:
default:
- component: oh-label-card
config:
action: toggle
actionCommand: ON
actionCommandAlt: OFF
background: red
fontSize: 34px
fontWeight: bold
item:
title: PiHole Status
actionItem:
masonry: []
grid: null
Hello all,
just a trackback
with the latest update, its not working anymore for me.
Now you need to change baseURL in thing definition
from
baseURL="http://pihole.IP.address/admin/api.php
to
baseURL="http://pihole.IP.address/admin/api.php?summary&auth=API-TOKEN-goes-here"
You can get the token from Settings/API/Show API token or from /etc/pihole/setupVars.conf (WEBPASSWORD).
Hey @kristofejro i also noticed this and thats why i added a second pihole-cmd thing for the actual changes in the block mode.
For those, who are interested in accessing a pihole instance which is behind cloudflare access, please check out my comment on that topic:
Thanks to this thread and the information provided by the community, I integrated the current Pi-Hole version in OpenHab using the latest HTTP Binding. Preconditions and requirements are:
- HTTP-Binding installed (Settings → Add-ons → Bindings)
- JSONPath-Transformation installed (Settings → Add-ons → Transformations)
I just wanted to give back and provide my “Things” configuration here for others to benefit from:
Thing http:url:pihole "PiHole" [baseURL="http://PI-HOLE_IP:PI-HOLE_PORT/admin/api.php", refresh=30, timeout=3000] {
Channels:
Type switch : enable_disable "PiHole Command (Enable/Disable)" [
mode = "WRITEONLY",
commandExtension = "?%2$s=0&auth=API_KEY_HERE",
onValue = "enable",
offValue = "disable"
]
Type switch : status "PiHole State (read-only)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.status",
onValue = "enabled",
offValue = "disabled"
]
Type number : dns_queries_today "Total Queries (Today)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.dns_queries_today"
]
Type number : ads_blocked_today "Queries Blocked (Today)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.ads_blocked_today"
]
Type number : ads_percentage_today "Percentage Blocked (Today)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.ads_percentage_today"
]
Type number : domains_being_blocked "Domains on Blocklist (Total)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.domains_being_blocked"
]
Type number : unique_domains "Domains on Blacklist (Unique)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.unique_domains"
]
Type number : queries_forwarded "Queries resolved via upstream DNS Server" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.queries_forwarded"
]
Type number : queries_cached "Queries resolved via local DNS Cache/Config" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.queries_cached"
]
Type number : clients_ever_seen "Clients seen (Total)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.clients_ever_seen"
]
Type number : unique_clients "Clients seen (Unique)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.unique_clients"
]
Type number : dns_queries_all_types "DNS Queries (All Types)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.dns_queries_all_types"
]
Type number : reply_NODATA "DNS Replies (NODATA)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.reply_NODATA"
]
Type number : reply_NXDOMAIN "DNS Replies (NXDOMAIN)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.reply_NXDOMAIN"
]
Type number : reply_CNAME "DNS Replies (CNAME)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.reply_CNAME"
]
Type number : reply_IP "DNS Replies (IP)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.reply_IP"
]
Type number : privacy_level "Statitics Privacy Level (0=Anonymize none,1=no domains,2=no domains/clients,3=Anonymize all)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.privacy_level"
]
Type string : file_exists "Gravity updated" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.gravity_last_updated.file_exists"
]
Type number : absolute "Gravity update duration" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.gravity_last_updated.absolute"
]
Type number : days "Gravity time since last update (days)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.gravity_last_updated.relative.days"
]
Type number : hours "Gravity time since last update (days)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.gravity_last_updated.relative.hours"
]
Type number : minutes "Gravity time since last update (days)" [
mode = "READONLY",
stateExtension = "?summary&auth=API_KEY_HERE",
stateTransformation = "JSONPATH:$.gravity_last_updated.relative.minutes"
]
}
You can even make the state a single read/write channel (sorry only got the code from MainUI):
channels:
- id: status
channelTypeUID: http:switch
label: Status
description: ""
configuration:
onValue: enabled
commandTransformation: MAP:piholestatus.map
offValue: disabled
stateExtension: /admin/api.php?summaryRaw&auth=AUTHKEY
commandExtension: /admin/api.php?%2$s&auth= AUTHKEY
stateTransformation: JSONPATH:$.status
With piholestatus.map:
enabled=enable
disabled=disable
Nice, did that by mapping command and the state channel to one item. But your way is more elegant, will try to set this up in text. Thanks for the hint.
Does somebody use the new Beta 6 version of pi-hole?
Need some help with the new api
Hello, yes I am using it…which help do you need?
how to configurate with the new api key
This is the api doc
https://ftl.pi-hole.net/development-v6/docs/
For the password itself, go to settings and “app password” generate one or use your normal password
- Generate a session with
curl -X POST "https://pi.hole:443/api/auth" \
-H "accept: application/json"\
-H "content-type: application/json" \
-d '{"password":"abcdef"}'
- Do what ever you wanna do
It wasn’t possible for me to implement it…but Christmas is coming so maybe I find a little bit of time
Here is the beginning @_tobi
rules.JSRule({
name: "pihole API rule",
description: "Access to pihole API",
triggers: [triggers.GenericCronTrigger("0/10 * * * * ? *")],
execute: (event) => {
var resposne;
var sessionId;
var responseData;
response = actions.HTTP.sendHttpGetRequest('http://pi.hole:8080/api/auth', {"accept": "application/json"}, 5000);
if (response != null) {
responseData = JSON.parse(response);
if (responseData.session.sid == null) {
actions.Log.logInfo("pihole API rule", "No open session");
response = actions.HTTP.sendHttpPostRequest('http://pihole.fritz.box:8080/api/auth', 'application/json', '{"password":"{yourpassword"}', {"accept": "application/json"}, 5000);
if (response != null) {
responseData = JSON.parse(response);
if (responseData.session.sid != null) {
actions.Log.logInfo("pihole API rule", "Session started");
} else {
actions.Log.logError("pihole API rule","Error during session start");
if (response != null) {
actions.Log.logError("pihole API rule", response);
}
}
} else {
actions.Log.logError("pihole API rule","Error during API request");
}
} else {
sessionId = responseData.session.sid;
actions.Log.logInfo("pihole API rule", "There is a session open with ID");
actions.Log.logInfo("pihole API rule", sessionId);
}
} else {
actions.Log.logError("pihole API rule","Error during API request");
}
console.log(response);
},
tags: ["pihole", "pihole api"],
id: "pihole API rule"
});