[guntamatic] Initial contribution: Binding for Guntamatic Heating Systems (#12011)

Signed-off-by: Michael Weger <weger.michael@gmx.net>
This commit is contained in:
MikeTheTux
2022-01-11 22:35:18 +01:00
committed by GitHub
parent 11ed1c3e66
commit 7b0ba301e7
16 changed files with 1776 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.guntamatic-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-guntamatic" description="Guntamatic Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.guntamatic/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,76 @@
/**
* 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.guntamatic.internal;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link GuntamaticBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Weger Michael - Initial contribution
*/
@NonNullByDefault
public class GuntamaticBindingConstants {
public static final String BINDING_ID = "guntamatic";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_BIOSTAR = new ThingTypeUID(BINDING_ID, "biostar");
public static final ThingTypeUID THING_TYPE_POWERCHIP = new ThingTypeUID(BINDING_ID, "powerchip");
public static final ThingTypeUID THING_TYPE_POWERCORN = new ThingTypeUID(BINDING_ID, "powercorn");
public static final ThingTypeUID THING_TYPE_BIOCOM = new ThingTypeUID(BINDING_ID, "biocom");
public static final ThingTypeUID THING_TYPE_PRO = new ThingTypeUID(BINDING_ID, "pro");
public static final ThingTypeUID THING_TYPE_THERM = new ThingTypeUID(BINDING_ID, "therm");
// List of all Channel ids
public static final String CHANNEL_CONTROLBOILERAPPROVAL = "controlBoilerApproval";
public static final String CHANNEL_CONTROLPROGRAM = "controlProgram";
public static final String CHANNEL_CONTROLHEATCIRCPROGRAM0 = "controlHeatCircProgram0";
public static final String CHANNEL_CONTROLHEATCIRCPROGRAM1 = "controlHeatCircProgram1";
public static final String CHANNEL_CONTROLHEATCIRCPROGRAM2 = "controlHeatCircProgram2";
public static final String CHANNEL_CONTROLHEATCIRCPROGRAM3 = "controlHeatCircProgram3";
public static final String CHANNEL_CONTROLHEATCIRCPROGRAM4 = "controlHeatCircProgram4";
public static final String CHANNEL_CONTROLHEATCIRCPROGRAM5 = "controlHeatCircProgram5";
public static final String CHANNEL_CONTROLHEATCIRCPROGRAM6 = "controlHeatCircProgram6";
public static final String CHANNEL_CONTROLHEATCIRCPROGRAM7 = "controlHeatCircProgram7";
public static final String CHANNEL_CONTROLHEATCIRCPROGRAM8 = "controlHeatCircProgram8";
public static final String CHANNEL_CONTROLWWHEAT0 = "controlWwHeat0";
public static final String CHANNEL_CONTROLWWHEAT1 = "controlWwHeat1";
public static final String CHANNEL_CONTROLWWHEAT2 = "controlWwHeat2";
public static final String CHANNEL_CONTROLEXTRAWWHEAT0 = "controlExtraWwHeat0";
public static final String CHANNEL_CONTROLEXTRAWWHEAT1 = "controlExtraWwHeat1";
public static final String CHANNEL_CONTROLEXTRAWWHEAT2 = "controlExtraWwHeat2";
public static final List<String> CHANNELIDS = Arrays.asList(CHANNEL_CONTROLBOILERAPPROVAL, CHANNEL_CONTROLPROGRAM,
CHANNEL_CONTROLHEATCIRCPROGRAM0, CHANNEL_CONTROLHEATCIRCPROGRAM1, CHANNEL_CONTROLHEATCIRCPROGRAM2,
CHANNEL_CONTROLHEATCIRCPROGRAM3, CHANNEL_CONTROLHEATCIRCPROGRAM4, CHANNEL_CONTROLHEATCIRCPROGRAM5,
CHANNEL_CONTROLHEATCIRCPROGRAM6, CHANNEL_CONTROLHEATCIRCPROGRAM7, CHANNEL_CONTROLHEATCIRCPROGRAM8,
CHANNEL_CONTROLWWHEAT0, CHANNEL_CONTROLWWHEAT1, CHANNEL_CONTROLWWHEAT2, CHANNEL_CONTROLEXTRAWWHEAT0,
CHANNEL_CONTROLEXTRAWWHEAT1, CHANNEL_CONTROLEXTRAWWHEAT2);
public static final String PARAMETER_BOILERAPPROVAL = "boilerApproval";
public static final String PARAMETER_PROGRAM = "program";
public static final String PARAMETER_HEATCIRCPROGRAM = "heatCircProgram";
public static final String PARAMETER_WWHEAT = "wwHeat";
public static final String PARAMETER_EXTRAWWHEAT = "extraWwHeat";
public static final String DAQDATA_URL = "/daqdata.cgi";
public static final String DAQDESC_URL = "/daqdesc.cgi";
public static final String DAQEXTDESC_URL = "/ext/daqdesc.cgi";
public static final String PARSET_URL = "/ext/parset.cgi";
}

View File

@@ -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.guntamatic.internal;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.type.ChannelType;
import org.openhab.core.thing.type.ChannelTypeBuilder;
import org.openhab.core.thing.type.ChannelTypeProvider;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.thing.type.StateChannelTypeBuilder;
import org.openhab.core.types.StateDescriptionFragmentBuilder;
import org.osgi.service.component.annotations.Component;
/**
* Provide channelTypes for Guntamatic Heating Systems
*
* @author Weger Michael - Initial contribution
*/
@Component(service = { ChannelTypeProvider.class, GuntamaticChannelTypeProvider.class })
@NonNullByDefault
public class GuntamaticChannelTypeProvider implements ChannelTypeProvider {
private final Map<String, ChannelType> channelTypes = new ConcurrentHashMap<>();
@Override
public Collection<ChannelType> getChannelTypes(@Nullable Locale locale) {
return channelTypes.values();
}
@Override
public @Nullable ChannelType getChannelType(ChannelTypeUID channelTypeUID, @Nullable Locale locale) {
return channelTypes.get(channelTypeUID.getAsString()); // returns null if not found
}
public void addChannelType(ChannelTypeUID channelTypeUID, String label, String itemType, String description,
boolean advanced, String pattern) {
StateDescriptionFragmentBuilder stateDescriptionFragmentBuilder = StateDescriptionFragmentBuilder.create()
.withReadOnly(true);
if (!pattern.isEmpty()) {
stateDescriptionFragmentBuilder.withPattern(pattern);
}
StateChannelTypeBuilder stateChannelTypeBuilder = ChannelTypeBuilder.state(channelTypeUID, label, itemType)
.withDescription(description).isAdvanced(advanced)
.withStateDescriptionFragment(stateDescriptionFragmentBuilder.build());
channelTypes.put(channelTypeUID.getAsString(), stateChannelTypeBuilder.build());
}
}

View File

@@ -0,0 +1,32 @@
/**
* 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.guntamatic.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link GuntamaticConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Weger Michael - Initial contribution
*/
@NonNullByDefault
public class GuntamaticConfiguration {
/**
* Configuration parameters
*/
public String hostname = "";
public String key = "";
public int refreshInterval = 60;
public String encoding = "windows-1252";
}

View File

@@ -0,0 +1,459 @@
/**
* 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.guntamatic.internal;
import static org.openhab.binding.guntamatic.internal.GuntamaticBindingConstants.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.openhab.core.library.CoreItemFactory;
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.types.StringType;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
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.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;
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.RefreshType;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
/**
* The {@link GuntamaticHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Weger Michael - Initial contribution
*/
@NonNullByDefault
public class GuntamaticHandler extends BaseThingHandler {
private static final String NUMBER_TEMPERATURE = CoreItemFactory.NUMBER + ":Temperature";
private static final String NUMBER_VOLUME = CoreItemFactory.NUMBER + ":Volume";
private static final String NUMBER_TIME = CoreItemFactory.NUMBER + ":Time";
private static final String NUMBER_DIMENSIONLESS = CoreItemFactory.NUMBER + ":Dimensionless";
private static final Map<String, Unit<?>> MAP_UNIT = Map.of("%", Units.PERCENT, "°C", SIUnits.CELSIUS, "°F",
ImperialUnits.FAHRENHEIT, "m3", SIUnits.CUBIC_METRE, "d", Units.DAY, "h", Units.HOUR);
private static final Map<Unit<?>, String> MAP_UNIT_ITEMTYPE = Map.of(Units.PERCENT, NUMBER_DIMENSIONLESS,
SIUnits.CELSIUS, NUMBER_TEMPERATURE, ImperialUnits.FAHRENHEIT, NUMBER_TEMPERATURE, SIUnits.CUBIC_METRE,
NUMBER_VOLUME, Units.DAY, NUMBER_TIME, Units.HOUR, NUMBER_TIME);
private final Logger logger = LoggerFactory.getLogger(GuntamaticHandler.class);
private final HttpClient httpClient;
private @Nullable ScheduledFuture<?> pollingFuture = null;
private GuntamaticConfiguration config = new GuntamaticConfiguration();
private Boolean channelsInitialized = false;
private GuntamaticChannelTypeProvider guntamaticChannelTypeProvider;
private Map<Integer, String> channels = new HashMap<>();
private Map<Integer, String> types = new HashMap<>();
private Map<Integer, Unit<?>> units = new HashMap<>();
public GuntamaticHandler(Thing thing, HttpClient httpClient,
GuntamaticChannelTypeProvider guntamaticChannelTypeProvider) {
super(thing);
this.httpClient = httpClient;
this.guntamaticChannelTypeProvider = guntamaticChannelTypeProvider;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (!(command instanceof RefreshType)) {
if (!config.key.isBlank()) {
String param;
String channelID = channelUID.getId();
switch (channelID) {
case CHANNEL_CONTROLBOILERAPPROVAL:
param = getThing().getProperties().get(PARAMETER_BOILERAPPROVAL);
break;
case CHANNEL_CONTROLPROGRAM:
param = getThing().getProperties().get(PARAMETER_PROGRAM);
break;
case CHANNEL_CONTROLHEATCIRCPROGRAM0:
case CHANNEL_CONTROLHEATCIRCPROGRAM1:
case CHANNEL_CONTROLHEATCIRCPROGRAM2:
case CHANNEL_CONTROLHEATCIRCPROGRAM3:
case CHANNEL_CONTROLHEATCIRCPROGRAM4:
case CHANNEL_CONTROLHEATCIRCPROGRAM5:
case CHANNEL_CONTROLHEATCIRCPROGRAM6:
case CHANNEL_CONTROLHEATCIRCPROGRAM7:
case CHANNEL_CONTROLHEATCIRCPROGRAM8:
param = getThing().getProperties().get(PARAMETER_HEATCIRCPROGRAM).replace("x",
channelID.substring(channelID.length() - 1));
break;
case CHANNEL_CONTROLWWHEAT0:
case CHANNEL_CONTROLWWHEAT1:
case CHANNEL_CONTROLWWHEAT2:
param = getThing().getProperties().get(PARAMETER_WWHEAT).replace("x",
channelID.substring(channelID.length() - 1));
break;
case CHANNEL_CONTROLEXTRAWWHEAT0:
case CHANNEL_CONTROLEXTRAWWHEAT1:
case CHANNEL_CONTROLEXTRAWWHEAT2:
param = getThing().getProperties().get(PARAMETER_EXTRAWWHEAT).replace("x",
channelID.substring(channelID.length() - 1));
break;
default:
return;
}
String response = sendGetRequest(PARSET_URL, "syn=" + param, "value=" + command.toString());
if (response != null) {
State newState = new StringType(response);
updateState(channelID, newState);
}
} else {
logger.warn("A 'key' needs to be configured in order to control the Guntamatic Heating System");
}
}
}
private void parseAndUpdate(String html) {
String[] daqdata = html.split("\\n");
for (Integer i : channels.keySet()) {
String channel = channels.get(i);
Unit<?> unit = units.get(i);
if ((channel != null) && (i < daqdata.length)) {
String value = daqdata[i];
Channel chn = thing.getChannel(channel);
if ((chn != null) && (value != null)) {
value = value.trim();
String typeName = chn.getAcceptedItemType();
try {
State newState = null;
if (typeName != null) {
switch (typeName) {
case CoreItemFactory.SWITCH:
// Guntamatic uses German OnOff when configured to German and English OnOff for
// all other languages
if ("ON".equals(value) || "EIN".equals(value)) {
newState = OnOffType.ON;
} else if ("OFF".equals(value) || "AUS".equals(value)) {
newState = OnOffType.OFF;
}
break;
case CoreItemFactory.NUMBER:
newState = new DecimalType(value);
break;
case NUMBER_DIMENSIONLESS:
case NUMBER_TEMPERATURE:
case NUMBER_VOLUME:
case NUMBER_TIME:
if (unit != null) {
newState = new QuantityType<>(Double.parseDouble(value), unit);
}
break;
case CoreItemFactory.STRING:
newState = new StringType(value);
break;
default:
break;
}
}
if (newState != null) {
updateState(channel, newState);
} else {
logger.warn("Data for unknown typeName '{}' or unknown unit received", typeName);
}
} catch (NumberFormatException e) {
logger.warn("NumberFormatException: {}", ((e.getMessage() != null) ? e.getMessage() : ""));
}
}
} else {
logger.warn("Data for not intialized ChannelId '{}' received", i);
}
}
}
private void parseAndJsonInit(String html) {
try {
// remove non JSON compliant, empty element ",,"
JsonArray json = JsonParser.parseString(html.replace(",,", ",")).getAsJsonArray();
for (int i = 1; i < json.size(); i++) {
JsonObject points = json.get(i).getAsJsonObject();
if (points.has("id") && points.has("type")) {
int id = points.get("id").getAsInt();
String type = points.get("type").getAsString();
types.put(id, type);
}
}
} catch (JsonParseException | IllegalStateException | ClassCastException e) {
logger.warn("Invalid JSON data will be ignored: '{}'", html.replace(",,", ","));
}
}
private void parseAndInit(String html) {
String[] daqdesc = html.split("\\n");
List<Channel> channelList = new ArrayList<>();
for (String channelID : CHANNELIDS) {
Channel channel = thing.getChannel(channelID);
if (channel == null) {
logger.warn("Static Channel '{}' is not present: remove and re-add Thing", channelID);
} else {
channelList.add(channel);
}
}
for (int i = 0; i < daqdesc.length; i++) {
String[] param = daqdesc[i].split(";");
String label = param[0].replace("C02", "CO2");
if (!"reserved".equals(label)) {
String channel = toLowerCamelCase(replaceUmlaut(label));
label = label.substring(0, 1).toUpperCase() + label.substring(1);
String unitStr = ((param.length == 1) || param[1].isBlank()) ? "" : param[1].trim();
Unit<?> unit = guessUnit(unitStr);
boolean channelInitialized = channels.containsValue(channel);
if (!channelInitialized) {
String itemType;
String pattern;
String type = types.get(i);
if (type == null) {
type = "";
}
if ("boolean".equals(type)) {
itemType = CoreItemFactory.SWITCH;
pattern = "";
} else if ("integer".equals(type)) {
itemType = guessItemType(unit);
pattern = "%d";
if (unit != null) {
pattern += " %unit%";
}
} else if ("float".equals(type)) {
itemType = guessItemType(unit);
pattern = "%.2f";
if (unit != null) {
pattern += " %unit%";
}
} else if ("string".equals(type)) {
itemType = CoreItemFactory.STRING;
pattern = "%s";
} else {
if (unitStr.isBlank()) {
itemType = CoreItemFactory.STRING;
pattern = "%s";
} else {
itemType = guessItemType(unit);
pattern = "%.2f";
if (unit != null) {
pattern += " %unit%";
}
}
}
ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, channel);
guntamaticChannelTypeProvider.addChannelType(channelTypeUID, channel, itemType,
"Guntamatic " + label, false, pattern);
Channel newChannel = ChannelBuilder.create(new ChannelUID(thing.getUID(), channel), itemType)
.withType(channelTypeUID).withKind(ChannelKind.STATE).withLabel(label).build();
channelList.add(newChannel);
channels.put(i, channel);
if (unit != null) {
units.put(i, unit);
}
logger.debug(
"Supported Channel: Idx: '{}', Name: '{}'/'{}', Type: '{}'/'{}', Unit: '{}', Pattern '{}' ",
String.format("%03d", i), label, channel, type, itemType, unitStr, pattern);
}
}
}
ThingBuilder thingBuilder = editThing();
thingBuilder.withChannels(channelList);
updateThing(thingBuilder.build());
channelsInitialized = true;
}
private @Nullable Unit<?> guessUnit(String unit) {
Unit<?> finalUnit = MAP_UNIT.get(unit);
if (!unit.isBlank() && (finalUnit == null)) {
logger.warn("Unsupported unit '{}' detected", unit);
}
return finalUnit;
}
private String guessItemType(@Nullable Unit<?> unit) {
String itemType = (unit != null) ? MAP_UNIT_ITEMTYPE.get(unit) : CoreItemFactory.NUMBER;
if (itemType == null) {
itemType = CoreItemFactory.NUMBER;
logger.warn("Unsupported unit '{}' detected: using native '{}' type", unit, itemType);
}
return itemType;
}
private static String replaceUmlaut(String input) {
// replace all lower Umlauts
String output = input.replace("ü", "ue").replace("ö", "oe").replace("ä", "ae").replace("ß", "ss");
// first replace all capital umlaute in a non-capitalized context (e.g. Übung)
output = output.replaceAll("Ü(?=[a-zäöüß ])", "Ue").replaceAll("Ö(?=[a-zäöüß ])", "Oe")
.replaceAll("Ä(?=[a-zäöüß ])", "Ae");
// now replace all the other capital umlaute
output = output.replace("Ü", "UE").replace("Ö", "OE").replace("Ä", "AE");
return output;
}
private String toLowerCamelCase(String input) {
char delimiter = ' ';
String output = input.replace("´", "").replaceAll("[^\\w]", String.valueOf(delimiter));
StringBuilder builder = new StringBuilder();
boolean nextCharLow = true;
for (int i = 0; i < output.length(); i++) {
char currentChar = output.charAt(i);
if (delimiter == currentChar) {
nextCharLow = false;
} else if (nextCharLow) {
builder.append(Character.toLowerCase(currentChar));
} else {
builder.append(Character.toUpperCase(currentChar));
nextCharLow = true;
}
}
return builder.toString();
}
private @Nullable String sendGetRequest(String url, String... params) {
String errorReason = "";
String req = "http://" + config.hostname + url;
if (!config.key.isBlank()) {
req += "?key=" + config.key;
}
for (int i = 0; i < params.length; i++) {
if ((i == 0) && config.key.isBlank()) {
req += "?";
} else {
req += "&";
}
req += params[i];
}
Request request = httpClient.newRequest(req);
request.method(HttpMethod.GET).timeout(30, TimeUnit.SECONDS).header(HttpHeader.ACCEPT_ENCODING, "gzip");
try {
ContentResponse contentResponse = request.send();
if (HttpStatus.OK_200 == contentResponse.getStatus()) {
if (!this.getThing().getStatus().equals(ThingStatus.ONLINE)) {
updateStatus(ThingStatus.ONLINE);
}
try {
String response = new String(contentResponse.getContent(), Charset.forName(config.encoding));
if (url.equals(DAQEXTDESC_URL)) {
parseAndJsonInit(response);
} else if (url.equals(DAQDATA_URL)) {
parseAndUpdate(response);
} else if (url.equals(DAQDESC_URL)) {
parseAndInit(response);
}
// PARSET_URL via return
return response;
} catch (IllegalArgumentException e) {
errorReason = String.format("IllegalArgumentException: %s",
((e.getMessage() != null) ? e.getMessage() : ""));
}
} else {
errorReason = String.format("Guntamatic request failed with %d: %s", contentResponse.getStatus(),
((contentResponse.getReason() != null) ? contentResponse.getReason() : ""));
}
} catch (TimeoutException e) {
errorReason = "TimeoutException: Guntamatic was not reachable on your network";
} catch (ExecutionException e) {
errorReason = String.format("ExecutionException: %s", ((e.getMessage() != null) ? e.getMessage() : ""));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
errorReason = String.format("InterruptedException: %s", ((e.getMessage() != null) ? e.getMessage() : ""));
}
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, errorReason);
return null;
}
private void pollGuntamatic() {
if (!channelsInitialized) {
if (!config.key.isBlank()) {
sendGetRequest(DAQEXTDESC_URL);
}
sendGetRequest(DAQDESC_URL);
} else {
sendGetRequest(DAQDATA_URL);
}
}
@Override
public void initialize() {
config = getConfigAs(GuntamaticConfiguration.class);
if (config.hostname.isBlank()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid hostname configuration");
} else {
updateStatus(ThingStatus.UNKNOWN);
pollingFuture = scheduler.scheduleWithFixedDelay(this::pollGuntamatic, 1, config.refreshInterval,
TimeUnit.SECONDS);
}
}
@Override
public void dispose() {
final ScheduledFuture<?> job = pollingFuture;
if (job != null) {
job.cancel(true);
pollingFuture = null;
}
channelsInitialized = false;
}
}

