[proteusecometer] Proteus Eco Meter Binding - Initial contribution (#11333)

* Proteus Eco Meter Binding

Signed-off-by: Matthias Herrmann <matthias.mh.herrmann@gmail.com>

* Fulfil some conventions and choose better tradeoffs

Signed-off-by: Matthias Herrmann <matthias.mh.herrmann@gmail.com>

* Patch shell script in another PR

Signed-off-by: Matthias Herrmann <matthias.mh.herrmann@gmail.com>

* Move 4 lines into another PR

Signed-off-by: Matthias Herrmann <matthias.mh.herrmann@gmail.com>

* Improvements

Signed-off-by: Matthias Herrmann <matthias.mh.herrmann@gmail.com>

* File based doc

Signed-off-by: Matthias Herrmann <matthias.mh.herrmann@gmail.com>

* Rename identifiers

Signed-off-by: Matthias Herrmann <matthias.mh.herrmann@gmail.com>

* Changed identifier

Signed-off-by: Matthias Herrmann <matthias.mh.herrmann@gmail.com>

* Uniformed unit pattern

Signed-off-by: Matthias Herrmann <matthias.mh.herrmann@gmail.com>
This commit is contained in:
Matthias Herrmann 2021-10-23 11:27:13 +02:00 committed by GitHub
parent 8337f8b92d
commit d2e6780140
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 770 additions and 0 deletions

View File

@ -240,6 +240,7 @@
/bundles/org.openhab.binding.plugwise/ @wborn
/bundles/org.openhab.binding.plugwiseha/ @lsiepel
/bundles/org.openhab.binding.powermax/ @lolodomo
/bundles/org.openhab.binding.proteusecometer/ @2chilled
/bundles/org.openhab.binding.pulseaudio/ @peuter
/bundles/org.openhab.binding.pushbullet/ @hakan42
/bundles/org.openhab.binding.pushover/ @cweitkamp

View File

@ -1181,6 +1181,11 @@
<artifactId>org.openhab.binding.powermax</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.proteusecometer</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.pulseaudio</artifactId>

View File

@ -0,0 +1,20 @@
This content is produced and maintained by the openHAB project.
* Project home: https://www.openhab.org
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/openhab/openhab-addons
== Third-party Content
jSerialComm
* License: Apache 2.0 License
* Project: https://github.com/Fazecast/jSerialComm
* Source: https://github.com/Fazecast/jSerialComm

View File

@ -0,0 +1,52 @@
# ProteusEcoMeter Binding
This is the binding for the Proteus EcoMeter S, which is able to report the level of a cistern or tank.
Note that this binding currently supports no write channels.
This means you have to configure your sensor by considering the manual of the product (using wireless display).
After doing that the binding comes into play and helps you to get your measured values into openHAB.
Please be patient while waiting for the first received data.
The sensor reports at an interval of approx. 1h, except when the water level changes relatively fast.
## Supported Things
Proteus EcoMeter S.
The binding has been tested with this EcoMeter sensor only.
## Discovery
No auto discovery implemented yet.
## Thing Configuration
Plug the wireless display into an USB port.
Note [openHAB Serial Port documentation](https://www.openhab.org/docs/administration/serial.html) for general serial port configuration.
After that you can add the device as thing and configure the usbPort your OS generated for the display.
```
UID: proteusecometer:EcoMeterS:e90705eaa4
label: Proteus EcoMeter S
thingTypeUID: proteusecometer:EcoMeterS
configuration:
usbPort: /dev/ttyUSB0
```
## Channels
| channel | type | description |
|-----------------------|----------------------|------------------------------------------------------|
| temperature | Number:Temperature | Temperature measured by the sensor |
| sensorLevel | Number:Length | Distance between sensor and water surface |
| usableLevel | Number:Volume | How much liquid is usable |
| usableLevelInPercent | Number:Dimensionless | How much liquid is usable relative to total capacity |
| totalCapacity | Number:Volume | Total capacity of measured cistern/tank |
## Full Example
Thing proteusecometer:EcoMeterS:e90705eaa4 "Proteus EcoMeter S" [ usbPort="/dev/ttyUSB0" ]
Number:Temperature Temperature "Measured temperature [%.1f °C]" { channel="proteusecometer:EcoMeterS:e90705eaa4:temperature" }
Number:Length SensorLevelCm "Sensor Level" { channel="proteusecometer:EcoMeterS:e90705eaa4:sensorLevel" }
Number:Volume UsableLevel "Usable Level" { channel="proteusecometer:EcoMeterS:e90705eaa4:usableLevel" }
Number:Dimensionless UsableLevelinpercent "Usable Level" { channel="proteusecometer:EcoMeterS:e90705eaa4:usableLevelInPercent" }
Number:Volume TotalCapacityinliter "Total Capacity" { channel="proteusecometer:EcoMeterS:e90705eaa4:totalCapacity" }

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>3.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.proteusecometer</artifactId>
<name>openHAB Add-ons :: Bundles :: ProteusEcoMeter Binding</name>
<dependencies>
<dependency>
<groupId>com.fazecast</groupId>
<artifactId>jSerialComm</artifactId>
<version>2.7.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.proteusecometer-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-proteusecometer" description="ProteusEcoMeter Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.proteusecometer/${project.version}</bundle>
</feature>
</features>

View File

@ -0,0 +1,41 @@
/**
* Copyright (c) 2010-2021 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.proteusecometer.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link ProteusEcoMeterBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Matthias Herrmann - Initial contribution
*/
@NonNullByDefault
public class ProteusEcoMeterBindingConstants {
private static final String BINDING_ID = "proteusecometer";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_ECO_METER_S = new ThingTypeUID(BINDING_ID, "EcoMeterS");
public static final String TEMPERATURE = "temperature";
public static final String SENSOR_LEVEL = "sensorLevel";
public static final String USABLE_LEVEL = "usableLevel";
public static final String USABLE_LEVEL_IN_PERCENT = "usableLevelInPercent";
public static final String TOTAL_CAPACITY = "totalCapacity";
}

View File

@ -0,0 +1,25 @@
/**
* Copyright (c) 2010-2021 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.proteusecometer.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link ProteusEcoMeterConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Matthias Herrmann - Initial contribution
*/
@NonNullByDefault
public class ProteusEcoMeterConfiguration {
public String usbPort = "";
}

View File

@ -0,0 +1,65 @@
/**
* Copyright (c) 2010-2021 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.proteusecometer.internal;
import static org.openhab.binding.proteusecometer.internal.ProteusEcoMeterBindingConstants.THING_TYPE_ECO_METER_S;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.proteusecometer.internal.ecometers.handler.ProteusEcoMeterSHandler;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link ProteusEcoMeterHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Matthias Herrmann - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.proteusecometer", service = ThingHandlerFactory.class)
public class ProteusEcoMeterHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_ECO_METER_S);
private final Logger logger = LoggerFactory.getLogger(ProteusEcoMeterHandlerFactory.class);
@Activate
public ProteusEcoMeterHandlerFactory() {
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (THING_TYPE_ECO_METER_S.equals(thingTypeUID)) {
logger.trace("Creating ProteusEcoMeterSHandler");
return new ProteusEcoMeterSHandler(thing);
}
return null;
}
}

View File

@ -0,0 +1,30 @@
/**
* Copyright (c) 2010-2021 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.proteusecometer.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Allows you to transform an {@link Exception} to {@link RuntimeException} to circumvent checked exception
* issues.
*
* @author Matthias Herrmann - Initial contribution
*/
@NonNullByDefault
public class WrappedException extends RuntimeException {
private static final long serialVersionUID = 1L;
public WrappedException(final Exception wrapped) {
super(wrapped);
}
}

View File

@ -0,0 +1,76 @@
/**
* Copyright (c) 2010-2021 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.proteusecometer.internal.ecometers;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Parse the bytes from the device
*
* @author Matthias Herrmann - Initial contribution
*
*/
@NonNullByDefault
class ProteusEcoMeterSParser {
private final Logger logger = LoggerFactory.getLogger(ProteusEcoMeterSParser.class);
/**
* @param bytes Raw bytes send from the device
* @return A structured version of the bytes, if possible
*/
public Optional<ProteusEcoMeterSReply> parseFromBytes(final byte[] bytes) {
return Optional.ofNullable(bytes).flatMap(b -> {
final String hexString = HexUtils.bytesToHex(b);
logger.trace("Received hex string: {}", hexString);
if (hexString.length() < 4) {
return Optional.empty();
} else {
final String marker = hexString.substring(0, 4);
if (!"5349".equals(marker)) {
logger.trace("Marker is not {} but {}", "5349", marker);
return Optional.empty();
} else if (hexString.length() < 40) {
logger.trace("hexString is of length {}, expected >= 40", hexString.length());
return Optional.empty();
} else {
try {
return Optional
.of(new ProteusEcoMeterSReply(parseInt(hexString.substring(26, 28), "tempInFahrenheit"),
parseInt(hexString.substring(28, 32), "sensorLevelInCm"),
parseInt(hexString.substring(32, 36), "usableLevelInLiter"),
parseInt(hexString.substring(36, 40), "totalCapacityInLiter")));
} catch (final NumberFormatException e) {
logger.debug("Error while parsing numbers", e);
return Optional.empty();
}
}
}
});
}
private Integer parseInt(final String toParse, final String fieldName) throws NumberFormatException {
try {
return Integer.parseInt(toParse, 16);
} catch (final NumberFormatException e) {
logger.trace("Unable to parse field {}", fieldName, e);
throw e;
}
}
}

View File

@ -0,0 +1,43 @@
/**
* Copyright (c) 2010-2021 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.proteusecometer.internal.ecometers;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The reply of Proteus EcoMeter S
*
* @author Matthias Herrmann - Initial contribution
*
*/
@NonNullByDefault
public class ProteusEcoMeterSReply {
public final double tempInFahrenheit;
public final int sensorLevelInCm;
public final int usableLevelInLiter;
public final int totalCapacityInLiter;
public ProteusEcoMeterSReply(final double tempInFahrenheit, final int sensorLevelInCm, final int usableLevelInLiter,
final int totalCapacityInLiter) {
this.tempInFahrenheit = tempInFahrenheit;
this.sensorLevelInCm = sensorLevelInCm;
this.usableLevelInLiter = usableLevelInLiter;
this.totalCapacityInLiter = totalCapacityInLiter;
}
@Override
public String toString() {
return "ProteusEcoMeterSReply [sensorLevelInCm=" + sensorLevelInCm + ", tempInFahrenheit=" + tempInFahrenheit
+ ", totalCapacityInLiter=" + totalCapacityInLiter + ", usableLevelInLiter=" + usableLevelInLiter + "]";
}
}

View File

@ -0,0 +1,78 @@
/**
* Copyright (c) 2010-2021 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.proteusecometer.internal.ecometers;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.proteusecometer.internal.WrappedException;
import org.openhab.binding.proteusecometer.internal.serialport.SerialPortService;
import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Read from Proteus EcoMeter S
*
* @author Matthias Herrmann - Initial contribution
*
*/
@NonNullByDefault
public class ProteusEcoMeterSService {
private final Logger logger = LoggerFactory.getLogger(ProteusEcoMeterSService.class);
/**
* Initialize the communication with the device, i.e. open the serial port etc.
*
* @return {@code true} if we can communicate with the device
* @throws IOException
*/
public Stream<ProteusEcoMeterSReply> read(final String portId, final SerialPortService serialPort)
throws IOException {
logger.trace("communicate");
final InputStream inputStream = serialPort.getInputStream(portId, 115200, 8, 1, 0);
final Supplier<Optional<ProteusEcoMeterSReply>> supplier = () -> {
logger.trace("Input stream opened for the port");
try {
final byte[] deviceBytes = new byte[22];
inputStream.read(deviceBytes, 0, 22);
final String hexString = HexUtils.bytesToHex(deviceBytes);
logger.trace("Received hex string: {}", hexString);
final ProteusEcoMeterSParser parser = new ProteusEcoMeterSParser();
final Optional<ProteusEcoMeterSReply> dataOpt = parser.parseFromBytes(deviceBytes);
if (dataOpt.isEmpty()) {
logger.warn("Received bytes I don't understand: {}", hexString);
}
return dataOpt;
} catch (final IOException e) {
throw new WrappedException(e);
} finally {
try {
inputStream.close();
} catch (final IOException e) {
}
}
};
return Stream.generate(supplier).takeWhile(reply -> !Thread.interrupted()).filter(Optional::isPresent)
.map(Optional::get);
}
}

View File

@ -0,0 +1,149 @@
/**
* Copyright (c) 2010-2021 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.proteusecometer.internal.ecometers.handler;
import static org.openhab.binding.proteusecometer.internal.ProteusEcoMeterBindingConstants.*;
import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
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.proteusecometer.internal.ProteusEcoMeterConfiguration;
import org.openhab.binding.proteusecometer.internal.WrappedException;
import org.openhab.binding.proteusecometer.internal.ecometers.ProteusEcoMeterSReply;
import org.openhab.binding.proteusecometer.internal.ecometers.ProteusEcoMeterSService;
import org.openhab.binding.proteusecometer.internal.serialport.SerialPortService;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.MetricPrefix;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fazecast.jSerialComm.SerialPort;
/**
* The {@link ProteusEcoMeterSHandler} updates thing channels when receiving data
*
* @author Matthias Herrmann - Initial contribution
*/
@NonNullByDefault
public class ProteusEcoMeterSHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(ProteusEcoMeterSHandler.class);
private @Nullable SerialPort serialPort;
private ProteusEcoMeterConfiguration config = new ProteusEcoMeterConfiguration();
private @Nullable ScheduledFuture<?> job;
private SerialPortService serialPortService = new SerialPortService() {
@NonNullByDefault
public InputStream getInputStream(String portId, int baudRate, int numDataBits, int numStopBits, int parity) {
try {
ProteusEcoMeterSHandler.this.serialPort = SerialPort.getCommPort(portId);
final SerialPort localSerialPort = ProteusEcoMeterSHandler.this.serialPort;
if (localSerialPort == null) {
throw new IOException("SerialPort.getCommPort(" + portId + ") returned null");
}
localSerialPort.closePort();
localSerialPort.setBaudRate(baudRate);
localSerialPort.setNumDataBits(numDataBits);
localSerialPort.setNumStopBits(numStopBits);
localSerialPort.setParity(parity);
localSerialPort.openPort();
localSerialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 0, 0);
final InputStream inputStream = localSerialPort.getInputStream();
if (inputStream == null) {
throw new IOException("serialPort.getInputStream() returned null");
}
return inputStream;
} catch (final Exception e) {
closeSerialPort();
throw new WrappedException(e);
}
}
};
public ProteusEcoMeterSHandler(final Thing thing) {
super(thing);
}
@Override
public void initialize() {
config = getConfigAs(ProteusEcoMeterConfiguration.class);
updateStatus(ThingStatus.UNKNOWN);
job = scheduler.schedule(() -> handleDeviceReplies(), 0, TimeUnit.SECONDS);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
// at the moment there are no commands supported. The Eco Meter S would support configuration
// commands, but this is not implemented yet
}
@Override
public void dispose() {
super.dispose();
closeSerialPort();
final ScheduledFuture<?> localJob = job;
if (localJob != null) {
localJob.cancel(true);
job = null;
}
}
private void handleDeviceReplies() {
final Duration retryInitDelay = Duration.ofSeconds(10);
try {
final ProteusEcoMeterSService ecoMeterSService = new ProteusEcoMeterSService();
final Stream<ProteusEcoMeterSReply> replyStream = ecoMeterSService.read(config.usbPort, serialPortService);
updateStatus(ThingStatus.ONLINE);
replyStream.forEach(reply -> {
updateState(SENSOR_LEVEL, new QuantityType<>(reply.sensorLevelInCm, MetricPrefix.CENTI(SIUnits.METRE)));
updateState(USABLE_LEVEL, new QuantityType<>(reply.usableLevelInLiter, Units.LITRE));
updateState(USABLE_LEVEL_IN_PERCENT, new QuantityType<>(
100d / reply.totalCapacityInLiter * reply.usableLevelInLiter, Units.PERCENT));
updateState(TEMPERATURE, new QuantityType<>(reply.tempInFahrenheit, ImperialUnits.FAHRENHEIT));
updateState(TOTAL_CAPACITY, new QuantityType<>(reply.totalCapacityInLiter, Units.LITRE));
});
logger.debug("The reply stream ended unexpectedly. Retrying in {}", retryInitDelay);
} catch (final Exception e) {
logger.debug("Error communicating with eco meter s. Retrying in {}", retryInitDelay, e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
"Error reading from Port: " + e.getMessage());
} finally {
closeSerialPort();
job = scheduler.schedule(this::handleDeviceReplies, retryInitDelay.getSeconds(), TimeUnit.SECONDS);
}
}
private void closeSerialPort() {
if (serialPort != null) {
final boolean closed = serialPort.closePort();
logger.debug("serialPort.closePort() returned {}", closed);
serialPort = null;
}
}
}

