added migrated 2.x add-ons

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

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.nibeuplink-${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-nibeuplink" description="NibeUplink Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.nibeuplink/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* trait class which contains useful helper methods. Thus, the interface can be implemented and methods are available
* within the class.
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public interface AtomicReferenceTrait {
/**
* this should usually not called directly. use updateJobReference or cancelJobReference instead
*
* @param job job to cancel.
*/
default void cancelJob(@Nullable Future<?> job) {
if (job != null) {
job.cancel(true);
}
}
/**
* updates a job reference with a new job. the old job will be cancelled if there is one.
*
* @param jobReference reference to be updated
* @param newJob job to be assigned
*/
default void updateJobReference(AtomicReference<@Nullable Future<?>> jobReference, Future<?> newJob) {
cancelJob(jobReference.getAndSet(newJob));
}
/**
* updates a job reference to null and cancels any existing job which might be assigned to the reference.
*
* @param jobReference to be updated to null.
*/
default void cancelJobReference(AtomicReference<@Nullable Future<?>> jobReference) {
cancelJob(jobReference.getAndSet(null));
}
}

View File

@@ -0,0 +1,115 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link NibeUplinkBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public final class NibeUplinkBindingConstants {
private static final String BINDING_ID = "nibeuplink";
// List of main device types
public static final String DEVICE_VVM320 = "vvm320";
public static final String DEVICE_VVM310 = "vvm310";
public static final String DEVICE_F730 = "f730";
public static final String DEVICE_F750 = "f750";
public static final String DEVICE_F1145 = "f1145";
public static final String DEVICE_F1155 = "f1155";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_VVM320 = new ThingTypeUID(BINDING_ID, DEVICE_VVM320);
public static final ThingTypeUID THING_TYPE_VVM310 = new ThingTypeUID(BINDING_ID, DEVICE_VVM310);
public static final ThingTypeUID THING_TYPE_F730 = new ThingTypeUID(BINDING_ID, DEVICE_F730);
public static final ThingTypeUID THING_TYPE_F750 = new ThingTypeUID(BINDING_ID, DEVICE_F750);
public static final ThingTypeUID THING_TYPE_F1145 = new ThingTypeUID(BINDING_ID, DEVICE_F1145);
public static final ThingTypeUID THING_TYPE_F1155 = new ThingTypeUID(BINDING_ID, DEVICE_F1155);
public static final String VALID_CHANNEL_ID_REGEX = "[1-5][0-9][0-9][0-9][0-9]";
public static final String PARAMETER_NAME_WRITE_API_URL = "writeApiUrl";
public static final String PARAMETER_NAME_VALIDATION_REGEXP = "validationExpression";
public static final String PARAMETER_NAME_OFF_MAPPING = "offMapping";
public static final String PARAMETER_NAME_ON_MAPPING = "onMapping";
// List of all channel types
public static final String CHANNEL_TYPE_NUMBER_UNSCALED = "type-number-unscaled";
public static final String CHANNEL_TYPE_NUMBER_SCALE10 = "type-number-scale10";
public static final String CHANNEL_TYPE_NUMBER_SCALE100 = "type-number-scale100";
public static final String CHANNEL_TYPE_TEMPERATURE = "type-temperature";
public static final String CHANNEL_TYPE_SWITCH = "type-switch";
public static final String CHANNEL_TYPE_POWER = "type-power";
public static final String CHANNEL_TYPE_ENERGY = "type-energy";
public static final String CHANNEL_TYPE_ELECTRIC_CURRENT = "type-electric-current";
public static final String CHANNEL_TYPE_TIME_UNSCALED = "type-time-unscaled";
public static final String CHANNEL_TYPE_TIME_SCALE10 = "type-time-scale10";
public static final String CHANNEL_TYPE_FREQUENCY_UNSCALED = "type-frequency-unscaled";
public static final String CHANNEL_TYPE_FREQUENCY_SCALE10 = "type-frequency-scale10";
public static final String CHANNEL_TYPE_FLOW = "type-flow";
public static final String CHANNEL_TYPE_SPEED = "type-speed-percent";
public static final String CHANNEL_TYPE_DEFROSTING_STATE = "type-defrosting-state";
public static final String CHANNEL_TYPE_HPAC_STATE = "type-hpac-state";
public static final String CHANNEL_TYPE_PRESSURE = "type-pressure";
public static final String RW_CHANNEL_PREFIX = "rw";
public static final String CHANNEL_TYPE_HEAT_OFFSET_RW = "rwtype-heat-offset";
public static final String CHANNEL_TYPE_START_COOLING_RW = "rwtype-start-cooling";
public static final String CHANNEL_TYPE_STOP_HEATING_RW = "rwtype-stop-heating";
public static final String CHANNEL_TYPE_STOP_ADD_HEATING_RW = "rwtype-stop-add-heating";
public static final String CHANNEL_TYPE_FILTER_TIME_RW = "rwtype-filter-time";
public static final String CHANNEL_TYPE_ROOM_SENSOR_FACTOR_RW = "rwtype-room-sensor-factor";
public static final String CHANNEL_TYPE_SWITCH_RW = "rwtype-switch";
public static final String CHANNEL_TYPE_DEGREE_MINUTES_RW = "rwtype-degree-minutes";
public static final String CHANNEL_TYPE_HW_LUX_RW = "rwtype-hw-lux";
public static final String CHANNEL_TYPE_HW_MODE_RW = "rwtype-hw-mode";
public static final String CHANNEL_TYPE_FAN_SPEED_RW = "rwtype-fan-speed";
// URLs
public static final String LOGIN_URL = "https://www.nibeuplink.com/LogIn";
public static final String DATA_API_URL = "https://www.nibeuplink.com/PrivateAPI/QueueValues";
public static final String MANAGE_API_BASE_URL = "https://www.nibeuplink.com/System/";
// login field names
public static final String LOGIN_FIELD_PASSWORD = "Password";
public static final String LOGIN_FIELD_EMAIL = "Email";
public static final String LOGIN_FIELD_RETURN_URL = "returnUrl";
// other field names
public static final String DATA_API_FIELD_LAST_DATE = "currentWebDate";
public static final String DATA_API_FIELD_LAST_DATE_DEFAULT_VALUE = "01.01.2017 13:37:42";
public static final String DATA_API_FIELD_ID = "hpid";
public static final String DATA_API_FIELD_DATA = "variables";
public static final String DATA_API_FIELD_DATA_DEFAULT_VALUE = "0";
// web request constants
public static final long WEB_REQUEST_INITIAL_DELAY = TimeUnit.SECONDS.toMillis(30);
public static final long WEB_REQUEST_INTERVAL = TimeUnit.SECONDS.toMillis(5);
public static final int WEB_REQUEST_QUEUE_MAX_SIZE = 20;
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(THING_TYPE_VVM320, THING_TYPE_VVM310, THING_TYPE_F730, THING_TYPE_F750,
THING_TYPE_F1145, THING_TYPE_F1155).collect(Collectors.toSet()));
}

View File

@@ -0,0 +1,71 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal;
import static org.openhab.binding.nibeuplink.internal.NibeUplinkBindingConstants.SUPPORTED_THING_TYPES_UIDS;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.nibeuplink.internal.handler.GenericHandler;
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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link NibeUplinkHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Alexander Friese - initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.nibeuplink")
@NonNullByDefault
public class NibeUplinkHandlerFactory extends BaseThingHandlerFactory {
private final Logger logger = LoggerFactory.getLogger(NibeUplinkHandlerFactory.class);
/**
* the shared http client
*/
private final HttpClient httpClient;
@Activate
public NibeUplinkHandlerFactory(@Reference HttpClientFactory httpClientFactory) {
this.httpClient = httpClientFactory.getCommonHttpClient();
}
@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 GenericHandler(thing, httpClient);
} else {
logger.warn("Unsupported Thing-Type: {}", thingTypeUID.getAsString());
}
return null;
}
}

View File

@@ -0,0 +1,178 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.callback;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpStatus.Code;
import org.openhab.binding.nibeuplink.internal.command.NibeUplinkCommand;
import org.openhab.binding.nibeuplink.internal.config.NibeUplinkConfiguration;
import org.openhab.binding.nibeuplink.internal.connector.CommunicationStatus;
import org.openhab.binding.nibeuplink.internal.connector.StatusUpdateListener;
import org.openhab.binding.nibeuplink.internal.model.GenericDataResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
/**
* base class for all commands. common logic should be implemented here
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public abstract class AbstractUplinkCommandCallback extends BufferingResponseListener implements NibeUplinkCommand {
/**
* logger
*/
protected final Logger logger = LoggerFactory.getLogger(AbstractUplinkCommandCallback.class);
/**
* the configuration
*/
protected final NibeUplinkConfiguration config;
/**
* status code of fulfilled request
*/
private CommunicationStatus communicationStatus;
/**
* listener to provide updates to the WebInterface class
*/
private @Nullable StatusUpdateListener listener;
/**
* JSON deserializer
*/
private final Gson gson;
/**
* the constructor
*
* @param config
*/
public AbstractUplinkCommandCallback(NibeUplinkConfiguration config) {
this.communicationStatus = new CommunicationStatus();
this.config = config;
this.gson = new Gson();
}
/**
* the constructor
*
* @param config
*/
public AbstractUplinkCommandCallback(NibeUplinkConfiguration config, StatusUpdateListener listener) {
this(config);
this.listener = listener;
}
/**
* Log request success
*/
@Override
public final void onSuccess(@Nullable Response response) {
super.onSuccess(response);
if (response != null) {
communicationStatus.setHttpCode(HttpStatus.getCode(response.getStatus()));
logger.debug("HTTP response {}", response.getStatus());
}
}
/**
* Log request failure
*/
@Override
public final void onFailure(@Nullable Response response, @Nullable Throwable failure) {
super.onFailure(response, failure);
if (failure != null) {
logger.debug("Request failed: {}", failure.toString());
communicationStatus.setError((Exception) failure);
if (failure instanceof SocketTimeoutException || failure instanceof TimeoutException) {
communicationStatus.setHttpCode(Code.REQUEST_TIMEOUT);
} else if (failure instanceof UnknownHostException) {
communicationStatus.setHttpCode(Code.BAD_GATEWAY);
} else {
communicationStatus.setHttpCode(Code.INTERNAL_SERVER_ERROR);
}
}
}
@Override
public void onContent(@Nullable Response response, @Nullable ByteBuffer content) {
super.onContent(response, content);
logger.debug("received content, length: {}", getContentAsString().length());
}
@Override
public void performAction(HttpClient asyncclient) {
Request request = asyncclient.newRequest(getURL()).timeout(config.getAsyncTimeout(), TimeUnit.SECONDS);
prepareRequest(request).send(this);
}
/**
* @Nullable wrapper of gson which does not 'understand' nonnull annotations
*
* @param json
* @return
*/
protected @Nullable GenericDataResponse fromJson(String json) {
// gson is not able to handle @NonNull annotation, thus the return value can be null.
return gson.fromJson(json, GenericDataResponse.class);
}
/**
* returns Http Status Code
*/
public CommunicationStatus getCommunicationStatus() {
return communicationStatus;
}
/**
* concrete implementation has to prepare the requests with additional parameters, etc
*
* @return
*/
protected abstract Request prepareRequest(Request requestToPrepare);
/**
* concrete implementation has to provide the URL
*
* @return
*/
protected abstract String getURL();
@Override
public final @Nullable StatusUpdateListener getListener() {
return listener;
}
@Override
public final void setListener(StatusUpdateListener listener) {
this.listener = listener;
}
}

View File

