[openwebnet] Replace gnu.io dependency with serial transport (#16376)

Signed-off-by: Massimo Valla <mvcode00@gmail.com>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
M Valla 2024-02-05 18:16:03 +01:00 committed by Ciprian Pascu
parent b2737becd6
commit 17f5a069a7
7 changed files with 295 additions and 19 deletions

View File

@ -14,16 +14,12 @@
<name>openHAB Add-ons :: Bundles :: OpenWebNet (BTicino/Legrand) Binding</name> <name>openHAB Add-ons :: Bundles :: OpenWebNet (BTicino/Legrand) Binding</name>
<properties>
<bnd.importpackage>gnu.io;version="[3.12,6)"</bnd.importpackage>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>io.github.openwebnet4j</groupId> <groupId>io.github.openwebnet4j</groupId>
<artifactId>openwebnet4j</artifactId> <artifactId>openwebnet4j</artifactId>
<version>0.10.1</version> <version>0.12.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>

View File

@ -18,11 +18,11 @@ import java.util.Set;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants; import org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants;
import org.openhab.binding.openwebnet.internal.serial.SerialPortProviderAdapter;
import org.openhab.core.config.discovery.AbstractDiscoveryService; import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult; import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder; import org.openhab.core.config.discovery.DiscoveryResultBuilder;
@ -44,11 +44,14 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* The {@link UsbGatewayDiscoveryService} extends {@link AbstractDiscoveryService} to detect Zigbee USB gateways * The {@link UsbGatewayDiscoveryService} extends
* connected via serial port. The service will iterate over the available serial ports and open each one to test if a * {@link AbstractDiscoveryService} to detect Zigbee USB gateways connected via
* OpenWebNet Zigbee USB gateway is connected. On successful connection, a new DiscoveryResult is created. * serial port. The service will iterate over the available serial ports and
* open each one to test if a OpenWebNet Zigbee USB gateway is connected. On
* successful connection, a new DiscoveryResult is created.
* *
* @author Massimo Valla - Initial contribution * @author Massimo Valla - Initial contribution. Inject SerialPortManager to
* openwebnet4j lib.
*/ */
@NonNullByDefault @NonNullByDefault
@Component(service = DiscoveryService.class, configurationPid = "discovery.openwebnet") @Component(service = DiscoveryService.class, configurationPid = "discovery.openwebnet")
@ -64,6 +67,8 @@ public class UsbGatewayDiscoveryService extends AbstractDiscoveryService impleme
private @Nullable ScheduledFuture<?> connectTimeout; private @Nullable ScheduledFuture<?> connectTimeout;
private final SerialPortManager serialPortManager; private final SerialPortManager serialPortManager;
private final SerialPortProviderAdapter transportAdapter;
private @Nullable USBGateway zbGateway; private @Nullable USBGateway zbGateway;
private String currentScannedPortName = ""; private String currentScannedPortName = "";
@ -74,27 +79,35 @@ public class UsbGatewayDiscoveryService extends AbstractDiscoveryService impleme
private boolean scanning; private boolean scanning;
/** /**
* Constructs a new UsbGatewayDiscoveryService with the specified Zigbee USB Bridge ThingTypeUID * Constructs a new UsbGatewayDiscoveryService with the specified Zigbee USB
* Bridge ThingTypeUID
*/ */
@Activate @Activate
public UsbGatewayDiscoveryService(final @Reference SerialPortManager spm) { public UsbGatewayDiscoveryService(final @Reference SerialPortManager spm) {
super(Set.of(OpenWebNetBindingConstants.THING_TYPE_ZB_GATEWAY), DISCOVERY_TIMEOUT_SECONDS, false); super(Set.of(OpenWebNetBindingConstants.THING_TYPE_ZB_GATEWAY), DISCOVERY_TIMEOUT_SECONDS, false);
// Obtain the serial port manager service using an OSGi reference // Inject the SerialPortManager passed via @Reference into the adapter
serialPortManager = spm; serialPortManager = spm;
SerialPortProviderAdapter.setSerialPortManager(spm);
this.transportAdapter = new SerialPortProviderAdapter();
logger.debug("**** -SPI- **** Set SerialPortManager to: {}", SerialPortProviderAdapter.serialPortManager);
} }
/** /**
* Starts a new discovery scan. All available Serial Ports are scanned. * Starts a new discovery scan. All available SerialPortsIdentifiers returned by
* SerialPortManager are scanned.
*/ */
@Override @Override
protected void startScan() { protected void startScan() {
logger.debug("Started OpenWebNet Zigbee USB Gateway discovery scan"); logger.debug("Started OpenWebNet Zigbee USB Gateway discovery scan");
removeOlderResults(getTimestampOfLastScan()); removeOlderResults(getTimestampOfLastScan());
scanning = true; scanning = true;
Stream<SerialPortIdentifier> portEnum = serialPortManager.getIdentifiers();
SerialPortIdentifier[] foundSerialPortIds = serialPortManager.getIdentifiers()
.toArray(SerialPortIdentifier[]::new);
// Check each available serial port // Check each available serial port
try { try {
for (SerialPortIdentifier portIdentifier : portEnum.toArray(SerialPortIdentifier[]::new)) { for (SerialPortIdentifier portIdentifier : foundSerialPortIds) {
if (scanning) { if (scanning) {
currentScannedPortName = portIdentifier.getName(); currentScannedPortName = portIdentifier.getName();
logger.debug("[{}] == checking serial port", currentScannedPortName); logger.debug("[{}] == checking serial port", currentScannedPortName);
@ -104,6 +117,7 @@ public class UsbGatewayDiscoveryService extends AbstractDiscoveryService impleme
} else { } else {
logger.debug("[{}] trying to connect to a Zigbee USB Gateway...", currentScannedPortName); logger.debug("[{}] trying to connect to a Zigbee USB Gateway...", currentScannedPortName);
USBGateway gw = new USBGateway(currentScannedPortName); USBGateway gw = new USBGateway(currentScannedPortName);
gw.setSerialPortProvider(transportAdapter);
zbGateway = gw; zbGateway = gw;
gw.subscribe(this); gw.subscribe(this);
portCheckLatch = new CountDownLatch(1); portCheckLatch = new CountDownLatch(1);

View File

@ -32,6 +32,7 @@ import org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants;
import org.openhab.binding.openwebnet.internal.discovery.OpenWebNetDeviceDiscoveryService; import org.openhab.binding.openwebnet.internal.discovery.OpenWebNetDeviceDiscoveryService;
import org.openhab.binding.openwebnet.internal.handler.config.OpenWebNetBusBridgeConfig; import org.openhab.binding.openwebnet.internal.handler.config.OpenWebNetBusBridgeConfig;
import org.openhab.binding.openwebnet.internal.handler.config.OpenWebNetZigBeeBridgeConfig; import org.openhab.binding.openwebnet.internal.handler.config.OpenWebNetZigBeeBridgeConfig;
import org.openhab.binding.openwebnet.internal.serial.SerialPortProviderAdapter;
import org.openhab.core.config.core.status.ConfigStatusMessage; import org.openhab.core.config.core.status.ConfigStatusMessage;
import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.ChannelUID;
@ -179,7 +180,11 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
"@text/offline.conf-error-no-serial-port"); "@text/offline.conf-error-no-serial-port");
return null; return null;
} else { } else {
return new USBGateway(serialPort); USBGateway tmpUSBGateway = new USBGateway(serialPort);
tmpUSBGateway.setSerialPortProvider(new SerialPortProviderAdapter());
logger.debug("**** -SPI- **** OpenWebNetBridgeHandler :: setSerialPortProvider to: {}",
tmpUSBGateway.getSerialPortProvider());
return tmpUSBGateway;
} }
} }

View File

@ -385,8 +385,7 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
* *
* @param channelId the channelId string * @param channelId the channelId string
**/ **/
@Nullable private String toWhere(String channelId) throws OWNException {
private String toWhere(String channelId) {
Where w = deviceWhere; Where w = deviceWhere;
if (w != null) { if (w != null) {
OpenWebNetBridgeHandler brH = bridgeHandler; OpenWebNetBridgeHandler brH = bridgeHandler;
@ -400,6 +399,6 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
} }
} }
} }
return null; throw new OWNException("Cannot select channel from WHERE " + w);
} }
} }

