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

[fenecon] Initial contribution #17174

Merged
merged 36 commits into from
Sep 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9d2c67c
Initial implementation of the FENECON Binding
nixoso Jul 28, 2024
32194f6
Fix: Enter new binding in bundle pom.xml
nixoso Jul 28, 2024
83f63a1
Fix: Enter new binding in bom/openhab-addons pom.xml
nixoso Jul 28, 2024
6e2f943
Fix format validation in bundle pom.xml
nixoso Jul 28, 2024
3b338e1
Fix warning in markdown
nixoso Jul 28, 2024
a4e7d5a
Fix null pointer warnings
nixoso Jul 28, 2024
0cf1589
Fix tow checkstyle notices.
nixoso Jul 28, 2024
02ff037
Removed unnecessary code comments.
nixoso Jul 28, 2024
469c7ef
Add code owner information.
nixoso Aug 2, 2024
6281b0d
[Review]: Change initial delay of the polling job.
nixoso Aug 2, 2024
496594f
[Review]: Change log level of initialization message.
nixoso Aug 2, 2024
816c395
[Review]: Add unitHint for battery state
nixoso Aug 2, 2024
113dcef
[Review]: Fix naming convention
nixoso Aug 2, 2024
6518705
[Review]: Change emergency-power-mode description
nixoso Aug 2, 2024
6ac4c93
[Review]: Label / Naming improvements
nixoso Aug 2, 2024
d013bf4
[Review]: Add default translation file
nixoso Aug 2, 2024
f716017
[Review]: Change thing type id
nixoso Aug 2, 2024
fc1e6e5
Remove comment
nixoso Aug 3, 2024
40a3199
[Review]: Seperation of concerns and extract strings as constants
nixoso Aug 3, 2024
1f472f8
Small refactorings for converting values.
nixoso Aug 3, 2024
10455d7
Added tests.
nixoso Aug 3, 2024
89fb2ab
Add connection tag to addon.xml
nixoso Aug 3, 2024
6308e04
[Review]: Add tabs for DSL demo.rules
nixoso Aug 3, 2024
6e13a9e
[Review]: Change thing type id to home-device
nixoso Aug 3, 2024
6f101bf
Remove a checkstyle and PMD info and warning.
nixoso Aug 3, 2024
0d0570e
[Review]: Update readme.md to new thing type id.
nixoso Aug 3, 2024
1dd5e07
Error handling improved.
nixoso Aug 15, 2024
1a567a4
Handling improved for values that are not available.
nixoso Aug 16, 2024
de82640
Added new channels for each consumption-active-power-phase 1, 2 and 3.
nixoso Aug 16, 2024
c7af0d9
Added new channels for consumption and production max active power.
nixoso Aug 16, 2024
a66b870
Fix format conflict.
nixoso Aug 24, 2024
4c081d1
Fix format conflict.
nixoso Aug 24, 2024
77b4893
[Review]: Removed unnecessary tags.
nixoso Aug 29, 2024
8f72843
[Review]: Removed unnecessary comment.
nixoso Aug 29, 2024
354c41e
[Review]: Removed unnecessary blank lines.
nixoso Aug 29, 2024
9bd8908
[Review]: Change from java to jetty common httpclient.
nixoso Sep 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
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 @@ -113,6 +113,7 @@
/bundles/org.openhab.binding.exec/ @kgoderis
/bundles/org.openhab.binding.feed/ @openhab/add-ons-maintainers
/bundles/org.openhab.binding.feican/ @Hilbrand
/bundles/org.openhab.binding.fenecon/ @nixoso
/bundles/org.openhab.binding.fineoffsetweatherstation/ @Andy2003
/bundles/org.openhab.binding.flicbutton/ @pfink
/bundles/org.openhab.binding.fmiweather/ @ssalonen
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 @@ -556,6 +556,11 @@
<artifactId>org.openhab.binding.feican</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.fenecon</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.fineoffsetweatherstation</artifactId>
Expand Down
13 changes: 13 additions & 0 deletions bundles/org.openhab.binding.fenecon/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
160 changes: 160 additions & 0 deletions bundles/org.openhab.binding.fenecon/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# FENECON Binding