@@ -0,0 +1,102 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.command;
import static org.openhab.binding.nibeuplink.internal.NibeUplinkBindingConstants.*;
import java.nio.charset.StandardCharsets;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.FormContentProvider;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.Fields;
import org.openhab.binding.nibeuplink.internal.callback.AbstractUplinkCommandCallback;
import org.openhab.binding.nibeuplink.internal.connector.StatusUpdateListener;
import org.openhab.binding.nibeuplink.internal.handler.NibeUplinkHandler;
import org.openhab.binding.nibeuplink.internal.model.DataResponse;
import org.openhab.binding.nibeuplink.internal.model.DataResponseTransformer;
import org.openhab.core.thing.Channel;
/**
* generic command that retrieves status values for all channels defined in {@link VVM320Channels}
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public class GenericStatusUpdate extends AbstractUplinkCommandCallback implements NibeUplinkCommand {
private final NibeUplinkHandler handler;
private final DataResponseTransformer transformer;
private int retries = 0;
public GenericStatusUpdate(NibeUplinkHandler handler) {
super(handler.getConfiguration());
this.handler = handler;
this.transformer = new DataResponseTransformer(handler);
}
@Override
protected Request prepareRequest(Request requestToPrepare) {
Fields fields = new Fields();
fields.add(DATA_API_FIELD_LAST_DATE, DATA_API_FIELD_LAST_DATE_DEFAULT_VALUE);
fields.add(DATA_API_FIELD_ID, config.getNibeId());
for (Channel channel : handler.getChannels()) {
if (!handler.getDeadChannels().contains(channel)) {
fields.add(DATA_API_FIELD_DATA, channel.getUID().getIdWithoutGroup());
}
}
fields.add(DATA_API_FIELD_DATA, DATA_API_FIELD_DATA_DEFAULT_VALUE);
FormContentProvider cp = new FormContentProvider(fields);
requestToPrepare.header(HttpHeader.ACCEPT, "application/json");
requestToPrepare.header(HttpHeader.ACCEPT_ENCODING, StandardCharsets.UTF_8.name());
requestToPrepare.content(cp);
requestToPrepare.followRedirects(false);
requestToPrepare.method(HttpMethod.POST);
return requestToPrepare;
}
@Override
protected String getURL() {
return DATA_API_URL;
}
@Override
public void onComplete(@Nullable Result result) {
logger.debug("onComplete()");
if (!HttpStatus.Code.OK.equals(getCommunicationStatus().getHttpCode()) && retries++ < MAX_RETRIES) {
StatusUpdateListener listener = getListener();
if (listener != null) {
listener.update(getCommunicationStatus());
}
handler.getWebInterface().enqueueCommand(this);
} else {
String json = getContentAsString(StandardCharsets.UTF_8);
if (json != null && !json.isEmpty()) {
logger.debug("JSON String: {}", json);
DataResponse jsonObject = fromJson(json);
if (jsonObject != null) {
handler.updateChannelStatus(transformer.transform(jsonObject));
}
}
}
}
}

View File

@@ -0,0 +1,67 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.command;
import static org.openhab.binding.nibeuplink.internal.NibeUplinkBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.FormContentProvider;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.util.Fields;
import org.openhab.binding.nibeuplink.internal.callback.AbstractUplinkCommandCallback;
import org.openhab.binding.nibeuplink.internal.connector.StatusUpdateListener;
import org.openhab.binding.nibeuplink.internal.handler.NibeUplinkHandler;
/**
* implements the login to the webinterface
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public class Login extends AbstractUplinkCommandCallback implements NibeUplinkCommand {
public Login(NibeUplinkHandler handler, StatusUpdateListener listener) {
super(handler.getConfiguration(), listener);
}
@Override
protected Request prepareRequest(Request requestToPrepare) {
Fields fields = new Fields();
fields.add(LOGIN_FIELD_EMAIL, config.getUser());
fields.add(LOGIN_FIELD_PASSWORD, config.getPassword());
fields.add(LOGIN_FIELD_RETURN_URL, "");
FormContentProvider cp = new FormContentProvider(fields);
requestToPrepare.content(cp);
requestToPrepare.followRedirects(false);
requestToPrepare.method(HttpMethod.POST);
return requestToPrepare;
}
@Override
protected String getURL() {
return LOGIN_URL;
}
@Override
public void onComplete(@Nullable Result result) {
StatusUpdateListener listener = getListener();
if (listener != null) {
listener.update(getCommunicationStatus());
}
}
}

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.command;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Response.CompleteListener;
import org.eclipse.jetty.client.api.Response.ContentListener;
import org.eclipse.jetty.client.api.Response.FailureListener;
import org.eclipse.jetty.client.api.Response.SuccessListener;
import org.openhab.binding.nibeuplink.internal.connector.StatusUpdateListener;
/**
* public interface for all commands
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public interface NibeUplinkCommand extends SuccessListener, FailureListener, ContentListener, CompleteListener {
public static int MAX_RETRIES = 5;
/**
* this method is to be called by the UplinkWebinterface class
*
* @param asyncclient client which will handle the command
*/
void performAction(HttpClient asyncclient);
/**
* get the current listener
*
* @return instance of the listener, might be null.
*/
@Nullable
StatusUpdateListener getListener();
/**
* register a listener
*
* @param listener the listener to be registered.
*/
void setListener(StatusUpdateListener listener);
}

View File

