forked from openhab/openhab-addons
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[pixometer] Pixometer Binding initial contribution (openhab#4162)
Signed-off-by: Jerome Luckenbach <github@luckenba.ch>
- Loading branch information
1 parent
28e7a69
commit c8272b9
Showing
29 changed files
with
1,783 additions
and
0 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<classpath> | ||
<classpathentry kind="src" output="target/classes" path="src/main/java"> | ||
<attributes> | ||
<attribute name="optional" value="true"/> | ||
<attribute name="maven.pomderived" value="true"/> | ||
</attributes> | ||
</classpathentry> | ||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> | ||
<attributes> | ||
<attribute name="maven.pomderived" value="true"/> | ||
</attributes> | ||
</classpathentry> | ||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"> | ||
<attributes> | ||
<attribute name="optional" value="true"/> | ||
<attribute name="maven.pomderived" value="true"/> | ||
<attribute name="test" value="true"/> | ||
</attributes> | ||
</classpathentry> | ||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"> | ||
<attributes> | ||
<attribute name="maven.pomderived" value="true"/> | ||
</attributes> | ||
</classpathentry> | ||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> | ||
<attributes> | ||
<attribute name="maven.pomderived" value="true"/> | ||
</attributes> | ||
</classpathentry> | ||
<classpathentry kind="output" path="target/classes"/> | ||
</classpath> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<projectDescription> | ||
<name>org.openhab.binding.pixometer</name> | ||
<comment></comment> | ||
<projects> | ||
</projects> | ||
<buildSpec> | ||
<buildCommand> | ||
<name>org.eclipse.jdt.core.javabuilder</name> | ||
<arguments> | ||
</arguments> | ||
</buildCommand> | ||
<buildCommand> | ||
<name>org.eclipse.m2e.core.maven2Builder</name> | ||
<arguments> | ||
</arguments> | ||
</buildCommand> | ||
</buildSpec> | ||
<natures> | ||
<nature>org.eclipse.jdt.core.javanature</nature> | ||
<nature>org.eclipse.m2e.core.maven2Nature</nature> | ||
</natures> | ||
</projectDescription> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
This content is produced and maintained by the openHAB project. | ||
|
||
* Project home: https://www.openhab.org | ||
|
||
== Declared Project Licenses | ||
|
||
This program and the accompanying materials are made available under the terms | ||
of the Eclipse Public License 2.0 which is available at | ||
https://www.eclipse.org/legal/epl-2.0/. | ||
|
||
== Source Code | ||
|
||
https://github.com/openhab/openhab2-addons |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Pixometer Binding | ||
|
||
This binding connects to the pixometer API, which can manage your meter readings through a native smartphone app. | ||
|
||
## Supported Things | ||
|
||
This binding supports the following thing types according to the capabilities of pixometer: | ||
|
||
| Name | Type | Description | | ||
|-------------|--------|-----------------------------------------------------------------------------| | ||
| Account | Bridge | Representation of a pixometer account, which connects to the pixometer API. | | ||
| Energymeter | Thing | Provides access to the readings of configured energy meters. | | ||
| Gasmeter | Thing | Provides access to the readings of configured gas meters. | | ||
| Watermeter | Thing | Provides access to the readings of configured water meters. | | ||
|
||
The different meter types are pretty similar in basic, but are implemented in parallel to provide Units of Measurement support. | ||
|
||
## Thing Configuration | ||
|
||
### Account (bridge) | ||
|
||
| Parameter | Description | Required | Default Value | Comment | | ||
|--------------|--------------------------------------------------------------------|----------|------------------|---------------------------------------------------------------| | ||
| user | | Yes | - | | | ||
| password | | Yes | - | | | ||
| refresh | Sets the refresh time. Minimum is 60 Minutes. | Yes | 240 | | | ||
|
||
### Meter Things | ||
|
||
| Parameter | Description | Required | | ||
|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------| | ||
| resource_id | 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" | Yes | | ||
|
||
## Channels | ||
|
||
All meter things have the following channels: | ||
|
||
| Channel ID | Channel Description | Supported item type | Advanced | | ||
|--------------------|--------------------------------------------------------|---------------------|----------| | ||
| last_reading_value | The last value that has been read for this meter. | Number | false | | ||
| last_reading_date | The time at which the last reading value was recorded. | DateTime | false | | ||
| last_refresh_date | The last time that the current thing has been updated. | DateTime | false | | ||
|
||
## Full Example | ||
|
||
pixometer.things: | ||
|
||
```java | ||
Bridge pixometer:account:AccountName "MyAccountName" [ user="xxxxxxxx@xxxx.xx", password="xxxxxxxxxxxx", refresh= 60 ] { | ||
Thing energymeter MeterName1 "MyMeterName1" [ resource_id = "xxxxxxxx" ] | ||
Thing gasmeter MeterName2 "MyMeterName2" [ resource_id = "xxxxxxxx" ] | ||
Thing watermeter MeterName3 "MyMeterName3" [ resource_id = "xxxxxxxx" ] | ||
} | ||
``` | ||
|
||
pixometer.items: | ||
|
||
```java | ||
Number:Volume Meter_Gas_ReadingValue "[.3%f %unit%]" [] {channel="pixometer:gasmeter:accountname:metername1:last_reading_value"} | ||
DateTime Meter_Gas_LastReadingDate "[%1$td.%1$tm.%1$tY %1$tH:%1$tM]" [] {channel="pixometer:gasmeter:accountname:metername1:last_reading_date"} | ||
Number:Energy Meter_Electricity_ReadingValue "[.3%f %unit%]" [] {channel="pixometer:energymeter:accountname:metername2:last_reading_value"} | ||
DateTime Meter_Electricity_LastReadingDate "[%1$td.%1$tm.%1$tY %1$tH:%1$tM]" [] {channel="pixometer:energymeter:accountname:metername2:last_reading_date"} | ||
Number:Volume Meter_Water_ReadingValue "[.3%f %unit%]" [] {channel="pixometer:watermeter:accountname:metername3:last_reading_value"} | ||
DateTime Meter_Water_LastReadingDate "[%1$td.%1$tm.%1$tY %1$tH:%1$tM]" [] {channel="pixometer:watermeter:accountname:metername3:last_reading_date"} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
|
||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>org.openhab.addons.bundles</groupId> | ||
<artifactId>org.openhab.addons.reactor.bundles</artifactId> | ||
<version>2.5.0-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>org.openhab.binding.pixometer</artifactId> | ||
|
||
<name>openHAB Add-ons :: Bundles :: pixometer Binding</name> | ||
|
||
</project> |
9 changes: 9 additions & 0 deletions
9
bundles/org.openhab.binding.pixometer/src/main/feature/feature.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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/${project.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> |
171 changes: 171 additions & 0 deletions
171
...binding.pixometer/src/main/java/org/openhab/binding/pixometer/handler/AccountHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
/** | ||
* Copyright (c) 2010-2019 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.eclipse.smarthome.core.thing.Bridge; | ||
import org.eclipse.smarthome.core.thing.ChannelUID; | ||
import org.eclipse.smarthome.core.thing.ThingStatus; | ||
import org.eclipse.smarthome.core.thing.ThingStatusDetail; | ||
import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler; | ||
import org.eclipse.smarthome.core.types.Command; | ||
import org.eclipse.smarthome.io.net.http.HttpUtil; | ||
import org.openhab.binding.pixometer.internal.config.PixometerAccountConfiguration; | ||
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; | ||
} | ||
|
||
} |
Oops, something went wrong.