Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions bundles/org.openhab.binding.network/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The binding has the following configuration options:
- **arpPingToolPath:** If the ARP ping tool is not called `arping` and cannot be found in the PATH environment variable, the absolute path can be configured here. Default is `arping`.
- **cacheDeviceStateTimeInMS:** The result of a device presence detection is cached for a small amount of time. Set this time here in milliseconds. Be aware that no new pings will be issued within this time frame, even if explicitly requested. Default is 2000.
- **preferResponseTimeAsLatency:** If enabled, an attempt will be made to extract the latency from the output of the ping command. If no such latency value is found in the ping command output, the time to execute the ping command is used as fallback latency. If disabled, the time to execute the ping command is always used as latency value. This is disabled by default to be backwards-compatible and to not break statistics and monitoring which existed before this feature.
- **numberOfDiscoveryThreads:** Specifies the number of threads to be used during the discovery process. Increasing this value may speed up the discovery of devices on large networks but could also increase the load on the system. Default is `100`.

Create a `<openHAB-conf>/services/network.cfg` file and use the above options like this:

Expand All @@ -22,6 +23,7 @@ binding.network:allowSystemPings=true
binding.network:allowDHCPlisten=false
binding.network:arpPingToolPath=arping
binding.network:cacheDeviceStateTimeInMS=2000
binding.network:numberOfDiscoveryThreads=100
```

## Supported Things
Expand Down Expand Up @@ -54,6 +56,12 @@ Use the following options for a **network:pingdevice**:
- **timeout:** How long the ping will wait for an answer, in milliseconds. Default: `5000` (5 seconds).
- **refreshInterval:** How often the device will be checked, in milliseconds. Default: `60000` (one minute).
- **useIOSWakeUp:** When set to true, an additional port knock is performed before a ping. Default: `true`.
- **useArpPing:** When set to true if the presence detection is allowed to use arp ping.
This can speed up presence detection, but may lead to inaccurate ping latency measurements.
Switch off if you want to use this for ping latency monitoring. Default: `true`.
- **useIcmpPing:** When set to true if the presence detection is allowed to use icmp ping.
When also using arp ping, the latency measurements will not be comparable.
Switch off if you rather want to use arp ping latency monitoring. Default: `true`.
- **networkInterfaceNames:** The network interface names used for communicating with the device.
Limiting the network interfaces reduces the load when arping and Wake-on-LAN are used.
Use comma separated values when using textual config. Default: empty (all network interfaces).
Expand Down Expand Up @@ -190,6 +198,7 @@ demo.things:

```java
Thing network:pingdevice:devicename [ hostname="192.168.0.42", macAddress="6f:70:65:6e:48:41", useIOSWakeUp="false" ]
Thing network:pingdevice:router [ hostname="192.168.0.1", useArpPing="false" ]
Thing network:speedtest:local "SpeedTest 50Mo" @ "Internet" [url="https://bouygues.testdebit.info/", fileName="50M.iso"]
```

Expand All @@ -199,6 +208,8 @@ demo.items:
Switch MyDevice { channel="network:pingdevice:devicename:online" }
Number:Time MyDeviceResponseTime { channel="network:pingdevice:devicename:latency" }

Number:Time MyRouterResponseTime { channel="network:pingdevice:router:latency" }

String Speedtest_Running "Test running ... [%s]" {channel="network:speedtest:local:isRunning"}
Number:Dimensionless Speedtest_Progress "Test progress [%d %unit%]" {channel="network:speedtest:local:progress"}
Number:DataTransferRate Speedtest_ResultDown "Downlink [%.2f %unit%]" {channel="network:speedtest:local:rateDown"}
Expand All @@ -218,6 +229,10 @@ sitemap demo label="Main Menu"
Text item=MyDeviceResponseTime label="Device Response Time [%s]"
}

Frame {
Text item=MyRouterResponseTime label="Router Response Time [%s]"
}

Frame label="SpeedTest" {
Text item=Speedtest_Start
Switch item=Speedtest_Running
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@
@NonNullByDefault
public class NetworkBindingConfiguration {

public final static int DEFAULT_DISCOVERY_THREADS = 100;
public final static String DEFAULT_ARPING_TOOL_PATH = "arping";
public final static ArpPingUtilEnum DEFAULT_ARPING_METHOD = ArpPingUtilEnum.DISABLED;
public boolean allowSystemPings = true;
public boolean allowDHCPlisten = true;
public BigDecimal cacheDeviceStateTimeInMS = BigDecimal.valueOf(2000);
public String arpPingToolPath = "arping";
public ArpPingUtilEnum arpPingUtilMethod = ArpPingUtilEnum.DISABLED;
public String arpPingToolPath = DEFAULT_ARPING_TOOL_PATH;
public ArpPingUtilEnum arpPingUtilMethod = DEFAULT_ARPING_METHOD;
// For backwards compatibility reasons, the default is to use the ping method execution time as latency value
public boolean preferResponseTimeAsLatency = false;
public int numberOfDiscoveryThreads = DEFAULT_DISCOVERY_THREADS;

private List<NetworkBindingConfigurationListener> listeners = new ArrayList<>();

Expand All @@ -45,6 +49,7 @@ public void update(NetworkBindingConfiguration newConfiguration) {
this.cacheDeviceStateTimeInMS = newConfiguration.cacheDeviceStateTimeInMS;
this.arpPingToolPath = newConfiguration.arpPingToolPath;
this.preferResponseTimeAsLatency = newConfiguration.preferResponseTimeAsLatency;
this.numberOfDiscoveryThreads = newConfiguration.numberOfDiscoveryThreads;

NetworkUtils networkUtils = new NetworkUtils();
this.arpPingUtilMethod = networkUtils.determineNativeArpPingMethod(arpPingToolPath);
Expand All @@ -65,6 +70,6 @@ public String toString() {
return "NetworkBindingConfiguration{" + "allowSystemPings=" + allowSystemPings + ", allowDHCPlisten="
+ allowDHCPlisten + ", cacheDeviceStateTimeInMS=" + cacheDeviceStateTimeInMS + ", arpPingToolPath='"
+ arpPingToolPath + '\'' + ", arpPingUtilMethod=" + arpPingUtilMethod + ", preferResponseTimeAsLatency="
+ preferResponseTimeAsLatency + '}';
+ preferResponseTimeAsLatency + ", numberOfDiscoveryThreads=" + numberOfDiscoveryThreads + '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
public class NetworkBindingConstants {

public static final String BINDING_ID = "network";
public static final String BINDING_CONFIGURATION_PID = "binding.network";

// List of all Thing Type UIDs
public static final ThingTypeUID BACKWARDS_COMPATIBLE_DEVICE = new ThingTypeUID(BINDING_ID, "device");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,7 @@ public class NetworkHandlerConfiguration {
public Integer refreshInterval = 60000;
public Integer timeout = 5000;
public boolean useIOSWakeUp = true;
public boolean useArpPing = true;
public boolean useIcmpPing = true;
public Set<String> networkInterfaceNames = Set.of();
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,21 @@
*/
package org.openhab.binding.network.internal;

import static org.openhab.binding.network.internal.NetworkBindingConstants.*;

import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.network.internal.handler.NetworkHandler;
import org.openhab.binding.network.internal.handler.SpeedTestHandler;
import org.openhab.core.common.NamedThreadFactory;
import org.openhab.core.common.ThreadPoolManager;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
Expand All @@ -39,28 +48,44 @@
* @author David Graeff - Initial contribution
*/
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.network")
@Component(service = ThingHandlerFactory.class, configurationPid = BINDING_CONFIGURATION_PID)
public class NetworkHandlerFactory extends BaseThingHandlerFactory {
final NetworkBindingConfiguration configuration = new NetworkBindingConfiguration();

private static final String NETWORK_HANDLER_THREADPOOL_NAME = "networkBinding";
private static final String NETWORK_RESOLVER_THREADPOOL_NAME = "binding-network-resolver";
private final Logger logger = LoggerFactory.getLogger(NetworkHandlerFactory.class);
private final ScheduledExecutorService executor = ThreadPoolManager
.getScheduledPool(NETWORK_HANDLER_THREADPOOL_NAME);
private volatile @Nullable ExecutorService resolver;

@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return NetworkBindingConstants.SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}

// The activate component call is used to access the bindings configuration
@Activate
protected void activate(ComponentContext componentContext, Map<String, Object> config) {
super.activate(componentContext);
modified(config);
ExecutorService resolver = this.resolver;
if (resolver != null) {
// This should not happen
resolver.shutdownNow();
}
this.resolver = new ThreadPoolExecutor(1, Integer.MAX_VALUE, 20L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), new NamedThreadFactory(NETWORK_RESOLVER_THREADPOOL_NAME));
}

@Override
@Deactivate
protected void deactivate(ComponentContext componentContext) {
super.deactivate(componentContext);
ExecutorService resolver = this.resolver;
if (resolver != null) {
resolver.shutdownNow();
this.resolver = null;
}
}

@Modified
Expand All @@ -74,14 +99,20 @@ protected void modified(Map<String, Object> config) {

@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ExecutorService resolver = this.resolver;
if (resolver == null) {
// This should be impossible
logger.error("Failed to create handler for Thing \"{}\" - handler factory hasn't been activated",
thing.getUID());
return null;
}
ThingTypeUID thingTypeUID = thing.getThingTypeUID();

if (thingTypeUID.equals(NetworkBindingConstants.PING_DEVICE)
|| thingTypeUID.equals(NetworkBindingConstants.BACKWARDS_COMPATIBLE_DEVICE)) {
return new NetworkHandler(thing, false, configuration);
} else if (thingTypeUID.equals(NetworkBindingConstants.SERVICE_DEVICE)) {
return new NetworkHandler(thing, true, configuration);
} else if (thingTypeUID.equals(NetworkBindingConstants.SPEEDTEST_DEVICE)) {
if (thingTypeUID.equals(PING_DEVICE) || thingTypeUID.equals(BACKWARDS_COMPATIBLE_DEVICE)) {
return new NetworkHandler(thing, executor, resolver, false, configuration);
} else if (thingTypeUID.equals(SERVICE_DEVICE)) {
return new NetworkHandler(thing, executor, resolver, true, configuration);
} else if (thingTypeUID.equals(SPEEDTEST_DEVICE)) {
return new SpeedTestHandler(thing);
}
return null;
Expand Down
Loading