@@ -0,0 +1,121 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.command;
import java.nio.charset.StandardCharsets;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.FormContentProvider;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.Fields;
import org.openhab.binding.nibeuplink.internal.NibeUplinkBindingConstants;
import org.openhab.binding.nibeuplink.internal.callback.AbstractUplinkCommandCallback;
import org.openhab.binding.nibeuplink.internal.handler.ChannelUtil;
import org.openhab.binding.nibeuplink.internal.handler.NibeUplinkHandler;
import org.openhab.binding.nibeuplink.internal.model.ValidationException;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.Command;
/**
* allows update of writable channels
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public class UpdateSetting extends AbstractUplinkCommandCallback implements NibeUplinkCommand {
private final NibeUplinkHandler handler;
private final Channel channel;
private String value;
private int retries = 0;
public UpdateSetting(NibeUplinkHandler handler, Channel channel, Command command) {
super(handler.getConfiguration());
this.handler = handler;
this.channel = channel;
this.value = extractValue(command);
}
private String extractValue(Command command) {
// this is necessary because we must not send the unit to the nibe backend
if (command instanceof QuantityType<?>) {
return String.valueOf(((QuantityType<?>) command).doubleValue());
} else if (command instanceof OnOffType) {
return ChannelUtil.mapValue(channel, (OnOffType) command);
} else {
return command.toString();
}
}
@Override
protected Request prepareRequest(Request requestToPrepare) {
ChannelTypeUID typeUID = channel.getChannelTypeUID();
String channelId = channel.getUID().getIdWithoutGroup();
if (typeUID == null || typeUID.getId() == null
|| !typeUID.getId().startsWith(NibeUplinkBindingConstants.RW_CHANNEL_PREFIX)) {
logger.info("channel '{}' does not support write access - value to set '{}'", channelId, value);
throw new UnsupportedOperationException("channel (" + channelId + ") does not support write access");
}
// although we have integers openhab often transfers decimals which will then cause a validation error. So we
// will shorten here.
if (value.endsWith(".0")) {
value = value.substring(0, value.length() - 2);
}
String expr = ChannelUtil.getValidationExpression(channel);
if (value.matches(expr)) {
Fields fields = new Fields();
fields.add(channelId, value);
FormContentProvider cp = new FormContentProvider(fields);
requestToPrepare.header(HttpHeader.ACCEPT_ENCODING, StandardCharsets.UTF_8.name());
requestToPrepare.content(cp);
requestToPrepare.followRedirects(false);
requestToPrepare.method(HttpMethod.POST);
return requestToPrepare;
} else {
logger.info("channel '{}' does not allow value '{}' - validation rule '{}'", channelId, value, expr);
throw new ValidationException("channel (" + channelId + ") could not be updated due to a validation error");
}
}
@Override
protected String getURL() {
return NibeUplinkBindingConstants.MANAGE_API_BASE_URL + config.getNibeId()
+ ChannelUtil.getWriteApiUrlSuffix(channel);
}
@Override
public void onComplete(@Nullable Result result) {
logger.debug("onComplete()");
if (!HttpStatus.Code.FOUND.equals(getCommunicationStatus().getHttpCode()) && retries++ < MAX_RETRIES) {
logger.debug("Could not set value '{}' for channel '{}' ({})", value, channel.getUID().getId(),
channel.getLabel());
handler.getWebInterface().enqueueCommand(this);
}
}
}

View File

@@ -0,0 +1,99 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.config;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* Bean holding configuration data according to bridge.xml
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public class NibeUplinkConfiguration {
private @Nullable String user;
private @Nullable String password;
private @Nullable String nibeId;
private Integer asyncTimeout = 120;
private Integer syncTimeout = 120;
private Integer pollingInterval = 60;
private Integer houseKeepingInterval = 3600;
public @Nullable String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public @Nullable String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public @Nullable String getNibeId() {
return nibeId;
}
public void setNibeId(String nibeId) {
this.nibeId = nibeId;
}
public Integer getAsyncTimeout() {
return asyncTimeout;
}
public void setAsyncTimeout(Integer asyncTimeout) {
this.asyncTimeout = asyncTimeout;
}
public Integer getSyncTimeout() {
return syncTimeout;
}
public void setSyncTimeout(Integer syncTimeout) {
this.syncTimeout = syncTimeout;
}
public Integer getPollingInterval() {
return pollingInterval;
}
public void setPollingInterval(Integer pollingInterval) {
this.pollingInterval = pollingInterval;
}
public Integer getHouseKeepingInterval() {
return houseKeepingInterval;
}
public void setHouseKeepingInterval(Integer houseKeepingInterval) {
this.houseKeepingInterval = houseKeepingInterval;
}
@Override
public String toString() {
return new ToStringBuilder(this).append("user", getUser()).append("password", getPassword())
.append("nibeId", getNibeId()).append("pollingInterval", getPollingInterval())
.append("houseKeepingInterval", getHouseKeepingInterval()).append("asyncTimeout", getAsyncTimeout())
.append("syncTimeout", getSyncTimeout()).toString();
}
}

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.connector;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.http.HttpStatus.Code;
/**
* this class contains the HTTP status of the communication and an optional exception that might occoured during
* communication
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public class CommunicationStatus {
private @Nullable Code httpCode;
private @Nullable Exception error;
public final Code getHttpCode() {
Code code = httpCode;
return code == null ? Code.INTERNAL_SERVER_ERROR : code;
}
public final void setHttpCode(Code httpCode) {
this.httpCode = httpCode;
}
public final @Nullable Exception getError() {
return error;
}
public final void setError(Exception error) {
this.error = error;
}
public final String getMessage() {
Exception err = error;
String msg = getHttpCode().getMessage();
if (err != null && err.getMessage() != null && !err.getMessage().isEmpty()) {
return err.getMessage();
} else if (msg != null && !msg.isEmpty()) {
return msg;
}
return "";
}
}

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.connector;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* callback interface to update the status of the {@link UplinkWebInterface}
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public interface StatusUpdateListener {
void update(CommunicationStatus status);
}

View File

@@ -0,0 +1,285 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.connector;
import static org.openhab.binding.nibeuplink.internal.NibeUplinkBindingConstants.*;
import java.io.UnsupportedEncodingException;
import java.util.Queue;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.openhab.binding.nibeuplink.internal.AtomicReferenceTrait;
import org.openhab.binding.nibeuplink.internal.command.Login;
import org.openhab.binding.nibeuplink.internal.command.NibeUplinkCommand;
import org.openhab.binding.nibeuplink.internal.config.NibeUplinkConfiguration;
import org.openhab.binding.nibeuplink.internal.handler.NibeUplinkHandler;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class handles requests to the NibeUplink web interface. It manages authentication and wraps commands.
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public class UplinkWebInterface implements AtomicReferenceTrait {
private static final int NIBE_ID_THRESHOLD = 14;
private final Logger logger = LoggerFactory.getLogger(UplinkWebInterface.class);
/**
* Configuration
*/
private NibeUplinkConfiguration config;
/**
* handler for updating thing status
*/
private final NibeUplinkHandler uplinkHandler;
/**
* holds authentication status
*/
private boolean authenticated = false;
/**
* HTTP client for asynchronous calls
*/
private final HttpClient httpClient;
/**
* the scheduler which periodically sends web requests to the solaredge API. Should be initiated with the thing's
* existing scheduler instance.
*/
private final ScheduledExecutorService scheduler;
/**
* request executor
*/
private final WebRequestExecutor requestExecutor;
/**
* periodic request executor job
*/
private AtomicReference<@Nullable Future<?>> requestExecutorJobReference = new AtomicReference<>(null);
/**
* this class is responsible for executing periodic web requests. This ensures that only one request is executed at
* the same time and there will be a guaranteed minimum delay between subsequent requests.
*
* @author afriese - initial contribution
*/
@NonNullByDefault
private class WebRequestExecutor implements Runnable {
/**
* queue which holds the commands to execute
*/
private final Queue<@Nullable NibeUplinkCommand> commandQueue;
/**
* constructor
*/
WebRequestExecutor() {
this.commandQueue = new BlockingArrayQueue<>(WEB_REQUEST_QUEUE_MAX_SIZE);
}
/**
* puts a command into the queue
*
* @param command the command which will be queued
*/
void enqueue(NibeUplinkCommand command) {
try {
commandQueue.add(command);
} catch (IllegalStateException ex) {
if (commandQueue.size() >= WEB_REQUEST_QUEUE_MAX_SIZE) {
logger.debug(
"Could not add command to command queue because queue is already full. Maybe NIBE Uplink is down?");
} else {
logger.warn("Could not add command to queue - IllegalStateException");
}
}
}
/**
* executes the web request
*/
@Override
public void run() {
if (!isAuthenticated()) {
authenticate();
}
else if (isAuthenticated() && !commandQueue.isEmpty()) {
StatusUpdateListener statusUpdater = new StatusUpdateListener() {
@Override
public void update(CommunicationStatus status) {
switch (status.getHttpCode()) {
case SERVICE_UNAVAILABLE:
uplinkHandler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
status.getMessage());
setAuthenticated(false);
break;
case FOUND:
uplinkHandler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"most likely your NibeId is wrong. please check your NibeId.");
setAuthenticated(false);
break;
case OK:
// no action needed as the thing is already online.
break;
default:
uplinkHandler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
status.getMessage());
setAuthenticated(false);
}
}
};
NibeUplinkCommand command = commandQueue.poll();
if (command != null) {
command.setListener(statusUpdater);
command.performAction(httpClient);
}
}
}
}
/**
* Constructor to set up interface
*
* @param config the Bridge configuration
*/
public UplinkWebInterface(ScheduledExecutorService scheduler, NibeUplinkHandler handler, HttpClient httpClient) {
this.config = handler.getConfiguration();
this.uplinkHandler = handler;
this.scheduler = scheduler;
this.requestExecutor = new WebRequestExecutor();
this.httpClient = httpClient;
}
/**
* starts the periodic request executor job which handles all web requests
*/
public void start() {
this.config = uplinkHandler.getConfiguration();
setAuthenticated(false);
updateJobReference(requestExecutorJobReference, scheduler.scheduleWithFixedDelay(requestExecutor,
WEB_REQUEST_INITIAL_DELAY, WEB_REQUEST_INTERVAL, TimeUnit.MILLISECONDS));
}
/**
* queues any command for execution
*
* @param command the command which will be put into the queue
*/
public void enqueueCommand(NibeUplinkCommand command) {
requestExecutor.enqueue(command);
}
/**
* authenticates with the Nibe Uplink WEB interface
*
* @throws UnsupportedEncodingException
*/
private synchronized void authenticate() {
setAuthenticated(false);
if (preCheck()) {
StatusUpdateListener statusUpdater = new StatusUpdateListener() {
@Override
public void update(CommunicationStatus status) {
switch (status.getHttpCode()) {
case FOUND:
uplinkHandler.setStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, "logged in");
setAuthenticated(true);
break;
case OK:
uplinkHandler.setStatusInfo(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_ERROR,
"invalid username or password");
setAuthenticated(false);
break;
case SERVICE_UNAVAILABLE:
uplinkHandler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
status.getMessage());
setAuthenticated(false);
break;
default:
uplinkHandler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
status.getMessage());
setAuthenticated(false);
}
}
};
new Login(uplinkHandler, statusUpdater).performAction(httpClient);
}
}
/**
* performs some pre cheks on configuration before attempting to login
*
* @return true on success, false otherwise
*/
private boolean preCheck() {
String preCheckStatusMessage = "";
String localPassword = config.getPassword();
String localUser = config.getUser();
String localNibeId = config.getNibeId();
if (localPassword == null || localPassword.isEmpty()) {
preCheckStatusMessage = "please configure password first";
} else if (localUser == null || localUser.isEmpty()) {
preCheckStatusMessage = "please configure user first";
} else if (localNibeId == null || localNibeId.isEmpty()) {
preCheckStatusMessage = "please configure nibeId first";
} else if (localNibeId.length() > NIBE_ID_THRESHOLD) {
preCheckStatusMessage = "your NibeId is too long. Please refer to the documentation on how to set this value.";
} else {
return true;
}
this.uplinkHandler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
preCheckStatusMessage);
return false;
}
/**
* will be called by the ThingHandler to abort periodic jobs.
*/
public void dispose() {
logger.debug("Webinterface disposed.");
cancelJobReference(requestExecutorJobReference);
setAuthenticated(false);
}
private boolean isAuthenticated() {
return authenticated;
}
private void setAuthenticated(boolean authenticated) {
this.authenticated = authenticated;
}
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.handler;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.Channel;
/**
* this interface provides all methods which deal with channels
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public interface ChannelProvider {
List<Channel> getChannels();
Set<Channel> getDeadChannels();
@Nullable
Channel getSpecificChannel(String channelCode);
}

View File

@@ -0,0 +1,149 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.nibeuplink.internal.NibeUplinkBindingConstants;
import org.openhab.binding.nibeuplink.internal.model.ConfigurationException;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Channel;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* this class provides all methods which deal with channels
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public final class ChannelUtil {
private static final Logger logger = LoggerFactory.getLogger(ChannelUtil.class);
/**
* only static methods no instance needed
*/
private ChannelUtil() {
}
/**
* checks whether the channel ha a valid numeric Id
*
* @param channel to check
* @return true or false
*/
public static boolean isValidNibeChannel(Channel channel) {
String id = channel.getUID().getIdWithoutGroup();
return id.matches(NibeUplinkBindingConstants.VALID_CHANNEL_ID_REGEX);
}
/**
* map data response from API to OnOff-Type. uses mapping from channel configuration
*
* @param channel switch channel which has mapping configured
* @param value value to map
* @return mapped value
*/
public static State mapValue(Channel channel, String value) {
String off = getOffMapping(channel);
String on = getOnMapping(channel);
if (value.equals(off)) {
return OnOffType.OFF;
} else if (value.equals(on)) {
return OnOffType.ON;
} else {
logger.warn("Channel {} value '{}' could not be mapped, valid values: ON={}, OFF={}",
channel.getUID().getId(), value, on, off);
return UnDefType.UNDEF;
}
}
/**
* map data response from API to OnOff-Type. uses mapping from channel configuration
*
* @param channel switch channel which has mapping configured
* @param value value to map
* @return mapped value
*/
public static State mapValue(Channel channel, long value) {
return mapValue(channel, String.valueOf(value));
}
/**
* map OnOff-Type to API compatible value. uses mapping from channel configuration
*
* @param channel switch channel which has mapping configured
* @param value value to map
* @return mapped value
*/
public static String mapValue(Channel channel, OnOffType value) {
if (value.equals(OnOffType.OFF)) {
return String.valueOf(getOffMapping(channel));
} else {
return String.valueOf(getOnMapping(channel));
}
}
/**
* retrieves the validation expression which is assigned to this channel, fallback to a default, if no validation is
* defined.
*
* @param channel
* @return the validation expression
*/
public static String getValidationExpression(Channel channel) {
String expr = getPropertyOrParameter(channel, NibeUplinkBindingConstants.PARAMETER_NAME_VALIDATION_REGEXP);
if (expr == null) {
logger.info("Channel {} does not have a validation expression configured", channel.getUID().getId());
throw new ConfigurationException(
"channel (" + channel.getUID().getId() + ") does not have a validation expression configured");
}
return expr;
}
/**
* retrieves the write API url suffix which is assigned to this channel.
*
* @param channel
* @return the url suffix
*/
public static String getWriteApiUrlSuffix(Channel channel) {
String suffix = getPropertyOrParameter(channel, NibeUplinkBindingConstants.PARAMETER_NAME_WRITE_API_URL);
if (suffix == null) {
logger.info("channel {} does not have a write api url suffix configured", channel.getUID().getId());
throw new ConfigurationException(
"channel (" + channel.getUID().getId() + ") does not have a write api url suffix configured");
}
return suffix;
}
private static @Nullable String getOffMapping(Channel channel) {
return getPropertyOrParameter(channel, NibeUplinkBindingConstants.PARAMETER_NAME_OFF_MAPPING);
}
private static @Nullable String getOnMapping(Channel channel) {
return getPropertyOrParameter(channel, NibeUplinkBindingConstants.PARAMETER_NAME_ON_MAPPING);
}
private static @Nullable String getPropertyOrParameter(Channel channel, String name) {
String value = channel.getProperties().get(name);
// also eclipse says this cannot be null, it definitely can!
if (value == null || value.isEmpty()) {
Object obj = channel.getConfiguration().get(name);
value = obj == null ? null : obj.toString();
}
return value;
}
}

View File

@@ -0,0 +1,61 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.handler;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
/**
* generic implementation of handler logic
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public class GenericHandler extends UplinkBaseHandler {
/**
* constructor, called by the factory
*
* @param thing instance of the thing, passed in by the factory
* @param httpClient the httpclient that communicates with the API
*/
public GenericHandler(Thing thing, HttpClient httpClient) {
super(thing, httpClient);
}
@Override
public @Nullable Channel getSpecificChannel(String channelId) {
Channel channel = getThing().getChannel(channelId);
if (channel == null) {
for (ChannelGroupUID channelGroupUID : getRegisteredGroups()) {
channel = getThing().getChannel(new ChannelUID(channelGroupUID, channelId));
if (channel != null) {
break;
}
}
}
return channel;
}
@Override
public List<Channel> getChannels() {
return getThing().getChannels();
}
}

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.handler;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.nibeuplink.internal.config.NibeUplinkConfiguration;
import org.openhab.binding.nibeuplink.internal.connector.UplinkWebInterface;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.State;
/**
* public interface of the {@link UplinkBaseHandler}
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public interface NibeUplinkHandler extends ThingHandler, ChannelProvider {
/**
* Called from {@link NibeUplinkWebInterface#authenticate()} to update
* the thing status because updateStatus is protected.
*
* @param status Bridge status
* @param statusDetail Bridge status detail
* @param description Bridge status description
*/
void setStatusInfo(ThingStatus status, ThingStatusDetail statusDetail, String description);
/**
* Provides the web interface object.
*
* @return The web interface object
*/
UplinkWebInterface getWebInterface();
void updateChannelStatus(Map<Channel, State> values);
NibeUplinkConfiguration getConfiguration();
}

View File

