PiHole Version 6 integration script

While we wait for the version of the PiHole binding that can be used in the new version 6 of PiHole, I created this simple script to collect some statistics and information.

It is based on bash and MQTT and can be run on any host that has access to both PiHole server and the MQTT host used by OH.

I hope it can help someone and that others, if interested, can improve and fix this collector.

#!/bin/bash
#
# Dependencies
#
# - curl
# - jq
# - mosquitto-clients
#
Pi_OH_Stats_DIR="<YOUR-DIR>"
#
PiHoleServer="<YOUR-PIHOLE-SERVER-ADDRESS>"
PiHoleAccess="https://"
#
PiHoleUser=""
PiHolePassword="<YOUR-PIHOLE-PASSWORD>"
#
MQTTHost="<MQTT-HOST-IP>"
MQTTUser="<MQTT-USER>"
MQTTPassword="<MQTT-PASSWORD>"
MQTTTopic="PiHoleStats"
MQTTPubFile="$Pi_OH_Stats_DIR/MQTT_PUB"
#
#
PiHoleSID=""
#
PiHoleAPIStatus=""
#
PiHoleAuthStatus=""
#
BLOCKING_STATUS=""
#
Stats_Summary=""
#
SID_FILE="$Pi_OH_Stats_DIR/SID_FILE"
#
SID_AUTH=""
#
SID_OK=false
#
#
CURL_Q1="curl -s -k --request POST -d '{\"password\":\"$PiHolePassword\"}' $PiHoleAccess$PiHoleServer/api/auth | jq -r '.session.sid'"
#
CURL_Q2=""
#
CURL_Q3=""
#
CURL_Q4=""
#
function testSIDAuth() {
    CURL_Q2="curl -skX GET \"$PiHoleAccess$PiHoleServer/api/dns/blocking\" -H \"accept: application/json\" -H \"sid: $SID_AUTH\" | jq -r '.blocking'"

    BLOCKING_STATUS=$(eval "$CURL_Q2");
}


function tryToLogin() {
    SID_AUTH=$(eval "$CURL_Q1");

    if [[ -z "$SID_AUTH" ]]; then
	echo -e "\nAuthentication failed!"
        SID_OK=false
    else
	echo -e "\nAuthentication OK"
        echo $SID_AUTH > $SID_FILE
	SID_OK=true
    fi
}

function testSIDFile() {
    if [ -f $SID_FILE ]; then
	SID_AUTH=$(cat $SID_FILE)
	SID_OK=true
    else
#
# SID AUTH file does not exist. Try to authenticate
#
    tryToLogin
        if [ $SID_OK == false ]; then
		echo "Login failed"
    	    exit 1
	fi
    fi
}


function parseStatsSummary() {
    Total_Queries=$(echo $Stats_Summary | jq -r '.queries.total')
    Total_Blocked=$(echo $Stats_Summary | jq -r '.queries.blocked')
    Percent_Blocked=$(echo $Stats_Summary | jq -r '.queries.percent_blocked')

    Unique_Domains=$(echo $Stats_Summary | jq -r '.queries.unique_domains')
    Forwarded=$(echo $Stats_Summary | jq -r '.queries.forwarded')
    Cached=$(echo $Stats_Summary | jq -r '.queries.cached')

    Clients_Active=$(echo $Stats_Summary | jq -r '.clients.active')
    Clients_Total=$(echo $Stats_Summary | jq -r '.clients.total')

    Gravity_Domains_Being_Blocked=$(echo $Stats_Summary | jq -r '.gravity.domains_being_blocked')
    Gravity_Last_Update_TS=$(echo $Stats_Summary | jq -r '.gravity.last_update')

    tsNow=$(date +%s)
    diffTS=$(expr $tsNow - $Gravity_Last_Update_TS)
    Gravity_Last_Update_Days=$(expr $diffTS / 86400)

}


