diff --git a/CODEOWNERS b/CODEOWNERS index 633bb100fabbd..66aac3bf1fb14 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -129,6 +129,7 @@ /bundles/org.openhab.binding.minecraft/ @ibaton /bundles/org.openhab.binding.modbus/ @ssalonen /bundles/org.openhab.binding.modbus.e3dc/ @weymann +/bundles/org.openhab.binding.modbus.studer/ @giovannimirulla /bundles/org.openhab.binding.modbus.sunspec/ @mrbig /bundles/org.openhab.binding.modbus.stiebeleltron/ @pail23 /bundles/org.openhab.binding.monopriceaudio/ @mlobstein diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index 9854dc430c463..cbf7f42233686 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -1046,6 +1046,11 @@ org.openhab.binding.squeezebox ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.modbus.studer + ${project.version} + org.openhab.addons.bundles org.openhab.binding.modbus.sunspec diff --git a/bundles/org.openhab.binding.modbus.studer/.classpath b/bundles/org.openhab.binding.modbus.studer/.classpath new file mode 100644 index 0000000000000..f79ae85591f5a --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/.classpath @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.studer/.project b/bundles/org.openhab.binding.modbus.studer/.project new file mode 100644 index 0000000000000..90e9e10eff905 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/.project @@ -0,0 +1,23 @@ + + + org.openhab.binding.modbus.studer + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/bundles/org.openhab.binding.modbus.studer/NOTICE b/bundles/org.openhab.binding.modbus.studer/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/NOTICE @@ -0,0 +1,13 @@ +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 diff --git a/bundles/org.openhab.binding.modbus.studer/README.md b/bundles/org.openhab.binding.modbus.studer/README.md new file mode 100644 index 0000000000000..4520f35f4d066 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/README.md @@ -0,0 +1,142 @@ +# Studer + +This extension adds support for the Studer protocol. + +Studer Innotec, founded in 1987 by Roland Studer, is an ISO certified company that develops and manufactures inverters, inverter/chargers and MPPT solar charge controllers to communicate over the Modbus protocol entirely in Switzerland + +For a list of certified products see this page: https://www.studer-innotec.com/ + +## Supported Things + +This bundle adds the following thing type to the Modbus binding. +Note, that the things will show up under the Modbus binding. + +| Thing Type IDs | Description | Picture | +|----------------|----------------------------------------------------------------------------------------------------------------------|-------------------------------------| +| bsp | For BSP that offer a highly precise measuring for Xtender, VarioTrack and VarioString systems | ![BSP](doc/bsp.png) | +| xtender | For the Xtender models for system capacities from 0.5kVA to 72kVA that allow for the optimal use of available energy | ![Xtender](doc/xtender.png) | +| variotrack | For the VarioTrack models of MPPT solar charge controllers for systems with solar PV capacity from 1 - 75kWp | ![VarioTrack](doc/variotrack.png) | +| variostring | For the VarioString models of MPPT solar charge controllers for systems with solar PV capacity from 4 | ![VarioString](doc/variostring.png) | + + +## Thing Configuration + +You need first to set up a Serial Modbus bridge according to the Modbus documentation. +Things in this extension will use the selected bridge to connect to the device. + +For defining a thing textually, you have to find out the start address of the model block and the length of it. +While the length is usually fixed, the address is not. +Please refer to your device's vendor documentation how model blocks are laid for your equipment. + +The following parameters are valid for all thing types: + +| Parameter | Type | Required | Default if omitted | Description | +|-----------|---------|----------|-------------------------|----------------------------------------------------------------------------| +| address | integer | yes | `first slave of device` | Address of slave | +| refresh | integer | yes | 5 | Poll interval in seconds. Increase this if you encounter connection errors | + +## Channels + +The following Channels, and their associated channel types are shown below divided by device. + +#### BSP + +All channels read for a BSP device + +| Channel | Type | Description | +| ------------------ | ------------------------ | --------------------- | +| power | Number:Power | Power | +| batteryVoltage | Number:ElectricPotential | Battery voltage | +| batteryCurrent | Number:ElectricCurrent | Battery current | +| stateOfCharge | Number:Dimensionless | State of Charge | +| batteryTemperature | Number:Temperature | Battery temperature | + +#### Xtender + +All channels read for a Xtender device + +| Channel | Type | Description | +| ----------------- | ------------------------ | ----------------------- | +| inputVoltage | Number:ElectricPotential | Input voltage | +| inputCurrent | Number:ElectricCurrent | Input current | +| inputActivePower | Number:Power | Input active power | +| inputFrequency | Number:Frequency | Input frequency | +| outputVoltage | Number:ElectricPotential | Output voltage | +| outputCurrent | Number:ElectricCurrent | Output current | +| outputActivePower | Number:Power | Output active power | +| outputFrequency | Number:Frequency | Output frequency | +| operatingState | String | Operating state | +| stateInverter | String | State of the inverter | + +#### VarioTrack + +All channels read for a VarioTrack device + +| Channel | Type | Description | +| -------------------- | ------------------------ | ----------------------------------------- | +| modelVarioTrack | String | Model of VarioTrack | +| voltagePVGenerator | Number:ElectricPotential | Voltage of the PV generator | +| powerPVGenerator | Number:Power | Power of the PV generator | +| productionCurrentDay | Number:Energy | Production in (kWh) for the current day | +| batteryVoltage | Number:ElectricPotential | Battery voltage | +| batteryCurrent | Number:ElectricCurrent | Battery current | +| operatingMode | String | Operating mode | +| stateVarioTrack | String | State of the VarioTrack | + +#### VarioString + +All channels read for a VarioString device + +| Channel | Type | Description | +| ----------------------- | ------------------------ | --------------------------------------------- | +| PVVoltage | Number:ElectricPotential | PV voltage | +| PVCurrent | Number:ElectricCurrent | PV current | +| PVPower | Number:Power | PV power | +| ProductionPVCurrentDay | Number:Energy | Production PV in (kWh) for the current day | +| PV1Voltage | Number:ElectricPotential | PV1 voltage | +| PV1Current | Number:ElectricCurrent | PV1 current | +| PV1Power | Number:Power | PV1 power | +| ProductionPV1CurrentDay | Number:Energy | Production PV1 in (kWh) for the current day | +| PV2Voltage | Number:ElectricPotential | PV2 voltage | +| PV2Current | Number:ElectricCurrent | PV2 current | +| PV2Power | Number:Power | PV2 power | +| ProductionPV2CurrentDay | Number:Energy | Production PV2 in (kWh) for the current day | +| batteryVoltage | Number:ElectricPotential | Battery voltage | +| batteryCurrent | Number:ElectricCurrent | Battery current | +| PVMode | String | PV operating mode | +| PV1Mode | String | PV1 operating mode | +| PV2Mode | String | PV2 operating mode | +| stateVarioString | String | State of the VarioString | + +## Example + +### Thing Configuration + +``` +Bridge modbus:serial:bridge [port="/dev/ttyUSB0",baud=9600,dataBits=8,parity="even",stopBits="1.0",encoding="rtu"] +Thing modbus:xtender:bridge:xtenderdevice "Xtender" (modbus:serial:modbusbridge) [ slaveAddress=10, refresh=5 ] +``` + +Note: Make sure that refresh and slave address are numerical, without quotes. + +### Item Configuration + +``` +Number XtenderStuderThing_InputVoltage "Input Voltage [%.2f %unit%]" +{channel="modbus:xtender:bridge:xtenderdevice:inputVoltage"} + +Number XtenderStuderThing_InputCurrent "Input Current [%.2f %unit%]" {channel="modbus:xtender:bridge:xtenderdevice:inputCurrent"} + +String XtenderStuderThing_StateInverter "State: [%s]" {channel="modbus:xtender:bridge:xtenderdevice:stateInverter"} +``` + +### Sitemap Configuration + +``` +Text item=XtenderStuderThing_InputVoltage +Text item=XtenderStuderThing_InputCurrent +Text item=XtenderStuderThing_StateInverter + +Chart item=XtenderStuderThing_InputVoltage period=D refresh=600000 +Chart item=XtenderStuderThing_InputCurrent period=D refresh=30000 +``` \ No newline at end of file diff --git a/bundles/org.openhab.binding.modbus.studer/doc/bsp.png b/bundles/org.openhab.binding.modbus.studer/doc/bsp.png new file mode 100644 index 0000000000000..fdb291aa2daaa Binary files /dev/null and b/bundles/org.openhab.binding.modbus.studer/doc/bsp.png differ diff --git a/bundles/org.openhab.binding.modbus.studer/doc/variostring.png b/bundles/org.openhab.binding.modbus.studer/doc/variostring.png new file mode 100644 index 0000000000000..2c0927af2949b Binary files /dev/null and b/bundles/org.openhab.binding.modbus.studer/doc/variostring.png differ diff --git a/bundles/org.openhab.binding.modbus.studer/doc/variotrack.png b/bundles/org.openhab.binding.modbus.studer/doc/variotrack.png new file mode 100644 index 0000000000000..b79f8a87e9ef4 Binary files /dev/null and b/bundles/org.openhab.binding.modbus.studer/doc/variotrack.png differ diff --git a/bundles/org.openhab.binding.modbus.studer/doc/xtender.png b/bundles/org.openhab.binding.modbus.studer/doc/xtender.png new file mode 100644 index 0000000000000..3234918d3914b Binary files /dev/null and b/bundles/org.openhab.binding.modbus.studer/doc/xtender.png differ diff --git a/bundles/org.openhab.binding.modbus.studer/pom.xml b/bundles/org.openhab.binding.modbus.studer/pom.xml new file mode 100644 index 0000000000000..0f46566058e4c --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/pom.xml @@ -0,0 +1,30 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 2.5.9-SNAPSHOT + + + org.openhab.binding.modbus.studer + + openHAB Add-ons :: Bundles :: Studer Binding + + + org.openhab.addons.bundles + org.openhab.binding.modbus + ${project.version} + provided + + + org.openhab.addons.bundles + org.openhab.io.transport.modbus + ${project.version} + provided + + + diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/feature/feature.xml b/bundles/org.openhab.binding.modbus.studer/src/main/feature/feature.xml new file mode 100644 index 0000000000000..c46afeefc0570 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/src/main/feature/feature.xml @@ -0,0 +1,12 @@ + + + file:${basedirRoot}/bundles/org.openhab.io.transport.modbus/target/feature/feature.xml + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + openhab-transport-modbus + mvn:org.openhab.addons.bundles/org.openhab.binding.modbus/${project.version} + mvn:org.openhab.addons.bundles/org.openhab.binding.modbus.studer/${project.version} + + diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderBindingConstants.java b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderBindingConstants.java new file mode 100644 index 0000000000000..5edc3e367a274 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderBindingConstants.java @@ -0,0 +1,229 @@ +/** + * Copyright (c) 2010-2020 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.studer.internal; + +import static org.eclipse.smarthome.core.library.unit.MetricPrefix.KILO; +import static org.eclipse.smarthome.core.library.unit.SIUnits.CELSIUS; +import static org.eclipse.smarthome.core.library.unit.SmartHomeUnits.*; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.measure.Unit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.thing.ThingTypeUID; +import org.openhab.binding.modbus.ModbusBindingConstants; + +/** + * The {@link StuderBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Giovanni Mirulla - Initial contribution + */ +@NonNullByDefault +public class StuderBindingConstants { + + private static final String BINDING_ID = ModbusBindingConstants.BINDING_ID; + + // List of all Thing Type UIDs + public static final ThingTypeUID THING_TYPE_BSP = new ThingTypeUID(BINDING_ID, "bsp"); + public static final ThingTypeUID THING_TYPE_XTENDER = new ThingTypeUID(BINDING_ID, "xtender"); + public static final ThingTypeUID THING_TYPE_VARIOTRACK = new ThingTypeUID(BINDING_ID, "variotrack"); + public static final ThingTypeUID THING_TYPE_VARIOSTRING = new ThingTypeUID(BINDING_ID, "variostring"); + + public static final Set SUPPORTED_THING_TYPES_UIDS = new HashSet<>(); + static { + SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_BSP); + SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_XTENDER); + SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_VARIOTRACK); + SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_VARIOSTRING); + } + + // List of all Channel ids + public static final String CHANNEL_POWER = "power"; + public static final String CHANNEL_BATTERY_VOLTAGE = "batteryVoltage"; + public static final String CHANNEL_BATTERY_CURRENT = "batteryCurrent"; + public static final String CHANNEL_STATE_OF_CHARGE = "stateOfCharge"; + public static final String CHANNEL_BATTERY_TEMPERATURE = "batteryTemperature"; + + public static final String CHANNEL_INPUT_VOLTAGE = "inputVoltage"; + public static final String CHANNEL_INPUT_CURRENT = "inputCurrent"; + public static final String CHANNEL_INPUT_ACTIVE_POWER = "inputActivePower"; + public static final String CHANNEL_INPUT_FREQUENCY = "inputFrequency"; + public static final String CHANNEL_OUTPUT_VOLTAGE = "outputVoltage"; + public static final String CHANNEL_OUTPUT_CURRENT = "outputCurrent"; + public static final String CHANNEL_OUTPUT_ACTIVE_POWER = "outputActivePower"; + public static final String CHANNEL_OUTPUT_FREQUENCY = "outputFrequency"; + public static final String CHANNEL_OPERATING_STATE = "operatingState"; + public static final String CHANNEL_STATE_INVERTER = "stateInverter"; + + public static final String CHANNEL_MODEL_VARIOTRACK = "modelVarioTrack"; + public static final String CHANNEL_VOLTAGE_PV_GENERATOR = "voltagePVGenerator"; + public static final String CHANNEL_POWER_PV_GENERATOR = "powerPVGenerator"; + public static final String CHANNEL_PRODUCTION_CURRENT_DAY = "productionCurrentDay"; + public static final String CHANNEL_OPERATING_MODE = "operatingMode"; + public static final String CHANNEL_STATE_VARIOTRACK = "stateVarioTrack"; + + public static final String CHANNEL_PV_VOLTAGE = "PVVoltage"; + public static final String CHANNEL_PV_CURRENT = "PVCurrent"; + public static final String CHANNEL_PV_POWER = "PVPower"; + public static final String CHANNEL_PRODUCTION_PV_CURRENT_DAY = "ProductionPVCurrentDay"; + public static final String CHANNEL_PV_OPERATING_MODE = "PVMode"; + public static final String CHANNEL_PV1_VOLTAGE = "PV1Voltage"; + public static final String CHANNEL_PV1_CURRENT = "PV1Current"; + public static final String CHANNEL_PV1_POWER = "PV1Power"; + public static final String CHANNEL_PRODUCTION_PV1_CURRENT_DAY = "ProductionPV1CurrentDay"; + public static final String CHANNEL_PV1_OPERATING_MODE = "PV1Mode"; + public static final String CHANNEL_PV2_VOLTAGE = "PV2Voltage"; + public static final String CHANNEL_PV2_CURRENT = "PV2Current"; + public static final String CHANNEL_PV2_POWER = "PV2Power"; + public static final String CHANNEL_PRODUCTION_PV2_CURRENT_DAY = "ProductionPV2CurrentDay"; + public static final String CHANNEL_PV2_OPERATING_MODE = "PV2Mode"; + public static final String CHANNEL_STATE_VARIOSTRING = "stateVarioString"; + + /** + * Map of the supported BSP channel with their registers + */ + public static final Map CHANNELS_BSP = new HashMap<>(); + static { + CHANNELS_BSP.put(6, CHANNEL_POWER); + CHANNELS_BSP.put(0, CHANNEL_BATTERY_VOLTAGE); + CHANNELS_BSP.put(2, CHANNEL_BATTERY_CURRENT); + CHANNELS_BSP.put(4, CHANNEL_STATE_OF_CHARGE); + CHANNELS_BSP.put(58, CHANNEL_BATTERY_TEMPERATURE); + } + + /** + * Map of the supported BSP channel with their unit + */ + public static final Map> UNIT_CHANNELS_BSP = new HashMap<>(); + static { + UNIT_CHANNELS_BSP.put(6, WATT); + UNIT_CHANNELS_BSP.put(0, VOLT); + UNIT_CHANNELS_BSP.put(2, AMPERE); + UNIT_CHANNELS_BSP.put(4, PERCENT); + UNIT_CHANNELS_BSP.put(58, CELSIUS); + } + + /** + * Map of the supported Xtender channel with their registers + */ + public static final Map CHANNELS_XTENDER = new HashMap<>(); + static { + CHANNELS_XTENDER.put(22, CHANNEL_INPUT_VOLTAGE); + CHANNELS_XTENDER.put(24, CHANNEL_INPUT_CURRENT); + CHANNELS_XTENDER.put(274, CHANNEL_INPUT_ACTIVE_POWER); + CHANNELS_XTENDER.put(168, CHANNEL_INPUT_FREQUENCY); + CHANNELS_XTENDER.put(42, CHANNEL_OUTPUT_VOLTAGE); + CHANNELS_XTENDER.put(44, CHANNEL_OUTPUT_CURRENT); + CHANNELS_XTENDER.put(272, CHANNEL_OUTPUT_ACTIVE_POWER); + CHANNELS_XTENDER.put(170, CHANNEL_OUTPUT_FREQUENCY); + CHANNELS_XTENDER.put(56, CHANNEL_OPERATING_STATE); + CHANNELS_XTENDER.put(98, CHANNEL_STATE_INVERTER); + } + + /** + * Map of the supported Xtender channel with their unit + */ + public static final Map> UNIT_CHANNELS_XTENDER = new HashMap<>(); + static { + UNIT_CHANNELS_XTENDER.put(22, VOLT); + UNIT_CHANNELS_XTENDER.put(24, AMPERE); + UNIT_CHANNELS_XTENDER.put(274, KILO(WATT)); + UNIT_CHANNELS_XTENDER.put(168, HERTZ); + UNIT_CHANNELS_XTENDER.put(42, VOLT); + UNIT_CHANNELS_XTENDER.put(44, AMPERE); + UNIT_CHANNELS_XTENDER.put(272, KILO(WATT)); + UNIT_CHANNELS_XTENDER.put(170, HERTZ); + } + + /** + * Map of the supported VarioTrack channel with their registers + */ + public static final Map CHANNELS_VARIOTRACK = new HashMap<>(); + static { + CHANNELS_VARIOTRACK.put(30, CHANNEL_MODEL_VARIOTRACK); + CHANNELS_VARIOTRACK.put(4, CHANNEL_VOLTAGE_PV_GENERATOR); + CHANNELS_VARIOTRACK.put(8, CHANNEL_POWER_PV_GENERATOR); + CHANNELS_VARIOTRACK.put(14, CHANNEL_PRODUCTION_CURRENT_DAY); + CHANNELS_VARIOTRACK.put(0, CHANNEL_BATTERY_VOLTAGE); + CHANNELS_VARIOTRACK.put(2, CHANNEL_BATTERY_CURRENT); + CHANNELS_VARIOTRACK.put(32, CHANNEL_OPERATING_MODE); + CHANNELS_VARIOTRACK.put(138, CHANNEL_STATE_VARIOTRACK); + } + + /** + * Map of the supported VarioTrack channel with their unit + */ + public static final Map> UNIT_CHANNELS_VARIOTRACK = new HashMap<>(); + static { + UNIT_CHANNELS_VARIOTRACK.put(4, VOLT); + UNIT_CHANNELS_VARIOTRACK.put(8, KILO(WATT)); + UNIT_CHANNELS_VARIOTRACK.put(14, KILOWATT_HOUR); + UNIT_CHANNELS_VARIOTRACK.put(0, VOLT); + UNIT_CHANNELS_VARIOTRACK.put(2, AMPERE); + } + + /** + * Map of the supported VarioString channel with their registers + */ + public static final Map CHANNELS_VARIOSTRING = new HashMap<>(); + static { + CHANNELS_VARIOSTRING.put(0, CHANNEL_BATTERY_VOLTAGE); + CHANNELS_VARIOSTRING.put(2, CHANNEL_BATTERY_CURRENT); + CHANNELS_VARIOSTRING.put(8, CHANNEL_PV_VOLTAGE); + CHANNELS_VARIOSTRING.put(14, CHANNEL_PV_CURRENT); + CHANNELS_VARIOSTRING.put(20, CHANNEL_PV_POWER); + CHANNELS_VARIOSTRING.put(34, CHANNEL_PRODUCTION_PV_CURRENT_DAY); + CHANNELS_VARIOSTRING.put(26, CHANNEL_PV_OPERATING_MODE); + CHANNELS_VARIOSTRING.put(10, CHANNEL_PV1_VOLTAGE); + CHANNELS_VARIOSTRING.put(16, CHANNEL_PV1_CURRENT); + CHANNELS_VARIOSTRING.put(22, CHANNEL_PV1_POWER); + CHANNELS_VARIOSTRING.put(36, CHANNEL_PRODUCTION_PV1_CURRENT_DAY); + CHANNELS_VARIOSTRING.put(28, CHANNEL_PV1_OPERATING_MODE); + CHANNELS_VARIOSTRING.put(12, CHANNEL_PV2_VOLTAGE); + CHANNELS_VARIOSTRING.put(18, CHANNEL_PV2_CURRENT); + CHANNELS_VARIOSTRING.put(24, CHANNEL_PV2_POWER); + CHANNELS_VARIOSTRING.put(38, CHANNEL_PRODUCTION_PV2_CURRENT_DAY); + CHANNELS_VARIOSTRING.put(30, CHANNEL_PV2_OPERATING_MODE); + CHANNELS_VARIOSTRING.put(216, CHANNEL_STATE_VARIOSTRING); + } + + /** + * Map of the supported VarioString channel with their unit + */ + public static final Map> UNIT_CHANNELS_VARIOSTRING = new HashMap<>(); + static { + UNIT_CHANNELS_VARIOSTRING.put(0, VOLT); + UNIT_CHANNELS_VARIOSTRING.put(2, AMPERE); + UNIT_CHANNELS_VARIOSTRING.put(8, VOLT); + UNIT_CHANNELS_VARIOSTRING.put(14, AMPERE); + UNIT_CHANNELS_VARIOSTRING.put(20, KILO(WATT)); + UNIT_CHANNELS_VARIOSTRING.put(34, KILOWATT_HOUR); + UNIT_CHANNELS_VARIOSTRING.put(10, VOLT); + UNIT_CHANNELS_VARIOSTRING.put(16, AMPERE); + UNIT_CHANNELS_VARIOSTRING.put(22, KILO(WATT)); + UNIT_CHANNELS_VARIOSTRING.put(36, KILOWATT_HOUR); + UNIT_CHANNELS_VARIOSTRING.put(12, VOLT); + UNIT_CHANNELS_VARIOSTRING.put(18, AMPERE); + UNIT_CHANNELS_VARIOSTRING.put(24, KILO(WATT)); + UNIT_CHANNELS_VARIOSTRING.put(38, KILOWATT_HOUR); + } + + // List of all parameters + public static final String SLAVE_ADDRESS = "slaveAddress"; + public static final String REFRESH = "refresh"; +} diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderConfiguration.java b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderConfiguration.java new file mode 100644 index 0000000000000..1436a3b81b0e9 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderConfiguration.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2010-2020 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.studer.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link StuderConfiguration} class contains fields mapping thing configuration parameters. + * + * @author Giovanni Mirulla - Initial contribution + */ +@NonNullByDefault +public class StuderConfiguration { + /** + * Address of slave device + */ + public int slaveAddress = 0; + /** + * Refresh interval in seconds + */ + public int refresh = 5; + /** + * Max tries for one register + */ + public int maxTries = 3; +} diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandler.java b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandler.java new file mode 100644 index 0000000000000..c8f6e6ef36d09 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandler.java @@ -0,0 +1,442 @@ +/** + * Copyright (c) 2010-2020 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.studer.internal; + +import static org.openhab.binding.modbus.studer.internal.StuderBindingConstants.*; + +import java.util.ArrayList; +import java.util.Optional; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.smarthome.core.library.types.OnOffType; +import org.eclipse.smarthome.core.library.types.QuantityType; +import org.eclipse.smarthome.core.library.types.StringType; +import org.eclipse.smarthome.core.thing.Bridge; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.ThingStatus; +import org.eclipse.smarthome.core.thing.ThingStatusDetail; +import org.eclipse.smarthome.core.thing.ThingStatusInfo; +import org.eclipse.smarthome.core.thing.ThingTypeUID; +import org.eclipse.smarthome.core.thing.binding.BaseThingHandler; +import org.eclipse.smarthome.core.thing.binding.ThingHandler; +import org.eclipse.smarthome.core.types.Command; +import org.eclipse.smarthome.core.types.UnDefType; +import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler; +import org.openhab.binding.modbus.studer.internal.StuderParser.ModeXtender; +import org.openhab.binding.modbus.studer.internal.StuderParser.VSMode; +import org.openhab.binding.modbus.studer.internal.StuderParser.VTMode; +import org.openhab.binding.modbus.studer.internal.StuderParser.VTType; +import org.openhab.io.transport.modbus.AsyncModbusFailure; +import org.openhab.io.transport.modbus.ModbusCommunicationInterface; +import org.openhab.io.transport.modbus.ModbusReadFunctionCode; +import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint; +import org.openhab.io.transport.modbus.ModbusRegisterArray; +import org.openhab.io.transport.modbus.PollTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link StuderHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Giovanni Mirulla - Initial contribution + */ +@NonNullByDefault +public class StuderHandler extends BaseThingHandler { + + private final Logger logger = LoggerFactory.getLogger(StuderHandler.class); + + private @Nullable StuderConfiguration config; + + /** + * Array of tasks used to poll the device + */ + private ArrayList pollTasks = new ArrayList(); + + /** + * Communication interface to the slave endpoint we're connecting to + */ + protected volatile @Nullable ModbusCommunicationInterface comms = null; + + /** + * Importing parser methods and enums + */ + final StuderParser parser = new StuderParser(); + /** + * Support variable for type of thing + */ + protected ThingTypeUID type; + + /** + * Array of registers of Studer slave to read, we store this once initialization is complete + */ + private Integer[] registers = new Integer[0]; + + /** + * Instances of this handler + * + * @param thing the thing to handle + * @param type the type of thing to handle + * @param slaveAddress the address of thing + * @param refreshSec the address of thing + */ + public StuderHandler(Thing thing) { + super(thing); + this.type = thing.getThingTypeUID(); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + + // Currently we do not support any commands + } + + /** + * Initialization: + * Load the config object + * Connect to the slave bridge + * Get registers to poll + * Start the periodic polling + */ + @Override + public void initialize() { + config = getConfigAs(StuderConfiguration.class); + logger.debug("Initializing thing with configuration: {}", thing.getConfiguration()); + + startUp(); + } + + /* + * This method starts the operation of this handler + * Connect to the slave bridge + * Get registers to poll + * Start the periodic polling + */ + private void startUp() { + + connectEndpoint(); + + if (comms == null || config == null) { + logger.debug("Invalid endpoint/config/manager ref for studer handler"); + return; + } + + if (!pollTasks.isEmpty()) { + return; + } + + if (type.equals(THING_TYPE_BSP)) { + Set keys = CHANNELS_BSP.keySet(); + registers = keys.toArray(new Integer[keys.size()]); + } else if (type.equals(THING_TYPE_XTENDER)) { + Set keys = CHANNELS_XTENDER.keySet(); + registers = keys.toArray(new Integer[keys.size()]); + } else if (type.equals(THING_TYPE_VARIOTRACK)) { + Set keys = CHANNELS_VARIOTRACK.keySet(); + registers = keys.toArray(new Integer[keys.size()]); + } else if (type.equals(THING_TYPE_VARIOSTRING)) { + Set keys = CHANNELS_VARIOSTRING.keySet(); + registers = keys.toArray(new Integer[keys.size()]); + } + + for (int r : registers) { + registerPollTask(r); + + } + } + + /** + * Dispose the binding correctly + */ + @Override + public void dispose() { + tearDown(); + } + + /** + * Unregister the poll tasks and release the endpoint reference + */ + private void tearDown() { + unregisterPollTasks(); + unregisterEndpoint(); + } + + /** + * 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) { + ModbusEndpointThingHandler slaveEndpoint = (ModbusEndpointThingHandler) handler; + return slaveEndpoint; + } else { + logger.debug("Unexpected bridge handler: {}", handler); + return null; + } + } + + /** + * Get a reference to the modbus endpoint + */ + private void connectEndpoint() { + if (comms != null) { + return; + } + + 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)); + logger.debug("No bridge handler available -- aborting init for {}", label); + return; + } + comms = slaveEndpointThingHandler.getCommunicationInterface(); + 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)); + logger.debug("Bridge not initialized fully (no endpoint) -- aborting init for {}", this); + return; + } + } + + /** + * Remove the endpoint if exists + */ + private void unregisterEndpoint() { + // Comms will be close()'d by endpoint thing handler + comms = null; + } + + private synchronized void unregisterPollTasks() { + if (pollTasks.isEmpty()) { + return; + } + logger.debug("Unregistering polling from ModbusManager"); + ModbusCommunicationInterface mycomms = comms; + if (mycomms != null) { + for (PollTask t : pollTasks) { + mycomms.unregisterRegularPoll(t); + } + pollTasks.clear(); + } + } + + /** + * Register poll task + * This is where we set up our regular poller + */ + private synchronized void registerPollTask(int registerNumber) { + if (pollTasks.size() >= registers.length) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR); + throw new IllegalStateException("New pollTask invalid"); + } + ModbusCommunicationInterface mycomms = comms; + StuderConfiguration studerConfig = config; + if (studerConfig == null || mycomms == null) { + throw new IllegalStateException("registerPollTask called without proper configuration"); + } + + logger.debug("Setting up regular polling"); + + ModbusReadRequestBlueprint request = new ModbusReadRequestBlueprint(studerConfig.slaveAddress, + ModbusReadFunctionCode.READ_INPUT_REGISTERS, registerNumber, 2, studerConfig.maxTries); + long refreshMillis = studerConfig.refresh * 1000; + PollTask pollTask = mycomms.registerRegularPoll(request, refreshMillis, 1000, result -> { + if (result.getRegisters().isPresent()) { + ModbusRegisterArray reg = result.getRegisters().get(); + handlePolledData(registerNumber, reg); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR); + return; + } + if (getThing().getStatus() != ThingStatus.ONLINE) { + updateStatus(ThingStatus.ONLINE); + } + }, this::handleError); + pollTasks.add(pollTask); + } + + /** + * This method is called each time new data has been polled from the modbus slave + * The register array is first parsed, then each of the channels are updated + * to the new values + * + * @param n register readed + * @param registers byte array read from the modbus slave + */ + protected void handlePolledData(int registerNumber, ModbusRegisterArray registers) { + String hexString = registers.toHexString().toString(); + Float quantity = parser.hexToFloat(hexString); + if (quantity != null) { + if (type.equals(THING_TYPE_BSP)) { + updateState(CHANNELS_BSP.get(registerNumber), + new QuantityType<>(quantity, UNIT_CHANNELS_BSP.get(registerNumber))); + } else if (type.equals(THING_TYPE_XTENDER)) { + handlePolledDataXtender(registerNumber, quantity); + } else if (type.equals(THING_TYPE_VARIOTRACK)) { + handlePolledDataVarioTrack(registerNumber, quantity); + } else if (type.equals(THING_TYPE_VARIOSTRING)) { + handlePolledDataVarioString(registerNumber, quantity); + } + } + resetCommunicationError(); + } + + /** + * This method is called each time new data has been polled from the VarioString slave + * The register array is first parsed, then each of the channels are updated + * to the new values + */ + protected void handlePolledDataVarioString(int registerNumber, Float quantity) { + switch (CHANNELS_VARIOSTRING.get(registerNumber)) { + case CHANNEL_PV_OPERATING_MODE: + case CHANNEL_PV1_OPERATING_MODE: + case CHANNEL_PV2_OPERATING_MODE: + VSMode vsmode = StuderParser.getVSModeByCode(quantity.intValue()); + if (vsmode == VSMode.UNKNOWN) { + updateState(CHANNELS_VARIOSTRING.get(registerNumber), UnDefType.UNDEF); + } else { + updateState(CHANNELS_VARIOSTRING.get(registerNumber), new StringType(vsmode.name())); + } + break; + case CHANNEL_STATE_VARIOSTRING: + OnOffType vsstate = StuderParser.getStateByCode(quantity.intValue()); + updateState(CHANNELS_VARIOSTRING.get(registerNumber), vsstate); + break; + default: + updateState(CHANNELS_VARIOSTRING.get(registerNumber), + new QuantityType<>(quantity, UNIT_CHANNELS_VARIOSTRING.get(registerNumber))); + } + } + + /** + * This method is called each time new data has been polled from the VarioTrack slave + * The register array is first parsed, then each of the channels are updated + * to the new values + */ + protected void handlePolledDataVarioTrack(int registerNumber, Float quantity) { + switch (CHANNELS_VARIOTRACK.get(registerNumber)) { + case CHANNEL_MODEL_VARIOTRACK: + VTType type = StuderParser.getVTTypeByCode(quantity.intValue()); + if (type == VTType.UNKNOWN) { + updateState(CHANNELS_VARIOTRACK.get(registerNumber), UnDefType.UNDEF); + } else { + updateState(CHANNELS_VARIOTRACK.get(registerNumber), new StringType(type.name())); + } + break; + + case CHANNEL_OPERATING_MODE: + VTMode vtmode = StuderParser.getVTModeByCode(quantity.intValue()); + if (vtmode == VTMode.UNKNOWN) { + updateState(CHANNELS_VARIOTRACK.get(registerNumber), UnDefType.UNDEF); + } else { + updateState(CHANNELS_VARIOTRACK.get(registerNumber), new StringType(vtmode.name())); + } + break; + + case CHANNEL_STATE_VARIOTRACK: + OnOffType vtstate = StuderParser.getStateByCode(quantity.intValue()); + updateState(CHANNELS_VARIOTRACK.get(registerNumber), vtstate); + break; + default: + updateState(CHANNELS_VARIOTRACK.get(registerNumber), + new QuantityType<>(quantity, UNIT_CHANNELS_VARIOTRACK.get(registerNumber))); + } + } + + /** + * This method is called each time new data has been polled from the Xtender slave + * The register array is first parsed, then each of the channels are updated + * to the new values + */ + protected void handlePolledDataXtender(int registerNumber, Float quantity) { + switch (CHANNELS_XTENDER.get(registerNumber)) { + case CHANNEL_OPERATING_STATE: + ModeXtender mode = StuderParser.getModeXtenderByCode(quantity.intValue()); + if (mode == ModeXtender.UNKNOWN) { + updateState(CHANNELS_XTENDER.get(registerNumber), UnDefType.UNDEF); + } else { + updateState(CHANNELS_XTENDER.get(registerNumber), new StringType(mode.name())); + } + break; + case CHANNEL_STATE_INVERTER: + OnOffType xtstate = StuderParser.getStateByCode(quantity.intValue()); + updateState(CHANNELS_XTENDER.get(registerNumber), xtstate); + break; + default: + updateState(CHANNELS_XTENDER.get(registerNumber), + new QuantityType<>(quantity, UNIT_CHANNELS_XTENDER.get(registerNumber))); + } + } + + /** + * Handle errors received during communication + */ + protected void handleError(AsyncModbusFailure failure) { + // Ignore all incoming data and errors if configuration is not correct + if (hasConfigurationError() || getThing().getStatus() == ThingStatus.OFFLINE) { + return; + } + String msg = failure.getCause().getMessage(); + String cls = failure.getCause().getClass().getName(); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, + String.format("Error with read: %s: %s", cls, msg)); + } + + /** + * Returns true, if we're in a CONFIGURATION_ERROR state + * + * @return + */ + protected boolean hasConfigurationError() { + ThingStatusInfo statusInfo = getThing().getStatusInfo(); + return statusInfo.getStatus() == ThingStatus.OFFLINE + && statusInfo.getStatusDetail() == ThingStatusDetail.CONFIGURATION_ERROR; + } + + /** + * Reset communication status to ONLINE if we're in an OFFLINE state + */ + protected void resetCommunicationError() { + ThingStatusInfo statusInfo = thing.getStatusInfo(); + if (ThingStatus.OFFLINE.equals(statusInfo.getStatus()) + && ThingStatusDetail.COMMUNICATION_ERROR.equals(statusInfo.getStatusDetail())) { + updateStatus(ThingStatus.ONLINE); + } + } +} diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandlerFactory.java b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandlerFactory.java new file mode 100644 index 0000000000000..f15eb9eea264d --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderHandlerFactory.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2010-2020 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.studer.internal; + +import static org.openhab.binding.modbus.studer.internal.StuderBindingConstants.SUPPORTED_THING_TYPES_UIDS; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.ThingTypeUID; +import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory; +import org.eclipse.smarthome.core.thing.binding.ThingHandler; +import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Component; + +/** + * The {@link StuderHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Giovanni Mirulla - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.studer", service = ThingHandlerFactory.class) +public class StuderHandlerFactory extends BaseThingHandlerFactory { + + @Override + public boolean supportsThingType(ThingTypeUID thingTypeUID) { + return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); + } + + @Override + protected @Nullable ThingHandler createHandler(Thing thing) { + return new StuderHandler(thing); + } +} diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderParser.java b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderParser.java new file mode 100644 index 0000000000000..830792a4efed0 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/src/main/java/org/openhab/binding/modbus/studer/internal/StuderParser.java @@ -0,0 +1,218 @@ +/** + * Copyright (c) 2010-2020 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.studer.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.smarthome.core.library.types.OnOffType; + +/** + * The {@link StuderParser} class with helper method + * and possible values for mode and state + * + * @author Giovanni Mirulla - Initial contribution + */ +@NonNullByDefault +public class StuderParser { + public enum ModeXtender { + INVALID(0), + INVERTER(1), + CHARGER(2), + BOOST(3), + INJECTION(4), + UNKNOWN(-1); + + private final int code; + + ModeXtender(int code) { + this.code = code; + } + + public int code() { + return this.code; + } + } + + public static ModeXtender getModeXtenderByCode(int code) { + switch (code) { + case 0: + return ModeXtender.INVALID; + case 1: + return ModeXtender.INVERTER; + case 2: + return ModeXtender.CHARGER; + case 3: + return ModeXtender.BOOST; + case 4: + return ModeXtender.INJECTION; + default: + return ModeXtender.UNKNOWN; + } + } + + public static OnOffType getStateByCode(int code) { + switch (code) { + case 0: + return OnOffType.OFF; + case 1: + return OnOffType.ON; + default: + return OnOffType.OFF; + } + } + + public enum VTType { + VT80(0), + VT65(1), + UNKNOWN(-1); + + private final int code; + + VTType(int code) { + this.code = code; + } + + public int code() { + return this.code; + } + } + + public static VTType getVTTypeByCode(int code) { + switch (code) { + case 0: + return VTType.VT80; + case 1: + return VTType.VT65; + default: + return VTType.UNKNOWN; + } + } + + public enum VTMode { + NIGHT(0), + STARTUP(1), + CHARGER(3), + SECURITY(5), + OFF(6), + CHARGE(8), + CHARGEV(9), + CHARGEI(10), + CHARGET(11), + CHIBSP(12), + UNKNOWN(-1); + + private final int code; + + VTMode(int code) { + this.code = code; + } + + public int code() { + return this.code; + } + } + + public static VTMode getVTModeByCode(int code) { + switch (code) { + case 0: + return VTMode.NIGHT; + case 1: + return VTMode.STARTUP; + case 3: + return VTMode.CHARGER; + case 5: + return VTMode.SECURITY; + case 6: + return VTMode.OFF; + case 8: + return VTMode.CHARGE; + case 9: + return VTMode.CHARGEV; + case 10: + return VTMode.CHARGEI; + case 11: + return VTMode.CHARGET; + case 12: + return VTMode.CHIBSP; + default: + return VTMode.UNKNOWN; + } + } + + public enum VSMode { + NIGHT(0), + SECURITY(1), + OFF(2), + CHARGE(3), + CHARGEV(4), + CHARGEI(5), + CHARGEP(6), + CHARGEIPV(7), + CHARGET(8), + CHIBSP(10), + UNKNOWN(-1); + + private final int code; + + VSMode(int code) { + this.code = code; + } + + public int code() { + return this.code; + } + } + + public static VSMode getVSModeByCode(int code) { + switch (code) { + case 0: + return VSMode.NIGHT; + case 1: + return VSMode.SECURITY; + case 2: + return VSMode.OFF; + case 3: + return VSMode.CHARGE; + case 4: + return VSMode.CHARGEV; + case 5: + return VSMode.CHARGEI; + case 6: + return VSMode.CHARGEP; + case 7: + return VSMode.CHARGEIPV; + case 8: + return VSMode.CHARGET; + case 10: + return VSMode.CHIBSP; + default: + return VSMode.UNKNOWN; + } + } + + /** + * Convert an hex string to float + * + * @param hex string to convert from + * @return the converted float + */ + public @Nullable Float hexToFloat(String hex) { + String t = hex.replaceAll(" ", ""); + float f = Float.intBitsToFloat((int) Long.parseLong(t, 16)); + if (Float.isNaN(f)) { + return null; + } else { + return f; + } + } +} diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/BSP-channel-types.xml b/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/BSP-channel-types.xml new file mode 100644 index 0000000000000..39dbdaa3c5493 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/BSP-channel-types.xml @@ -0,0 +1,24 @@ + + + + + Number:Power + + + + + + Number:Dimensionless + + + + + + Number:Temperature + + + + diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/Common-channel-types.xml b/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/Common-channel-types.xml new file mode 100644 index 0000000000000..84ea4f78e70da --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/Common-channel-types.xml @@ -0,0 +1,18 @@ + + + + + Number:ElectricPotential + + + + + + Number:ElectricCurrent + + + + diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/VarioTrack-channel-types.xml b/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/VarioTrack-channel-types.xml new file mode 100644 index 0000000000000..313e11902b8de --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/VarioTrack-channel-types.xml @@ -0,0 +1,61 @@ + + + + + String + + + + + + + + + + + Number:ElectricPotential + + + + + + Number:Power + + + + + + Number:Energy + + + + + + String + + + + + + + + + + + + + + + + + + + + Switch + + + + diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/VariotString-channel-types.xml b/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/VariotString-channel-types.xml new file mode 100644 index 0000000000000..d76ef0431bd45 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/VariotString-channel-types.xml @@ -0,0 +1,144 @@ + + + + + Number:ElectricPotential + + + + + + Number:ElectricCurrent + + + + + + Number:Power + + + + + + Number:Energy + + + + + + String + + + + + + + + + + + + + + + + + + + + Number:ElectricPotential + + + + + + Number:ElectricCurrent + + + + + + Number:Power + + + + + + Number:Energy + + + + + + String + + + + + + + + + + + + + + + + + + + + Number:ElectricPotential + + + + + + Number:ElectricCurrent + + + + + + Number:Power + + + + + + Number:Energy + + + + + + String + + + + + + + + + + + + + + + + + + + + Switch + + + + diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/Xtender-channel-types.xml b/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/Xtender-channel-types.xml new file mode 100644 index 0000000000000..00cd830c25760 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/Xtender-channel-types.xml @@ -0,0 +1,79 @@ + + + + + Number:ElectricPotential + + + + + + Number:ElectricCurrent + + + + + + Number:Power + + + + + + Number:Frequency + + + + + + Number:ElectricPotential + + + + + + Number:ElectricCurrent + + + + + + Number:Power + + + + + + Number:Frequency + + + + + + String + + + + + + + + + + + + + + String + + + + + + + + + diff --git a/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/thing-types.xml new file mode 100644 index 0000000000000..8c0d9ea38330e --- /dev/null +++ b/bundles/org.openhab.binding.modbus.studer/src/main/resources/ESH-INF/thing/thing-types.xml @@ -0,0 +1,139 @@ + + + + + + + + + Thing for Studer BSP Device + + + + + + + + + + + Slave address of BSP device + 60 + + + + Poll interval + 5 + true + + + + + + + + + + Thing for Studer Xtender Device + + + + + + + + + + + + + + + + Slave address of Xtender device + 10 + + + + Poll interval + 5 + true + + + + + + + + + + Thing for Studer VarioTrack Device + + + + + + + + + + + + + + Slave address of VarioTrack device + 20 + + + + Poll interval + 5 + true + + + + + + + + + + Thing for Studer VarioString Device + + + + + + + + + + + + + + + + + + + + + + + + Slave address of VarioString device + 40 + + + + Poll interval + 5 + true + + + + diff --git a/bundles/pom.xml b/bundles/pom.xml index 52f3a06b66a64..78d2713a4ba41 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -166,6 +166,7 @@ org.openhab.binding.minecraft org.openhab.binding.modbus org.openhab.binding.modbus.e3dc + org.openhab.binding.modbus.studer org.openhab.binding.modbus.sunspec org.openhab.binding.modbus.stiebeleltron org.openhab.binding.monopriceaudio