Skip to content

Commit

Permalink
[fenecon] Initial contribution (#17174)
Browse files Browse the repository at this point in the history
* Initial implementation of the FENECON Binding

Signed-off-by: Philipp Schneider <philipp.schneider@nixo-soft.de>
  • Loading branch information
nixoso authored Sep 8, 2024
1 parent 66cfcc2 commit 6b2462c
Show file tree
Hide file tree
Showing 26 changed files with 1,382 additions and 0 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,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 @@ -551,6 +551,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
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>

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

0 comments on commit 6b2462c

Please sign in to comment.