function parseInfoVersion() {

    Core_Version=$(echo $Info_Version | jq -r '.version.core.local.version')
    WEB_Version=$(echo $Info_Version | jq -r '.version.web.local.version')
    FTL_Version=$(echo $Info_Version | jq -r '.version.ftl.local.version')


    CoreLocalHash=$(echo $Info_Version | jq -r '.version.core.local.hash')
    WEBLocalHash=$(echo $Info_Version | jq -r '.version.web.local.hash')
    FTLLocalHash=$(echo $Info_Version | jq -r '.version.ftl.local.hash')

    CoreRemoteHash=$(echo $Info_Version | jq -r '.version.core.remote.hash')
    WEBRemoteHash=$(echo $Info_Version | jq -r '.version.web.remote.hash')
    FTLRemoteHash=$(echo $Info_Version | jq -r '.version.ftl.remote.hash')

    if [ $CoreLocalHash == $CoreRemoteHash ]; then
	Core_Update="OFF"
    else
	Core_Update="ON"
    fi

    if [ $WEBLocalHash == $WEBRemoteHash ]; then
        WEB_Update="OFF"
    else
	WEB_Update="ON"
    fi

    if [ $FTLLocalHash == $FTLRemoteHash ]; then
        FTL_Update="OFF"
    else
	FTL_Update="ON"
    fi
}

function initResults() {

    MQTT_PUB=""

    BLOCKING_STATUS="N/A"

    Total_Queries=0
    Total_Blocked=0
    Percent_Blocked=0

    Unique_Domains=0
    Forwarded=0
    Cached=0

    Clients_Active=0
    Clients_Total=0
    Gravity_Domains_Being_Blocked=0
    Gravity_Last_Update_TS=0

    Gravity_Last_Update_Days=0

    Core_Version="N/A"
    WEB_Version="N/A"
    FTL_Version="N/A"

    Core_Update="OFF"
    WEB_Update="OFF"
    FTL_Update="OFF"
}

function showResults() {

    echo $BLOCKING_STATUS

    echo $Total_Queries
    echo $Total_Blocked
    echo $Percent_Blocked

    echo $Unique_Domains
    echo $Forwarded
    echo $Cached

    echo $Clients_Active
    echo $Clients_Total
    echo $Gravity_Domains_Being_Blocked
    echo $Gravity_Last_Update_TS

    echo $Gravity_Last_Update_Days

    echo $Core_Version
    echo $WEB_Version
    echo $FTL_Version

    echo $Core_Update
    echo $WEB_Update
    echo $FTL_Update

}

function getStatsSummary() {
    CURL_Q3="curl -skX GET \"$PiHoleAccess$PiHoleServer/api/stats/summary\" -H \"accept: application/json\" -H \"sid: $SID_AUTH\""
    Stats_Summary=$(eval "$CURL_Q3");
}


function getInfoVersion() {
    CURL_Q4="curl -skX GET \"$PiHoleAccess$PiHoleServer/api/info/version\" -H \"accept: application/json\" -H \"sid: $SID_AUTH\""
    Info_Version=$(eval "$CURL_Q4");
}


function createMQTTPub() {
MQTT_PUB="{\"blocking_status\":$BLOCKING_STATUS,\"total_queries\":$Total_Queries,\
\"total_blocked\":$Total_Blocked,\"percent_blocked\":$Percent_Blocked,\
\"unique_domains\":$Unique_Domains,\"forwarded\":$Forwarded,\"cached\":$Cached,\
\"clients_active\":$Clients_Active,\"clients_total\":$Clients_Total,\
\"gravity_domains_being_blocked\":$Gravity_Domains_Being_Blocked,\
\"gravity_last_update_ts\":$Gravity_Last_Update_TS,\"gravity_last_update_days\":$Gravity_Last_Update_Days,\
\"core_update\":$Core_Update,\"web_update\":$WEB_Update,\"ftl_update\":$FTL_Update}"

echo $MQTT_PUB > $MQTTPubFile
}

#
    initResults
#
    testSIDFile
#
    testSIDAuth

#
# If testSIDAuth can not use current SID_AUTH try to authenticate and get a newer SID_AUTH
#
    if [[ -z "$BLOCKING_STATUS" ]]; then
        tryToLogin
	    if [ $SID_OK == false ]; then
	    	echo "Login failed"
    		exit 1
	    fi
    fi

#
    getStatsSummary
#
    getInfoVersion
#
    parseStatsSummary
#
    parseInfoVersion
#
#    showResults
#
    createMQTTPub