View File

@ -0,0 +1,145 @@
/**
* Copyright (c) 2010-2024 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.openwebnet.internal.serial;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.TooManyListenersException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.io.transport.serial.PortInUseException;
import org.openhab.core.io.transport.serial.SerialPort;
import org.openhab.core.io.transport.serial.SerialPortEvent;
import org.openhab.core.io.transport.serial.SerialPortEventListener;
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
import org.openhab.core.io.transport.serial.UnsupportedCommOperationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* openwebnet4j SerialPort implementation based on OH serial transport
*
* @author M. Valla - Initial contribution
*/
@NonNullByDefault
public class SerialPortAdapter implements org.openwebnet4j.communication.serial.spi.SerialPort {
private static final Logger logger = LoggerFactory.getLogger(SerialPortAdapter.class);
private static final int OPEN_TIMEOUT_MS = 200;
private final SerialPortIdentifier spid;
private @Nullable SerialPort sp = null;
public SerialPortAdapter(final SerialPortIdentifier spid) {
this.spid = spid;
}
@Override
public boolean setSerialPortParams(int baudrate, int dataBits, int stopBits, int parity) {
@Nullable
SerialPort lsp = sp;
if (lsp != null) {
try {
lsp.setSerialPortParams(baudrate, dataBits, stopBits, parity);
return true;
} catch (UnsupportedCommOperationException e) {
logger.error("UnsupportedCommOperationException while setting port params in setSerialPortParams: {}",
e.getMessage());
return false;
}
}
return false;
}
@Override
public boolean addEventListener(org.openwebnet4j.communication.serial.spi.SerialPortEventListener listener) {
@Nullable
SerialPort lsp = sp;
if (lsp != null) {
try {
lsp.addEventListener(new SerialPortEventListener() {
@Override
public void serialEvent(SerialPortEvent event) {
if (event != null) {
listener.serialEvent(new SerialPortEventAdapter(event));
}
}
});
lsp.notifyOnDataAvailable(true);
return true;
} catch (TooManyListenersException e) {
logger.error("TooManyListenersException while adding event listener: {}", e.getMessage());
}
}
return false;
}
@Override
public boolean open() {
try {
sp = spid.open(this.getClass().getName(), OPEN_TIMEOUT_MS);
} catch (PortInUseException e) {
logger.error("PortInUseException while opening serial port {}: {}", spid.getName(), e.getMessage());
return false;
}
return true;
}
@Override
public @Nullable String getName() {
@Nullable
SerialPort lsp = sp;
if (lsp != null) {
return lsp.getName();
} else {
return null;
}
}
@Override
public @Nullable InputStream getInputStream() throws IOException {
@Nullable
SerialPort lsp = sp;
if (lsp != null) {
return lsp.getInputStream();
} else {
return null;
}
}
@Override
public @Nullable OutputStream getOutputStream() throws IOException {
@Nullable
SerialPort lsp = sp;
if (lsp != null) {
return lsp.getOutputStream();
} else {
return null;
}
}
@Override
public void close() {
@Nullable
SerialPort lsp = sp;
if (lsp != null) {
lsp.close();
}
}
}

