Skip to content

Commit

Permalink
Merge
Browse files Browse the repository at this point in the history
  • Loading branch information
jenkins committed Jan 12, 2020
2 parents bd8f322 + 672a143 commit e2b7633
Show file tree
Hide file tree
Showing 15 changed files with 427 additions and 116 deletions.
6 changes: 3 additions & 3 deletions bundles/org.openhab.binding.darksky/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ Number:Speed localCurrentSnowIntensity "Current snow intensity [%.2f mm/h]" <sno
Number:Speed localCurrentPrecipitationIntensity "Current precipitation intensity [%.2f mm/h]" <rain> { channel="darksky:weather-and-forecast:api:local:current#precip-intensity" }
Number:Dimensionless localCurrentPrecipitationProbability "Current precipitation probability [%d %unit%]" <rain> { channel="darksky:weather-and-forecast:api:local:current#precip-probability" }
String localCurrentPrecipitationType "Current precipitation type [%s]" <rain> { channel="darksky:weather-and-forecast:api:local:current#precip-type" }
Number localCurrentUVIndex "Current precipitation probability [%d]" <none> { channel="darksky:weather-and-forecast:api:local:current#uvindex" }
Number localCurrentUVIndex "Current UV index [%d]" <none> { channel="darksky:weather-and-forecast:api:local:current#uvindex" }
Number:ArealDensity localCurrentOzone "Current ozone [%.1f %unit%]" <none> { channel="darksky:weather-and-forecast:api:local:current#ozone" }
DateTime localSunrise "Sunrise [%1$tY-%1$tm-%1$tdT%1$tH:%1$tM:%1$tS]" <sun> { channel="darksky:weather-and-forecast:api:local:current#sunrise" }
DateTime localSunset "Sunset [%1$tY-%1$tm-%1$tdT%1$tH:%1$tM:%1$tS]" <sun> { channel="darksky:weather-and-forecast:api:local:current#sunset" }
Expand Down Expand Up @@ -294,8 +294,8 @@ sitemap demo label="Dark Sky" {
Image item=localDailyForecastTodayConditionIcon
Text item=localDailyForecastTodayMinTemperature
Text item=localDailyForecastTodayMaxTemperature
Text item=localDailyForecastTodayMinApprentTemperature
Text item=localDailyForecastTodayMaxApprentTemperature
Text item=localDailyForecastTodayMinApparentTemperature
Text item=localDailyForecastTodayMaxApparentTemperature
Text item=localDailyForecastTodayPressure
Text item=localDailyForecastTodayHumidity
Text item=localDailyForecastTodayWindSpeed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,15 @@ protected synchronized void modified(ComponentContext componentContext) {
}

try {
logger.info("Starting FTP server, port={}, idleTimeout={}", port, idleTimeout);
logger.debug("Starting FTP server, port={}, idleTimeout={}", port, idleTimeout);
ftpServer.startServer(port, idleTimeout);
} catch (FtpException | FtpServerConfigurationException e) {
logger.warn("FTP server starting failed, reason: {}", e.getMessage());
}
}

private void stopFtpServer() {
logger.info("Stopping FTP server");
logger.debug("Stopping FTP server");
ftpServer.stopServer();
}
}
13 changes: 13 additions & 0 deletions bundles/org.openhab.binding.network/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The binding has the following configuration options:
- **allowDHCPlisten:** If devices leave and reenter a network, they usually request their last IPv4 address by using DHCP requests. By listening for those messages, the status update can be more "real-time" without having to wait for the next refresh cycle. Default is true.
- **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.

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