#
    MQTTCmd="mosquitto_pub -h $MQTTHost -t $MQTTTopic -u $MQTTUser -P $MQTTPassword -f $MQTTPubFile"
    $(eval "$MQTTCmd");
#
    exit 0
#

Page code

config:
  icon: f7:umbrella
  label: Pi Hole Status
  sidebar: true
blocks:
  - component: oh-block
    config: {}
    slots:
      default:
        - component: oh-grid-row
          config: {}
          slots:
            default:
              - component: oh-grid-col
                config:
                  width: "100"
                  small: "25"
                slots:
                  default:
                    - component: oh-label-card
                      config:
                        background: green
                        fontSize: 34px
                        fontWeight: bold
                        icon: f7:globe
                        item: PiHole_Stats_V6_PiHole_Total_queries
                        outline: true
                        title: Total Queries
                        trendItem: PiHole_Stats_V6_PiHole_Total_queries
              - component: oh-grid-col
                config:
                  width: "100"
                  small: "25"
                slots:
                  default:
                    - component: oh-label-card
                      config:
                        background: rgb(26, 140, 255)
                        fontSize: 34px
                        fontWeight: bold
                        icon: f7:hand_raised_slash
                        item: PiHole_Stats_V6_PiHole_Total_Blocked
                        outline: true
                        title: Queries Blocked
                        trendItem: PiHole_Stats_V6_PiHole_Total_Blocked
              - component: oh-grid-col
                config:
                  width: "100"
                  small: "25"
                slots:
                  default:
                    - component: oh-label-card
                      config:
                        background: orange
                        fontSize: 34px
                        fontWeight: bold
                        icon: f7:chart_pie
                        item: PiHole_Stats_V6_PiHole_Percent_Blocked
                        outline: true
                        title: Percent Blocked
                        trendItem: PiHole_Stats_V6_PiHole_Percent_Blocked
              - component: oh-grid-col
                config:
                  width: "100"
                  small: "25"
                slots:
                  default:
                    - component: oh-label-card
                      config:
                        background: red
                        fontSize: 34px
                        fontWeight: bold
                        icon: f7:list_dash
                        item: PiHole_Stats_V6_PiHole_Gravity_Domains_Being_Blocked
                        outline: true
                        title: Domains on Blocklist
  - component: oh-block
    config: {}
    slots:
      default:
        - component: oh-grid-row
          config: {}
          slots:
            default:
              - component: oh-grid-col
                config:
                  width: "100"
                  small: "25"
                slots:
                  default:
                    - component: oh-label-card
                      config:
                        action: analyzer
                        actionAnalyzerItems:
                          - null
                        background: green
                        fontSize: 34px
                        fontWeight: bold
                        icon: f7:clock
                        item: PiHole_Stats_V6_PiHole_Gravity_Last_Update_Days
                        outline: true
                        title: Gravity Update Days
              - component: oh-grid-col
                config:
                  width: "100"
                  small: "25"
                slots:
                  default:
                    - component: oh-label-card
                      config:
                        action: analyzer
                        actionAnalyzerItems:
                          - null
                        background: rgb(26, 140, 255)
                        fontSize: 34px
                        fontWeight: bold
                        icon: f7:bag_badge_plus
                        item: PiHole_Stats_V6_PiHole_Cached
                        outline: true
                        title: Queries Cached
              - component: oh-grid-col
                config:
                  width: "100"
                  small: "25"
                slots:
                  default:
                    - component: oh-label-card
                      config:
                        action: analyzer
                        actionAnalyzerItems:
                          - null
                        background: orange
                        fontSize: 34px
                        fontWeight: bold
                        icon: f7:checkmark_alt
                        item: PiHole_Stats_V6_PiHole_Unique_Domains
                        outline: true
                        title: Unique Domains
              - component: oh-grid-col
                config:
                  width: "100"
                  small: "25"
                slots:
                  default:
                    - component: oh-label-card
                      config:
                        action: toggle
                        actionCommand: ON
                        actionCommandAlt: OFF
                        background: "=(items.PiHole_Stats_V6_PiHole_Blocking_Status.displayState ===
                          'ON') ? 'green' : 'red'"
                        fontSize: 34px
                        fontWeight: bold
                        icon: "=(items.PiHole_Stats_V6_PiHole_Blocking_Status.displayState === 'ON') ?
                          'f7:lock' : 'f7:lock_open'"
                        item: PiHole_Stats_V6_PiHole_Blocking_Status
                        outline: true
                        title: PiHole Status
  - component: oh-block
    config:
      title: PiHole - Atualizações
    slots:
      default:
        - component: oh-grid-row
          config: {}
          slots:
            default:
              - component: oh-grid-col
                config:
                  small: "33"
                  width: "100"
                slots:
                  default:
                    - component: oh-label-card
                      config:
                        actionAnalyzerItems:
                          - null
                        background: rgba(179, 240, 255, 0.2)
                        fontSize: 34px
                        fontWeight: bold
                        icon: "=(items.PiHole_Stats_V6_PiHole_Core_Update.state === 'OFF') ?
                          'f7:hand_thumbsup' : 'f7:hand_thumbsdown'"
                        iconColor: "=(items.PiHole_Stats_V6_PiHole_Core_Update.state === 'ON') ? 'red' :
                          'green'"
                        item: PiHole_Stats_V6_PiHole_Core_Update
                        outline: true
                        title: Core Update
              - component: oh-grid-col
                config:
                  small: "33"
                  width: "100"
                slots:
                  default:
                    - component: oh-label-card
                      config:
                        actionAnalyzerItems:
                          - null
                        background: rgba(179, 240, 255, 0.2)
                        fontSize: 34px
                        fontWeight: bold
                        icon: "=(items.PiHole_Stats_V6_PiHole_WEB_Update.state === 'OFF') ?
                          'f7:hand_thumbsup' : 'f7:hand_thumbsdown'"
                        iconColor: "=(items.PiHole_Stats_V6_PiHole_WEB_Update.state === 'ON') ? 'red' :
                          'green'"
                        item: PiHole_Stats_V6_PiHole_WEB_Update
                        outline: true
                        title: WEB Update
              - component: oh-grid-col
                config:
                  small: "33"
                  width: "100"
                slots:
                  default:
                    - component: oh-label-card
                      config:
                        actionAnalyzerItems:
                          - null
                        background: rgba(179, 240, 255, 0.2)
                        fontSize: 34px
                        fontWeight: bold
                        icon: "=(items.PiHole_Stats_V6_PiHole_FTL_Update.state === 'OFF') ?
                          'f7:hand_thumbsup' : 'f7:hand_thumbsdown'"
                        iconColor: "=(items.PiHole_Stats_V6_PiHole_FTL_Update.state === 'ON') ? 'red' :
                          'green'"
                        item: PiHole_Stats_V6_PiHole_FTL_Update
                        outline: true
                        title: FTL Update
