diff --git a/bundles/org.openhab.binding.snmp/README.md b/bundles/org.openhab.binding.snmp/README.md
index e2cd61acb4a..725d27f9459 100644
--- a/bundles/org.openhab.binding.snmp/README.md
+++ b/bundles/org.openhab.binding.snmp/README.md
@@ -77,13 +77,8 @@ The default is `v1`.
### `target3`
-The `target3` thing has additional mandatory parameters: `engineId` and `user`.
-
-The `engineId` must be given in hexadecimal notation (case-insensitive) without separators (e.g. `80000009035c710dbcd9e6`).
-The allowed length is 11 to 32 bytes (22 to 64 hex characters).
-If you encounter problems, please check if your agent prefixes the set engine id (e.g. Mikrotik uses `80003a8c04` and appends the set value to that).
-
-The `user` parameter is named "securityName" or "userName" in most agents.
+The `target3` thing has an additional mandatory parameter: `user`.
+This value of this parameter is named "securityName" or "userName" in most agents.
Optional configuration parameters are: `securityModel`, `authProtocol`, `authPassphrase`, `privProtocol` and `privPassphrase`.
@@ -99,7 +94,7 @@ If authentication encryption is required, at least `authPassphrase` needs to be
Other possible values for `authProtocol` are `SHA`, `HMAC128SHA224`, `HMAC192SHA256`, `HMAC256SHA384` and `HMAC384SHA512`.
If encryption of transmitted data (privacy encryption) is required, at least `privPassphrase` needs to be set, while `privProtocol` defaults to `DES`.
-Other possible values for `privProtocol` are `AES128`, `AES192` and `AES256`.
+Other possible values for `privProtocol` are `DES3`, `AES128`, `AES192` and `AES256`.
## Channels
diff --git a/bundles/org.openhab.binding.snmp/pom.xml b/bundles/org.openhab.binding.snmp/pom.xml
index a53a670b5db..89182919dbe 100644
--- a/bundles/org.openhab.binding.snmp/pom.xml
+++ b/bundles/org.openhab.binding.snmp/pom.xml
@@ -18,7 +18,13 @@
org.snmp4j
snmp4j
- 2.8.6
+ 3.8.2
+ compile
+
+
+ org.snmp4j
+ snmp4j-unix-transport
+ 1.1.0
compile
diff --git a/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpService.java b/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpService.java
index 58b42791004..80f51eacc70 100644
--- a/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpService.java
+++ b/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpService.java
@@ -16,12 +16,13 @@ import java.io.IOException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.binding.snmp.internal.types.SnmpAuthProtocol;
-import org.openhab.binding.snmp.internal.types.SnmpPrivProtocol;
import org.snmp4j.CommandResponder;
import org.snmp4j.PDU;
import org.snmp4j.Target;
import org.snmp4j.event.ResponseListener;
+import org.snmp4j.security.UsmUser;
+import org.snmp4j.smi.Address;
+import org.snmp4j.smi.OctetString;
/**
* The {@link SnmpService} is responsible for SNMP communication
@@ -33,12 +34,53 @@ import org.snmp4j.event.ResponseListener;
@NonNullByDefault
public interface SnmpService {
+ /**
+ * Add a listener for received PDUs to the service
+ *
+ * @param listener the listener
+ */
void addCommandResponder(CommandResponder listener);
+ /**
+ * Remove a listener for received PDUs from the service
+ *
+ * @param listener the listener
+ */
void removeCommandResponder(CommandResponder listener);
- void send(PDU pdu, Target target, @Nullable Object userHandle, ResponseListener listener) throws IOException;
+ /**
+ * Send a PDU to the given target
+ *
+ * @param pdu the PDU
+ * @param target the target
+ * @param userHandle an optional user-handle to identify the request
+ * @param listener the listener for the response (always called, even in case of timeout)
+ * @throws IOException when an error occurs
+ */
+ void send(PDU pdu, Target> target, @Nullable Object userHandle, ResponseListener listener) throws IOException;
- void addUser(String userName, SnmpAuthProtocol snmpAuthProtocol, @Nullable String authPassphrase,
- SnmpPrivProtocol snmpPrivProtocol, @Nullable String privPassphrase, byte[] engineId);
+ /**
+ * Add a user to the service for a given engine id (v3 only)
+ *
+ * @param user the {@link UsmUser} that should be added
+ * @param engineId the engine id
+ */
+ void addUser(UsmUser user, OctetString engineId);
+
+ /**
+ * Remove a user from the service and clear the context engine id for this address (v3 only)
+ *
+ * @param address the remote address
+ * @param user the user
+ * @param engineId the engine id
+ */
+ void removeUser(Address address, UsmUser user, OctetString engineId);
+
+ /**
+ * Get the engine id of a remote system for a given address (v3 only)
+ *
+ * @param address the address of the remote system
+ * @return the engine id or {@code null} when engine id could not be determined
+ */
+ byte @Nullable [] getEngineId(Address address);
}
diff --git a/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpServiceImpl.java b/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpServiceImpl.java
index 86e223feb38..5182e7093af 100644
--- a/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpServiceImpl.java
+++ b/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpServiceImpl.java
@@ -22,8 +22,6 @@ import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.snmp.internal.config.SnmpServiceConfiguration;
-import org.openhab.binding.snmp.internal.types.SnmpAuthProtocol;
-import org.openhab.binding.snmp.internal.types.SnmpPrivProtocol;
import org.openhab.core.config.core.Configuration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
@@ -37,11 +35,22 @@ import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.MPv3;
+import org.snmp4j.security.AuthHMAC128SHA224;
+import org.snmp4j.security.AuthHMAC192SHA256;
+import org.snmp4j.security.AuthHMAC256SHA384;
+import org.snmp4j.security.AuthHMAC384SHA512;
+import org.snmp4j.security.AuthMD5;
+import org.snmp4j.security.AuthSHA;
import org.snmp4j.security.Priv3DES;
+import org.snmp4j.security.PrivAES128;
+import org.snmp4j.security.PrivAES192;
+import org.snmp4j.security.PrivAES256;
+import org.snmp4j.security.PrivDES;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.security.UsmUser;
+import org.snmp4j.smi.Address;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.transport.DefaultUdpTransportMapping;
@@ -58,7 +67,6 @@ import org.snmp4j.transport.DefaultUdpTransportMapping;
public class SnmpServiceImpl implements SnmpService {
private final Logger logger = LoggerFactory.getLogger(SnmpServiceImpl.class);
- private @NonNullByDefault({}) SnmpServiceConfiguration config;
private @Nullable Snmp snmp;
private @Nullable DefaultUdpTransportMapping transport;
@@ -67,9 +75,7 @@ public class SnmpServiceImpl implements SnmpService {
@Activate
public SnmpServiceImpl(Map config) {
- SecurityProtocols.getInstance().addDefaultProtocols();
- SecurityProtocols.getInstance().addPrivacyProtocol(new Priv3DES());
-
+ addProtocols();
OctetString localEngineId = new OctetString(MPv3.createLocalEngineID());
USM usm = new USM(SecurityProtocols.getInstance(), localEngineId, 0);
SecurityModels.getInstance().addSecurityModel(usm);
@@ -79,34 +85,33 @@ public class SnmpServiceImpl implements SnmpService {
@Modified
protected void modified(Map config) {
- this.config = new Configuration(config).as(SnmpServiceConfiguration.class);
+ SnmpServiceConfiguration snmpCfg = new Configuration(config).as(SnmpServiceConfiguration.class);
try {
shutdownSnmp();
final DefaultUdpTransportMapping transport;
- if (this.config.port > 0) {
- transport = new DefaultUdpTransportMapping(new UdpAddress(this.config.port), true);
+ if (snmpCfg.port > 0) {
+ transport = new DefaultUdpTransportMapping(new UdpAddress(snmpCfg.port), true);
} else {
transport = new DefaultUdpTransportMapping();
}
- SecurityProtocols.getInstance().addDefaultProtocols();
- SecurityProtocols.getInstance().addPrivacyProtocol(new Priv3DES());
+ addProtocols();
final Snmp snmp = new Snmp(transport);
listeners.forEach(snmp::addCommandResponder);
snmp.listen();
// re-add user entries
- userEntries.forEach(u -> addUser(snmp, u));
+ userEntries.forEach(u -> snmp.getUSM().addUser(u.user, u.engineId));
this.snmp = snmp;
this.transport = transport;
logger.debug("initialized SNMP at {}", transport.getAddress());
} catch (IOException e) {
- logger.warn("could not open SNMP instance on port {}: {}", this.config.port, e.getMessage());
+ logger.warn("could not open SNMP instance on port {}: {}", snmpCfg.port, e.getMessage());
}
}
@@ -120,6 +125,21 @@ public class SnmpServiceImpl implements SnmpService {
}
}
+ private void addProtocols() {
+ SecurityProtocols secProtocols = SecurityProtocols.getInstance();
+ secProtocols.addAuthenticationProtocol(new AuthMD5());
+ secProtocols.addAuthenticationProtocol(new AuthSHA());
+ secProtocols.addAuthenticationProtocol(new AuthHMAC128SHA224());
+ secProtocols.addAuthenticationProtocol(new AuthHMAC192SHA256());
+ secProtocols.addAuthenticationProtocol(new AuthHMAC256SHA384());
+ secProtocols.addAuthenticationProtocol(new AuthHMAC384SHA512());
+ secProtocols.addPrivacyProtocol(new PrivDES());
+ secProtocols.addPrivacyProtocol(new Priv3DES());
+ secProtocols.addPrivacyProtocol(new PrivAES128());
+ secProtocols.addPrivacyProtocol(new PrivAES192());
+ secProtocols.addPrivacyProtocol(new PrivAES256());
+ }
+
private void shutdownSnmp() throws IOException {
DefaultUdpTransportMapping transport = this.transport;
if (transport != null) {
@@ -152,7 +172,7 @@ public class SnmpServiceImpl implements SnmpService {
}
@Override
- public void send(PDU pdu, Target target, @Nullable Object userHandle, ResponseListener listener)
+ public void send(PDU pdu, Target> target, @Nullable Object userHandle, ResponseListener listener)
throws IOException {
Snmp snmp = this.snmp;
if (snmp != null) {
@@ -164,35 +184,40 @@ public class SnmpServiceImpl implements SnmpService {
}
@Override
- public void addUser(String userName, SnmpAuthProtocol snmpAuthProtocol, @Nullable String authPassphrase,
- SnmpPrivProtocol snmpPrivProtocol, @Nullable String privPassphrase, byte[] engineId) {
- UsmUser usmUser = new UsmUser(new OctetString(userName),
- authPassphrase != null ? snmpAuthProtocol.getOid() : null,
- authPassphrase != null ? new OctetString(authPassphrase) : null,
- privPassphrase != null ? snmpPrivProtocol.getOid() : null,
- privPassphrase != null ? new OctetString(privPassphrase) : null);
- OctetString securityNameOctets = new OctetString(userName);
-
- UserEntry userEntry = new UserEntry(securityNameOctets, new OctetString(engineId), usmUser);
+ public void addUser(UsmUser user, OctetString engineId) {
+ UserEntry userEntry = new UserEntry(user, engineId);
userEntries.add(userEntry);
Snmp snmp = this.snmp;
if (snmp != null) {
- addUser(snmp, userEntry);
+ snmp.getUSM().addUser(user, engineId);
}
}
- private static void addUser(Snmp snmp, UserEntry userEntry) {
- snmp.getUSM().addUser(userEntry.securityName, userEntry.engineId, userEntry.user);
+ @Override
+ public void removeUser(Address address, UsmUser user, OctetString engineId) {
+ Snmp snmp = this.snmp;
+ if (snmp != null) {
+ snmp.getUSM().removeAllUsers(user.getSecurityName(), engineId);
+ snmp.removeCachedContextEngineId(address);
+ }
+ userEntries.removeIf(e -> e.engineId.equals(engineId) && e.user.equals(user));
+ }
+
+ @Override
+ public byte @Nullable [] getEngineId(Address address) {
+ Snmp snmp = this.snmp;
+ if (snmp != null) {
+ return snmp.discoverAuthoritativeEngineID(address, 15000);
+ }
+ return null;
}
private static class UserEntry {
- public OctetString securityName;
public OctetString engineId;
public UsmUser user;
- public UserEntry(OctetString securityName, OctetString engineId, UsmUser user) {
- this.securityName = securityName;
+ public UserEntry(UsmUser user, OctetString engineId) {
this.engineId = engineId;
this.user = user;
}
diff --git a/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpTargetHandler.java b/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpTargetHandler.java
index 5b3c8bd72c3..7890e50112a 100644
--- a/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpTargetHandler.java
+++ b/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpTargetHandler.java
@@ -17,7 +17,6 @@ import static org.openhab.binding.snmp.internal.SnmpBindingConstants.*;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
-import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
@@ -53,7 +52,6 @@ import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.openhab.core.types.util.UnitUtils;
-import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snmp4j.AbstractTarget;
@@ -68,6 +66,8 @@ import org.snmp4j.UserTarget;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.SnmpConstants;
+import org.snmp4j.security.UsmUser;
+import org.snmp4j.smi.Address;
import org.snmp4j.smi.Counter64;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.IpAddress;
@@ -87,8 +87,8 @@ import org.snmp4j.smi.VariableBinding;
*/
@NonNullByDefault
public class SnmpTargetHandler extends BaseThingHandler implements ResponseListener, CommandResponder {
- private static final Pattern HEXSTRING_VALIDITY = Pattern.compile("([a-f0-9]{2}[ :-]?)+");
- private static final Pattern HEXSTRING_EXTRACTOR = Pattern.compile("[^a-f0-9]");
+ private static final Pattern HEX_STRING_VALIDITY = Pattern.compile("([A-Fa-f0-9]{2}[ :-]?)+");
+ private static final Pattern HEX_STRING_EXTRACTOR = Pattern.compile("[^A-Fa-f0-9]");
private final Logger logger = LoggerFactory.getLogger(SnmpTargetHandler.class);
@@ -97,13 +97,17 @@ public class SnmpTargetHandler extends BaseThingHandler implements ResponseListe
private @Nullable ScheduledFuture> refresh;
private int timeoutCounter = 0;
- private @NonNullByDefault({}) AbstractTarget target;
+ private @NonNullByDefault({}) AbstractTarget target;
private @NonNullByDefault({}) String targetAddressString;
private @NonNullByDefault({}) Set readChannelSet;
private @NonNullByDefault({}) Set writeChannelSet;
private @NonNullByDefault({}) Set trapChannelSet;
+ // SNMP v3
+ private @Nullable UsmUser usmUser;
+ private @Nullable OctetString engineId;
+
public SnmpTargetHandler(Thing thing, SnmpService snmpService) {
super(thing);
this.snmpService = snmpService;
@@ -139,7 +143,7 @@ public class SnmpTargetHandler extends BaseThingHandler implements ResponseListe
}
} else {
Command rawValue = command;
- if (command instanceof QuantityType quantityCommand) {
+ if (command instanceof QuantityType> quantityCommand) {
Unit> channelUnit = channel.unit;
if (channelUnit == null) {
rawValue = new DecimalType(quantityCommand.toBigDecimal());
@@ -180,7 +184,7 @@ public class SnmpTargetHandler extends BaseThingHandler implements ResponseListe
try {
if (config.protocol.toInteger() == SnmpConstants.version1
|| config.protocol.toInteger() == SnmpConstants.version2c) {
- CommunityTarget target = new CommunityTarget();
+ CommunityTarget target = new CommunityTarget<>();
target.setCommunity(new OctetString(config.community));
this.target = target;
} else if (config.protocol.toInteger() == SnmpConstants.version3) {
@@ -189,31 +193,31 @@ public class SnmpTargetHandler extends BaseThingHandler implements ResponseListe
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "user not set");
return;
}
- String engineIdHexString = config.engineId;
- if (engineIdHexString == null) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "engineId not set");
- return;
- }
String authPassphrase = config.authPassphrase;
- if ((config.securityModel == SnmpSecurityModel.AUTH_PRIV
- || config.securityModel == SnmpSecurityModel.AUTH_NO_PRIV)
- && (authPassphrase == null || authPassphrase.isEmpty())) {
+ if (config.securityModel != SnmpSecurityModel.NO_AUTH_NO_PRIV
+ && (authPassphrase == null || authPassphrase.isBlank())) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Authentication passphrase not configured");
return;
}
String privPassphrase = config.privPassphrase;
if (config.securityModel == SnmpSecurityModel.AUTH_PRIV
- && (privPassphrase == null || privPassphrase.isEmpty())) {
+ && (privPassphrase == null || privPassphrase.isBlank())) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Privacy passphrase not configured");
return;
}
- byte[] engineId = HexUtils.hexToBytes(engineIdHexString);
- snmpService.addUser(userName, config.authProtocol, authPassphrase, config.privProtocol, privPassphrase,
- engineId);
- UserTarget target = new UserTarget();
- target.setAuthoritativeEngineID(engineId);
+ usmUser = new UsmUser(new OctetString(userName),
+ config.securityModel != SnmpSecurityModel.NO_AUTH_NO_PRIV ? config.authProtocol.getOid() : null,
+ config.securityModel != SnmpSecurityModel.NO_AUTH_NO_PRIV && authPassphrase != null
+ ? new OctetString(authPassphrase)
+ : null,
+ config.securityModel == SnmpSecurityModel.AUTH_PRIV ? config.privProtocol.getOid() : null,
+ config.securityModel == SnmpSecurityModel.AUTH_PRIV && privPassphrase != null
+ ? new OctetString(privPassphrase)
+ : null);
+
+ UserTarget target = new UserTarget<>();
target.setSecurityName(new OctetString(config.user));
target.setSecurityLevel(config.securityModel.getSecurityLevel());
this.target = target;
@@ -248,6 +252,16 @@ public class SnmpTargetHandler extends BaseThingHandler implements ResponseListe
r.cancel(true);
}
snmpService.removeCommandResponder(this);
+
+ UsmUser user = usmUser;
+ OctetString engineId = this.engineId;
+ Address address = target.getAddress();
+ if (user != null && engineId != null && address != null) {
+ snmpService.removeUser(address, user, engineId);
+ }
+
+ usmUser = null;
+ this.engineId = null;
}
@Override
@@ -260,7 +274,7 @@ public class SnmpTargetHandler extends BaseThingHandler implements ResponseListe
// Always cancel async request when response has been received
// otherwise a memory leak is created! Not canceling a request
// immediately can be useful when sending a request to a broadcast
- // address (Comment is taken from the snmp4j API doc).
+ // address (Comment is taken from the SNMP4J API doc).
((Snmp) event.getSource()).cancel(event.getRequest(), this);
}
@@ -350,7 +364,7 @@ public class SnmpTargetHandler extends BaseThingHandler implements ResponseListe
if (configUnit != null) {
unit = UnitUtils.parseUnit(configUnit);
if (unit == null) {
- logger.warn("Failed to parse unit from '{}'for channel '{}'", unit, channel.getUID());
+ logger.warn("Failed to parse unit from '{}'for channel '{}'", configUnit, channel.getUID());
}
}
} else if (CHANNEL_TYPE_UID_STRING.equals(channel.getChannelTypeUID())) {
@@ -394,8 +408,9 @@ public class SnmpTargetHandler extends BaseThingHandler implements ResponseListe
}
private void generateChannelConfigs() {
- Set channelConfigs = Collections.unmodifiableSet(thing.getChannels().stream()
- .map(this::getChannelConfigFromChannel).filter(Objects::nonNull).collect(Collectors.toSet()));
+ Set channelConfigs = thing.getChannels().stream()
+ .map(this::getChannelConfigFromChannel).filter(Objects::nonNull).map(Objects::requireNonNull)
+ .collect(Collectors.toUnmodifiableSet());
this.readChannelSet = channelConfigs.stream()
.filter(c -> c.mode == SnmpChannelMode.READ || c.mode == SnmpChannelMode.READ_WRITE)
.collect(Collectors.toSet());
@@ -520,9 +535,9 @@ public class SnmpTargetHandler extends BaseThingHandler implements ResponseListe
case HEXSTRING -> {
if (command instanceof StringType stringCommand) {
String commandString = stringCommand.toString().toLowerCase();
- Matcher commandMatcher = HEXSTRING_VALIDITY.matcher(commandString);
+ Matcher commandMatcher = HEX_STRING_VALIDITY.matcher(commandString);
if (commandMatcher.matches()) {
- commandString = HEXSTRING_EXTRACTOR.matcher(commandString).replaceAll("");
+ commandString = HEX_STRING_EXTRACTOR.matcher(commandString).replaceAll("");
return OctetString.fromHexStringPairs(commandString);
}
}
@@ -541,7 +556,25 @@ public class SnmpTargetHandler extends BaseThingHandler implements ResponseListe
private boolean renewTargetAddress() {
try {
target.setAddress(new UdpAddress(InetAddress.getByName(config.hostname), config.port));
- targetAddressString = ((UdpAddress) target.getAddress()).getInetAddress().getHostAddress();
+ targetAddressString = target.getAddress().getInetAddress().getHostAddress();
+ logger.trace("Determined {} as address for {} (thing {})", target.getAddress(), config.hostname,
+ this.thing.getUID());
+ UsmUser user = usmUser;
+ if (user != null && target instanceof UserTarget userTarget) {
+ byte[] engineIdBytes = snmpService.getEngineId(target.getAddress());
+ if (engineIdBytes != null) {
+ OctetString engineIdOctets = new OctetString(engineIdBytes);
+ this.engineId = engineIdOctets;
+ logger.trace("Determined {} as engineId for {}", engineIdOctets, target.getAddress());
+ snmpService.addUser(user, engineIdOctets);
+ userTarget.setAuthoritativeEngineID(engineIdBytes);
+ } else {
+ target.setAddress(null);
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ "Cannot determine engineId");
+ return false;
+ }
+ }
return true;
} catch (UnknownHostException e) {
target.setAddress(null);
diff --git a/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/config/SnmpTargetConfiguration.java b/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/config/SnmpTargetConfiguration.java
index 218a48e6e8c..8f3a0068ac0 100644
--- a/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/config/SnmpTargetConfiguration.java
+++ b/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/config/SnmpTargetConfiguration.java
@@ -41,7 +41,6 @@ public class SnmpTargetConfiguration {
// v3 only
public SnmpSecurityModel securityModel = SnmpSecurityModel.NO_AUTH_NO_PRIV;
public @Nullable String user;
- public @Nullable String engineId;
public SnmpAuthProtocol authProtocol = SnmpAuthProtocol.MD5;
public @Nullable String authPassphrase;
public SnmpPrivProtocol privProtocol = SnmpPrivProtocol.DES;
diff --git a/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/types/SnmpPrivProtocol.java b/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/types/SnmpPrivProtocol.java
index 91148048818..9efee83a8de 100644
--- a/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/types/SnmpPrivProtocol.java
+++ b/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/types/SnmpPrivProtocol.java
@@ -13,6 +13,7 @@
package org.openhab.binding.snmp.internal.types;
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.snmp4j.security.Priv3DES;
import org.snmp4j.security.PrivAES128;
import org.snmp4j.security.PrivAES192;
import org.snmp4j.security.PrivAES256;
@@ -29,7 +30,8 @@ public enum SnmpPrivProtocol {
AES128(PrivAES128.ID),
AES192(PrivAES192.ID),
AES256(PrivAES256.ID),
- DES(PrivDES.ID);
+ DES(PrivDES.ID),
+ DES3(Priv3DES.ID);
private final OID oid;
diff --git a/bundles/org.openhab.binding.snmp/src/main/resources/OH-INF/i18n/snmp.properties b/bundles/org.openhab.binding.snmp/src/main/resources/OH-INF/i18n/snmp.properties
index ee531d1c769..322261c92e5 100644
--- a/bundles/org.openhab.binding.snmp/src/main/resources/OH-INF/i18n/snmp.properties
+++ b/bundles/org.openhab.binding.snmp/src/main/resources/OH-INF/i18n/snmp.properties
@@ -47,6 +47,7 @@ thing-type.config.snmp.target3.privProtocol.option.AES128 = AES128
thing-type.config.snmp.target3.privProtocol.option.AES192 = AES192
thing-type.config.snmp.target3.privProtocol.option.AES256 = AES256
thing-type.config.snmp.target3.privProtocol.option.DES = DES
+thing-type.config.snmp.target3.privProtocol.option.DES3 = 3DES
thing-type.config.snmp.target3.refresh.label = Refresh Time
thing-type.config.snmp.target3.refresh.description = Refresh time in s (default 60s)
thing-type.config.snmp.target3.retries.label = Retries
@@ -85,8 +86,8 @@ channel-type.config.snmp.number.mode.option.READ_WRITE = Read/Write
channel-type.config.snmp.number.mode.option.TRAP = Trap
channel-type.config.snmp.number.oid.label = OID
channel-type.config.snmp.number.oid.description = OID in dotted format (eg. .1.3.6.1.4.1.6574.3.1.1.3.0)
-channel-type.config.snmp.number.unit.label = Unit Of Measurement
-channel-type.config.snmp.number.unit.description = Unit of measurement (optional). The unit is used for representing the value in the GUI as well as for converting incoming values (like from '°F' to '°C'). Examples: "°C", "°F"
+channel-type.config.snmp.number.unit.label = Unit
+channel-type.config.snmp.number.unit.description = The unit of this value.
channel-type.config.snmp.string.datatype.label = Datatype
channel-type.config.snmp.string.datatype.description = Content data type
channel-type.config.snmp.string.datatype.option.STRING = String
diff --git a/bundles/org.openhab.binding.snmp/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.snmp/src/main/resources/OH-INF/thing/thing-types.xml
index 782d70d6fe0..82ffc2d8985 100644
--- a/bundles/org.openhab.binding.snmp/src/main/resources/OH-INF/thing/thing-types.xml
+++ b/bundles/org.openhab.binding.snmp/src/main/resources/OH-INF/thing/thing-types.xml
@@ -64,10 +64,6 @@
Hostname or IP address of target host
network-address
-
-
- The authorization engine ID of this target in hexadecimal notation (22-64 characters)
-
@@ -106,6 +102,7 @@
+
true
DES
diff --git a/bundles/org.openhab.binding.snmp/src/test/java/org/openhab/binding/snmp/internal/AbstractSnmpTargetHandlerTest.java b/bundles/org.openhab.binding.snmp/src/test/java/org/openhab/binding/snmp/internal/AbstractSnmpTargetHandlerTest.java
index 2ad98869c54..570f3faba57 100644
--- a/bundles/org.openhab.binding.snmp/src/test/java/org/openhab/binding/snmp/internal/AbstractSnmpTargetHandlerTest.java
+++ b/bundles/org.openhab.binding.snmp/src/test/java/org/openhab/binding/snmp/internal/AbstractSnmpTargetHandlerTest.java
@@ -21,7 +21,6 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Vector;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@@ -156,9 +155,8 @@ public abstract class AbstractSnmpTargetHandlerTest extends JavaTest {
if (refresh) {
ArgumentCaptor pduCaptor = ArgumentCaptor.forClass(PDU.class);
verify(snmpService, timeout(500).atLeast(1)).send(pduCaptor.capture(), any(), eq(null), eq(thingHandler));
- Vector extends VariableBinding> variables = pduCaptor.getValue().getVariableBindings();
- assertTrue(variables.stream().filter(v -> v.getOid().toDottedString().equals(TEST_OID)).findFirst()
- .isPresent());
+ List extends VariableBinding> variables = pduCaptor.getValue().getVariableBindings();
+ assertTrue(variables.stream().anyMatch(v -> v.getOid().toDottedString().equals(TEST_OID)));
} else {
verify(snmpService, never()).send(any(), any(), eq(null), eq(thingHandler));
}