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

[iotawatt] Initial contribution #16491

Merged
merged 40 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
3bdcdbd
[iotawatt] generate new binding
PRosenb Feb 16, 2024
435fa4a
[iotawatt] add new binding
PRosenb Feb 17, 2024
517272c
[iotawatt] add output channels
PRosenb Mar 18, 2024
7811f2c
[iotawatt] add input power-factor and phase
PRosenb Mar 23, 2024
5e3d7bd
[iotawatt] add Javadoc
PRosenb May 5, 2024
fc0e02d
[iotawatt] spelling
PRosenb May 5, 2024
28c4684
[iotawatt] Use Optional for null check
PRosenb May 5, 2024
11eb6fd
Update bundles/org.openhab.binding.iotawatt/README.md
PRosenb May 5, 2024
7e237af
Update bundles/org.openhab.binding.iotawatt/src/main/java/org/openhab…
PRosenb May 5, 2024
3e7b786
Update bundles/org.openhab.binding.iotawatt/src/main/java/org/openhab…
PRosenb May 5, 2024
c8c534b
[iotawatt] update readme
PRosenb May 6, 2024
77f54ff
Update bundles/org.openhab.binding.iotawatt/src/main/resources/OH-INF…
PRosenb May 6, 2024
eedb41f
Update bundles/org.openhab.binding.iotawatt/src/main/resources/OH-INF…
PRosenb May 6, 2024
f7183bb
Update bundles/org.openhab.binding.iotawatt/src/main/resources/OH-INF…
PRosenb May 6, 2024
176daef
[iotawatt] run i18n plugin
PRosenb May 6, 2024
0e2645d
[iotawatt] add connection
PRosenb May 6, 2024
b1c84da
[iotawatt] adjust to Java 21
PRosenb May 7, 2024
5cf7fcb
[iotawatt] use custom exception
PRosenb May 7, 2024
4419f1f
[iotawatt] add request timeout
PRosenb May 7, 2024
d732e3d
[iotawatt] configurable request timeout
PRosenb May 7, 2024
73379d2
[iotawatt] check httpsStatus
PRosenb May 7, 2024
f58a2ef
[iotawatt] update translations
PRosenb May 7, 2024
29c2f83
[iotawatt] split exception to individual ones
PRosenb May 8, 2024
7689031
[iotawatt] adjust log level
PRosenb May 13, 2024
ed52ca3
[iotawatt] use Optional for null check
PRosenb May 13, 2024
b231d6d
[iotawatt] rename to deviceHandlerCallback
PRosenb May 13, 2024
66b799f
[iotawatt] update example config
PRosenb May 13, 2024
87df964
[iotawatt] add configuration error
PRosenb May 19, 2024
b2ae559
[iotawatt] start httpClient outside of factory
PRosenb May 19, 2024
9bcdbf2
Update bundles/org.openhab.binding.iotawatt/src/main/java/org/openhab…
PRosenb May 22, 2024
3ce5cc6
Update bundles/org.openhab.binding.iotawatt/src/main/java/org/openhab…
PRosenb May 22, 2024
203f18a
Update bundles/org.openhab.binding.iotawatt/README.md
PRosenb May 22, 2024
bedbed7
Update bundles/org.openhab.binding.iotawatt/src/main/resources/OH-INF…
PRosenb May 22, 2024
df7370b
[iotawatt] move to channels
PRosenb May 22, 2024
6171654
[iotawatt] remove not required mockito config
PRosenb May 22, 2024
636a185
[iotawatt] add channel IDs in table
PRosenb May 22, 2024
7c163fe
[iotawatt] add @Deactivate
PRosenb May 22, 2024
18bd203
[iotawatt] move configuration-error to iotawatt.properties
PRosenb May 22, 2024
d6f371a
[iotawatt] add dimensions to Items definition
PRosenb May 25, 2024
c170b54
[iotawatt] use %unit% in state pattern
PRosenb May 25, 2024
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
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@
/bundles/org.openhab.binding.ihc/ @paulianttila
/bundles/org.openhab.binding.insteon/ @robnielsen
/bundles/org.openhab.binding.intesis/ @hmerk
/bundles/org.openhab.binding.iotawatt/ @PRosenb
/bundles/org.openhab.binding.ipcamera/ @Skinah
/bundles/org.openhab.binding.ipobserver/ @Skinah
/bundles/org.openhab.binding.ipp/ @peuter
Expand Down
5 changes: 5 additions & 0 deletions bom/openhab-addons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,11 @@
<artifactId>org.openhab.binding.intesis</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.iotawatt</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.ipcamera</artifactId>
Expand Down
13 changes: 13 additions & 0 deletions bundles/org.openhab.binding.iotawatt/NOTICE
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/openhab-addons
86 changes: 86 additions & 0 deletions bundles/org.openhab.binding.iotawatt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# IoTaWatt Binding