@@ -0,0 +1,207 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.handler;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.nibeuplink.internal.AtomicReferenceTrait;
import org.openhab.binding.nibeuplink.internal.NibeUplinkBindingConstants;
import org.openhab.binding.nibeuplink.internal.command.UpdateSetting;
import org.openhab.binding.nibeuplink.internal.config.NibeUplinkConfiguration;
import org.openhab.binding.nibeuplink.internal.connector.UplinkWebInterface;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
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.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandler;
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;
/**
* The {@link UplinkBaseHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public abstract class UplinkBaseHandler extends BaseThingHandler implements NibeUplinkHandler, AtomicReferenceTrait {
private final Logger logger = LoggerFactory.getLogger(UplinkBaseHandler.class);
private final long POLLING_INITIAL_DELAY = 30;
private final long HOUSE_KEEPING_INITIAL_DELAY = 300;
private final Set<Channel> deadChannels = new HashSet<>(100);
private final Set<ChannelGroupUID> registeredGroups = new HashSet<>(10);
/**
* Interface object for querying the NibeUplink web interface
*/
private UplinkWebInterface webInterface;
/**
* Schedule for polling
*/
private final AtomicReference<@Nullable Future<?>> pollingJobReference;
/**
* Schedule for periodic cleaning dead channel list
*/
private final AtomicReference<@Nullable Future<?>> deadChannelHouseKeepingReference;
public UplinkBaseHandler(Thing thing, HttpClient httpClient) {
super(thing);
this.webInterface = new UplinkWebInterface(scheduler, this, httpClient);
this.pollingJobReference = new AtomicReference<>(null);
this.deadChannelHouseKeepingReference = new AtomicReference<>(null);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (!(command instanceof RefreshType)) {
logger.debug("command for {}: {}", channelUID.getIdWithoutGroup(), command.toString());
Channel channel = getSpecificChannel(channelUID.getIdWithoutGroup());
if (channel != null) {
ChannelTypeUID typeUID = channel.getChannelTypeUID();
if (typeUID != null && typeUID.getId() != null
&& typeUID.getId().startsWith(NibeUplinkBindingConstants.RW_CHANNEL_PREFIX)) {
webInterface.enqueueCommand(new UpdateSetting(this, channel, command));
}
}
}
}
@Override
public void initialize() {
logger.debug("About to initialize NibeUplink");
NibeUplinkConfiguration config = getConfiguration();
logger.debug("NibeUplink initialized with configuration: {}", config);
registeredGroups.clear();
validateChannelsAndRegisterGroups();
startPolling();
webInterface.start();
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "waiting for web api login");
}
/**
* initialize the channels out of the configuration
*
*/
private void validateChannelsAndRegisterGroups() {
logger.debug("Validating {} channels", getThing().getChannels().size());
for (Channel channel : getThing().getChannels()) {
if (!ChannelUtil.isValidNibeChannel(channel)) {
logger.warn("Channel {} is not a valid Nibe channel ({})", channel.getUID().getIdWithoutGroup(),
channel.getLabel());
deadChannels.add(channel);
} else {
logger.debug("Successfully validated channel {} ({})", channel.getUID().getIdWithoutGroup(),
channel.getLabel());
String groupId = channel.getUID().getGroupId();
if (groupId != null) {
ThingUID thingUID = this.getThing().getUID();
if (registeredGroups.add(new ChannelGroupUID(thingUID, groupId))) {
logger.debug("Successfully registered channel-group '{}'", groupId);
}
}
}
}
}
/**
* Start the polling.
*/
private void startPolling() {
updateJobReference(pollingJobReference, scheduler.scheduleWithFixedDelay(new UplinkPolling(this),
POLLING_INITIAL_DELAY, getConfiguration().getPollingInterval(), TimeUnit.SECONDS));
updateJobReference(deadChannelHouseKeepingReference, scheduler.scheduleWithFixedDelay(deadChannels::clear,
HOUSE_KEEPING_INITIAL_DELAY, getConfiguration().getHouseKeepingInterval(), TimeUnit.SECONDS));
}
/**
* Disposes the bridge.
*/
@Override
public void dispose() {
logger.debug("Handler disposed.");
cancelJobReference(pollingJobReference);
cancelJobReference(deadChannelHouseKeepingReference);
// the webinterface also makes use of the scheduler and must stop it's jobs
webInterface.dispose();
}
@Override
public UplinkWebInterface getWebInterface() {
return webInterface;
}
/**
* will update all channels provided in the map
*
* @param values map containing the data updates
*/
@Override
public void updateChannelStatus(Map<Channel, @Nullable State> values) {
logger.debug("Handling channel update. ({} Channels)", values.size());
for (Channel channel : values.keySet()) {
if (getChannels().contains(channel)) {
State value = values.get(channel);
if (value != null) {
logger.debug("Channel is to be updated: {}: {}", channel.getUID().getAsString(), value);
updateState(channel.getUID(), value);
}
} else {
logger.debug("Could not identify channel: {} for model {}", channel.getUID().getAsString(),
getThing().getThingTypeUID().getAsString());
}
}
}
@Override
public Set<Channel> getDeadChannels() {
return deadChannels;
}
@Override
public void setStatusInfo(ThingStatus status, ThingStatusDetail statusDetail, String description) {
super.updateStatus(status, statusDetail, description);
}
@Override
public NibeUplinkConfiguration getConfiguration() {
return this.getConfigAs(NibeUplinkConfiguration.class);
}
public Set<ChannelGroupUID> getRegisteredGroups() {
return registeredGroups;
}
}

View File

