From a5056e1c3e0b2453c8c49920baf4382c0bc8d9ba Mon Sep 17 00:00:00 2001 From: Kai Neuhaus Date: Sat, 20 Jan 2024 09:16:23 +0100 Subject: [PATCH 01/21] [kermi] Initial working state Signed-off-by: Kai Neuhaus --- bom/openhab-addons/pom.xml | 5 + .../org.openhab.binding.modbus.kermi/pom.xml | 25 ++ .../kermi/internal/KermiBindingConstants.java | 36 ++ .../kermi/internal/KermiConfiguration.java | 26 ++ .../kermi/internal/KermiHandlerFactory.java | 47 +++ .../kermi/internal/dto/DataConverter.java | 64 +++ .../modbus/kermi/internal/dto/StateDTO.java | 64 +++ .../handler/KermiXcenterThingHandler.java | 392 ++++++++++++++++++ .../modbus/kermi/internal/modbus/Data.java | 28 ++ .../internal/modbus/KermiModbusConstans.java | 56 +++ .../modbus/kermi/internal/modbus/Parser.java | 107 +++++ .../resources/OH-INF/i18n/kermi.properties | 129 ++++++ .../resources/OH-INF/i18n/kermi_de.properties | 81 ++++ .../OH-INF/thing/bridge-kermi-xcenter.xml | 23 + .../thing/xcenter-state-channel-groups.xml | 15 + .../thing/xcenter-state-channel-types.xml | 21 + .../kermi/internal/dto/StateDTOTest.java | 34 ++ bundles/pom.xml | 1 + 18 files changed, 1154 insertions(+) create mode 100644 bundles/org.openhab.binding.modbus.kermi/pom.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiBindingConstants.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiConfiguration.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiHandlerFactory.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/DataConverter.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/StateDTO.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/handler/KermiXcenterThingHandler.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/modbus/Data.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/modbus/KermiModbusConstans.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/modbus/Parser.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/i18n/kermi.properties create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/i18n/kermi_de.properties create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/bridge-kermi-xcenter.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-state-channel-groups.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-state-channel-types.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/test/java/org/openhab/binding/modbus/kermi/internal/dto/StateDTOTest.java diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index 3bd18dbc0ba81..567f4952b94e8 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -1141,6 +1141,11 @@ org.openhab.binding.modbus.helioseasycontrols ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.modbus.kermi + ${project.version} + org.openhab.addons.bundles org.openhab.binding.modbus.sbc diff --git a/bundles/org.openhab.binding.modbus.kermi/pom.xml b/bundles/org.openhab.binding.modbus.kermi/pom.xml new file mode 100644 index 0000000000000..8c2f0579c2512 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/pom.xml @@ -0,0 +1,25 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 4.2.0-SNAPSHOT + + + org.openhab.binding.modbus.kermi + + openHAB Add-ons :: Bundles :: Kermi Modbus Binding + + + + org.openhab.addons.bundles + org.openhab.binding.modbus + ${project.version} + provided + + + diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiBindingConstants.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiBindingConstants.java new file mode 100644 index 0000000000000..f5618aa165bac --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiBindingConstants.java @@ -0,0 +1,36 @@ +/** + * 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.modbus.kermi.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.ModbusBindingConstants; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link KermiBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Kai Neuhaus - Initial contribution + */ +@NonNullByDefault +public class KermiBindingConstants { + + private static final String BINDING_ID = ModbusBindingConstants.BINDING_ID; + + // Supported Thing Types + public static final ThingTypeUID THING_TYPE_KERMI_XCENTER = new ThingTypeUID(BINDING_ID, "kermi-xcenter"); + + // Channels for State Block + public static final String GLOBAL_STATE_CHANNEL = "global-state"; + public static final String GLOBAL_STATE_ID_CHANNEL = "global-state-id"; +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiConfiguration.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiConfiguration.java new file mode 100644 index 0000000000000..dab20b767bf1d --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiConfiguration.java @@ -0,0 +1,26 @@ +/** + * 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.modbus.kermi.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link KermiConfiguration} class contains fields mapping thing configuration parameters. + * + * @author Kai Neuhaus - Initial contribution + */ +@NonNullByDefault +public class KermiConfiguration { + + public int refresh = 5000; +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiHandlerFactory.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiHandlerFactory.java new file mode 100644 index 0000000000000..899cd1272ff28 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiHandlerFactory.java @@ -0,0 +1,47 @@ +/** + * 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.modbus.kermi.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.modbus.kermi.internal.handler.KermiXcenterThingHandler; +import org.openhab.core.thing.Bridge; +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.Component; + +/** + * The {@link KermiHandlerFactory} is responsible for creating things and thing handlers. + * + * @author Kai Neuhaus - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.kermi", service = ThingHandlerFactory.class) +public class KermiHandlerFactory extends BaseThingHandlerFactory { + @Override + public boolean supportsThingType(ThingTypeUID thingTypeUID) { + return thingTypeUID.equals(KermiBindingConstants.THING_TYPE_KERMI_XCENTER); + } + + @Override + protected @Nullable ThingHandler createHandler(Thing thing) { + ThingTypeUID thingTypeUID = thing.getThingTypeUID(); + if (KermiBindingConstants.THING_TYPE_KERMI_XCENTER.equals(thingTypeUID)) { + return new KermiXcenterThingHandler((Bridge) thing); + } // else here + return null; + } +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/DataConverter.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/DataConverter.java new file mode 100644 index 0000000000000..c311bc4a545a8 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/DataConverter.java @@ -0,0 +1,64 @@ +/** + * 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.modbus.kermi.internal.dto; + +import java.nio.charset.StandardCharsets; +import java.util.BitSet; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.io.transport.modbus.ValueBuffer; + +/** + * The {@link DataConverter} Helper class to convert bytes from modbus into desired data format + * + * @author Bernd Weymann - Initial contribution + * @author Kai Neuhaus - used for Modbus.Kermi Binding + */ +@NonNullByDefault +public class DataConverter { + + /** + * Get double value from 2 bytes with correction factor + * + * @param wrap + * @return double + */ + public static double getUDoubleValue(ValueBuffer wrap, double factor) { + return round(wrap.getUInt16() * factor, 2); + } + + public static String getString(byte[] bArray) { + return ModbusBitUtilities.extractStringFromBytes(bArray, 0, bArray.length, StandardCharsets.US_ASCII).trim(); + } + + public static int toInt(BitSet bitSet) { + int intValue = 0; + for (int bit = 0; bit < bitSet.length(); bit++) { + if (bitSet.get(bit)) { + intValue |= (1 << bit); + } + } + return intValue; + } + + public static double round(double value, int places) { + if (places < 0) { + throw new IllegalArgumentException(); + } + + long factor = (long) Math.pow(10, places); + long tmp = Math.round(value * factor); + return (double) tmp / factor; + } +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/StateDTO.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/StateDTO.java new file mode 100644 index 0000000000000..6e63eb339e7f3 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/StateDTO.java @@ -0,0 +1,64 @@ +/** + * 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.modbus.kermi.internal.dto; + +import org.openhab.binding.modbus.kermi.internal.modbus.Data; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.StringType; + +/** + * The {@link StateDTO} Data object for Kermi Xcenter State Block + * + * @author Kai Neuhaus - Initial contribution + */ +public class StateDTO implements Data { + + public StringType globalState = STATE_UNKOWN; + public DecimalType globalStateId = new DecimalType(-1); + + // State definitions + public static final StringType STATE_STANDBY = StringType.valueOf("Standby"); + public static final StringType STATE_ALARM = StringType.valueOf("Alarm"); + public static final StringType STATE_TWE = StringType.valueOf("TWE"); + public static final StringType STATE_KUEHLEN = StringType.valueOf("Kuehlen"); + public static final StringType STATE_HEIZEN = StringType.valueOf("Heizen"); + public static final StringType STATE_ABTAUUNG = StringType.valueOf("Abtauung"); + public static final StringType STATE_VORBEREITUNG = StringType.valueOf("Vorbereitung"); + public static final StringType STATE_BLOCKIERT = StringType.valueOf("Blockiert"); + public static final StringType STATE_EVU_SPERRE = StringType.valueOf("EVU Sperre"); + public static final StringType STATE_NICHT_VERFUEGBAR = StringType.valueOf("Nicht verfuegbar"); + public static final StringType STATE_UNKOWN = StringType.valueOf("Status unknown"); + public static final StringType[] STATE_ARRAY = new StringType[] { STATE_STANDBY, STATE_ALARM, STATE_TWE, + STATE_KUEHLEN, STATE_HEIZEN, STATE_ABTAUUNG, STATE_VORBEREITUNG, STATE_BLOCKIERT, STATE_EVU_SPERRE, + STATE_NICHT_VERFUEGBAR }; + + public StateDTO(byte[] bArray) { + + int status = ModbusBitUtilities.extractUInt16(bArray, 0); + + globalStateId = new DecimalType(status); + + if (status >= 0 && status < 10) { + globalState = STATE_ARRAY[status]; + } else { + globalState = STATE_UNKOWN; + } + // + // // index handling to calculate the correct start index + // ValueBuffer wrap = ValueBuffer.wrap(bArray); + // + // // int32_swap value = 4 byte + // int globalState = wrap.getUInt16(); + } +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/handler/KermiXcenterThingHandler.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/handler/KermiXcenterThingHandler.java new file mode 100644 index 0000000000000..b898f8f768a2a --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/handler/KermiXcenterThingHandler.java @@ -0,0 +1,392 @@ +/** + * 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.modbus.kermi.internal.handler; + +import static org.openhab.binding.modbus.kermi.internal.KermiBindingConstants.GLOBAL_STATE_CHANNEL; +import static org.openhab.binding.modbus.kermi.internal.KermiBindingConstants.GLOBAL_STATE_ID_CHANNEL; +import static org.openhab.binding.modbus.kermi.internal.modbus.KermiModbusConstans.STATE_POLL_REFRESH_TIME_MS; +import static org.openhab.binding.modbus.kermi.internal.modbus.KermiModbusConstans.STATE_REG_SIZE; +import static org.openhab.binding.modbus.kermi.internal.modbus.KermiModbusConstans.STATE_REG_START; + +import java.util.Optional; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.modbus.handler.EndpointNotInitializedException; +import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; +import org.openhab.binding.modbus.kermi.internal.KermiConfiguration; +import org.openhab.binding.modbus.kermi.internal.dto.StateDTO; +import org.openhab.binding.modbus.kermi.internal.modbus.Data; +import org.openhab.binding.modbus.kermi.internal.modbus.Parser; +import org.openhab.core.io.transport.modbus.AsyncModbusFailure; +import org.openhab.core.io.transport.modbus.AsyncModbusReadResult; +import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.core.io.transport.modbus.PollTask; +import org.openhab.core.thing.Bridge; +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.BaseBridgeHandler; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.types.Command; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link KermiXcenterThingHandler} Basic modbus connection to the Kermi device(s) + * + * @author Kai Neuhaus - Initial contribution + */ +@NonNullByDefault +public class KermiXcenterThingHandler extends BaseBridgeHandler { + public enum ReadStatus { + NOT_RECEIVED, + READ_SUCCESS, + READ_FAILED + } + + static final String INFO_DATA_READ_ERROR = "Information And Data Modbus Read Errors"; + static final String INFO_READ_ERROR = "Information Modbus Read Error"; + static final String DATA_READ_ERROR = "Data Modbus Read Error"; + + static final String STATE_GROUP = "xcenter-state"; + + private ChannelUID globalStateChannel; + private ChannelUID globalStateIdChannel; + // private ChannelUID globalAlarmChannel; + + // private final ArrayList listeners = new ArrayList<>(); + private final Logger logger = LoggerFactory.getLogger(KermiXcenterThingHandler.class); + private final Parser dataParser = new Parser(Data.DataType.DATA); + private ReadStatus dataRead = ReadStatus.NOT_RECEIVED; + private final Parser infoParser = new Parser(Data.DataType.INFO); + private ReadStatus infoRead = ReadStatus.NOT_RECEIVED; + private @Nullable PollTask infoPoller; + private @Nullable PollTask dataPoller; + private @Nullable KermiConfiguration config; + + /** + * Communication interface to the slave endpoint we're connecting to + */ + protected volatile @Nullable ModbusCommunicationInterface comms = null; + private int slaveId; + + public KermiXcenterThingHandler(Bridge thing) { + super(thing); + + globalStateChannel = channelUID(thing, STATE_GROUP, GLOBAL_STATE_CHANNEL); + globalStateIdChannel = channelUID(thing, STATE_GROUP, GLOBAL_STATE_ID_CHANNEL); + } + + public @Nullable ModbusCommunicationInterface getComms() { + return comms; + } + + public int getSlaveId() { + return slaveId; + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + // no control of Kermi device possible yet + } + + @Override + public void initialize() { + updateStatus(ThingStatus.UNKNOWN); + scheduler.execute(() -> { + KermiConfiguration localConfig = getConfigAs(KermiConfiguration.class); + config = localConfig; + ModbusCommunicationInterface localComms = connectEndpoint(); + if (localComms != null) { + // register low speed info poller + ModbusReadRequestBlueprint infoRequest = new ModbusReadRequestBlueprint(slaveId, + ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, STATE_REG_START, STATE_REG_SIZE, 3); + infoPoller = localComms.registerRegularPoll(infoRequest, STATE_POLL_REFRESH_TIME_MS, 0, + this::handleInfoResult, this::handleInfoFailure); + + // ModbusReadRequestBlueprint dataRequest = new ModbusReadRequestBlueprint(slaveId, + // ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, POWER_REG_START, + // REGISTER_LENGTH - INFO_REG_SIZE, 3); + // if (config != null) { + // dataPoller = localComms.registerRegularPoll(dataRequest, localConfig.refresh, 0, + // this::handleDataResult, this::handleDataFailure); + // } else { + // updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + // "E3DC Configuration missing"); + // } + } // else state handling performed in connectEndPoint function + }); + } + + /** + * Get a reference to the modbus endpoint + */ + private @Nullable ModbusCommunicationInterface connectEndpoint() { + if (comms != null) { + return comms; + } + + ModbusEndpointThingHandler slaveEndpointThingHandler = getEndpointThingHandler(); + if (slaveEndpointThingHandler == null) { + @SuppressWarnings("null") + String label = Optional.ofNullable(getBridge()).map(b -> b.getLabel()).orElse(""); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, + String.format("Bridge '%s' is offline", label)); + return null; + } + try { + slaveId = slaveEndpointThingHandler.getSlaveId(); + comms = slaveEndpointThingHandler.getCommunicationInterface(); + } catch (EndpointNotInitializedException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, + String.format("Slave Endpoint not initialized")); + return null; + } + if (comms == null) { + @SuppressWarnings("null") + String label = Optional.ofNullable(getBridge()).map(b -> b.getLabel()).orElse(""); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, + String.format("Bridge '%s' not completely initialized", label)); + return null; + } else { + return comms; + } + } + + /** + * Get the endpoint handler from the bridge this handler is connected to + * Checks that we're connected to the right type of bridge + * + * @return the endpoint handler or null if the bridge does not exist + */ + private @Nullable ModbusEndpointThingHandler getEndpointThingHandler() { + Bridge bridge = getBridge(); + if (bridge == null) { + logger.debug("Bridge is null"); + return null; + } + if (bridge.getStatus() != ThingStatus.ONLINE) { + logger.debug("Bridge is not online"); + return null; + } + + ThingHandler handler = bridge.getHandler(); + if (handler == null) { + logger.debug("Bridge handler is null"); + return null; + } + + if (handler instanceof ModbusEndpointThingHandler thingHandler) { + return thingHandler; + } else { + logger.debug("Unexpected bridge handler: {}", handler); + return null; + } + } + + /** + * Returns the channel UID for the specified group and channel id + * + * @param string the channel group + * @param string the channel id in that group + * @return the globally unique channel uid + */ + private ChannelUID channelUID(Thing t, String group, String id) { + return new ChannelUID(t.getUID(), group, id); + } + + void handleInfoResult(AsyncModbusReadResult result) { + if (infoRead != ReadStatus.READ_SUCCESS) { + // update status only if bit switches + infoRead = ReadStatus.READ_SUCCESS; + updateStatus(); + } + infoParser.handle(result); + Optional dtoOpt = infoParser.parse(Data.DataType.INFO); + if (dtoOpt.isPresent()) { + StateDTO dto = (StateDTO) dtoOpt.get(); + updateState(globalStateChannel, dto.globalState); + updateState(globalStateIdChannel, dto.globalStateId); + // updateState(modbusVersionChannel, dto.modbusVersion); + // updateState(supportedRegistersChannel, dto.supportedRegisters); + // updateState(manufacturerChannel, dto.manufacturer); + // updateState(modelNameChannel, dto.modelName); + // updateState(serialNumberChannel, dto.serialNumber); + // updateState(firmwareChannel, dto.firmware); + } else { + logger.debug("Unable to get {} from provider {}", Data.DataType.INFO, dataParser.toString()); + } + } + + void handleInfoFailure(AsyncModbusFailure result) { + if (infoRead != ReadStatus.READ_FAILED) { + // update status only if bit switches + infoRead = ReadStatus.READ_FAILED; + updateStatus(); + } + } + + void handleDataResult(AsyncModbusReadResult result) { + if (dataRead != ReadStatus.READ_SUCCESS) { + // update status only if bit switches + dataRead = ReadStatus.READ_SUCCESS; + updateStatus(); + } + dataParser.handle(result); + // Update channels in emergency group + // { + // Optional blockOpt = dataParser.parse(DataType.EMERGENCY); + // if (blockOpt.isPresent()) { + // EmergencyBlock block = (EmergencyBlock) blockOpt.get(); + // updateState(epStatusChannel, block.epStatus); + // updateState(batteryChargingLockedChannel, block.batteryChargingLocked); + // updateState(batteryDischargingLockedChannel, block.batteryDischargingLocked); + // updateState(epPossibleChannel, block.epPossible); + // updateState(weatherPredictedChargingChannel, block.weatherPredictedCharging); + // updateState(regulationStatusChannel, block.regulationStatus); + // updateState(chargeLockTimeChannel, block.chargeLockTime); + // updateState(dischargeLockTimeChannel, block.dischargeLockTime); + // } else { + // logger.debug("Unable to get {} from provider {}", DataType.EMERGENCY, dataParser.toString()); + // } + // } + + // Update channels in power group + // { + // Optional blockOpt = dataParser.parse(DataType.POWER); + // if (blockOpt.isPresent()) { + // PowerBlock block = (PowerBlock) blockOpt.get(); + // updateState(pvPowerSupplyChannel, block.pvPowerSupply); + // updateState(batteryPowerSupplyChannel, block.batteryPowerSupply); + // updateState(batteryPowerConsumptionChannel, block.batteryPowerConsumption); + // updateState(householdPowerConsumptionChannel, block.householdPowerConsumption); + // updateState(gridPowerConsumpitionChannel, block.gridPowerConsumpition); + // updateState(gridPowerSupplyChannel, block.gridPowerSupply); + // updateState(externalPowerSupplyChannel, block.externalPowerSupply); + // updateState(wallboxPowerConsumptionChannel, block.wallboxPowerConsumption); + // updateState(wallboxPVPowerConsumptionChannel, block.wallboxPVPowerConsumption); + // updateState(autarkyChannel, block.autarky); + // updateState(selfConsumptionChannel, block.selfConsumption); + // updateState(batterySOCChannel, block.batterySOC); + // if (config != null) { + // if (config.batteryCapacity > 0) { + // double soc = block.batterySOC.doubleValue(); + // QuantityType charged = QuantityType.valueOf(soc * config.batteryCapacity / 100, + // Units.KILOWATT_HOUR); + // updateState(batteryChargedChannel, charged); + // QuantityType uncharged = QuantityType + // .valueOf((100 - soc) * config.batteryCapacity / 100, Units.KILOWATT_HOUR); + // updateState(batteryUnchargedChannel, uncharged); + // } + // } + // } else { + // logger.debug("Unable to get {} from provider {}", DataType.POWER, dataParser.toString()); + // } + // } + + // Update channels in strings group + // { + // Optional blockOpt = dataParser.parse(DataType.STRINGS); + // if (blockOpt.isPresent()) { + // StringBlock block = (StringBlock) blockOpt.get(); + // updateState(string1AmpereChannel, block.string1Ampere); + // updateState(string1VoltChannel, block.string1Volt); + // updateState(string1WattChannel, block.string1Watt); + // updateState(string2AmpereChannel, block.string2Ampere); + // updateState(string2VoltChannel, block.string2Volt); + // updateState(string2WattChannel, block.string2Watt); + // updateState(string3AmpereChannel, block.string3Ampere); + // updateState(string3VoltChannel, block.string3Volt); + // updateState(string3WattChannel, block.string3Watt); + // } else { + // logger.debug("Unable to get {} from provider {}", DataType.STRINGS, dataParser.toString()); + // } + // } + + // Reactivate when KermiKomponents are included / implemented + // listeners.forEach(l -> { + // l.handle(result); + // }); + } + + void handleDataFailure(AsyncModbusFailure result) { + if (dataRead != ReadStatus.READ_FAILED) { + // update status only if bit switches + dataRead = ReadStatus.READ_FAILED; + updateStatus(); + } + // Reactivate when KermiKomponents are included / implemented + // listeners.forEach(l -> { + // l.handleError(result); + // }); + } + + @Override + public void dispose() { + ModbusCommunicationInterface localComms = comms; + if (localComms != null) { + PollTask localInfoPoller = infoPoller; + if (localInfoPoller != null) { + localComms.unregisterRegularPoll(localInfoPoller); + } + PollTask localDataPoller = dataPoller; + if (localDataPoller != null) { + localComms.unregisterRegularPoll(localDataPoller); + } + } + // Comms will be close()'d by endpoint thing handler + comms = null; + } + + private void updateStatus() { + logger.debug("Status update: Info {} Data {} ", infoRead, dataRead); + if (infoRead != ReadStatus.NOT_RECEIVED) { // && dataRead != ReadStatus.NOT_RECEIVED + if (infoRead == ReadStatus.READ_SUCCESS) { + updateStatus(ThingStatus.ONLINE); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, INFO_READ_ERROR); + } + // if (infoRead == dataRead) { + // // both reads are ok or else both failed + // if (infoRead == ReadStatus.READ_SUCCESS) { + // updateStatus(ThingStatus.ONLINE); + // } else { + // updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, INFO_DATA_READ_ERROR); + // } + // } else { + // // either info or data read failed - update status with details + // if (infoRead == ReadStatus.READ_FAILED) { + // updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, INFO_READ_ERROR); + // } else { + // updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, DATA_READ_ERROR); + // } + // } + } // else - one status isn't received yet - wait until both Modbus polls returns either success or error + } + + /* + * @Override + * public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) { + * listeners.add((E3DCWallboxThingHandler) childHandler); + * } + * + * @Override + * public void childHandlerDisposed(ThingHandler childHandler, Thing childThing) { + * listeners.remove(childHandler); + * } + */ +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/modbus/Data.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/modbus/Data.java new file mode 100644 index 0000000000000..401f4a09291c8 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/modbus/Data.java @@ -0,0 +1,28 @@ +/** + * 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.modbus.kermi.internal.modbus; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link Data} Marker Interface for delivered Modbus Data + * + * @author Kai Neuhaus - Initial contribution + */ +@NonNullByDefault +public interface Data { + enum DataType { + INFO, + DATA // marks all types besides INFO + } +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/modbus/KermiModbusConstans.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/modbus/KermiModbusConstans.java new file mode 100644 index 0000000000000..63ca2f6ed30b8 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/modbus/KermiModbusConstans.java @@ -0,0 +1,56 @@ +/** + * 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.modbus.kermi.internal.modbus; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link KermiModbusConstans} Variables for register handling. + * The numbers are taken from Kermi ExcelChart for Modbus + * (Registers start from 0 (not 1!) so from the documented registers subtract 1) + * + * @author Kai Neuhaus - adapted for Kermi + */ +@NonNullByDefault +public class KermiModbusConstans { + // "String" registers at the beginning shall be read with very low frequency - 1 hour + public static final int INFO_POLL_REFRESH_TIME_MS = 60 * 60 * 1000; + + // poll every 30 seconds + public static final int STATE_POLL_REFRESH_TIME_MS = 30 * 1000; + + // Constants where a certain Block starts and block size. Note: General offset is -1 so INFO_REG from E3DC Modbus + // Spec starts at 1 but it's Register 0! + public static final int ENERGY_SOURCE_REG_START = 1; + public static final int ENERGY_SOURCE_REG_SIZE = 3; + + public static final int CHARGING_CIRCUIT_REG_START = 50; + public static final int CHARGING_CIRCUIT_REG_SIZE = 3; + + public static final int POWER_REG_START = 100; + public static final int POWER_REG_SIZE = 12; + + public static final int WORK_HOURS_REG_START = 150; + public static final int WORK_HOURS_REG_SIZE = 3; + + public static final int STATE_REG_START = 200; + public static final int STATE_REG_SIZE = 1; + + public static final int ALARM_REG_START = 250; + public static final int ALARM_REG_SIZE = 1; + + public static final int PV_MODULATION_REG_START = 300; + public static final int PV_MODULATION_REG_SIZE = 4; + + public static final int REGISTER_LENGTH = 104; +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/modbus/Parser.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/modbus/Parser.java new file mode 100644 index 0000000000000..324156e7d188b --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/modbus/Parser.java @@ -0,0 +1,107 @@ +/** + * 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.modbus.kermi.internal.modbus; + +import static org.openhab.binding.modbus.kermi.internal.modbus.KermiModbusConstans.POWER_REG_SIZE; +import static org.openhab.binding.modbus.kermi.internal.modbus.KermiModbusConstans.REGISTER_LENGTH; +import static org.openhab.binding.modbus.kermi.internal.modbus.KermiModbusConstans.STATE_REG_SIZE; + +import java.util.Arrays; +import java.util.Optional; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.modbus.kermi.internal.dto.StateDTO; +import org.openhab.binding.modbus.kermi.internal.modbus.Data.DataType; +import org.openhab.core.io.transport.modbus.AsyncModbusReadResult; +import org.openhab.core.io.transport.modbus.ModbusRegisterArray; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link Parser} class receives callbacks from modbus poller + * + * @author Bernd Weymann - Initial contribution + * @author Kai Neuhaus - adapted for Kermi + */ +@NonNullByDefault +public class Parser { + private static final int MEASURE_COUNT = 100; + private final Logger logger = LoggerFactory.getLogger(Parser.class); + private DataType callbackType; + private byte[] bArray; + private int size; + private int counter = 0; + private long maxDuration = Long.MIN_VALUE; + private long minDuration = Long.MAX_VALUE; + private long avgDuration = 0; + + public Parser(DataType type) { + callbackType = type; + if (type.equals(DataType.INFO)) { + size = STATE_REG_SIZE * 2; + bArray = new byte[size]; + } else if (type.equals(DataType.DATA)) { + size = POWER_REG_SIZE * 2; + bArray = new byte[size]; + } else { + size = (REGISTER_LENGTH - STATE_REG_SIZE) * 2; + bArray = new byte[size]; + } + } + + public void handle(AsyncModbusReadResult result) { + long startTime = System.currentTimeMillis(); + Optional opt = result.getRegisters(); + if (opt.isPresent()) { + setArray(opt.get().getBytes()); + + long duration = System.currentTimeMillis() - startTime; + avgDuration += duration; + minDuration = Math.min(minDuration, duration); + maxDuration = Math.max(maxDuration, duration); + counter++; + if (counter % MEASURE_COUNT == 0) { + logger.debug("Min {} Max {} Avg {}", minDuration, maxDuration, avgDuration / MEASURE_COUNT); + avgDuration = 0; + minDuration = Long.MAX_VALUE; + maxDuration = Long.MIN_VALUE; + } + } else { + logger.warn("Modbus read result doesn't return expected registers"); + } + } + + public synchronized void setArray(byte[] b) { + if (b.length != size) { + logger.warn("Wrong byte size received. Should be {} but is {}. Data maybe corrupted!", size, b.length); + } + bArray = b.clone(); + } + + public Optional parse(DataType type) { + synchronized (bArray) { + if (type.equals(DataType.INFO) && callbackType.equals(DataType.INFO)) { + return Optional.of(new StateDTO(Arrays.copyOfRange(bArray, 0, STATE_REG_SIZE * 2))); + } + } + logger.warn("Wrong Block requested. Request is {} but type is {}", type, callbackType); + return Optional.empty(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(this.getClass().getName()).append(":").append(callbackType); + return sb.toString(); + } +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/i18n/kermi.properties b/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/i18n/kermi.properties new file mode 100644 index 0000000000000..0a9ea0b708229 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/i18n/kermi.properties @@ -0,0 +1,129 @@ +# thing types + +thing-type.modbus.e3dc-wallbox.label = E3DC Wallbox +thing-type.modbus.e3dc-wallbox.description = Provide your Wallbox Settings. Switches like "Sunmode" or "1-Phase Charging" can be changed +thing-type.modbus.e3dc.label = E3DC Home Power Plant +thing-type.modbus.e3dc.description = Provide Power values, String Details, Emergency Power Status and general Information of your E3DC Home Power Plant + +# thing types config + +thing-type.config.modbus.e3dc-wallbox.wallboxId.label = Wallbox ID +thing-type.config.modbus.e3dc-wallbox.wallboxId.description = E3DC supports up to 8 Wallboxes - select a value from 0 to 7 +thing-type.config.modbus.e3dc.refresh.label = Refresh Interval +thing-type.config.modbus.e3dc.refresh.description = Refresh Rate of E3DC values in Milliseconds + +# channel group types + +channel-group-type.modbus.emergency-values.label = EMS Settings +channel-group-type.modbus.emergency-values.description = Provides values of Emergency Power Status (EMS) and regulations like Battery charging / discharging restrictions +channel-group-type.modbus.info-values.label = Information +channel-group-type.modbus.info-values.description = Basic Information of your E3DC Device like Model Name, Serial Number and Software Versions +channel-group-type.modbus.power-values.label = Power Values +channel-group-type.modbus.power-values.description = Provides values of your attached electrical Producers (Photovoltaic, Battery, ... and Consumers (Household, Wallbox, ...) +channel-group-type.modbus.string-values.label = String Details +channel-group-type.modbus.string-values.description = Provide detailed values of your attached Photovoltaic Strings. Evaluate how much Power each String provides + +# channel types + +channel-type.modbus.autarky-channel.label = Autarky +channel-type.modbus.autarky-channel.description = Your current Autarky Level in Percent +channel-type.modbus.battery-charging-lock-channel.label = Battery Charge Locked +channel-type.modbus.battery-charging-lock-channel.description = Battery charging is locked +channel-type.modbus.battery-discharging-lock-channel.label = Battery Discharge Locked +channel-type.modbus.battery-discharging-lock-channel.description = Battery discharging is locked +channel-type.modbus.battery-power-consumption-channel.label = Battery Charge +channel-type.modbus.battery-power-consumption-channel.description = Battery charges and consumes Power +channel-type.modbus.battery-power-supply-channel.label = Battery Discharge +channel-type.modbus.battery-power-supply-channel.description = Battery discharges and provides Power +channel-type.modbus.battery-soc-channel.label = Battery State Of Charge +channel-type.modbus.battery-soc-channel.description = Charge Level of your attached Battery in Percent +channel-type.modbus.battery-charged-channel.label = Battery Charge +channel-type.modbus.battery-charged-channel.description = Charged energy of battery +channel-type.modbus.battery-uncharged-channel.label = Battery Open Capacity +channel-type.modbus.battery-uncharged-channel.description = Open energy capacity of battery +channel-type.modbus.charge-lock-time-channel.label = Charge Lock Time Active +channel-type.modbus.charge-lock-time-channel.description = Charge Lock Time is currently active +channel-type.modbus.discharge-lock-time-channel.label = Discharge Lock Time Active +channel-type.modbus.discharge-lock-time-channel.description = Discharge Lock Time is currently active +channel-type.modbus.emergency-power-possible-channel.label = Emergency Power Possible +channel-type.modbus.emergency-power-possible-channel.description = Emergency Power Supply is possible +channel-type.modbus.emergency-power-status-channel.label = Emergency Power Status +channel-type.modbus.emergency-power-status-channel.description = Indicates if Emergency Power Supply is possible or not, active or inactive +channel-type.modbus.external-power-supply-channel.label = External Power Supply +channel-type.modbus.external-power-supply-channel.description = Power produced by an external device which is attached to your E3DC device +channel-type.modbus.firmware-release-channel.label = Firmware Release +channel-type.modbus.firmware-release-channel.description = Firmware installed on this particular E3DC Device +channel-type.modbus.grid-power-consumption-channel.label = Grid Power Consumption +channel-type.modbus.grid-power-consumption-channel.description = More Photovoltaic Power is produced than needed. Additional Power is consumed by Grid +channel-type.modbus.grid-power-supply-channel.label = Grid Power Supply +channel-type.modbus.grid-power-supply-channel.description = Grid Power is needed in order to satisfy your overall Power consumption +channel-type.modbus.household-power-consumption-channel.label = Household Consumption +channel-type.modbus.household-power-consumption-channel.description = Household consuming Power +channel-type.modbus.manufacturer-name-channel.label = Manufacturer Name +channel-type.modbus.manufacturer-name-channel.description = Name of the Device Manufacturer +channel-type.modbus.modbus-firmware-channel.label = Modbus Firmware +channel-type.modbus.modbus-firmware-channel.description = Version of Modbus Firmware +channel-type.modbus.modbus-id-channel.label = Modbus-ID +channel-type.modbus.modbus-id-channel.description = Modbus ID / Magic Byte of E3DC +channel-type.modbus.model-name-channel.label = Model Name +channel-type.modbus.model-name-channel.description = Name of the E3DC Model +channel-type.modbus.pv-power-supply-channel.label = PV Output +channel-type.modbus.pv-power-supply-channel.description = Photovoltaic Power Production +channel-type.modbus.regulation-status-channel.label = Grid Power Supply Regulation +channel-type.modbus.regulation-status-channel.description = Grid Power Supply is currently regulated +channel-type.modbus.self-consumption-channel.label = Self Consumtion +channel-type.modbus.self-consumption-channel.description = Your current Photovoltaic Self Consumption Level in Percent +channel-type.modbus.serial-number-channel.label = Serial Number +channel-type.modbus.serial-number-channel.description = Serial Number of this particular E3DC Device +channel-type.modbus.string1-dc-current-channel.label = String 1 Current +channel-type.modbus.string1-dc-current-channel.description = Current on String 1 +channel-type.modbus.string1-dc-output-channel.label = String 1 Power +channel-type.modbus.string1-dc-output-channel.description = Power produced by String 1 +channel-type.modbus.string1-dc-voltage-channel.label = String 1 Potential +channel-type.modbus.string1-dc-voltage-channel.description = Voltage on String 1 +channel-type.modbus.string2-dc-current-channel.label = String 2 Current +channel-type.modbus.string2-dc-current-channel.description = Current on String 2 +channel-type.modbus.string2-dc-output-channel.label = String 2 Power +channel-type.modbus.string2-dc-output-channel.description = Power produced by String 2 +channel-type.modbus.string2-dc-voltage-channel.label = String 2 Potential +channel-type.modbus.string2-dc-voltage-channel.description = Voltage on String 2 +channel-type.modbus.string3-dc-current-channel.label = String 3 Current +channel-type.modbus.string3-dc-current-channel.description = Current on String 3 +channel-type.modbus.string3-dc-output-channel.label = String 3 Power +channel-type.modbus.string3-dc-output-channel.description = Power produced by String 3 +channel-type.modbus.string3-dc-voltage-channel.label = String 3 Potential +channel-type.modbus.string3-dc-voltage-channel.description = Voltage on String 3 +channel-type.modbus.supported-registers-channel.label = Supported Registers +channel-type.modbus.supported-registers-channel.description = Number of registers supported by Modbus +channel-type.modbus.wallbox-power-consumption-channel.label = Wallbox Power Consumption +channel-type.modbus.wallbox-power-consumption-channel.description = Power consumption of attached Wallboxes +channel-type.modbus.wallbox-pv-power-consumption-channel.label = Wallbox PV Power Consumption +channel-type.modbus.wallbox-pv-power-consumption-channel.description = Photovoltaic Power consumption (PV plus Battery) of attached Wallboxes +channel-type.modbus.wb-1phase-channel.label = 1-Phase Charging +channel-type.modbus.wb-1phase-channel.description = 1-phase charging is activated. If OFF 3-phase charging is activated +channel-type.modbus.wb-available-channel.label = Available +channel-type.modbus.wb-available-channel.description = Indicates if the Wallbox is attached. Check your Wallbox ID in offline case +channel-type.modbus.wb-charging-aborted-channel.label = Charging Aborted +channel-type.modbus.wb-charging-aborted-channel.description = Wallbox charging is aborted +channel-type.modbus.wb-charging-channel.label = Charging +channel-type.modbus.wb-charging-channel.description = Wallbox is charging +channel-type.modbus.wb-jack-locked-channel.label = Jack Locked +channel-type.modbus.wb-jack-locked-channel.description = Jack is locked +channel-type.modbus.wb-jack-plugged-channel.label = Jack Plugged +channel-type.modbus.wb-jack-plugged-channel.description = Jack is plugged +channel-type.modbus.wb-relay-16a-channel.label = 16A Relay On +channel-type.modbus.wb-relay-16a-channel.description = Wallbox 16A Relay is ON +channel-type.modbus.wb-relay-32a-channel.label = 32A Relay On +channel-type.modbus.wb-relay-32a-channel.description = Wallbox 32A Relay is ON +channel-type.modbus.wb-schuko-locked-channel.label = Schuko Socket Locked +channel-type.modbus.wb-schuko-locked-channel.description = If your Wallbox has an additional Schuko Socket it provides locked state ON or OFF +channel-type.modbus.wb-schuko-on-channel.label = Schuko Socket On +channel-type.modbus.wb-schuko-on-channel.description = If your Wallbox has an additional Schuko Socket it provides state ON or OFF +channel-type.modbus.wb-schuko-plugged-channel.label = Schuko Socket Plugged +channel-type.modbus.wb-schuko-plugged-channel.description = If your Wallbox has an additional Schuko Socket it provides plugged state ON or OFF +channel-type.modbus.wb-schuko-relay-16a-channel.label = Schuko 16A Relay On +channel-type.modbus.wb-schuko-relay-16a-channel.description = Schuko 16A Relay is ON +channel-type.modbus.wb-sunmode-channel.label = Sun Mode +channel-type.modbus.wb-sunmode-channel.description = Activate / Deactivate Sun Mode. Off case takes Grid Power to ensure highest possible charging +channel-type.modbus.weather-predicted-charging-channel.label = Weather Predicted Battery Charging +channel-type.modbus.weather-predicted-charging-channel.description = Weather Predicted Battery Charging is activated diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/i18n/kermi_de.properties b/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/i18n/kermi_de.properties new file mode 100644 index 0000000000000..23c878a98a418 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/i18n/kermi_de.properties @@ -0,0 +1,81 @@ +# thing types +thing-type.modbus.e3dc.label = E3DC Hauskraftwerk +thing-type.modbus.e3dc.description = Zeigt die Leistungswerte, String Details, Notstrom Zustand und generelle Details zu Ihrem E3DC Hauskraftwerk +thing-type.modbus.e3dc-wallbox.label = E3DC Wallbox +thing-type.modbus.e3dc-wallbox.description = Zeigt die Einstellungen der verbundenen Wallbox. Schalter wie "Sonnenmodus" oder "1-phasiges Laden" können geändert werden + +# thing type config description +thing-type.config.modbus.e3dc.refresh.label = Zyklische Abfragezeit +thing-type.config.modbus.e3dc.refresh.description = Intervall in Millisekunden, wie oft die Werte abgerufen werden sollen +thing-type.config.modbus.e3dc-wallbox.wallboxId.label = Wallbox-Nummer +thing-type.config.modbus.e3dc-wallbox.wallboxId.description = Das E3DC Gerät unterstützt bis zu 8 Wallboxen - Wählen Sie einen Wert zwischen 0 und 7 + +# Channel group types +channel-group-type.modbus.info-values.label = Informationen +channel-group-type.modbus.info-values.description = Basisinformationen zum E3DC Hauskraftwerk wie Modellname, Seriennummer und Software-Versionen +channel-group-type.modbus.power-values.label = Leistungswerte +channel-group-type.modbus.power-values.description = Elektrische Werte der angeschlossenen Erzeuger (Photovoltaik, Batterie, ...) und Verbraucher (Haushaltsverbrauch, Wallbox,...) +channel-group-type.modbus.string-values.label = String Details +channel-group-type.modbus.string-values.description = Detaillierte Werte der angeschlossenen Photovoltaik Strings. Zeigt die einzelnen Werte jedes angeschlossenen Strings +channel-group-type.modbus.emergency-values.label = Notstrom Einstellungen +channel-group-type.modbus.emergency-values.description = Status und Werte der Notstromversorgung wie Batterie Lade- und Entladesperren, Einspeise-Abregelung + +# Wallbox Channels +channel-type.modbus.wb-available-channel.label = Vorhanden +channel-type.modbus.wb-sunmode-channel.label = Sonnenmodus +channel-type.modbus.wb-charging-aborted-channel.label = Laden Abgebrochen +channel-type.modbus.wb-charging-channel.label = Auto lädt +channel-type.modbus.wb-jack-locked-channel.label = Ladekabel Verriegelt +channel-type.modbus.wb-jack-plugged-channel.label = Ladekabel Gesteckt +channel-type.modbus.wb-schuko-on-channel.label = Schuko-Steckdose An +channel-type.modbus.wb-schuko-plugged-channel.label = Schuko-Stecker Gesteckt +channel-type.modbus.wb-schuko-locked-channel.label = Schuko-Stecker Verriegelt +channel-type.modbus.wb-schuko-relay-16a-channel.label = Schuko-Steckdose 16A Relais An +channel-type.modbus.wb-relay-16a-channel.label = 16A Relais An +channel-type.modbus.wb-relay-32a-channel.label = 32A Relais An +channel-type.modbus.wb-1phase-channel.label = 1-phasiges Laden An + +# Emergency Channels +channel-type.modbus.emergency-power-status-channel.label = Notstrom Status +channel-type.modbus.battery-charging-lock-channel.label = Batterie Laden Gesperrt +channel-type.modbus.battery-discharging-lock-channel.label = Batterie Entladen Gesperrt +channel-type.modbus.emergency-power-possible-channel.label = Notstrom Versorgung Möglich +channel-type.modbus.weather-predicted-charging-channel.label = Wetterbasiertes Laden +channel-type.modbus.regulation-status-channel.label = Einspeise Abregelung +channel-type.modbus.charge-lock-time-channel.label = Batterie Ladesperrzeiten Aktiv +channel-type.modbus.discharge-lock-time-channel.label = Batterie Entladesperrzeiten Aktiv + +# Info Channels +channel-type.modbus.modbus-id-channel.label = Modbus ID +channel-type.modbus.modbus-firmware-channel.label = Modbus Firmware +channel-type.modbus.supported-registers-channel.label = Unterstützte Register +channel-type.modbus.manufacturer-name-channel.label = Hersteller +channel-type.modbus.model-name-channel.label = Modellname +channel-type.modbus.serial-number-channel.label = Seriennummer +channel-type.modbus.firmware-release-channel.label = Firmware + +# Power Channels +channel-type.modbus.pv-power-supply-channel.label = Photovoltaik Leistung +channel-type.modbus.battery-power-supply-channel.label = Batterie Entladen +channel-type.modbus.battery-power-consumption-channel.label = Batterie Laden +channel-type.modbus.household-power-consumption-channel.label = Haushalt Verbrauch +channel-type.modbus.grid-power-consumption-channel.label = Stromnetz Einspeisung +channel-type.modbus.grid-power-supply-channel.label = Stromnetz Verbrauch +channel-type.modbus.external-power-supply-channel.label = Externer Stromproduzent +channel-type.modbus.wallbox-power-consumption-channel.label = Wallbox Ladestrom +channel-type.modbus.wallbox-pv-power-consumption-channel.label = Wallbox Photovoltaik Ladestrom +channel-type.modbus.autarky-channel.label = Autarkie in Prozent +channel-type.modbus.self-consumption-channel.label = Eigenverbrauch in Prozent +channel-type.modbus.battery-soc-channel.label = Batterie Ladestand in Prozent + +# String Channels +channel-type.modbus.string1-dc-voltage-channel.label = String 1 Spannung +channel-type.modbus.string2-dc-voltage-channel.label = String 2 Spannung +channel-type.modbus.string3-dc-voltage-channel.label = String 3 Spannung +channel-type.modbus.string1-dc-current-channel.label = String 1 Stromstärke +channel-type.modbus.string2-dc-current-channel.label = String 2 Stromstärke +channel-type.modbus.string3-dc-current-channel.label = String 3 Stromstärke +channel-type.modbus.string1-dc-output-channel.label = String 1 Leistung +channel-type.modbus.string2-dc-output-channel.label = String 2 Leistung +channel-type.modbus.string3-dc-output-channel.label = String 3 Leistung + diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/bridge-kermi-xcenter.xml b/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/bridge-kermi-xcenter.xml new file mode 100644 index 0000000000000..440db563f849b --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/bridge-kermi-xcenter.xml @@ -0,0 +1,23 @@ + + + + + + + + Provide Energy values, String Details and general Information of your Kermi Heat Pump + + + + + + + Refresh Rate of Xcenter values in Milliseconds + 5000 + + + + diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-state-channel-groups.xml b/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-state-channel-groups.xml new file mode 100644 index 0000000000000..3c13e10009222 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-state-channel-groups.xml @@ -0,0 +1,15 @@ + + + + + Basic Information and State of your Kermi Heatpump X-Center + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-state-channel-types.xml b/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-state-channel-types.xml new file mode 100644 index 0000000000000..402ce9e6f8177 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-state-channel-types.xml @@ -0,0 +1,21 @@ + + + + String + + Current mode of your heat pump + + + Number + + Current mode of your heat pump + + + Boolean + + If there's a global alarm + + diff --git a/bundles/org.openhab.binding.modbus.kermi/src/test/java/org/openhab/binding/modbus/kermi/internal/dto/StateDTOTest.java b/bundles/org.openhab.binding.modbus.kermi/src/test/java/org/openhab/binding/modbus/kermi/internal/dto/StateDTOTest.java new file mode 100644 index 0000000000000..2a1b5a6f7fa8b --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/test/java/org/openhab/binding/modbus/kermi/internal/dto/StateDTOTest.java @@ -0,0 +1,34 @@ +/** + * 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.modbus.kermi.internal.dto; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +/** + * Test for {@link StateDTO} class + * + * @author Kai Neuhaus + */ +public class StateDTOTest { + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } +} diff --git a/bundles/pom.xml b/bundles/pom.xml index b3a95a4c86b52..0f8b3ac3c5120 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -263,6 +263,7 @@ org.openhab.binding.minecraft org.openhab.binding.modbus org.openhab.binding.modbus.e3dc + org.openhab.binding.modbus.kermi org.openhab.binding.modbus.sbc org.openhab.binding.modbus.studer org.openhab.binding.modbus.sungrow From 89161b497aa0ff91f979400005876f0c4879b4af Mon Sep 17 00:00:00 2001 From: Kai Neuhaus Date: Wed, 24 Jan 2024 18:19:16 +0100 Subject: [PATCH 02/21] [kermi] Added all channels of XCenter Signed-off-by: Kai Neuhaus --- .../kermi/internal/KermiBindingConstants.java | 42 +- .../kermi/internal/KermiConfiguration.java | 1 + .../modbus/kermi/internal/dto/AlarmDTO.java | 34 + .../internal/dto/ChargingCircuitDTO.java | 42 ++ .../kermi/internal/dto/EnergySourceDTO.java | 39 ++ .../modbus/kermi/internal/dto/PowerDTO.java | 64 ++ .../modbus/kermi/internal/dto/PvDTO.java | 52 ++ .../modbus/kermi/internal/dto/StateDTO.java | 14 +- .../kermi/internal/dto/WorkHoursDTO.java | 41 ++ .../handler/KermiXcenterThingHandler.java | 598 +++++++++++++----- .../modbus/kermi/internal/modbus/Data.java | 10 +- .../internal/modbus/KermiModbusConstans.java | 12 +- .../modbus/kermi/internal/modbus/Parser.java | 56 +- .../OH-INF/thing/bridge-kermi-xcenter.xml | 11 + .../thing/xcenter-alarm-channel-groups.xml | 13 + .../thing/xcenter-alarm-channel-types.xml | 11 + ...xcenter-chargingcircuit-channel-groups.xml | 15 + .../xcenter-chargingcircuit-channel-types.xml | 21 + .../xcenter-energysource-channel-groups.xml | 15 + .../xcenter-energysource-channel-types.xml | 21 + .../thing/xcenter-power-channel-groups.xml | 24 + .../thing/xcenter-power-channel-types.xml | 68 ++ .../xcenter-pvmodulation-channel-groups.xml | 18 + .../xcenter-pvmodulation-channel-types.xml | 26 + .../thing/xcenter-state-channel-groups.xml | 1 - .../xcenter-workhours-channel-groups.xml | 15 + .../thing/xcenter-workhours-channel-types.xml | 21 + .../kermi/internal/dto/StateDTOTest.java | 2 +- 28 files changed, 1114 insertions(+), 173 deletions(-) create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/AlarmDTO.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/ChargingCircuitDTO.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/EnergySourceDTO.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/PowerDTO.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/PvDTO.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/WorkHoursDTO.java create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-alarm-channel-groups.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-alarm-channel-types.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-chargingcircuit-channel-groups.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-chargingcircuit-channel-types.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-energysource-channel-groups.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-energysource-channel-types.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-power-channel-groups.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-power-channel-types.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-pvmodulation-channel-groups.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-pvmodulation-channel-types.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-workhours-channel-groups.xml create mode 100644 bundles/org.openhab.binding.modbus.kermi/src/main/resources/OH-INF/thing/xcenter-workhours-channel-types.xml diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiBindingConstants.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiBindingConstants.java index f5618aa165bac..b9bea78bb4571 100644 --- a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiBindingConstants.java +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiBindingConstants.java @@ -30,7 +30,47 @@ public class KermiBindingConstants { // Supported Thing Types public static final ThingTypeUID THING_TYPE_KERMI_XCENTER = new ThingTypeUID(BINDING_ID, "kermi-xcenter"); - // Channels for State Block + // Channels for State public static final String GLOBAL_STATE_CHANNEL = "global-state"; public static final String GLOBAL_STATE_ID_CHANNEL = "global-state-id"; + + // Alarm State + public static final String ALARM_STATE_CHANNEL = "alarm-state"; + + // Energy Source + public static final String FLOW_TEMPERATURE_CHANNEL = "flow-temperature"; + public static final String RETURN_TEMPERATURE_CHANNEL = "return-temperature"; + public static final String FLOW_SPEED_CHANNEL = "flow-speed"; + + // Charging Circuit + public static final String EXIT_TEMPERATURE_CHANNEL = "exit-temperature"; + public static final String INCOMING_TEMPERATURE_CHANNEL = "incoming-temperature"; + public static final String TEMPERATURE_SENSOR_OUTSIDE_CHANNEL = "temperature-sensor-outside"; + + // Power + public static final String COP_CHANNEL = "cop"; + public static final String COP_HEATING_CHANNEL = "cop-heating"; + public static final String COP_DRINKINGWATER_CHANNEL = "cop-drinkingwater"; + public static final String COP_COOLING_CHANNEL = "cop-cooling"; + + public static final String POWER_CHANNEL = "power"; + public static final String POWER_HEATING_CHANNEL = "power-heating"; + public static final String POWER_DRINKINGWATER_CHANNEL = "power-drinkingwater"; + public static final String POWER_COOLING_CHANNEL = "power-cooling"; + + public static final String ELECTRIC_POWER_CHANNEL = "electric-power"; + public static final String ELECTRIC_POWER_HEATING_CHANNEL = "electric-power-heating"; + public static final String ELECTRIC_POWER_DRINKINGWATER_CHANNEL = "electric-power-drinkingwater"; + public static final String ELECTRIC_POWER_COOLING_CHANNEL = "electric-power-cooling"; + + // Work hours + public static final String WORKHOURS_FAN_CHANNEL = "workhours-fan"; + public static final String WORKHOURS_STORAGE_LOADING_PUMP_CHANNEL = "workhours-storage-loading-pump"; + public static final String WORKHOURS_COMPRESSOR_CHANNEL = "workhours-compressor"; + + // PV + public static final String PV_STATE_CHANNEL = "pv-state"; + public static final String PV_POWER_CHANNEL = "pv-power"; + public static final String PV_TARGET_TEMPERATURE_HEATING_CHANNEL = "pv-target-temperature-heating"; + public static final String PV_TARGET_TEMPERATURE_DRINKINGWATER_CHANNEL = "pv-target-temperature-drinkingwater"; } diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiConfiguration.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiConfiguration.java index dab20b767bf1d..f1401dc218f0e 100644 --- a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiConfiguration.java +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/KermiConfiguration.java @@ -23,4 +23,5 @@ public class KermiConfiguration { public int refresh = 5000; + public boolean pvEnabled = false; } diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/AlarmDTO.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/AlarmDTO.java new file mode 100644 index 0000000000000..06109bc2f6100 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/AlarmDTO.java @@ -0,0 +1,34 @@ +/** + * 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.modbus.kermi.internal.dto; + +import static org.openhab.binding.modbus.kermi.internal.modbus.KermiModbusConstans.ALARM_REG_SIZE; + +import org.openhab.binding.modbus.kermi.internal.modbus.Data; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.library.types.OnOffType; + +/** + * The {@link AlarmDTO} Data object for Kermi Xcenter + * + * @author Kai Neuhaus - Initial contribution + */ +public class AlarmDTO implements Data { + + public OnOffType alarmIsActive; + + public AlarmDTO(byte[] bArray) { + int status = ModbusBitUtilities.extractBit(bArray, ALARM_REG_SIZE); + alarmIsActive = status == 0 ? OnOffType.OFF : OnOffType.ON; + } +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/ChargingCircuitDTO.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/ChargingCircuitDTO.java new file mode 100644 index 0000000000000..57aa0af7a8445 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/ChargingCircuitDTO.java @@ -0,0 +1,42 @@ +/** + * 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.modbus.kermi.internal.dto; + +import static org.openhab.core.library.unit.Units.LITRE_PER_MINUTE; + +import javax.measure.quantity.Temperature; + +import org.openhab.binding.modbus.kermi.internal.modbus.Data; +import org.openhab.core.io.transport.modbus.ValueBuffer; +import org.openhab.core.library.dimension.VolumetricFlowRate; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.SIUnits; + +/** + * The {@link ChargingCircuitDTO} Data object for Kermi Xcenter + * + * @author Kai Neuhaus - Initial contribution + */ +public class ChargingCircuitDTO implements Data { + + public QuantityType flowTemperature; + public QuantityType returnFlowTemperature; + public QuantityType flowSpeed; + + public ChargingCircuitDTO(byte[] bArray) { + ValueBuffer wrap = ValueBuffer.wrap(bArray); + flowTemperature = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.1), SIUnits.CELSIUS); + returnFlowTemperature = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.1), SIUnits.CELSIUS); + flowSpeed = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.1), LITRE_PER_MINUTE); + } +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/EnergySourceDTO.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/EnergySourceDTO.java new file mode 100644 index 0000000000000..d55893670618c --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/EnergySourceDTO.java @@ -0,0 +1,39 @@ +/** + * 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.modbus.kermi.internal.dto; + +import javax.measure.quantity.Temperature; + +import org.openhab.binding.modbus.kermi.internal.modbus.Data; +import org.openhab.core.io.transport.modbus.ValueBuffer; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.SIUnits; + +/** + * The {@link EnergySourceDTO} Data object for Kermi Xcenter + * + * @author Kai Neuhaus - Initial contribution + */ +public class EnergySourceDTO implements Data { + + public QuantityType exitTemperature; + public QuantityType incomingTemperature; + public QuantityType outsideTemperature; + + public EnergySourceDTO(byte[] bArray) { + ValueBuffer wrap = ValueBuffer.wrap(bArray); + exitTemperature = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.1), SIUnits.CELSIUS); + incomingTemperature = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.1), SIUnits.CELSIUS); + outsideTemperature = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.1), SIUnits.CELSIUS); + } +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/PowerDTO.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/PowerDTO.java new file mode 100644 index 0000000000000..2ce4bba818053 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/PowerDTO.java @@ -0,0 +1,64 @@ +/** + * 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.modbus.kermi.internal.dto; + +import javax.measure.quantity.Power; + +import org.openhab.binding.modbus.kermi.internal.modbus.Data; +import org.openhab.core.io.transport.modbus.ValueBuffer; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.Units; + +/** + * The {@link PowerDTO} Data object for Kermi Xcenter State Block + * + * @author Kai Neuhaus - Initial contribution + */ +public class PowerDTO implements Data { + + public DecimalType cop; + public DecimalType copHeating; + public DecimalType copDrinkingwater; + public DecimalType copCooling; + + public QuantityType power; + public QuantityType powerHeating; + public QuantityType powerDrinkingwater; + public QuantityType powerCooling; + + public QuantityType electricPower; + public QuantityType electricPowerHeating; + public QuantityType electricPowerDrinkingwater; + public QuantityType electricPowerCooling; + + public PowerDTO(byte[] bArray) { + + ValueBuffer wrap = ValueBuffer.wrap(bArray); + + cop = new DecimalType(DataConverter.getUDoubleValue(wrap, 0.1)); + copHeating = new DecimalType(DataConverter.getUDoubleValue(wrap, 0.1)); + copDrinkingwater = new DecimalType(DataConverter.getUDoubleValue(wrap, 0.1)); + copCooling = new DecimalType(DataConverter.getUDoubleValue(wrap, 0.1)); + + power = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 100), Units.WATT); + powerHeating = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 100), Units.WATT); + powerDrinkingwater = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 100), Units.WATT); + powerCooling = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 100), Units.WATT); + + electricPower = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 100), Units.WATT); + electricPowerHeating = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 100), Units.WATT); + electricPowerDrinkingwater = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 100), Units.WATT); + electricPowerCooling = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 100), Units.WATT); + } +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/PvDTO.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/PvDTO.java new file mode 100644 index 0000000000000..f6da0ab9da781 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/PvDTO.java @@ -0,0 +1,52 @@ +/** + * 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.modbus.kermi.internal.dto; + +import javax.measure.quantity.Power; +import javax.measure.quantity.Temperature; + +import org.openhab.binding.modbus.kermi.internal.modbus.Data; +import org.openhab.core.io.transport.modbus.ModbusBitUtilities; +import org.openhab.core.io.transport.modbus.ValueBuffer; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.library.unit.Units; + +/** + * The {@link PvDTO} Data object for Kermi Xcenter + * + * @author Kai Neuhaus - Initial contribution + */ +public class PvDTO implements Data { + + public OnOffType pvModulationActive; + public QuantityType pvModulationPower; + public QuantityType pvTargetTemperatureHeating; + public QuantityType pvTargetTemperatureDrinkingwater; + + public PvDTO(byte[] bArray) { + + int modActive = ModbusBitUtilities.extractBit(bArray, 0); + pvModulationActive = modActive == 0 ? OnOffType.OFF : OnOffType.ON; + + ValueBuffer wrap = ValueBuffer.wrap(bArray); + // skip first bit -> modActive-Value + wrap.position(2); + + pvModulationPower = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.1), Units.WATT); + pvTargetTemperatureHeating = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.1), SIUnits.CELSIUS); + pvTargetTemperatureDrinkingwater = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.1), + SIUnits.CELSIUS); + } +} diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/StateDTO.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/StateDTO.java index 6e63eb339e7f3..e9ad4adad100f 100644 --- a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/StateDTO.java +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/StateDTO.java @@ -18,14 +18,14 @@ import org.openhab.core.library.types.StringType; /** - * The {@link StateDTO} Data object for Kermi Xcenter State Block + * The {@link StateDTO} Data object for Kermi Xcenter * * @author Kai Neuhaus - Initial contribution */ public class StateDTO implements Data { - public StringType globalState = STATE_UNKOWN; - public DecimalType globalStateId = new DecimalType(-1); + public StringType globalState; + public DecimalType globalStateId; // State definitions public static final StringType STATE_STANDBY = StringType.valueOf("Standby"); @@ -45,7 +45,7 @@ public class StateDTO implements Data { public StateDTO(byte[] bArray) { - int status = ModbusBitUtilities.extractUInt16(bArray, 0); + int status = ModbusBitUtilities.extractBit(bArray, 0); globalStateId = new DecimalType(status); @@ -54,11 +54,5 @@ public StateDTO(byte[] bArray) { } else { globalState = STATE_UNKOWN; } - // - // // index handling to calculate the correct start index - // ValueBuffer wrap = ValueBuffer.wrap(bArray); - // - // // int32_swap value = 4 byte - // int globalState = wrap.getUInt16(); } } diff --git a/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/WorkHoursDTO.java b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/WorkHoursDTO.java new file mode 100644 index 0000000000000..f3bb44d99616a --- /dev/null +++ b/bundles/org.openhab.binding.modbus.kermi/src/main/java/org/openhab/binding/modbus/kermi/internal/dto/WorkHoursDTO.java @@ -0,0 +1,41 @@ +/** + * 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.modbus.kermi.internal.dto; + +import javax.measure.quantity.Time; + +import org.openhab.binding.modbus.kermi.internal.modbus.Data; +import org.openhab.core.io.transport.modbus.ValueBuffer; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.Units; + +/** + * The {@link WorkHoursDTO} Data object for Kermi Xcenter State Block + * + * @author Kai Neuhaus - Initial contribution + */ +public class WorkHoursDTO implements Data { + + public QuantityType