This binding integrates [IoTaWatt™ Open WiFi Electric Power Monitor](https://iotawatt.com/) into openHAB.

Limitations of this version:

- No authentication support

## Supported Things

The IoTaWatt binding supports one Thing called `iotawatt`.

## Discovery

The binding does not auto-discover the IoTaWatt device.

## Thing Configuration

### IoTaWatt Thing Configuration

| Name | Type | Description | Default | Required | Advanced |
|-----------------|---------|------------------------------------------------|---------|----------|----------|
| hostname | text | Hostname or IP address of the device | N/A | yes | no |
| refreshInterval | integer | Interval the device is polled in sec. | 10 | no | no |
| requestTimeout | long | The request timeout to call the device in sec. | 10 | no | no |

## Channels

The binding detects configured inputs and outputs and creates channels for them.

| Channel | Type | ID | Read/Write | Description |
|---------------------|--------------------------|---------------------|------------|---------------------------------|
| Amps | Number:Power | amps | RO | The current amps |
| Frequency | Number:Frequency | frequency | RO | The current AC frequency |
| Power Factor | Number:Dimensionless | power-factor | RO | The current power factor |
| Apparent Power | Number:Power | apparent-power | RO | The current apparent power |
| Reactive Power | Number:Power | reactive-power | RO | The current reactive power |
| Reactive Power hour | Number:Power | reactive-power-hour | RO | The current reactive power hour |
| Voltage | Number:ElectricPotential | voltage | RO | The current voltage |
| Power Consumption | Number:Power | watts | RO | The current power consumption |
| Phase | Number:Dimensionless | phase | RO | The current phase |

## Example Configuration

### Thing with Channels

```java
Thing iotawatt:iotawatt:iotawatt1 "IoTaWatt 1" [ hostname="192.168.1.10" ] {
Channels:
Type voltage : input_00#voltage "Voltage"
Type frequency : input_00#frequency "AC Frequency"
Type phase : input_00#phase "Phase"
Type watts : input_01#watts "Power Consumption"
Type power-factor : input_01#power-factor "Power Factor"
Type phase : input_01#phase "Phase"

Type amps : output_00#Input_1_amps "Amps"
Type frequency : output_01#Input_1_hz "Frequency"
Type power-factor : output_02#Input_1_pf "Power Factor"
Type apparent-power : output_03#Input_1_va "Apparent Power"
Type reactive-power : output_04#Input_1_var "Reactive Power"
Type reactive-power-hour : output_05#Input_1_varh "Reactive Power Hour"
Type voltage : output_06#Input_1_volts "Voltage"
Type watts : output_07#Input_1_watts "Watts"
}
```

### Items

```java
Number:ElectricPotential input_voltage "Voltage" { channel="iotawatt:iotawatt:iotawatt1:input_00#voltage" }
Number:Frequency input_frequency "AC Frequency" { channel="iotawatt:iotawatt:iotawatt1:input_00#frequency" }
Number:Dimensionless input_phase0 "Phase" { channel="iotawatt:iotawatt:iotawatt1:input_00#phase" }
Number:Power input_watts "Watts" { channel="iotawatt:iotawatt:iotawatt1:input_01#watts" }
Number:Dimensionless input_power_factor "Power Factor" { channel="iotawatt:iotawatt:iotawatt1:input_01#power-factor" }
Number:Dimensionless input_phase1 "Phase" { channel="iotawatt:iotawatt:iotawatt1:input_01#phase" }

Number:ElectricCurrent output_amps "Amps" { channel="iotawatt:iotawatt:iotawatt1:output_00#Input_1_amps" }
Number:Frequency output_frequency "AC Frequency" { channel="iotawatt:iotawatt:iotawatt1:output_01#Input_1_hz" }
Number:Dimensionless output_power_factor "Power Factor" { channel="iotawatt:iotawatt:iotawatt1:output_02#Input_1_pf" }
Number:Power output_apparent_power "Apparent Power" { channel="iotawatt:iotawatt:iotawatt1:output_03#Input_1_va" }
Number:Power output_reactive_power "Reactive Power" { channel="iotawatt:iotawatt:iotawatt1:output_04#Input_1_var" }
Number:Energy output_reactive_power_hour "Reactive Power Hour" { channel="iotawatt:iotawatt:iotawatt1:output_05#Input_1_varh" }
Number:ElectricPotential output_voltage "Voltage" { channel="iotawatt:iotawatt:iotawatt1:output_06#Input_1_volts" }
Number:Power output_watts "Watts" { channel="iotawatt:iotawatt:iotawatt1:output_07#Input_1_watts" }
```
25 changes: 25 additions & 0 deletions bundles/org.openhab.binding.iotawatt/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?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 https://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>4.2.0-SNAPSHOT</version>
</parent>

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

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

<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.11.0</version>
lsiepel marked this conversation as resolved.
Show resolved Hide resolved
<scope>test</scope>
</dependency>
</dependencies>
</project>
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.iotawatt-${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-iotawatt" description="IoTaWatt Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.iotawatt/${project.version}</bundle>
</feature>
</features>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2024 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.iotawatt.internal;

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

/**
* The {@link IoTaWattBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Peter Rosenberg - Initial contribution
*/
@NonNullByDefault
public class IoTaWattBindingConstants {
/**
* The binding ID of the IoTaWatt binding
*/
public static final String BINDING_ID = "iotawatt";

/**
* The list of all Thing Type UIDs
*/
public static final ThingTypeUID THING_TYPE_IOTAWATT = new ThingTypeUID(BINDING_ID, "iotawatt");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* Copyright (c) 2010-2024 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.iotawatt.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The {@link IoTaWattConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Peter Rosenberg - Initial contribution
*/
@NonNullByDefault
public class IoTaWattConfiguration {
private final Logger logger = LoggerFactory.getLogger(IoTaWattConfiguration.class);
/**
* The default refresh interval of the IoTaWatt device
*/
public static final int REFRESH_INTERVAL_DEFAULT = 10;
/**
* The default of the request timeout
*/
public static final long REQUEST_TIMEOUT_DEFAULT = 10;

/**
* Configuration parameters
*/
public String hostname = "";
/**
* The request timeout in seconds when fetching data from the IoTaWatt device
*/
public long requestTimeout = REQUEST_TIMEOUT_DEFAULT;
/**
* The refresh interval of the IoTaWatt device in seconds
*/
public int refreshInterval = REFRESH_INTERVAL_DEFAULT;

public boolean isValid() {
if (hostname.trim().isBlank()) {
logger.warn("Hostname is blank, please specify the hostname/IP address of IoTaWatt.");
return false;
}
if (requestTimeout <= 0) {
logger.warn("Invalid requestTimeout {}, please use a positive number", requestTimeout);
return false;
}
if (refreshInterval <= 0) {
logger.warn("Invalid refreshInterval {}, please use a positive number", refreshInterval);
return false;
}
// Also update "configuration-error" in src/main/resources/OH-INF/i18n/iotawatt_en.properties
return true;
}
}
PRosenb marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Copyright (c) 2010-2024 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.iotawatt.internal;

import static org.openhab.binding.iotawatt.internal.IoTaWattBindingConstants.THING_TYPE_IOTAWATT;

import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.openhab.binding.iotawatt.internal.client.IoTaWattClient;
import org.openhab.binding.iotawatt.internal.handler.FetchDataServiceProvider;
import org.openhab.binding.iotawatt.internal.handler.HttpClientProvider;
import org.openhab.binding.iotawatt.internal.handler.IoTaWattClientProvider;
import org.openhab.binding.iotawatt.internal.handler.IoTaWattHandler;
import org.openhab.binding.iotawatt.internal.service.DeviceHandlerCallback;
import org.openhab.binding.iotawatt.internal.service.FetchDataService;
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;
import org.osgi.service.component.annotations.Deactivate;

import com.google.gson.Gson;

/**
* The {@link IoTaWattHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Peter Rosenberg - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.iotawatt", service = ThingHandlerFactory.class)
public class IoTaWattHandlerFactory extends BaseThingHandlerFactory
implements HttpClientProvider, IoTaWattClientProvider, FetchDataServiceProvider {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_IOTAWATT);

private final HttpClient insecureClient;
private final Gson gson = new Gson();

/**
* Creates a IoTaWattHandlerFactory
*/
public IoTaWattHandlerFactory() {
this.insecureClient = new HttpClient(new SslContextFactory.Client(true));
}

@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 (THING_TYPE_IOTAWATT.equals(thingTypeUID)) {
return new IoTaWattHandler(thing, this, this);
}

return null;
}

@Override
public HttpClient getInsecureClient() {
return insecureClient;
}

@Override
public IoTaWattClient getIoTaWattClient(String hostname, long requestTimeout) {
return new IoTaWattClient(hostname, requestTimeout, insecureClient, gson);
}

PRosenb marked this conversation as resolved.
Show resolved Hide resolved
@Override
public FetchDataService getFetchDataService(DeviceHandlerCallback deviceHandlerCallback) {
return new FetchDataService(deviceHandlerCallback);
}

@Deactivate
public void deactivate() {
insecureClient.destroy();
}
}