View File

@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2024 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.openwebnet.internal.serial;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openwebnet4j.communication.serial.spi.SerialPortEvent;
/**
* openwebnet4j SerialPortEvent implementation based on OH serial transport
*
* @author M. Valla - Initial contribution
*/
@NonNullByDefault
public class SerialPortEventAdapter implements SerialPortEvent {
private final org.openhab.core.io.transport.serial.SerialPortEvent event;
/**
* Constructor.
*
* @param event the underlying event implementation
*/
public SerialPortEventAdapter(org.openhab.core.io.transport.serial.SerialPortEvent event) {
this.event = event;
}
@Override
public int getEventType() {
if (event.getEventType() == org.openhab.core.io.transport.serial.SerialPortEvent.PORT_DISCONNECTED) {
return SerialPortEvent.EVENT_PORT_DISCONNECTED;
} else if (event.getEventType() == org.openhab.core.io.transport.serial.SerialPortEvent.DATA_AVAILABLE) {
return SerialPortEvent.EVENT_DATA_AVAILABLE;
} else {
return event.getEventType();
}
}
}

View File

@ -0,0 +1,69 @@
/**
* Copyright (c) 2010-2024 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.openwebnet.internal.serial;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openwebnet4j.communication.serial.spi.SerialPort;
import org.openwebnet4j.communication.serial.spi.SerialPortProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import aQute.bnd.annotation.spi.ServiceProvider;
/**
* openwebnet4j SerialPortProvider implementation based on OH serial transport
*
* @author M. Valla - Initial contribution
*/
@ServiceProvider(value = SerialPortProvider.class)
@NonNullByDefault
public class SerialPortProviderAdapter implements SerialPortProvider {
private Logger logger = LoggerFactory.getLogger(SerialPortProviderAdapter.class);
@Nullable
public static SerialPortManager serialPortManager = null;
public static void setSerialPortManager(SerialPortManager serialPortManager) {
SerialPortProviderAdapter.serialPortManager = serialPortManager;
}
@Override
public @Nullable SerialPort getSerialPort(String portName) {
final @Nullable SerialPortManager spm = serialPortManager;
if (spm == null) {
return null;
}
SerialPortIdentifier spid = spm.getIdentifier(portName);
if (spid == null) {
logger.debug("No SerialPort {} found", portName);
return null;
} else {
return new SerialPortAdapter(spid);
}
}
@Override
public Stream<SerialPort> getSerialPorts() {
final @Nullable SerialPortManager spm = serialPortManager;
if (spm == null) {
return Stream.empty();
}
return spm.getIdentifiers().map(sid -> new SerialPortAdapter(sid));
}
}