View File

@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2021 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.proteusecometer.internal.serialport;
import java.io.InputStream;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Abstract over serial port implementations
*
* @author Matthias Herrmann - Initial contribution
*
*/
@NonNullByDefault
public interface SerialPortService {
public InputStream getInputStream(String portId, int baudRate, int numDataBits, int numStopBits, int parity);
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="proteusecometer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>Proteus EcoMeter</name>
<description>Puts your EcoMeter data into openHAB</description>
</binding:binding>

View File

@ -0,0 +1,24 @@
# binding
binding.proteusecometer.name = Proteus EcoMeter
binding.proteusecometer.description = Puts your EcoMeter data into openHAB
# thing types
thing-type.proteusecometer.EcoMeterS.label = Proteus EcoMeter S
thing-type.proteusecometer.EcoMeterS.description = Sensor for measuring water level of a cistern. Connected via USB
thing-type.config.proteusecometer.EcoMeterS.usbPort.label = USB Port
thing-type.config.proteusecometer.EcoMeterS.usbPort.description = USB port the device is connected to i.e. /dev/ttyUSB0
# channel types
channel-type.proteusecometer.Temperature.label = Temperature
channel-type.proteusecometer.Temperature.description = Temperature measured by the sensor
channel-type.proteusecometer.SensorLevel.label = Sensor Level
channel-type.proteusecometer.SensorLevel.description = The distance between the sensor and the water surface
channel-type.proteusecometer.UsableLevel.label = Usable Level in litre
channel-type.proteusecometer.UsableLevel.description = The usable level in litre
channel-type.proteusecometer.UsableLevelInPercent.label = Usable Level in percent
channel-type.proteusecometer.UsableLevelInPercent.description = The usable level in percent
channel-type.proteusecometer.TotalCapacity.label = Total Capacity
channel-type.proteusecometer.TotalCapacity.description = The total capacity of your cistern/tank

View File

@ -0,0 +1,24 @@
# binding
binding.proteusecometer.name = Proteus EcoMeter
binding.proteusecometer.description = EcoMeter Sensordaten in openHAB
# thing types
thing-type.proteusecometer.EcoMeterS.label = Proteus EcoMeter S
thing-type.proteusecometer.EcoMeterS.description = Füllstandsanzeige für Zisterne, Wassertanks, Erdtanks
thing-type.config.proteusecometer.EcoMeterS.usbPort.label = USB Port
thing-type.config.proteusecometer.EcoMeterS.usbPort.description = USB Port des Geräts, z.B. /dev/ttyUSB0
# channel types
channel-type.proteusecometer.Temperature.label = Temperatur
channel-type.proteusecometer.Temperature.description = Umgebungstemperatur des Sensors
channel-type.proteusecometer.SensorLevel.label = Sensorhöhe
channel-type.proteusecometer.SensorLevel.description = Sensorhöhe über Flüssigkeitsoberfläche
channel-type.proteusecometer.UsableLevel.label = Füllmenge in Liter
channel-type.proteusecometer.UsableLevel.description = Füllmenge in Liter
channel-type.proteusecometer.UsableLevelInPercent.label = Füllmenge in Prozent
channel-type.proteusecometer.UsableLevelInPercent.description = Füllmenge in Prozent
channel-type.proteusecometer.TotalCapacity.label = Gesamtkapazität
channel-type.proteusecometer.TotalCapacity.description = Gesamtkapazität des Messobjekts

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="proteusecometer"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="EcoMeterS">
<label>Proteus EcoMeter S</label>
<description>Sensor for measuring water level of a cistern. Connected via USB</description>
<channels>
<channel id="temperature" typeId="Temperature"/>
<channel id="sensorLevel" typeId="SensorLevel"/>
<channel id="usableLevel" typeId="UsableLevel"/>
<channel id="usableLevelInPercent" typeId="UsableLevelInPercent"/>
<channel id="totalCapacity" typeId="TotalCapacity"/>
</channels>
<config-description>
<parameter name="usbPort" type="text" required="true">
<context>serial-port</context>
<label>USB Port</label>
<description>USB port the device is connected to i.e. /dev/ttyUSB0</description>
</parameter>
</config-description>
</thing-type>
<channel-type id="Temperature">
<item-type>Number:Temperature</item-type>
<label>Temperature</label>
<description>Temperature measured by the sensor</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="SensorLevel">
<item-type>Number:Length</item-type>
<label>Sensor Level</label>
<description>The distance between the sensor and the water surface</description>
<state readOnly="true" pattern="%d %unit%"/>
</channel-type>
<channel-type id="UsableLevel">
<item-type>Number:Volume</item-type>
<label>Usable Level in litre</label>
<description>The usable level in litre</description>
<state readOnly="true" pattern="%d %unit%"/>
</channel-type>
<channel-type id="UsableLevelInPercent">
<item-type>Number:Dimensionless</item-type>
<label>Usable Level in percent</label>
<description>The usable level in percent</description>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="TotalCapacity">
<item-type>Number:Volume</item-type>
<label>Total Capacity</label>
<description>The total capacity of your cistern/tank</description>
<state readOnly="true" pattern="%d %unit%"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -272,6 +272,7 @@
<module>org.openhab.binding.plugwise</module>
<module>org.openhab.binding.plugwiseha</module>
<module>org.openhab.binding.powermax</module>
<module>org.openhab.binding.proteusecometer</module>
<module>org.openhab.binding.pulseaudio</module>
<module>org.openhab.binding.pushbullet</module>
<module>org.openhab.binding.pushover</module>