Expand Down Expand Up @@ -156,6 +157,18 @@ iptables -A PREROUTING -t mangle -p udp ! -s 127.0.0.1 --dport 67 -j TEE --gatew
iptables -A OUTPUT -t nat -p udp -s 127.0.0.1/32 --dport 67 -j DNAT --to 127.0.0.1:6767
```

Above iptables solutions to check *dhcp_state* are not working when OpenHAB is started in Docker. Use another workaround

```shell
iptables -I PREROUTING -t nat -p udp --src 0.0.0.0 --dport 67 -j DNAT --to 0.0.0.0:6767
```

To verify PREROUTING list use below command

```shell
iptables -L -n -t nat
```

## Channels

Things support the following channels:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
package org.openhab.binding.network.internal;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.network.internal.utils.NetworkUtils;
Expand All @@ -26,19 +28,47 @@
*/
@NonNullByDefault
public class NetworkBindingConfiguration {

public Boolean allowSystemPings = true;
public Boolean allowDHCPlisten = true;
public BigDecimal cacheDeviceStateTimeInMS = BigDecimal.valueOf(2000);
public String arpPingToolPath = "arping";
public @NonNullByDefault({}) ArpPingUtilEnum arpPingUtilMethod;
// For backwards compatibility reasons, the default is to use the ping method execution time as latency value
public boolean preferResponseTimeAsLatency = false;

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

public void update(NetworkBindingConfiguration newConfiguration) {
this.allowSystemPings = newConfiguration.allowSystemPings;
this.allowDHCPlisten = newConfiguration.allowDHCPlisten;
this.cacheDeviceStateTimeInMS = newConfiguration.cacheDeviceStateTimeInMS;
this.arpPingToolPath = newConfiguration.arpPingToolPath;
this.preferResponseTimeAsLatency = newConfiguration.preferResponseTimeAsLatency;

NetworkUtils networkUtils = new NetworkUtils();
this.arpPingUtilMethod = networkUtils.determineNativeARPpingMethod(arpPingToolPath);

notifyListeners();
}

public void addNetworkBindingConfigurationListener(NetworkBindingConfigurationListener listener) {
listeners.add(listener);
}

private void notifyListeners() {
listeners.forEach(NetworkBindingConfigurationListener::bindingConfigurationChanged);
}

@Override
public String toString() {
return "NetworkBindingConfiguration{" +
"allowSystemPings=" + allowSystemPings +
", allowDHCPlisten=" + allowDHCPlisten +
", cacheDeviceStateTimeInMS=" + cacheDeviceStateTimeInMS +
", arpPingToolPath='" + arpPingToolPath + '\'' +
", arpPingUtilMethod=" + arpPingUtilMethod +
", preferResponseTimeAsLatency=" + preferResponseTimeAsLatency +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.network.internal;

/**
* Listener for binding configuration changes.
*
* @author Andreas Hirsch - Initial contribution
*/
public interface NetworkBindingConfigurationListener {

void bindingConfigurationChanged();
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The handler factory retrieves the binding configuration and is responsible for creating
Expand All @@ -41,6 +43,8 @@
public class NetworkHandlerFactory extends BaseThingHandlerFactory {
final NetworkBindingConfiguration configuration = new NetworkBindingConfiguration();

private final Logger logger = LoggerFactory.getLogger(NetworkHandlerFactory.class);

@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return NetworkBindingConstants.SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
Expand All @@ -65,6 +69,7 @@ protected void modified(Map<String, Object> config) {
// configuration, the values are automatically available in all handlers. Because they all
// share the same instance.
configuration.update(new Configuration(config).as(NetworkBindingConfiguration.class));
logger.debug("Updated binding configuration to {}", configuration);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,6 @@
*/
package org.openhab.binding.network.internal;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.cache.ExpiringCache;
Expand All @@ -35,9 +21,20 @@
import org.openhab.binding.network.internal.utils.NetworkUtils;
import org.openhab.binding.network.internal.utils.NetworkUtils.ArpPingUtilEnum;
import org.openhab.binding.network.internal.utils.NetworkUtils.IpPingMethodEnum;
import org.openhab.binding.network.internal.utils.PingResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.*;
import java.util.function.Consumer;

/**
* The {@link PresenceDetection} handles the connection to the Device
*
Expand All @@ -47,6 +44,7 @@
*/
@NonNullByDefault
public class PresenceDetection implements IPRequestReceivedCallback {

public static final double NOT_REACHABLE = -1;
public static final int DESTINATION_TTL = 300 * 1000; // in ms, 300 s

Expand All @@ -71,6 +69,8 @@ public class PresenceDetection implements IPRequestReceivedCallback {
private @NonNullByDefault({}) ExpiringCache<@Nullable InetAddress> destination;
private @Nullable InetAddress cachedDestination = null;

public boolean preferResponseTimeAsLatency;

/// State variables (cannot be final because of test dependency injections)
ExpiringCacheAsync<PresenceDetectionValue> cache;
private final PresenceDetectionListener updateListener;
Expand Down Expand Up @@ -148,6 +148,10 @@ public void setTimeout(int timeout) {
this.timeoutInMS = timeout;
}

public void setPreferResponseTimeAsLatency(boolean preferResponseTimeAsLatency) {
this.preferResponseTimeAsLatency = preferResponseTimeAsLatency;
}

/**
* Sets the ping method. This method will perform a feature test. If SYSTEM_PING
* does not work on this system, JAVA_PING will be used instead.
Expand Down Expand Up @@ -339,13 +343,13 @@ public boolean performPresenceDetection(boolean waitForDetectionToFinish) {
performARPping("");
checkIfFinished();
});
} else if (interfaceNames != null) {
} else if (interfaceNames != null) {
for (final String interfaceName : interfaceNames) {
executorService.execute(() -> {
Thread.currentThread().setName("presenceDetectionARP_" + hostname + " " + interfaceName);
performARPping(interfaceName);
checkIfFinished();
});
});
}
}

Expand Down Expand Up @@ -468,15 +472,15 @@ synchronized PresenceDetectionValue updateReachableValue(PresenceDetectionType t
protected void performServicePing(int tcpPort) {
logger.trace("Perform TCP presence detection for {} on port: {}", hostname, tcpPort);
try {
double pingTime = System.nanoTime();
InetAddress destinationAddress = destination.getValue();
if (destinationAddress != null
&& networkUtils.servicePing(destinationAddress.getHostAddress(), tcpPort, timeoutInMS)) {
final double latency = Math.round((System.nanoTime() - pingTime) / 1000000.0f);
PresenceDetectionValue v = updateReachableValue(PresenceDetectionType.TCP_CONNECTION, latency);
v.addReachableTcpService(tcpPort);
updateListener.partialDetectionResult(v);
}

networkUtils.servicePing(destinationAddress.getHostAddress(), tcpPort, timeoutInMS).ifPresent(o -> {
if(o.isSuccess()) {
PresenceDetectionValue v = updateReachableValue(PresenceDetectionType.TCP_CONNECTION, getLatency(o, preferResponseTimeAsLatency));
v.addReachableTcpService(tcpPort);
updateListener.partialDetectionResult(v);
}
});
} catch (IOException e) {
// This should not happen and might be a user configuration issue, we log a warning message therefore.
logger.warn("Could not create a socket connection", e);
Expand All @@ -502,13 +506,14 @@ protected void performARPping(String interfaceName) {
networkUtils.wakeUpIOS(destinationAddress);
Thread.sleep(50);
}
double pingTime = System.nanoTime();
if (networkUtils.nativeARPPing(arpPingMethod, arpPingUtilPath, interfaceName,
destinationAddress.getHostAddress(), timeoutInMS)) {
final double latency = Math.round((System.nanoTime() - pingTime) / 1000000.0f);
PresenceDetectionValue v = updateReachableValue(PresenceDetectionType.ARP_PING, latency);
updateListener.partialDetectionResult(v);
}

networkUtils.nativeARPPing(arpPingMethod, arpPingUtilPath, interfaceName,
destinationAddress.getHostAddress(), timeoutInMS).ifPresent(o -> {
if (o.isSuccess()) {
PresenceDetectionValue v = updateReachableValue(PresenceDetectionType.ARP_PING, getLatency(o, preferResponseTimeAsLatency));
updateListener.partialDetectionResult(v);
}
});
} catch (IOException e) {
logger.trace("Failed to execute an arp ping for ip {}", hostname, e);
} catch (InterruptedException ignored) {
Expand All @@ -523,43 +528,56 @@ protected void performARPping(String interfaceName) {
* (http://docs.oracle.com/javase/7/docs/api/java/net/InetAddress.html#isReachable%28int%29)
*/
protected void performJavaPing() {
try {
logger.trace("Perform java ping presence detection for {}", hostname);
double pingTime = System.nanoTime();
InetAddress destinationAddress = destination.getValue();
if (destinationAddress == null) {
return;
}
if (destinationAddress.isReachable(timeoutInMS)) {
final double latency = Math.round((System.nanoTime() - pingTime) / 1000000.0f);
PresenceDetectionValue v = updateReachableValue(PresenceDetectionType.ICMP_PING, latency);
logger.trace("Perform java ping presence detection for {}", hostname);

InetAddress destinationAddress = destination.getValue();
if (destinationAddress == null) {
return;
}

networkUtils.javaPing(timeoutInMS, destinationAddress).ifPresent(o -> {
if (o.isSuccess()) {
PresenceDetectionValue v = updateReachableValue(PresenceDetectionType.ICMP_PING, getLatency(o, preferResponseTimeAsLatency));
updateListener.partialDetectionResult(v);
}
} catch (IOException e) {
logger.trace("Failed to execute a java ping for ip {}", hostname, e);
}
});
}

protected void performSystemPing() {
try {
logger.trace("Perform native ping presence detection for {}", hostname);
double pingTime = System.nanoTime();
InetAddress destinationAddress = destination.getValue();
if (destinationAddress == null) {
return;
}
if (networkUtils.nativePing(pingMethod, destinationAddress.getHostAddress(), timeoutInMS)) {
final double latency = Math.round((System.nanoTime() - pingTime) / 1000000.0f);
PresenceDetectionValue v = updateReachableValue(PresenceDetectionType.ICMP_PING, latency);
updateListener.partialDetectionResult(v);
}

networkUtils.nativePing(pingMethod, destinationAddress.getHostAddress(), timeoutInMS).ifPresent(o -> {
if (o.isSuccess()) {
PresenceDetectionValue v = updateReachableValue(PresenceDetectionType.ICMP_PING, getLatency(o, preferResponseTimeAsLatency));
updateListener.partialDetectionResult(v);
}
});


} catch (IOException e) {
logger.trace("Failed to execute a native ping for ip {}", hostname, e);
} catch (InterruptedException e) {
// This can be ignored, the thread will end anyway
}
}

private double getLatency(PingResult pingResult, boolean preferResponseTimeAsLatency) {
logger.debug("Getting latency from ping result {} using latency mode {}", pingResult, preferResponseTimeAsLatency);
// Execution time is always set and this value is also the default. So lets use it first.
double latency = pingResult.getExecutionTimeInMS();

if (preferResponseTimeAsLatency && pingResult.getResponseTimeInMS().isPresent()) {
latency = pingResult.getResponseTimeInMS().get();
}

return latency;
}

@Override
public void dhcpRequestReceived(String ipAddress) {
PresenceDetectionValue v = updateReachableValue(PresenceDetectionType.DHCP_REQUEST, 0);
Expand Down
Loading

0 comments on commit e2b7633

Please sign in to comment.