masonry: []
grid: []
canvas: []

Script new version

#!/bin/bash
#
# Version 1.1 - 2025-03-03
#
# fixed authentication error when SID is no longer valid
#
# Dependencies
#
# - curl
# - jq
# - mosquitto-clients
#
Pi_OH_Stats_DIR="<YOUR-DIR>"
#
PiHoleServer="<YOUR-PIHOLE-SERVER-ADDRESS>"
PiHoleAccess="https://"
#
PiHoleUser=""
PiHolePassword="<YOUR-PIHOLE-PASSWORD>"
#
MQTTHost="<MQTT-HOST-IP>"
MQTTUser="<MQTT-USER>"
MQTTPassword="<MQTT-PASSWORD>"
MQTTTopic="PiHoleStats"
MQTTPubFile="$Pi_OH_Stats_DIR/MQTT_PUB"
#
#
PiHoleSID=""
#
PiHoleAPIStatus=""
#
PiHoleAuthStatus=""
#
BLOCKING_STATUS=""
#
Stats_Summary=""
#
SID_FILE="$Pi_OH_Stats_DIR/SID_FILE"
#
SID_AUTH=""
#
SID_OK=false
#
#
CURL_Q1="curl -s -k --request POST -d '{\"password\":\"$PiHolePassword\"}' $PiHoleAccess$PiHoleServer/api/auth | jq -r '.session.sid'"
#
CURL_Q2=""
#
CURL_Q3=""
#
#
function testSIDAuth() {
    CURL_Q2="curl -skX GET \"$PiHoleAccess$PiHoleServer/api/dns/blocking\" -H \"accept: application/json\" -H \"sid: $SID_AUTH\" | jq -r '.blocking'"
    BLOCKING_STATUS=$(eval "$CURL_Q2");
}


