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.pixometer-${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-pixometer" description="pixometer Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.pixometer/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,170 @@
/**
* 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.pixometer.handler;
import static org.openhab.binding.pixometer.internal.PixometerBindingConstants.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.pixometer.internal.config.PixometerAccountConfiguration;
import org.openhab.core.io.net.http.HttpUtil;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
* The {@link AccountHandler} is responsible for handling the api connection and authorization (including token
* refresh)
*
* @author Jerome Luckenbach - Initial contribution
*/
@NonNullByDefault
public class AccountHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private static final int TOKEN_MIN_DIFF_MS = (int) TimeUnit.DAYS.toMillis(2);
private final JsonParser jsonParser = new JsonParser();
private @NonNullByDefault({}) String authToken;
private int refreshInterval;
private long tokenExpiryDate;
public AccountHandler(Bridge bridge) {
super(bridge);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
// Nothing to handle here currently
}
@Override
public void initialize() {
logger.debug("Initialize Pixometer Accountservice");
PixometerAccountConfiguration config = getConfigAs(PixometerAccountConfiguration.class);
setRefreshInterval(config.refresh);
String user = config.user;
String password = config.password;
String scope = "read"; // Prepared for config value
// Check expiry date every Day and obtain new access token if difference is less then or equal to 2 days
scheduler.scheduleWithFixedDelay(() -> {
logger.debug("Checking if new access token is needed...");
try {
long difference = getTokenExpiryDate() - System.nanoTime();
if (difference <= TOKEN_MIN_DIFF_MS) {
obtainAuthTokenAndExpiryDate(user, password, scope);
}
} catch (RuntimeException r) {
logger.debug("Could not check token expiry date for Thing {}: {}", getThing().getUID(), r.getMessage(),
r);
}
}, 1, TimeUnit.DAYS.toMinutes(1), TimeUnit.MINUTES);
logger.debug("Refresh job scheduled to run every days. for '{}'", getThing().getUID());
}
@Override
public void updateStatus(ThingStatus status) {
super.updateStatus(status);
}
/**
* Request auth token with read or write access.
* (Write access is prepared for a possible later usage for updating meters.)
*
* @param user The username to use
* @param password The corresponding password
* @param scope The granted scope on the api for the binding
*/
private void obtainAuthTokenAndExpiryDate(String user, String password, String scope) {
try {
String url = API_BASE_URL + "v1/access-token/";
Properties urlHeader = (Properties) new Properties().put("CONTENT-TYPE", "application/json");
JsonObject httpBody = new JsonObject();
httpBody.addProperty("username", user);
httpBody.addProperty("password", password);
httpBody.addProperty("scope", scope);
InputStream content = new ByteArrayInputStream(httpBody.toString().getBytes(StandardCharsets.UTF_8));
String urlResponse = HttpUtil.executeUrl("POST", url, urlHeader, content, "application/json", 2000);
JsonObject responseJson = (JsonObject) jsonParser.parse(urlResponse);
if (responseJson.has(AUTH_TOKEN)) {
// Store the expire date for automatic token refresh
int expiresIn = Integer.parseInt(responseJson.get("expires_in").toString());
setTokenExpiryDate(TimeUnit.SECONDS.toNanos(expiresIn));
setAuthToken(responseJson.get(AUTH_TOKEN).toString().replaceAll("\"", ""));
updateStatus(ThingStatus.ONLINE);
return;
}
String errorMsg = String.format("Invalid Api Response ( %s )", responseJson);
throw new IOException(errorMsg);
} catch (IOException e) {
String errorMsg = String.format(
"Could not obtain auth token. Please check your configured account credentials. %s %s",
this.getThing().getUID(), e.getMessage());
logger.debug(errorMsg, e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, errorMsg);
}
}
/**
* Getters and Setters
*/
public String getAuthToken() {
return authToken;
}
private void setAuthToken(String authToken) {
this.authToken = authToken;
}
public int getRefreshInterval() {
return refreshInterval;
}
private void setRefreshInterval(int refreshInterval) {
this.refreshInterval = refreshInterval;
}
public long getTokenExpiryDate() {
return tokenExpiryDate;
}
private void setTokenExpiryDate(long expiresIn) {
this.tokenExpiryDate = System.nanoTime() + expiresIn;
}
}

View File