View File

@@ -0,0 +1,70 @@
/**
* 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.guntamatic.internal;
import static org.openhab.binding.guntamatic.internal.GuntamaticBindingConstants.*;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The {@link GuntamaticHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Weger Michael - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.guntamatic", service = ThingHandlerFactory.class)
public class GuntamaticHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_BIOSTAR, THING_TYPE_POWERCHIP,
THING_TYPE_POWERCORN, THING_TYPE_BIOCOM, THING_TYPE_PRO, THING_TYPE_THERM);
private final HttpClient httpClient;
private GuntamaticChannelTypeProvider guntamaticChannelTypeProvider;
@Activate
public GuntamaticHandlerFactory(@Reference HttpClientFactory httpClientFactory,
@Reference GuntamaticChannelTypeProvider guntamaticChannelTypeProvider) {
this.httpClient = httpClientFactory.getCommonHttpClient();
this.guntamaticChannelTypeProvider = guntamaticChannelTypeProvider;
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (supportsThingType(thingTypeUID)) {
return new GuntamaticHandler(thing, httpClient, guntamaticChannelTypeProvider);
}
return null;
}
}

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="guntamatic" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>Guntamatic Binding</name>
<description>Binding for Guntamatic Heating Systems.</description>
</binding:binding>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<config-description:config-descriptions
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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:guntamatic:heatingsystem">
<parameter name="hostname" type="text" required="true">
<context>network-address</context>
<label>Hostname</label>
<description>Hostname or IP address of the Guntamatic Heating System</description>
</parameter>
<parameter name="key" type="text" required="false">
<context>password</context>
<label>Key</label>
<description>Optional, but required to read protected parameters and to control the Guntamatic Heating System.
The key
needs to be reqested from Guntamatic support.</description>
</parameter>
<parameter name="refreshInterval" type="integer" unit="s" min="1" required="false">
<default>60</default>
<label>Refresh Interval</label>
<description>Interval the Guntamatic Heating System is polled in seconds. Default: 60s</description>
</parameter>
<parameter name="encoding" type="text" required="false">
<default>windows-1252</default>
<label>Encoding</label>
<description>Code page used by the Guntamatic Heating System. Default: 'windows-1252'</description>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@@ -0,0 +1,158 @@
# binding
binding.guntamatic.name = Guntamatic Binding
binding.guntamatic.description = Binding for Guntamatic Heating Systems.
# thing types
thing-type.guntamatic.biocom.label = Guntamatic Biocom
thing-type.guntamatic.biocom.description = Guntamatic Biocom Heating System. Untested! Please provide Feedback!
thing-type.guntamatic.biocom.channel.controlBoilerApproval.label = Set Boiler Approval
thing-type.guntamatic.biocom.channel.controlExtraWwHeat0.label = Trigger Extra Warm Water Circle 0
thing-type.guntamatic.biocom.channel.controlExtraWwHeat1.label = Trigger Extra Warm Water Circle 1
thing-type.guntamatic.biocom.channel.controlExtraWwHeat2.label = Trigger Extra Warm Water Circle 2
thing-type.guntamatic.biocom.channel.controlHeatCircProgram0.label = Set Heat Circle 0 Program
thing-type.guntamatic.biocom.channel.controlHeatCircProgram1.label = Set Heat Circle 1 Program
thing-type.guntamatic.biocom.channel.controlHeatCircProgram2.label = Set Heat Circle 2 Program
thing-type.guntamatic.biocom.channel.controlHeatCircProgram3.label = Set Heat Circle 3 Program
thing-type.guntamatic.biocom.channel.controlHeatCircProgram4.label = Set Heat Circle 4 Program
thing-type.guntamatic.biocom.channel.controlHeatCircProgram5.label = Set Heat Circle 5 Program
thing-type.guntamatic.biocom.channel.controlHeatCircProgram6.label = Set Heat Circle 6 Program
thing-type.guntamatic.biocom.channel.controlHeatCircProgram7.label = Set Heat Circle 7 Program
thing-type.guntamatic.biocom.channel.controlHeatCircProgram8.label = Set Heat Circle 8 Program
thing-type.guntamatic.biocom.channel.controlProgram.label = Set Program
thing-type.guntamatic.biocom.channel.controlWwHeat0.label = Trigger Warm Water Circle 0
thing-type.guntamatic.biocom.channel.controlWwHeat1.label = Trigger Warm Water Circle 1
thing-type.guntamatic.biocom.channel.controlWwHeat2.label = Trigger Warm Water Circle 2
thing-type.guntamatic.biostar.label = Guntamatic Biostar
thing-type.guntamatic.biostar.description = Guntamatic Biostar Heating System
thing-type.guntamatic.biostar.channel.controlBoilerApproval.label = Set Boiler Approval
thing-type.guntamatic.biostar.channel.controlExtraWwHeat0.label = Trigger Extra Warm Water Circle 0
thing-type.guntamatic.biostar.channel.controlExtraWwHeat1.label = Trigger Extra Warm Water Circle 1
thing-type.guntamatic.biostar.channel.controlExtraWwHeat2.label = Trigger Extra Warm Water Circle 2
thing-type.guntamatic.biostar.channel.controlHeatCircProgram0.label = Set Heat Circle 0 Program
thing-type.guntamatic.biostar.channel.controlHeatCircProgram1.label = Set Heat Circle 1 Program
thing-type.guntamatic.biostar.channel.controlHeatCircProgram2.label = Set Heat Circle 2 Program
thing-type.guntamatic.biostar.channel.controlHeatCircProgram3.label = Set Heat Circle 3 Program
thing-type.guntamatic.biostar.channel.controlHeatCircProgram4.label = Set Heat Circle 4 Program
thing-type.guntamatic.biostar.channel.controlHeatCircProgram5.label = Set Heat Circle 5 Program
thing-type.guntamatic.biostar.channel.controlHeatCircProgram6.label = Set Heat Circle 6 Program
thing-type.guntamatic.biostar.channel.controlHeatCircProgram7.label = Set Heat Circle 7 Program
thing-type.guntamatic.biostar.channel.controlHeatCircProgram8.label = Set Heat Circle 8 Program
thing-type.guntamatic.biostar.channel.controlProgram.label = Set Program
thing-type.guntamatic.biostar.channel.controlWwHeat0.label = Trigger Warm Water Circle 0
thing-type.guntamatic.biostar.channel.controlWwHeat1.label = Trigger Warm Water Circle 1
thing-type.guntamatic.biostar.channel.controlWwHeat2.label = Trigger Warm Water Circle 2
thing-type.guntamatic.powerchip.label = Guntamatic Powerchip
thing-type.guntamatic.powerchip.description = Guntamatic Powerchip Heating System. Untested! Please provide Feedback!
thing-type.guntamatic.powerchip.channel.controlBoilerApproval.label = Set Boiler Approval
thing-type.guntamatic.powerchip.channel.controlExtraWwHeat0.label = Trigger Extra Warm Water Circle 0
thing-type.guntamatic.powerchip.channel.controlExtraWwHeat1.label = Trigger Extra Warm Water Circle 1
thing-type.guntamatic.powerchip.channel.controlExtraWwHeat2.label = Trigger Extra Warm Water Circle 2
thing-type.guntamatic.powerchip.channel.controlHeatCircProgram0.label = Set Heat Circle 0 Program
thing-type.guntamatic.powerchip.channel.controlHeatCircProgram1.label = Set Heat Circle 1 Program
thing-type.guntamatic.powerchip.channel.controlHeatCircProgram2.label = Set Heat Circle 2 Program
thing-type.guntamatic.powerchip.channel.controlHeatCircProgram3.label = Set Heat Circle 3 Program
thing-type.guntamatic.powerchip.channel.controlHeatCircProgram4.label = Set Heat Circle 4 Program
thing-type.guntamatic.powerchip.channel.controlHeatCircProgram5.label = Set Heat Circle 5 Program
thing-type.guntamatic.powerchip.channel.controlHeatCircProgram6.label = Set Heat Circle 6 Program
thing-type.guntamatic.powerchip.channel.controlHeatCircProgram7.label = Set Heat Circle 7 Program
thing-type.guntamatic.powerchip.channel.controlHeatCircProgram8.label = Set Heat Circle 8 Program
thing-type.guntamatic.powerchip.channel.controlProgram.label = Set Program
thing-type.guntamatic.powerchip.channel.controlWwHeat0.label = Trigger Warm Water Circle 0
thing-type.guntamatic.powerchip.channel.controlWwHeat1.label = Trigger Warm Water Circle 1
thing-type.guntamatic.powerchip.channel.controlWwHeat2.label = Trigger Warm Water Circle 2
thing-type.guntamatic.powercorn.label = Guntamatic Powercorn
thing-type.guntamatic.powercorn.description = Guntamatic Powercorn Heating System. Untested! Please provide Feedback!
thing-type.guntamatic.powercorn.channel.controlBoilerApproval.label = Set Boiler Approval
thing-type.guntamatic.powercorn.channel.controlExtraWwHeat0.label = Trigger Extra Warm Water Circle 0
thing-type.guntamatic.powercorn.channel.controlExtraWwHeat1.label = Trigger Extra Warm Water Circle 1
thing-type.guntamatic.powercorn.channel.controlExtraWwHeat2.label = Trigger Extra Warm Water Circle 2
thing-type.guntamatic.powercorn.channel.controlHeatCircProgram0.label = Set Heat Circle 0 Program
thing-type.guntamatic.powercorn.channel.controlHeatCircProgram1.label = Set Heat Circle 1 Program
thing-type.guntamatic.powercorn.channel.controlHeatCircProgram2.label = Set Heat Circle 2 Program
thing-type.guntamatic.powercorn.channel.controlHeatCircProgram3.label = Set Heat Circle 3 Program
thing-type.guntamatic.powercorn.channel.controlHeatCircProgram4.label = Set Heat Circle 4 Program
thing-type.guntamatic.powercorn.channel.controlHeatCircProgram5.label = Set Heat Circle 5 Program
thing-type.guntamatic.powercorn.channel.controlHeatCircProgram6.label = Set Heat Circle 6 Program
thing-type.guntamatic.powercorn.channel.controlHeatCircProgram7.label = Set Heat Circle 7 Program
thing-type.guntamatic.powercorn.channel.controlHeatCircProgram8.label = Set Heat Circle 8 Program
thing-type.guntamatic.powercorn.channel.controlProgram.label = Set Program
thing-type.guntamatic.powercorn.channel.controlWwHeat0.label = Trigger Warm Water Circle 0
thing-type.guntamatic.powercorn.channel.controlWwHeat1.label = Trigger Warm Water Circle 1
thing-type.guntamatic.powercorn.channel.controlWwHeat2.label = Trigger Warm Water Circle 2
thing-type.guntamatic.pro.label = Guntamatic Pro
thing-type.guntamatic.pro.description = Guntamatic Pro Heating System. Untested! Please provide Feedback!
thing-type.guntamatic.pro.channel.controlBoilerApproval.label = Set Boiler Approval
thing-type.guntamatic.pro.channel.controlExtraWwHeat0.label = Trigger Extra Warm Water Circle 0
thing-type.guntamatic.pro.channel.controlExtraWwHeat1.label = Trigger Extra Warm Water Circle 1
thing-type.guntamatic.pro.channel.controlExtraWwHeat2.label = Trigger Extra Warm Water Circle 2
thing-type.guntamatic.pro.channel.controlHeatCircProgram0.label = Set Heat Circle 0 Program
thing-type.guntamatic.pro.channel.controlHeatCircProgram1.label = Set Heat Circle 1 Program
thing-type.guntamatic.pro.channel.controlHeatCircProgram2.label = Set Heat Circle 2 Program
thing-type.guntamatic.pro.channel.controlHeatCircProgram3.label = Set Heat Circle 3 Program
thing-type.guntamatic.pro.channel.controlHeatCircProgram4.label = Set Heat Circle 4 Program
thing-type.guntamatic.pro.channel.controlHeatCircProgram5.label = Set Heat Circle 5 Program
thing-type.guntamatic.pro.channel.controlHeatCircProgram6.label = Set Heat Circle 6 Program
thing-type.guntamatic.pro.channel.controlHeatCircProgram7.label = Set Heat Circle 7 Program
thing-type.guntamatic.pro.channel.controlHeatCircProgram8.label = Set Heat Circle 8 Program
thing-type.guntamatic.pro.channel.controlProgram.label = Set Program
thing-type.guntamatic.pro.channel.controlWwHeat0.label = Trigger Warm Water Circle 0
thing-type.guntamatic.pro.channel.controlWwHeat1.label = Trigger Warm Water Circle 1
thing-type.guntamatic.pro.channel.controlWwHeat2.label = Trigger Warm Water Circle 2
thing-type.guntamatic.therm.label = Guntamatic Therm
thing-type.guntamatic.therm.description = Guntamatic Therm Heating System. Untested! Please provide Feedback!
thing-type.guntamatic.therm.channel.controlBoilerApproval.label = Set Boiler Approval
thing-type.guntamatic.therm.channel.controlExtraWwHeat0.label = Trigger Extra Warm Water Circle 0
thing-type.guntamatic.therm.channel.controlExtraWwHeat1.label = Trigger Extra Warm Water Circle 1
thing-type.guntamatic.therm.channel.controlExtraWwHeat2.label = Trigger Extra Warm Water Circle 2
thing-type.guntamatic.therm.channel.controlHeatCircProgram0.label = Set Heat Circle 0 Program
thing-type.guntamatic.therm.channel.controlHeatCircProgram1.label = Set Heat Circle 1 Program
thing-type.guntamatic.therm.channel.controlHeatCircProgram2.label = Set Heat Circle 2 Program
thing-type.guntamatic.therm.channel.controlHeatCircProgram3.label = Set Heat Circle 3 Program
thing-type.guntamatic.therm.channel.controlHeatCircProgram4.label = Set Heat Circle 4 Program
thing-type.guntamatic.therm.channel.controlHeatCircProgram5.label = Set Heat Circle 5 Program
thing-type.guntamatic.therm.channel.controlHeatCircProgram6.label = Set Heat Circle 6 Program
thing-type.guntamatic.therm.channel.controlHeatCircProgram7.label = Set Heat Circle 7 Program
thing-type.guntamatic.therm.channel.controlHeatCircProgram8.label = Set Heat Circle 8 Program
thing-type.guntamatic.therm.channel.controlProgram.label = Set Program
thing-type.guntamatic.therm.channel.controlWwHeat0.label = Trigger Warm Water Circle 0
thing-type.guntamatic.therm.channel.controlWwHeat1.label = Trigger Warm Water Circle 1
thing-type.guntamatic.therm.channel.controlWwHeat2.label = Trigger Warm Water Circle 2
# thing types config
thing-type.config.guntamatic.heatingsystem.encoding.label = Encoding
thing-type.config.guntamatic.heatingsystem.encoding.description = Code page used by the Guntamatic Heating System. Default: 'windows-1252'
thing-type.config.guntamatic.heatingsystem.hostname.label = Hostname
thing-type.config.guntamatic.heatingsystem.hostname.description = Hostname or IP address of the Guntamatic Heating System
thing-type.config.guntamatic.heatingsystem.key.label = Key
thing-type.config.guntamatic.heatingsystem.key.description = Optional, but required to read protected parameters and to control the Guntamatic Heating System. The key needs to be reqested from Guntamatic support.
thing-type.config.guntamatic.heatingsystem.refreshInterval.label = Refresh Interval
thing-type.config.guntamatic.heatingsystem.refreshInterval.description = Interval the Guntamatic Heating System is polled in seconds. Default: 60s
# channel types
channel-type.guntamatic.controlBoilerApproval.label = Set Boiler Approval
channel-type.guntamatic.controlBoilerApproval.description = Set Boiler Approval of the Guntamatic Heating System (AUTO, OFF, ON)
channel-type.guntamatic.controlBoilerApproval.state.option.0 = AUTO
channel-type.guntamatic.controlBoilerApproval.state.option.1 = OFF
channel-type.guntamatic.controlBoilerApproval.state.option.2 = ON
channel-type.guntamatic.controlExtraWwHeat.label = Trigger Extra Warm Water Circle
channel-type.guntamatic.controlExtraWwHeat.description = Trigger Extra Warm Water Circle of the Guntamatic Heating System (RECHARGE)
channel-type.guntamatic.controlExtraWwHeat.state.option.0 = RECHARGE
channel-type.guntamatic.controlHeatCircProgram.label = Set Heat Circle Program
channel-type.guntamatic.controlHeatCircProgram.description = Set Heat Circle of the Guntamatic Heating System (OFF, NORMAL, HEAT, LOWER)
channel-type.guntamatic.controlHeatCircProgram.state.option.0 = OFF
channel-type.guntamatic.controlHeatCircProgram.state.option.1 = NORMAL
channel-type.guntamatic.controlHeatCircProgram.state.option.2 = HEAT
channel-type.guntamatic.controlHeatCircProgram.state.option.3 = LOWER
channel-type.guntamatic.controlProgram.label = Set Program
channel-type.guntamatic.controlProgram.description = Set Program of the Guntamatic Heating System (OFF, NORMAL, WARMWATER, MANUAL)
channel-type.guntamatic.controlProgram.state.option.0 = OFF
channel-type.guntamatic.controlProgram.state.option.1 = NORMAL
channel-type.guntamatic.controlProgram.state.option.2 = WARMWATER
channel-type.guntamatic.controlProgram.state.option.8 = MANUAL
channel-type.guntamatic.controlWwHeat.label = Trigger Warm Water Circle
channel-type.guntamatic.controlWwHeat.description = Trigger Warm Water Circle of the Guntamatic Heating System (RECHARGE)
channel-type.guntamatic.controlWwHeat.state.option.0 = RECHARGE

View File

@@ -0,0 +1,470 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="guntamatic"
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="biostar">
<label>Guntamatic Biostar</label>
<description>Guntamatic Biostar Heating System</description>
<channels>
<channel id="controlBoilerApproval" typeId="controlBoilerApproval">
<label>Set Boiler Approval</label>
</channel>
<channel id="controlProgram" typeId="controlProgram">
<label>Set Program</label>
</channel>
<channel id="controlHeatCircProgram0" typeId="controlHeatCircProgram">
<label>Set Heat Circle 0 Program</label>
</channel>
<channel id="controlHeatCircProgram1" typeId="controlHeatCircProgram">
<label>Set Heat Circle 1 Program</label>
</channel>
<channel id="controlHeatCircProgram2" typeId="controlHeatCircProgram">
<label>Set Heat Circle 2 Program</label>
</channel>
<channel id="controlHeatCircProgram3" typeId="controlHeatCircProgram">
<label>Set Heat Circle 3 Program</label>
</channel>
<channel id="controlHeatCircProgram4" typeId="controlHeatCircProgram">
<label>Set Heat Circle 4 Program</label>
</channel>
<channel id="controlHeatCircProgram5" typeId="controlHeatCircProgram">
<label>Set Heat Circle 5 Program</label>
</channel>
<channel id="controlHeatCircProgram6" typeId="controlHeatCircProgram">
<label>Set Heat Circle 6 Program</label>
</channel>
<channel id="controlHeatCircProgram7" typeId="controlHeatCircProgram">
<label>Set Heat Circle 7 Program</label>
</channel>
<channel id="controlHeatCircProgram8" typeId="controlHeatCircProgram">
<label>Set Heat Circle 8 Program</label>
</channel>
<channel id="controlWwHeat0" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 0</label>
</channel>
<channel id="controlWwHeat1" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 1</label>
</channel>
<channel id="controlWwHeat2" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 2</label>
</channel>
<channel id="controlExtraWwHeat0" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 0</label>
</channel>
<channel id="controlExtraWwHeat1" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 1</label>
</channel>
<channel id="controlExtraWwHeat2" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 2</label>
</channel>
</channels>
<properties>
<property name="boilerApproval">K0010</property>
<property name="program">PR001</property>
<property name="heatCircProgram">HKx01</property>
<property name="wwHeat">BKx06</property>
<property name="extraWwHeat">ZKx06</property>
</properties>
<config-description-ref uri="thing-type:guntamatic:heatingsystem"/>
</thing-type>
<thing-type id="powerchip">
<label>Guntamatic Powerchip</label>
<description>Guntamatic Powerchip Heating System. Untested! Please provide Feedback!</description>
<channels>
<channel id="controlBoilerApproval" typeId="controlBoilerApproval">
<label>Set Boiler Approval</label>
</channel>
<channel id="controlProgram" typeId="controlProgram">
<label>Set Program</label>
</channel>
<channel id="controlHeatCircProgram0" typeId="controlHeatCircProgram">
<label>Set Heat Circle 0 Program</label>
</channel>
<channel id="controlHeatCircProgram1" typeId="controlHeatCircProgram">
<label>Set Heat Circle 1 Program</label>
</channel>
<channel id="controlHeatCircProgram2" typeId="controlHeatCircProgram">
<label>Set Heat Circle 2 Program</label>
</channel>
<channel id="controlHeatCircProgram3" typeId="controlHeatCircProgram">
<label>Set Heat Circle 3 Program</label>
</channel>
<channel id="controlHeatCircProgram4" typeId="controlHeatCircProgram">
<label>Set Heat Circle 4 Program</label>
</channel>
<channel id="controlHeatCircProgram5" typeId="controlHeatCircProgram">
<label>Set Heat Circle 5 Program</label>
</channel>
<channel id="controlHeatCircProgram6" typeId="controlHeatCircProgram">
<label>Set Heat Circle 6 Program</label>
</channel>
<channel id="controlHeatCircProgram7" typeId="controlHeatCircProgram">
<label>Set Heat Circle 7 Program</label>
</channel>
<channel id="controlHeatCircProgram8" typeId="controlHeatCircProgram">
<label>Set Heat Circle 8 Program</label>
</channel>
<channel id="controlWwHeat0" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 0</label>
</channel>
<channel id="controlWwHeat1" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 1</label>
</channel>
<channel id="controlWwHeat2" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 2</label>
</channel>
<channel id="controlExtraWwHeat0" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 0</label>
</channel>
<channel id="controlExtraWwHeat1" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 1</label>
</channel>
<channel id="controlExtraWwHeat2" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 2</label>
</channel>
</channels>
<properties>
<property name="boilerApproval">PK002</property>
<property name="program">PR001</property>
<property name="heatCircProgram">HKx01</property>
<property name="wwHeat">BKx06</property>
<property name="extraWwHeat">ZKx06</property>
</properties>
<config-description-ref uri="thing-type:guntamatic:heatingsystem"/>
</thing-type>
<thing-type id="powercorn">
<label>Guntamatic Powercorn</label>
<description>Guntamatic Powercorn Heating System. Untested! Please provide Feedback!</description>
<channels>
<channel id="controlBoilerApproval" typeId="controlBoilerApproval">
<label>Set Boiler Approval</label>
</channel>
<channel id="controlProgram" typeId="controlProgram">
<label>Set Program</label>
</channel>
<channel id="controlHeatCircProgram0" typeId="controlHeatCircProgram">
<label>Set Heat Circle 0 Program</label>
</channel>
<channel id="controlHeatCircProgram1" typeId="controlHeatCircProgram">
<label>Set Heat Circle 1 Program</label>
</channel>
<channel id="controlHeatCircProgram2" typeId="controlHeatCircProgram">
<label>Set Heat Circle 2 Program</label>
</channel>
<channel id="controlHeatCircProgram3" typeId="controlHeatCircProgram">
<label>Set Heat Circle 3 Program</label>
</channel>
<channel id="controlHeatCircProgram4" typeId="controlHeatCircProgram">
<label>Set Heat Circle 4 Program</label>
</channel>
<channel id="controlHeatCircProgram5" typeId="controlHeatCircProgram">
<label>Set Heat Circle 5 Program</label>
</channel>
<channel id="controlHeatCircProgram6" typeId="controlHeatCircProgram">
<label>Set Heat Circle 6 Program</label>
</channel>
<channel id="controlHeatCircProgram7" typeId="controlHeatCircProgram">
<label>Set Heat Circle 7 Program</label>
</channel>
<channel id="controlHeatCircProgram8" typeId="controlHeatCircProgram">
<label>Set Heat Circle 8 Program</label>
</channel>
<channel id="controlWwHeat0" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 0</label>
</channel>
<channel id="controlWwHeat1" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 1</label>
</channel>
<channel id="controlWwHeat2" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 2</label>
</channel>
<channel id="controlExtraWwHeat0" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 0</label>
</channel>
<channel id="controlExtraWwHeat1" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 1</label>
</channel>
<channel id="controlExtraWwHeat2" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 2</label>
</channel>
</channels>
<properties>
<property name="boilerApproval">PK002</property>
<property name="program">PR001</property>
<property name="heatCircProgram">HKx01</property>
<property name="wwHeat">BKx06</property>
<property name="extraWwHeat">ZKx06</property>
</properties>
<config-description-ref uri="thing-type:guntamatic:heatingsystem"/>
</thing-type>
<thing-type id="biocom">
<label>Guntamatic Biocom</label>
<description>Guntamatic Biocom Heating System. Untested! Please provide Feedback!</description>
<channels>
<channel id="controlBoilerApproval" typeId="controlBoilerApproval">
<label>Set Boiler Approval</label>
</channel>
<channel id="controlProgram" typeId="controlProgram">
<label>Set Program</label>
</channel>
<channel id="controlHeatCircProgram0" typeId="controlHeatCircProgram">
<label>Set Heat Circle 0 Program</label>
</channel>
<channel id="controlHeatCircProgram1" typeId="controlHeatCircProgram">
<label>Set Heat Circle 1 Program</label>
</channel>
<channel id="controlHeatCircProgram2" typeId="controlHeatCircProgram">
<label>Set Heat Circle 2 Program</label>
</channel>
<channel id="controlHeatCircProgram3" typeId="controlHeatCircProgram">
<label>Set Heat Circle 3 Program</label>
</channel>
<channel id="controlHeatCircProgram4" typeId="controlHeatCircProgram">
<label>Set Heat Circle 4 Program</label>
</channel>
<channel id="controlHeatCircProgram5" typeId="controlHeatCircProgram">
<label>Set Heat Circle 5 Program</label>
</channel>
<channel id="controlHeatCircProgram6" typeId="controlHeatCircProgram">
<label>Set Heat Circle 6 Program</label>
</channel>
<channel id="controlHeatCircProgram7" typeId="controlHeatCircProgram">
<label>Set Heat Circle 7 Program</label>
</channel>
<channel id="controlHeatCircProgram8" typeId="controlHeatCircProgram">
<label>Set Heat Circle 8 Program</label>
</channel>
<channel id="controlWwHeat0" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 0</label>
</channel>
<channel id="controlWwHeat1" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 1</label>
</channel>
<channel id="controlWwHeat2" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 2</label>
</channel>
<channel id="controlExtraWwHeat0" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 0</label>
</channel>
<channel id="controlExtraWwHeat1" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 1</label>
</channel>
<channel id="controlExtraWwHeat2" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 2</label>
</channel>
</channels>
<properties>
<property name="boilerApproval">PK002</property>
<property name="program">PR001</property>
<property name="heatCircProgram">HKx01</property>
<property name="wwHeat">BKx06</property>
<property name="extraWwHeat">ZKx06</property>
</properties>
<config-description-ref uri="thing-type:guntamatic:heatingsystem"/>
</thing-type>
<thing-type id="pro">
<label>Guntamatic Pro</label>
<description>Guntamatic Pro Heating System. Untested! Please provide Feedback!</description>
<channels>
<channel id="controlBoilerApproval" typeId="controlBoilerApproval">
<label>Set Boiler Approval</label>
</channel>
<channel id="controlProgram" typeId="controlProgram">
<label>Set Program</label>
</channel>
<channel id="controlHeatCircProgram0" typeId="controlHeatCircProgram">
<label>Set Heat Circle 0 Program</label>
</channel>
<channel id="controlHeatCircProgram1" typeId="controlHeatCircProgram">
<label>Set Heat Circle 1 Program</label>
</channel>
<channel id="controlHeatCircProgram2" typeId="controlHeatCircProgram">
<label>Set Heat Circle 2 Program</label>
</channel>
<channel id="controlHeatCircProgram3" typeId="controlHeatCircProgram">
<label>Set Heat Circle 3 Program</label>
</channel>
<channel id="controlHeatCircProgram4" typeId="controlHeatCircProgram">
<label>Set Heat Circle 4 Program</label>
</channel>
<channel id="controlHeatCircProgram5" typeId="controlHeatCircProgram">
<label>Set Heat Circle 5 Program</label>
</channel>
<channel id="controlHeatCircProgram6" typeId="controlHeatCircProgram">
<label>Set Heat Circle 6 Program</label>
</channel>
<channel id="controlHeatCircProgram7" typeId="controlHeatCircProgram">
<label>Set Heat Circle 7 Program</label>
</channel>
<channel id="controlHeatCircProgram8" typeId="controlHeatCircProgram">
<label>Set Heat Circle 8 Program</label>
</channel>
<channel id="controlWwHeat0" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 0</label>
</channel>
<channel id="controlWwHeat1" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 1</label>
</channel>
<channel id="controlWwHeat2" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 2</label>
</channel>
<channel id="controlExtraWwHeat0" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 0</label>
</channel>
<channel id="controlExtraWwHeat1" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 1</label>
</channel>
<channel id="controlExtraWwHeat2" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 2</label>
</channel>
</channels>
<properties>
<property name="boilerApproval">PK002</property>
<property name="program">PR001</property>
<property name="heatCircProgram">HKx01</property>
<property name="wwHeat">BKx06</property>
<property name="extraWwHeat">ZKx06</property>
</properties>
<config-description-ref uri="thing-type:guntamatic:heatingsystem"/>
</thing-type>
<thing-type id="therm">
<label>Guntamatic Therm</label>
<description>Guntamatic Therm Heating System. Untested! Please provide Feedback!</description>
<channels>
<channel id="controlBoilerApproval" typeId="controlBoilerApproval">
<label>Set Boiler Approval</label>
</channel>
<channel id="controlProgram" typeId="controlProgram">
<label>Set Program</label>
</channel>
<channel id="controlHeatCircProgram0" typeId="controlHeatCircProgram">
<label>Set Heat Circle 0 Program</label>
</channel>
<channel id="controlHeatCircProgram1" typeId="controlHeatCircProgram">
<label>Set Heat Circle 1 Program</label>
</channel>
<channel id="controlHeatCircProgram2" typeId="controlHeatCircProgram">
<label>Set Heat Circle 2 Program</label>
</channel>
<channel id="controlHeatCircProgram3" typeId="controlHeatCircProgram">
<label>Set Heat Circle 3 Program</label>
</channel>
<channel id="controlHeatCircProgram4" typeId="controlHeatCircProgram">
<label>Set Heat Circle 4 Program</label>
</channel>
<channel id="controlHeatCircProgram5" typeId="controlHeatCircProgram">
<label>Set Heat Circle 5 Program</label>
</channel>
<channel id="controlHeatCircProgram6" typeId="controlHeatCircProgram">
<label>Set Heat Circle 6 Program</label>
</channel>
<channel id="controlHeatCircProgram7" typeId="controlHeatCircProgram">
<label>Set Heat Circle 7 Program</label>
</channel>
<channel id="controlHeatCircProgram8" typeId="controlHeatCircProgram">
<label>Set Heat Circle 8 Program</label>
</channel>
<channel id="controlWwHeat0" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 0</label>
</channel>
<channel id="controlWwHeat1" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 1</label>
</channel>
<channel id="controlWwHeat2" typeId="controlWwHeat">
<label>Trigger Warm Water Circle 2</label>
</channel>
<channel id="controlExtraWwHeat0" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 0</label>
</channel>
<channel id="controlExtraWwHeat1" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 1</label>
</channel>
<channel id="controlExtraWwHeat2" typeId="controlExtraWwHeat">
<label>Trigger Extra Warm Water Circle 2</label>
</channel>
</channels>
<properties>
<property name="boilerApproval">K0010</property>
<property name="program">PR001</property>
<property name="heatCircProgram">HKx01</property>
<property name="wwHeat">BKx06</property>
<property name="extraWwHeat">ZKx06</property>
</properties>
<config-description-ref uri="thing-type:guntamatic:heatingsystem"/>
</thing-type>
<channel-type id="controlProgram" advanced="false">
<item-type>String</item-type>
<label>Set Program</label>
<description>Set Program of the Guntamatic Heating System (OFF, NORMAL, WARMWATER, MANUAL)</description>
<state>
<options>
<option value="0">OFF</option>
<option value="1">NORMAL</option>
<option value="2">WARMWATER</option>
<option value="8">MANUAL</option>
</options>
</state>
</channel-type>
<channel-type id="controlBoilerApproval" advanced="true">
<item-type>String</item-type>
<label>Set Boiler Approval</label>
<description>Set Boiler Approval of the Guntamatic Heating System (AUTO, OFF, ON)</description>
<state>
<options>
<option value="0">AUTO</option>
<option value="1">OFF</option>
<option value="2">ON</option>
</options>
</state>
</channel-type>
<channel-type id="controlHeatCircProgram" advanced="true">
<item-type>String</item-type>
<label>Set Heat Circle Program</label>
<description>Set Heat Circle of the Guntamatic Heating System (OFF, NORMAL, HEAT, LOWER)</description>
<state>
<options>
<option value="0">OFF</option>
<option value="1">NORMAL</option>
<option value="2">HEAT</option>
<option value="3">LOWER</option>
</options>
</state>
</channel-type>
<channel-type id="controlWwHeat" advanced="true">
<item-type>String</item-type>
<label>Trigger Warm Water Circle</label>
<description>Trigger Warm Water Circle of the Guntamatic Heating System (RECHARGE)</description>
<state>
<options>
<option value="0">RECHARGE</option>
</options>
</state>
</channel-type>
<channel-type id="controlExtraWwHeat" advanced="true">
<item-type>String</item-type>
<label>Trigger Extra Warm Water Circle</label>
<description>Trigger Extra Warm Water Circle of the Guntamatic Heating System (RECHARGE)</description>
<state>
<options>
<option value="0">RECHARGE</option>
</options>
</state>
</channel-type>
</thing:thing-descriptions>