[openthermgateway] Add support for Ventilation/Heat Recovery units (#12367)
* [openthermgateway] clean version of prior PR * [openthermgateway] fix NoSuchMethod exception * [openthermgateway] create thread according to OH guidelines * [openthermgateway] fix annotation warning * [openthermgateway] framework handles bridge status changes * [openthermgateway] implement learnings from PR #12356 * [openthermgateway] add ReadMe chapter on migration v3.2 .. v3.3 * [openthermgateway] delete duplicate OpenThermGatewayBindingConstants class * [openthermgateway] remove redundant else clause, remove npe warning * [openthermgateway] log to debug rather than info; eliminate static import * [openthermgateway] eliminate static import * [openthermgateway] suppress unused argument warning * [openthermgateway] delete xml definitions for no longer used 'otgw' Thing type Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
This commit is contained in:
committed by
GitHub
parent
5842ad1644
commit
ba07a870fe
@@ -1,101 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.openthermgateway;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link OpenThermGatewayBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenThermGatewayBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "openthermgateway";
|
||||
|
||||
// List of all Thing Type UID's
|
||||
public static final ThingTypeUID MAIN_THING_TYPE = new ThingTypeUID(BINDING_ID, "otgw");
|
||||
|
||||
// List of all Channel id's
|
||||
public static final String CHANNEL_SEND_COMMAND = "sendcommand";
|
||||
|
||||
public static final String CHANNEL_OVERRIDE_SETPOINT_TEMPORARY = "temperaturetemporary";
|
||||
public static final String CHANNEL_OVERRIDE_SETPOINT_CONSTANT = "temperatureconstant";
|
||||
public static final String CHANNEL_OVERRIDE_DHW_SETPOINT = "overridedhwsetpoint";
|
||||
public static final String CHANNEL_ROOM_TEMPERATURE = "roomtemp";
|
||||
public static final String CHANNEL_ROOM_SETPOINT = "roomsetpoint";
|
||||
public static final String CHANNEL_FLOW_TEMPERATURE = "flowtemp";
|
||||
public static final String CHANNEL_RETURN_TEMPERATURE = "returntemp";
|
||||
public static final String CHANNEL_OUTSIDE_TEMPERATURE = "outsidetemp";
|
||||
public static final String CHANNEL_CENTRAL_HEATING_WATER_SETPOINT = "controlsetpoint";
|
||||
public static final String CHANNEL_REQUESTED_CENTRAL_HEATING_WATER_SETPOINT = "controlsetpointrequested";
|
||||
public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT = "controlsetpointoverride";
|
||||
public static final String CHANNEL_CENTRAL_HEATING2_WATER_SETPOINT = "controlsetpoint2";
|
||||
public static final String CHANNEL_REQUESTED_CENTRAL_HEATING2_WATER_SETPOINT = "controlsetpoint2requested";
|
||||
public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT = "controlsetpoint2override";
|
||||
public static final String CHANNEL_CENTRAL_HEATING_WATER_PRESSURE = "waterpressure";
|
||||
public static final String CHANNEL_CENTRAL_HEATING_ENABLED = "ch_enable";
|
||||
public static final String CHANNEL_REQUESTED_CENTRAL_HEATING_ENABLED = "ch_enablerequested";
|
||||
public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED = "ch_enableoverride";
|
||||
public static final String CHANNEL_CENTRAL_HEATING2_ENABLED = "ch2_enable";
|
||||
public static final String CHANNEL_REQUESTED_CENTRAL_HEATING2_ENABLED = "ch2_enablerequested";
|
||||
public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED = "ch2_enableoverride";
|
||||
public static final String CHANNEL_CENTRAL_HEATING_MODE = "ch_mode";
|
||||
public static final String CHANNEL_DOMESTIC_HOT_WATER_TEMPERATURE = "dhwtemp";
|
||||
public static final String CHANNEL_DOMESTIC_HOT_WATER_ENABLED = "dhw_enable";
|
||||
public static final String CHANNEL_DOMESTIC_HOT_WATER_MODE = "dhw_mode";
|
||||
public static final String CHANNEL_DOMESTIC_HOT_WATER_SETPOINT = "tdhwset";
|
||||
public static final String CHANNEL_FLAME = "flame";
|
||||
public static final String CHANNEL_RELATIVE_MODULATION_LEVEL = "modulevel";
|
||||
public static final String CHANNEL_MAXIMUM_MODULATION_LEVEL = "maxrelmdulevel";
|
||||
public static final String CHANNEL_FAULT = "fault";
|
||||
public static final String CHANNEL_SERVICEREQUEST = "servicerequest";
|
||||
public static final String CHANNEL_REMOTE_RESET = "lockout-reset";
|
||||
public static final String CHANNEL_LOW_WATER_PRESSURE = "lowwaterpress";
|
||||
public static final String CHANNEL_GAS_FLAME_FAULT = "gasflamefault";
|
||||
public static final String CHANNEL_AIR_PRESSURE_FAULT = "airpressfault";
|
||||
public static final String CHANNEL_WATER_OVER_TEMP = "waterovtemp";
|
||||
public static final String CHANNEL_OEM_FAULTCODE = "oemfaultcode";
|
||||
public static final String CHANNEL_DIAGNOSTICS_INDICATION = "diag";
|
||||
public static final String CHANNEL_UNSUCCESSFUL_BURNER_STARTS = "unsuccessfulburnerstarts";
|
||||
public static final String CHANNEL_BURNER_STARTS = "burnerstarts";
|
||||
public static final String CHANNEL_CH_PUMP_STARTS = "chpumpstarts";
|
||||
public static final String CHANNEL_DHW_PV_STARTS = "dhwpvstarts";
|
||||
public static final String CHANNEL_DHW_BURNER_STARTS = "dhwburnerstarts";
|
||||
public static final String CHANNEL_BURNER_HOURS = "burnerhours";
|
||||
public static final String CHANNEL_CH_PUMP_HOURS = "chpumphours";
|
||||
public static final String CHANNEL_DHW_PV_HOURS = "dhwpvhours";
|
||||
public static final String CHANNEL_DHW_BURNER_HOURS = "dhwburnerhours";
|
||||
|
||||
public static final Set<String> SUPPORTED_CHANNEL_IDS = Set.of(CHANNEL_ROOM_TEMPERATURE, CHANNEL_ROOM_SETPOINT,
|
||||
CHANNEL_FLOW_TEMPERATURE, CHANNEL_RETURN_TEMPERATURE, CHANNEL_OUTSIDE_TEMPERATURE,
|
||||
CHANNEL_CENTRAL_HEATING_WATER_PRESSURE, CHANNEL_CENTRAL_HEATING_ENABLED,
|
||||
CHANNEL_REQUESTED_CENTRAL_HEATING_ENABLED, CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED,
|
||||
CHANNEL_CENTRAL_HEATING2_ENABLED, CHANNEL_REQUESTED_CENTRAL_HEATING2_ENABLED,
|
||||
CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED, CHANNEL_CENTRAL_HEATING_MODE,
|
||||
CHANNEL_CENTRAL_HEATING_WATER_SETPOINT, CHANNEL_REQUESTED_CENTRAL_HEATING_WATER_SETPOINT,
|
||||
CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT, CHANNEL_CENTRAL_HEATING2_WATER_SETPOINT,
|
||||
CHANNEL_REQUESTED_CENTRAL_HEATING2_WATER_SETPOINT, CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT,
|
||||
CHANNEL_DOMESTIC_HOT_WATER_TEMPERATURE, CHANNEL_DOMESTIC_HOT_WATER_ENABLED, CHANNEL_DOMESTIC_HOT_WATER_MODE,
|
||||
CHANNEL_DOMESTIC_HOT_WATER_SETPOINT, CHANNEL_FLAME, CHANNEL_RELATIVE_MODULATION_LEVEL,
|
||||
CHANNEL_MAXIMUM_MODULATION_LEVEL, CHANNEL_FAULT, CHANNEL_SERVICEREQUEST, CHANNEL_REMOTE_RESET,
|
||||
CHANNEL_LOW_WATER_PRESSURE, CHANNEL_GAS_FLAME_FAULT, CHANNEL_AIR_PRESSURE_FAULT, CHANNEL_WATER_OVER_TEMP,
|
||||
CHANNEL_OEM_FAULTCODE, CHANNEL_DIAGNOSTICS_INDICATION, CHANNEL_UNSUCCESSFUL_BURNER_STARTS,
|
||||
CHANNEL_BURNER_STARTS, CHANNEL_CH_PUMP_STARTS, CHANNEL_DHW_PV_STARTS, CHANNEL_DHW_BURNER_STARTS,
|
||||
CHANNEL_BURNER_HOURS, CHANNEL_CH_PUMP_HOURS, CHANNEL_DHW_PV_HOURS, CHANNEL_DHW_BURNER_HOURS);
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.openthermgateway.handler;
|
||||
|
||||
import static org.openhab.binding.openthermgateway.internal.OpenThermGatewayBindingConstants.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.openthermgateway.internal.DataItem;
|
||||
import org.openhab.binding.openthermgateway.internal.DataItemGroup;
|
||||
import org.openhab.binding.openthermgateway.internal.Message;
|
||||
import org.openhab.binding.openthermgateway.internal.TspFhbSizeDataItem;
|
||||
import org.openhab.binding.openthermgateway.internal.TspFhbValueDataItem;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerCallback;
|
||||
import org.openhab.core.thing.type.ChannelKind;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link BaseDeviceHandler} is a base class for actual Things.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class BaseDeviceHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(BaseDeviceHandler.class);
|
||||
|
||||
public BaseDeviceHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (getBridge() == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
|
||||
} else {
|
||||
// note: the framework handles bridge configuration resp. offline errors
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
Bridge bridge = getBridge();
|
||||
|
||||
if (bridge != null) {
|
||||
OpenThermGatewayHandler handler = (OpenThermGatewayHandler) bridge.getHandler();
|
||||
if (handler != null) {
|
||||
handler.handleCommand(channelUID, command);
|
||||
}
|
||||
} else {
|
||||
logger.debug("Bridge is missing");
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveMessage(Message message) {
|
||||
DataItem[] dataItems = DataItemGroup.DATAITEMGROUPS.get(message.getID());
|
||||
|
||||
if (dataItems == null) {
|
||||
logger.debug("No DataItem found for message id {}", message.getID());
|
||||
return;
|
||||
}
|
||||
|
||||
for (DataItem dataItem : dataItems) {
|
||||
if (dataItem instanceof TspFhbSizeDataItem) {
|
||||
logger.debug("Received TSP or FHB size message {} ({})", message.getID(), dataItem.getSubject());
|
||||
|
||||
verifyTspFhbChannels(((TspFhbSizeDataItem) dataItem).getValueId(),
|
||||
message.getUInt(dataItem.getByteType()));
|
||||
} else {
|
||||
String channelId = dataItem.getChannelId(message);
|
||||
|
||||
if (thing.getChannel(channelId) == null || !dataItem.hasValidCodeType(message)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
State state = dataItem.createState(message);
|
||||
|
||||
logger.debug("Received update for channel {}: {}", channelId, state);
|
||||
updateState(channelId, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyTspFhbChannels(int id, int size) {
|
||||
// Dynamically create TSP or FHB value channels based on TSP or FHB size message
|
||||
ThingHandlerCallback callback = getCallback();
|
||||
|
||||
if (callback == null) {
|
||||
logger.debug("Unable to get thing handler callback");
|
||||
return;
|
||||
}
|
||||
|
||||
DataItem[] dataItems = DataItemGroup.DATAITEMGROUPS.get(id);
|
||||
|
||||
if (dataItems == null) {
|
||||
logger.debug("Unable to find dataItem for id {}", id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dataItems.length != 1) {
|
||||
logger.debug("Found zero or multiple dataItems for id {}", id);
|
||||
return;
|
||||
}
|
||||
|
||||
TspFhbValueDataItem dataItem = (TspFhbValueDataItem) dataItems[0];
|
||||
|
||||
logger.debug("Checking number of TSP or FHB channels for DATA-ID {}: {}", id, size);
|
||||
|
||||
// A generic Number:Dimensionless channel type for TSP and FHB values
|
||||
ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, CHANNEL_TSPFHB);
|
||||
|
||||
List<Channel> channels = new ArrayList<>(getThing().getChannels());
|
||||
|
||||
boolean changed = false;
|
||||
for (int i = 0; i < size; i++) {
|
||||
String channelId = dataItem.getChannelId(i);
|
||||
ChannelUID channelUID = new ChannelUID(thing.getUID(), channelId);
|
||||
|
||||
if (!channels.stream().map(Channel::getUID).anyMatch(channelUID::equals)) {
|
||||
String label = dataItem.getLabel(i);
|
||||
|
||||
logger.debug("Adding channel {}", channelId);
|
||||
|
||||
channels.add(callback.createChannelBuilder(channelUID, channelTypeUID).withKind(ChannelKind.STATE)
|
||||
.withLabel(label).build());
|
||||
changed = true;
|
||||
} else {
|
||||
logger.debug("Channel {} already exists", channelId);
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
logger.debug("Updating Thing with new channels");
|
||||
updateThing(editThing().withChannels(channels).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.openthermgateway.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* The {@link BoilerHandler} represemts a boiler with thermostat.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BoilerHandler extends BaseDeviceHandler {
|
||||
|
||||
public BoilerHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
}
|
||||
@@ -15,32 +15,29 @@ package org.openhab.binding.openthermgateway.handler;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.openthermgateway.OpenThermGatewayBindingConstants;
|
||||
import org.openhab.binding.openthermgateway.internal.DataItem;
|
||||
import org.openhab.binding.openthermgateway.internal.ConnectionState;
|
||||
import org.openhab.binding.openthermgateway.internal.DataItemGroup;
|
||||
import org.openhab.binding.openthermgateway.internal.GatewayCommand;
|
||||
import org.openhab.binding.openthermgateway.internal.GatewayCommandCode;
|
||||
import org.openhab.binding.openthermgateway.internal.Message;
|
||||
import org.openhab.binding.openthermgateway.internal.OpenThermGatewayBindingConstants;
|
||||
import org.openhab.binding.openthermgateway.internal.OpenThermGatewayCallback;
|
||||
import org.openhab.binding.openthermgateway.internal.OpenThermGatewayConfiguration;
|
||||
import org.openhab.binding.openthermgateway.internal.OpenThermGatewayConnector;
|
||||
import org.openhab.binding.openthermgateway.internal.OpenThermGatewaySocketConnector;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -52,38 +49,37 @@ import org.slf4j.LoggerFactory;
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenThermGatewayHandler extends BaseThingHandler implements OpenThermGatewayCallback {
|
||||
public class OpenThermGatewayHandler extends BaseBridgeHandler implements OpenThermGatewayCallback {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(OpenThermGatewayHandler.class);
|
||||
|
||||
private @Nullable OpenThermGatewayConfiguration config;
|
||||
private @Nullable OpenThermGatewayConfiguration configuration;
|
||||
private @Nullable OpenThermGatewayConnector connector;
|
||||
private @Nullable ScheduledFuture<?> reconnectTask;
|
||||
|
||||
private boolean connecting = false;
|
||||
private boolean explicitDisconnect = false;
|
||||
private @Nullable ConnectionState state;
|
||||
private boolean autoReconnect = true;
|
||||
private boolean disposing = false;
|
||||
|
||||
public OpenThermGatewayHandler(Thing thing) {
|
||||
super(thing);
|
||||
public OpenThermGatewayHandler(Bridge bridge) {
|
||||
super(bridge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing OpenTherm Gateway handler for uid '{}'", getThing().getUID());
|
||||
logger.debug("Initializing OpenThermGateway handler for uid {}", getThing().getUID());
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "Initializing");
|
||||
|
||||
config = getConfigAs(OpenThermGatewayConfiguration.class);
|
||||
configuration = getConfigAs(OpenThermGatewayConfiguration.class);
|
||||
logger.debug("Using configuration: {}", configuration);
|
||||
|
||||
disposing = false;
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
connect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
@Nullable
|
||||
OpenThermGatewayConnector conn = connector;
|
||||
|
||||
logger.debug("Received channel: {}, command: {}", channelUID, command);
|
||||
logger.debug("Received command {} for channel {}", command, channelUID);
|
||||
|
||||
if (!(command instanceof RefreshType)) {
|
||||
String channel = channelUID.getId();
|
||||
@@ -108,146 +104,121 @@ public class OpenThermGatewayHandler extends BaseThingHandler implements OpenThe
|
||||
gatewayCommand = GatewayCommand.parse(code, command.toFullString());
|
||||
}
|
||||
|
||||
if (conn != null && conn.isConnected()) {
|
||||
conn.sendCommand(gatewayCommand);
|
||||
sendCommand(gatewayCommand);
|
||||
|
||||
if (GatewayCommandCode.ControlSetpoint.equals(code)) {
|
||||
if (gatewayCommand.getMessage().equals("0.0")) {
|
||||
updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT,
|
||||
UnDefType.UNDEF);
|
||||
}
|
||||
updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED,
|
||||
OnOffType.from(!gatewayCommand.getMessage().equals("0.0")));
|
||||
} else if (GatewayCommandCode.ControlSetpoint2.equals(code)) {
|
||||
if (gatewayCommand.getMessage().equals("0.0")) {
|
||||
updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT,
|
||||
UnDefType.UNDEF);
|
||||
}
|
||||
updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED,
|
||||
OnOffType.from(!gatewayCommand.getMessage().equals("0.0")));
|
||||
if (GatewayCommandCode.CONTROLSETPOINT.equals(code)) {
|
||||
if (gatewayCommand.getMessage().equals("0.0")) {
|
||||
updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT,
|
||||
UnDefType.UNDEF);
|
||||
}
|
||||
} else {
|
||||
connect();
|
||||
updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED,
|
||||
OnOffType.from(!gatewayCommand.getMessage().equals("0.0")));
|
||||
} else if (GatewayCommandCode.CONTROLSETPOINT2.equals(code)) {
|
||||
if (gatewayCommand.getMessage().equals("0.0")) {
|
||||
updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT,
|
||||
UnDefType.UNDEF);
|
||||
}
|
||||
updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED,
|
||||
OnOffType.from(!gatewayCommand.getMessage().equals("0.0")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connecting() {
|
||||
connecting = true;
|
||||
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "Connecting");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connected() {
|
||||
connecting = false;
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected() {
|
||||
public void sendCommand(GatewayCommand gatewayCommand) {
|
||||
@Nullable
|
||||
OpenThermGatewayConfiguration conf = config;
|
||||
OpenThermGatewayConnector conn = connector;
|
||||
|
||||
connecting = false;
|
||||
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Disconnected");
|
||||
|
||||
// retry connection if disconnect is not explicitly requested
|
||||
if (!explicitDisconnect && conf != null && conf.connectionRetryInterval > 0) {
|
||||
logger.debug("Scheduling to reconnect in {} seconds.", conf.connectionRetryInterval);
|
||||
reconnectTask = scheduler.schedule(this::connect, conf.connectionRetryInterval, TimeUnit.SECONDS);
|
||||
if (conn != null && conn.isConnected()) {
|
||||
conn.sendCommand(gatewayCommand);
|
||||
} else {
|
||||
logger.debug("Unable to send command {}: connector not connected", gatewayCommand.toFullString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveMessage(Message message) {
|
||||
if (DataItemGroup.dataItemGroups.containsKey(message.getID())) {
|
||||
DataItem[] dataItems = DataItemGroup.dataItemGroups.get(message.getID());
|
||||
scheduler.submit(() -> receiveMessageTask(message));
|
||||
}
|
||||
|
||||
for (DataItem dataItem : dataItems) {
|
||||
String channelId = dataItem.getSubject();
|
||||
private void receiveMessageTask(Message message) {
|
||||
int msgId = message.getID();
|
||||
|
||||
if (!OpenThermGatewayBindingConstants.SUPPORTED_CHANNEL_IDS.contains(channelId)
|
||||
|| (dataItem.getFilteredCode() != null && dataItem.getFilteredCode() != message.getCode())) {
|
||||
continue;
|
||||
}
|
||||
if (!DataItemGroup.DATAITEMGROUPS.containsKey(msgId)) {
|
||||
logger.debug("Unsupported message id {}", msgId);
|
||||
return;
|
||||
}
|
||||
|
||||
State state = null;
|
||||
for (Thing thing : getThing().getThings()) {
|
||||
BaseDeviceHandler handler = (BaseDeviceHandler) thing.getHandler();
|
||||
|
||||
switch (dataItem.getDataType()) {
|
||||
case FLAGS:
|
||||
state = OnOffType.from(message.getBit(dataItem.getByteType(), dataItem.getBitPos()));
|
||||
break;
|
||||
case UINT8:
|
||||
case UINT16:
|
||||
state = new DecimalType(message.getUInt(dataItem.getByteType()));
|
||||
break;
|
||||
case INT8:
|
||||
case INT16:
|
||||
state = new DecimalType(message.getInt(dataItem.getByteType()));
|
||||
break;
|
||||
case FLOAT:
|
||||
float value = message.getFloat();
|
||||
@Nullable
|
||||
Unit<?> unit = dataItem.getUnit();
|
||||
state = (unit == null) ? new DecimalType(value) : new QuantityType<>(value, unit);
|
||||
break;
|
||||
case DOWTOD:
|
||||
break;
|
||||
}
|
||||
if (handler != null) {
|
||||
handler.receiveMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state != null) {
|
||||
logger.debug("Received update for channel '{}': {}", channelId, state);
|
||||
updateState(channelId, state);
|
||||
}
|
||||
@Override
|
||||
public void connectionStateChanged(ConnectionState state) {
|
||||
scheduler.submit(() -> connectionStateChangedTask(state));
|
||||
}
|
||||
|
||||
private void connectionStateChangedTask(ConnectionState state) {
|
||||
if (this.state != state) {
|
||||
this.state = state;
|
||||
|
||||
switch (state) {
|
||||
case CONNECTED:
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
cancelAutoReconnect();
|
||||
break;
|
||||
case DISCONNECTED:
|
||||
if (!disposing) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
autoReconnect();
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRemoval() {
|
||||
logger.debug("Removing OpenTherm Gateway handler");
|
||||
logger.debug("Removing OpenThermGateway handler");
|
||||
disconnect();
|
||||
super.handleRemoval();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Disposing OpenThermGateway handler");
|
||||
disposing = true;
|
||||
disconnect();
|
||||
|
||||
ScheduledFuture<?> localReconnectTask = reconnectTask;
|
||||
if (localReconnectTask != null) {
|
||||
localReconnectTask.cancel(true);
|
||||
reconnectTask = null;
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void connect() {
|
||||
@Nullable
|
||||
OpenThermGatewayConfiguration conf = config;
|
||||
OpenThermGatewayConfiguration config = configuration;
|
||||
|
||||
explicitDisconnect = false;
|
||||
|
||||
if (connecting) {
|
||||
logger.debug("OpenTherm Gateway connector is already connecting ...");
|
||||
if (this.state == ConnectionState.CONNECTING) {
|
||||
logger.debug("OpenThermGateway connector is already connecting");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure everything is cleaned up before creating a new connection
|
||||
disconnect();
|
||||
|
||||
if (conf != null) {
|
||||
logger.debug("Starting OpenTherm Gateway connector");
|
||||
if (config != null) {
|
||||
connectionStateChanged(ConnectionState.INITIALIZING);
|
||||
|
||||
connector = new OpenThermGatewaySocketConnector(this, conf.ipaddress, conf.port);
|
||||
logger.debug("Starting OpenThermGateway connector");
|
||||
|
||||
Thread thread = new Thread(connector, "OpenTherm Gateway Binding - socket listener thread");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
autoReconnect = true;
|
||||
|
||||
logger.debug("OpenTherm Gateway connector started");
|
||||
OpenThermGatewayConnector conn = connector = new OpenThermGatewaySocketConnector(this, config);
|
||||
conn.start();
|
||||
|
||||
logger.debug("OpenThermGateway connector started");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,36 +226,59 @@ public class OpenThermGatewayHandler extends BaseThingHandler implements OpenThe
|
||||
@Nullable
|
||||
OpenThermGatewayConnector conn = connector;
|
||||
|
||||
explicitDisconnect = true;
|
||||
autoReconnect = false;
|
||||
|
||||
cancelAutoReconnect();
|
||||
|
||||
if (conn != null) {
|
||||
if (conn.isConnected()) {
|
||||
logger.debug("Stopping OpenTherm Gateway connector");
|
||||
conn.stop();
|
||||
conn.stop();
|
||||
connector = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void autoReconnect() {
|
||||
@Nullable
|
||||
OpenThermGatewayConfiguration config = configuration;
|
||||
|
||||
if (autoReconnect && config != null && config.connectionRetryInterval > 0) {
|
||||
logger.debug("Scheduling to auto reconnect in {} seconds", config.connectionRetryInterval);
|
||||
reconnectTask = scheduler.schedule(this::connect, config.connectionRetryInterval, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelAutoReconnect() {
|
||||
ScheduledFuture<?> localReconnectTask = reconnectTask;
|
||||
|
||||
if (localReconnectTask != null) {
|
||||
if (!localReconnectTask.isDone()) {
|
||||
logger.debug("Cancelling auto reconnect task");
|
||||
localReconnectTask.cancel(true);
|
||||
}
|
||||
|
||||
connector = null;
|
||||
reconnectTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable String getGatewayCodeFromChannel(String channel) throws IllegalArgumentException {
|
||||
switch (channel) {
|
||||
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_SETPOINT_TEMPORARY:
|
||||
return GatewayCommandCode.TemperatureTemporary;
|
||||
return GatewayCommandCode.TEMPERATURETEMPORARY;
|
||||
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_SETPOINT_CONSTANT:
|
||||
return GatewayCommandCode.TemperatureConstant;
|
||||
return GatewayCommandCode.TEMPERATURECONSTANT;
|
||||
case OpenThermGatewayBindingConstants.CHANNEL_OUTSIDE_TEMPERATURE:
|
||||
return GatewayCommandCode.TemperatureOutside;
|
||||
return GatewayCommandCode.TEMPERATUREOUTSIDE;
|
||||
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_DHW_SETPOINT:
|
||||
return GatewayCommandCode.SetpointWater;
|
||||
return GatewayCommandCode.SETPOINTWATER;
|
||||
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT:
|
||||
return GatewayCommandCode.ControlSetpoint;
|
||||
return GatewayCommandCode.CONTROLSETPOINT;
|
||||
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED:
|
||||
return GatewayCommandCode.CentralHeating;
|
||||
return GatewayCommandCode.CENTRALHEATING;
|
||||
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT:
|
||||
return GatewayCommandCode.ControlSetpoint2;
|
||||
return GatewayCommandCode.CONTROLSETPOINT2;
|
||||
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED:
|
||||
return GatewayCommandCode.CentralHeating2;
|
||||
return GatewayCommandCode.CENTRALHEATING2;
|
||||
case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_VENTILATION_SETPOINT:
|
||||
return GatewayCommandCode.VENTILATIONSETPOINT;
|
||||
case OpenThermGatewayBindingConstants.CHANNEL_SEND_COMMAND:
|
||||
return null;
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.openthermgateway.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* The {@link VentilationHeatRecoveryHandler} represents a Ventilation/Heat Recovery unit.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VentilationHeatRecoveryHandler extends BaseDeviceHandler {
|
||||
|
||||
public VentilationHeatRecoveryHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,14 @@
|
||||
*/
|
||||
package org.openhab.binding.openthermgateway.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ByteType} enum specifies whether the upper, lower or both bytes are used
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum ByteType {
|
||||
HIGHBYTE,
|
||||
LOWBYTE,
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
*/
|
||||
package org.openhab.binding.openthermgateway.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link CodeType} field is not part of OpenTherm specification, but added by OpenTherm Gateway.
|
||||
* It can be any of the following:
|
||||
@@ -25,6 +27,7 @@ package org.openhab.binding.openthermgateway.internal;
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
* @author James Melville - Introduced code filtering functionality
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum CodeType {
|
||||
/**
|
||||
* Message received from the thermostat
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.openthermgateway.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ConnectionState} is used to indicate changes in connection state.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum ConnectionState {
|
||||
INITIALIZING,
|
||||
DISCONNECTED,
|
||||
CONNECTING,
|
||||
CONNECTED
|
||||
}
|
||||
@@ -12,81 +12,62 @@
|
||||
*/
|
||||
package org.openhab.binding.openthermgateway.internal;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link DataItem} holds the internal OpenTherm message and meta data.
|
||||
* The {@link DataItem} represents the base dataitem.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class DataItem {
|
||||
private int id;
|
||||
public abstract class DataItem {
|
||||
private Msg msg;
|
||||
private ByteType byteType;
|
||||
private DataType dataType;
|
||||
private int bitpos;
|
||||
private String subject;
|
||||
private @Nullable Unit<?> unit;
|
||||
private @Nullable CodeType filteredCode;
|
||||
|
||||
public int getID() {
|
||||
return id;
|
||||
}
|
||||
private @Nullable CodeType codeType;
|
||||
|
||||
public Msg getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public ByteType getByteType() {
|
||||
return this.byteType;
|
||||
}
|
||||
|
||||
public DataType getDataType() {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
public int getBitPos() {
|
||||
return bitpos;
|
||||
return byteType;
|
||||
}
|
||||
|
||||
public String getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
public @Nullable Unit<?> getUnit() {
|
||||
return unit;
|
||||
public @Nullable CodeType getCodeType() {
|
||||
return codeType;
|
||||
}
|
||||
|
||||
public @Nullable CodeType getFilteredCode() {
|
||||
return filteredCode;
|
||||
}
|
||||
|
||||
public DataItem(int id, Msg msg, ByteType byteType, DataType dataType, int bit, String subject) {
|
||||
this(id, msg, byteType, dataType, bit, subject, null, null);
|
||||
}
|
||||
|
||||
public DataItem(int id, Msg msg, ByteType byteType, DataType dataType, int bit, String subject, Unit<?> unit) {
|
||||
this(id, msg, byteType, dataType, bit, subject, unit, null);
|
||||
}
|
||||
|
||||
public DataItem(int id, Msg msg, ByteType byteType, DataType dataType, int bit, String subject,
|
||||
CodeType filteredCode) {
|
||||
this(id, msg, byteType, dataType, bit, subject, null, filteredCode);
|
||||
}
|
||||
|
||||
public DataItem(int id, Msg msg, ByteType byteType, DataType dataType, int bit, String subject,
|
||||
@Nullable Unit<?> unit, @Nullable CodeType filteredCode) {
|
||||
this.id = id;
|
||||
public DataItem(Msg msg, ByteType byteType, String subject, @Nullable CodeType codeType) {
|
||||
this.msg = msg;
|
||||
this.byteType = byteType;
|
||||
this.dataType = dataType;
|
||||
this.bitpos = bit;
|
||||
this.subject = subject;
|
||||
this.unit = unit;
|
||||
this.filteredCode = filteredCode;
|
||||
this.codeType = codeType;
|
||||
}
|
||||
|
||||
public boolean hasValidCodeType(Message message) {
|
||||
// Used to bind a dataitem to a specific TBRA code
|
||||
@Nullable
|
||||
CodeType code = this.getCodeType();
|
||||
|
||||
return (code == null || code == message.getCodeType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message unused in this default implementation
|
||||
* @return the channel id
|
||||
*/
|
||||
public String getChannelId(Message message) {
|
||||
// Default implementation
|
||||
return subject;
|
||||
}
|
||||
|
||||
public abstract State createState(Message message);
|
||||
}
|
||||
|
||||
@@ -27,177 +27,206 @@ import org.openhab.core.library.unit.Units;
|
||||
@NonNullByDefault
|
||||
public class DataItemGroup {
|
||||
|
||||
public static final Map<Integer, DataItem[]> dataItemGroups = createDataItemGroups();
|
||||
public static final Map<Integer, DataItem[]> DATAITEMGROUPS = createDataItemGroups();
|
||||
|
||||
private static Map<Integer, DataItem[]> createDataItemGroups() {
|
||||
HashMap<Integer, DataItem[]> g = new HashMap<>();
|
||||
|
||||
g.put(0, new DataItem[] {
|
||||
new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "ch_enable", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "ch_enablerequested", CodeType.T),
|
||||
new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "ch_enableoverride", CodeType.R),
|
||||
new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 1, "dhw_enable", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 2, "cooling_enabled", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 3, "otc_active", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "ch2_enable", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "ch2_enablerequested", CodeType.T),
|
||||
new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "ch2_enableoverride", CodeType.R),
|
||||
new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 5, "0x00:5", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 6, "0x00:6", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 7, "0x00:7", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 0, "fault", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 1, "ch_mode", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 2, "dhw_mode", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 3, "flame", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 4, "cooling", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 5, "ch2E", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 6, "diag", CodeType.B),
|
||||
new DataItem(0, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 7, "0x00:7", CodeType.B) });
|
||||
g.put(1, new DataItem[] {
|
||||
new DataItem(1, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "controlsetpoint", SIUnits.CELSIUS,
|
||||
CodeType.B),
|
||||
new DataItem(1, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "controlsetpointrequested",
|
||||
SIUnits.CELSIUS, CodeType.T),
|
||||
new DataItem(1, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "controlsetpointoverride", SIUnits.CELSIUS,
|
||||
CodeType.R) });
|
||||
g.put(2, new DataItem[] { new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 0, "0x02:0"),
|
||||
new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 1, "0x02:1"),
|
||||
new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 2, "0x02:2"),
|
||||
new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 3, "0x02:3"),
|
||||
new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 4, "0x02:4"),
|
||||
new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 5, "0x02:5"),
|
||||
new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 6, "0x02:6"),
|
||||
new DataItem(2, Msg.WRITE, ByteType.HIGHBYTE, DataType.FLAGS, 7, "0x02:7"),
|
||||
new DataItem(2, Msg.WRITE, ByteType.LOWBYTE, DataType.UINT8, 0, "mastermemberid") });
|
||||
g.put(3, new DataItem[] { new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "dhwpresent"),
|
||||
new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 1, "controltype"),
|
||||
new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 2, "coolingsupport"),
|
||||
new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 3, "dhwconfig"),
|
||||
new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "masterlowoff"),
|
||||
new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 5, "ch2present"),
|
||||
new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 6, "0x03:6"),
|
||||
new DataItem(3, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 7, "0x03:7"),
|
||||
new DataItem(3, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "slavememberid") });
|
||||
g.put(4, new DataItem[] { new DataItem(4, Msg.WRITE, ByteType.HIGHBYTE, DataType.UINT8, 0, "commandcode"),
|
||||
new DataItem(4, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "commandresponse") });
|
||||
g.put(5, new DataItem[] { new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "servicerequest"),
|
||||
new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 1, "lockout-reset"),
|
||||
new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 2, "lowwaterpress"),
|
||||
new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 3, "gasflamefault"),
|
||||
new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "airpressfault"),
|
||||
new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 5, "waterovtemp"),
|
||||
new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 6, "0x05:6"),
|
||||
new DataItem(5, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 7, "0x05:7"),
|
||||
new DataItem(5, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "oemfaultcode") });
|
||||
g.put(6, new DataItem[] { new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 0, "0x06:l0"),
|
||||
new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 1, "0x06:l1"),
|
||||
new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 2, "0x06:l2"),
|
||||
new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 3, "0x06:l3"),
|
||||
new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 4, "0x06:l4"),
|
||||
new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 5, "0x06:l5"),
|
||||
new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 6, "0x06:l6"),
|
||||
new DataItem(6, Msg.READ, ByteType.LOWBYTE, DataType.FLAGS, 7, "0x06:l7"),
|
||||
new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "0x06:h0"),
|
||||
new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 1, "0x06:h1"),
|
||||
new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 2, "0x06:h2"),
|
||||
new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 3, "0x06:h3"),
|
||||
new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "0x06:h4"),
|
||||
new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 5, "0x06:h5"),
|
||||
new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 6, "0x06:h6"),
|
||||
new DataItem(6, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 7, "0x06:h7") });
|
||||
g.put(7, new DataItem[] { new DataItem(7, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "0x07") });
|
||||
g.put(8, new DataItem[] {
|
||||
new DataItem(8, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "controlsetpoint2", SIUnits.CELSIUS,
|
||||
CodeType.B),
|
||||
new DataItem(8, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "controlsetpoint2requested",
|
||||
SIUnits.CELSIUS, CodeType.T),
|
||||
new DataItem(8, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "controlsetpoint2override",
|
||||
SIUnits.CELSIUS, CodeType.R) });
|
||||
g.put(9, new DataItem[] { new DataItem(9, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "overridesetpoint") });
|
||||
g.put(10, new DataItem[] { new DataItem(10, Msg.WRITE, ByteType.HIGHBYTE, DataType.UINT8, 0, "0x0a:h"),
|
||||
new DataItem(10, Msg.WRITE, ByteType.LOWBYTE, DataType.UINT8, 0, "0x0a:l") });
|
||||
g.put(11, new DataItem[] { new DataItem(11, Msg.READWRITE, ByteType.HIGHBYTE, DataType.UINT8, 0, "tspindex"),
|
||||
new DataItem(11, Msg.READWRITE, ByteType.LOWBYTE, DataType.UINT8, 0, "tspvalue") });
|
||||
g.put(12, new DataItem[] { new DataItem(12, Msg.READ, ByteType.HIGHBYTE, DataType.UINT8, 0, "0x0c:h"),
|
||||
new DataItem(12, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "0x0c:l") });
|
||||
g.put(13, new DataItem[] { new DataItem(13, Msg.READ, ByteType.HIGHBYTE, DataType.UINT8, 0, "0x0d:h"),
|
||||
new DataItem(13, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "0x0d:l") });
|
||||
g.put(14, new DataItem[] {
|
||||
new DataItem(14, Msg.READ, ByteType.LOWBYTE, DataType.FLOAT, 0, "maxrelmdulevel", Units.PERCENT) });
|
||||
g.put(15, new DataItem[] { new DataItem(15, Msg.READ, ByteType.HIGHBYTE, DataType.UINT8, 0, "maxcapkw"),
|
||||
new DataItem(15, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "maxcapprc") });
|
||||
g.put(16, new DataItem[] {
|
||||
new DataItem(16, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "roomsetpoint", SIUnits.CELSIUS) });
|
||||
g.put(17, new DataItem[] {
|
||||
new DataItem(17, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "modulevel", Units.PERCENT) });
|
||||
g.put(18, new DataItem[] {
|
||||
new DataItem(18, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "waterpressure", Units.BAR) });
|
||||
g.put(19, new DataItem[] { new DataItem(19, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "dhwflow") });
|
||||
g.put(20, new DataItem[] { new DataItem(20, Msg.READWRITE, ByteType.BOTH, DataType.DOWTOD, 0, "dowtod") });
|
||||
g.put(21, new DataItem[] { new DataItem(21, Msg.READWRITE, ByteType.HIGHBYTE, DataType.UINT8, 0, "month"),
|
||||
new DataItem(21, Msg.READWRITE, ByteType.LOWBYTE, DataType.UINT8, 0, "dom") });
|
||||
g.put(22, new DataItem[] { new DataItem(22, Msg.READWRITE, ByteType.LOWBYTE, DataType.UINT8, 0, "year") });
|
||||
g.put(23, new DataItem[] { new DataItem(23, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "setpointch2") });
|
||||
g.put(24, new DataItem[] {
|
||||
new DataItem(24, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "roomtemp", SIUnits.CELSIUS) });
|
||||
g.put(25, new DataItem[] {
|
||||
new DataItem(25, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "flowtemp", SIUnits.CELSIUS) });
|
||||
g.put(26, new DataItem[] {
|
||||
new DataItem(26, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "dhwtemp", SIUnits.CELSIUS) });
|
||||
g.put(27, new DataItem[] {
|
||||
new DataItem(27, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "outsidetemp", SIUnits.CELSIUS) });
|
||||
g.put(28, new DataItem[] {
|
||||
new DataItem(28, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "returntemp", SIUnits.CELSIUS) });
|
||||
g.put(29, new DataItem[] { new DataItem(29, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "solstortemp") });
|
||||
g.put(30, new DataItem[] { new DataItem(30, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "solcolltemp") });
|
||||
g.put(31, new DataItem[] { new DataItem(31, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "flowtemp2") });
|
||||
g.put(32, new DataItem[] { new DataItem(32, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "dhw2temp") });
|
||||
g.put(33, new DataItem[] { new DataItem(33, Msg.READ, ByteType.BOTH, DataType.INT16, 0, "exhausttemp") });
|
||||
g.put(48, new DataItem[] { new DataItem(48, Msg.READ, ByteType.HIGHBYTE, DataType.INT8, 0, "tdhwsetu"),
|
||||
new DataItem(48, Msg.READ, ByteType.LOWBYTE, DataType.INT8, 0, "tdhwsetl") });
|
||||
g.put(49, new DataItem[] { new DataItem(49, Msg.READ, ByteType.HIGHBYTE, DataType.INT8, 0, "maxchu"),
|
||||
new DataItem(49, Msg.READ, ByteType.LOWBYTE, DataType.INT8, 0, "maxchl") });
|
||||
g.put(50, new DataItem[] { new DataItem(50, Msg.READ, ByteType.HIGHBYTE, DataType.INT8, 0, "otcu"),
|
||||
new DataItem(50, Msg.READ, ByteType.LOWBYTE, DataType.INT8, 0, "otcl") });
|
||||
g.put(56, new DataItem[] {
|
||||
new DataItem(56, Msg.READWRITE, ByteType.BOTH, DataType.FLOAT, 0, "tdhwset", SIUnits.CELSIUS) });
|
||||
g.put(57, new DataItem[] { new DataItem(57, Msg.READWRITE, ByteType.BOTH, DataType.FLOAT, 0, "tchmax") });
|
||||
g.put(58, new DataItem[] { new DataItem(58, Msg.READWRITE, ByteType.BOTH, DataType.FLOAT, 0, "otchcratio") });
|
||||
g.put(0, new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "ch_enable", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "ch_enablerequested", CodeType.T),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "ch_enableoverride", CodeType.R),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "dhw_enable", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "cooling_enabled", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "otc_active", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "ch2_enable", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "ch2_enablerequested", CodeType.T),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "ch2_enableoverride", CodeType.R),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 5, "0x00:5", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 6, "0x00:6", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 7, "0x00:7", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 0, "fault", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 1, "ch_mode", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 2, "dhw_mode", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 3, "flame", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 4, "cooling", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 5, "ch2E", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 6, "diag", CodeType.B),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 7, "0x00:7", CodeType.B) });
|
||||
g.put(1, new DataItem[] { new FloatDataItem(Msg.WRITE, "controlsetpoint", SIUnits.CELSIUS, CodeType.B),
|
||||
new FloatDataItem(Msg.WRITE, "controlsetpointrequested", SIUnits.CELSIUS, CodeType.T),
|
||||
new FloatDataItem(Msg.WRITE, "controlsetpointoverride", SIUnits.CELSIUS, CodeType.R) });
|
||||
g.put(2, new DataItem[] { new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 0, "0x02:0"),
|
||||
new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 1, "0x02:1"),
|
||||
new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 2, "0x02:2"),
|
||||
new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 3, "0x02:3"),
|
||||
new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 4, "0x02:4"),
|
||||
new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 5, "0x02:5"),
|
||||
new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 6, "0x02:6"),
|
||||
new FlagDataItem(Msg.WRITE, ByteType.HIGHBYTE, 7, "0x02:7"),
|
||||
new UIntDataItem(Msg.WRITE, ByteType.LOWBYTE, "mastermemberid") });
|
||||
g.put(3, new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "dhwpresent"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "controltype"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "coolingsupport"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "dhwconfig"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "masterlowoff"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 5, "ch2present"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 6, "0x03:6"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 7, "0x03:7"),
|
||||
new UIntDataItem(Msg.READ, ByteType.LOWBYTE, "slavememberid") });
|
||||
g.put(4, new DataItem[] { new UIntDataItem(Msg.WRITE, ByteType.HIGHBYTE, "commandcode"),
|
||||
new UIntDataItem(Msg.READ, ByteType.LOWBYTE, "commandresponse") });
|
||||
g.put(5, new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "servicerequest"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "lockout-reset"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "lowwaterpress"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "gasflamefault"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "airpressfault"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 5, "waterovtemp"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 6, "0x05:6"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 7, "0x05:7"),
|
||||
new IntDataItem(Msg.READ, ByteType.LOWBYTE, "oemfaultcode") });
|
||||
g.put(6, new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "0x06:h0"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "0x06:h1"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "0x06:h2"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "0x06:h3"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "0x06:h4"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 5, "0x06:h5"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 6, "0x06:h6"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 7, "0x06:h7"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 0, "0x06:l0"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 1, "0x06:l1"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 2, "0x06:l2"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 3, "0x06:l3"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 4, "0x06:l4"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 5, "0x06:l5"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 6, "0x06:l6"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 7, "0x06:l7") });
|
||||
g.put(7, new DataItem[] { new FloatDataItem(Msg.WRITE, "coolingcontrolsignal") });
|
||||
g.put(8, new DataItem[] { new FloatDataItem(Msg.WRITE, "controlsetpoint2", SIUnits.CELSIUS, CodeType.B),
|
||||
new FloatDataItem(Msg.WRITE, "controlsetpoint2requested", SIUnits.CELSIUS, CodeType.T),
|
||||
new FloatDataItem(Msg.WRITE, "controlsetpoint2override", SIUnits.CELSIUS, CodeType.R) });
|
||||
g.put(9, new DataItem[] { new FloatDataItem(Msg.READ, "overridesetpoint") });
|
||||
g.put(10, new DataItem[] { new TspFhbSizeDataItem(Msg.WRITE, ByteType.HIGHBYTE, 11, "tspnumber") });
|
||||
g.put(11, new DataItem[] { new TspFhbValueDataItem(Msg.READWRITE, "tspentry") });
|
||||
g.put(12, new DataItem[] { new TspFhbSizeDataItem(Msg.READ, ByteType.HIGHBYTE, 13, "fhbnumber") });
|
||||
g.put(13, new DataItem[] { new TspFhbValueDataItem(Msg.READ, "fhbentry") });
|
||||
g.put(14, new DataItem[] { new FloatDataItem(Msg.READ, "maxrelmdulevel", Units.PERCENT) });
|
||||
g.put(15, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.HIGHBYTE, "maxcapkw"),
|
||||
new UIntDataItem(Msg.READ, ByteType.LOWBYTE, "maxcapprc") });
|
||||
g.put(16, new DataItem[] { new FloatDataItem(Msg.WRITE, "roomsetpoint", SIUnits.CELSIUS) });
|
||||
g.put(17, new DataItem[] { new FloatDataItem(Msg.READ, "modulevel", Units.PERCENT) });
|
||||
g.put(18, new DataItem[] { new FloatDataItem(Msg.READ, "waterpressure", Units.BAR) });
|
||||
g.put(19, new DataItem[] { new FloatDataItem(Msg.READ, "dhwflow") });
|
||||
g.put(20, new DataItem[] { new UIntDataItem(Msg.READWRITE, ByteType.BOTH, "dowtod") });
|
||||
g.put(21, new DataItem[] { new UIntDataItem(Msg.READWRITE, ByteType.HIGHBYTE, "month"),
|
||||
new UIntDataItem(Msg.READWRITE, ByteType.LOWBYTE, "day") });
|
||||
g.put(22, new DataItem[] { new UIntDataItem(Msg.READWRITE, ByteType.BOTH, "year") });
|
||||
g.put(23, new DataItem[] { new FloatDataItem(Msg.WRITE, "setpointch2") });
|
||||
g.put(24, new DataItem[] { new FloatDataItem(Msg.WRITE, "roomtemp", SIUnits.CELSIUS) });
|
||||
g.put(25, new DataItem[] { new FloatDataItem(Msg.READ, "flowtemp", SIUnits.CELSIUS) });
|
||||
g.put(26, new DataItem[] { new FloatDataItem(Msg.READ, "dhwtemp", SIUnits.CELSIUS) });
|
||||
g.put(27, new DataItem[] { new FloatDataItem(Msg.READ, "outsidetemp", SIUnits.CELSIUS) });
|
||||
g.put(28, new DataItem[] { new FloatDataItem(Msg.READ, "returntemp", SIUnits.CELSIUS) });
|
||||
|
||||
g.put(29, new DataItem[] { new FloatDataItem(Msg.READ, "ss_temperature") });
|
||||
g.put(30, new DataItem[] { new FloatDataItem(Msg.READ, "ss_collectortemperature") });
|
||||
|
||||
g.put(31, new DataItem[] { new FloatDataItem(Msg.READ, "flowtemp2") });
|
||||
g.put(32, new DataItem[] { new FloatDataItem(Msg.READ, "dhw2temp") });
|
||||
g.put(33, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "exhausttemp") });
|
||||
g.put(48, new DataItem[] { new IntDataItem(Msg.READ, ByteType.HIGHBYTE, "tdhwsetu"),
|
||||
new IntDataItem(Msg.READ, ByteType.LOWBYTE, "tdhwsetl") });
|
||||
g.put(49, new DataItem[] { new IntDataItem(Msg.READ, ByteType.HIGHBYTE, "maxchu"),
|
||||
new IntDataItem(Msg.READ, ByteType.LOWBYTE, "maxchl") });
|
||||
g.put(50, new DataItem[] { new IntDataItem(Msg.READ, ByteType.HIGHBYTE, "otcu"),
|
||||
new IntDataItem(Msg.READ, ByteType.LOWBYTE, "otcl") });
|
||||
g.put(56, new DataItem[] { new FloatDataItem(Msg.READWRITE, "tdhwset", SIUnits.CELSIUS) });
|
||||
g.put(57, new DataItem[] { new FloatDataItem(Msg.READWRITE, "tchmax") });
|
||||
g.put(58, new DataItem[] { new FloatDataItem(Msg.READWRITE, "otchcratio") });
|
||||
g.put(70,
|
||||
new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "vh_ventilationenable"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "vh_bypassposition"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "vh_bypassmode"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "vh_freeventilationmode"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 0, "vh_faultindication"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 1, "vh_ventilationmode"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 2, "vh_bypassstatus"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 3, "vh_bypassautomaticstatus"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 4, "vh_freeventilationstatus"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 5, "vh_filtercheck"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 6, "vh_diagnosticindication") });
|
||||
g.put(71, new DataItem[] { new UIntDataItem(Msg.WRITE, ByteType.LOWBYTE, "vh_controlsetpoint") });
|
||||
g.put(72,
|
||||
new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "vh_servicerequest"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "vh_exhaustfanfault"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "vh_inletfanfault"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "vh_frostprotection"),
|
||||
new UIntDataItem(Msg.READ, ByteType.LOWBYTE, "vh_faultcode") });
|
||||
g.put(73, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_diagnosticcode") });
|
||||
g.put(74,
|
||||
new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "vh_systemtype"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "vh_bypass"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "vh_speedcontrol"),
|
||||
new UIntDataItem(Msg.READ, ByteType.LOWBYTE, "vh_memberid") });
|
||||
g.put(75, new DataItem[] { new FloatDataItem(Msg.READ, "vh_openthermversion") });
|
||||
g.put(76, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_versiontype") });
|
||||
g.put(77, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_relativeventilation") });
|
||||
g.put(78, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_relativehumidity") });
|
||||
g.put(79, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_co2level") });
|
||||
g.put(80, new DataItem[] { new FloatDataItem(Msg.READ, "vh_supplyinlettemp") });
|
||||
g.put(81, new DataItem[] { new FloatDataItem(Msg.READ, "vh_supplyoutlettemp") });
|
||||
g.put(82, new DataItem[] { new FloatDataItem(Msg.READ, "vh_exhaustinlettemp") });
|
||||
g.put(83, new DataItem[] { new FloatDataItem(Msg.READ, "vh_exhaustoutlettemp") });
|
||||
g.put(84, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_actualexhaustfanspeed") });
|
||||
g.put(85, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "vh_actualinletfanspeed") });
|
||||
g.put(86, new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "vh_nominalventenable"),
|
||||
new FlagDataItem(Msg.READ, ByteType.LOWBYTE, 0, "vh_nominalventrw") });
|
||||
g.put(87, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.HIGHBYTE, "vh_nominalventilationvalue") });
|
||||
g.put(88, new DataItem[] { new TspFhbSizeDataItem(Msg.READ, ByteType.HIGHBYTE, 89, "vh_tspnumber") });
|
||||
g.put(89, new DataItem[] { new TspFhbValueDataItem(Msg.READ, "vh_tspentry") });
|
||||
g.put(90, new DataItem[] { new TspFhbSizeDataItem(Msg.READ, ByteType.HIGHBYTE, 91, "vh_fhbnumber") });
|
||||
g.put(91, new DataItem[] { new TspFhbValueDataItem(Msg.READ, "vh_fhbentry") });
|
||||
g.put(100,
|
||||
new DataItem[] { new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 0, "rof0"),
|
||||
new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 1, "rof1"),
|
||||
new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 2, "rof2"),
|
||||
new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 3, "rof3"),
|
||||
new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 4, "rof4"),
|
||||
new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 5, "rof5"),
|
||||
new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 6, "rof6"),
|
||||
new DataItem(100, Msg.READ, ByteType.HIGHBYTE, DataType.FLAGS, 7, "rof7") });
|
||||
g.put(113, new DataItem[] {
|
||||
new DataItem(113, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "unsuccessfulburnerstarts") });
|
||||
g.put(115, new DataItem[] { new DataItem(115, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "oemdiagcode") });
|
||||
g.put(116, new DataItem[] { new DataItem(116, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "burnerstarts") });
|
||||
g.put(117, new DataItem[] { new DataItem(117, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "chpumpstarts") });
|
||||
g.put(118, new DataItem[] { new DataItem(118, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "dhwpvstarts") });
|
||||
g.put(119,
|
||||
new DataItem[] { new DataItem(119, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "dhwburnerstarts") });
|
||||
g.put(120, new DataItem[] {
|
||||
new DataItem(120, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "burnerhours", Units.HOUR) });
|
||||
g.put(121, new DataItem[] {
|
||||
new DataItem(121, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "chpumphours", Units.HOUR) });
|
||||
g.put(122, new DataItem[] {
|
||||
new DataItem(122, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "dhwpvhours", Units.HOUR) });
|
||||
g.put(123, new DataItem[] {
|
||||
new DataItem(123, Msg.READ, ByteType.BOTH, DataType.UINT16, 0, "dhwburnerhours", Units.HOUR) });
|
||||
g.put(124,
|
||||
new DataItem[] { new DataItem(124, Msg.WRITE, ByteType.BOTH, DataType.FLOAT, 0, "masterotversion") });
|
||||
g.put(125, new DataItem[] { new DataItem(125, Msg.READ, ByteType.BOTH, DataType.FLOAT, 0, "slaveotversion") });
|
||||
g.put(126,
|
||||
new DataItem[] {
|
||||
new DataItem(126, Msg.WRITE, ByteType.HIGHBYTE, DataType.UINT8, 0, "masterproducttype"),
|
||||
new DataItem(126, Msg.WRITE, ByteType.LOWBYTE, DataType.UINT8, 0, "masterproductversion") });
|
||||
g.put(127,
|
||||
new DataItem[] { new DataItem(127, Msg.READ, ByteType.HIGHBYTE, DataType.UINT8, 0, "slaveproducttype"),
|
||||
new DataItem(127, Msg.READ, ByteType.LOWBYTE, DataType.UINT8, 0, "slaveproductversion") });
|
||||
new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "rof0"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "rof1"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "rof2"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "rof3"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "rof4"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 5, "rof5"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 6, "rof6"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 7, "rof7") });
|
||||
|
||||
g.put(101,
|
||||
new DataItem[] { new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 0, "rof0"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 1, "rof1"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 2, "rof2"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 3, "rof3"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 4, "rof4"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 5, "rof5"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 6, "rof6"),
|
||||
new FlagDataItem(Msg.READ, ByteType.HIGHBYTE, 7, "rof7") });
|
||||
g.put(102, new DataItem[] {});
|
||||
|
||||
g.put(105, new DataItem[] { new TspFhbSizeDataItem(Msg.READ, ByteType.HIGHBYTE, 106, "ss_tspnumber") });
|
||||
g.put(106, new DataItem[] { new TspFhbValueDataItem(Msg.READ, "ss_tspentry") });
|
||||
|
||||
g.put(107, new DataItem[] { new TspFhbSizeDataItem(Msg.READ, ByteType.HIGHBYTE, 108, "ss_fhbnumber") });
|
||||
g.put(108, new DataItem[] { new TspFhbValueDataItem(Msg.READ, "ss_fhbentry") });
|
||||
g.put(113, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "unsuccessfulburnerstarts") });
|
||||
g.put(115, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "oemdiagcode") });
|
||||
g.put(116, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "burnerstarts") });
|
||||
g.put(117, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "chpumpstarts") });
|
||||
g.put(118, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "dhwpvstarts") });
|
||||
g.put(119, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "dhwburnerstarts") });
|
||||
g.put(120, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "burnerhours", Units.HOUR) });
|
||||
g.put(121, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "chpumphours", Units.HOUR) });
|
||||
g.put(122, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "dhwpvhours", Units.HOUR) });
|
||||
g.put(123, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.BOTH, "dhwburnerhours", Units.HOUR) });
|
||||
g.put(124, new DataItem[] { new FloatDataItem(Msg.WRITE, "masterotversion") });
|
||||
g.put(125, new DataItem[] { new FloatDataItem(Msg.READ, "slaveotversion") });
|
||||
g.put(126, new DataItem[] { new UIntDataItem(Msg.WRITE, ByteType.HIGHBYTE, "masterproducttype"),
|
||||
new UIntDataItem(Msg.WRITE, ByteType.LOWBYTE, "masterproductversion") });
|
||||
g.put(127, new DataItem[] { new UIntDataItem(Msg.READ, ByteType.HIGHBYTE, "slaveproducttype"),
|
||||
new UIntDataItem(Msg.READ, ByteType.LOWBYTE, "slaveproductversion") });
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
@@ -12,11 +12,14 @@
|
||||
*/
|
||||
package org.openhab.binding.openthermgateway.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link DataType} enum indicates the type of data from a DataItem.
|
||||
*
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum DataType {
|
||||
FLAGS,
|
||||
UINT8,
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.openthermgateway.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link DataItem} holds the internal OpenTherm message and meta data.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FlagDataItem extends DataItem {
|
||||
private int bitpos;
|
||||
|
||||
public int getBitPos() {
|
||||
return bitpos;
|
||||
}
|
||||
|
||||
public FlagDataItem(Msg msg, ByteType byteType, int bitpos, String subject) {
|
||||
this(msg, byteType, bitpos, subject, null);
|
||||
}
|
||||
|
||||
public FlagDataItem(Msg msg, ByteType byteType, int bitpos, String subject, @Nullable CodeType codeType) {
|
||||
super(msg, byteType, subject, codeType);
|
||||
|
||||
this.bitpos = bitpos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State createState(Message message) {
|
||||
return OnOffType.from(message.getBit(super.getByteType(), this.getBitPos()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.openthermgateway.internal;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link FloatDataItem} represents a 2-byte float value in a 2's complement format.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FloatDataItem extends DataItem {
|
||||
|
||||
private @Nullable Unit<?> unit;
|
||||
|
||||
public @Nullable Unit<?> getUnit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
public FloatDataItem(Msg msg, String subject) {
|
||||
this(msg, subject, null, null);
|
||||
}
|
||||
|
||||
public FloatDataItem(Msg msg, String subject, Unit<?> unit) {
|
||||
this(msg, subject, unit, null);
|
||||
}
|
||||
|
||||
public FloatDataItem(Msg msg, String subject, CodeType codetype) {
|
||||
this(msg, subject, null, codetype);
|
||||
}
|
||||
|
||||
public FloatDataItem(Msg msg, String subject, @Nullable Unit<?> unit, @Nullable CodeType codetype) {
|
||||
super(msg, ByteType.BOTH, subject, codetype);
|
||||
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State createState(Message message) {
|
||||
@Nullable
|
||||
Unit<?> unit = this.getUnit();
|
||||
float value = message.getFloat();
|
||||
return (unit == null) ? new DecimalType(value) : new QuantityType<>(value, unit);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GatewayCommand {
|
||||
private static final Map<String, @Nullable String> supportedCommands = getSupportedCommands();
|
||||
private static final Map<String, @Nullable String> SUPPORTEDCOMMANDS = getSupportedCommands();
|
||||
|
||||
private String code;
|
||||
private String validationSet;
|
||||
@@ -83,19 +83,17 @@ public class GatewayCommand {
|
||||
if (code != null && code.length() == 2) {
|
||||
String codeUpperCase = code.toUpperCase();
|
||||
|
||||
if (supportedCommands.containsKey(codeUpperCase)) {
|
||||
String validateSet = supportedCommands.get(codeUpperCase);
|
||||
if (SUPPORTEDCOMMANDS.containsKey(codeUpperCase)) {
|
||||
String validateSet = SUPPORTEDCOMMANDS.get(codeUpperCase);
|
||||
|
||||
if (validateSet == null) {
|
||||
validateSet = "";
|
||||
}
|
||||
|
||||
return new GatewayCommand(codeUpperCase, message, validateSet);
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("Unsupported gateway code '%s'", code.toUpperCase()));
|
||||
}
|
||||
throw new IllegalArgumentException(String.format("Unsupported gateway code '%s'", code.toUpperCase()));
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Unable to parse gateway command with code '%s' and message '%s'", code, message));
|
||||
}
|
||||
@@ -103,45 +101,45 @@ public class GatewayCommand {
|
||||
private static Map<String, @Nullable String> getSupportedCommands() {
|
||||
Map<String, @Nullable String> c = new HashMap<>();
|
||||
|
||||
c.put(GatewayCommandCode.TemperatureTemporary, null);
|
||||
c.put(GatewayCommandCode.TemperatureConstant, null);
|
||||
c.put(GatewayCommandCode.TemperatureOutside, null);
|
||||
c.put(GatewayCommandCode.SetClock, null);
|
||||
c.put(GatewayCommandCode.HotWater, null);
|
||||
c.put(GatewayCommandCode.PrintReport, "A,B,C,G,I,L,M,O,P,R,S,T,V,W");
|
||||
c.put(GatewayCommandCode.PrintSummary, "0,1");
|
||||
c.put(GatewayCommandCode.GateWay, "0,1,R");
|
||||
c.put(GatewayCommandCode.LedA, "R,X,T,B,O,F,H,W,C,E,M,P");
|
||||
c.put(GatewayCommandCode.LedB, "R,X,T,B,O,F,H,W,C,E,M,P");
|
||||
c.put(GatewayCommandCode.LedC, "R,X,T,B,O,F,H,W,C,E,M,P");
|
||||
c.put(GatewayCommandCode.LedD, "R,X,T,B,O,F,H,W,C,E,M,P");
|
||||
c.put(GatewayCommandCode.LedE, "R,X,T,B,O,F,H,W,C,E,M,P");
|
||||
c.put(GatewayCommandCode.LedF, "R,X,T,B,O,F,H,W,C,E,M,P");
|
||||
c.put(GatewayCommandCode.GpioA, "0,1,2,3,4,5,6,7");
|
||||
c.put(GatewayCommandCode.GpioB, "0,1,2,3,4,5,6,7");
|
||||
c.put(GatewayCommandCode.SetBack, null);
|
||||
c.put(GatewayCommandCode.TemperatureSensor, "O,R");
|
||||
c.put(GatewayCommandCode.AddAlternative, null);
|
||||
c.put(GatewayCommandCode.DeleteAlternative, null);
|
||||
c.put(GatewayCommandCode.UnknownID, null);
|
||||
c.put(GatewayCommandCode.KnownID, null);
|
||||
c.put(GatewayCommandCode.PriorityMessage, null);
|
||||
c.put(GatewayCommandCode.SetResponse, null);
|
||||
c.put(GatewayCommandCode.ClearResponse, null);
|
||||
c.put(GatewayCommandCode.SetpointHeating, null);
|
||||
c.put(GatewayCommandCode.SetpointWater, null);
|
||||
c.put(GatewayCommandCode.MaximumModulation, null);
|
||||
c.put(GatewayCommandCode.ControlSetpoint, null);
|
||||
c.put(GatewayCommandCode.ControlSetpoint2, null);
|
||||
c.put(GatewayCommandCode.CentralHeating, "0,1");
|
||||
c.put(GatewayCommandCode.CentralHeating2, "0,1");
|
||||
c.put(GatewayCommandCode.VentilationSetpoint, null);
|
||||
c.put(GatewayCommandCode.Reset, null);
|
||||
c.put(GatewayCommandCode.IgnoreTransition, "0,1");
|
||||
c.put(GatewayCommandCode.OverrideHighbyte, "0,1");
|
||||
c.put(GatewayCommandCode.ForceThermostat, "0,1");
|
||||
c.put(GatewayCommandCode.VoltageReference, "0,1,2,3,4,5,6,7,8,9");
|
||||
c.put(GatewayCommandCode.DebugPointer, null);
|
||||
c.put(GatewayCommandCode.TEMPERATURETEMPORARY, null);
|
||||
c.put(GatewayCommandCode.TEMPERATURECONSTANT, null);
|
||||
c.put(GatewayCommandCode.TEMPERATUREOUTSIDE, null);
|
||||
c.put(GatewayCommandCode.SETCLOCK, null);
|
||||
c.put(GatewayCommandCode.HOTWATER, null);
|
||||
c.put(GatewayCommandCode.PRINTREPORT, "A,B,C,G,I,L,M,O,P,R,S,T,V,W");
|
||||
c.put(GatewayCommandCode.PRINTSUMMARY, "0,1");
|
||||
c.put(GatewayCommandCode.GATEWAY, "0,1,R");
|
||||
c.put(GatewayCommandCode.LEDA, "R,X,T,B,O,F,H,W,C,E,M,P");
|
||||
c.put(GatewayCommandCode.LEDB, "R,X,T,B,O,F,H,W,C,E,M,P");
|
||||
c.put(GatewayCommandCode.LEDC, "R,X,T,B,O,F,H,W,C,E,M,P");
|
||||
c.put(GatewayCommandCode.LEDD, "R,X,T,B,O,F,H,W,C,E,M,P");
|
||||
c.put(GatewayCommandCode.LEDE, "R,X,T,B,O,F,H,W,C,E,M,P");
|
||||
c.put(GatewayCommandCode.LEDF, "R,X,T,B,O,F,H,W,C,E,M,P");
|
||||
c.put(GatewayCommandCode.GPIOA, "0,1,2,3,4,5,6,7");
|
||||
c.put(GatewayCommandCode.GPIOB, "0,1,2,3,4,5,6,7");
|
||||
c.put(GatewayCommandCode.SETBACK, null);
|
||||
c.put(GatewayCommandCode.TEMPERATURESENSOR, "O,R");
|
||||
c.put(GatewayCommandCode.ADDALTERNATIVE, null);
|
||||
c.put(GatewayCommandCode.DELETEALTERNATIVE, null);
|
||||
c.put(GatewayCommandCode.UNKNOWNID, null);
|
||||
c.put(GatewayCommandCode.KNOWNID, null);
|
||||
c.put(GatewayCommandCode.PRIORITYMESSAGE, null);
|
||||
c.put(GatewayCommandCode.SETRESPONSE, null);
|
||||
c.put(GatewayCommandCode.CLEARRESPONSE, null);
|
||||
c.put(GatewayCommandCode.SETPOINTHEATING, null);
|
||||
c.put(GatewayCommandCode.SETPOINTWATER, null);
|
||||
c.put(GatewayCommandCode.MAXIMUMMODULATION, null);
|
||||
c.put(GatewayCommandCode.CONTROLSETPOINT, null);
|
||||
c.put(GatewayCommandCode.CONTROLSETPOINT2, null);
|
||||
c.put(GatewayCommandCode.CENTRALHEATING, "0,1");
|
||||
c.put(GatewayCommandCode.CENTRALHEATING2, "0,1");
|
||||
c.put(GatewayCommandCode.VENTILATIONSETPOINT, null);
|
||||
c.put(GatewayCommandCode.RESET, null);
|
||||
c.put(GatewayCommandCode.IGNORETRANSITION, "0,1");
|
||||
c.put(GatewayCommandCode.OVERRIDEHIGHBYTE, "0,1");
|
||||
c.put(GatewayCommandCode.FORCETHERMOSTAT, "0,1");
|
||||
c.put(GatewayCommandCode.VOLTAGEREFERENCE, "0,1,2,3,4,5,6,7,8,9");
|
||||
c.put(GatewayCommandCode.DEBUGPOINTER, null);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -21,43 +21,43 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GatewayCommandCode {
|
||||
public static final String TemperatureTemporary = "TT";
|
||||
public static final String TemperatureConstant = "TC";
|
||||
public static final String TemperatureOutside = "OT";
|
||||
public static final String SetClock = "ST";
|
||||
public static final String HotWater = "HW";
|
||||
public static final String PrintReport = "PR";
|
||||
public static final String PrintSummary = "PS";
|
||||
public static final String GateWay = "GW";
|
||||
public static final String LedA = "LA";
|
||||
public static final String LedB = "LB";
|
||||
public static final String LedC = "LC";
|
||||
public static final String LedD = "LD";
|
||||
public static final String LedE = "LE";
|
||||
public static final String LedF = "LF";
|
||||
public static final String GpioA = "GA";
|
||||
public static final String GpioB = "GB";
|
||||
public static final String SetBack = "SB";
|
||||
public static final String TemperatureSensor = "TS";
|
||||
public static final String AddAlternative = "AA";
|
||||
public static final String DeleteAlternative = "DA";
|
||||
public static final String UnknownID = "UI";
|
||||
public static final String KnownID = "KI";
|
||||
public static final String PriorityMessage = "PM";
|
||||
public static final String SetResponse = "SR";
|
||||
public static final String ClearResponse = "CR";
|
||||
public static final String SetpointHeating = "SH";
|
||||
public static final String SetpointWater = "SW";
|
||||
public static final String MaximumModulation = "MM";
|
||||
public static final String ControlSetpoint = "CS";
|
||||
public static final String ControlSetpoint2 = "C2";
|
||||
public static final String CentralHeating = "CH";
|
||||
public static final String CentralHeating2 = "H2";
|
||||
public static final String VentilationSetpoint = "VS";
|
||||
public static final String Reset = "RS";
|
||||
public static final String IgnoreTransition = "IT";
|
||||
public static final String OverrideHighbyte = "OH";
|
||||
public static final String ForceThermostat = "FT";
|
||||
public static final String VoltageReference = "VR";
|
||||
public static final String DebugPointer = "DP";
|
||||
public static final String TEMPERATURETEMPORARY = "TT";
|
||||
public static final String TEMPERATURECONSTANT = "TC";
|
||||
public static final String TEMPERATUREOUTSIDE = "OT";
|
||||
public static final String SETCLOCK = "ST";
|
||||
public static final String HOTWATER = "HW";
|
||||
public static final String PRINTREPORT = "PR";
|
||||
public static final String PRINTSUMMARY = "PS";
|
||||
public static final String GATEWAY = "GW";
|
||||
public static final String LEDA = "LA";
|
||||
public static final String LEDB = "LB";
|
||||
public static final String LEDC = "LC";
|
||||
public static final String LEDD = "LD";
|
||||
public static final String LEDE = "LE";
|
||||
public static final String LEDF = "LF";
|
||||
public static final String GPIOA = "GA";
|
||||
public static final String GPIOB = "GB";
|
||||
public static final String SETBACK = "SB";
|
||||
public static final String TEMPERATURESENSOR = "TS";
|
||||
public static final String ADDALTERNATIVE = "AA";
|
||||
public static final String DELETEALTERNATIVE = "DA";
|
||||
public static final String UNKNOWNID = "UI";
|
||||
public static final String KNOWNID = "KI";
|
||||
public static final String PRIORITYMESSAGE = "PM";
|
||||
public static final String SETRESPONSE = "SR";
|
||||
public static final String CLEARRESPONSE = "CR";
|
||||
public static final String SETPOINTHEATING = "SH";
|
||||
public static final String SETPOINTWATER = "SW";
|
||||
public static final String MAXIMUMMODULATION = "MM";
|
||||
public static final String CONTROLSETPOINT = "CS";
|
||||
public static final String CONTROLSETPOINT2 = "C2";
|
||||
public static final String CENTRALHEATING = "CH";
|
||||
public static final String CENTRALHEATING2 = "H2";
|
||||
public static final String VENTILATIONSETPOINT = "VS";
|
||||
public static final String RESET = "RS";
|
||||
public static final String IGNORETRANSITION = "IT";
|
||||
public static final String OVERRIDEHIGHBYTE = "OH";
|
||||
public static final String FORCETHERMOSTAT = "FT";
|
||||
public static final String VOLTAGEREFERENCE = "VR";
|
||||
public static final String DEBUGPOINTER = "DP";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.openthermgateway.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link IntDataItem} represents an 8 or 16 bit signed integer.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class IntDataItem extends DataItem {
|
||||
|
||||
public IntDataItem(Msg msg, ByteType byteType, String subject) {
|
||||
super(msg, byteType, subject, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public State createState(Message message) {
|
||||
return new DecimalType(message.getInt(super.getByteType()));
|
||||
}
|
||||
}
|
||||
@@ -25,15 +25,15 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||
@NonNullByDefault
|
||||
public class Message {
|
||||
|
||||
private static final Pattern messagePattern = Pattern.compile("[TBRA]{1}[A-F0-9]{8}");
|
||||
private static final Pattern MESSAGEPATTERN = Pattern.compile("[TBRA]{1}[A-F0-9]{8}");
|
||||
|
||||
private CodeType code;
|
||||
private CodeType codeType;
|
||||
private MessageType messageType;
|
||||
private int id;
|
||||
private String data;
|
||||
|
||||
public CodeType getCode() {
|
||||
return this.code;
|
||||
public CodeType getCodeType() {
|
||||
return codeType;
|
||||
}
|
||||
|
||||
public MessageType getMessageType() {
|
||||
@@ -129,30 +129,30 @@ public class Message {
|
||||
// If the message is a Request sent to the boiler or an Answer returned to the
|
||||
// thermostat, and it's ID is equal to the previous message, then this is an
|
||||
// override sent by the OpenTherm Gateway
|
||||
return other != null && this.getID() == other.getID() && (this.code == CodeType.R || this.code == CodeType.A);
|
||||
return other != null && this.getID() == other.getID() && (codeType == CodeType.R || codeType == CodeType.A);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s - %s - %s", this.code, this.id, this.data);
|
||||
return String.format("%s - %s - %s", this.codeType, this.id, this.data);
|
||||
}
|
||||
|
||||
public Message(CodeType code, MessageType messageType, int id, String data) {
|
||||
this.code = code;
|
||||
public Message(CodeType codeType, MessageType messageType, int id, String data) {
|
||||
this.codeType = codeType;
|
||||
this.messageType = messageType;
|
||||
this.id = id;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public static @Nullable Message parse(String message) {
|
||||
if (messagePattern.matcher(message).matches()) {
|
||||
if (MESSAGEPATTERN.matcher(message).matches()) {
|
||||
// For now, only parse TBRA codes
|
||||
CodeType code = CodeType.valueOf(message.substring(0, 1));
|
||||
CodeType codeType = CodeType.valueOf(message.substring(0, 1));
|
||||
MessageType messageType = getMessageType(message.substring(1, 3));
|
||||
int id = Integer.valueOf(message.substring(3, 5), 16);
|
||||
String data = message.substring(5);
|
||||
|
||||
return new Message(code, messageType, id, data);
|
||||
return new Message(codeType, messageType, id, data);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -12,12 +12,15 @@
|
||||
*/
|
||||
package org.openhab.binding.openthermgateway.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link MessageType} indicates the type of message received by the OpenTherm Gateway, based
|
||||
* on the OpenTherm specification.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum MessageType {
|
||||
READDATA, // 000
|
||||
READACK, // 100
|
||||
|
||||
@@ -12,12 +12,15 @@
|
||||
*/
|
||||
package org.openhab.binding.openthermgateway.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link Msg} flag is used to indicate whether the message is sent for Reading, Writing
|
||||
* or both, based on the OpenTherm specification.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum Msg {
|
||||
READ,
|
||||
WRITE,
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.openthermgateway.internal;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link OpenThermGatewayBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenThermGatewayBindingConstants {
|
||||
|
||||
// Binding Id
|
||||
public static final String BINDING_ID = "openthermgateway";
|
||||
|
||||
// List of all the ThingType UID's
|
||||
public static final ThingTypeUID OPENTHERM_GATEWAY_THING_TYPE_UID = new ThingTypeUID(BINDING_ID,
|
||||
"openthermgateway");
|
||||
public static final ThingTypeUID BOILER_THING_TYPE_UID = new ThingTypeUID(BINDING_ID, "boiler");
|
||||
public static final ThingTypeUID VENTILATION_HEATRECOVERY_THING_TYPE_UID = new ThingTypeUID(BINDING_ID,
|
||||
"ventilationheatrecovery");
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPE_UIDS = Set.of(OPENTHERM_GATEWAY_THING_TYPE_UID,
|
||||
BOILER_THING_TYPE_UID, VENTILATION_HEATRECOVERY_THING_TYPE_UID);
|
||||
|
||||
// List of id's for writeable channels
|
||||
public static final String CHANNEL_SEND_COMMAND = "sendcommand";
|
||||
public static final String CHANNEL_OVERRIDE_SETPOINT_TEMPORARY = "temperaturetemporary";
|
||||
public static final String CHANNEL_OVERRIDE_SETPOINT_CONSTANT = "temperatureconstant";
|
||||
public static final String CHANNEL_OVERRIDE_DHW_SETPOINT = "overridedhwsetpoint";
|
||||
public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT = "controlsetpointoverride";
|
||||
public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT = "controlsetpoint2override";
|
||||
public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED = "ch_enableoverride";
|
||||
public static final String CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED = "ch2_enableoverride";
|
||||
public static final String CHANNEL_OUTSIDE_TEMPERATURE = "outsidetemp";
|
||||
public static final String CHANNEL_OVERRIDE_VENTILATION_SETPOINT = "vh_ventilationsetpoint";
|
||||
|
||||
// Generic channel type for Transparent Slave Parameter and Fault History Buffer values
|
||||
public static final String CHANNEL_TSPFHB = "tspfhb";
|
||||
}
|
||||
@@ -22,11 +22,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface OpenThermGatewayCallback {
|
||||
void connecting();
|
||||
|
||||
void connected();
|
||||
|
||||
void disconnected();
|
||||
void connectionStateChanged(ConnectionState state);
|
||||
|
||||
void receiveMessage(Message message);
|
||||
}
|
||||
|
||||
@@ -27,4 +27,8 @@ public class OpenThermGatewayConfiguration {
|
||||
public int port = 0;
|
||||
|
||||
public int connectionRetryInterval = 60;
|
||||
|
||||
public int connectTimeoutSeconds = 5;
|
||||
|
||||
public int readTimeoutSeconds = 20;
|
||||
}
|
||||
|
||||
@@ -12,19 +12,23 @@
|
||||
*/
|
||||
package org.openhab.binding.openthermgateway.internal;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link OpenThermGatewayConnector} interface is used to allow multiple types of connectors
|
||||
* to be implemented and used to connect to the OpenTherm Gateway.
|
||||
*
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface OpenThermGatewayConnector extends Runnable {
|
||||
public interface OpenThermGatewayConnector extends Callable<Boolean> {
|
||||
void sendCommand(GatewayCommand command);
|
||||
|
||||
boolean isConnected();
|
||||
|
||||
void stop();
|
||||
|
||||
void start();
|
||||
}
|
||||
|
||||
@@ -14,8 +14,10 @@ package org.openhab.binding.openthermgateway.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.openthermgateway.OpenThermGatewayBindingConstants;
|
||||
import org.openhab.binding.openthermgateway.handler.BoilerHandler;
|
||||
import org.openhab.binding.openthermgateway.handler.OpenThermGatewayHandler;
|
||||
import org.openhab.binding.openthermgateway.handler.VentilationHeatRecoveryHandler;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
@@ -35,15 +37,19 @@ public class OpenThermGatewayHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return thingTypeUID.equals(OpenThermGatewayBindingConstants.MAIN_THING_TYPE);
|
||||
return OpenThermGatewayBindingConstants.SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (thingTypeUID.equals(OpenThermGatewayBindingConstants.MAIN_THING_TYPE)) {
|
||||
return new OpenThermGatewayHandler(thing);
|
||||
if (thingTypeUID.equals(OpenThermGatewayBindingConstants.OPENTHERM_GATEWAY_THING_TYPE_UID)) {
|
||||
return new OpenThermGatewayHandler((Bridge) thing);
|
||||
} else if (thingTypeUID.equals(OpenThermGatewayBindingConstants.BOILER_THING_TYPE_UID)) {
|
||||
return new BoilerHandler(thing);
|
||||
} else if (thingTypeUID.equals(OpenThermGatewayBindingConstants.VENTILATION_HEATRECOVERY_THING_TYPE_UID)) {
|
||||
return new VentilationHeatRecoveryHandler(thing);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
*/
|
||||
package org.openhab.binding.openthermgateway.internal;
|
||||
|
||||
import static org.openhab.binding.openthermgateway.internal.OpenThermGatewayBindingConstants.BINDING_ID;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
@@ -22,12 +24,16 @@ import java.util.AbstractMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.common.NamedThreadFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -39,107 +45,138 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenThermGatewaySocketConnector implements OpenThermGatewayConnector {
|
||||
private static final int COMMAND_RESPONSE_TIME_MILLISECONDS = 100;
|
||||
private static final int COMMAND_TIMEOUT_MILLISECONDS = 5000;
|
||||
private static final int COMMAND_RESPONSE_MIN_WAIT_TIME_MILLISECONDS = 100;
|
||||
private static final int COMMAND_RESPONSE_MAX_WAIT_TIME_MILLISECONDS = 5000;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(OpenThermGatewaySocketConnector.class);
|
||||
|
||||
private final OpenThermGatewayCallback callback;
|
||||
private final String ipaddress;
|
||||
private final int port;
|
||||
private final int connectTimeoutMilliseconds;
|
||||
private final int readTimeoutMilliSeconds;
|
||||
|
||||
private @Nullable PrintWriter writer;
|
||||
|
||||
private volatile boolean stopping;
|
||||
private boolean connected;
|
||||
private @Nullable volatile PrintWriter writer;
|
||||
private @Nullable volatile Thread thread;
|
||||
private @Nullable Future<Boolean> future;
|
||||
private @Nullable ExecutorService executor;
|
||||
|
||||
private Map<String, Entry<Long, GatewayCommand>> pendingCommands = new ConcurrentHashMap<>();
|
||||
|
||||
public OpenThermGatewaySocketConnector(OpenThermGatewayCallback callback, String ipaddress, int port) {
|
||||
public OpenThermGatewaySocketConnector(OpenThermGatewayCallback callback, OpenThermGatewayConfiguration config) {
|
||||
this.callback = callback;
|
||||
this.ipaddress = ipaddress;
|
||||
this.port = port;
|
||||
ipaddress = config.ipaddress;
|
||||
port = config.port;
|
||||
connectTimeoutMilliseconds = config.connectTimeoutSeconds * 1000;
|
||||
readTimeoutMilliSeconds = config.readTimeoutSeconds * 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
stopping = false;
|
||||
connected = false;
|
||||
|
||||
logger.debug("Connecting OpenThermGatewaySocketConnector to {}:{}", this.ipaddress, this.port);
|
||||
|
||||
callback.connecting();
|
||||
|
||||
public Boolean call() throws Exception {
|
||||
thread = Thread.currentThread();
|
||||
try (Socket socket = new Socket()) {
|
||||
socket.connect(new InetSocketAddress(this.ipaddress, this.port), COMMAND_TIMEOUT_MILLISECONDS);
|
||||
socket.setSoTimeout(COMMAND_TIMEOUT_MILLISECONDS);
|
||||
logger.debug("Connecting OpenThermGatewaySocketConnector to {}:{}", this.ipaddress, this.port);
|
||||
callback.connectionStateChanged(ConnectionState.CONNECTING);
|
||||
|
||||
connected = true;
|
||||
|
||||
callback.connected();
|
||||
socket.connect(new InetSocketAddress(ipaddress, port), connectTimeoutMilliseconds);
|
||||
socket.setSoTimeout(readTimeoutMilliSeconds);
|
||||
|
||||
logger.debug("OpenThermGatewaySocketConnector connected");
|
||||
callback.connectionStateChanged(ConnectionState.CONNECTED);
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
PrintWriter wrt = new PrintWriter(socket.getOutputStream(), true)) {
|
||||
// Make writer accessible on class level
|
||||
writer = wrt;
|
||||
|
||||
sendCommand(GatewayCommand.parse(GatewayCommandCode.PrintReport, "A"));
|
||||
sendCommand(GatewayCommand.parse(GatewayCommandCode.PRINTREPORT, "A"));
|
||||
// Set the OTGW to report every message it receives and transmits
|
||||
sendCommand(GatewayCommand.parse(GatewayCommandCode.PrintSummary, "0"));
|
||||
sendCommand(GatewayCommand.parse(GatewayCommandCode.PRINTSUMMARY, "0"));
|
||||
|
||||
while (!stopping && !Thread.currentThread().isInterrupted()) {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
@Nullable
|
||||
String message = reader.readLine();
|
||||
|
||||
if (message != null) {
|
||||
handleMessage(message);
|
||||
} else {
|
||||
logger.debug("Connection closed by OpenTherm Gateway");
|
||||
logger.debug("Received NULL message from OpenTherm Gateway (EOF)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("Stopping OpenThermGatewaySocketConnector");
|
||||
} finally {
|
||||
connected = false;
|
||||
|
||||
logger.debug("OpenThermGatewaySocketConnector disconnected");
|
||||
callback.disconnected();
|
||||
} catch (IOException ex) {
|
||||
logger.warn("Error communicating with OpenTherm Gateway: '{}'", ex.getMessage());
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
logger.warn("Unable to connect to the OpenTherm Gateway.", ex);
|
||||
callback.disconnected();
|
||||
logger.warn("Unable to connect to the OpenTherm Gateway: '{}'", ex.getMessage());
|
||||
}
|
||||
thread = null;
|
||||
writer = null;
|
||||
logger.debug("OpenThermGatewaySocketConnector disconnected");
|
||||
callback.connectionStateChanged(ConnectionState.DISCONNECTED);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
logger.debug("Stopping OpenThermGatewaySocketConnector");
|
||||
stopping = true;
|
||||
|
||||
Thread thread = this.thread;
|
||||
Future<Boolean> future = this.future;
|
||||
ExecutorService executor = this.executor;
|
||||
|
||||
if (executor != null) {
|
||||
executor.shutdown();
|
||||
}
|
||||
if ((thread != null) && thread.isAlive()) {
|
||||
thread.interrupt();
|
||||
}
|
||||
if (future != null) {
|
||||
try {
|
||||
future.get(readTimeoutMilliSeconds, TimeUnit.MILLISECONDS);
|
||||
} catch (ExecutionException e) {
|
||||
// expected exception due to e.g. IOException on socket close
|
||||
} catch (TimeoutException | InterruptedException e) {
|
||||
// unexpected exception
|
||||
logger.warn("stop() exception '{}' => PLEASE REPORT !!", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
this.thread = null;
|
||||
this.future = null;
|
||||
this.executor = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return connected;
|
||||
public void start() {
|
||||
logger.debug("Starting OpenThermGatewaySocketConnector");
|
||||
ExecutorService executor = this.executor = Executors
|
||||
.newSingleThreadExecutor(new NamedThreadFactory("binding-" + BINDING_ID));
|
||||
future = executor.submit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCommand(GatewayCommand command) {
|
||||
@Nullable
|
||||
PrintWriter wrtr = writer;
|
||||
public synchronized boolean isConnected() {
|
||||
Thread thread = this.thread;
|
||||
return (thread != null) && thread.isAlive();
|
||||
}
|
||||
|
||||
String msg = command.toFullString();
|
||||
@Override
|
||||
public synchronized void sendCommand(GatewayCommand command) {
|
||||
PrintWriter wrt = writer;
|
||||
|
||||
pendingCommands.put(command.getCode(),
|
||||
new AbstractMap.SimpleImmutableEntry<>(System.currentTimeMillis(), command));
|
||||
|
||||
if (connected) {
|
||||
String msg = command.toFullString();
|
||||
|
||||
if (isConnected() && (wrt != null)) {
|
||||
logger.debug("Sending message: {}", msg);
|
||||
if (wrtr != null) {
|
||||
wrtr.print(msg + "\r\n");
|
||||
wrtr.flush();
|
||||
wrt.print(msg + "\r\n");
|
||||
wrt.flush();
|
||||
if (wrt.checkError()) {
|
||||
logger.warn("sendCommand() error sending message to OpenTherm Gateway => PLEASE REPORT !!");
|
||||
stop();
|
||||
}
|
||||
} else {
|
||||
logger.debug("Unable to send message: {}. OpenThermGatewaySocketConnector is not connected.", msg);
|
||||
@@ -159,8 +196,8 @@ public class OpenThermGatewaySocketConnector implements OpenThermGatewayConnecto
|
||||
long currentTime = System.currentTimeMillis();
|
||||
|
||||
for (Entry<Long, GatewayCommand> timeAndCommand : pendingCommands.values()) {
|
||||
long responseTime = timeAndCommand.getKey() + COMMAND_RESPONSE_TIME_MILLISECONDS;
|
||||
long timeoutTime = timeAndCommand.getKey() + COMMAND_TIMEOUT_MILLISECONDS;
|
||||
long responseTime = timeAndCommand.getKey() + COMMAND_RESPONSE_MIN_WAIT_TIME_MILLISECONDS;
|
||||
long timeoutTime = timeAndCommand.getKey() + COMMAND_RESPONSE_MAX_WAIT_TIME_MILLISECONDS;
|
||||
|
||||
if (currentTime > responseTime && currentTime <= timeoutTime) {
|
||||
logger.debug("Resending command: {}", timeAndCommand.getValue());
|
||||
@@ -175,47 +212,11 @@ public class OpenThermGatewaySocketConnector implements OpenThermGatewayConnecto
|
||||
if (msg == null) {
|
||||
logger.trace("Received message: {}, (unknown)", message);
|
||||
return;
|
||||
} else {
|
||||
logger.trace("Received message: {}, {} {} {}", message, msg.getID(), msg.getCode(), msg.getMessageType());
|
||||
}
|
||||
|
||||
if (DataItemGroup.dataItemGroups.containsKey(msg.getID())) {
|
||||
DataItem[] dataItems = DataItemGroup.dataItemGroups.get(msg.getID());
|
||||
|
||||
for (DataItem dataItem : dataItems) {
|
||||
State state = null;
|
||||
|
||||
switch (dataItem.getDataType()) {
|
||||
case FLAGS:
|
||||
state = OnOffType.from(msg.getBit(dataItem.getByteType(), dataItem.getBitPos()));
|
||||
break;
|
||||
case UINT8:
|
||||
case UINT16:
|
||||
state = new DecimalType(msg.getUInt(dataItem.getByteType()));
|
||||
break;
|
||||
case INT8:
|
||||
case INT16:
|
||||
state = new DecimalType(msg.getInt(dataItem.getByteType()));
|
||||
break;
|
||||
case FLOAT:
|
||||
state = new DecimalType(msg.getFloat());
|
||||
break;
|
||||
case DOWTOD:
|
||||
break;
|
||||
}
|
||||
|
||||
logger.trace(" Data: {} {} {} {}", dataItem.getID(), dataItem.getSubject(), dataItem.getDataType(),
|
||||
state == null ? "" : state);
|
||||
}
|
||||
}
|
||||
|
||||
logger.trace("Received message: {}, {} {} {}", message, msg.getID(), msg.getCodeType(), msg.getMessageType());
|
||||
if (msg.getMessageType() == MessageType.READACK || msg.getMessageType() == MessageType.WRITEDATA
|
||||
|| msg.getID() == 0 || msg.getID() == 1) {
|
||||
receiveMessage(msg);
|
||||
callback.receiveMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void receiveMessage(Message message) {
|
||||
callback.receiveMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.openthermgateway.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link DataItem} represents a transparent slave parameter or fault history buffer size.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TspFhbSizeDataItem extends DataItem {
|
||||
private int valueId;
|
||||
|
||||
public int getValueId() {
|
||||
return valueId;
|
||||
}
|
||||
|
||||
public TspFhbSizeDataItem(Msg msg, ByteType byteType, int valueId, String subject) {
|
||||
super(msg, byteType, subject, null);
|
||||
|
||||
this.valueId = valueId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State createState(Message message) {
|
||||
return new DecimalType(message.getUInt(super.getByteType()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.openthermgateway.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link TspFhbValueDataItem} represents a transparent slave parameter or fault history buffer value.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TspFhbValueDataItem extends DataItem {
|
||||
|
||||
public TspFhbValueDataItem(Msg msg, String subject) {
|
||||
super(msg, ByteType.BOTH, subject, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChannelId(Message message) {
|
||||
// With TSP or FHB values, the index is HIGHBYTE, the value is LOWBYTE
|
||||
int index = message.getUInt(ByteType.HIGHBYTE);
|
||||
return getChannelId(index);
|
||||
}
|
||||
|
||||
public String getChannelId(int index) {
|
||||
return super.getSubject() + "_" + index;
|
||||
}
|
||||
|
||||
public String getLabel(int index) {
|
||||
return super.getSubject() + " " + index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State createState(Message message) {
|
||||
// With TSP or FHB values, the index is HIGHBYTE, the value is LOWBYTE
|
||||
// TSP values are treated as Number:Dimensionless
|
||||
return new DecimalType(message.getUInt(ByteType.LOWBYTE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.openthermgateway.internal;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link UIntDataItem} represents an 8 or 16 bit unsigned integer.
|
||||
*
|
||||
* @author Arjen Korevaar - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class UIntDataItem extends DataItem {
|
||||
|
||||
private @Nullable Unit<?> unit;
|
||||
|
||||
public @Nullable Unit<?> getUnit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
public UIntDataItem(Msg msg, ByteType byteType, String subject) {
|
||||
this(msg, byteType, subject, null);
|
||||
}
|
||||
|
||||
public UIntDataItem(Msg msg, ByteType byteType, String subject, @Nullable Unit<?> unit) {
|
||||
super(msg, byteType, subject, null);
|
||||
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State createState(Message message) {
|
||||
@Nullable
|
||||
Unit<?> unit = getUnit();
|
||||
int value = message.getUInt(super.getByteType());
|
||||
return (unit == null) ? new DecimalType(value) : new QuantityType<>(value, unit);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
|
||||
<config-description uri="thing-type:openthermgateway:otgw">
|
||||
<config-description uri="thing-type:openthermgateway:openthermgateway">
|
||||
<parameter-group name="connection">
|
||||
<label>Connection</label>
|
||||
<description>Connection settings.</description>
|
||||
@@ -28,6 +28,20 @@
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
|
||||
<parameter name="connectTimeoutSeconds" type="integer" required="true" groupName="connection" min="5"
|
||||
max="60" unit="s">
|
||||
<label>Connect Timeout</label>
|
||||
<description>The maximum time (seconds) to wait for establishing a connection to the gateway.</description>
|
||||
<default>5</default>
|
||||
</parameter>
|
||||
|
||||
<parameter name="readTimeoutSeconds" type="integer" required="true" groupName="connection" min="5" max="60"
|
||||
unit="s">
|
||||
<label>Read Timeout</label>
|
||||
<description>The maximum time (seconds) to wait for reading responses from the gateway.</description>
|
||||
<default>20</default>
|
||||
</parameter>
|
||||
|
||||
</config-description>
|
||||
|
||||
</config-description:config-descriptions>
|
||||
@@ -3,9 +3,12 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
<thing-type id="otgw">
|
||||
<label>OpenTherm Gateway</label>
|
||||
<description>OpenTherm Gateway binding</description>
|
||||
<thing-type id="boiler">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="openthermgateway"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Boiler</label>
|
||||
<description>Boiler and thermostat</description>
|
||||
<channels>
|
||||
<channel id="roomtemp" typeId="roomtemp"/>
|
||||
<channel id="roomsetpoint" typeId="roomsetpoint"/>
|
||||
@@ -44,6 +47,7 @@
|
||||
<channel id="airpressfault" typeId="airpressfault"/>
|
||||
<channel id="waterovtemp" typeId="waterovtemp"/>
|
||||
<channel id="oemfaultcode" typeId="oemfaultcode"/>
|
||||
<channel id="diag" typeId="diag"/>
|
||||
<channel id="unsuccessfulburnerstarts" typeId="unsuccessfulburnerstarts"/>
|
||||
<channel id="burnerstarts" typeId="burnerstarts"/>
|
||||
<channel id="chpumpstarts" typeId="chpumpstarts"/>
|
||||
@@ -53,12 +57,11 @@
|
||||
<channel id="chpumphours" typeId="chpumphours"/>
|
||||
<channel id="dhwpvhours" typeId="dhwpvhours"/>
|
||||
<channel id="dhwburnerhours" typeId="dhwburnerhours"/>
|
||||
<channel id="sendcommand" typeId="sendcommand"/>
|
||||
<channel id="tspnumber" typeId="tspnumber"/>
|
||||
<channel id="tspentry" typeId="tspentry"/>
|
||||
<channel id="fhbnumber" typeId="fhbnumber"/>
|
||||
<channel id="fhbentry" typeId="fhbentry"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="version">1.3.0</property>
|
||||
</properties>
|
||||
<config-description-ref uri="thing-type:openthermgateway:otgw"/>
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -4,6 +4,26 @@
|
||||
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">
|
||||
|
||||
<!-- generic channel type for dynamic tsp and fhb channels -->
|
||||
|
||||
<channel-type id="tspfhb">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Set Dynamically</label>
|
||||
<description>Transparent slave parameter or Fault history buffer value</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- openthermgateway -->
|
||||
|
||||
<channel-type id="sendcommand">
|
||||
<item-type>String</item-type>
|
||||
<label>Send Command</label>
|
||||
<description>Channel to send commands to the OpenTherm Gateway device</description>
|
||||
<state readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- boiler -->
|
||||
|
||||
<channel-type id="roomtemp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Room Temperature</label>
|
||||
@@ -349,11 +369,351 @@
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sendcommand">
|
||||
<item-type>String</item-type>
|
||||
<label>Send Command</label>
|
||||
<description>Channel to send commands to the OpenTherm Gateway device</description>
|
||||
<state readOnly="false"/>
|
||||
<channel-type id="tspnumber">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Transparent Slave Parameter Number</label>
|
||||
<description>Number of transparant slave parameter entries</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tspentry">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Transparent Slave Parameter Entry</label>
|
||||
<description>Transparent slave parameter entry</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fhbnumber">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Fault History Buffer Number</label>
|
||||
<description>Number of fault history buffer entries</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fhbentry">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Fault History Buffer Entry</label>
|
||||
<description>Fault history buffer entry</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- ventilationheatrecovery -->
|
||||
|
||||
<channel-type id="vh_ventilationenable">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Ventilation</label>
|
||||
<description>Ventilation enabled</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_bypassposition">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Bypass Position</label>
|
||||
<description>Bypass position</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="0">close</option>
|
||||
<option value="1">open</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_bypassmode">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Bypass Mode</label>
|
||||
<description>Bypass mode</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="0">manual</option>
|
||||
<option value="1">automatic</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_freeventilationmode">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Free Ventilation Mode</label>
|
||||
<description>Free ventilation mode</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_faultindication">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Fault Indication</label>
|
||||
<description>Fault indication</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_ventilationmode">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Ventilation Mode</label>
|
||||
<description>Ventilation mode</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_bypassstatus">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Bypass Status</label>
|
||||
<description>Bypass status</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_bypassautomaticstatus">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Bypass Automatic Status</label>
|
||||
<description>Bypass automatic status</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="0">manual</option>
|
||||
<option value="1">automatic</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_freeventilationstatus">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Free Ventilation Status</label>
|
||||
<description>Free ventilation status</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_diagnosticindication">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Diagnostic Indication</label>
|
||||
<description>Diagnostic indication</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_controlsetpoint">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Control Setpoint</label>
|
||||
<description>Control setpoint</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_servicerequest">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Service Request</label>
|
||||
<description>Service request</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_exhaustfanfault">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Exhaust Fan Fault</label>
|
||||
<description>Exhaust fan fault</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_inletfanfault">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Inlet Fan Fault</label>
|
||||
<description>Inlet fan fault</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_frostprotection">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Frost Protection</label>
|
||||
<description>Frost protection</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_faultcode">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Fault Code</label>
|
||||
<description>Fault code</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_diagnosticcode">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Diagnostic Code</label>
|
||||
<description>Diagnostic code</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_systemtype">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>System Type</label>
|
||||
<description>System type</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="0">central exaust</option>
|
||||
<option value="1">heat-recovery</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_bypass">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Bypass</label>
|
||||
<description>Bypass</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_speedcontrol">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Speed Control</label>
|
||||
<description>Speed control</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="0">3-speed</option>
|
||||
<option value="1">variable</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_memberid">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Member ID</label>
|
||||
<description>Member ID</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_openthermversion">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>OpenTherm Version</label>
|
||||
<description>OpenTherm version</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_versiontype">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Version Type</label>
|
||||
<description>Version type</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_relativeventilation">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Relative Ventilation</label>
|
||||
<description>Relative ventilation position</description>
|
||||
<state readOnly="true" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_relativehumidity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Relative Humidity</label>
|
||||
<description>Relative humidity exhaust air</description>
|
||||
<state readOnly="true" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_co2level">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>CO2 Level</label>
|
||||
<description>CO2 level exhaust air</description>
|
||||
<state readOnly="true" pattern="%d ppm"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_supplyinlettemp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Supply Inlet Temperature</label>
|
||||
<description>Supply inlet temperature</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_supplyoutlettemp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Supply Outlet Temperature</label>
|
||||
<description>Supply outlet temperature</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_exhaustinlettemp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Exhaust Inlet Temperature</label>
|
||||
<description>Exhaust inlet temperature</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_exhaustoutlettemp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Exhaust Outlet Temperature</label>
|
||||
<description>Exhaust outlet temperature</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_actualexhaustfanspeed">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Actual Exhaust Fan Speed</label>
|
||||
<description>Actual exhaust fan speed</description>
|
||||
<state readOnly="true" pattern="%d rpm"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_actualinletfanspeed">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Actual Inlet Fan Speed</label>
|
||||
<description>Actual inlet fan speed</description>
|
||||
<state readOnly="true" pattern="%d rpm"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_nominalventenable">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Nominal Ventilation Value Transfer</label>
|
||||
<description>Nominal ventilation value transfer enabled</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_nominalventrw">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Nominal Ventilation Value</label>
|
||||
<description>Nominal ventilation value</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="0">read-only</option>
|
||||
<option value="1">read/write</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_nominalventilationvalue">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Nominal Ventilation Value</label>
|
||||
<description>Nominal ventilation value</description>
|
||||
<state readOnly="true" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_filtercheck">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Filter Check</label>
|
||||
<description>Filter Check enabled</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_tspnumber">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Transparent Slave Parameter Number</label>
|
||||
<description>Number of transparent slave parameter entries</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_tspentry">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Transparent Slave Parameter Entry</label>
|
||||
<description>Transparent slave parameter entry</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_fhbnumber">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Fault History Buffer Number</label>
|
||||
<description>Number of fault history buffer entries</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_fhbentry">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Fault History Buffer Entry</label>
|
||||
<description>Fault history buffer entry</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="vh_ventilationsetpoint">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Ventilation Setpoint</label>
|
||||
<description>Ventilation setpoint override</description>
|
||||
<state readOnly="false" min="0" max="100" step="1"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="openthermgateway"
|
||||
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">
|
||||
<bridge-type id="openthermgateway">
|
||||
<label>OpenTherm Gateway</label>
|
||||
<description>OpenTherm Gateway</description>
|
||||
<channels>
|
||||
<channel id="sendcommand" typeId="sendcommand"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="version">2.2.0</property>
|
||||
</properties>
|
||||
<config-description-ref uri="thing-type:openthermgateway:openthermgateway"/>
|
||||
</bridge-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="openthermgateway"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
<thing-type id="ventilationheatrecovery">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="openthermgateway"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Ventilation / Heat Recovery</label>
|
||||
<description>Ventilation or Heat Recovery unit</description>
|
||||
<channels>
|
||||
<channel id="vh_ventilationenable" typeId="vh_ventilationenable"/>
|
||||
<channel id="vh_bypassposition" typeId="vh_bypassposition"/>
|
||||
<channel id="vh_bypassmode" typeId="vh_bypassmode"/>
|
||||
<channel id="vh_freeventilationmode" typeId="vh_freeventilationmode"/>
|
||||
<channel id="vh_faultindication" typeId="vh_faultindication"/>
|
||||
<channel id="vh_ventilationmode" typeId="vh_ventilationmode"/>
|
||||
<channel id="vh_bypassstatus" typeId="vh_bypassstatus"/>
|
||||
<channel id="vh_bypassautomaticstatus" typeId="vh_bypassautomaticstatus"/>
|
||||
<channel id="vh_freeventilationstatus" typeId="vh_freeventilationstatus"/>
|
||||
<channel id="vh_filtercheck" typeId="vh_filtercheck"/>
|
||||
<channel id="vh_diagnosticindication" typeId="vh_diagnosticindication"/>
|
||||
<channel id="vh_controlsetpoint" typeId="vh_controlsetpoint"/>
|
||||
<channel id="vh_servicerequest" typeId="vh_servicerequest"/>
|
||||
<channel id="vh_exhaustfanfault" typeId="vh_exhaustfanfault"/>
|
||||
<channel id="vh_inletfanfault" typeId="vh_inletfanfault"/>
|
||||
<channel id="vh_frostprotection" typeId="vh_frostprotection"/>
|
||||
<channel id="vh_faultcode" typeId="vh_faultcode"/>
|
||||
<channel id="vh_diagnosticcode" typeId="vh_diagnosticcode"/>
|
||||
<channel id="vh_systemtype" typeId="vh_systemtype"/>
|
||||
<channel id="vh_bypass" typeId="vh_bypass"/>
|
||||
<channel id="vh_speedcontrol" typeId="vh_speedcontrol"/>
|
||||
<channel id="vh_memberid" typeId="vh_memberid"/>
|
||||
<channel id="vh_openthermversion" typeId="vh_openthermversion"/>
|
||||
<channel id="vh_versiontype" typeId="vh_versiontype"/>
|
||||
<channel id="vh_relativeventilation" typeId="vh_relativeventilation"/>
|
||||
<channel id="vh_relativehumidity" typeId="vh_relativehumidity"/>
|
||||
<channel id="vh_co2level" typeId="vh_co2level"/>
|
||||
<channel id="vh_supplyinlettemp" typeId="vh_supplyinlettemp"/>
|
||||
<channel id="vh_supplyoutlettemp" typeId="vh_supplyoutlettemp"/>
|
||||
<channel id="vh_exhaustinlettemp" typeId="vh_exhaustinlettemp"/>
|
||||
<channel id="vh_exhaustoutlettemp" typeId="vh_exhaustoutlettemp"/>
|
||||
<channel id="vh_actualexhaustfanspeed" typeId="vh_actualexhaustfanspeed"/>
|
||||
<channel id="vh_actualinletfanspeed" typeId="vh_actualinletfanspeed"/>
|
||||
<channel id="vh_nominalventenable" typeId="vh_nominalventenable"/>
|
||||
<channel id="vh_nominalventrw" typeId="vh_nominalventrw"/>
|
||||
<channel id="vh_nominalventilationvalue" typeId="vh_nominalventilationvalue"/>
|
||||
<channel id="vh_ventilationsetpoint" typeId="vh_ventilationsetpoint"/>
|
||||
<channel id="vh_tspnumber" typeId="vh_tspnumber"/>
|
||||
<channel id="vh_tspentry" typeId="vh_tspentry"/>
|
||||
<channel id="vh_fhbnumber" typeId="vh_fhbnumber"/>
|
||||
<channel id="vh_fhbentry" typeId="vh_fhbentry"/>
|
||||
</channels>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user