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