[speedtest] Add timestamp and result image channel, update thing description (#15278)

* added timestamp channel, updated thing description
* added resultImage

---------

Signed-off-by: Michael Weger <weger.michael@gmx.net>
This commit is contained in:
MikeTheTux 2023-10-19 22:22:47 +02:00 committed by GitHub
parent b8805ba687
commit c7568cb206
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 185 additions and 48 deletions

View File

@ -76,6 +76,7 @@ Ensure that the user that openHAB is running with, has the permissions to access
| Channel | Type | Description |
|-----------------------|---------------------------|-------------------------------------------------------------------|
| `server` | `String` | The remote server that the Speedtest was run against |
| `timestamp` | `DateTime` | Timestamp of the Speedtest run |
| `pingJitter` | `Number:Time` | Ping Jitter - the variation in the response time |
| `pingLatency` | `Number:Time` | Ping Latency - the reaction time of your internet connection |
| `downloadBandwidth` | `Number:DataTransferRate` | Download bandwidth, e.g. in Mbit/s |
@ -88,6 +89,7 @@ Ensure that the user that openHAB is running with, has the permissions to access
| `interfaceInternalIp` | `String` | IP address of the internal interface that was used for the test |
| `interfaceExternalIp` | `String` | IP address of the external interface that was used for the test |
| `resultUrl` | `String` | The URL to the Speedtest results in HTML on the Ookla webserver |
| `resultImage` | `Image ` | The Speedtest results as image |
| `triggerTest` | `Switch` | Trigger in order to run Speedtest manually |
## Full Example
@ -102,6 +104,7 @@ Thing speedtest:speedtest:myspeedtest "Ookla Speedtest" [ execPath="/usr/
```java
String Speedtest_Server "Server" { channel="speedtest:speedtest:myspeedtest:server" }
DateTime Speedtest_Timestamp "Timestamp" { channel="speedtest:speedtest:myspeedtest:timestamp" }
Number:Time Speedtest_Ping_Jitter "Ping Jitter" { channel="speedtest:speedtest:myspeedtest:pingJitter" }
Number:Time Speedtest_Ping_Latency "Ping Latency" { channel="speedtest:speedtest:myspeedtest:pingLatency" }
Number:DataTransferRate Speedtest_Download_Bandwith "Download Bandwith" { channel="speedtest:speedtest:myspeedtest:downloadBandwidth" }
@ -114,5 +117,6 @@ String Speedtest_ISP "ISP"
String Speedtest_Interface_InternalIP "Internal IP Address" { channel="speedtest:speedtest:myspeedtest:interfaceInternalIp" }
String Speedtest_Interface_ExternalIP "External IP Address" { channel="speedtest:speedtest:myspeedtest:interfaceExternalIp" }
String Speedtest_ResultURL "Result URL" { channel="speedtest:speedtest:myspeedtest:resultUrl" }
Image Speedtest_ResultImage "Result Image" { channel="speedtest:speedtest:myspeedtest:resultImage" }
Switch Speedtest_TriggerTest "Trigger Test" { channel="speedtest:speedtest:myspeedtest:triggerTest" }
```

View File

@ -40,6 +40,7 @@ public class SpeedtestBindingConstants {
// Channels
public static final String SERVER = "server";
public static final String TIMESTAMP = "timestamp";
public static final String PING_JITTER = "pingJitter";
public static final String PING_LATENCY = "pingLatency";
public static final String DOWNLOAD_BANDWIDTH = "downloadBandwidth";
@ -52,6 +53,7 @@ public class SpeedtestBindingConstants {
public static final String INTERFACE_INTERNALIP = "interfaceInternalIp";
public static final String INTERFACE_EXTERNALIP = "interfaceExternalIp";
public static final String RESULT_URL = "resultUrl";
public static final String RESULT_IMAGE = "resultImage";
public static final String TRIGGER_TEST = "triggerTest";
public static final String PROPERTY_SERVER_LIST1 = "Server List 1";
@ -65,7 +67,7 @@ public class SpeedtestBindingConstants {
public static final String PROPERTY_SERVER_LIST9 = "Server List 9";
public static final String PROPERTY_SERVER_LIST10 = "Server List 10";
public static final Set<String> SUPPORTED_CHANNEL_IDS = Set.of(SERVER, PING_JITTER, PING_LATENCY,
public static final Set<String> SUPPORTED_CHANNEL_IDS = Set.of(SERVER, TIMESTAMP, PING_JITTER, PING_LATENCY,
DOWNLOAD_BANDWIDTH, DOWNLOAD_BYTES, DOWNLOAD_ELAPSED, UPLOAD_BANDWIDTH, UPLOAD_BYTES, UPLOAD_ELAPSED, ISP,
INTERFACE_INTERNALIP, INTERFACE_EXTERNALIP, RESULT_URL);
INTERFACE_INTERNALIP, INTERFACE_EXTERNALIP, RESULT_URL, RESULT_IMAGE, TRIGGER_TEST);
}

View File

@ -17,6 +17,8 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
@ -27,8 +29,12 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.speedtest.internal.dto.ResultContainer;
import org.openhab.binding.speedtest.internal.dto.ResultsContainerServerList;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.io.net.http.HttpUtil;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.RawType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.ChannelUID;
@ -39,6 +45,7 @@ import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -58,6 +65,7 @@ public class SpeedtestHandler extends BaseThingHandler {
private static Runtime rt = Runtime.getRuntime();
private long pollingInterval = 60;
private String serverID = "";
private final TimeZoneProvider timeZoneProvider;
private @Nullable ScheduledFuture<?> pollingJob;
public volatile boolean isRunning = false;
@ -69,19 +77,21 @@ public class SpeedtestHandler extends BaseThingHandler {
private static volatile OS os = OS.NOT_SET;
private static final Object LOCK = new Object();
private String pingJitter = "";
private String pingLatency = "";
private String downloadBandwidth = "";
private String downloadBytes = "";
private String downloadElapsed = "";
private String uploadBandwidth = "";
private String uploadBytes = "";
private String uploadElapsed = "";
private State pingJitter = UnDefType.NULL;
private State pingLatency = UnDefType.NULL;
private State downloadBandwidth = UnDefType.NULL;
private State downloadBytes = UnDefType.NULL;
private State downloadElapsed = UnDefType.NULL;
private State uploadBandwidth = UnDefType.NULL;
private State uploadBytes = UnDefType.NULL;
private State uploadElapsed = UnDefType.NULL;
private String isp = "";
private String interfaceInternalIp = "";
private String interfaceExternalIp = "";
private String resultUrl = "";
private State resultImage = UnDefType.NULL;
private String server = "";
private State timestamp = UnDefType.NULL;
/**
* Contains information about which operating system openHAB is running on.
@ -95,8 +105,9 @@ public class SpeedtestHandler extends BaseThingHandler {
NOT_SET
}
public SpeedtestHandler(Thing thing) {
public SpeedtestHandler(Thing thing, TimeZoneProvider timeZoneProvider) {
super(thing);
this.timeZoneProvider = timeZoneProvider;
}
@Override
@ -286,18 +297,85 @@ public class SpeedtestHandler extends BaseThingHandler {
ResultContainer.class);
if (tmpCont != null) {
if ("result".equals(tmpCont.getType())) {
pingJitter = tmpCont.getPing().getJitter();
pingLatency = tmpCont.getPing().getLatency();
downloadBandwidth = tmpCont.getDownload().getBandwidth();
downloadBytes = tmpCont.getDownload().getBytes();
downloadElapsed = tmpCont.getDownload().getElapsed();
uploadBandwidth = tmpCont.getUpload().getBandwidth();
uploadBytes = tmpCont.getUpload().getBytes();
uploadElapsed = tmpCont.getUpload().getElapsed();
try {
// timestamp format: "2023-07-20T19:34:54Z"
ZonedDateTime zonedDateTime = ZonedDateTime.parse(tmpCont.getTimestamp())
.withZoneSameInstant(timeZoneProvider.getTimeZone());
timestamp = new DateTimeType(zonedDateTime);
} catch (DateTimeParseException e) {
timestamp = UnDefType.NULL;
logger.debug("Exception: {}", e.getMessage());
}
try {
pingJitter = new QuantityType<>(Double.parseDouble(tmpCont.getPing().getJitter()) / 1000.0,
Units.SECOND);
} catch (NumberFormatException e) {
pingJitter = UnDefType.NULL;
logger.debug("Exception: {}", e.getMessage());
}
try {
pingLatency = new QuantityType<>(Double.parseDouble(tmpCont.getPing().getLatency()) / 1000.0,
Units.SECOND);
} catch (NumberFormatException e) {
pingLatency = UnDefType.NULL;
logger.debug("Exception: {}", e.getMessage());
}
try {
downloadBandwidth = new QuantityType<>(
Double.parseDouble(tmpCont.getDownload().getBandwidth()) / 125000.0,
Units.MEGABIT_PER_SECOND);
} catch (NumberFormatException e) {
downloadBandwidth = UnDefType.NULL;
logger.debug("Exception: {}", e.getMessage());
}
try {
downloadBytes = new QuantityType<>(Double.parseDouble(tmpCont.getDownload().getBytes()),
Units.BYTE);
} catch (NumberFormatException e) {
downloadBytes = UnDefType.NULL;
logger.debug("Exception: {}", e.getMessage());
}
try {
downloadElapsed = new QuantityType<>(
Double.parseDouble(tmpCont.getDownload().getElapsed()) / 1000.0, Units.SECOND);
} catch (NumberFormatException e) {
downloadElapsed = UnDefType.NULL;
logger.debug("Exception: {}", e.getMessage());
}
try {
uploadBandwidth = new QuantityType<>(
Double.parseDouble(tmpCont.getUpload().getBandwidth()) / 125000.0,
Units.MEGABIT_PER_SECOND);
} catch (NumberFormatException e) {
uploadBandwidth = UnDefType.NULL;
logger.debug("Exception: {}", e.getMessage());
}
try {
uploadBytes = new QuantityType<>(Double.parseDouble(tmpCont.getUpload().getBytes()), Units.BYTE);
} catch (NumberFormatException e) {
uploadBytes = UnDefType.NULL;
logger.debug("Exception: {}", e.getMessage());
}
try {
uploadElapsed = new QuantityType<>(Double.parseDouble(tmpCont.getUpload().getElapsed()) / 1000.0,
Units.SECOND);
} catch (NumberFormatException e) {
uploadElapsed = UnDefType.NULL;
logger.debug("Exception: {}", e.getMessage());
}
isp = tmpCont.getIsp();
interfaceInternalIp = tmpCont.getInterface().getInternalIp();
interfaceExternalIp = tmpCont.getInterface().getExternalIp();
resultUrl = tmpCont.getResult().getUrl();
String url = String.valueOf(resultUrl) + ".png";
logger.debug("Downloading result image from: {}", url);
RawType image = HttpUtil.downloadImage(url);
if (image != null) {
resultImage = image;
} else {
resultImage = UnDefType.NULL;
}
server = tmpCont.getServer().getName() + " (" + tmpCont.getServer().getId().toString() + ") "
+ tmpCont.getServer().getLocation();
updateChannels();
@ -332,45 +410,53 @@ public class SpeedtestHandler extends BaseThingHandler {
private void updateChannels() {
logger.debug("Updating channels");
State newState = new QuantityType<>(Double.parseDouble(pingJitter) / 1000.0, Units.SECOND);
logger.debug("pingJitter: {}", newState);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.PING_JITTER), newState);
logger.debug("timestamp: {}", timestamp);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.TIMESTAMP), timestamp);
newState = new QuantityType<>(Double.parseDouble(pingLatency) / 1000.0, Units.SECOND);
logger.debug("pingLatency: {}", newState);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.PING_LATENCY), newState);
logger.debug("pingJitter: {}", pingJitter);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.PING_JITTER), pingJitter);
newState = new QuantityType<>(Double.parseDouble(downloadBandwidth) / 125000.0, Units.MEGABIT_PER_SECOND);
logger.debug("downloadBandwidth: {}", newState);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.DOWNLOAD_BANDWIDTH), newState);
logger.debug("pingLatency: {}", pingLatency);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.PING_LATENCY), pingLatency);
newState = new QuantityType<>(Double.parseDouble(downloadBytes), Units.BYTE);
logger.debug("downloadBytes: {}", newState);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.DOWNLOAD_BYTES), newState);
logger.debug("downloadBandwidth: {}", downloadBandwidth);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.DOWNLOAD_BANDWIDTH),
downloadBandwidth);
newState = new QuantityType<>(Double.parseDouble(downloadElapsed) / 1000.0, Units.SECOND);
logger.debug("downloadElapsed: {}", newState);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.DOWNLOAD_ELAPSED), newState);
logger.debug("downloadBytes: {}", downloadBytes);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.DOWNLOAD_BYTES), downloadBytes);
newState = new QuantityType<>(Double.parseDouble(uploadBandwidth) / 125000.0, Units.MEGABIT_PER_SECOND);
logger.debug("uploadBandwidth: {}", newState);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.UPLOAD_BANDWIDTH), newState);
logger.debug("downloadElapsed: {}", downloadElapsed);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.DOWNLOAD_ELAPSED), downloadElapsed);
newState = new QuantityType<>(Double.parseDouble(uploadBytes), Units.BYTE);
logger.debug("uploadBytes: {}", newState);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.UPLOAD_BYTES), newState);
logger.debug("uploadBandwidth: {}", uploadBandwidth);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.UPLOAD_BANDWIDTH), uploadBandwidth);
newState = new QuantityType<>(Double.parseDouble(uploadElapsed) / 1000.0, Units.SECOND);
logger.debug("uploadElapsed: {}", newState);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.UPLOAD_ELAPSED), newState);
logger.debug("uploadBytes: {}", uploadBytes);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.UPLOAD_BYTES), uploadBytes);
logger.debug("uploadElapsed: {}", uploadElapsed);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.UPLOAD_ELAPSED), uploadElapsed);
logger.debug("interfaceExternalIp: {}", interfaceExternalIp);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.INTERFACE_EXTERNALIP),
new StringType(interfaceExternalIp));
logger.debug("interfaceInternalIp: {}", interfaceInternalIp);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.INTERFACE_INTERNALIP),
new StringType(interfaceInternalIp));
logger.debug("isp: {}", isp);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.ISP), new StringType(isp));
logger.debug("resultUrl: {}", resultUrl);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.RESULT_URL),
new StringType(resultUrl));
logger.debug("resultImage: <RawType>");
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.RESULT_IMAGE), resultImage);
logger.debug("server: {}", server);
updateState(new ChannelUID(getThing().getUID(), SpeedtestBindingConstants.SERVER), new StringType(server));
}

View File

@ -19,12 +19,15 @@ 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.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The {@link SpeedtestHandlerFactory} is responsible for creating things and thing
@ -37,6 +40,12 @@ import org.osgi.service.component.annotations.Component;
public class SpeedtestHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_SPEEDTEST);
private final TimeZoneProvider timeZoneProvider;
@Activate
public SpeedtestHandlerFactory(final @Reference TimeZoneProvider timeZoneProvider) {
this.timeZoneProvider = timeZoneProvider;
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
@ -48,7 +57,7 @@ public class SpeedtestHandlerFactory extends BaseThingHandlerFactory {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (THING_TYPE_SPEEDTEST.equals(thingTypeUID)) {
return new SpeedtestHandler(thing);
return new SpeedtestHandler(thing, timeZoneProvider);
}
return null;

View File

@ -5,8 +5,8 @@ addon.speedtest.description = Binding for Ookla Speedtest (https://www.speedtest
# thing types
thing-type.speedtest.speedtest.label = Speedtest Binding
thing-type.speedtest.speedtest.description = Binding for Ookla Speedtest (https://www.speedtest.net/)
thing-type.speedtest.speedtest.label = Ookla Speedtest
thing-type.speedtest.speedtest.description = Ookla Speedtest (https://www.speedtest.net/)
# thing types config
@ -43,10 +43,14 @@ channel-type.speedtest.pingJitter.label = Ping Jitter
channel-type.speedtest.pingJitter.description = Ping Jitter - the variation in the response time
channel-type.speedtest.pingLatency.label = Ping Latency
channel-type.speedtest.pingLatency.description = Ping Latency - the reaction time of your internet connection
channel-type.speedtest.resultImage.label = Result Image
channel-type.speedtest.resultImage.description = The Speedtest results as image
channel-type.speedtest.resultUrl.label = Result URL
channel-type.speedtest.resultUrl.description = The URL to the Speedtest results in HTML on the Ookla webserver
channel-type.speedtest.server.label = Server
channel-type.speedtest.server.description = The remote server that the Speedtest was run against
channel-type.speedtest.timestamp.label = Timestamp
channel-type.speedtest.timestamp.description = Timestamp of the Speedtest run
channel-type.speedtest.triggerTest.label = Trigger Test
channel-type.speedtest.triggerTest.description = Trigger in order to run Speedtest manually
channel-type.speedtest.uploadBandwidth.label = Upload Bandwidth

View File

@ -5,10 +5,11 @@
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="speedtest">
<label>Speedtest Binding</label>
<description>Binding for Ookla Speedtest (https://www.speedtest.net/)</description>
<label>Ookla Speedtest</label>
<description>Ookla Speedtest (https://www.speedtest.net/)</description>
<channels>
<channel id="server" typeId="server"/>
<channel id="timestamp" typeId="timestamp"/>
<channel id="pingJitter" typeId="pingJitter"/>
<channel id="pingLatency" typeId="pingLatency"/>
@ -27,6 +28,7 @@
<channel id="interfaceExternalIp" typeId="interfaceExternalIp"/>
<channel id="resultUrl" typeId="resultUrl"/>
<channel id="resultImage" typeId="resultImage"/>
<channel id="triggerTest" typeId="triggerTest"/>
</channels>
@ -41,6 +43,7 @@
<property name="Server List 8"></property>
<property name="Server List 9"></property>
<property name="Server List 10"></property>
<property name="thingTypeVersion">1</property>
</properties>
<config-description>
<parameter-group name="config-info">
@ -78,6 +81,12 @@
<description>The remote server that the Speedtest was run against</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="timestamp" advanced="true">
<item-type>DateTime</item-type>
<label>Timestamp</label>
<description>Timestamp of the Speedtest run</description>
<state readOnly="true" pattern="%1$tF %1$tH:%1$tM:%1$tS"></state>
</channel-type>
<channel-type id="pingJitter" advanced="true">
<item-type>Number:Time</item-type>
<label>Ping Jitter</label>
@ -150,6 +159,12 @@
<description>The URL to the Speedtest results in HTML on the Ookla webserver</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="resultImage">
<item-type>Image</item-type>
<label>Result Image</label>
<description>The Speedtest results as image</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="triggerTest" advanced="true">
<item-type>Switch</item-type>
<label>Trigger Test</label>

View File

@ -0,0 +1,17 @@
<?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="speedtest:speedtest">
<instruction-set targetVersion="1">
<add-channel id="timestamp">
<type>speedtest:timestamp</type>
</add-channel>
<add-channel id="resultImage">
<type>speedtest:resultImage</type>
</add-channel>
</instruction-set>
</thing-type>
</update:update-descriptions>