@@ -0,0 +1,308 @@
/**
* 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.pixometer.handler;
import static org.openhab.binding.pixometer.internal.PixometerBindingConstants.*;
import java.io.IOException;
import java.time.Duration;
import java.util.Properties;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Volume;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.pixometer.internal.config.PixometerMeterConfiguration;
import org.openhab.binding.pixometer.internal.config.ReadingInstance;
import org.openhab.binding.pixometer.internal.data.MeterState;
import org.openhab.binding.pixometer.internal.serializer.CustomReadingInstanceDeserializer;
import org.openhab.core.cache.ExpiringCache;
import org.openhab.core.io.net.http.HttpUtil;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.SmartHomeUnits;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
* The {@link MeterHandler} is responsible for handling data and measurements of a meter thing
*
* @author Jerome Luckenbach - Initial contribution
*/
@NonNullByDefault
public class MeterHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(MeterHandler.class);
private static final String API_VERSION = "v1";
private static final String API_METER_ENDPOINT = "meters";
private static final String API_READINGS_ENDPOINT = "readings";
private final GsonBuilder gsonBuilder = new GsonBuilder().registerTypeAdapter(ReadingInstance.class,
new CustomReadingInstanceDeserializer());
private final Gson gson = gsonBuilder.create();
private final JsonParser jsonParser = new JsonParser();
private @NonNullByDefault({}) String resourceID;
private @NonNullByDefault({}) String meterID;
private @NonNullByDefault({}) ExpiringCache<@Nullable MeterState> cache;
private @Nullable ScheduledFuture<?> pollingJob;
public MeterHandler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
try {
if (command instanceof RefreshType) {
updateMeter(channelUID, cache.getValue());
} else {
logger.debug("The pixometer binding is read-only and can not handle command {}", command);
}
} catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
}
@Override
public void initialize() {
logger.debug("Initializing Pixometer handler '{}'", getThing().getUID());
updateStatus(ThingStatus.UNKNOWN);
PixometerMeterConfiguration config = getConfigAs(PixometerMeterConfiguration.class);
setRessourceID(config.resourceId);
cache = new ExpiringCache<>(Duration.ofMinutes(60), this::refreshCache);
Bridge b = this.getBridge();
if (b == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not find bridge (pixometer config). Did you choose one?");
return;
}
obtainMeterId();
// Start polling job with the interval, that has been set up in the bridge
int pollingPeriod = Integer.parseInt(b.getConfiguration().get(CONFIG_BRIDGE_REFRESH).toString());
pollingJob = scheduler.scheduleWithFixedDelay(() -> {
logger.debug("Try to refresh meter data");
try {
updateMeter(cache.getValue());
} catch (RuntimeException r) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
}
}, 2, pollingPeriod, TimeUnit.MINUTES);
logger.debug("Refresh job scheduled to run every {} minutes for '{}'", pollingPeriod, getThing().getUID());
}
/**
* @return returns the auth token or null for error handling if the bridge was not found.
*/
private @Nullable String getTokenFromBridge() {
Bridge b = this.getBridge();
if (b == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not find bridge (pixometer config). Did you choose one?");
return null;
}
return new StringBuilder("Bearer ").append(((AccountHandler) b.getHandler()).getAuthToken()).toString();
}
@Override
public void dispose() {
if (pollingJob != null) {
pollingJob.cancel(true);
}
super.dispose();
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
logger.debug("Bridge Status updated to {} for device: {}", bridgeStatusInfo.getStatus(), getThing().getUID());
if (bridgeStatusInfo.getStatus() != ThingStatus.ONLINE) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, bridgeStatusInfo.getDescription());
}
}
/**
* Requests the corresponding meter data and stores the meterId internally for later usage
*
* @param token The current active auth token
*/
private void obtainMeterId() {
try {
String token = getTokenFromBridge();
if (token == null) {
throw new IOException(
"Auth token has not been delivered.\n API request can't get executed without authentication.");
}
String url = getApiString(API_METER_ENDPOINT);
Properties urlHeader = new Properties();
urlHeader.put("CONTENT-TYPE", "application/json");
urlHeader.put("Authorization", token);
String urlResponse = HttpUtil.executeUrl("GET", url, urlHeader, null, null, 2000);
JsonObject responseJson = (JsonObject) jsonParser.parse(urlResponse);
if (responseJson.has("meter_id")) {
setMeterID(responseJson.get("meter_id").toString());
updateStatus(ThingStatus.ONLINE);
return;
}
String errorMsg = String.format("Invalid Api Response ( %s )", responseJson);
throw new IOException(errorMsg);
} catch (IOException e) {
String errorMsg = String.format("Could not initialize Thing ( %s ). %s", this.getThing().getUID(),
e.getMessage());
logger.debug(errorMsg, e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, errorMsg);
}
}
/**
* Checks if a channel is linked and redirects to the updateMeter method if link is existing
*
* @param channelUID the channel requested for refresh
* @param meterState a meterState instance with current values
*/
private void updateMeter(ChannelUID channelUID, @Nullable MeterState meterState) throws IOException {
if (!isLinked(channelUID)) {
throw new IOException("Channel is not linked.");
}
updateMeter(meterState);
}
/**
* updates all corresponding channels
*
* @param token The current active access token
*/
private void updateMeter(@Nullable MeterState meterState) {
try {
if (meterState == null) {
throw new IOException("Meter state has not been delivered to update method. Can't update channels.");
}
ThingTypeUID thingtype = getThing().getThingTypeUID();
if (THING_TYPE_ENERGYMETER.equals(thingtype)) {
QuantityType<Energy> state = new QuantityType<>(meterState.getReadingValue(),
SmartHomeUnits.KILOWATT_HOUR);
updateState(CHANNEL_LAST_READING_VALUE, state);
}
if (thingtype.equals(THING_TYPE_GASMETER) || thingtype.equals(THING_TYPE_WATERMETER)) {
QuantityType<Volume> state = new QuantityType<>(meterState.getReadingValue(), SIUnits.CUBIC_METRE);
updateState(CHANNEL_LAST_READING_VALUE, state);
}
updateState(CHANNEL_LAST_READING_DATE, meterState.getLastReadingDate());
updateState(CHANNEL_LAST_REFRESH_DATE, meterState.getLastRefreshTime());
} catch (IOException e) {
logger.debug("Exception while updating Meter {}: {}", getThing().getUID(), e.getMessage(), e);
}
}
private @Nullable MeterState refreshCache() {
try {
String url = getApiString(API_READINGS_ENDPOINT);
Properties urlHeader = new Properties();
urlHeader.put("CONTENT-TYPE", "application/json");
urlHeader.put("Authorization", getTokenFromBridge());
String urlResponse = HttpUtil.executeUrl("GET", url, urlHeader, null, null, 2000);
ReadingInstance latestReading = gson.fromJson(new JsonParser().parse(urlResponse), ReadingInstance.class);
return new MeterState(latestReading);
} catch (IOException e) {
logger.debug("Exception while refreshing cache for Meter {}: {}", getThing().getUID(), e.getMessage(), e);
return null;
}
}
/**
* Generates a url string based on the given api endpoint
*
* @param endpoint The choosen api endpoint
* @return The generated url string
*/
private String getApiString(String endpoint) {
StringBuilder sb = new StringBuilder(API_BASE_URL);
sb.append(API_VERSION).append("/");
switch (endpoint) {
case API_METER_ENDPOINT:
sb.append(API_METER_ENDPOINT).append("/");
sb.append(this.getRessourceID()).append("/?");
break;
case API_READINGS_ENDPOINT:
sb.append(API_READINGS_ENDPOINT).append("/");
sb.append("?meter_ressource_id=").append(this.getRessourceID());
sb.append("&o=-reading_date").append("&");
break;
}
sb.append("format=json");
return sb.toString();
}
/**
* Getters and Setters
*/
public String getRessourceID() {
return resourceID;
}
private void setRessourceID(String ressourceID) {
this.resourceID = ressourceID;
}
public String getMeterID() {
return meterID;
}
private void setMeterID(String meterID) {
this.meterID = meterID;
}
}

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.pixometer.internal;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link PixometerBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Jerome Luckenbach - Initial contribution
*/
@NonNullByDefault
public class PixometerBindingConstants {
private static final String BINDING_ID = "pixometer";
// Api base url
public static final String API_BASE_URL = "https://pixometer.io/api/";
// List of all Thing Type UIDs
public static final ThingTypeUID BRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, "account");
public static final ThingTypeUID THING_TYPE_ENERGYMETER = new ThingTypeUID(BINDING_ID, "energymeter");
public static final ThingTypeUID THING_TYPE_GASMETER = new ThingTypeUID(BINDING_ID, "gasmeter");
public static final ThingTypeUID THING_TYPE_WATERMETER = new ThingTypeUID(BINDING_ID, "watermeter");
public static final Set<ThingTypeUID> BRIDGE_THING_TYPES_UIDS = Collections.singleton(BRIDGE_THING_TYPE);
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream
.of(THING_TYPE_ENERGYMETER, THING_TYPE_GASMETER, THING_TYPE_WATERMETER).collect(Collectors.toSet());
// List of all Channel ids
public static final String CHANNEL_LAST_READING_VALUE = "last_reading_value";
public static final String CHANNEL_LAST_READING_DATE = "last_reading_date";
public static final String CHANNEL_LAST_REFRESH_DATE = "last_refresh_date";
// List of all config ids
public static final String CONFIG_BRIDGE_PASSWORD = "password";
public static final String CONFIG_BRIDGE_REFRESH = "refresh";
public static final String CONFIG_BRIDGE_USER = "user";
public static final String CONFIG_THING_RESSOURCE_ID = "resource_id";
// References for needed API identifiers
public static final String AUTH_TOKEN = "access_token";
}

