Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 7 commits into from
Feb 5, 2024
6 changes: 1 addition & 5 deletions bundles/org.openhab.binding.openwebnet/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,12 @@

<name>openHAB Add-ons :: Bundles :: OpenWebNet (BTicino/Legrand) Binding</name>

<properties>
<bnd.importpackage>gnu.io;version="[3.12,6)"</bnd.importpackage>
</properties>

<dependencies>

<dependency>
<groupId>io.github.openwebnet4j</groupId>
<artifactId>openwebnet4j</artifactId>
<version>0.10.1</version>
<version>0.12.0</version>
<scope>compile</scope>
</dependency>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
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.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
Expand All @@ -44,11 +44,14 @@
import org.slf4j.LoggerFactory;

/**
* The {@link UsbGatewayDiscoveryService} extends {@link AbstractDiscoveryService} to detect Zigbee USB gateways
* connected via 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.
* The {@link UsbGatewayDiscoveryService} extends
* {@link AbstractDiscoveryService} to detect Zigbee USB gateways connected via
* 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
@Component(service = DiscoveryService.class, configurationPid = "discovery.openwebnet")
Expand All @@ -64,6 +67,8 @@ public class UsbGatewayDiscoveryService extends AbstractDiscoveryService impleme
private @Nullable ScheduledFuture<?> connectTimeout;

private final SerialPortManager serialPortManager;
private final SerialPortProviderAdapter transportAdapter;

private @Nullable USBGateway zbGateway;

private String currentScannedPortName = "";
Expand All @@ -74,27 +79,35 @@ public class UsbGatewayDiscoveryService extends AbstractDiscoveryService impleme
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
public UsbGatewayDiscoveryService(final @Reference SerialPortManager spm) {
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;
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
protected void startScan() {
logger.debug("Started OpenWebNet Zigbee USB Gateway discovery scan");
removeOlderResults(getTimestampOfLastScan());
scanning = true;
Stream<SerialPortIdentifier> portEnum = serialPortManager.getIdentifiers();

SerialPortIdentifier[] foundSerialPortIds = serialPortManager.getIdentifiers()
.toArray(SerialPortIdentifier[]::new);

// Check each available serial port
try {
for (SerialPortIdentifier portIdentifier : portEnum.toArray(SerialPortIdentifier[]::new)) {
for (SerialPortIdentifier portIdentifier : foundSerialPortIds) {
if (scanning) {
currentScannedPortName = portIdentifier.getName();
logger.debug("[{}] == checking serial port", currentScannedPortName);
Expand All @@ -104,6 +117,7 @@ protected void startScan() {
} else {
logger.debug("[{}] trying to connect to a Zigbee USB Gateway...", currentScannedPortName);
USBGateway gw = new USBGateway(currentScannedPortName);
gw.setSerialPortProvider(transportAdapter);
zbGateway = gw;
gw.subscribe(this);
portCheckLatch = new CountDownLatch(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
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.OpenWebNetZigBeeBridgeConfig;
import org.openhab.binding.openwebnet.internal.serial.SerialPortProviderAdapter;
import org.openhab.core.config.core.status.ConfigStatusMessage;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
Expand Down Expand Up @@ -179,7 +180,11 @@ public void initialize() {
"@text/offline.conf-error-no-serial-port");
return null;
} else {
return new USBGateway(serialPort);
USBGateway tmpUSBGateway = new USBGateway(serialPort);
tmpUSBGateway.setSerialPortProvider(new SerialPortProviderAdapter());
logger.debug("**** -SPI- **** OpenWebNetBridgeHandler :: setSerialPortProvider to: {}",
tmpUSBGateway.getSerialPortProvider());
return tmpUSBGateway;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,7 @@ protected Where buildBusWhere(String wStr) throws IllegalArgumentException {
*
* @param channelId the channelId string
**/
@Nullable
private String toWhere(String channelId) {
private String toWhere(String channelId) throws OWNException {
Where w = deviceWhere;
if (w != null) {
OpenWebNetBridgeHandler brH = bridgeHandler;
Expand All @@ -400,6 +399,6 @@ private String toWhere(String channelId) {
}
}
}
return null;
throw new OWNException("Cannot select channel from WHERE " + w);
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
}