function tryToLogin() {
    SID_AUTH=$(eval "$CURL_Q1");
    if [[ $SID_AUTH =~ "null" ]]; then
    echo -e "\nAuthentication failed!"
        SID_OK=false
    else
    echo -e "\nAuthentication OK"
        echo $SID_AUTH > $SID_FILE
    SID_OK=true
    fi
}

function testSIDFile() {
    if [ -f $SID_FILE ]; then
    SID_AUTH=$(cat $SID_FILE)
    SID_OK=true
    else
#
# SID AUTH file does not exist. Try to authenticate
#
    tryToLogin
        if [ $SID_OK == false ]; then
	echo "Login failed"
	    exit 1
    fi
    fi
}


function parseStatsSummary() {
    Total_Queries=$(echo $Stats_Summary | jq -r '.queries.total')
    Total_Blocked=$(echo $Stats_Summary | jq -r '.queries.blocked')
    Percent_Blocked=$(echo $Stats_Summary | jq -r '.queries.percent_blocked')

    Unique_Domains=$(echo $Stats_Summary | jq -r '.queries.unique_domains')
    Forwarded=$(echo $Stats_Summary | jq -r '.queries.forwarded')
    Cached=$(echo $Stats_Summary | jq -r '.queries.cached')

    Clients_Active=$(echo $Stats_Summary | jq -r '.clients.active')
    Clients_Total=$(echo $Stats_Summary | jq -r '.clients.total')

    Gravity_Domains_Being_Blocked=$(echo $Stats_Summary | jq -r '.gravity.domains_being_blocked')
    Gravity_Last_Update_TS=$(echo $Stats_Summary | jq -r '.gravity.last_update')

    tsNow=$(date +%s)
    diffTS=$(expr $tsNow - $Gravity_Last_Update_TS)

    Gravity_Last_Update_Days=$(expr $diffTS / 86400)

}


function parseInfoVersion() {

    Core_Version=$(echo $Info_Version | jq -r '.version.core.local.version')
    WEB_Version=$(echo $Info_Version | jq -r '.version.web.local.version')
    FTL_Version=$(echo $Info_Version | jq -r '.version.ftl.local.version')


    CoreLocalHash=$(echo $Info_Version | jq -r '.version.core.local.hash')
    WEBLocalHash=$(echo $Info_Version | jq -r '.version.web.local.hash')
    FTLLocalHash=$(echo $Info_Version | jq -r '.version.ftl.local.hash')

    CoreRemoteHash=$(echo $Info_Version | jq -r '.version.core.remote.hash')
    WEBRemoteHash=$(echo $Info_Version | jq -r '.version.web.remote.hash')
    FTLRemoteHash=$(echo $Info_Version | jq -r '.version.ftl.remote.hash')

    if [ $CoreLocalHash == $CoreRemoteHash ]; then
    Core_Update="OFF"
    else
    Core_Update="ON"
    fi

    if [ $WEBLocalHash == $WEBRemoteHash ]; then
        WEB_Update="OFF"
    else
    WEB_Update="ON"
    fi

    if [ $FTLLocalHash == $FTLRemoteHash ]; then
        FTL_Update="OFF"
    else
    FTL_Update="ON"
    fi
}

function initResults() {

    MQTT_PUB=""

    BLOCKING_STATUS="N/A"

    Total_Queries=0
    Total_Blocked=0
    Percent_Blocked=0

    Unique_Domains=0
    Forwarded=0
    Cached=0

    Clients_Active=0
    Clients_Total=0
    Gravity_Domains_Being_Blocked=0
    Gravity_Last_Update_TS=0

    Gravity_Last_Update_Days=0

    Core_Version="N/A"
    WEB_Version="N/A"
    FTL_Version="N/A"

    Core_Update="OFF"
    WEB_Update="OFF"
    FTL_Update="OFF"
}

