2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.smartmeter.internal.iec62056;
15 import java.io.IOException;
16 import java.time.Duration;
17 import java.util.function.Supplier;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.smartmeter.connectors.ConnectorBase;
22 import org.openhab.binding.smartmeter.internal.helper.Baudrate;
23 import org.openhab.binding.smartmeter.internal.helper.ProtocolMode;
24 import org.openhab.core.io.transport.serial.SerialPortManager;
25 import org.openmuc.j62056.DataMessage;
26 import org.openmuc.j62056.Iec21Port;
27 import org.openmuc.j62056.Iec21Port.Builder;
28 import org.openmuc.j62056.ModeDListener;
29 import org.reactivestreams.Publisher;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
33 import io.reactivex.Flowable;
34 import io.reactivex.FlowableEmitter;
37 * This connector reads meter values with IEC62056-21 protocol.
39 * @author Matthias Steigenberger - Initial contribution
43 public class Iec62056_21SerialConnector extends ConnectorBase<DataMessage> {
45 private final Logger logger = LoggerFactory.getLogger(Iec62056_21SerialConnector.class);
47 private int baudrateChangeDelay;
48 private ProtocolMode protocolMode;
50 private Iec21Port iec21Port;
52 public Iec62056_21SerialConnector(Supplier<SerialPortManager> serialPortManagerSupplier, String portName,
53 int baudrate, int baudrateChangeDelay, ProtocolMode protocolMode) {
55 this.baudrate = baudrate;
56 this.baudrateChangeDelay = baudrateChangeDelay;
57 this.protocolMode = protocolMode;
61 protected boolean applyPeriod() {
62 return protocolMode != ProtocolMode.D;
66 protected boolean applyRetryHandling() {
67 return protocolMode != ProtocolMode.D;
71 protected Publisher<?> getRetryPublisher(Duration period, Publisher<Throwable> attempts) {
72 if (protocolMode == ProtocolMode.D) {
73 return Flowable.empty();
75 return super.getRetryPublisher(period, attempts);
80 protected DataMessage readNext(byte @Nullable [] initMessage) throws IOException {
81 if (iec21Port != null) {
82 DataMessage dataMessage = iec21Port.read();
83 logger.debug("Datamessage read: {}", dataMessage);
86 throw new IOException("SerialPort was not yet created!");
90 protected void emitValues(byte @Nullable [] initMessage, FlowableEmitter<@Nullable DataMessage> emitter)
92 switch (protocolMode) {
94 super.emitValues(initMessage, emitter);
97 if (iec21Port != null) {
98 iec21Port.listen(new ModeDListener() {
101 public void newDataMessage(@Nullable DataMessage dataMessage) {
102 logger.debug("Datamessage read: {}", dataMessage);
103 emitter.onNext(dataMessage);
107 public void exceptionWhileListening(@Nullable Exception e) {
108 logger.warn("Exception while listening for mode D data message", e);
114 throw new IOException("SML mode not supported");
119 public void openConnection() throws IOException {
120 Builder iec21Builder = new Iec21Port.Builder(getPortName());
121 if (Baudrate.fromBaudrate(this.baudrate) != Baudrate.AUTO) {
122 iec21Builder.setInitialBaudrate(this.baudrate);
124 iec21Builder.setBaudRateChangeDelay(baudrateChangeDelay);
125 iec21Builder.enableVerboseMode(true);
126 iec21Port = iec21Builder.buildAndOpen();
130 public void closeConnection() {
131 if (iec21Port != null) {