The FENECON Binding integrates the [FENECON energy storage system](https://fenecon.de/) device into the openHAB system via [REST-API](https://docs.fenecon.de/_/de/fems/fems-app/OEM_App_REST_JSON.html).

With the binding, it is possible to request status information from FENECON Home to allow you home automation decisions based on the current energy management.

This makes it possible, for example, to switch on other consumers such as the dishwasher or washing machine in the case of power overproduction.

## Supported Things

Currently only one Thing is supported: The `home-device` connection to the FENECON energy storage system.

This Binding was tested with an [FENECON HOME 10](https://fenecon.de/fenecon-home-10/) device.

## Discovery

Auto-discovery is not supported.

## Thing Configuration

The FENECON Thing only needs to be configured with the `hostname`, all other parameters are optional and prefilled with the suitable default values:

| Parameter | Description |
|-----------------|----------------------------------------------------------------------------------|
| hostname | Hostname or IP address of the FENECON device, e.g. 192.168.1.11 |
| password | Password of the FENECON device. The password for guest access is set by default. |
| port | Port of the FENECON device. Default: 8084 |
| refreshInterval | Interval the device is polled in sec. Default 30 seconds |

## Channels

The FENECON binding currently only provides access to read out the values from the energy storage system.

| Channel | Type | Read/Write | Description |
|-------------------------------|----------------------|------------|-----------------------------------------------------------------------------|
| state | String | R | FENECON system state: Ok, Info, Warning or Fault |
| last-update | DateTime | R | Last successful update via REST-API from the FENECON system |
| ess-soc | Number:Dimensionless | R | Battery state of charge in percent |
| charger-power | Number:Power | R | Current charger power of energy storage system in watt. |
| discharger-power | Number:Power | R | Current discharger power of energy storage system in watt. |
| emergency-power-mode | Switch | R | Indicates if there is grid power is off and the emergency power mode is on. |
| production-active-power | Number:Power | R | Current active power producer load in watt. |
| production-max-active-power | Number:Power | R | Maximum active production power in watt that was measured. |
| export-to-grid-power | Number:Power | R | Current export power to grid in watt. |
| exported-to-grid-energy | Number:Energy | R | Total energy exported to the grid in watt per hour. |
| consumption-active-power | Number:Power | R | Current active power consumer load in watt. |
| consumption-max-active-power | Number:Power | R | Maximum active consumption power in watt that was measured. |
| consumption-active-power-l1 | Number:Power | R | Current active power consumer load in watt on phase 1. |
| consumption-active-power-l2 | Number:Power | R | Current active power consumer load in watt on phase 2. |
| consumption-active-power-l3 | Number:Power | R | Current active power consumer load in watt on phase 3. |
| import-from-grid-power | Number:Power | R | Current import power from grid in watt. |
| imported-from-grid-energy | Number:Energy | R | Total energy imported from the grid in watt per hour. |

## Full Example

### fenecon.things

```java
Thing fenecon:home-device:local "FENECON Home" [hostname="192.168.1.11", refreshInterval=5]
```

### demo.items

```java
// Sitemap Items
Group Home "MyHome" <house> ["Indoor"]
Group GF "GroundFloor" <groundfloor> (Home) ["GroundFloor"]
// Utility room
Group GF_UtilityRoom "Utility room" <energy> (Home, GF) ["Room"]
Group GF_UtilityRoomSolar "Utility room solar" <solarplant> (GF_UtilityRoom) ["Inverter"]

// FENECON items
String EssState <text> (GF_UtilityRoomSolar) ["Status"] {channel="fenecon:home-device:local:state"}
DateTime LastFeneconUpdate <time> (GF_UtilityRoomSolar) ["Status"] {channel="fenecon:home-device:local:last-update"}
Number:Dimensionless EssSoc <batterylevel> (GF_UtilityRoomSolar) ["Measurement"] {unit="%", channel="fenecon:home-device:local:ess-soc"}
Number:Power ChargerPower <energy> (GF_UtilityRoomSolar) ["Measurement", "Power"] {channel="fenecon:home-device:local:charger-power"}
Number:Power DischargerPower <energy> (GF_UtilityRoomSolar) ["Measurement", "Power"] {channel="fenecon:home-device:local:discharger-power"}
Switch EmergencyPowerMode <switch> (GF_UtilityRoomSolar) ["Switch"] {channel="fenecon:home-device:local:emergency-power-mode"}

Number:Power ProductionActivePower <energy> (GF_UtilityRoomSolar) ["Measurement", "Power"] {channel="fenecon:home-device:local:production-active-power"}
Number:Power ProductionMaxActivePower <energy> (GF_UtilityRoomSolar) ["Measurement", "Power"] {channel="fenecon:home-device:local:production-max-active-power"}
Number:Power SellToGridPower <energy> (GF_UtilityRoomSolar) ["Measurement", "Power"] {channel="fenecon:home-device:local:export-to-grid-power"}
Number:Energy TotalSellEnergy <energy> (GF_UtilityRoomSolar) ["Measurement", "Energy"] {channel="fenecon:home-device:local:exported-to-grid-energy"}

Number:Power ConsumptionActivePower <energy> (GF_UtilityRoomSolar) ["Measurement", "Power"] {channel="fenecon:home-device:local:consumption-active-power"}
Number:Power ConsumptionMaxActivePower <energy> (GF_UtilityRoomSolar) ["Measurement", "Power"] {channel="fenecon:home-device:local:consumption-max-active-power"}
Number:Power ConsumptionActivePowerPhase1 <energy> (GF_UtilityRoomSolar) ["Measurement", "Power"] {channel="fenecon:home-device:local:consumption-active-power-l1"}
Number:Power ConsumptionActivePowerPhase2 <energy> (GF_UtilityRoomSolar) ["Measurement", "Power"] {channel="fenecon:home-device:local:consumption-active-power-l2"}
Number:Power ConsumptionActivePowerPhase3 <energy> (GF_UtilityRoomSolar) ["Measurement", "Power"] {channel="fenecon:home-device:local:consumption-active-power-l3"}
Number:Power BuyFromGridPower <energy> (GF_UtilityRoomSolar) ["Measurement", "Power"] {channel="fenecon:home-device:local:import-from-grid-power"}
Number:Energy TotalBuyEnergy <energy> (GF_UtilityRoomSolar) ["Measurement", "Energy"] {channel="fenecon:home-device:local:imported-from-grid-energy"}

// Examples of items for calculating the energy purchased and sold. Look at the demo.rules section.
Number:Currency SoldEnergy "Total sold energy [%.2f €]" <price> (GF_UtilityRoomSolar)
Number:Currency PurchasedEnergy "Total purchased energy [%.2f €]" <price> (GF_UtilityRoomSolar)

```

### demo.sitemap

```perl
sitemap demo label="FENECON Example Sitemap" {
Frame label="Groundfloor" icon="groundfloor" {
Group item=GF_UtilityRoom
}
}
```

### demo.rules

:::: tabs

::: tab DSL

```java
lsiepel marked this conversation as resolved.
Show resolved Hide resolved
rule "Blackout detection"
when
Item EmergencyPowerMode changed to ON
then
val msg = "🚨 Power blackout detected, emergency power mode running."
logInfo("PowerBlackout", msg)
sendBroadcastNotification(msg)
end

rule "Battery 100 percent"
when
Item EssSoc changed
then
var batteryState = (EssSoc.getState() as Number).intValue()
if(batteryState == 100){
val msg = "🔋 Full battery, consumers can be activated."
logInfo("FullBattery", msg)
sendBroadcastNotification(msg)
}
end

rule "Calculation sold energy"
when
Item TotalSellEnergy changed
then
val sellingPricePerKiloWattHour = 0.07 // €
var current = (TotalSellEnergy.getState() as Number).intValue()
var result = current * sellingPricePerKiloWattHour;
SoldEnergy.postUpdate(result)
end

rule "Calculation purchased energy"
when
Item TotalBuyEnergy changed
then
val purchasedPricePerKiloWattHour = 0.32 // €
var current = (TotalBuyEnergy.getState() as Number).intValue()
var result = current * purchasedPricePerKiloWattHour;
PurchasedEnergy.postUpdate(result)
end
```

:::

::::
17 changes: 17 additions & 0 deletions bundles/org.openhab.binding.fenecon/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?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.3.0-SNAPSHOT</version>
</parent>

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

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

lsiepel marked this conversation as resolved.
Show resolved Hide resolved
lsiepel marked this conversation as resolved.
Show resolved Hide resolved
</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.fenecon-${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-fenecon" description="FENECON Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.fenecon/${project.version}</bundle>
</feature>
</features>
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* 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.fenecon.internal;

import java.util.List;

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

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

private static final String BINDING_ID = "fenecon";

// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_HOME_DEVICE = new ThingTypeUID(BINDING_ID, "home-device");

// List of all FENECON Addresses
public static final String STATE_ADDRESS = "_sum/State";
public static final String ESS_SOC_ADDRESS = "_sum/EssSoc";
public static final String CONSUMPTION_ACTIVE_POWER_ADDRESS = "_sum/ConsumptionActivePower";
public static final String CONSUMPTION_ACTIVE_POWER_PHASE1_ADDRESS = "_sum/ConsumptionActivePowerL1";
public static final String CONSUMPTION_ACTIVE_POWER_PHASE2_ADDRESS = "_sum/ConsumptionActivePowerL2";
public static final String CONSUMPTION_ACTIVE_POWER_PHASE3_ADDRESS = "_sum/ConsumptionActivePowerL3";
public static final String CONSUMPTION_MAX_ACTIVE_POWER_ADDRESS = "_sum/ConsumptionMaxActivePower";
public static final String PRODUCTION_MAX_ACTIVE_POWER_ADDRESS = "_sum/ProductionMaxActivePower";
public static final String PRODUCTION_ACTIVE_POWER_ADDRESS = "_sum/ProductionActivePower";
public static final String GRID_ACTIVE_POWER_ADDRESS = "_sum/GridActivePower";
public static final String ESS_DISCHARGE_POWER_ADDRESS = "_sum/EssDischargePower";
public static final String GRID_MODE_ADDRESS = "_sum/GridMode";
public static final String GRID_SELL_ACTIVE_ENERGY_ADDRESS = "_sum/GridSellActiveEnergy";
public static final String GRID_BUY_ACTIVE_ENERGY_ADDRESS = "_sum/GridBuyActiveEnergy";
// Group of all FENECON Addresses
public static final List<String> ADDRESSES = List.of(STATE_ADDRESS, GRID_MODE_ADDRESS,
CONSUMPTION_ACTIVE_POWER_ADDRESS, CONSUMPTION_ACTIVE_POWER_PHASE1_ADDRESS,
CONSUMPTION_ACTIVE_POWER_PHASE2_ADDRESS, CONSUMPTION_ACTIVE_POWER_PHASE3_ADDRESS,
CONSUMPTION_MAX_ACTIVE_POWER_ADDRESS, PRODUCTION_MAX_ACTIVE_POWER_ADDRESS, PRODUCTION_ACTIVE_POWER_ADDRESS,
GRID_ACTIVE_POWER_ADDRESS, GRID_BUY_ACTIVE_ENERGY_ADDRESS, GRID_SELL_ACTIVE_ENERGY_ADDRESS, ESS_SOC_ADDRESS,
ESS_DISCHARGE_POWER_ADDRESS);

// List of all Channel IDs
public static final String STATE_CHANNEL = "state";
public static final String ESS_SOC_CHANNEL = "ess-soc";
public static final String CONSUMPTION_ACTIVE_POWER_CHANNEL = "consumption-active-power";
public static final String CONSUMPTION_ACTIVE_POWER_PHASE1_CHANNEL = "consumption-active-power-l1";
public static final String CONSUMPTION_ACTIVE_POWER_PHASE2_CHANNEL = "consumption-active-power-l2";
public static final String CONSUMPTION_ACTIVE_POWER_PHASE3_CHANNEL = "consumption-active-power-l3";
public static final String CONSUMPTION_MAX_ACTIVE_POWER_CHANNEL = "consumption-max-active-power";
public static final String PRODUCTION_MAX_ACTIVE_POWER_CHANNEL = "production-max-active-power";
public static final String PRODUCTION_ACTIVE_POWER_CHANNEL = "production-active-power";
public static final String EXPORT_TO_GRID_POWER_CHANNEL = "export-to-grid-power";
public static final String IMPORT_FROM_GRID_POWER_CHANNEL = "import-from-grid-power";
public static final String ESS_CHARGER_POWER_CHANNEL = "charger-power";
public static final String ESS_DISCHARGER_POWER_CHANNEL = "discharger-power";
public static final String EMERGENCY_POWER_MODE_CHANNEL = "emergency-power-mode";
public static final String EXPORTED_TO_GRID_ENERGY_CHANNEL = "exported-to-grid-energy";
public static final String IMPORTED_FROM_GRID_ENERGY_CHANNEL = "imported-from-grid-energy";
public static final String LAST_UPDATE_CHANNEL = "last-update";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* 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.fenecon.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;

/**
* The {@link FeneconConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Philipp Schneider - Initial contribution
*/
@NonNullByDefault
public class FeneconConfiguration {

public String hostname = "";
public String password = "user";
public int port = 8084;
public int refreshInterval = 30;
}
Loading