added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.modbus.studer-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>file:${basedirRoot}/bundles/org.openhab.io.transport.modbus/target/feature/feature.xml</repository>
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-bindings-modbus-studer" description="Studer Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-transport-modbus</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.modbus/${project.version}</bundle>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.modbus.studer/${project.version}</bundle>
</feature>
</features>

View File

@@ -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.openhab.core.library.unit.MetricPrefix.KILO;
import static org.openhab.core.library.unit.SIUnits.CELSIUS;
import static org.openhab.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.openhab.binding.modbus.ModbusBindingConstants;
import org.openhab.core.thing.ThingTypeUID;
/**
* 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<ThingTypeUID> 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<Integer, String> 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<Integer, Unit<?>> 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<Integer, String> 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<Integer, Unit<?>> 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<Integer, String> 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<Integer, Unit<?>> 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<Integer, String> 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<Integer, Unit<?>> 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";
}

View File

@@ -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;
}

View File

@@ -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.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.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
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.ThingStatusInfo;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.UnDefType;
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<PollTask> pollTasks = new ArrayList<PollTask>();
/**
* 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<Integer> keys = CHANNELS_BSP.keySet();
registers = keys.toArray(new Integer[keys.size()]);
} else if (type.equals(THING_TYPE_XTENDER)) {
Set<Integer> keys = CHANNELS_XTENDER.keySet();
registers = keys.toArray(new Integer[keys.size()]);
} else if (type.equals(THING_TYPE_VARIOTRACK)) {
Set<Integer> keys = CHANNELS_VARIOTRACK.keySet();
registers = keys.toArray(new Integer[keys.size()]);
} else if (type.equals(THING_TYPE_VARIOSTRING)) {
Set<Integer> 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("<null>");
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("<null>");
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<ModbusReadRequestBlueprint> 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);
}
}
}

View File

@@ -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.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 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);
}
}

View File

@@ -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.openhab.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;
}
}
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Power Channel Type -->
<channel-type id="Pbat">
<item-type>Number:Power</item-type>
<label>Power</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- State of charge Channel Type -->
<channel-type id="SOC">
<item-type>Number:Dimensionless</item-type>
<label>State of Charge</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Battery temperature Channel Type -->
<channel-type id="Tbat">
<item-type>Number:Temperature</item-type>
<label>Battery Temperature</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Battery voltage Channel Type -->
<channel-type id="Ubat">
<item-type>Number:ElectricPotential</item-type>
<label>Battery Voltage</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Battery current Channel Type -->
<channel-type id="Ibat">
<item-type>Number:ElectricCurrent</item-type>
<label>Battery Current</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Model of VarioTrack Channel Type -->
<channel-type id="Type">
<item-type>String</item-type>
<label>Model of VarioTrack</label>
<state readOnly="true">
<options>
<option value="VT80">VT-80</option>
<option value="VT65">VT-65</option>
</options>
</state>
</channel-type>
<!-- Voltage of the PV generator Channel Type -->
<channel-type id="Upv">
<item-type>Number:ElectricPotential</item-type>
<label>PV Generator Voltage</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Power of the PV generator Channel Type -->
<channel-type id="Psol">
<item-type>Number:Power</item-type>
<label>Power of the PV Generator</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Production in (kWh) for the current day Channel Type -->
<channel-type id="Ed">
<item-type>Number:Energy</item-type>
<label>Current Day Production</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Operating state Channel Type -->
<channel-type id="Mode">
<item-type>String</item-type>
<label>Operating Mode</label>
<state readOnly="true">
<options>
<option value="NIGHT">Night</option>
<option value="STARTUP">StartUp</option>
<option value="UNKNOWN">---</option>
<option value="CHARGER">Charger</option>
<option value="SECURITY">Security</option>
<option value="OFF">OFF</option>
<option value="CHARGE">Charge</option>
<option value="CHARGEV">Charge V</option>
<option value="CHARGEI">Charge I</option>
<option value="CHARGET">Charge T</option>
<option value="CHIBSP">Ch. Ibsp</option>
</options>
</state>
</channel-type>
<!-- State of the VarioTrack Channel Type -->
<channel-type id="VTstate">
<item-type>Switch</item-type>
<label>State of the VarioTrack</label>
<state readOnly="true"></state>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- PV voltage Channel Type -->
<channel-type id="Upv0">
<item-type>Number:ElectricPotential</item-type>
<label>PV Voltage</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- PV current Channel Type -->
<channel-type id="Ipv0">
<item-type>Number:ElectricCurrent</item-type>
<label>PV Current</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- PV Power Channel Type -->
<channel-type id="Ppv0">
<item-type>Number:Power</item-type>
<label>PV Power</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Production PV in (kWh) for the current day Channel Type -->
<channel-type id="Ed0">
<item-type>Number:Energy</item-type>
<label>PV Current Day Production</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- PV operating mode Channel Type -->
<channel-type id="Mod0">
<item-type>String</item-type>
<label>PV Operating State</label>
<state readOnly="true">
<options>
<option value="NIGHT">Night</option>
<option value="SECURITY">Security</option>
<option value="OFF">OFF</option>
<option value="CHARGE">Charge</option>
<option value="CHARGEV">Charge V</option>
<option value="CHARGEI">Charge I</option>
<option value="CHARGEP">Charge P</option>
<option value="CHARGEIPV">Charge Ipv</option>
<option value="CHARGET">Charge T</option>
<option value="UNKNOWN">---</option>
<option value="CHIBSP">Ch. Ibsp</option>
</options>
</state>
</channel-type>
<!-- PV1 voltage Channel Type -->
<channel-type id="Upv1">
<item-type>Number:ElectricPotential</item-type>
<label>PV1 Voltage</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- PV1 current Channel Type -->
<channel-type id="Ipv1">
<item-type>Number:ElectricCurrent</item-type>
<label>PV1 Current</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- PV1 Power Channel Type -->
<channel-type id="Ppv1">
<item-type>Number:Power</item-type>
<label>PV1 Power</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Production PV1 in (kWh) for the current day Channel Type -->
<channel-type id="Ed1">
<item-type>Number:Energy</item-type>
<label>PV1 Current Day Production</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- PV1 operating mode Channel Type -->
<channel-type id="Mod1">
<item-type>String</item-type>
<label>PV1 Operating State</label>
<state readOnly="true">
<options>
<option value="NIGHT">Night</option>
<option value="SECURITY">Security</option>
<option value="OFF">OFF</option>
<option value="CHARGE">Charge</option>
<option value="CHARGEV">Charge V</option>
<option value="CHARGEI">Charge I</option>
<option value="CHARGEP">Charge P</option>
<option value="CHARGEIPV">Charge Ipv</option>
<option value="CHARGET">Charge T</option>
<option value="UNKNOWN">---</option>
<option value="CHIBSP">Ch. Ibsp</option>
</options>
</state>
</channel-type>
<!-- PV2 voltage Channel Type -->
<channel-type id="Upv2">
<item-type>Number:ElectricPotential</item-type>
<label>PV2 Voltage</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- PV2 current Channel Type -->
<channel-type id="Ipv2">
<item-type>Number:ElectricCurrent</item-type>
<label>PV2 Current</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- PV2 Power Channel Type -->
<channel-type id="Ppv2">
<item-type>Number:Power</item-type>
<label>PV2 Power</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Production PV2 in (kWh) for the current day Channel Type -->
<channel-type id="Ed2">
<item-type>Number:Energy</item-type>
<label>PV2 Current Day Production</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- PV operating mode Channel Type -->
<channel-type id="Mod2">
<item-type>String</item-type>
<label>PV2 Operating State</label>
<state readOnly="true">
<options>
<option value="NIGHT">Night</option>
<option value="SECURITY">Security</option>
<option value="OFF">OFF</option>
<option value="CHARGE">Charge</option>
<option value="CHARGEV">Charge V</option>
<option value="CHARGEI">Charge I</option>
<option value="CHARGEP">Charge P</option>
<option value="CHARGEIPV">Charge Ipv</option>
<option value="CHARGET">Charge T</option>
<option value="UNKNOWN">---</option>
<option value="CHIBSP">Ch. Ibsp</option>
</options>
</state>
</channel-type>
<!-- State of the VarioString Channel Type -->
<channel-type id="VSstate">
<item-type>Switch</item-type>
<label>State of the VarioString</label>
<state readOnly="true"></state>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Input voltage Channel Type -->
<channel-type id="Uin">
<item-type>Number:ElectricPotential</item-type>
<label>Input Voltage</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Input current Channel Type -->
<channel-type id="Iin">
<item-type>Number:ElectricCurrent</item-type>
<label>Input Current</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Input active power Channel Type -->
<channel-type id="Pina">
<item-type>Number:Power</item-type>
<label>Input Active Power</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Input frequency Channel Type -->
<channel-type id="Fin">
<item-type>Number:Frequency</item-type>
<label>Input Frequency</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Output voltage Channel Type -->
<channel-type id="Uout">
<item-type>Number:ElectricPotential</item-type>
<label>Output Voltage</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Output current Channel Type -->
<channel-type id="Iout">
<item-type>Number:ElectricCurrent</item-type>
<label>Output Current</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Output active power Channel Type -->
<channel-type id="Pouta">
<item-type>Number:Power</item-type>
<label>Output Active Power</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Output frequency Channel Type -->
<channel-type id="Fout">
<item-type>Number:Frequency</item-type>
<label>Output Frequency</label>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<!-- Operating state Channel Type -->
<channel-type id="Mode">
<item-type>String</item-type>
<label>Operating State</label>
<state readOnly="true">
<options>
<option value="INVALID">Invalid value</option>
<option value="INVERTER">Inverter</option>
<option value="CHARGER">Charger</option>
<option value="BOOST">Boost</option>
<option value="INJECTION">Injection</option>
</options>
</state>
</channel-type>
<!-- State of the inverter Channel Type -->
<channel-type id="XTstate">
<item-type>String</item-type>
<label>State of the Inverter</label>
<state readOnly="true">
<options>
<option value="OFF">OFF</option>
<option value="ON">ON</option>
</options>
</state>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,139 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- BSP Thing Type -->
<thing-type id="bsp">
<supported-bridge-type-refs>
<bridge-type-ref id="serial"/>
</supported-bridge-type-refs>
<label>BSP Studer</label>
<description>Thing for Studer BSP Device</description>
<channels>
<channel id="batteryVoltage" typeId="Ubat"/>
<channel id="batteryCurrent" typeId="Ibat"/>
<channel id="power" typeId="Pbat"/>
<channel id="stateOfCharge" typeId="SOC"/>
<channel id="batteryTemperature" typeId="Tbat"/>
</channels>
<config-description>
<parameter name="slaveAddress" type="integer" min="60" max="61">
<label>Slave Address</label>
<description>Slave address of BSP device</description>
<default>60</default>
</parameter>
<parameter name="refresh" type="integer" min="1" unit="s">
<label>Refresh Interval</label>
<description>Poll interval</description>
<default>5</default>
<advanced>true</advanced>
</parameter>
</config-description>
</thing-type>
<!-- Xtender Thing Type -->
<thing-type id="xtender">
<supported-bridge-type-refs>
<bridge-type-ref id="serial"/>
</supported-bridge-type-refs>
<label>Xtender Studer</label>
<description>Thing for Studer Xtender Device</description>
<channels>
<channel id="inputVoltage" typeId="Uin"/>
<channel id="inputCurrent" typeId="Iin"/>
<channel id="inputActivePower" typeId="Pina"/>
<channel id="inputFrequency" typeId="Fin"/>
<channel id="outputVoltage" typeId="Uout"/>
<channel id="outputCurrent" typeId="Iout"/>
<channel id="outputActivePower" typeId="Pouta"/>
<channel id="outputFrequency" typeId="Fout"/>
<channel id="operatingState" typeId="Mode"/>
<channel id="stateInverter" typeId="XTstate"/>
</channels>
<config-description>
<parameter name="slaveAddress" type="integer" min="10" max="19">
<label>Slave Address</label>
<description>Slave address of Xtender device</description>
<default>10</default>
</parameter>
<parameter name="refresh" type="integer" min="1" unit="s">
<label>Refresh Interval</label>
<description>Poll interval</description>
<default>5</default>
<advanced>true</advanced>
</parameter>
</config-description>
</thing-type>
<!-- VarioTrack Thing Type -->
<thing-type id="variotrack">
<supported-bridge-type-refs>
<bridge-type-ref id="serial"/>
</supported-bridge-type-refs>
<label>VarioTrack Studer</label>
<description>Thing for Studer VarioTrack Device</description>
<channels>
<channel id="batteryVoltage" typeId="Ubat"/>
<channel id="batteryCurrent" typeId="Ibat"/>
<channel id="modelVarioTrack" typeId="Type"/>
<channel id="voltagePVGenerator" typeId="Upv"/>
<channel id="powerPVGenerator" typeId="Psol"/>
<channel id="productionCurrentDay" typeId="Ed"/>
<channel id="operatingMode" typeId="Mode"/>
<channel id="stateVarioTrack" typeId="VTstate"/>
</channels>
<config-description>
<parameter name="slaveAddress" type="integer" min="20" max="35">
<label>Slave Address</label>
<description>Slave address of VarioTrack device</description>
<default>20</default>
</parameter>
<parameter name="refresh" type="integer" min="1" unit="s">
<label>Refresh Interval</label>
<description>Poll interval</description>
<default>5</default>
<advanced>true</advanced>
</parameter>
</config-description>
</thing-type>
<!-- VarioString Thing Type -->
<thing-type id="variostring">
<supported-bridge-type-refs>
<bridge-type-ref id="serial"/>
</supported-bridge-type-refs>
<label>VarioString Studer</label>
<description>Thing for Studer VarioString Device</description>
<channels>
<channel id="batteryVoltage" typeId="Ubat"/>
<channel id="batteryCurrent" typeId="Ibat"/>
<channel id="PVVoltage" typeId="Upv0"/>
<channel id="PVCurrent" typeId="Ipv0"/>
<channel id="PVPower" typeId="Ppv0"/>
<channel id="ProductionPVCurrentDay" typeId="Ed0"/>
<channel id="PVMode" typeId="Mod0"/>
<channel id="PV1Voltage" typeId="Upv1"/>
<channel id="PV1Current" typeId="Ipv1"/>
<channel id="PV1Power" typeId="Ppv1"/>
<channel id="ProductionPV1CurrentDay" typeId="Ed1"/>
<channel id="PV1Mode" typeId="Mod1"/>
<channel id="PV2Voltage" typeId="Upv2"/>
<channel id="PV2Current" typeId="Ipv2"/>
<channel id="PV2Power" typeId="Ppv2"/>
<channel id="ProductionPV2CurrentDay" typeId="Ed2"/>
<channel id="PV2Mode" typeId="Mod2"/>
<channel id="stateVarioString" typeId="VSstate"/>
</channels>
<config-description>
<parameter name="slaveAddress" type="integer" min="40" max="55">
<label>Slave Address</label>
<description>Slave address of VarioString device</description>
<default>40</default>
</parameter>
<parameter name="refresh" type="integer" min="1" unit="s">
<label>Refresh Interval</label>
<description>Poll interval</description>
<default>5</default>
<advanced>true</advanced>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>