Skip to content

Commit

Permalink
[iammeter] Iammeter Binding initial contribution (openhab#8252)
Browse files Browse the repository at this point in the history
Signed-off-by: Yang Bo <service@lewei50.com>
  • Loading branch information
lewei50 authored and markus7017 committed Sep 18, 2020
1 parent 37f1d5b commit 6c0b825
Show file tree
Hide file tree
Showing 20 changed files with 788 additions and 0 deletions.
5 changes: 5 additions & 0 deletions bom/openhab-addons/pom.xml
Expand Up @@ -426,6 +426,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.


## 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 |



## 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");
}

0 comments on commit 6c0b825

Please sign in to comment.