[pihole] Add channels for gravity (#17413)

* Add channels for gravity

Signed-off-by: Martin Grześlowski <martin.grzeslowski@gmail.com>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Martin 2024-09-15 13:55:31 +02:00 committed by Ciprian Pascu
parent 01c0a2f8df
commit 48f5995df4
6 changed files with 90 additions and 62 deletions

View File

@ -28,36 +28,38 @@ The Pi-hole Binding allows you to monitor Pi-hole statistics and control its fun
## Channels
| Channel | Type | Read/Write | Description |
|-------------------------|--------|------------|------------------------------------------------------------|
| domains-being-blocked | Number | RO | The total number of domains currently being blocked. |
| dns-queries-today | Number | RO | The count of DNS queries made today. |
| ads-blocked-today | Number | RO | The number of ads blocked today. |
| ads-percentage-today | Number | RO | The percentage of ads blocked today. |
| unique-domains | Number | RO | The count of unique domains queried. |
| queries-forwarded | Number | RO | The number of queries forwarded to an external DNS server. |
| queries-cached | Number | RO | The number of queries served from the cache. |
| clients-ever-seen | Number | RO | The total number of unique clients ever seen. |
| unique-clients | Number | RO | The current count of unique clients. |
| dns-queries-all-types | Number | RO | The total number of DNS queries of all types. |
| reply-unknown | Number | RO | DNS replies with an unknown status. |
| reply-nodata | Number | RO | DNS replies indicating no data. |
| reply-nxdomain | Number | RO | DNS replies indicating non-existent domain. |
| reply-cname | Number | RO | DNS replies with a CNAME record. |
| reply-ip | Number | RO | DNS replies with an IP address. |
| reply-domain | Number | RO | DNS replies with a domain name. |
| reply-rrname | Number | RO | DNS replies with a resource record name. |
| reply-servfail | Number | RO | DNS replies indicating a server failure. |
| reply-refused | Number | RO | DNS replies indicating refusal. |
| reply-notimp | Number | RO | DNS replies indicating not implemented. |
| reply-other | Number | RO | DNS replies with other statuses. |
| reply-dnssec | Number | RO | DNS replies with DNSSEC information. |
| reply-none | Number | RO | DNS replies with no data. |
| reply-blob | Number | RO | DNS replies with a BLOB (binary large object). |
| dns-queries-all-replies | Number | RO | The total number of DNS queries with all reply types. |
| privacy-level | Number | RO | The privacy level setting. |
| enabled | Switch | RO | The current status of blocking |
| disable-enable | String | RW | Is blocking enabled/disabled |
| Channel | Type | Read/Write | Description |
|-------------------------|----------|------------|------------------------------------------------------------|
| domains-being-blocked | Number | RO | The total number of domains currently being blocked. |
| dns-queries-today | Number | RO | The count of DNS queries made today. |
| ads-blocked-today | Number | RO | The number of ads blocked today. |
| ads-percentage-today | Number | RO | The percentage of ads blocked today. |
| unique-domains | Number | RO | The count of unique domains queried. |
| queries-forwarded | Number | RO | The number of queries forwarded to an external DNS server. |
| queries-cached | Number | RO | The number of queries served from the cache. |
| clients-ever-seen | Number | RO | The total number of unique clients ever seen. |
| unique-clients | Number | RO | The current count of unique clients. |
| dns-queries-all-types | Number | RO | The total number of DNS queries of all types. |
| reply-unknown | Number | RO | DNS replies with an unknown status. |
| reply-nodata | Number | RO | DNS replies indicating no data. |
| reply-nxdomain | Number | RO | DNS replies indicating non-existent domain. |
| reply-cname | Number | RO | DNS replies with a CNAME record. |
| reply-ip | Number | RO | DNS replies with an IP address. |
| reply-domain | Number | RO | DNS replies with a domain name. |
| reply-rrname | Number | RO | DNS replies with a resource record name. |
| reply-servfail | Number | RO | DNS replies indicating a server failure. |
| reply-refused | Number | RO | DNS replies indicating refusal. |
| reply-notimp | Number | RO | DNS replies indicating not implemented. |
| reply-other | Number | RO | DNS replies with other statuses. |
| reply-dnssec | Number | RO | DNS replies with DNSSEC information. |
| reply-none | Number | RO | DNS replies with no data. |
| reply-blob | Number | RO | DNS replies with a BLOB (binary large object). |
| dns-queries-all-replies | Number | RO | The total number of DNS queries with all reply types. |
| privacy-level | Number | RO | The privacy level setting. |
| enabled | Switch | RO | The current status of blocking |
| disable-enable | String | RW | Is blocking enabled/disabled |
| gravity-last-update | DateTime | RO | Last update of gravity |
| gravity-file-exists | DateTime | RO | Does gravity file exists |
## Full Example

View File

@ -58,6 +58,8 @@ public class PiHoleBindingConstants {
public static final String PRIVACY_LEVEL_CHANNEL = "privacy-level";
public static final String ENABLED_CHANNEL = "enabled";
public static final String DISABLE_ENABLE_CHANNEL = "disable-enable";
public static final String GRAVITY_FILE_EXISTS = "gravity-file-exists";
public static final String GRAVITY_LAST_UPDATE = "gravity-last-update";
public static enum DisableEnable {
DISABLE,

View File

@ -13,36 +13,8 @@
package org.openhab.binding.pihole.internal;
import static java.util.concurrent.TimeUnit.*;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.ADS_BLOCKED_TODAY_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.ADS_PERCENTAGE_TODAY_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.CLIENTS_EVER_SEEN_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.DISABLE_ENABLE_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.DNS_QUERIES_ALL_REPLIES_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.DNS_QUERIES_ALL_TYPES_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.DNS_QUERIES_TODAY_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.DOMAINS_BEING_BLOCKED_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.DisableEnable;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.*;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.DisableEnable.ENABLE;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.ENABLED_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.PRIVACY_LEVEL_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.QUERIES_CACHED_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.QUERIES_FORWARDED_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_BLOB_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_CNAME_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_DNSSEC_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_DOMAIN_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_IP_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_NODATA_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_NONE_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_NOTIMP_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_NXDOMAIN_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_OTHER_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_REFUSED_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_RRNAME_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_SERVFAIL_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.REPLY_UNKNOWN_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.UNIQUE_CLIENTS_CHANNEL;
import static org.openhab.binding.pihole.internal.PiHoleBindingConstants.Channels.UNIQUE_DOMAINS_CHANNEL;
import static org.openhab.core.library.unit.Units.PERCENT;
import static org.openhab.core.thing.ThingStatus.OFFLINE;
import static org.openhab.core.thing.ThingStatus.ONLINE;
@ -52,6 +24,7 @@ import static org.openhab.core.thing.ThingStatusDetail.*;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Instant;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
@ -63,6 +36,8 @@ import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.pihole.internal.rest.AdminService;
import org.openhab.binding.pihole.internal.rest.JettyAdminService;
import org.openhab.binding.pihole.internal.rest.model.DnsStatistics;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
@ -87,14 +62,16 @@ public class PiHoleHandler extends BaseThingHandler implements AdminService {
private static final int HTTP_DELAY_SECONDS = 1;
private final Logger logger = LoggerFactory.getLogger(PiHoleHandler.class);
private final Object lock = new Object();
private final TimeZoneProvider timeZoneProvider;
private final HttpClient httpClient;
private @Nullable AdminService adminService;
private @Nullable DnsStatistics dnsStatistics;
private @Nullable ScheduledFuture<?> scheduledFuture;
public PiHoleHandler(Thing thing, HttpClient httpClient) {
public PiHoleHandler(Thing thing, TimeZoneProvider timeZoneProvider, HttpClient httpClient) {
super(thing);
this.timeZoneProvider = timeZoneProvider;
this.httpClient = httpClient;
}
@ -218,6 +195,19 @@ public class PiHoleHandler extends BaseThingHandler implements AdminService {
if (localDnsStatistics.enabled()) {
updateState(DISABLE_ENABLE_CHANNEL, new StringType(ENABLE.toString()));
}
var gravityLastUpdated = localDnsStatistics.gravityLastUpdated();
if (gravityLastUpdated != null) {
var absolute = gravityLastUpdated.absolute();
if (absolute != null) {
var instant = Instant.ofEpochSecond(absolute);
var zonedDateTime = instant.atZone(timeZoneProvider.getTimeZone());
updateState(GRAVITY_LAST_UPDATE, new DateTimeType(zonedDateTime));
}
var fileExists = gravityLastUpdated.fileExists();
if (fileExists != null) {
updateState(GRAVITY_FILE_EXISTS, OnOffType.from(fileExists));
}
}
}
private void updateDecimalState(String channelID, @Nullable Integer value) {

View File

@ -18,6 +18,7 @@ import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
@ -39,10 +40,13 @@ import org.osgi.service.component.annotations.Reference;
public class PiHoleHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(PI_HOLE_TYPE);
private final TimeZoneProvider timeZoneProvider;
private final HttpClientFactory httpClientFactory;
@Activate
public PiHoleHandlerFactory(@Reference HttpClientFactory httpClientFactory) {
public PiHoleHandlerFactory(@Reference TimeZoneProvider timeZoneProvider,
@Reference HttpClientFactory httpClientFactory) {
this.timeZoneProvider = timeZoneProvider;
this.httpClientFactory = httpClientFactory;
}
@ -56,7 +60,7 @@ public class PiHoleHandlerFactory extends BaseThingHandlerFactory {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (PI_HOLE_TYPE.equals(thingTypeUID)) {
return new PiHoleHandler(thing, httpClientFactory.getCommonHttpClient());
return new PiHoleHandler(thing, timeZoneProvider, httpClientFactory.getCommonHttpClient());
}
return null;

View File

@ -116,6 +116,9 @@
<channel id="enabled" typeId="enabled-channel"/>
<channel id="disable-enable" typeId="disable-enable-channel"/>
</channels>
<properties>
<property name="thingTypeVersion">1</property>
</properties>
<config-description>
<parameter name="hostname" type="text" required="true">
@ -161,4 +164,15 @@
</options>
</command>
</channel-type>
<channel-type id="gravity-file-exists-channel">
<item-type>Switch</item-type>
<label>Gravity File Exists</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="gravity-last-update-channel">
<item-type>DateTime</item-type>
<label>Gravity Last Update</label>
<category>time</category>
<state readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
<thing-type uid="pihole:server">
<instruction-set targetVersion="1">
<add-channel id="gravity-file-exists">
<type>pihole:gravity-file-exists-channel</type>
</add-channel>
<add-channel id="gravity-last-update">
<type>pihole:gravity-last-update-channel</type>
</add-channel>
</instruction-set>
</thing-type>
</update:update-descriptions>