function showResults() {

    echo $BLOCKING_STATUS

    echo $Total_Queries
    echo $Total_Blocked
    echo $Percent_Blocked

    echo $Unique_Domains
    echo $Forwarded
    echo $Cached

    echo $Clients_Active
    echo $Clients_Total
    echo $Gravity_Domains_Being_Blocked
    echo $Gravity_Last_Update_TS

    echo $Gravity_Last_Update_Days

    echo $Core_Update
    echo $WEB_Update
    echo $FTL_Update

}

function getStatsSummary() {
    CURL_Q3="curl -skX GET \"$PiHoleAccess$PiHoleServer/api/stats/summary\" -H \"accept: application/json\" -H \"sid: $SID_AUTH\""
    Stats_Summary=$(eval "$CURL_Q3");
}


function getInfoVersion() {
    CURL_Q4="curl -skX GET \"$PiHoleAccess$PiHoleServer/api/info/version\" -H \"accept: application/json\" -H \"sid: $SID_AUTH\""
    Info_Version=$(eval "$CURL_Q4");
}


function createMQTTPub() {
MQTT_PUB="{\"blocking_status\":$BLOCKING_STATUS,\"total_queries\":$Total_Queries,\
\"total_blocked\":$Total_Blocked,\"percent_blocked\":$Percent_Blocked,\
\"unique_domains\":$Unique_Domains,\"forwarded\":$Forwarded,\"cached\":$Cached,\
\"clients_active\":$Clients_Active,\"clients_total\":$Clients_Total,\
\"gravity_domains_being_blocked\":$Gravity_Domains_Being_Blocked,\
\"gravity_last_update_ts\":$Gravity_Last_Update_TS,\"gravity_last_update_days\":$Gravity_Last_Update_Days,\
\"core_update\":$Core_Update,\"web_update\":$WEB_Update,\"ftl_update\":$FTL_Update}"

echo $MQTT_PUB > $MQTTPubFile
}

#
    initResults
#
#
    testSIDFile
#
    testSIDAuth
#
#
# If testSIDAuth can not use current SID_AUTH try to authenticate and get a newer SID_AUTH
#
    if [[ $BLOCKING_STATUS =~ "null" ]]; then
        tryToLogin
        if [ $SID_OK == false ]; then
    	echo "Login failed"
	    exit 1
        else
	testSIDAuth
        fi
    fi
#
    getStatsSummary
#
    getInfoVersion
#
    parseStatsSummary
#
    parseInfoVersion
#
#    showResults
#
    createMQTTPub
#
    MQTTCmd="mosquitto_pub -h $MQTTHost -t $MQTTTopic -u $MQTTUser -P $MQTTPassword -f $MQTTPubFile"
    $(eval "$MQTTCmd");
#
    exit 0
#

Script Version 1.2

#!/bin/bash
#
# Version 1.1 - 2025-03-03
#
# fixed authentication error when SID is no longer valid
#
# Version 1.2 - 2025-03-04
#
# test GitHub hash version return. Sometimes returns empty value.
#
# Dependencies
#
# - curl
# - jq
# - mosquitto-clients
#
Pi_OH_Stats_DIR="<YOUR-DIR>"
#
PiHoleServer="<YOUR-PIHOLE-SERVER-ADDRESS>"
PiHoleAccess="https://"
#
PiHoleUser=""
PiHolePassword="<YOUR-PIHOLE-PASSWORD>"
#
MQTTHost="<MQTT-HOST-IP>"
MQTTUser="<MQTT-USER>"
MQTTPassword="<MQTT-PASSWORD>"
MQTTTopic="PiHoleStats"
MQTTPubFile="$Pi_OH_Stats_DIR/MQTT_PUB"
#
#
PiHoleSID=""
#
PiHoleAPIStatus=""
#
PiHoleAuthStatus=""
#
BLOCKING_STATUS=""
#
Stats_Summary=""
#
SID_FILE="$Pi_OH_Stats_DIR/SID_FILE"
#
SID_AUTH=""
#
SID_OK=false
#
#
CURL_Q1="curl -s -k --request POST -d '{\"password\":\"$PiHolePassword\"}' $PiHoleAccess$PiHoleServer/api/auth | jq -r '.session.sid'"
#
CURL_Q2=""
#
CURL_Q3=""
#
#
function testSIDAuth() {
    CURL_Q2="curl -skX GET \"$PiHoleAccess$PiHoleServer/api/dns/blocking\" -H \"accept: application/json\" -H \"sid: $SID_AUTH\" | jq -r '.blocking'"
    BLOCKING_STATUS=$(eval "$CURL_Q2");
}