@@ -0,0 +1,54 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.nibeuplink.internal.command.GenericStatusUpdate;
import org.openhab.binding.nibeuplink.internal.command.NibeUplinkCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Polling worker class. This is responsible for periodic polling of status values.
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public class UplinkPolling implements Runnable {
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* Handler for delegation to callbacks.
*/
private final NibeUplinkHandler handler;
/**
* Constructor.
*
* @param handler instance of the thing handler
*/
public UplinkPolling(NibeUplinkHandler handler) {
this.handler = handler;
}
/**
* Poll the Nibe Uplink webservice one time.
*/
@Override
public void run() {
logger.debug("polling NibeUplink {}", handler.getConfiguration());
NibeUplinkCommand command = new GenericStatusUpdate(handler);
handler.getWebInterface().enqueueCommand(command);
}
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.model;
/**
* used to determine the group a channel belongs to
*
* @author Alexander Friese - initial contribution
*/
public enum ChannelGroup {
BASE,
GENERAL,
COMPRESSOR,
HOTWATER,
AIRSUPPLY,
CUSTOM
}

View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* exception whichs is used to state a validation error
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public class ConfigurationException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ConfigurationException() {
super();
}
public ConfigurationException(String message) {
super(message);
}
public ConfigurationException(Throwable cause) {
super(cause);
}
public ConfigurationException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.model;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* common interface for all data response classes
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public interface DataResponse {
Map<String, Long> getValues();
}

View File

@@ -0,0 +1,161 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.model;
import static org.openhab.binding.nibeuplink.internal.NibeUplinkBindingConstants.*;
import java.util.HashMap;
import java.util.Map;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.nibeuplink.internal.handler.ChannelProvider;
import org.openhab.binding.nibeuplink.internal.handler.ChannelUtil;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.MetricPrefix;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* transforms the http response into the openhab datamodel (instances of State)
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public class DataResponseTransformer {
private final Logger logger = LoggerFactory.getLogger(DataResponseTransformer.class);
private static final double UNSCALED = 1;
private static final double DIV_10 = 0.1;
private static final double DIV_100 = 0.01;
private final ChannelProvider channelProvider;
public DataResponseTransformer(ChannelProvider channelProvider) {
this.channelProvider = channelProvider;
}
public Map<Channel, State> transform(DataResponse response) {
Map<String, Long> source = response.getValues();
Map<Channel, State> result = new HashMap<>(source.size());
for (String channelId : source.keySet()) {
Long value = source.get(channelId);
Channel channel = channelProvider.getSpecificChannel(channelId);
if (channel == null) {
// This should not happen but we want to get informed about it
logger.warn("Channel not found: {}", channelId);
} else {
ChannelTypeUID typeUID = channel.getChannelTypeUID();
String type = typeUID == null ? "null" : typeUID.getId();
switch (type) {
case CHANNEL_TYPE_TEMPERATURE:
case CHANNEL_TYPE_START_COOLING_RW:
putQuantityType(result, channel, value, DIV_10, SIUnits.CELSIUS);
break;
case CHANNEL_TYPE_PRESSURE:
putQuantityType(result, channel, value, DIV_10, SmartHomeUnits.BAR);
break;
case CHANNEL_TYPE_ENERGY:
putQuantityType(result, channel, value, DIV_10, MetricPrefix.KILO(SmartHomeUnits.WATT_HOUR));
break;
case CHANNEL_TYPE_POWER:
putQuantityType(result, channel, value, DIV_100, MetricPrefix.KILO(SmartHomeUnits.WATT));
break;
case CHANNEL_TYPE_SWITCH_RW:
case CHANNEL_TYPE_SWITCH:
putOnOffType(result, channel, value);
break;
case CHANNEL_TYPE_ELECTRIC_CURRENT:
putQuantityType(result, channel, value, DIV_10, SmartHomeUnits.AMPERE);
break;
case CHANNEL_TYPE_TIME_UNSCALED:
putQuantityType(result, channel, value, UNSCALED, SmartHomeUnits.HOUR);
break;
case CHANNEL_TYPE_TIME_SCALE10:
putQuantityType(result, channel, value, DIV_10, SmartHomeUnits.HOUR);
break;
case CHANNEL_TYPE_FREQUENCY_UNSCALED:
putQuantityType(result, channel, value, UNSCALED, SmartHomeUnits.HERTZ);
break;
case CHANNEL_TYPE_FREQUENCY_SCALE10:
putQuantityType(result, channel, value, DIV_10, SmartHomeUnits.HERTZ);
break;
case CHANNEL_TYPE_FLOW:
putQuantityType(result, channel, value, DIV_10,
SmartHomeUnits.LITRE.divide(SmartHomeUnits.MINUTE));
break;
case CHANNEL_TYPE_SPEED:
putQuantityType(result, channel, value, UNSCALED, SmartHomeUnits.PERCENT);
break;
case CHANNEL_TYPE_NUMBER_SCALE100:
putDecimalType(result, channel, value, DIV_100);
break;
case CHANNEL_TYPE_NUMBER_SCALE10:
case CHANNEL_TYPE_DEGREE_MINUTES_RW:
case CHANNEL_TYPE_STOP_HEATING_RW:
case CHANNEL_TYPE_STOP_ADD_HEATING_RW:
case CHANNEL_TYPE_ROOM_SENSOR_FACTOR_RW:
putDecimalType(result, channel, value, DIV_10);
break;
case CHANNEL_TYPE_NUMBER_UNSCALED:
case CHANNEL_TYPE_DEFROSTING_STATE:
case CHANNEL_TYPE_HPAC_STATE:
case CHANNEL_TYPE_HW_LUX_RW:
case CHANNEL_TYPE_HW_MODE_RW:
case CHANNEL_TYPE_FAN_SPEED_RW:
case CHANNEL_TYPE_FILTER_TIME_RW:
case CHANNEL_TYPE_HEAT_OFFSET_RW:
putDecimalType(result, channel, value, UNSCALED);
break;
default:
logger.warn("could not handle unknown type {}, channel {}, value {}", type, channel.getUID(),
value);
}
}
}
return result;
}
private final void putQuantityType(Map<Channel, State> targetMap, Channel channel, long value, double factor,
Unit<?> unit) {
// make sure that values are stored as long if no factor is to be applied
State val = factor == UNSCALED ? new QuantityType<>(value, unit) : new QuantityType<>(value * factor, unit);
targetMap.put(channel, val);
logger.debug("Channel {} transformed to QuantityType ({}*{} {}) -> {}", channel.getUID().getId(), value, factor,
unit, val);
}
private final void putOnOffType(Map<Channel, State> targetMap, Channel channel, long value) {
State val = ChannelUtil.mapValue(channel, value);
targetMap.put(channel, val);
logger.debug("Channel {} transformed to OnOffType ({}) -> {}", channel.getUID().getId(), value, val);
}
private final void putDecimalType(Map<Channel, State> targetMap, Channel channel, long value, double factor) {
// make sure that values are stored as long if no factor is to be applied
State val = factor == UNSCALED ? new DecimalType(value) : new DecimalType(value * factor);
targetMap.put(channel, val);
logger.debug("Channel {} transformed to DecimalType ({}*{}) -> {}", channel.getUID().getId(), value, factor,
val);
}
}

View File

@@ -0,0 +1,90 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.annotations.SerializedName;
/**
* data class to map the json status response
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public class GenericDataResponse implements DataResponse {
private final Logger logger = LoggerFactory.getLogger(GenericDataResponse.class);
@NonNullByDefault
public static class Value {
@SerializedName("VariableId")
private @Nullable String variableId;
@SerializedName("CurrentValue")
private @Nullable String currentValue;
@SerializedName("CurrentIntValue")
private @Nullable Long currentIntValue;
@SerializedName("IsLoading")
private boolean isLoading;
}
@SerializedName("IsOffline")
private @Nullable String isOffline;
@SerializedName("OnlineImage")
private @Nullable String onlineImage;
@SerializedName("Date")
private @Nullable String date;
@SerializedName("FuzzyDate")
private @Nullable String fuzzyDate;
@SerializedName("Values")
private List<Value> values = new ArrayList<>();
@Override
public Map<String, @Nullable Long> getValues() {
Map<String, @Nullable Long> valueMap = new HashMap<>();
for (Value value : values) {
String id = value.variableId;
if (!value.isLoading && id != null) {
if (logger.isDebugEnabled()) {
logger.debug("Channel {} updated to: {} ({})", value.variableId, value.currentIntValue,
value.currentValue);
}
valueMap.put(id, value.currentIntValue);
}
}
return valueMap;
}
public @Nullable String getIsOffline() {
return isOffline;
}
public @Nullable String getOnlineImage() {
return onlineImage;
}
public @Nullable String getDate() {
return date;
}
public @Nullable String getFuzzyDate() {
return fuzzyDate;
}
}

View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.nibeuplink.internal.model;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* exception whichs is used to state a validation error
*
* @author Alexander Friese - initial contribution
*/
@NonNullByDefault
public class ValidationException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ValidationException() {
super();
}
public ValidationException(String message) {
super(message);
}
public ValidationException(Throwable cause) {
super(cause);
}
public ValidationException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="nibeuplink" 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>NibeUplink Binding</name>
<description>This is the binding for NibeUplink.</description>
<author>Alexander Friese</author>
</binding:binding>

View File

@@ -0,0 +1,46 @@
<?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:nibeuplink:web">
<parameter-group name="authentication">
<label>Authentication</label>
<description>Authentication settings.</description>
</parameter-group>
<parameter-group name="connection">
<label>Connection</label>
<description>Connection settings.</description>
</parameter-group>
<parameter-group name="general">
<label>General</label>
<description>General settings.</description>
</parameter-group>
<parameter-group name="customChannels">
<label>Custom Channels</label>
<description>Custom Channel configuration</description>
</parameter-group>
<parameter name="user" type="text" required="true" groupName="authentication">
<label>Username</label>
<description>The Username to login at NibeIplink.</description>
</parameter>
<parameter name="password" type="text" required="true" groupName="authentication">
<label>Password</label>
<context>password</context>
<description>The Password to login at NibeIplink.</description>
</parameter>
<parameter name="nibeId" type="text" required="true" groupName="general">
<label>Nibe ID</label>
<description>The ID to identify the heat pump at NibeIplink.</description>
</parameter>
<parameter name="pollingInterval" type="integer" required="false" min="30" max="3600" unit="s"
groupName="connection">
<label>Polling Interval</label>
<description>Interval in which data is polled from Nibe Uplink (in seconds).</description>
<default>60</default>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@@ -0,0 +1,26 @@
# binding
binding.nibeuplink.name = Nibe Uplink binding
binding.nibeuplink.description = Abfrage von Nibe Wärmepumpendaten über die Nibe Uplink API.
# thing types
thing-type.nibeuplink.web.label = Nibe Wärmepumpe
thing-type.nibeuplink.web.description = Wärmepumpenspezifischer WebZugang zu Nibe Uplink
# groups
thing-type.config.nibeuplink.web.group.authentication.label = Authentifizierung
thing-type.config.nibeuplink.web.group.authentication.description = Einstellungen für die Authentifizierung.
thing-type.config.nibeuplink.web.group.connection.label = Verbindung
thing-type.config.nibeuplink.web.group.connection.description = Einstellungen für die Verbindung.
thing-type.config.nibeuplink.web.group.general.label = Allgemeines
thing-type.config.nibeuplink.web.group.general.description = Allgemeine Einstellungen.
thing-type.config.nibeuplink.web.group.customChannels.label = Benutzerdefinierte Kanäle
thing-type.config.nibeuplink.web.group.customChannels.description = Benutzerdefinierte Kanäle.
thing-type.config.nibeuplink.web.user.label = Benutzer
thing-type.config.nibeuplink.web.user.description = Benutzer zur Authentifizierung bei Nibe Uplink.
thing-type.config.nibeuplink.web.password.label = Passwort
thing-type.config.nibeuplink.web.password.description = Passwort zur Authentifizierung bei Nibe Uplink.
thing-type.config.nibeuplink.web.nibeId.label = Nibe ID
thing-type.config.nibeuplink.web.nibeId.description = ID der Wärmepumpeninstallation bei Nibe Uplink.
thing-type.config.nibeuplink.web.pollingInterval.label = Abfrageintervall
thing-type.config.nibeuplink.web.pollingInterval.description = Intervall in welchem Abfragen an Nibe Uplink geschickt werden.

View File

@@ -0,0 +1,195 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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">
<channel-group-type id="base-base">
<label>Base Channels</label>
<channels>
<channel id="40004" typeId="type-temperature">
<label>BT1 Outdoor Temperature</label>
<description>Current outdoor temperature</description>
</channel>
<channel id="40067" typeId="type-temperature">
<label>BT1 Average</label>
<description>EB100-BT1 Outdoor temperature average</description>
</channel>
<channel id="43005" typeId="rwtype-degree-minutes">
<label>Degree Minutes (16 Bit)</label>
<description>Degree minutes, 16bit value (-32768 &lt; x &lt; 32767). Values outside valid values are rounded to the
closest valid value.</description>
<properties>
<property name="writeApiUrl">/Manage/4.9.3</property>
<property name="validationExpression">-?[0-9]+</property>
</properties>
</channel>
<channel id="43009" typeId="type-temperature">
<label>Calc. Supply S1</label>
<description>Calculated supply temperature for the climate system</description>
</channel>
<channel id="40071" typeId="type-temperature">
<label>BT25 Ext. Supply</label>
<description>External supply temperature, BT25</description>
</channel>
<channel id="40033" typeId="type-temperature">
<label>BT50 Room Temp S1</label>
<description>Room Temperature S1 (BT50)</description>
</channel>
<channel id="43161" typeId="type-switch">
<label>External Adjustment Activated Via Input S1</label>
<description>External Adjustment Activated Via Input S1</description>
<properties>
<property name="offMapping">0</property>
<property name="onMapping">1</property>
</properties>
</channel>
<channel id="40008" typeId="type-temperature">
<label>BT2 Supply Temp S1</label>
<description>Supply temperature for system 1</description>
</channel>
<channel id="40012" typeId="type-temperature">
<label>EB100-EP14-BT3 Return Temp</label>
<description>Return temperature</description>
</channel>
<channel id="40072" typeId="type-flow">
<label>BF1 EP14 Flow</label>
<description>Current flow EP14|Current flow EP15</description>
</channel>
<channel id="40079" typeId="type-electric-current">
<label>EB100-BE3 Current</label>
<description>BE3 Current</description>
</channel>
<channel id="40081" typeId="type-electric-current">
<label>EB100-BE2 Current</label>
<description>BE2 Current</description>
</channel>
<channel id="40083" typeId="type-electric-current">
<label>EB100-BE1 Current</label>
<description>BE1 Current</description>
</channel>
<channel id="10033" typeId="type-switch">
<label>Int. El.add. Blocked</label>
<description>states if internal electric additional heater is blocked</description>
<properties>
<property name="offMapping">0</property>
<property name="onMapping">1</property>
</properties>
</channel>
<channel id="43081" typeId="type-time-scale10">
<label>Tot. Op.time Add.</label>
<description>Total electric additive operation time</description>
</channel>
<channel id="43084" typeId="type-power">
<label>Int. El.add. Power</label>
<description>Current power from the internal electrical addition</description>
</channel>
<channel id="47212" typeId="type-power">
<label>Max Int Add. Power</label>
<description>Maximum power from the internal electrical addition</description>
</channel>
<channel id="48914" typeId="type-power">
<label>Max Int Add. Power, SG Ready</label>
<description>Maximum power from the internal electrical addition in SG-Ready Mode</description>
</channel>
<channel id="44308" typeId="type-energy">
<label>Heat Meter - Heat Cpr EP14</label>
<description>Accumulated energy production as calculated by the heat meter</description>
</channel>
<channel id="44304" typeId="type-energy">
<label>Heat Meter - Pool Cpr EP14</label>
<description>Accumulated energy production as calculated by the heat meter</description>
</channel>
<channel id="44300" typeId="type-energy">
<label>Heat Meter - Heat Cpr and Add EP14</label>
<description>Accumulated energy production as calculated by the heat meter</description>
</channel>
<channel id="48043" typeId="rwtype-switch">
<label>Holiday</label>
<description>states if Holiday mode is activated</description>
<properties>
<property name="writeApiUrl">/Manage/4.7</property>
<property name="validationExpression">.*</property>
<property name="offMapping">0</property>
<property name="onMapping">10</property>
</properties>
</channel>
<channel id="10012" typeId="type-switch">
<label>Compressor Blocked</label>
<description>states if the compressor is blocked</description>
<properties>
<property name="offMapping">0</property>
<property name="onMapping">1</property>
</properties>
</channel>
<channel id="43437" typeId="type-speed-percent">
<label>Supply Pump Speed EP14</label>
<description>Supply Pump Speed, EP14 (GP6)</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="base-hotwater">
<label>Hot Water Channels</label>
<channels>
<channel id="40013" typeId="type-temperature">
<label>BT7 HW Top</label>
<description>Hot water top temperature, BT7</description>
</channel>
<channel id="40014" typeId="type-temperature">
<label>BT6 HW Load</label>
<description>Hot water load temperature, BT6</description>
</channel>
<channel id="44306" typeId="type-energy">
<label>Heat Meter - HW Cpr EP14</label>
<description>Accumulated energy production as calculated by the heat meter</description>
</channel>
<channel id="44298" typeId="type-energy">
<label>Heat Meter - HW Cpr and Add EP14</label>
<description>Accumulated energy production as calculated by the heat meter</description>
</channel>
<channel id="48132" typeId="rwtype-hw-lux">
<label>Temporary Lux</label>
<description>Temporary hot water lux mode</description>
<properties>
<property name="writeApiUrl">/Manage/2.1</property>
<property name="validationExpression">[01234]</property>
</properties>
</channel>
<channel id="47041" typeId="rwtype-hw-mode">
<label>Hot Water Mode</label>
<description>The currently active hotwater mode</description>
<properties>
<property name="writeApiUrl">/Manage/2.2</property>
<property name="validationExpression">[012]</property>
</properties>
</channel>
<channel id="47045" typeId="type-temperature">
<label>Start Temperature HW Economy</label>
<description>Start temperature for heating water in Economy mode</description>
</channel>
<channel id="47049" typeId="type-temperature">
<label>Stop Temperature HW Economy</label>
<description>Stop temperature for heating water in Economy mode</description>
</channel>
<channel id="47044" typeId="type-temperature">
<label>Start Temperature HW Normal</label>
<description>Start temperature for heating water in Normal mode</description>
</channel>
<channel id="47048" typeId="type-temperature">
<label>Stop Temperature HW Normal</label>
<description>Stop temperature for heating water in Normal mode</description>
</channel>
<channel id="47043" typeId="type-temperature">
<label>Start Temperature HW Luxury</label>
<description>Start temperature for heating water in Luxury mode</description>
</channel>
<channel id="47047" typeId="type-temperature">
<label>Stop Temperature HW Luxury</label>
<description>Stop temperature for heating water in Luxory mode</description>
</channel>
<channel id="47046" typeId="type-temperature">
<label>Stop Temperature Periodic HW</label>
<description>Stop temperature for heating water in periodic heating</description>
</channel>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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">
<channel-group-type id="f1145-general">
<label>General Channels</label>
<channels>
<channel id="44302" typeId="type-energy">
<label>Heat Meter - Cooling Cpr EP14</label>
<description>Accumulated energy production as calculated by the heat meter</description>
</channel>
<channel id="44270" typeId="type-temperature">
<label>Calculated Cooling Supply Temperature S1</label>
<description>Calculated supply temperature in cooling mode for the climate system</description>
</channel>
<channel id="43103" typeId="type-hpac-state">
<label>HPAC State</label>
<description>State of the HPAC accessory</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="f1145-compressor">
<label>Compressor Channels</label>
<channels>
<channel id="43424" typeId="type-defrosting-state">
<label>Tot. HW Op.time Compr. EB100-EP14</label>
<description>Total compressor operation time in hot water mode</description>
</channel>
<channel id="43420" typeId="type-defrosting-state">
<label>Tot. Op.time Compr. EB100-EP14</label>
<description>Total compressor operation time</description>
</channel>
<channel id="43416" typeId="type-number-unscaled">
<label>Compressor Starts EB100-EP14</label>
<description>Number of compressor starts</description>
</channel>
<channel id="40022" typeId="type-temperature">
<label>EB100-EP14-BT17 Suction</label>
<description>Suction temperature, BT17</description>
</channel>
<channel id="40019" typeId="type-temperature">
<label>EB100-EP14-BT15 Liquid Line</label>
<description>Liquid line temperature, BT15</description>
</channel>
<channel id="40018" typeId="type-temperature">
<label>EB100-EP14-BT14 Hot Gas Temp</label>
<description>Hot gas temperature, BT14</description>
</channel>
<channel id="40017" typeId="type-temperature">
<label>EB100-EP14-BT12 Condensor Out</label>
<description>Condensor out temperature, BT12</description>
</channel>
<channel id="40015" typeId="type-temperature">
<label>EB100-EP14-BT10 Brine in Temperature</label>
<description>Brine in temperature, BT10</description>
</channel>
<channel id="40016" typeId="type-temperature">
<label>EB100-EP14-BT11 Brine out Temperature</label>
<description>Brine out temperature, BT11</description>
</channel>
<channel id="43439" typeId="type-speed-percent">
<label>EP14-GP2 Brine Pump Speed</label>
<description>Brine pump speed EP14 (GP2)</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="f1145-airsupply">
<label>Air Supply/Exhaust Channels</label>
<channels>
<channel id="40025" typeId="type-temperature">
<label>BT20 Exhaust Air Temp. 1</label>
<description>Exhaust Air Temperature (BT20)</description>
</channel>
<channel id="40026" typeId="type-temperature">
<label>BT21 Vented Air Temp. 1</label>
<description>Vented Air Temperature (BT21)</description>
</channel>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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="f1145" extensible="type-number-unscaled,type-number-scale10,type-number-scale100">
<label>Nibe F1145</label>
<description>Nibe F1145 heat pump connected through Nibe UpLink</description>
<channel-groups>
<channel-group typeId="base-base" id="base"/>
<channel-group typeId="base-hotwater" id="hotwater"/>
<channel-group typeId="f1145-general" id="general"/>
<channel-group typeId="f1145-compressor" id="compressor"/>
<channel-group typeId="f1145-airsupply" id="airsupply"/>
</channel-groups>
<config-description-ref uri="thing-type:nibeuplink:web"/>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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">
<channel-group-type id="f1155-general">
<label>General Channels</label>
<channels>
<channel id="44302" typeId="type-energy">
<label>Heat Meter - Cooling Cpr EP14</label>
<description>Accumulated energy production as calculated by the heat meter</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="f1155-compressor">
<label>Compressor Channels</label>
<channels>
<channel id="43424" typeId="type-defrosting-state">
<label>Tot. HW Op.time Compr. EB100-EP14</label>
<description>Total compressor operation time in hot water mode</description>
</channel>
<channel id="43420" typeId="type-defrosting-state">
<label>Tot. Op.time Compr. EB100-EP14</label>
<description>Total compressor operation time</description>
</channel>
<channel id="43416" typeId="type-number-unscaled">
<label>Compressor Starts EB100-EP14</label>
<description>Number of compressor starts</description>
</channel>
<channel id="40022" typeId="type-temperature">
<label>EB100-EP14-BT17 Suction</label>
<description>Suction temperature, BT17</description>
</channel>
<channel id="40019" typeId="type-temperature">
<label>EB100-EP14-BT15 Liquid Line</label>
<description>Liquid line temperature, BT15</description>
</channel>
<channel id="40018" typeId="type-temperature">
<label>EB100-EP14-BT14 Hot Gas Temp</label>
<description>Hot gas temperature, BT14</description>
</channel>
<channel id="40017" typeId="type-temperature">
<label>EB100-EP14-BT12 Condensor Out</label>
<description>Condensor out temperature, BT12</description>
</channel>
<channel id="43136" typeId="type-frequency-scale10">
<label>Compressor Frequency, Actual</label>
<description>The compressor frequency the compressor is currently running at</description>
</channel>
<channel id="43122" typeId="type-frequency-unscaled">
<label>Compr. Current Min.freq.</label>
<description>The current minimum frequency of the compressor</description>
</channel>
<channel id="43123" typeId="type-frequency-unscaled">
<label>Compr. Current Max.freq.</label>
<description>The current maximum frequency of the compressor</description>
</channel>
<channel id="40015" typeId="type-temperature">
<label>EB100-EP14-BT10 Brine in Temperature</label>
<description>Brine in temperature, BT10</description>
</channel>
<channel id="40016" typeId="type-temperature">
<label>EB100-EP14-BT11 Brine out Temperature</label>
<description>Brine out temperature, BT11</description>
</channel>
<channel id="43439" typeId="type-speed-percent">
<label>EP14-GP2 Brine Pump Speed</label>
<description>Brine pump speed EP14 (GP2)</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="f1155-airsupply">
<label>Air Supply/Exhaust Channels</label>
<channels>
<channel id="40025" typeId="type-temperature">
<label>BT20 Exhaust Air Temp. 1</label>
<description>Exhaust Air Temperature (BT20)</description>
</channel>
<channel id="40026" typeId="type-temperature">
<label>BT21 Vented Air Temp. 1</label>
<description>Vented Air Temperature (BT21)</description>
</channel>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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="f1155" extensible="type-number-unscaled,type-number-scale10,type-number-scale100">
<label>Nibe F1155</label>
<description>Nibe F1155 heat pump connected through Nibe UpLink</description>
<channel-groups>
<channel-group typeId="base-base" id="base"/>
<channel-group typeId="base-hotwater" id="hotwater"/>
<channel-group typeId="f1155-general" id="general"/>
<channel-group typeId="f1155-compressor" id="compressor"/>
<channel-group typeId="f1155-airsupply" id="airsupply"/>
</channel-groups>
<config-description-ref uri="thing-type:nibeuplink:web"/>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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">
<channel-group-type id="f730-compressor">
<label>Compressor Channels</label>
<channels>
<channel id="43181" typeId="type-speed-percent">
<label>Chargepump Speed</label>
<description>Chargepump Speed</description>
</channel>
<channel id="43424" typeId="type-time-unscaled">
<label>Tot. HW Op.time Compr. EB100-EP14</label>
<description>Total compressor operation time in hot water mode</description>
</channel>
<channel id="43420" typeId="type-time-unscaled">
<label>Tot. Op.time Compr. EB100-EP14</label>
<description>Total compressor operation time</description>
</channel>
<channel id="43416" typeId="type-number-unscaled">
<label>Compressor Starts EB100-EP14</label>
<description>Number of compressor starts</description>
</channel>
<channel id="40022" typeId="type-temperature">
<label>EB100-EP14-BT17 Suction</label>
<description>Suction temperature, BT17</description>
</channel>
<channel id="40019" typeId="type-temperature">
<label>EB100-EP14-BT15 Liquid Line</label>
<description>Liquid line temperature, BT15</description>
</channel>
<channel id="40018" typeId="type-temperature">
<label>EB100-EP14-BT14 Hot Gas Temp</label>
<description>Hot gas temperature, BT14</description>
</channel>
<channel id="40017" typeId="type-temperature">
<label>EB100-EP14-BT12 Condensor Out</label>
<description>Condensor out temperature, BT12</description>
</channel>
<channel id="40020" typeId="type-temperature">
<label>EB100-BT16 Evaporator Temp</label>
<description>Evaporator Temp (BT16)</description>
</channel>
<channel id="43136" typeId="type-frequency-scale10">
<label>Compressor Frequency, Actual</label>
<description>The compressor frequency the compressor is currently running at</description>
</channel>
<channel id="43122" typeId="type-frequency-unscaled">
<label>Compr. Current Min.freq.</label>
<description>The current minimum frequency of the compressor</description>
</channel>
<channel id="43123" typeId="type-frequency-unscaled">
<label>Compr. Current Max.freq.</label>
<description>The current maximum frequency of the compressor</description>
</channel>
<channel id="43066" typeId="type-time-unscaled">
<label>Defrosting Time</label>
<description>Defrosting time, no defrosting heater in the product</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="f730-airsupply">
<label>Air Supply/Exhaust Channels</label>
<channels>
<channel id="10001" typeId="type-speed-percent">
<label>Fan Speed Current</label>
<description>The current fan speed</description>
</channel>
<channel id="40025" typeId="type-temperature">
<label>BT20 Exhaust Air Temp. 1</label>
<description>Exhaust Air Temperature (BT20)</description>
</channel>
<channel id="40026" typeId="type-temperature">
<label>BT21 Vented Air Temp. 1</label>
<description>Vented Air Temperature (BT21)</description>
</channel>
<channel id="43124" typeId="type-number-scale10">
<label>Airflow Ref.</label>
<description>Reference value for the airflow.</description>
</channel>
<channel id="41026" typeId="type-number-unscaled">
<label>EB100-Adjusted BS1 Air Flow</label>
<description>Adjusted BS1 Air Flow (BT100)</description>
</channel>
<channel id="43125" typeId="type-number-unscaled">
<label>Airflow Reduction</label>
<description>Airflow Reduction</description>
</channel>
<channel id="40919" typeId="type-number-unscaled">
<label>Air Mix</label>
<description>Air Mix</description>
</channel>
<channel id="40101" typeId="type-temperature">
<label>BT28 Airmix Temp</label>
<description>External airmix temperature BT28</description>
</channel>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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="f730" extensible="type-number-unscaled,type-number-scale10,type-number-scale100">
<label>Nibe F730</label>
<description>Nibe F730 heat pump connected through Nibe UpLink</description>
<channel-groups>
<channel-group typeId="base-base" id="base"/>
<channel-group typeId="base-hotwater" id="hotwater"/>
<channel-group typeId="f730-compressor" id="compressor"/>
<channel-group typeId="f730-airsupply" id="airsupply"/>
</channel-groups>
<config-description-ref uri="thing-type:nibeuplink:web"/>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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">
<channel-group-type id="f750-compressor">
<label>Compressor Channels</label>
<channels>
<channel id="43181" typeId="type-speed-percent">
<label>Chargepump Speed</label>
<description>Chargepump Speed</description>
</channel>
<channel id="43424" typeId="type-time-unscaled">
<label>Tot. HW Op.time Compr. EB100-EP14</label>
<description>Total compressor operation time in hot water mode</description>
</channel>
<channel id="43420" typeId="type-time-unscaled">
<label>Tot. Op.time Compr. EB100-EP14</label>
<description>Total compressor operation time</description>
</channel>
<channel id="43416" typeId="type-number-unscaled">
<label>Compressor Starts EB100-EP14</label>
<description>Number of compressor starts</description>
</channel>
<channel id="40022" typeId="type-temperature">
<label>EB100-EP14-BT17 Suction</label>
<description>Suction temperature, BT17</description>
</channel>
<channel id="40019" typeId="type-temperature">
<label>EB100-EP14-BT15 Liquid Line</label>
<description>Liquid line temperature, BT15</description>
</channel>
<channel id="40018" typeId="type-temperature">
<label>EB100-EP14-BT14 Hot Gas Temp</label>
<description>Hot gas temperature, BT14</description>
</channel>
<channel id="40017" typeId="type-temperature">
<label>EB100-EP14-BT12 Condensor Out</label>
<description>Condensor out temperature, BT12</description>
</channel>
<channel id="40020" typeId="type-temperature">
<label>EB100-BT16 Evaporator Temp</label>
<description>Evaporator Temp (BT16)</description>
</channel>
<channel id="43136" typeId="type-frequency-scale10">
<label>Compressor Frequency, Actual</label>
<description>The compressor frequency the compressor is currently running at</description>
</channel>
<channel id="43122" typeId="type-frequency-unscaled">
<label>Compr. Current Min.freq.</label>
<description>The current minimum frequency of the compressor</description>
</channel>
<channel id="43123" typeId="type-frequency-unscaled">
<label>Compr. Current Max.freq.</label>
<description>The current maximum frequency of the compressor</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="f750-airsupply">
<label>Air Supply/Exhaust Channels</label>
<channels>
<channel id="40025" typeId="type-temperature">
<label>BT20 Exhaust Air Temp. 1</label>
<description>Exhaust Air Temperature (BT20)</description>
</channel>
<channel id="40026" typeId="type-temperature">
<label>BT21 Vented Air Temp. 1</label>
<description>Vented Air Temperature (BT21)</description>
</channel>
<channel id="43124" typeId="type-number-scale10">
<label>Airflow Ref.</label>
<description>Reference value for the airflow.</description>
</channel>
<channel id="41026" typeId="type-number-unscaled">
<label>EB100-Adjusted BS1 Air Flow</label>
<description>Adjusted BS1 Air Flow (BT100)</description>
</channel>
<channel id="47260" typeId="rwtype-fan-speed">
<label>Selected Fan Speed</label>
<description>Currently selected fan speed</description>
<properties>
<property name="writeApiUrl">/Manage/1.2</property>
<property name="validationExpression">[01234]</property>
</properties>
</channel>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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="f750" extensible="type-number-unscaled,type-number-scale10,type-number-scale100">
<label>Nibe F750</label>
<description>Nibe F750 heat pump connected through Nibe UpLink</description>
<channel-groups>
<channel-group typeId="base-base" id="base"/>
<channel-group typeId="base-hotwater" id="hotwater"/>
<channel-group typeId="f750-compressor" id="compressor"/>
<channel-group typeId="f750-airsupply" id="airsupply"/>
</channel-groups>
<config-description-ref uri="thing-type:nibeuplink:web"/>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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">
<channel-type id="type-number-unscaled">
<item-type>Number</item-type>
<label>Unnamed Number</label>
<state pattern="%d" readOnly="true">
</state>
</channel-type>
<channel-type id="type-number-scale10">
<item-type>Number</item-type>
<label>Unnamed Number (0.1)</label>
<state pattern="%.1f" readOnly="true">
</state>
</channel-type>
<channel-type id="type-number-scale100">
<item-type>Number</item-type>
<label>Unnamed Number (0.01)</label>
<state pattern="%.2f" readOnly="true">
</state>
</channel-type>
<channel-type id="type-switch">
<item-type>Switch</item-type>
<label>Unnamed Switch</label>
<state readOnly="true"></state>
</channel-type>
<channel-type id="type-temperature">
<item-type>Number:Temperature</item-type>
<label>Unnamed Temperature</label>
<state pattern="%.1f %unit%" readOnly="true">
</state>
</channel-type>
<channel-type id="type-flow">
<item-type>Number:Dimensionless</item-type>
<label>Unnamed Flow</label>
<state pattern="%.1f l/min" readOnly="true">
</state>
</channel-type>
<channel-type id="type-electric-current">
<item-type>Number:ElectricCurrent</item-type>
<label>Unnamed Current</label>
<state pattern="%.1f %unit%" readOnly="true">
</state>
</channel-type>
<channel-type id="type-time-unscaled">
<item-type>Number:Time</item-type>
<label>Unnamed Time</label>
<state pattern="%d %unit%" readOnly="true">
</state>
</channel-type>
<channel-type id="type-time-scale10">
<item-type>Number:Time</item-type>
<label>Unnamed Time</label>
<state pattern="%.1f %unit%" readOnly="true">
</state>
</channel-type>
<channel-type id="type-frequency-unscaled">
<item-type>Number:Frequency</item-type>
<label>Unnamed Frequency</label>
<state pattern="%d %unit%" readOnly="true">
</state>
</channel-type>
<channel-type id="type-frequency-scale10">
<item-type>Number:Frequency</item-type>
<label>Unnamed Frequency</label>
<state pattern="%d %unit%" readOnly="true">
</state>
</channel-type>
<channel-type id="type-power">
<item-type>Number:Power</item-type>
<label>Unnamed Power</label>
<state pattern="%.2f %unit%" readOnly="true">
</state>
</channel-type>
<channel-type id="type-energy">
<item-type>Number:Energy</item-type>
<label>Unnamed Energy</label>
<state pattern="%.1f %unit%" readOnly="true">
</state>
</channel-type>
<channel-type id="type-pressure">
<item-type>Number:Pressure</item-type>
<label>Unnamed Pressure</label>
<state pattern="%.1f %unit%" readOnly="true">
</state>
</channel-type>
<channel-type id="type-speed-percent">
<item-type>Number:Dimensionless</item-type>
<label>Unnamed Speed</label>
<state pattern="%d %%" readOnly="true">
</state>
</channel-type>
<channel-type id="type-defrosting-state">
<item-type>Number</item-type>
<label>Defrosting State</label>
<state readOnly="true">
<options>
<option value="0">No</option>
<option value="1">Active</option>
<option value="2">Passive</option>
</options>
</state>
</channel-type>
<channel-type id="type-hpac-state">
<item-type>Number</item-type>
<label>HPAC State</label>
<state pattern="%d" readOnly="true">
<options>
<option value="10">Off</option>
<option value="20">Wait</option>
<option value="30">Passive</option>
<option value="40">PassiveWait</option>
<option value="50">Active</option>
<option value="60">ActiveWait</option>
<option value="70">ActiveProtWait</option>
</options>
</state>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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">
<channel-type id="rwtype-heat-offset">
<item-type>Number</item-type>
<label>Heat Offset</label>
<state min="-10" max="10" step="1" pattern="%d" readOnly="false">
</state>
</channel-type>
<channel-type id="rwtype-start-cooling">
<item-type>Number</item-type>
<label>Start Temperature Cooling</label>
<state min="15" max="40" step="1" pattern="%d °C" readOnly="false">
</state>
</channel-type>
<channel-type id="rwtype-stop-heating">
<item-type>Number</item-type>
<label>Stop Temperature Heating</label>
<state min="0" max="25" step="1" pattern="%d °C" readOnly="false">
</state>
</channel-type>
<channel-type id="rwtype-stop-add-heating">
<item-type>Number</item-type>
<label>Stop Temperature Additive</label>
<state min="-20" max="10" step="1" pattern="%d °C" readOnly="false">
</state>
</channel-type>
<channel-type id="rwtype-filter-time">
<item-type>Number</item-type>
<label>Outdoor Filter Time</label>
<state min="1" max="48" step="1" pattern="%d h" readOnly="false">
</state>
</channel-type>
<channel-type id="rwtype-room-sensor-factor">
<item-type>Number</item-type>
<label>Room Sensor Factor</label>
<state min="0" max="6" step="1" pattern="%.1f" readOnly="false">
</state>
</channel-type>
<channel-type id="rwtype-switch">
<item-type>Switch</item-type>
<label>Unnamed Switch</label>
<state readOnly="false"></state>
</channel-type>
<channel-type id="rwtype-degree-minutes">
<item-type>Number</item-type>
<label>Unnamed Degree Minutes</label>
<state min="-30000" max="30000" step="1" pattern="%d °*min" readOnly="false">
</state>
</channel-type>
<channel-type id="rwtype-hw-lux">
<item-type>Number</item-type>
<label>Temporary Lux</label>
<state readOnly="false">
<options>
<option value="0">Off</option>
<option value="1">3h</option>
<option value="2">6h</option>
<option value="3">12h</option>
<option value="4">One time</option>
</options>
</state>
</channel-type>
<channel-type id="rwtype-hw-mode">
<item-type>Number</item-type>
<label>Hot Water Mode</label>
<state readOnly="false">
<options>
<option value="0">Economy</option>
<option value="1">Normal</option>
<option value="2">Luxury</option>
</options>
</state>
</channel-type>
<channel-type id="rwtype-fan-speed">
<item-type>Number</item-type>
<label>Selected Fan Speed</label>
<state readOnly="false">
<options>
<option value="0">normal</option>
<option value="1">speed 1</option>
<option value="2">speed 2</option>
<option value="3">speed 3</option>
<option value="4">speed 4</option>
</options>
</state>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,189 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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">
<channel-group-type id="vvm310-general">
<label>General Channels</label>
<channels>
<channel id="44270" typeId="type-temperature">
<label>Calc. Cooling Supply S1</label>
<description>Calculated supply temperature in cooling mode for the climate system</description>
</channel>
<channel id="40121" typeId="type-temperature">
<label>BT63 Add Supply Temp</label>
<description>Supply Temp at internal additional heater (BT63)</description>
</channel>
<channel id="44302" typeId="type-energy">
<label>Heat Meter - Cooling Cpr EP14</label>
<description>Accumulated energy production as calculated by the heat meter</description>
</channel>
<channel id="47011" typeId="rwtype-heat-offset">
<label>Heat Offset S1</label>
<description>Offset of the heat curve, see manual for more information</description>
<properties>
<property name="writeApiUrl">/Manage/1.9.1.1-S1</property>
<property name="validationExpression">[-1]*[0-9]</property>
</properties>
</channel>
<channel id="47394" typeId="rwtype-switch">
<label>Use Room Sensor S1</label>
<description>When activated the system uses the room sensor 0=Off 1=On</description>
<properties>
<property name="writeApiUrl">/Manage/1.9.4</property>
<property name="validationExpression">.*</property>
<property name="offMapping">0</property>
<property name="onMapping">1</property>
</properties>
</channel>
<channel id="47402" typeId="rwtype-room-sensor-factor">
<label>Room Sensor Factor S1</label>
<description>Setting of how much the difference between set and actual room temperature should affect the supply
temperature.</description>
<properties>
<property name="writeApiUrl">/Manage/1.9.4</property>
<property name="validationExpression">[0123456]*[0-9]</property>
</properties>
</channel>
<channel id="48793" typeId="rwtype-room-sensor-factor">
<label>Room Sensor Cool Factor S1</label>
<description>Setting of how much the difference between set and actual room temperature should affect the supply
temperature in cooling mode.</description>
<properties>
<property name="writeApiUrl">/Manage/1.9.4</property>
<property name="validationExpression">[0123456]*[0-9]</property>
</properties>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="vvm310-compressor">
<label>Compressor Channels</label>
<channels>
<channel id="44362" typeId="type-temperature">
<label>EB101-EP14-BT28 Outdoor Temp</label>
<description>Current outdoor temperature, BT28</description>
</channel>
<channel id="44396" typeId="type-speed-percent">
<label>EB101 Speed Charge Pump</label>
<description>Speed Charge Pump</description>
</channel>
<channel id="44703" typeId="type-defrosting-state">
<label>EB101-EP14 Defrosting Outdoor Unit</label>
<description>Defrosting state of the outdoor unit</description>
</channel>
<channel id="44073" typeId="type-time-unscaled">
<label>EB101-EP14 Tot. HW Op.time Compr</label>
<description>Total operation time of compressor in hotwater mode</description>
</channel>
<channel id="40737" typeId="type-time-unscaled">
<label>EB101-EP14 Tot. Cooling Op.time Compr</label>
<description>Total operation time of compressor in cooling mode</description>
</channel>
<channel id="44071" typeId="type-time-unscaled">
<label>EB101-EP14 Tot. Op.time Compr</label>
<description>Total operation time of compressor</description>
</channel>
<channel id="44069" typeId="type-number-unscaled">
<label>EB101-EP14 Compressor Starts</label>
<description>Total compressor starts</description>
</channel>
<channel id="44061" typeId="type-temperature">
<label>EB101-EP14-BT17 Suction</label>
<description>Suction temperature, BT17</description>
</channel>
<channel id="44060" typeId="type-temperature">
<label>EB101-EP14-BT15 Liquid Line</label>
<description>Liquid line temperature, BT15</description>
</channel>
<channel id="44059" typeId="type-temperature">
<label>EB101-EP14-BT14 Hot Gas Temp</label>
<description>Hot gas temperature, BT14</description>
</channel>
<channel id="44058" typeId="type-temperature">
<label>EB101-EP14-BT12 Condensor Out</label>
<description>Condensor temperature, BT12</description>
</channel>
<channel id="44055" typeId="type-temperature">
<label>EB101-EP14-BT3 Return Temp.</label>
<description>Return temperature, BT3</description>
</channel>
<channel id="44363" typeId="type-temperature">
<label>EB101-EP14-BT16 Evaporator</label>
<description>Evaporator temperature, BT16</description>
</channel>
<channel id="44699" typeId="type-pressure">
<label>EB101-EP14-BT4 Pressure Sensor</label>
<description>Pressure Sensor (BT4)</description>
</channel>
<channel id="40782" typeId="type-frequency-unscaled">
<label>EB101 Cpr Frequency Desired F2040</label>
<description>The desired frequency as shown in service info</description>
</channel>
<channel id="44701" typeId="type-frequency-scale10">
<label>EB101-EP14 Actual Cpr Frequency Outdoor Unit</label>
<description>Actual compressor frequency of the outdoor unit</description>
</channel>
<channel id="44702" typeId="type-switch">
<label>EB101-EP14 Protection Status Register Outdoor Unit</label>
<description>rotection status register of the outdoor unit</description>
<properties>
<property name="offMapping">0</property>
<property name="onMapping">1</property>
</properties>
</channel>
<channel id="44700" typeId="type-pressure">
<label>EB101-EP14 Low Pressure Sensor Outdoor Unit</label>
<description>Low pressure sensor outdoor unit</description>
</channel>
<channel id="44457" typeId="type-number-unscaled">
<label>EB101-EP14 Compressor State</label>
<description>Compressor state</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="vvm310-airsupply">
<label>Air Supply/Exhaust Channels</label>
<channels>
<channel id="40025" typeId="type-temperature">
<label>BT20 Exhaust Air Temp. 1</label>
<description>Exhaust Air Temperature (BT20)</description>
</channel>
<channel id="40026" typeId="type-temperature">
<label>BT21 Vented Air Temp. 1</label>
<description>Vented Air Temperature (BT21)</description>
</channel>
<channel id="40075" typeId="type-temperature">
<label>BT22 Supply Air Temp.</label>
<description>Supply Air Temperature (BT22)</description>
</channel>
<channel id="40183" typeId="type-temperature">
<label>AZ30-BT23 Outdoor Temp. ERS</label>
<description>Outdoor Temperature (BT23)</description>
</channel>
<channel id="40311" typeId="type-speed-percent">
<label>External ERS Accessory GQ2 Speed</label>
<description>Indicates the speed of the GQ2 fan speed on the ERS accessory.</description>
</channel>
<channel id="40312" typeId="type-speed-percent">
<label>External ERS Accessory GQ3 Speed</label>
<description>Indicates the speed of the GQ3 fan speed on the ERS accessory.</description>
</channel>
<channel id="40942" typeId="type-switch">
<label>External ERS Accessory Block Status</label>
<description>Indicates if the ERS accessory is externaly blocked.</description>
<properties>
<property name="offMapping">0</property>
<property name="onMapping">1</property>
</properties>
</channel>
<channel id="47260" typeId="rwtype-fan-speed">
<label>Selected Fan Speed</label>
<description>Currently selected fan speed</description>
<properties>
<property name="writeApiUrl">/Manage/1.2</property>
<property name="validationExpression">[01234]</property>
</properties>
</channel>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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="vvm310" extensible="type-number-unscaled,type-number-scale10,type-number-scale100">
<label>Nibe VVM310 / VVM500</label>
<description>Nibe VVM310 / VVM500 heat pump connected through Nibe UpLink</description>
<channel-groups>
<channel-group typeId="base-base" id="base"/>
<channel-group typeId="base-hotwater" id="hotwater"/>
<channel-group typeId="vvm310-general" id="general"/>
<channel-group typeId="vvm310-compressor" id="compressor"/>
<channel-group typeId="vvm310-airsupply" id="airsupply"/>
</channel-groups>
<config-description-ref uri="thing-type:nibeuplink:web"/>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,221 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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">
<channel-group-type id="vvm320-general">
<label>General Channels</label>
<channels>
<channel id="44270" typeId="type-temperature">
<label>Calc. Cooling Supply S1</label>
<description>Calculated supply temperature in cooling mode for the climate system</description>
</channel>
<channel id="40121" typeId="type-temperature">
<label>BT63 Add Supply Temp</label>
<description>Supply Temp at internal additional heater (BT63)</description>
</channel>
<channel id="44302" typeId="type-energy">
<label>Heat Meter - Cooling Cpr EP14</label>
<description>Accumulated energy production as calculated by the heat meter</description>
</channel>
<channel id="47011" typeId="rwtype-heat-offset">
<label>Heat Offset S1</label>
<description>Offset of the heat curve, see manual for more information</description>
<properties>
<property name="writeApiUrl">/Manage/1.9.1.1-S1</property>
<property name="validationExpression">[-1]*[0-9]</property>
</properties>
</channel>
<channel id="47394" typeId="rwtype-switch">
<label>Use Room Sensor S1</label>
<description>When activated the system uses the room sensor 0=Off 1=On</description>
<properties>
<property name="writeApiUrl">/Manage/1.9.4</property>
<property name="validationExpression">.*</property>
<property name="offMapping">0</property>
<property name="onMapping">1</property>
</properties>
</channel>
<channel id="47402" typeId="rwtype-room-sensor-factor">
<label>Room Sensor Factor S1</label>
<description>Setting of how much the difference between set and actual room temperature should affect the supply
temperature.</description>
<properties>
<property name="writeApiUrl">/Manage/1.9.4</property>
<property name="validationExpression">[0123456]*[0-9]</property>
</properties>
</channel>
<channel id="48793" typeId="rwtype-room-sensor-factor">
<label>Room Sensor Cool Factor S1</label>
<description>Setting of how much the difference between set and actual room temperature should affect the supply
temperature in cooling mode.</description>
<properties>
<property name="writeApiUrl">/Manage/1.9.4</property>
<property name="validationExpression">[0123456]*[0-9]</property>
</properties>
</channel>
<channel id="47374" typeId="rwtype-start-cooling">
<label>Start Temperature Cooling</label>
<description>Start Temperature Cooling in Auto mode</description>
<properties>
<property name="writeApiUrl">/Manage/4.9.2</property>
<property name="validationExpression">[0-9]*[0-9]</property>
</properties>
</channel>
<channel id="47375" typeId="rwtype-stop-heating">
<label>Stop Temperature Heating</label>
<description>Stop Temperature Heating in Auto mode</description>
<properties>
<property name="writeApiUrl">/Manage/4.9.2</property>
<property name="validationExpression">[0-9]*[0-9]</property>
</properties>
</channel>
<channel id="47376" typeId="rwtype-stop-add-heating">
<label>Stop Temperature Additive</label>
<description>Stop Temperature Additive heater in Auto mode</description>
<properties>
<property name="writeApiUrl">/Manage/4.9.2</property>
<property name="validationExpression">[0-9]*[0-9]</property>
</properties>
</channel>
<channel id="47377" typeId="rwtype-filter-time">
<label>Outdoor Filter Time</label>
<description>Outdoor Filter Time in Auto mode</description>
<properties>
<property name="writeApiUrl">/Manage/4.9.2</property>
<property name="validationExpression">[0-4]*[0-9]</property>
</properties>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="vvm320-compressor">
<label>Compressor Channels</label>
<channels>
<channel id="44362" typeId="type-temperature">
<label>EB101-EP14-BT28 Outdoor Temp</label>
<description>Current outdoor temperature, BT28</description>
</channel>
<channel id="44396" typeId="type-speed-percent">
<label>EB101 Speed Charge Pump</label>
<description>Speed Charge Pump</description>
</channel>
<channel id="44703" typeId="type-defrosting-state">
<label>EB101-EP14 Defrosting Outdoor Unit</label>
<description>Defrosting state of the outdoor unit</description>
</channel>
<channel id="44073" typeId="type-time-unscaled">
<label>EB101-EP14 Tot. HW Op.time Compr</label>
<description>Total operation time of compressor in hotwater mode</description>
</channel>
<channel id="40737" typeId="type-time-unscaled">
<label>EB101-EP14 Tot. Cooling Op.time Compr</label>
<description>Total operation time of compressor in cooling mode</description>
</channel>
<channel id="44071" typeId="type-time-unscaled">
<label>EB101-EP14 Tot. Op.time Compr</label>
<description>Total operation time of compressor</description>
</channel>
<channel id="44069" typeId="type-number-unscaled">
<label>EB101-EP14 Compressor Starts</label>
<description>Total compressor starts</description>
</channel>
<channel id="44061" typeId="type-temperature">
<label>EB101-EP14-BT17 Suction</label>
<description>Suction temperature, BT17</description>
</channel>
<channel id="44060" typeId="type-temperature">
<label>EB101-EP14-BT15 Liquid Line</label>
<description>Liquid line temperature, BT15</description>
</channel>
<channel id="44059" typeId="type-temperature">
<label>EB101-EP14-BT14 Hot Gas Temp</label>
<description>Hot gas temperature, BT14</description>
</channel>
<channel id="44058" typeId="type-temperature">
<label>EB101-EP14-BT12 Condensor Out</label>
<description>Condensor temperature, BT12</description>
</channel>
<channel id="44055" typeId="type-temperature">
<label>EB101-EP14-BT3 Return Temp.</label>
<description>Return temperature, BT3</description>
</channel>
<channel id="44363" typeId="type-temperature">
<label>EB101-EP14-BT16 Evaporator</label>
<description>Evaporator temperature, BT16</description>
</channel>
<channel id="44699" typeId="type-pressure">
<label>EB101-EP14-BT4 Pressure Sensor</label>
<description>Pressure Sensor (BT4)</description>
</channel>
<channel id="40782" typeId="type-frequency-unscaled">
<label>EB101 Cpr Frequency Desired F2040</label>
<description>The desired frequency as shown in service info</description>
</channel>
<channel id="44701" typeId="type-frequency-scale10">
<label>EB101-EP14 Actual Cpr Frequency Outdoor Unit</label>
<description>Actual compressor frequency of the outdoor unit</description>
</channel>
<channel id="44702" typeId="type-switch">
<label>EB101-EP14 Protection Status Register Outdoor Unit</label>
<description>rotection status register of the outdoor unit</description>
<properties>
<property name="offMapping">0</property>
<property name="onMapping">1</property>
</properties>
</channel>
<channel id="44700" typeId="type-pressure">
<label>EB101-EP14 Low Pressure Sensor Outdoor Unit</label>
<description>Low pressure sensor outdoor unit</description>
</channel>
<channel id="44457" typeId="type-number-unscaled">
<label>EB101-EP14 Compressor State</label>
<description>Compressor state</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="vvm320-airsupply">
<label>Air Supply/Exhaust Channels</label>
<channels>
<channel id="40025" typeId="type-temperature">
<label>BT20 Exhaust Air Temp. 1</label>
<description>Exhaust Air Temperature (BT20)</description>
</channel>
<channel id="40026" typeId="type-temperature">
<label>BT21 Vented Air Temp. 1</label>
<description>Vented Air Temperature (BT21)</description>
</channel>
<channel id="40075" typeId="type-temperature">
<label>BT22 Supply Air Temp.</label>
<description>Supply Air Temperature (BT22)</description>
</channel>
<channel id="40183" typeId="type-temperature">
<label>AZ30-BT23 Outdoor Temp. ERS</label>
<description>Outdoor Temperature (BT23)</description>
</channel>
<channel id="40311" typeId="type-speed-percent">
<label>External ERS Accessory GQ2 Speed</label>
<description>Indicates the speed of the GQ2 fan speed on the ERS accessory.</description>
</channel>
<channel id="40312" typeId="type-speed-percent">
<label>External ERS Accessory GQ3 Speed</label>
<description>Indicates the speed of the GQ3 fan speed on the ERS accessory.</description>
</channel>
<channel id="40942" typeId="type-switch">
<label>External ERS Accessory Block Status</label>
<description>Indicates if the ERS accessory is externaly blocked.</description>
<properties>
<property name="offMapping">0</property>
<property name="onMapping">1</property>
</properties>
</channel>
<channel id="47260" typeId="rwtype-fan-speed">
<label>Selected Fan Speed</label>
<description>Currently selected fan speed</description>
<properties>
<property name="writeApiUrl">/Manage/1.2</property>
<property name="validationExpression">[01234]</property>
</properties>
</channel>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="nibeuplink"
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="vvm320" extensible="type-number-unscaled,type-number-scale10,type-number-scale100">
<label>Nibe VVM320 / VVM325</label>
<description>Nibe VVM320 / VVM325 heat pump connected through Nibe UpLink</description>
<channel-groups>
<channel-group typeId="base-base" id="base"/>
<channel-group typeId="base-hotwater" id="hotwater"/>
<channel-group typeId="vvm320-general" id="general"/>
<channel-group typeId="vvm320-compressor" id="compressor"/>
<channel-group typeId="vvm320-airsupply" id="airsupply"/>
</channel-groups>
<config-description-ref uri="thing-type:nibeuplink:web"/>
</thing-type>
</thing:thing-descriptions>