added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -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>
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user