function tryToLogin() {
    SID_AUTH=$(eval "$CURL_Q1");
    if [[ $SID_AUTH =~ "null" ]]; then
    echo -e "\nAuthentication failed!"
        SID_OK=false
    else
    echo -e "\nAuthentication OK"
        echo $SID_AUTH > $SID_FILE
    SID_OK=true
    fi
}

function testSIDFile() {
    if [ -f $SID_FILE ]; then
    SID_AUTH=$(cat $SID_FILE)
    SID_OK=true
    else
#
# SID AUTH file does not exist. Try to authenticate
#
    tryToLogin
        if [ $SID_OK == false ]; then
	echo "Login failed"
	    exit 1
    fi
    fi
}


function parseStatsSummary() {
    Total_Queries=$(echo $Stats_Summary | jq -r '.queries.total')
    Total_Blocked=$(echo $Stats_Summary | jq -r '.queries.blocked')
    Percent_Blocked=$(echo $Stats_Summary | jq -r '.queries.percent_blocked')

    Unique_Domains=$(echo $Stats_Summary | jq -r '.queries.unique_domains')
    Forwarded=$(echo $Stats_Summary | jq -r '.queries.forwarded')
    Cached=$(echo $Stats_Summary | jq -r '.queries.cached')

    Clients_Active=$(echo $Stats_Summary | jq -r '.clients.active')
    Clients_Total=$(echo $Stats_Summary | jq -r '.clients.total')

    Gravity_Domains_Being_Blocked=$(echo $Stats_Summary | jq -r '.gravity.domains_being_blocked')
    Gravity_Last_Update_TS=$(echo $Stats_Summary | jq -r '.gravity.last_update')

    tsNow=$(date +%s)
    diffTS=$(expr $tsNow - $Gravity_Last_Update_TS)

    Gravity_Last_Update_Days=$(expr $diffTS / 86400)

}


function parseInfoVersion() {

    Core_Version=$(echo $Info_Version | jq -r '.version.core.local.version')
    WEB_Version=$(echo $Info_Version | jq -r '.version.web.local.version')
    FTL_Version=$(echo $Info_Version | jq -r '.version.ftl.local.version')

    CoreLocalHash=$(echo $Info_Version | jq -r '.version.core.local.hash')
    WEBLocalHash=$(echo $Info_Version | jq -r '.version.web.local.hash')
    FTLLocalHash=$(echo $Info_Version | jq -r '.version.ftl.local.hash')

    CoreRemoteHash=$(echo $Info_Version | jq -r '.version.core.remote.hash')
    WEBRemoteHash=$(echo $Info_Version | jq -r '.version.web.remote.hash')
    FTLRemoteHash=$(echo $Info_Version | jq -r '.version.ftl.remote.hash')

    if [[ -z "$CoreRemoteHash" || -z "$WEBRemoteHash" || -z "$FTLRemoteHash" ]]; then
	Core_Update="OFF"
	WEB_Update="OFF"
	FTL_Update="OFF"
	return
    fi

    if [ $CoreLocalHash == $CoreRemoteHash ]; then
        Core_Update="OFF"
    else
	Core_Update="ON"
    fi

    if [ $WEBLocalHash == $WEBRemoteHash ]; then
        WEB_Update="OFF"
    else
        WEB_Update="ON"
    fi

    if [ $FTLLocalHash == $FTLRemoteHash ]; then
        FTL_Update="OFF"
    else
    FTL_Update="ON"
    fi
}

function initResults() {

    MQTT_PUB=""

    BLOCKING_STATUS="N/A"

    Total_Queries=0
    Total_Blocked=0
    Percent_Blocked=0

    Unique_Domains=0
    Forwarded=0
    Cached=0

    Clients_Active=0
    Clients_Total=0
    Gravity_Domains_Being_Blocked=0
    Gravity_Last_Update_TS=0

    Gravity_Last_Update_Days=0

    Core_Version="N/A"
    WEB_Version="N/A"
    FTL_Version="N/A"

    Core_Update="OFF"
    WEB_Update="OFF"
    FTL_Update="OFF"
}

