Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iammeter] Iammeter Binding initial contribution #8252

Merged
merged 12 commits into from Sep 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions bom/openhab-addons/pom.xml
Expand Up @@ -414,6 +414,11 @@
<artifactId>org.openhab.binding.hyperion</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.iammeter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.iaqualink</artifactId>
Expand Down
15 changes: 15 additions & 0 deletions bundles/org.openhab.binding.iammeter/.classpath
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<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>
23 changes: 23 additions & 0 deletions bundles/org.openhab.binding.iammeter/.project
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.iammeter</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>
13 changes: 13 additions & 0 deletions bundles/org.openhab.binding.iammeter/NOTICE
@@ -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/openhab-addons
57 changes: 57 additions & 0 deletions bundles/org.openhab.binding.iammeter/README.md
@@ -0,0 +1,57 @@
# Iammeter Binding

[Iammeter](https://www.iammeter.com) provides real-time readings of single-phase (WEM3080, WEM3162) and three-phase (WEM3080T) meters from IAMMETER over Wi-Fi.

## Use of the binding

The Iammeter is exposed as one thing with a number of channels that can be used to read the values for different aspects of your Iammeter devices.

## Setup of the binding

You can add the Iammeter device via the openHAB UI manually.


Hilbrand marked this conversation as resolved.
Show resolved Hide resolved
## Available channels

The following table is taken from the official manual and contains all available channels.

Single-phase energy meter (WEM3080/WEM3162)
| Name | Unit | Description | Type |
|----------------|------|------------------------------|--------------------------|
| voltage_a | V | Voltage | Number:ElectricPotential |
| current_a | A | Current | Number:ElectricCurrent |
| power_a | W | Active power | Number:Power |
| importenergy_a | kWh | Energy consumption from gird | Number:Energy |
| exportgrid_a | kWh | Energy export to grid | Number:Energy |


Three-phase energy meter (WEM3080T)
| Name | Unit | Description | Type |
|----------------|------|-----------------------|--------------------------|
| voltage_a | V | A phase voltage | Number:ElectricPotential |
| current_a | A | A phase current | Number:ElectricCurrent |
| power_a | W | A phase active power | Number:Power |
| importenergy_a | kWh | A phase import energy | Number:Energy |
| exportgrid_a | kWh | A phase export energy | Number:Energy |
| frequency_a | kWh | A phase frequency | Number:Frequency |
| pf_a | kWh | A phase power factor | Number |
| voltage_b | V | B phase voltage | Number:ElectricPotential |
| current_b | A | B phase current | Number:ElectricCurrent |
| power_b | W | B phase active power | Number:Power |
| importenergy_b | kWh | B phase import energy | Number:Energy |
| exportgrid_b | kWh | B phase export energy | Number:Energy |
| frequency_b | kWh | B phase frequency | Number:Frequency |
| pf_b | kWh | B phase power factor | Number |
| voltage_c | V | C phase voltage | Number:ElectricPotential |
| current_c | A | C phase current | Number:ElectricCurrent |
| power_c | W | C phase active power | Number:Power |
| importenergy_c | kWh | C phase import energy | Number:Energy |
| exportgrid_c | kWh | C phase export energy | Number:Energy |
| frequency_c | kWh | C phase frequency | Number:Frequency |
| pf_c | kWh | C phase power factor | Number |



Hilbrand marked this conversation as resolved.
Show resolved Hide resolved
## More information

More information about the Iammeter devices can be found in the [Iammeter website](https://www.iammeter.com).
17 changes: 17 additions & 0 deletions bundles/org.openhab.binding.iammeter/pom.xml
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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/xsd/maven-4.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.9-SNAPSHOT</version>
</parent>

<artifactId>org.openhab.binding.iammeter</artifactId>

<name>openHAB Add-ons :: Bundles :: Iammeter Binding</name>

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

import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.thing.Channel;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingStatus;
import org.eclipse.smarthome.core.types.State;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

/**
* The {@link IammeterHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Yang Bo - Initial contribution
*/

@NonNullByDefault
public class Iammeter3080THandler extends IammeterBaseHandler {

public Iammeter3080THandler(Thing thing) {
super(thing);
}

@SuppressWarnings("null")
@Override
protected void resolveData(String response) {
JsonElement iammeterDataElement = new JsonParser().parse(response);
JsonObject iammeterData = iammeterDataElement.getAsJsonObject();
String keyWord = "Datas";
if (iammeterData.has("Datas") && iammeterData.has("SN")) {
String groups[] = { "powerPhaseA", "powerPhaseB", "powerPhaseC" };
for (int row = 0; row < groups.length; row++) {
String gpName = groups[row];
List<Channel> chnList = getThing().getChannelsOfGroup(gpName);
for (IammeterWEM3080Channel channelConfig : IammeterWEM3080Channel.values()) {
Channel chnl = chnList.get(channelConfig.ordinal());
if (chnl != null) {
State state = getQuantityState(iammeterData.get(keyWord).getAsJsonArray().get(row)
.getAsJsonArray().get(channelConfig.ordinal()).toString(), channelConfig.getUnit());
updateState(chnl.getUID(), state);
}
}
updateStatus(ThingStatus.ONLINE);
}
}
}
}
@@ -0,0 +1,126 @@
/**
* 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.iammeter.internal;

import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import javax.measure.Unit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.cache.ExpiringCache;
import org.eclipse.smarthome.core.library.types.QuantityType;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingStatus;
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.RefreshType;
import org.eclipse.smarthome.core.types.State;
import org.eclipse.smarthome.core.types.UnDefType;
import org.eclipse.smarthome.io.net.http.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.JsonSyntaxException;

/**
* The {@link IammeterHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Yang Bo - Initial contribution
*/

@NonNullByDefault
public abstract class IammeterBaseHandler extends BaseThingHandler {

private final Logger logger = LoggerFactory.getLogger(IammeterBaseHandler.class);
private @Nullable ScheduledFuture<?> refreshJob;
private IammeterConfiguration config;
private static final int TIMEOUT_MS = 5000;
private final ExpiringCache<Boolean> refreshCache = new ExpiringCache<>(Duration.ofSeconds(5), this::refresh);

public IammeterBaseHandler(Thing thing) {
super(thing);
config = getConfiguration();
}

@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
refreshCache.getValue();
}
}

@Override
public void initialize() {
ScheduledFuture<?> refreshJob = this.refreshJob;
config = getConfiguration();
if (refreshJob == null) {
refreshJob = scheduler.scheduleWithFixedDelay(this::refresh, 0, config.refreshInterval, TimeUnit.SECONDS);
this.refreshJob = refreshJob;
updateStatus(ThingStatus.UNKNOWN);
}
}

protected abstract void resolveData(String response);

@SuppressWarnings("null")
private boolean refresh() {
refreshCache.invalidateValue();
IammeterConfiguration config = this.config;
try {
String httpMethod = "GET";
String url = "http://" + config.username + ":" + config.password + "@" + config.host + ":" + config.port
+ "/monitorjson";
String response = HttpUtil.executeUrl(httpMethod, url, TIMEOUT_MS);
resolveData(response);
updateStatus(ThingStatus.ONLINE);
return true;
// Very rudimentary Exception differentiation
} catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Communication error with the device: " + e.getMessage());
} catch (JsonSyntaxException je) {
logger.warn("Invalid JSON when refreshing source {}: {}", getThing().getUID(), je.getMessage());
updateStatus(ThingStatus.OFFLINE);
}
return false;
}

protected State getQuantityState(String value, Unit<?> unit) {
try {
return QuantityType.valueOf(Float.parseFloat(value), unit);
} catch (NumberFormatException e) {
return UnDefType.UNDEF;
}
}

@Override
public void dispose() {
ScheduledFuture<?> refreshJob = this.refreshJob;
if (refreshJob != null && !refreshJob.isCancelled()) {
refreshJob.cancel(true);
this.refreshJob = null;
}
super.dispose();
}

public IammeterConfiguration getConfiguration() {
return this.getConfigAs(IammeterConfiguration.class);
}
}
@@ -0,0 +1,32 @@
/**
* 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.iammeter.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.thing.ThingTypeUID;

/**
* The {@link IammeterBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author yang bo - Initial contribution
*/
@NonNullByDefault
public class IammeterBindingConstants {

public static final String BINDING_ID = "iammeter";

// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_POWERMETER = new ThingTypeUID(BINDING_ID, "powermeter");
public static final ThingTypeUID THING_TYPE_POWERMETER_3080T = new ThingTypeUID(BINDING_ID, "powermeter3080T");
}