View File

@@ -0,0 +1,72 @@
/**
* 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.pixometer.internal;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.pixometer.handler.AccountHandler;
import org.openhab.binding.pixometer.handler.MeterHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
/**
* The {@link PixometerHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Jerome Luckenbach - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.pixometer", service = ThingHandlerFactory.class)
public class PixometerHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream
.of(PixometerBindingConstants.BRIDGE_THING_TYPES_UIDS, PixometerBindingConstants.SUPPORTED_THING_TYPES_UIDS)
.flatMap(Set::stream).collect(Collectors.toSet());
@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 (thingTypeUID.equals(PixometerBindingConstants.THING_TYPE_ENERGYMETER)) {
return new MeterHandler(thing);
}
if (thingTypeUID.equals(PixometerBindingConstants.THING_TYPE_GASMETER)) {
return new MeterHandler(thing);
}
if (thingTypeUID.equals(PixometerBindingConstants.THING_TYPE_WATERMETER)) {
return new MeterHandler(thing);
}
if (thingTypeUID.equals(PixometerBindingConstants.BRIDGE_THING_TYPE)) {
return new AccountHandler((Bridge) thing);
}
return null;
}
}

View File

@@ -0,0 +1,72 @@
/**
* 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.pixometer.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link Annotation} class is the representing java model for the json result for a annotation from the pixometer
* api
*
* @author Jerome Luckenbach - Initial Contribution
*
*/
@NonNullByDefault
public class Annotation {
private @NonNullByDefault({}) Integer id;
private @NonNullByDefault({}) Object rectangle;
private @NonNullByDefault({}) String meaning;
private @NonNullByDefault({}) String text;
private @NonNullByDefault({}) Integer image;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Object getRectangle() {
return rectangle;
}
public void setRectangle(Object rectangle) {
this.rectangle = rectangle;
}
public String getMeaning() {
return meaning;
}
public void setMeaning(String meaning) {
this.meaning = meaning;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Integer getImage() {
return image;
}
public void setImage(Integer image) {
this.image = image;
}
}

View File

@@ -0,0 +1,146 @@
/**
* 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.pixometer.internal.config;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link ImageMeta} class is the representing java model for the json result for Image Meta Data from the pixometer
* api
*
* @author Jerome Luckenbach - Initial Contribution
*
*/
@NonNullByDefault
public class ImageMeta {
private @NonNullByDefault({}) Integer id;
private @NonNullByDefault({}) List<Annotation> annotations = null;
private @NonNullByDefault({}) String image;
private @NonNullByDefault({}) String imageDownload;
private @NonNullByDefault({}) String cameraModel;
private @NonNullByDefault({}) Boolean flash;
private @NonNullByDefault({}) Integer frameNumber;
private @NonNullByDefault({}) Double secondsSinceDetection;
private @NonNullByDefault({}) Double secondsSinceStart;
private @NonNullByDefault({}) Double lat;
private @NonNullByDefault({}) Double lng;
private @NonNullByDefault({}) String osVersion;
private @NonNullByDefault({}) String pixolusVersion;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<Annotation> getAnnotations() {
return annotations;
}
public void setAnnotations(List<Annotation> annotations) {
this.annotations = annotations;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public String getImageDownload() {
return imageDownload;
}
public void setImageDownload(String imageDownload) {
this.imageDownload = imageDownload;
}
public String getCameraModel() {
return cameraModel;
}
public void setCameraModel(String cameraModel) {
this.cameraModel = cameraModel;
}
public Boolean getFlash() {
return flash;
}
public void setFlash(Boolean flash) {
this.flash = flash;
}
public Integer getFrameNumber() {
return frameNumber;
}
public void setFrameNumber(Integer frameNumber) {
this.frameNumber = frameNumber;
}
public Double getSecondsSinceDetection() {
return secondsSinceDetection;
}
public void setSecondsSinceDetection(Double secondsSinceDetection) {
this.secondsSinceDetection = secondsSinceDetection;
}
public Double getSecondsSinceStart() {
return secondsSinceStart;
}
public void setSecondsSinceStart(Double secondsSinceStart) {
this.secondsSinceStart = secondsSinceStart;
}
public Double getLat() {
return lat;
}
public void setLat(Double lat) {
this.lat = lat;
}
public Double getLng() {
return lng;
}
public void setLng(Double lng) {
this.lng = lng;
}
public String getOsVersion() {
return osVersion;
}
public void setOsVersion(String osVersion) {
this.osVersion = osVersion;
}
public String getPixolusVersion() {
return pixolusVersion;
}
public void setPixolusVersion(String pixolusVersion) {
this.pixolusVersion = pixolusVersion;
}
}

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.pixometer.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link MeterInstance} class is the representing java model for the json result for a meter from the pixometer
* api
*
* @author Jerome Luckenbach - Initial Contribution
*
*/
@NonNullByDefault
public class MeterInstance {
private @NonNullByDefault({}) String url;
private @NonNullByDefault({}) String owner;
private @NonNullByDefault({}) String changedHash;
private @NonNullByDefault({}) String created;
private @NonNullByDefault({}) String modified;
private @NonNullByDefault({}) String appearance;
private @NonNullByDefault({}) Integer fractionDigits;
private @NonNullByDefault({}) Boolean isDoubleTariff;
private @NonNullByDefault({}) String locationInBuilding;
private @NonNullByDefault({}) String meterId;
private @NonNullByDefault({}) String physicalMedium;
private @NonNullByDefault({}) String physicalUnit;
private @NonNullByDefault({}) Integer integerDigits;
private @NonNullByDefault({}) String registerOrder;
private @NonNullByDefault({}) Object city;
private @NonNullByDefault({}) Object zipCode;
private @NonNullByDefault({}) Object address;
private @NonNullByDefault({}) Object description;
private @NonNullByDefault({}) Object label;
private @NonNullByDefault({}) Integer resourceId;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getChangedHash() {
return changedHash;
}
public void setChangedHash(String changedHash) {
this.changedHash = changedHash;
}
public String getCreated() {
return created;
}
public void setCreated(String created) {
this.created = created;
}
public String getModified() {
return modified;
}
public void setModified(String modified) {
this.modified = modified;
}
public String getAppearance() {
return appearance;
}
public void setAppearance(String appearance) {
this.appearance = appearance;
}
public Integer getFractionDigits() {
return fractionDigits;
}
public void setFractionDigits(Integer fractionDigits) {
this.fractionDigits = fractionDigits;
}
public Boolean getIsDoubleTariff() {
return isDoubleTariff;
}
public void setIsDoubleTariff(Boolean isDoubleTariff) {
this.isDoubleTariff = isDoubleTariff;
}
public String getLocationInBuilding() {
return locationInBuilding;
}
public void setLocationInBuilding(String locationInBuilding) {
this.locationInBuilding = locationInBuilding;
}
public String getMeterId() {
return meterId;
}
public void setMeterId(String meterId) {
this.meterId = meterId;
}
public String getPhysicalMedium() {
return physicalMedium;
}
public void setPhysicalMedium(String physicalMedium) {
this.physicalMedium = physicalMedium;
}
public String getPhysicalUnit() {
return physicalUnit;
}
public void setPhysicalUnit(String physicalUnit) {
this.physicalUnit = physicalUnit;
}
public Integer getIntegerDigits() {
return integerDigits;
}
public void setIntegerDigits(Integer integerDigits) {
this.integerDigits = integerDigits;
}
public String getRegisterOrder() {
return registerOrder;
}
public void setRegisterOrder(String registerOrder) {
this.registerOrder = registerOrder;
}
public Object getCity() {
return city;
}
public void setCity(Object city) {
this.city = city;
}
public Object getZipCode() {
return zipCode;
}
public void setZipCode(Object zipCode) {
this.zipCode = zipCode;
}
public Object getAddress() {
return address;
}
public void setAddress(Object address) {
this.address = address;
}
public Object getDescription() {
return description;
}
public void setDescription(Object description) {
this.description = description;
}
public Object getLabel() {
return label;
}
public void setLabel(Object label) {
this.label = label;
}
public Integer getResourceId() {
return resourceId;
}
public void setResourceId(Integer resourceId) {
this.resourceId = resourceId;
}
}

View File

@@ -0,0 +1,39 @@
/**
* 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.pixometer.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Data class representing the user configurable settings of the api
*
* @author Jerome Luckenbach - Initial contribution
*/
@NonNullByDefault
public class PixometerAccountConfiguration {
/**
* The configured user name
*/
public @NonNullByDefault({}) String user;
/**
* The configured password
*/
public @NonNullByDefault({}) String password;
/**
* Configured refresh rate
*/
public int refresh;
}

View File

@@ -0,0 +1,29 @@
/**
* 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.pixometer.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Data class representing the user configurable settings of a meter thing
*
* @author Jerome Luckenbach - Initial contribution
*/
@NonNullByDefault
public class PixometerMeterConfiguration {
/**
* The resourceId of the current meter
*/
public @NonNullByDefault({}) String resourceId;
}

View File

@@ -0,0 +1,92 @@
/**
* 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.pixometer.internal.config;
import java.time.ZonedDateTime;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link ReadingInstance} class is the representing java model for the json result for a reading from the pixometer
* api
*
* @author Jerome Luckenbach - Initial Contribution
*
*/
@NonNullByDefault
public class ReadingInstance {
private @NonNullByDefault({}) String url;
private @NonNullByDefault({}) String appliedMethod;
private @NonNullByDefault({}) ZonedDateTime readingDate;
private double value;
private double valueSecondTariff;
private int providedFractionDigits;
private int providedFractionDigitsSecondTariff;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getAppliedMethod() {
return appliedMethod;
}
public void setAppliedMethod(String appliedMethod) {
this.appliedMethod = appliedMethod;
}
public ZonedDateTime getReadingDate() {
return readingDate;
}
public void setReadingDate(ZonedDateTime readingDate) {
this.readingDate = readingDate;
}
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public double getValueSecondTariff() {
return valueSecondTariff;
}
public void setValueSecondTariff(double valueSecondTariff) {
this.valueSecondTariff = valueSecondTariff;
}
public int getProvidedFractionDigits() {
return providedFractionDigits;
}
public void setProvidedFractionDigits(int provided_fraction_digits) {
this.providedFractionDigits = provided_fraction_digits;
}
public int getProvidedFractionDigitsSecondTariff() {
return providedFractionDigitsSecondTariff;
}
public void setProvidedFractionDigitsSecondTariff(int provided_fraction_digits_second_tariff) {
this.providedFractionDigitsSecondTariff = provided_fraction_digits_second_tariff;
}
}

View File

@@ -0,0 +1,64 @@
/**
* 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.pixometer.internal.data;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.pixometer.internal.config.ReadingInstance;
import org.openhab.core.library.types.DateTimeType;
/**
* Abstract data class to store shared/common meter state values
*
* @author Jerome Luckenbach - Initial contribution
*
*/
@NonNullByDefault
public class MeterState {
private final DateTimeType lastReadingDate;
private final DateTimeType lastRefreshTime;
private final double readingValue;
/**
* Initialize times from the given timestamps
*
* @param lastReadingDate time of last reading as ZonedDateTime
* @param lastRefreshTime time of last refresh as ZonedDateTime
*/
public MeterState(ReadingInstance reading) {
this.readingValue = reading.getValue();
this.lastReadingDate = new DateTimeType(reading.getReadingDate());
this.lastRefreshTime = new DateTimeType();
}
/**
* @return returns the current reading value
*/
public double getReadingValue() {
return readingValue;
}
/**
* @return returns the last time that the meter has been read into pixometer
*/
public DateTimeType getLastReadingDate() {
return lastReadingDate;
}
/**
* @return returns the last time, the item has been refreshed
*/
public DateTimeType getLastRefreshTime() {
return lastRefreshTime;
}
}

View File

@@ -0,0 +1,109 @@
/**
* 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.pixometer.internal.serializer;
import java.lang.reflect.Type;
import java.time.Instant;
import java.time.ZonedDateTime;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.pixometer.internal.config.ReadingInstance;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
/**
* Custom Deserializer for meter reading api responses
*
* @author Jerome Luckenbach - Initial contribution
*
*/
@NonNullByDefault
public class CustomReadingInstanceDeserializer implements JsonDeserializer<ReadingInstance> {
private static final String COUNT = "count";
private static final String RESULTS = "results";
private static final String URL = "url";
private static final String APPLIED_METHOD = "applied_method";
private static final String READING_DATE = "reading_date";
private static final String VALUE = "value";
private static final String VALUE_SECOND_TARIFF = "value_second_tariff";
private static final String PROVIDED_FRACTION_DIGITS = "provided_fraction_digits";
private static final String PROVIDED_FRACTION_DIGITS_SECOND_TARIFF = "provided_fraction_digits_second_tariff";
@Override
@NonNullByDefault({})
public ReadingInstance deserialize(final JsonElement json, final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
if (!jsonObject.has(COUNT)) {
throw new JsonParseException("Invalid Json Response");
}
ReadingInstance result = new ReadingInstance();
int resultCount = Integer.parseInt(jsonObject.get(COUNT).toString());
// No readings provided yet
if (resultCount < 1) {
result.setReadingDate(ZonedDateTime.from(Instant.EPOCH));
result.setValue(0);
}
// Fist result is the last reading instance
JsonObject latestReading = jsonObject.getAsJsonArray(RESULTS).get(0).getAsJsonObject();
result.setUrl(getStringFromJson(latestReading, URL));
result.setAppliedMethod(getStringFromJson(latestReading, APPLIED_METHOD));
result.setReadingDate(ZonedDateTime.parse(getStringFromJson(latestReading, READING_DATE)));
result.setValue(Double.parseDouble(getStringFromJson(latestReading, VALUE)));
// Not all meters provide useful data for second tariff and fraction digits , so zero should be used in case of
// a null value.
String secondTariffValue = getStringFromJson(latestReading, VALUE_SECOND_TARIFF);
result.setValueSecondTariff(
checkStringForNullValues(secondTariffValue) ? 0 : Double.parseDouble(secondTariffValue));
String providedFractionDigits = getStringFromJson(latestReading, PROVIDED_FRACTION_DIGITS);
result.setProvidedFractionDigits(
checkStringForNullValues(providedFractionDigits) ? 0 : Integer.parseInt(providedFractionDigits));
String secondprovidedFractionDigits = getStringFromJson(latestReading, PROVIDED_FRACTION_DIGITS_SECOND_TARIFF);
result.setProvidedFractionDigitsSecondTariff(checkStringForNullValues(secondprovidedFractionDigits) ? 0
: Integer.parseInt(secondprovidedFractionDigits));
return result;
}
/**
* Returns the node value and removes possible added quotation marks, which would lead to parse errors.
*
* @param data The Json source to get the string from
* @param key The key for the wanted Json Node
* @return The wanted string without unnecessary quotation marks
*/
private String getStringFromJson(JsonObject data, String key) {
return data.get(key).toString().replaceAll("\"", "");
}
/**
* @param s the striong to check
* @return returns true if null values have been found, false otherwise
*/
private boolean checkStringForNullValues(String s) {
return (s == null || s.isEmpty() || s.equals("null"));
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="pixometer" 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>Pixometer Binding</name>
<description>This binding integrates meter data through pixometer.</description>
<author>Jerome Luckenbach</author>
</binding:binding>

View File

@@ -0,0 +1,44 @@
# binding
binding.pixometer.name = Pixometer Binding
binding.pixometer.description = Mit dem Pixometer Binding ist es möglich über die Pixometer.io API Daten und Messwerte von den dort erfassten Zählern abzurufen.
# thing types
thing-type.pixometer.account.label = Pixometer Account
thing-type.pixometer.account.description = Stellt die Verbindung zur API für die eingerichteten Zähler bereit.
thing-type.config.pixometer.account.user.label = Benutzername
thing-type.config.pixometer.account.user.description = Der Pixometer Benutzername
thing-type.config.pixometer.account.password.label = Password
thing-type.config.pixometer.account.password.description = Das Pixometer Passwort
thing-type.config.pixometer.account.refresh.label = Aktualisierungsintervall
thing-type.config.pixometer.account.refresh.description = Das Intervall in dem ein Zähler aktualisiert wird (in Minuten, Minimum 60)
thing-type.pixometer.energymeter.label = Stromzähler
thing-type.pixometer.energymeter.description = Stellt die Informationen und Messwerte zu einem Stromzähler bereit.
thing-type.config.pixometer.energymeter.resource_id.label = Zähler Ressourcen ID
thing-type.config.pixometer.energymeter.resource_id.description = Unter dieser ID wird der Zähler im Pixometer Account geführt. Sie ist in der Pixometer Homepage in der Adressleiste des Browsers beim Bearbeiten des Zählers ersichtlich.
thing-type.pixometer.gasmeter.label = Gaszähler
thing-type.pixometer.gasmeter.description = Stellt die Informationen und Messwerte zu einem Gaszähler bereit.
thing-type.config.pixometer.gasmeter.resource_id.label = Zähler Ressourcen ID
thing-type.config.pixometer.gasmeter.resource_id.description = Unter dieser ID wird der Zähler im Pixometer Account geführt. Sie ist in der Pixometer Homepage in der Adressleiste des Browsers beim Bearbeiten des Zählers ersichtlich.
thing-type.pixometer.watermeter.label = Wasserzähler
thing-type.pixometer.watermeter.description = Stellt die Informationen und Messwerte zu einem Wasserzähler bereit.
thing-type.config.pixometer.watermeter.resource_id.label = Zähler Ressourcen ID
thing-type.config.pixometer.watermeter.resource_id.description = Unter dieser ID wird der Zähler im Pixometer Account geführt. Sie ist in der Pixometer Homepage in der Adressleiste des Browsers beim Bearbeiten des Zählers ersichtlich.
# channel types
channel-type.pixometer.last_reading_value.label = Zählerstand
channel-type.pixometer.last_reading_value.description = Der zuletzt von der API abgefragte Zählerstand für diesen Zähler.
channel-type.pixometer.last_reading_date.label = Ablesezeitpunkt
channel-type.pixometer.last_reading_date.description = Der Zeitpunkt der zuletzt abgefragten Ablesung für diesem Zähler.
channel-type.pixometer.last_refresh_date.label = Aktualisierungszeitpunkt
channel-type.pixometer.last_refresh_date.description = Der Zeitpunkt an dem dieser Zähler zuletzt vom Binding in der API abgefragt wurde.

View File

@@ -0,0 +1,44 @@
# binding
binding.pixometer.name = Pixometer Binding
binding.pixometer.description = This binding can connect to the Pixometer.io API and accesses meters and measurement data from the connected account.
# thing types
thing-type.pixometer.account.label = Pixometer Account
thing-type.pixometer.account.description =
thing-type.config.pixometer.account.user.label = Username
thing-type.config.pixometer.account.user.description = The Pixometer username
thing-type.config.pixometer.account.password.label = Password
thing-type.config.pixometer.account.password.description = The Pixometer password
thing-type.config.pixometer.account.refresh.label = Refresh Interval
thing-type.config.pixometer.account.refresh.description = The interval on which the API is refreshed. (at least 60 minutes)
thing-type.pixometer.energymeter.label = Energymeter
thing-type.pixometer.energymeter.description = An energymeter thing.
thing-type.config.pixometer.energymeter.resource_id.label = Meter Ressource ID
thing-type.config.pixometer.energymeter.resource_id.description = The ID which represents the current meter. You can find it in the pixometer browser app while editing a specific meter. It should look like this: "https://pixometer.io/portal/#/meters/XXXXX/edit"
thing-type.pixometer.gasmeter.label = Gasmeter
thing-type.pixometer.gasmeter.description = A gas meter.
thing-type.config.pixometer.gasmeter.resource_id.label = Meter Tressource ID
thing-type.config.pixometer.gasmeter.resource_id.description = The ID which represents the current meter. You can find it in the pixometer browser app while editing a specific meter. It should look like this: "https://pixometer.io/portal/#/meters/XXXXX/edit"
thing-type.pixometer.watermeter.label = Watermeter
thing-type.pixometer.watermeter.description = A water meter.
thing-type.config.pixometer.watermeter.resource_id.label = Meter Ressource ID
thing-type.config.pixometer.watermeter.resource_id.description = The ID which represents the current meter. You can find it in the pixometer browser app while editing a specific meter. It should look like this: "https://pixometer.io/portal/#/meters/XXXXX/edit"
# channel types
channel-type.pixometer.last_reading_value.label = Reading Value
channel-type.pixometer.last_reading_value.description = Value of the last reading that has been made with pixometer.
channel-type.pixometer.last_reading_date.label = Reading Date
channel-type.pixometer.last_reading_date.description = Date of the last reading that has been made with pixometer.
channel-type.pixometer.last_refresh_date.label = Refresh Date
channel-type.pixometer.last_refresh_date.description = Date of the last time the Api has been refreshed.

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="pixometer"
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">
<!-- API Bridge Type -->
<bridge-type id="account">
<label>Pixometer Account</label>
<description>This Bridge handles your Pixometer account.</description>
<config-description>
<parameter name="user" type="text" required="true">
<label>Username</label>
<description>Your Pixometer Username.</description>
<default></default>
</parameter>
<parameter name="password" type="text" required="true">
<context>password</context>
<label>Password</label>
<description>Your Pixometer Password.</description>
<default></default>
</parameter>
<parameter name="refresh" type="integer" required="true" min="60">
<label>Refresh Time</label>
<description>Sets the refresh time. Minimum is 60 Minutes.</description>
<default>240</default>
</parameter>
</config-description>
</bridge-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="pixometer"
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="last_reading_date">
<item-type>DateTime</item-type>
<label>Last Reading</label>
<description>The last time that the current meter has been read.</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="last_refresh_date">
<item-type>DateTime</item-type>
<label>Last Refresh</label>
<description>The last time that the thing has been refreshed.</description>
<state readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="pixometer"
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="energymeter">
<supported-bridge-type-refs>
<bridge-type-ref id="account"/>
</supported-bridge-type-refs>
<label>Energymeter</label>
<description>A specific energy meter.</description>
<channels>
<channel id="last_reading_value" typeId="last_reading_value_energy"/>
<channel id="last_reading_date" typeId="last_reading_date"/>
<channel id="last_refresh_date" typeId="last_refresh_date"/>
</channels>
<config-description>
<parameter name="resourceId" type="text" required="true">
<label>Ressource ID</label>
<description>The ID which represents the current meter. You can find it in the pixometer browser app while editing a
specific meter. It should look like this: "https://pixometer.io/portal/#/meters/XXXXX/edit"</description>
</parameter>
</config-description>
</thing-type>
<channel-type id="last_reading_value_energy">
<item-type>Number:Energy</item-type>
<label>Last Reading</label>
<description>The last value that has been read for this meter.</description>
<state pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="pixometer"
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="gasmeter">
<supported-bridge-type-refs>
<bridge-type-ref id="account"/>
</supported-bridge-type-refs>
<label>Gasmeter</label>
<description>A specific gas meter.</description>
<channels>
<channel id="last_reading_value" typeId="last_reading_value_gas"/>
<channel id="last_reading_date" typeId="last_reading_date"/>
<channel id="last_refresh_date" typeId="last_refresh_date"/>
</channels>
<config-description>
<parameter name="resourceId" type="text" required="true">
<label>Ressource ID</label>
<description>The ID which represents the current meter. You can find it in the pixometer browser app while editing a
specific meter. It should look like this: "https://pixometer.io/portal/#/meters/XXXXX/edit"</description>
</parameter>
</config-description>
</thing-type>
<channel-type id="last_reading_value_gas">
<item-type>Number:Volume</item-type>
<label>Last Reading</label>
<description>The last value that has been read for this meter.</description>
<state pattern="%.3f %unit%" readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="pixometer"
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="watermeter">
<supported-bridge-type-refs>
<bridge-type-ref id="account"/>
</supported-bridge-type-refs>
<label>Watermeter</label>
<description>A specific water meter.</description>
<channels>
<channel id="last_reading_value" typeId="last_reading_value_water"/>
<channel id="last_reading_date" typeId="last_reading_date"/>
<channel id="last_refresh_date" typeId="last_refresh_date"/>
</channels>
<config-description>
<parameter name="resourceId" type="text" required="true">
<label>Ressource ID</label>
<description>The ID which represents the current meter. You can find it in the pixometer browser app while editing a
specific meter. It should look like this: "https://pixometer.io/portal/#/meters/XXXXX/edit"</description>
</parameter>
</config-description>
</thing-type>
<channel-type id="last_reading_value_water">
<item-type>Number:Volume</item-type>
<label>Last Reading</label>
<description>The last value that has been read for this meter.</description>
<state pattern="%.3f %unit%" readOnly="true"/>
</channel-type>
</thing:thing-descriptions>