function showResults() {

    echo $BLOCKING_STATUS

    echo $Total_Queries
    echo $Total_Blocked
    echo $Percent_Blocked

    echo $Unique_Domains
    echo $Forwarded
    echo $Cached

    echo $Clients_Active
    echo $Clients_Total
    echo $Gravity_Domains_Being_Blocked
    echo $Gravity_Last_Update_TS

    echo $Gravity_Last_Update_Days

    echo $Core_Update
    echo $WEB_Update
    echo $FTL_Update

}

function getStatsSummary() {
    CURL_Q3="curl -skX GET \"$PiHoleAccess$PiHoleServer/api/stats/summary\" -H \"accept: application/json\" -H \"sid: $SID_AUTH\""
    Stats_Summary=$(eval "$CURL_Q3");
}


function getInfoVersion() {
    CURL_Q4="curl -skX GET \"$PiHoleAccess$PiHoleServer/api/info/version\" -H \"accept: application/json\" -H \"sid: $SID_AUTH\""
    Info_Version=$(eval "$CURL_Q4");
}


function createMQTTPub() {
MQTT_PUB="{\"blocking_status\":$BLOCKING_STATUS,\"total_queries\":$Total_Queries,\
\"total_blocked\":$Total_Blocked,\"percent_blocked\":$Percent_Blocked,\
\"unique_domains\":$Unique_Domains,\"forwarded\":$Forwarded,\"cached\":$Cached,\
\"clients_active\":$Clients_Active,\"clients_total\":$Clients_Total,\
\"gravity_domains_being_blocked\":$Gravity_Domains_Being_Blocked,\
\"gravity_last_update_ts\":$Gravity_Last_Update_TS,\"gravity_last_update_days\":$Gravity_Last_Update_Days,\
\"core_update\":$Core_Update,\"web_update\":$WEB_Update,\"ftl_update\":$FTL_Update}"

echo $MQTT_PUB > $MQTTPubFile
}

#
    initResults
#
#
    testSIDFile
#
    testSIDAuth
#
#
# If testSIDAuth can not use current SID_AUTH try to authenticate and get a newer SID_AUTH
#
    if [[ $BLOCKING_STATUS =~ "null" ]]; then
        tryToLogin
        if [ $SID_OK == false ]; then
    	echo "Login failed"
	    exit 1
        else
	testSIDAuth
        fi
    fi
#
    getStatsSummary
#
    getInfoVersion
#
    parseStatsSummary
#
    parseInfoVersion
#
#    showResults
#
    createMQTTPub
#
    MQTTCmd="mosquitto_pub -h $MQTTHost -t $MQTTTopic -u $MQTTUser -P $MQTTPassword -f $MQTTPubFile"
    $(eval "$MQTTCmd");
#
    exit 0
#

2 Likes

Hello that seams to be a nice integration. How to execute the script. As a crown job?
Where is the best place to store it.

Hi @arohleder !

Thanks for getting in touch.

I use crontab configured for every minute and run the script on the machine where PiHole is installed.

Thanks for your work!
but there is a Problem:

Job ID: jm8ncqsmu05

Event Title: PiHole

Hostname: cronicle

Date/Time: 2025/03/24 17:39:56 (GMT+0)

/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 63: jq: command not found
Authentication OK
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 58: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 92: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 93: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 94: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 96: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 97: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 98: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 100: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 101: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 103: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 104: jq: command not found
expr: syntax error
expr: syntax error
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 116: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 117: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 118: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 120: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 121: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 122: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 124: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 125: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 126: jq: command not found
/tmp/cronicle-script-temp-jm8ncqsmu05.sh: line 267: mosquitto_pub: command not found

Job completed successfully at 2025/03/24 17:39:57 (GMT+0).

End of log.

Hi!

You need to install jq as this is a dependency package.

Dependencies

- curl

- jq

- mosquitto-clients

In a Debian like system, just run:

sudo apt-get install jq

Regards.