added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<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>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.modbus.e3dc</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>

View File

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

View File

@@ -0,0 +1,371 @@
# E3DC Binding
<img align="right" src="./doc/E3DC_logo.png"/>
Integrates the Home Power Plants from E3/DC GmbH into openHAB. See [E3DC Website](https://www.e3dc.com/) to find more informations about the device.
The Power Plant handles all your Electrical Energy Resources like Photovoltaic Producers, Battery Storage, Wallbox Power Supply, Household Consumption and even more.
E3DC devices are integrated into the Modbus Binding.
See chapter [Thing Configuration](#thing-configuration) how to set them up or check the [full example Things](#things) for manual setup.
## Supported Things
First you need a Bridge which establishes the basic connection towards your E3DC device
| Name | Thing Type ID | Description |
|-----------------------|---------------|------------------------------------------------------------------------------------------------------|
| E3DC Home Power Plant | e3dc | Provides Power values, String Details, Emergency Power Status and general Information of your E3DC Home Power Plant |
| E3DC Wallbox | e3dc-wallbox | Provides your Wallbox Settings. Switches like "Sunmode" or "1-Phase Charging" can be changed |
## Discovery
There's no discovery. Modbus registers are available for all devices.
## Thing Configuration
As mentioned earlier in the [Binding Description](#e3dc-binding) the needed Things can be found in the **Modbus Binding** and have to be added manually without Discovery
<img align="right" src="./doc/E3DC_Modbus_Settings.png"/>
1. Create _Modbus TCP Bridge_ with matching Settings of your E3DC Device
* IP Address
* Device ID
* Port ID
2. Create _E3DC Home Power Plant_ and attach it to the previous installed _Modbus TCP Bridge_. Configuration requires an approriate Data Refresh Interval with more than 1000 Milliseconds
3. If you have a Wallbox attached add _E3DC Wallbox_ Thing with your previous installed _E3DC Home Power Plant_ as Bridge. Configuration requires a Wallbox ID between 0 and 7.
Check the [full example Things](#things) for manual setup.
### Modbus TCP Slave
| Parameter | Type | Description |
|-----------------|---------|-------------------------------------------------------------------------|
| host | text | IP Address of your device |
| port | integer | TCP Port of your E3DC device Modbus Settings.. Default is 502 |
| deviceid | integer | Modbus ID of your E3DC device Modbus Settings. Default is 1 |
### E3DC Home Power Plant
Select as Bridge your previously created Modbus TCP Slave.
| Parameter | Type | Description |
|-----------------|---------|-------------------------------------------------------------------------|
| refresh | integer | Refresh Rate of E3DC values in Milliseconds |
### E3DC Wallbox
Select as Bridge your previously created E3DC Home Power Plant.
| Parameter | Type | Description |
|-----------------|---------|-----------------------------------------------------------------------------|
| wallboxId | integer | E3DC supports up to 8 Wallboxes - select a value from 0 to 7 |
## Channels
The E3DC device offers quite an amount of channels. For clustering 4 Channel Groups are used:
### Channel Group _Information Block_
| Channel Label | Channel Group ID | Channel ID | Type | Description |
|-----------------------|------------------|---------------------|--------|---------------------------------------------------|
| Modbus-ID | info | modbus-id | String | Modbus ID / Magic Byte of E3DC |
| Modbus Firmware | info | modbus-firmware | String | Version of Modbus Firmware |
| Supported Registers | info | supported-registers | Number | Number of registers supported by Modbus |
| Manufacturer Name | info | manufacturer-name | String | Name of the Device Manufacturer |
| E3DC Model Name | info | model-name | String | Name of the E3DC Model |
| E3DC Firmware Release | info | firmware-release | String | Firmware installed on this particular E3DC Device |
| E3DC Serial Number | info | serial-number | String | Serial Number of this particular E3DC Device |
### Channel Group _Power Block_
| Channel Label | Channel Group ID | Channel ID | Type | Description |
|-------------------------------|-------------------|------------------------------|------------------------|------------------------------|
| PV Output | power | pv-power-supply | Number:Power | Photovoltaic Power Production |
| Battery Discharge | power | battery-power-supply | Number:Power | Battery discharges and provides Power |
| Battery Charge | power | battery-power-consumption | Number:Power | Battery charges and consumes Power |
| Household Consumption | power | household-power-consumption | Number:Power | Household consuming Power |
| Grid Power Consumption | power | grid-power-consumption | Number:Power | Grid Power is needed in order to satisfy your overall Power consumption |
| Grid Power Supply | power | grid-power-supply | Number:Power | More Photovoltaic Power is produced than needed. Additional Power is provided towards the Grid |
| External Power Supply | power | external-power-supply | Number:Power | Power produced by an external device which is attached to your E3DC device |
| Wallbox Power Consumption | power | wallbox-power-consumption | Number:Power | Power consumption of attached Wallboxes |
| Wallbox PV Power Consumption | power | wallbox-pv-power-consumption | Number:Power | Photovoltaic Power consumption (PV plus Battery) of attached Wallboxes |
| Autarky | power | autarky-channel | Number:Dimensionless | Your current Autarky Level in Percent |
| Self Consumption | power | self-consumption | Number:Dimensionless | Your current Photovoltaic Self Consumption Level in Percent |
| Battery State Of Charge | power | battery-soc | Number:Dimensionless | Charge Level of your attached Battery in Percent |
### Channel Group _String Details Block_
| Channel Label | Channel Group ID | Channel ID | Type | Description |
|-----------------------|------------------|--------------------|---------------------------|------------------------------|
| String 1 Potential | strings | string1-dc-voltage | Number:ElectricPotential | Voltage on String 1 |
| String 2 Potential | strings | string2-dc-voltage | Number:ElectricPotential | Voltage on String 2 |
| String 3 Potential | strings | string3-dc-voltage | Number:ElectricPotential | Voltage on String 3 |
| String 1 Current | strings | string1-dc-current | Number:ElectricCurrent | Current on String 1 |
| String 2 Current | strings | string2-dc-current | Number:ElectricCurrent | Current on String 2 |
| String 3 Current | strings | string3-dc-current | Number:ElectricCurrent | Current on String 3 |
| String 1 Power | strings | string1-dc-output | Number:Power | Power produced by String 1 |
| String 2 Power | strings | string2-dc-output | Number:Power | Power produced by String 2 |
| String 3 Power | strings | string3-dc-output | Number:Power | Power produced by String 3 |
### Channel _EMS Block_
| Channel Label | Channel Group ID | Channel ID | Type | Description |
|---------------------------------------------|------------------|----------------------------|----------------|------------------------------|
| Emergency Power Status | emergency | emergency-power-status | String | Possible values: EP not supported, EP active, EP not active, EP not available, EP Switch in wrong position, EP Status unknown |
| Battery Charging Locked | emergency | battery-charging-lock | Switch | Battery charging is locked |
| Battery Discharging Locked | emergency | battery-discharging-lock | Switch | Battery discharging is locked |
| Emergency Power Possible | emergency | emergency-power-possible | Switch | Emergency Power Supply is possible |
| Weather Predicted Battery Charging | emergency | weather-predicted-charging | Switch | Weather Predicted Battery Charging is activated |
| Regulation Status Of Max Grid Power Supply | emergency | regulation-status | Switch | Grid Power Supply is currently regulated |
| Charge Lock time Active | emergency | charge-lock-time | Switch | Charge Lock Time is currently active |
| Discharge Lock time Active | emergency | discharge-lock-time | Switch | Discharge Lock Time is currently active |
### E3DC Wallbox Channels
Some of the Wallbox Settings can be changed. See the Access column if the actual value is Read/Write (RW) or Read Only (RO)
| Channel Label | Channel ID | Type | Access | Description |
|--------------------------|---------------------|---------|--------|------------------------------|
| Wallbox Available | wb-available | Switch | RO | Indicates if the Wallbox is attached. Check your Wallbox ID in offline case |
| Sun Mode | wb-sunmode | Switch | RW | Activate / Deactivate Sun Mode. Off case takes Grid Power to ensure highest possible charging. |
| Wallbox Charging Aborted | wb-charging-aborted | Switch | RW | Wallbox charging is aborted |
| Wallbox Charging | wb-charging | Switch | RO | Wallbox is charging |
| Jack Locked | wb-jack-locked | Switch | RO | Jack is locked |
| Jack Plugged | wb-jack-plugged | Switch | RO | Jack is plugged |
| Schuko Socket On | wb-schuko-on | Switch | RW | If your Wallbox has an additional Schuko Socket it provides state ON or OFF |
| Schuko Socket Plugged | wb-schuko-plugged | Switch | RO | If your Wallbox has an additional Schuko Socket it provides plugged state ON or OFF |
| Schuko Socket Locked | wb-schuko-locked | Switch | RO | If your Wallbox has an additional Schuko Socket it provides locked state ON or OFF |
| Schuko 16A Relay On | wb-schuko-relay-16a | Switch | RO | Schuko 16A Relay is ON |
| 16A Relay On | wb-relay-16a | Switch | RO | Wallbox 16A Relay is ON |
| 32A Relay On | wb-relay-32a | Switch | RO | Wallbox 32A Relay is ON |
| 1-Phase Charging | 1-Phase Active | Switch | RW | 1-phase charging is activated. If OFF 3-phase charging is activated |
## Full Example
Following example provides the full configuration. If you enter the correct Connection Data, IP Address, Device ID and Port number in the thing configuration you should be fine.
### Things
```
Bridge modbus:tcp:device "E3DC Modbus TCP" [ host="192.168.178.56", port=502, id=1 ] {
Bridge e3dc powerplant "E3DC Power Plant" [ refresh=2500 ] {
Thing e3dc-wallbox wallbox0 "E3DC Wallbox" [ wallboxId=0]
}
}
```
### Items
```
String E3DC_ModbusId "E3DC Modbus ID" (e3dc) { channel="modbus:e3dc:device:powerplant:info#modbus-id" }
String E3DC_ModbusFirmware "E3DC Modbus Firmware" (e3dc) { channel="modbus:e3dc:device:powerplant:info#modbus-firmware" }
Number E3DC_SupportedRegisters "E3DC Supported Registers" (e3dc) { channel="modbus:e3dc:device:powerplant:info#supported-registers" }
String E3DC_Manufacturer "E3DC Manufacturer" (e3dc) { channel="modbus:e3dc:device:powerplant:info#manufacturer-name" }
String E3DC_ModelName "E3DC Model" (e3dc) { channel="modbus:e3dc:device:powerplant:info#model-name" }
String E3DC_Firmware "E3DC Modbus ID" (e3dc) { channel="modbus:e3dc:device:powerplant:info#firmware-release" }
String E3DC_SerialNumber "E3DC Modbus ID" (e3dc) { channel="modbus:e3dc:device:powerplant:info#serial-number" }
Number:Power E3DC_PVPower "E3DC PV Power" (e3dc,persist) { channel="modbus:e3dc:device:powerplant:power#pv-power-supply" }
Number:Power E3DC_BatteryDischarge "E3DC Battery Discharge" (e3dc,persist) { channel="modbus:e3dc:device:powerplant:power#battery-power-supply" }
Number:Power E3DC_BatteryCharge "E3DC Battery Charge" (e3dc,persist) { channel="modbus:e3dc:device:powerplant:power#battery-power-consumption" }
Number:Power E3DC_Household "E3DC Household Consumption" (e3dc,persist) { channel="modbus:e3dc:device:powerplant:power#household-power-consumption" }
Number:Power E3DC_GridConsumption "E3DC Grid Consumption" (e3dc,persist) { channel="modbus:e3dc:device:powerplant:power#grid-power-consumption" }
Number:Power E3DC_GridSupply "E3DC Grid Supply " (e3dc,persist) { channel="modbus:e3dc:device:powerplant:power#grid-power-supply" }
Number:Power E3DC_ExternalSupply "E3DC External Supply" (e3dc,persist) { channel="modbus:e3dc:device:powerplant:power#external-power-supply" }
Number:Power E3DC_WallboxConsumption "E3DC Wallbox Consumption" (e3dc,persist) { channel="modbus:e3dc:device:powerplant:power#wallbox-power-consumption" }
Number:Power E3DC_WallboxPVConsumption "E3DC Wallbox PV Consumption" (e3dc) { channel="modbus:e3dc:device:powerplant:power#wallbox-pv-power-consumption" }
Number:Dimensionless E3DC_AutarkyLevel "E3DC Autarky Level" (e3dc) { channel="modbus:e3dc:device:powerplant:power#autarky" }
Number:Dimensionless E3DC_SelfConsumptionLevel "E3DC Self Consumption Level" (e3dc) { channel="modbus:e3dc:device:powerplant:power#self-consumption" }
Number:Dimensionless E3DC_BatterySOC "E3DC Battery SOC" (e3dc,persist) { channel="modbus:e3dc:device:powerplant:power#battery-soc" }
Switch E3DC_WB_Available "E3DC WB available" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-available" }
Switch E3DC_WB_Sunmode "E3DC WB Sunmode" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-sunmode" }
Switch E3DC_WB_ChargingAborted "E3DC WB Charging Aborted" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-charging-aborted" }
Switch E3DC_WB_Charging "E3DC WB Charging" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-charging" }
Switch E3DC_WB_JackLocked "E3DC WB Jack Locked" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-jack-locked" }
Switch E3DC_WB_JackPlugged "E3DC WB Jack Plugged" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-jack-plugged" }
Switch E3DC_WB_SchukoOn "E3DC WB Schuko On" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-schuko-on" }
Switch E3DC_WB_SchukoPlugged "E3DC WB Schuko Plugged" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-schuko-plugged" }
Switch E3DC_WB_SchukoLocked "E3DC WB Schuko Locked" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-schuko-locked" }
Switch E3DC_WB_Schuko_Relay16A "E3DC WB Schuko 16A Relay" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-schuko-relay-16a" }
Switch E3DC_WB_Relay16A "E3DC WB 16A Relay" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-relay-16a" }
Switch E3DC_WB_Relay32A "E3DC WB 32A Relay" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-relay-32a" }
Switch E3DC_WB_1PhaseCharging "E3DC WB 1-Phase Charging" (e3dc) { channel="modbus:e3dc-wallbox:device:powerplant:wallbox0:wb-1phase" }
Number:ElectricPotential E3DC_String1V "E3DC String 1 Volt" (e3dc) { channel="modbus:e3dc:device:powerplant:strings#string1-dc-voltage" }
Number:ElectricPotential E3DC_String2V "E3DC String 2 Volt" (e3dc) { channel="modbus:e3dc:device:powerplant:strings#string2-dc-voltage" }
Number:ElectricPotential E3DC_String3V "E3DC String 3 Volt" (e3dc) { channel="modbus:e3dc:device:powerplant:strings#string3-dc-voltage" }
Number:ElectricCurrent E3DC_String1A "E3DC String 1 Ampere" (e3dc) { channel="modbus:e3dc:device:powerplant:strings#string1-dc-current" }
Number:ElectricCurrent E3DC_String2A "E3DC String 2 Ampere" (e3dc) { channel="modbus:e3dc:device:powerplant:strings#string2-dc-current" }
Number:ElectricCurrent E3DC_String3A "E3DC String 3 Ampere" (e3dc) { channel="modbus:e3dc:device:powerplant:strings#string3-dc-current" }
Number:Power E3DC_String1W "E3DC String 1 Watt" (e3dc,persist) { channel="modbus:e3dc:device:powerplant:strings#string1-dc-output" }
Number:Power E3DC_String2W "E3DC String 2 Watt" (e3dc,persist) { channel="modbus:e3dc:device:powerplant:strings#string2-dc-output" }
Number:Power E3DC_String3W "E3DC String 3 Watt" (e3dc,persist) { channel="modbus:e3dc:device:powerplant:strings#string3-dc-output" }
String E3DC_EMS_Status "E3DC EMS Status" (e3dc) { channel="modbus:e3dc:device:powerplant:emergency#emergency-power-status" }
Switch E3DC_EMS_BatteryChargingLock "E3DC EMS Battery Charging Locked" (e3dc) { channel="modbus:e3dc:device:powerplant:emergency#battery-charging-lock" }
Switch E3DC_EMS_BatteryDischargingLock "E3DC EMS Battery Discharging Locked" (e3dc) { channel="modbus:e3dc:device:powerplant:emergency#battery-discharging-lock" }
Switch E3DC_EMS_EmergencyPowerPossible "E3DC EMS Emergency Power possible" (e3dc) { channel="modbus:e3dc:device:powerplant:emergency#emergency-power-possible" }
Switch E3DC_EMS_WeatherPredictedCharging "E3DC EMS Weather Predicted Charging" (e3dc) { channel="modbus:e3dc:device:powerplant:emergency#weather-predicted-charging" }
Switch E3DC_EMS_RegulationStatus "E3DC EMS Regulation Status" (e3dc) { channel="modbus:e3dc:device:powerplant:emergency#regulation-status" }
Switch E3DC_EMS_ChargeLockTime "E3DC EMS Charge Lock Time" (e3dc) { channel="modbus:e3dc:device:powerplant:emergency#charge-lock-time" }
Switch E3DC_EMS_DischargeLockTime "E3DC EMS Discharge Lock TIme" (e3dc) { channel="modbus:e3dc:device:powerplant:emergency#discharge-lock-time" }
```
### Sitemap
```
sitemap E3DC label="E3DC Binding Sitemap" {
Frame label="Info" {
Text item=E3DC_ModbusId label="Modbus-ID [%s]"
Text item=E3DC_ModbusFirmware label="Modbus Firmware [%s]"
Text item=E3DC_SupportedRegisters label="Registers [%s]"
Text item=E3DC_Manufacturer label="Manufacturer [%s]"
Text item=E3DC_ModelName label="Model Name [%s]"
Text item=E3DC_Firmware label="Firmware [%s]"
Text item=E3DC_SerialNumber label="Serial Number[%s]"
}
Frame label="Power Producer" {
Text item=E3DC_PVPower label="PV Power [%d %unit%]"
Text item=E3DC_BatteryDischarge label="Battery Discharge [%d %unit%]"
Text item=E3DC_GridSupply label="Power from Grid [%d %unit%]"
Text item=E3DC_ExternalSupply label="External Supply [%d %unit%]"
}
Frame label="Power Consumer" {
Text item=E3DC_Household label="Household [%d %unit%]"
Text item=E3DC_BatteryCharge label="Battery Charge [%d %unit%]"
Text item=E3DC_GridConsumption label="Power to Grid [%d %unit%]"
Text item=E3DC_WallboxConsumption label="Wallbox [%d %unit%]"
Text item=E3DC_WallboxPVConsumption label="Wallbox PV [%d %unit%]"
}
Frame label="Power Measures" {
Text item=E3DC_AutarkyLevel label="Autarky [%d %%]"
Text item=E3DC_SelfConsumptionLevel label="Self Consumption [%d %%]"
Text item=E3DC_BatterySOC label="SOC [%d %%]"
}
Frame label="Wallbox" {
Switch item=E3DC_WB_Available label="Available [%s]"
Switch item=E3DC_WB_Sunmode label="Sunmode [%s]"
Switch item=E3DC_WB_ChargingAborted label="Charging Aborted[%s]"
Switch item=E3DC_WB_Charging label="Charging [%s]"
Switch item=E3DC_WB_JackLocked label="Jack locked [%s]"
Switch item=E3DC_WB_JackPlugged label="Jack plugged [%s]"
Switch item=E3DC_WB_SchukoOn label="Schuko On [%s]"
Switch item=E3DC_WB_SchukoPlugged label="Schuko plugged [%s]"
Switch item=E3DC_WB_SchukoLocked label="Schuko locked [%s]"
Switch item=E3DC_WB_Schuko_Relay16A label="Schuko Relay 16A [%s]"
Switch item=E3DC_WB_Relay16A label="Relay 16A [%s]"
Switch item=E3DC_WB_Relay32A label="Relay 32A [%s]"
Switch item=E3DC_WB_1PhaseCharging label="1-Phase charging [%s]"
}
Frame label="String 1 Details" {
Text item=E3DC_String1V label="Volt [%d %unit%]"
Text item=E3DC_String1A label="Ampere [%.2f %unit%]"
Text item=E3DC_String1W label="Watt [%d %unit%]"
}
Frame label="String 2 Details" {
Text item=E3DC_String2V label="Volt [%d %unit%]"
Text item=E3DC_String2A label="Ampere [%.2f %unit%]"
Text item=E3DC_String2W label="Watt [%d %unit%]"
}
Frame label="String 3 Details" {
Text item=E3DC_String3V label="Volt [%d %unit%]"
Text item=E3DC_String3A label="Ampere [%.2f %unit%]"
Text item=E3DC_String3W label="Watt [%d %unit%]"
}
Frame label="EMS" {
Text item=E3DC_EMS_Status label="Status [%s]"
Switch item=E3DC_EMS_BatteryChargingLock label="Battery Charging Lock [%s]"
Switch item=E3DC_EMS_BatteryDischargingLock label="Battery Discharging Lock [%s]"
Switch item=E3DC_EMS_EmergencyPowerPossible label="Emergency Power Possible [%s]"
Switch item=E3DC_EMS_WeatherPredictedCharging label="Weather Predicted Charging [%s]"
Switch item=E3DC_EMS_RegulationStatus label="Regulation [%s]"
Switch item=E3DC_EMS_ChargeLockTime label="Charge Lock Times [%s]"
Switch item=E3DC_EMS_DischargeLockTime label="Discharge Lock Times [%s]"
}
}
```
## Going further
Setup and configured everything the right way? Congratulations, you've now the recent E3DC values on your table. Don't stop and go ahead!
### Persistence
You can see in the example item configuration, that I added some items to the "persist". Feel free to choose your own group name but this opens the possibility
to store the items in a database. See following *.persist file configuration how this can be established.
```
Strategies {
everyMinute : "0 * * * * ?"
everyHour : "0 0 * * * ?"
everyDay : "0 0 0 * * ?"
default = everyChange
}
Items {
// persist items on every change and every minute - used for E3DC
persist : strategy = everyChange, everyMinute
}
```
### Visualization
After the timeline is available in your database you can continue with Visualization. I like the Grafana approach and I used the
[InfluxDB & Grafana Tutorial](https://community.openhab.org/t/influxdb-grafana-persistence-and-graphing/13761)
from the Community to set this up.
I prepared my machine and I'm quite pleased with the results.
<img style="float: right;" src="doc/GrafanaPV.png">
In the above picture there are two graphs
* The top one shows the Photovoltaic Production of my 2 attached Strings. You can clearly see when the sky wasn't bright the production goes down
* The bottom graph show the producers & consumers.
* Battery in blue charging during the day, discharging at night
* Household consumption in green
* Wallbox consumption in orange
* Grid consumption / supply in yellow
### Cross Connections
With the above setup you have now a great visualization and overview regarding your electric production and consumption. Now use the Power of openHAB and cross
connect your data. For example you can use the
[OpenweatherMap API Binding](https://www.openhab.org/addons/bindings/openweathermap/)
the cloudiness in Percent. With a modified *.persist file I store the cloudiness forecast also in the database
```
Strategies {
everyMinute : "0 * * * * ?"
everyHour : "0 0 * * * ?"
everyDay : "0 0 0 * * ?"
default = everyChange
}
Items {
// persist items on every change and every minute - used for E3DC
persist : strategy = everyChange, everyMinute
LocalWeatherAndForecast_Current_BewLkung : strategy = everyChange,everyHour
}
```
Having these values in the timeline you're able to cross check how the forecast influences the Photovoltaic Production.
<img style="float: right;" src="doc/GrafanaCloudiness.png">
I personally would like to have
more steering control of the E3DC to react on such forecast e.g. "stop charging the car if it gets too cloudy"

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -0,0 +1,174 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="357.98874"
height="209.74985"
viewBox="0 0 357.98874 209.74985"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="logoFARBE.svg">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="944"
inkscape:window-height="1002"
id="namedview30"
showgrid="false"
inkscape:zoom="0.96371746"
inkscape:cx="178.99437"
inkscape:cy="103.83728"
inkscape:window-x="960"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" />
<defs
id="defs4">
<clipPath
id="clipPath3058">
<path
d="m 0,0 2863.91,0 0,1678 L 0,1678 0,0 z"
id="path3060" />
</clipPath>
<clipPath
id="clipPath18"
clipPathUnits="userSpaceOnUse">
<path
id="path20"
d="m 0,0 2863.9,0 0,1678 L 0,1678 0,0 Z"
inkscape:connector-curvature="0" />
</clipPath>
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="g10"
transform="matrix(1.25,0,0,-1.25,0,277.74985)">
<g
id="g12"
transform="matrix(0.1,0,0,0.1,0,54.4)">
<g
id="g14">
<g
id="g16"
clip-path="url(#clipPath18)"
style="fill-rule:nonzero">
<path
id="path22"
d="m 1742.7,916.66 c -57.27,189.25 -186.71,325.74 -312.71,398.73 -263.04,148.69 -458.92,77.73 -451.69,77.64 -3.473,-18.3 188.74,29.09 424.88,-120.73 88.55,-56.9 176.97,-147.64 234.77,-266.31 19.74,-188.63 -164.02,-223.1 -214.26,-67.459 -57.96,179.55 -104.94,258.75 -173.84,249.53 -65.78,-7.13 -121.42,-183.59 -145.87,-259.48 -24.5,-75.94 -84.6,-294.63 -129.68,-393.35 -45.08,-98.68 -115.14,-142.36 -182.38,-140.66 -67.234,1.7 -120.82,45.993 -178.62,154.31 -19.129,3.457 -71.215,12.238 -71.215,12.238 27.344,-137.96 145.75,-291.33 264.21,-289.68 118.48,1.649 177.05,81.739 239.3,252.63 62.24,170.92 110.76,347.4 219.15,351.37 87.25,5.273 100.6,-108.04 124.21,-190.72 23.57,-82.734 66.78,-235.72 180.06,-236.36 43.81,0 77.03,27.821 101.56,64.723 -19.1,-57.92 -46.4,-114.24 -82.6,-166.39 -117.1,-169.47 -306.4,-267.49 -483.8,-279.23 -178.74,-15.43 -339.1,45.08 -447.68,126.05 -221.84,169.23 -247.77,364.82 -262.23,355.46 -4.02,6.38 1.17,-201.18 231.31,-395.68 112.55,-92.451 286.37,-164.98 483.4,-151.77 195.77,9.0312 408.12,115.93 538,304.29 130.46,187.88 155.12,424.46 95.59,610.8"
inkscape:connector-curvature="0"
style="fill:#66c430" />
<path
id="path24"
d="m 367.15,633.2 -346.39,0 C 8.734,633.2 0,641.94 0,653.97 l 0,734.3 c 0,12.02 8.7344,20.76 20.762,20.76 l 346.39,0 c 12.016,0 20.762,-8.74 20.762,-20.76 l 0,-45.89 c 0,-12.03 -8.746,-20.77 -20.762,-20.77 l -274.27,0 0,-251.32 252.42,0 c 12.015,0 20.765,-8.74 20.765,-20.76 l 0,-45.9 c 0,-12.017 -8.75,-20.759 -20.765,-20.759 l -252.42,0 0,-262.24 274.27,0 c 12.016,0 20.762,-8.75 20.762,-20.77 l 0,-45.89 c 0,-12.028 -8.746,-20.77 -20.762,-20.77"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path26"
d="m 690.6,622.28 c -86.328,0 -159.54,20.758 -159.54,20.758 -13.106,3.281 -20.766,9.84 -20.766,21.852 l 0,49.171 c 0,12.028 8.75,16.399 20.766,14.211 0,0 95.062,-18.574 157.35,-18.574 90.696,0 138.78,46.981 138.78,123.47 l 0,46.992 c 0,76.477 -48.086,112.55 -131.13,112.55 l -110.36,0 c -12.015,0 -20.761,8.739 -20.761,20.759 l 0,45.9 c 0,12.01 8.746,20.76 20.761,20.76 l 88.504,0 c 83.047,0 131.13,36.05 131.13,112.54 l 0,24.04 c 0,76.49 -45.891,115.83 -123.48,115.83 -62.278,0 -150.79,-18.57 -150.79,-18.57 -12.016,-2.19 -20.766,3.28 -20.766,15.3 l 0,49.16 c 0,12.03 5.473,17.49 20.766,20.76 0,0 64.472,20.76 152.98,20.76 137.68,0 214.17,-62.28 214.17,-203.24 l 0,-24.04 c 0,-71.02 -28.406,-119.1 -75.391,-149.7 59.008,-28.41 97.258,-81.943 97.258,-162.81 l 0,-46.992 c 0,-143.14 -81.965,-210.89 -229.48,-210.89"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path28"
d="m 2272.9,1157.7 c 0,84.14 -39.34,163.9 -147.51,163.9 l -147.53,0 0,-600.98 147.53,0 c 108.17,0 147.51,79.762 147.51,163.9 l 0,273.18 z m -147.51,-524.51 -219.64,0 c -12.03,0 -20.76,8.742 -20.76,20.77 l 0,734.3 c 0,12.02 8.73,20.76 20.76,20.76 l 219.64,0 c 167.17,0 240.38,-105.99 240.38,-251.32 l 0,-273.18 c 0,-145.34 -73.21,-251.33 -240.38,-251.33"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path30"
d="m 2837.8,633.2 c 0,0 -60.09,-10.918 -114.73,-10.918 -159.54,0 -231.65,105.99 -231.65,251.32 l 0,295.02 c 0,145.34 71.02,251.32 231.65,251.32 59,0 114.73,-12.01 114.73,-12.01 13.12,-3.28 19.67,-8.75 19.67,-20.76 l 0,-48.08 c 0,-12.03 -8.74,-17.49 -20.75,-16.4 0,0 -61.2,9.84 -110.37,9.84 -102.72,0 -142.06,-79.77 -142.06,-163.91 l 0,-295.02 c 0,-84.136 38.24,-163.91 142.06,-163.91 43.71,0 110.37,9.832 110.37,9.832 12.01,1.098 20.75,-4.379 20.75,-16.39 l 0,-49.172 c 0,-12.028 -6.55,-17.481 -19.67,-20.77"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path32"
d="m 1059.6,1500.7 -78.255,0 c -2.71,0 -4.683,1.97 -4.683,4.69 l 0,165.88 c 0,2.71 1.973,4.68 4.683,4.68 l 78.255,0 c 2.72,0 4.7,-1.97 4.7,-4.68 l 0,-10.37 c 0,-2.72 -1.98,-4.69 -4.7,-4.69 l -61.958,0 0,-56.78 57.018,0 c 2.72,0 4.7,-1.97 4.7,-4.69 l 0,-10.36 c 0,-2.72 -1.98,-4.69 -4.7,-4.69 l -57.018,0 0,-59.25 61.958,0 c 2.72,0 4.7,-1.97 4.7,-4.69 l 0,-10.36 c 0,-2.72 -1.98,-4.69 -4.7,-4.69"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path34"
d="m 1210.1,1500.7 -13.08,0 c -2.72,0 -4.45,2.22 -5.69,4.69 l -64.18,124.65 0,-124.65 c 0,-2.72 -1.97,-4.69 -4.68,-4.69 l -11.61,0 c -2.72,0 -4.69,1.97 -4.69,4.69 l 0,165.88 c 0,2.71 1.97,4.68 4.69,4.68 l 12.85,0 c 3.2,0 4.43,-1.72 5.67,-4.19 l 64.43,-125.15 0,124.66 c 0,2.71 1.97,4.68 4.69,4.68 l 11.6,0 c 2.72,0 4.69,-1.97 4.69,-4.68 l 0,-165.88 c 0,-2.72 -1.97,-4.69 -4.69,-4.69"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path36"
d="m 1344.5,1500.7 -78.26,0 c -2.71,0 -4.68,1.97 -4.68,4.69 l 0,165.88 c 0,2.71 1.97,4.68 4.68,4.68 l 78.26,0 c 2.72,0 4.69,-1.97 4.69,-4.68 l 0,-10.37 c 0,-2.72 -1.97,-4.69 -4.69,-4.69 l -61.96,0 0,-56.78 57.02,0 c 2.72,0 4.69,-1.97 4.69,-4.69 l 0,-10.36 c 0,-2.72 -1.97,-4.69 -4.69,-4.69 l -57.02,0 0,-59.25 61.96,0 c 2.72,0 4.69,-1.97 4.69,-4.69 l 0,-10.36 c 0,-2.72 -1.97,-4.69 -4.69,-4.69"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path38"
d="m 1440.5,1656.2 -28.38,0 0,-61.71 28.38,0 c 21.99,0 33.34,11.84 33.34,30.85 0,19.01 -11.35,30.86 -33.34,30.86 z m 55.8,-155.51 -15.3,0 c -2.97,0 -4.7,2.46 -6.18,4.69 l -41.21,69.36 -21.49,0 0,-69.36 c 0,-2.72 -1.97,-4.69 -4.69,-4.69 l -11.6,0 c -2.71,0 -4.69,1.97 -4.69,4.69 l 0,165.88 c 0,2.71 1.98,4.68 4.69,4.68 l 44.67,0 c 35.56,0 54.32,-17.77 54.32,-50.6 0,-27.4 -12.83,-44.18 -37.52,-49.11 l 42.2,-70.85 c 1.49,-2.23 -0.49,-4.69 -3.2,-4.69"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path40"
d="m 1591,1498.2 c -37.77,0 -54.3,23.94 -54.3,56.78 l 0,61.71 c 0,37.51 18.76,61.7 59.24,61.7 21.97,0 39.99,-5.67 39.99,-5.67 2.96,-0.74 4.44,-1.98 4.44,-4.69 l 0,-11.11 c 0,-2.72 -1.98,-4.2 -4.7,-3.71 0,0 -22.21,5.44 -39.73,5.44 -27.39,0 -38.27,-18.27 -38.27,-41.96 l 0,-61.71 c 0,-19.01 8.89,-37.04 33.33,-37.04 20.74,0 33.33,6.91 33.33,6.91 l 0,52.34 -32.34,0 c -2.72,0 -4.69,1.98 -4.69,4.69 l 0,10.37 c 0,2.72 1.97,4.69 4.69,4.69 l 48.63,0 c 2.72,0 4.69,-1.97 4.69,-4.69 l 0,-79.24 c 0,0 -16.55,-14.81 -54.31,-14.81"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path42"
d="m 1745.2,1561.2 0,-55.78 c 0,-2.72 -1.97,-4.69 -4.69,-4.69 l -11.6,0 c -2.72,0 -4.7,1.97 -4.7,4.69 l 0,55.78 -49.61,109.86 c -1.24,2.46 0.49,4.92 3.21,4.92 l 14.07,0 c 2.71,0 4.93,-2.22 5.92,-4.68 l 37.03,-85.41 36.78,85.41 c 0.98,2.46 3.21,4.68 5.93,4.68 l 14.07,0 c 2.72,0 4.43,-2.46 3.21,-4.92 L 1745.2,1561.2"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path44"
d="m 1951.9,1498.2 c -19,0 -38.02,5.18 -38.02,5.18 -3.2,0.74 -4.68,2.23 -4.68,4.93 l 0,11.36 c 0,2.72 1.48,4.2 4.68,3.71 0,0 21.49,-5.44 36.05,-5.44 18.76,0 32.09,7.67 32.09,27.66 l 0,7.41 c 0,16.52 -8.88,21.71 -23.46,26.9 l -16.04,5.68 c -16.54,5.92 -32.08,15.04 -32.08,41.46 l 0,6.17 c 0,30.12 20.72,45.17 50.1,45.17 18.27,0 35.3,-4.19 35.3,-4.19 3.21,-0.74 4.69,-2.22 4.69,-4.94 l 0,-10.86 c 0,-2.71 -1.48,-4.2 -4.69,-3.69 0,0 -18.76,3.94 -34.8,3.94 -18.77,0 -29.63,-8.15 -29.63,-25.43 l 0,-6.17 c 0,-12.09 8.4,-18.02 19.75,-21.97 l 15.8,-5.68 c 18.02,-6.41 36.04,-16.29 36.04,-46.39 l 0,-7.41 c 0,-34.81 -20.74,-47.4 -51.1,-47.4"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path46"
d="m 2138.9,1656.2 -39.01,0 0,-150.82 c 0,-2.72 -1.97,-4.69 -4.69,-4.69 l -11.6,0 c -2.72,0 -4.69,1.97 -4.69,4.69 l 0,150.82 -39.26,0 c -2.71,0 -4.68,1.97 -4.68,4.69 l 0,10.37 c 0,2.71 1.97,4.68 4.68,4.68 l 99.25,0 c 2.71,0 4.68,-1.97 4.68,-4.68 l 0,-10.37 c 0,-2.72 -1.97,-4.69 -4.68,-4.69"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path48"
d="m 2258.3,1621.6 c 0,19.01 -8.89,37.03 -33.33,37.03 -24.45,0 -33.33,-18.02 -33.33,-37.03 l 0,-66.64 c 0,-19.01 8.88,-37.04 33.33,-37.04 24.44,0 33.33,18.03 33.33,37.04 l 0,66.64 z m -33.33,-123.42 c -37.76,0 -54.31,23.94 -54.31,56.78 l 0,66.64 c 0,32.83 16.55,56.77 54.31,56.77 37.76,0 54.3,-23.94 54.3,-56.77 l 0,-66.64 c 0,-32.84 -16.54,-56.78 -54.3,-56.78"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path50"
d="m 2375.4,1656.2 -28.38,0 0,-61.71 28.38,0 c 21.99,0 33.33,11.84 33.33,30.85 0,19.01 -11.34,30.86 -33.33,30.86 z m 55.81,-155.51 -15.31,0 c -2.97,0 -4.7,2.46 -6.18,4.69 l -41.21,69.36 -21.49,0 0,-69.36 c 0,-2.72 -1.97,-4.69 -4.69,-4.69 l -11.6,0 c -2.71,0 -4.69,1.97 -4.69,4.69 l 0,165.88 c 0,2.71 1.98,4.68 4.69,4.68 l 44.67,0 c 35.56,0 54.32,-17.77 54.32,-50.6 0,-27.4 -12.83,-44.18 -37.51,-49.11 l 42.19,-70.85 c 1.49,-2.23 -0.49,-4.69 -3.19,-4.69"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path52"
d="m 2525.4,1642.1 -27.16,-87.13 54.07,0 -26.91,87.13 z m 60.97,-141.44 -13.58,0 c -2.71,0 -4.44,1.97 -5.17,4.69 l -9.14,29.86 -66.4,0 -9.14,-29.86 c -0.74,-2.72 -2.47,-4.69 -5.19,-4.69 l -13.57,0 c -2.72,0 -4.2,1.97 -3.45,4.69 l 52.57,165.88 c 0.74,2.71 2.71,4.68 5.43,4.68 l 13.08,0 c 2.72,0 4.7,-1.97 5.44,-4.68 l 52.57,-165.88 c 0.75,-2.72 -0.74,-4.69 -3.45,-4.69"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path54"
d="m 2675.2,1498.2 c -37.77,0 -54.31,23.94 -54.31,56.78 l 0,61.71 c 0,37.51 18.77,61.7 59.25,61.7 21.97,0 39.99,-5.67 39.99,-5.67 2.96,-0.74 4.43,-1.98 4.43,-4.69 l 0,-11.11 c 0,-2.72 -1.97,-4.2 -4.69,-3.71 0,0 -22.21,5.44 -39.73,5.44 -27.4,0 -38.27,-18.27 -38.27,-41.96 l 0,-61.71 c 0,-19.01 8.88,-37.04 33.33,-37.04 20.73,0 33.33,6.91 33.33,6.91 l 0,52.34 -32.35,0 c -2.71,0 -4.69,1.98 -4.69,4.69 l 0,10.37 c 0,2.72 1.98,4.69 4.69,4.69 l 48.64,0 c 2.71,0 4.68,-1.97 4.68,-4.69 l 0,-79.24 c 0,0 -16.54,-14.81 -54.3,-14.81"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
<path
id="path56"
d="m 2859.2,1500.7 -78.25,0 c -2.73,0 -4.7,1.97 -4.7,4.69 l 0,165.88 c 0,2.71 1.97,4.68 4.7,4.68 l 78.25,0 c 2.71,0 4.69,-1.97 4.69,-4.68 l 0,-10.37 c 0,-2.72 -1.98,-4.69 -4.69,-4.69 l -61.96,0 0,-56.78 57.02,0 c 2.71,0 4.68,-1.97 4.68,-4.69 l 0,-10.36 c 0,-2.72 -1.97,-4.69 -4.68,-4.69 l -57.02,0 0,-59.25 61.96,0 c 2.71,0 4.69,-1.97 4.69,-4.69 l 0,-10.36 c 0,-2.72 -1.98,-4.69 -4.69,-4.69"
inkscape:connector-curvature="0"
style="fill:#5b5f63" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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>3.0.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.modbus.e3dc</artifactId>
<name>openHAB Add-ons :: Bundles :: E3DC Modbus Binding</name>
<dependencies>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.modbus</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.io.transport.modbus</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.modbus.e3dc-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>file:${basedirRoot}/bundles/org.openhab.io.transport.modbus/target/feature/feature.xml</repository>
<feature name="openhab-binding-modbus-e3dc" description="E3DC Modbus Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-transport-modbus</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.modbus/${project.version}</bundle>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.modbus.e3dc/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,92 @@
/**
* 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.modbus.e3dc.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.ModbusBindingConstants;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link E3DCBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class E3DCBindingConstants {
private static final String BINDING_ID = ModbusBindingConstants.BINDING_ID;
// Supported Thing Types
public static final ThingTypeUID THING_TYPE_E3DC = new ThingTypeUID(BINDING_ID, "e3dc");
public static final ThingTypeUID THING_TYPE_E3DC_WALLBOX = new ThingTypeUID(BINDING_ID, "e3dc-wallbox");
// Channels for Info Block
public static final String MODBUS_ID_CHANNEL = "modbus-id";
public static final String MODBUS_FIRMWARE_CHANNEL = "modbus-firmware";
public static final String SUPPORTED_REGISTERS_CHANNEL = "supported-registers";
public static final String MANUFACTURER_NAME_CHANNEL = "manufacturer-name";
public static final String MODEL_NAME_CHANNEL = "model-name";
public static final String SERIAL_NUMBER_CHANNEL = "serial-number";
public static final String FIRMWARE_RELEASE_CHANNEL = "firmware-release";
// Channels for Power Block
public static final String PV_POWER_SUPPLY_CHANNEL = "pv-power-supply";
public static final String BATTERY_POWER_SUPPLY_CHANNEL = "battery-power-supply";
public static final String BATTERY_POWER_CONSUMPTION = "battery-power-consumption";
public static final String HOUSEHOLD_POWER_CONSUMPTION_CHANNEL = "household-power-consumption";
public static final String GRID_POWER_CONSUMPTION_CHANNEL = "grid-power-consumption";
public static final String GRID_POWER_SUPPLY_CHANNEL = "grid-power-supply";
public static final String EXTERNAL_POWER_SUPPLY_CHANNEL = "external-power-supply";
public static final String WALLBOX_POWER_CONSUMPTION_CHANNEL = "wallbox-power-consumption";
public static final String WALLBOX_PV_POWER_CONSUMPTION_CHANNEL = "wallbox-pv-power-consumption";
public static final String AUTARKY_CHANNEL = "autarky";
public static final String SELF_CONSUMPTION_CHANNEL = "self-consumption";
public static final String BATTERY_STATE_OF_CHARGE_CHANNEL = "battery-soc";
// Channels for Wallbox Block
public static final String WB_AVAILABLE_CHANNEL = "wb-available";
public static final String WB_SUNMODE_CHANNEL = "wb-sunmode";
public static final String WB_CHARGING_ABORTED_CHANNEL = "wb-charging-aborted";
public static final String WB_CHARGING_CHANNEL = "wb-charging";
public static final String WB_JACK_LOCKED_CHANNEL = "wb-jack-locked";
public static final String WB_JACK_PLUGGED_CHANNEL = "wb-jack-plugged";
public static final String WB_SCHUKO_ON_CHANNEL = "wb-schuko-on";
public static final String WB_SCHUKO_PLUGGED_CHANNEL = "wb-schuko-plugged";
public static final String WB_SCHUKO_LOCKED_CHANNEL = "wb-schuko-locked";
public static final String WB_SCHUKO_RELAY_16A_CHANNEL = "wb-schuko-relay-16a";
public static final String WB_RELAY_16A_CHANNEL = "wb-relay-16a";
public static final String WB_RELAY_32A_CHANNEL = "wb-relay-32a";
public static final String WB_1PHASE_CHANNEL = "wb-1phase";
// Channels for String details
public static final String STRING1_DC_VOLTAGE_CHANNEL = "string1-dc-voltage";
public static final String STRING1_DC_CURRENT_CHANNEL = "string1-dc-current";
public static final String STRING1_DC_OUTPUT_CHANNEL = "string1-dc-output";
public static final String STRING2_DC_VOLTAGE_CHANNEL = "string2-dc-voltage";
public static final String STRING2_DC_CURRENT_CHANNEL = "string2-dc-current";
public static final String STRING2_DC_OUTPUT_CHANNEL = "string2-dc-output";
public static final String STRING3_DC_VOLTAGE_CHANNEL = "string3-dc-voltage";
public static final String STRING3_DC_CURRENT_CHANNEL = "string3-dc-current";
public static final String STRING3_DC_OUTPUT_CHANNEL = "string3-dc-output";
// Channels for Emergency Status
public static final String EMERGENCY_POWER_STATUS = "emergency-power-status";
public static final String BATTERY_CHARGING_LOCKED = "battery-charging-lock";
public static final String BATTERY_DISCHARGING_LOCKED = "battery-discharging-lock";
public static final String EMERGENCY_POWER_POSSIBLE = "emergency-power-possible";
public static final String WEATHER_PREDICTED_CHARGING = "weather-predicted-charging";
public static final String REGULATION_STATUS = "regulation-status";
public static final String CHARGE_LOCK_TIME = "charge-lock-time";
public static final String DISCHARGE_LOCK_TIME = "discharge-lock-time";
}

View File

@@ -0,0 +1,29 @@
/**
* 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.modbus.e3dc.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link E3DCConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class E3DCConfiguration {
/**
* Data refresh interval
*/
public int refresh = 2000;
}

View File

@@ -0,0 +1,52 @@
/**
* 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.modbus.e3dc.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.modbus.e3dc.internal.handler.E3DCThingHandler;
import org.openhab.binding.modbus.e3dc.internal.handler.E3DCWallboxThingHandler;
import org.openhab.core.thing.Bridge;
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;
/**
* The {@link E3DCHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.e3dc", service = ThingHandlerFactory.class)
public class E3DCHandlerFactory extends BaseThingHandlerFactory {
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return (thingTypeUID.equals(E3DCBindingConstants.THING_TYPE_E3DC)
|| thingTypeUID.equals(E3DCBindingConstants.THING_TYPE_E3DC_WALLBOX));
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (E3DCBindingConstants.THING_TYPE_E3DC.equals(thingTypeUID)) {
return new E3DCThingHandler((Bridge) thing);
} else if (E3DCBindingConstants.THING_TYPE_E3DC_WALLBOX.equals(thingTypeUID)) {
return new E3DCWallboxThingHandler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,29 @@
/**
* 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.modbus.e3dc.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link E3DCWallboxConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class E3DCWallboxConfiguration {
/**
* Wallbox ID
*/
public int wallboxId = -1;
}

View File

@@ -0,0 +1,100 @@
/**
* 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.modbus.e3dc.internal.dto;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.BitSet;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link DataConverter} Helper class to convert bytes from modbus into desired data format
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class DataConverter {
private static final long MAX_INT32 = (long) Math.pow(2, Integer.SIZE);
/**
* Get unit16 value from 2 bytes
*
* @param wrap
* @return int
*/
public static int getUInt16Value(ByteBuffer wrap) {
return Short.toUnsignedInt(wrap.getShort());
}
/**
* Get unit32 value from 4 bytes
*
* @param wrap
* @return long
*/
public static long getLongValue(ByteBuffer wrap) {
return Integer.toUnsignedLong(wrap.getInt());
}
/**
* Get double value from 2 bytes with correction factor
*
* @param wrap
* @return double
*/
public static double getUDoubleValue(ByteBuffer wrap, double factor) {
return round(getUInt16Value(wrap) * factor, 2);
}
/**
* Conversion done according to E3DC Modbus Specification V1.7
*
* @param wrap
* @return decoded long value, Long.MIN_VALUE otherwise
*/
public static long getInt32Swap(ByteBuffer wrap) {
long a = getUInt16Value(wrap);
long b = getUInt16Value(wrap);
if (b < 32768) {
return b * 65536 + a;
} else {
return (MAX_INT32 - b * 65536 - a) * -1;
}
}
public static String getString(byte[] bArray) {
return new String(bArray, StandardCharsets.US_ASCII).trim();
}
public static int toInt(BitSet bitSet) {
int intValue = 0;
for (int bit = 0; bit < bitSet.length(); bit++) {
if (bitSet.get(bit)) {
intValue |= (1 << bit);
}
}
return intValue;
}
public static double round(double value, int places) {
if (places < 0) {
throw new IllegalArgumentException();
}
long factor = (long) Math.pow(10, places);
value = value * factor;
long tmp = Math.round(value);
return (double) tmp / factor;
}
}

View File

@@ -0,0 +1,76 @@
/**
* 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.modbus.e3dc.internal.dto;
import static org.openhab.binding.modbus.e3dc.internal.modbus.E3DCModbusConstans.*;
import java.nio.ByteBuffer;
import java.util.BitSet;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
/**
* The {@link EmergencyBlock} Data object for E3DC Info Block
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class EmergencyBlock implements Data {
public StringType epStatus = EP_UNKOWN;
public OnOffType batteryChargingLocked = OnOffType.OFF;
public OnOffType batteryDischargingLocked = OnOffType.OFF;
public OnOffType epPossible = OnOffType.OFF;
public OnOffType weatherPredictedCharging = OnOffType.OFF;
public OnOffType regulationStatus = OnOffType.OFF;
public OnOffType chargeLockTime = OnOffType.OFF;
public OnOffType dischargeLockTime = OnOffType.OFF;
// Possible Status definitions according to chapter 3.1.2, Register 40084, page 14 & 15
public static final StringType EP_NOT_SUPPORTED = StringType.valueOf("EP not supported");
public static final StringType EP_ACTIVE = StringType.valueOf("EP active");
public static final StringType EP_NOT_ACTIVE = StringType.valueOf("EP not active");
public static final StringType EP_POSSIBLE = StringType.valueOf("EP possible");
public static final StringType EP_SWITCH = StringType.valueOf("EP Switch in wrong position");
public static final StringType EP_UNKOWN = StringType.valueOf("EP Status unknown");
public static final StringType[] EP_STATUS_ARRAY = new StringType[] { EP_NOT_SUPPORTED, EP_ACTIVE, EP_NOT_ACTIVE,
EP_POSSIBLE, EP_SWITCH };
/**
* For decoding see Modbus Register Mapping Chapter 3.1.2 page 14 & 15
*
* @param bArray - Modbus Registers as bytes from 40084 to 40085
*/
public EmergencyBlock(byte[] bArray) {
// uint16 status register 40084 - possible Status Strings are defined in Constants above
int status = DataConverter.getUInt16Value(ByteBuffer.wrap(bArray));
if (status >= 0 && status < 5) {
epStatus = EP_STATUS_ARRAY[status];
} else {
epStatus = EP_UNKOWN;
}
// uint16 status register 40085 shall be handled as Bits - check cahpter 3.1.3 page 17
byte[] emsStatusBytes = new byte[] { bArray[3], bArray[2] };
BitSet bs = BitSet.valueOf(emsStatusBytes);
batteryChargingLocked = OnOffType.from(bs.get(EMS_CHARGING_LOCK_BIT));
batteryDischargingLocked = OnOffType.from(bs.get(EMS_DISCHARGING_LOCK_BIT));
epPossible = OnOffType.from(bs.get(EMS_DISCHARGING_LOCK_BIT));
weatherPredictedCharging = OnOffType.from(bs.get(EMS_WEATHER_CHARGING_BIT));
regulationStatus = OnOffType.from(bs.get(EMS_REGULATION_BIT));
chargeLockTime = OnOffType.from(bs.get(EMS_CHARGE_LOCKTIME_BIT));
dischargeLockTime = OnOffType.from(bs.get(EMS_DISCHARGE_LOCKTIME_BIT));
}
}

View File

@@ -0,0 +1,83 @@
/**
* 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.modbus.e3dc.internal.dto;
import java.nio.ByteBuffer;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.util.HexUtils;
/**
* The {@link InfoBlock} Data object for E3DC Info Block
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class InfoBlock implements Data {
private static final StringType EMPTY = new StringType("NULL");
public StringType modbusId = EMPTY;
public StringType modbusVersion = EMPTY;
public DecimalType supportedRegisters = new DecimalType(-1);
public StringType manufacturer = EMPTY;
public StringType modelName = EMPTY;
public StringType serialNumber = EMPTY;
public StringType firmware = EMPTY;
/**
* For decoding see Modbus Register Mapping Chapter 3.1.1 page 14
*
* @param bArray - Modbus Registers as bytes from 40001 to 40067
*/
public InfoBlock(byte[] bArray) {
// index handling to calculate the correct start index
ByteBuffer wrapper = ByteBuffer.wrap(bArray);
// first uint16 = 2 bytes - decode magic byte
byte[] magicBytes = new byte[2];
wrapper.get(magicBytes);
this.modbusId = new StringType(HexUtils.bytesToHex(magicBytes));
// first uint16 = 2 bytes - decode magic byte
// unit8 (Modbus Major Version) + uint8 Modbus minor Version
String modbusVersion = wrapper.get() + "." + wrapper.get();
this.modbusVersion = new StringType(modbusVersion);
// unit16 - supported registers
short supportedRegisters = wrapper.getShort();
this.supportedRegisters = new DecimalType(supportedRegisters);
byte[] buffer = new byte[32];
// 16 registers with uint16 = 32 bytes to decode a proper String
wrapper.get(buffer);
String manufacturer = DataConverter.getString(buffer);
this.manufacturer = new StringType(manufacturer);
// 16 registers with uint16 = 32 bytes to decode a proper String
wrapper.get(buffer);
String model = DataConverter.getString(buffer);
this.modelName = new StringType(model);
// 16 registers with uint16 = 32 bytes to decode a proper String
wrapper.get(buffer);
String serialNumber = DataConverter.getString(buffer);
this.serialNumber = new StringType(serialNumber);
// 16 registers with uint16 = 32 bytes to decode a proper String
wrapper.get(buffer);
String firmware = DataConverter.getString(buffer);
this.firmware = new StringType(firmware);
}
}

View File

@@ -0,0 +1,110 @@
/**
* 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.modbus.e3dc.internal.dto;
import java.nio.ByteBuffer;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.Power;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SmartHomeUnits;
/**
* The {@link PowerBlock} Data object for E3DC Info Block
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class PowerBlock implements Data {
public QuantityType<Power> pvPowerSupply;
public QuantityType<Power> batteryPowerSupply;
public QuantityType<Power> batteryPowerConsumption;
public QuantityType<Power> householdPowerConsumption;
public QuantityType<Power> gridPowerConsumpition;
public QuantityType<Power> gridPowerSupply;
public QuantityType<Power> externalPowerSupply;
public QuantityType<Power> wallboxPowerConsumption;
public QuantityType<Power> wallboxPVPowerConsumption;
public QuantityType<Dimensionless> autarky;
public QuantityType<Dimensionless> selfConsumption;
public QuantityType<Dimensionless> batterySOC;
/**
* For decoding see Modbus Register Mapping Chapter 3.1.2 page 14
*
* @param bArray - Modbus Registers as bytes from 40067 to 40083
*/
public PowerBlock(byte[] bArray) {
// index handling to calculate the correct start index
ByteBuffer wrap = ByteBuffer.wrap(bArray);
// int32_swap value = 4 byte
long pvPowerSupplyL = DataConverter.getInt32Swap(wrap);
/*
* int32_swap value don't provide negative values!
* Positive value - Battery is charging = Power consumer
* Negative value - Battery is discharging = Power supplier
*/
pvPowerSupply = QuantityType.valueOf(pvPowerSupplyL, SmartHomeUnits.WATT);
long batteryPower = DataConverter.getInt32Swap(wrap);
if (batteryPower > 0) {
// Battery is charging so Power is consumed by Battery
batteryPowerSupply = QuantityType.valueOf(0, SmartHomeUnits.WATT);
batteryPowerConsumption = QuantityType.valueOf(batteryPower, SmartHomeUnits.WATT);
} else {
// Battery is discharging so Power is provided by Battery
batteryPowerSupply = QuantityType.valueOf(batteryPower * -1, SmartHomeUnits.WATT);
batteryPowerConsumption = QuantityType.valueOf(0, SmartHomeUnits.WATT);
}
// int32_swap value = 4 byte
long householdPowerConsumptionL = DataConverter.getInt32Swap(wrap);
householdPowerConsumption = QuantityType.valueOf(householdPowerConsumptionL, SmartHomeUnits.WATT);
/*
* int32_swap value don't provide negative values!
* Positive value - Power provided towards Grid = Power consumer
* Negative value - Power requested from Grid = Power supplier
*/
long gridPower = DataConverter.getInt32Swap(wrap);
if (gridPower > 0) {
// Power is provided by Grid
gridPowerSupply = QuantityType.valueOf(gridPower, SmartHomeUnits.WATT);
gridPowerConsumpition = QuantityType.valueOf(0, SmartHomeUnits.WATT);
} else {
// Power is consumed by Grid
gridPowerConsumpition = QuantityType.valueOf(gridPower * -1, SmartHomeUnits.WATT);
gridPowerSupply = QuantityType.valueOf(0, SmartHomeUnits.WATT);
}
// int32_swap value = 4 byte
externalPowerSupply = QuantityType.valueOf(DataConverter.getInt32Swap(wrap), SmartHomeUnits.WATT);
// int32_swap value = 4 byte
wallboxPowerConsumption = QuantityType.valueOf(DataConverter.getInt32Swap(wrap), SmartHomeUnits.WATT);
// int32_swap value = 4 byte
wallboxPVPowerConsumption = QuantityType.valueOf(DataConverter.getInt32Swap(wrap), SmartHomeUnits.WATT);
// unit8 + uint8 - one register with split value for Autarky & Self Consumption
autarky = QuantityType.valueOf(wrap.get(), SmartHomeUnits.PERCENT);
selfConsumption = QuantityType.valueOf(wrap.get(), SmartHomeUnits.PERCENT);
// uint16 for Battery State of Charge
batterySOC = QuantityType.valueOf(wrap.getShort(), SmartHomeUnits.PERCENT);
}
}

View File

@@ -0,0 +1,62 @@
/**
* 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.modbus.e3dc.internal.dto;
import java.nio.ByteBuffer;
import javax.measure.quantity.ElectricCurrent;
import javax.measure.quantity.ElectricPotential;
import javax.measure.quantity.Power;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SmartHomeUnits;
/**
* The {@link StringBlock} Data object for E3DC Info Block
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class StringBlock implements Data {
public QuantityType<ElectricPotential> string1Volt;
public QuantityType<ElectricPotential> string2Volt;
public QuantityType<ElectricPotential> string3Volt;
public QuantityType<ElectricCurrent> string1Ampere;
public QuantityType<ElectricCurrent> string2Ampere;
public QuantityType<ElectricCurrent> string3Ampere;
public QuantityType<Power> string1Watt;
public QuantityType<Power> string2Watt;
public QuantityType<Power> string3Watt;
/**
* For decoding see Modbus Register Mapping Chapter 3.1.2 page 14-16
*
* @param bArray - Modbus Registers as bytes from 40096 to 40104
*/
public StringBlock(byte[] bArray) {
ByteBuffer wrap = ByteBuffer.wrap(bArray);
// straight forward - for each String the values Volt, Ampere and then Watt. All unt16 = 2 bytes values
string1Volt = QuantityType.valueOf(DataConverter.getUInt16Value(wrap), SmartHomeUnits.VOLT);
string2Volt = QuantityType.valueOf(DataConverter.getUInt16Value(wrap), SmartHomeUnits.VOLT);
string3Volt = QuantityType.valueOf(DataConverter.getUInt16Value(wrap), SmartHomeUnits.VOLT);
// E3DC Modbus Spec chapter 3.1.2, page 16 - Ampere values shall be handled with factor 0.01
string1Ampere = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.01), SmartHomeUnits.AMPERE);
string2Ampere = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.01), SmartHomeUnits.AMPERE);
string3Ampere = QuantityType.valueOf(DataConverter.getUDoubleValue(wrap, 0.01), SmartHomeUnits.AMPERE);
string1Watt = QuantityType.valueOf(DataConverter.getUInt16Value(wrap), SmartHomeUnits.WATT);
string2Watt = QuantityType.valueOf(DataConverter.getUInt16Value(wrap), SmartHomeUnits.WATT);
string3Watt = QuantityType.valueOf(DataConverter.getUInt16Value(wrap), SmartHomeUnits.WATT);
}
}

View File

@@ -0,0 +1,54 @@
/**
* 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.modbus.e3dc.internal.dto;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
/**
* The {@link WallboxArray} Data object for E3DC Info Block
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class WallboxArray implements Data {
private byte[] wbArray;
/**
* For decoding see Modbus Register Mapping Chapter 3.1.2 page 15
* The Registers for Wallbox Control are declared as uint16 but shall be handled as Bit registers => see chapter
* 3.1.5 page 19
*
* @param bArray - Modbus Registers as bytes from 40088 to 40095
*/
public WallboxArray(byte[] bArray) {
wbArray = bArray;
}
/**
* Return the 2 bytes according to the Wallbox ID.
*
* @param id Wallbox ID valid from 0 - 7
* @return WallboxBlock initialized with the Modbus registers from the given ID
*/
public Optional<WallboxBlock> getWallboxBlock(int id) {
if (id >= 0 && id < 8) {
int byteIndex = id * 2;
return Optional.of(new WallboxBlock(new byte[] { wbArray[byteIndex + 1], wbArray[byteIndex * 2] }));
} else {
return Optional.empty();
}
}
}

View File

@@ -0,0 +1,72 @@
/**
* 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.modbus.e3dc.internal.dto;
import static org.openhab.binding.modbus.e3dc.internal.modbus.E3DCModbusConstans.*;
import java.util.BitSet;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.core.library.types.OnOffType;
/**
* The {@link WallboxBlock} Data object for E3DC Info Block
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class WallboxBlock implements Data {
private BitSet bitSet;
public OnOffType wbAvailable = OnOffType.OFF;
public OnOffType wbSunmode = OnOffType.OFF;
public OnOffType wbChargingAborted = OnOffType.OFF;
public OnOffType wbCharging = OnOffType.OFF;
public OnOffType wbJackLocked = OnOffType.OFF;
public OnOffType wbJackPlugged = OnOffType.OFF;
public OnOffType wbSchukoOn = OnOffType.OFF;
public OnOffType wbSchukoPlugged = OnOffType.OFF;
public OnOffType wbSchukoLocked = OnOffType.OFF;
public OnOffType wbSchukoRelay16 = OnOffType.OFF;
public OnOffType wbRelay16 = OnOffType.OFF;
public OnOffType wbRelay32 = OnOffType.OFF;
public OnOffType wb1phase = OnOffType.OFF;
/**
* For decoding see Modbus Register Mapping Chapter 3.1.2 page 15
* The Registers for Wallbox Control are declared as uint16 but shall be handled as Bit registers => see chapter
* 3.1.5 page 19
*
* @param bArray - one Modbus Registers according to Wallbox ID
*/
public WallboxBlock(byte[] bArray) {
bitSet = BitSet.valueOf(bArray);
wbAvailable = OnOffType.from(bitSet.get(WB_AVAILABLE_BIT));
wbSunmode = OnOffType.from(bitSet.get(WB_SUNMODE_BIT));
wbChargingAborted = OnOffType.from(bitSet.get(WB_CHARGING_ABORTED_BIT));
wbCharging = OnOffType.from(bitSet.get(WB_CHARGING_BIT));
wbJackLocked = OnOffType.from(bitSet.get(WB_JACK_LOCKED_BIT));
wbJackPlugged = OnOffType.from(bitSet.get(WB_JACK_PLUGGED_BIT));
wbSchukoOn = OnOffType.from(bitSet.get(WB_SCHUKO_ON_BIT));
wbSchukoPlugged = OnOffType.from(bitSet.get(WB_SCHUKO_PLUGGED_BIT));
wbSchukoLocked = OnOffType.from(bitSet.get(WB_SCHUKO_LOCKED_BIT));
wbSchukoRelay16 = OnOffType.from(bitSet.get(WB_SCHUKO_RELAY16A_BIT));
wbRelay16 = OnOffType.from(bitSet.get(WB_RELAY_16A_BIT));
wbRelay32 = OnOffType.from(bitSet.get(WB_RELAY_32A_BIT));
wb1phase = OnOffType.from(bitSet.get(WB_1PHASE_BIT));
}
public BitSet getBitSet() {
return bitSet;
}
}

View File

@@ -0,0 +1,450 @@
/**
* 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.modbus.e3dc.internal.handler;
import static org.openhab.binding.modbus.e3dc.internal.E3DCBindingConstants.*;
import static org.openhab.binding.modbus.e3dc.internal.modbus.E3DCModbusConstans.*;
import java.util.ArrayList;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.modbus.e3dc.internal.E3DCConfiguration;
import org.openhab.binding.modbus.e3dc.internal.dto.EmergencyBlock;
import org.openhab.binding.modbus.e3dc.internal.dto.InfoBlock;
import org.openhab.binding.modbus.e3dc.internal.dto.PowerBlock;
import org.openhab.binding.modbus.e3dc.internal.dto.StringBlock;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data.DataType;
import org.openhab.binding.modbus.e3dc.internal.modbus.Parser;
import org.openhab.binding.modbus.handler.EndpointNotInitializedException;
import org.openhab.binding.modbus.handler.ModbusEndpointThingHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.openhab.io.transport.modbus.AsyncModbusFailure;
import org.openhab.io.transport.modbus.AsyncModbusReadResult;
import org.openhab.io.transport.modbus.ModbusCommunicationInterface;
import org.openhab.io.transport.modbus.ModbusReadFunctionCode;
import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint;
import org.openhab.io.transport.modbus.PollTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link E3DCThingHandler} Basic modbus connection towards the E3DC device
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class E3DCThingHandler extends BaseBridgeHandler {
public enum ReadStatus {
NOT_RECEIVED,
READ_SUCCESS,
READ_FAILED
}
static final String INFO_DATA_READ_ERROR = "Information And Data Modbus Read Errors";
static final String INFO_READ_ERROR = "Information Modbus Read Error";
static final String DATA_READ_ERROR = "Data Modbus Read Error";
static final String INFO_GROUP = "info";
static final String EMERGENCY_GROUP = "emergency";
static final String POWER_GROUP = "power";
static final String STRINGS_GROUP = "strings";
private ChannelUID modbusIdChannel;
private ChannelUID modbusVersionChannel;
private ChannelUID supportedRegistersChannel;
private ChannelUID manufacturerChannel;
private ChannelUID modelNameChannel;
private ChannelUID serialNumberChannel;
private ChannelUID firmwareChannel;
private ChannelUID epStatusChannel;
private ChannelUID batteryChargingLockedChannel;
private ChannelUID batteryDischargingLockedChannel;
private ChannelUID epPossibleChannel;
private ChannelUID weatherPredictedChargingChannel;
private ChannelUID regulationStatusChannel;
private ChannelUID chargeLockTimeChannel;
private ChannelUID dischargeLockTimeChannel;
private ChannelUID pvPowerSupplyChannel;
private ChannelUID batteryPowerSupplyChannel;
private ChannelUID batteryPowerConsumptionChannel;
private ChannelUID householdPowerConsumptionChannel;
private ChannelUID gridPowerConsumpitionChannel;
private ChannelUID gridPowerSupplyChannel;
private ChannelUID externalPowerSupplyChannel;
private ChannelUID wallboxPowerConsumptionChannel;
private ChannelUID wallboxPVPowerConsumptionChannel;
private ChannelUID autarkyChannel;
private ChannelUID selfConsumptionChannel;
private ChannelUID batterySOCChannel;
private ChannelUID string1AmpereChannel;
private ChannelUID string1VoltChannel;
private ChannelUID string1WattChannel;
private ChannelUID string2AmpereChannel;
private ChannelUID string2VoltChannel;
private ChannelUID string2WattChannel;
private ChannelUID string3AmpereChannel;
private ChannelUID string3VoltChannel;
private ChannelUID string3WattChannel;
private final ArrayList<E3DCWallboxThingHandler> listeners = new ArrayList<E3DCWallboxThingHandler>();
private final Logger logger = LoggerFactory.getLogger(E3DCThingHandler.class);
private final Parser dataParser = new Parser(DataType.DATA);
private ReadStatus dataRead = ReadStatus.NOT_RECEIVED;
private final Parser infoParser = new Parser(DataType.INFO);
private ReadStatus infoRead = ReadStatus.NOT_RECEIVED;
private @Nullable PollTask infoPoller;
private @Nullable PollTask dataPoller;
private @Nullable E3DCConfiguration config;
/**
* Communication interface to the slave endpoint we're connecting to
*/
protected volatile @Nullable ModbusCommunicationInterface comms = null;
private int slaveId;
public E3DCThingHandler(Bridge thing) {
super(thing);
modbusIdChannel = channelUID(thing, INFO_GROUP, MODBUS_ID_CHANNEL);
modbusVersionChannel = channelUID(thing, INFO_GROUP, MODBUS_FIRMWARE_CHANNEL);
supportedRegistersChannel = channelUID(thing, INFO_GROUP, SUPPORTED_REGISTERS_CHANNEL);
manufacturerChannel = channelUID(thing, INFO_GROUP, MANUFACTURER_NAME_CHANNEL);
modelNameChannel = channelUID(thing, INFO_GROUP, MODEL_NAME_CHANNEL);
serialNumberChannel = channelUID(thing, INFO_GROUP, SERIAL_NUMBER_CHANNEL);
firmwareChannel = channelUID(thing, INFO_GROUP, FIRMWARE_RELEASE_CHANNEL);
epStatusChannel = channelUID(thing, EMERGENCY_GROUP, EMERGENCY_POWER_STATUS);
batteryChargingLockedChannel = channelUID(thing, EMERGENCY_GROUP, BATTERY_CHARGING_LOCKED);
batteryDischargingLockedChannel = channelUID(thing, EMERGENCY_GROUP, BATTERY_DISCHARGING_LOCKED);
epPossibleChannel = channelUID(thing, EMERGENCY_GROUP, EMERGENCY_POWER_POSSIBLE);
weatherPredictedChargingChannel = channelUID(thing, EMERGENCY_GROUP, WEATHER_PREDICTED_CHARGING);
regulationStatusChannel = channelUID(thing, EMERGENCY_GROUP, REGULATION_STATUS);
chargeLockTimeChannel = channelUID(thing, EMERGENCY_GROUP, CHARGE_LOCK_TIME);
dischargeLockTimeChannel = channelUID(thing, EMERGENCY_GROUP, DISCHARGE_LOCK_TIME);
pvPowerSupplyChannel = channelUID(thing, POWER_GROUP, PV_POWER_SUPPLY_CHANNEL);
batteryPowerSupplyChannel = channelUID(thing, POWER_GROUP, BATTERY_POWER_SUPPLY_CHANNEL);
batteryPowerConsumptionChannel = channelUID(thing, POWER_GROUP, BATTERY_POWER_CONSUMPTION);
householdPowerConsumptionChannel = channelUID(thing, POWER_GROUP, HOUSEHOLD_POWER_CONSUMPTION_CHANNEL);
gridPowerConsumpitionChannel = channelUID(thing, POWER_GROUP, GRID_POWER_CONSUMPTION_CHANNEL);
gridPowerSupplyChannel = channelUID(thing, POWER_GROUP, GRID_POWER_SUPPLY_CHANNEL);
externalPowerSupplyChannel = channelUID(thing, POWER_GROUP, EXTERNAL_POWER_SUPPLY_CHANNEL);
wallboxPowerConsumptionChannel = channelUID(thing, POWER_GROUP, WALLBOX_POWER_CONSUMPTION_CHANNEL);
wallboxPVPowerConsumptionChannel = channelUID(thing, POWER_GROUP, WALLBOX_PV_POWER_CONSUMPTION_CHANNEL);
autarkyChannel = channelUID(thing, POWER_GROUP, AUTARKY_CHANNEL);
selfConsumptionChannel = channelUID(thing, POWER_GROUP, SELF_CONSUMPTION_CHANNEL);
batterySOCChannel = channelUID(thing, POWER_GROUP, BATTERY_STATE_OF_CHARGE_CHANNEL);
string1AmpereChannel = channelUID(thing, STRINGS_GROUP, STRING1_DC_CURRENT_CHANNEL);
string1VoltChannel = channelUID(thing, STRINGS_GROUP, STRING1_DC_VOLTAGE_CHANNEL);
string1WattChannel = channelUID(thing, STRINGS_GROUP, STRING1_DC_OUTPUT_CHANNEL);
string2AmpereChannel = channelUID(thing, STRINGS_GROUP, STRING2_DC_CURRENT_CHANNEL);
string2VoltChannel = channelUID(thing, STRINGS_GROUP, STRING2_DC_VOLTAGE_CHANNEL);
string2WattChannel = channelUID(thing, STRINGS_GROUP, STRING2_DC_OUTPUT_CHANNEL);
string3AmpereChannel = channelUID(thing, STRINGS_GROUP, STRING3_DC_CURRENT_CHANNEL);
string3VoltChannel = channelUID(thing, STRINGS_GROUP, STRING3_DC_VOLTAGE_CHANNEL);
string3WattChannel = channelUID(thing, STRINGS_GROUP, STRING3_DC_OUTPUT_CHANNEL);
}
public @Nullable ModbusCommunicationInterface getComms() {
return comms;
}
public int getSlaveId() {
return slaveId;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
// no control of E3DC device possible yet
}
@Override
public void initialize() {
updateStatus(ThingStatus.UNKNOWN);
scheduler.execute(() -> {
E3DCConfiguration localConfig = getConfigAs(E3DCConfiguration.class);
config = localConfig;
ModbusCommunicationInterface localComms = connectEndpoint();
if (localComms != null) {
// register low speed info poller
ModbusReadRequestBlueprint infoRequest = new ModbusReadRequestBlueprint(slaveId,
ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, INFO_REG_START, INFO_REG_SIZE, 3);
infoPoller = localComms.registerRegularPoll(infoRequest, INFO_POLL_REFRESH_TIME_MS, 0,
this::handleInfoResult, this::handleInfoFailure);
ModbusReadRequestBlueprint dataRequest = new ModbusReadRequestBlueprint(slaveId,
ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, POWER_REG_START,
REGISTER_LENGTH - INFO_REG_SIZE, 3);
if (config != null) {
dataPoller = localComms.registerRegularPoll(dataRequest, localConfig.refresh, 0,
this::handleDataResult, this::handleDataFailure);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"E3DC Configuration missing");
}
} // else state handling performed in connectEndPoint function
});
}
/**
* Get a reference to the modbus endpoint
*/
private @Nullable ModbusCommunicationInterface connectEndpoint() {
if (comms != null) {
return comms;
}
ModbusEndpointThingHandler slaveEndpointThingHandler = getEndpointThingHandler();
if (slaveEndpointThingHandler == null) {
@SuppressWarnings("null")
String label = Optional.ofNullable(getBridge()).map(b -> b.getLabel()).orElse("<null>");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
String.format("Bridge '%s' is offline", label));
return null;
}
try {
slaveId = slaveEndpointThingHandler.getSlaveId();
comms = slaveEndpointThingHandler.getCommunicationInterface();
} catch (EndpointNotInitializedException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
String.format("Slave Endpoint not initialized"));
return null;
}
if (comms == null) {
@SuppressWarnings("null")
String label = Optional.ofNullable(getBridge()).map(b -> b.getLabel()).orElse("<null>");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
String.format("Bridge '%s' not completely initialized", label));
return null;
} else {
return comms;
}
}
/**
* Get the endpoint handler from the bridge this handler is connected to
* Checks that we're connected to the right type of bridge
*
* @return the endpoint handler or null if the bridge does not exist
*/
private @Nullable ModbusEndpointThingHandler getEndpointThingHandler() {
Bridge bridge = getBridge();
if (bridge == null) {
logger.debug("Bridge is null");
return null;
}
if (bridge.getStatus() != ThingStatus.ONLINE) {
logger.debug("Bridge is not online");
return null;
}
ThingHandler handler = bridge.getHandler();
if (handler == null) {
logger.debug("Bridge handler is null");
return null;
}
if (handler instanceof ModbusEndpointThingHandler) {
ModbusEndpointThingHandler slaveEndpoint = (ModbusEndpointThingHandler) handler;
return slaveEndpoint;
} else {
logger.debug("Unexpected bridge handler: {}", handler);
return null;
}
}
/**
* Returns the channel UID for the specified group and channel id
*
* @param string the channel group
* @param string the channel id in that group
* @return the globally unique channel uid
*/
private ChannelUID channelUID(Thing t, String group, String id) {
return new ChannelUID(t.getUID(), group, id);
}
void handleInfoResult(AsyncModbusReadResult result) {
if (infoRead != ReadStatus.READ_SUCCESS) {
// update status only if bit switches
infoRead = ReadStatus.READ_SUCCESS;
updateStatus();
}
infoParser.handle(result);
Optional<Data> blockOpt = infoParser.parse(DataType.INFO);
if (blockOpt.isPresent()) {
InfoBlock block = (InfoBlock) blockOpt.get();
updateState(modbusIdChannel, block.modbusId);
updateState(modbusVersionChannel, block.modbusVersion);
updateState(supportedRegistersChannel, block.supportedRegisters);
updateState(manufacturerChannel, block.manufacturer);
updateState(modelNameChannel, block.modelName);
updateState(serialNumberChannel, block.serialNumber);
updateState(firmwareChannel, block.firmware);
} else {
logger.debug("Unable to get {} from provider {}", DataType.INFO, dataParser.toString());
}
}
void handleInfoFailure(AsyncModbusFailure<ModbusReadRequestBlueprint> result) {
if (infoRead != ReadStatus.READ_FAILED) {
// update status only if bit switches
infoRead = ReadStatus.READ_FAILED;
updateStatus();
}
}
void handleDataResult(AsyncModbusReadResult result) {
if (dataRead != ReadStatus.READ_SUCCESS) {
// update status only if bit switches
dataRead = ReadStatus.READ_SUCCESS;
updateStatus();
}
dataParser.handle(result);
// Update channels in emergency group
{
Optional<Data> blockOpt = dataParser.parse(DataType.EMERGENCY);
if (blockOpt.isPresent()) {
EmergencyBlock block = (EmergencyBlock) blockOpt.get();
updateState(epStatusChannel, block.epStatus);
updateState(batteryChargingLockedChannel, block.batteryChargingLocked);
updateState(batteryDischargingLockedChannel, block.batteryDischargingLocked);
updateState(epPossibleChannel, block.epPossible);
updateState(weatherPredictedChargingChannel, block.weatherPredictedCharging);
updateState(regulationStatusChannel, block.regulationStatus);
updateState(chargeLockTimeChannel, block.chargeLockTime);
updateState(dischargeLockTimeChannel, block.dischargeLockTime);
} else {
logger.debug("Unable to get {} from provider {}", DataType.EMERGENCY, dataParser.toString());
}
}
// Update channels in power group
{
Optional<Data> blockOpt = dataParser.parse(DataType.POWER);
if (blockOpt.isPresent()) {
PowerBlock block = (PowerBlock) blockOpt.get();
updateState(pvPowerSupplyChannel, block.pvPowerSupply);
updateState(batteryPowerSupplyChannel, block.batteryPowerSupply);
updateState(batteryPowerConsumptionChannel, block.batteryPowerConsumption);
updateState(householdPowerConsumptionChannel, block.householdPowerConsumption);
updateState(gridPowerConsumpitionChannel, block.gridPowerConsumpition);
updateState(gridPowerSupplyChannel, block.gridPowerSupply);
updateState(externalPowerSupplyChannel, block.externalPowerSupply);
updateState(wallboxPowerConsumptionChannel, block.wallboxPowerConsumption);
updateState(wallboxPVPowerConsumptionChannel, block.wallboxPVPowerConsumption);
updateState(autarkyChannel, block.autarky);
updateState(selfConsumptionChannel, block.selfConsumption);
updateState(batterySOCChannel, block.batterySOC);
} else {
logger.debug("Unable to get {} from provider {}", DataType.POWER, dataParser.toString());
}
}
// Update channels in strings group
{
Optional<Data> blockOpt = dataParser.parse(DataType.STRINGS);
if (blockOpt.isPresent()) {
StringBlock block = (StringBlock) blockOpt.get();
updateState(string1AmpereChannel, block.string1Ampere);
updateState(string1VoltChannel, block.string1Volt);
updateState(string1WattChannel, block.string1Watt);
updateState(string2AmpereChannel, block.string2Ampere);
updateState(string2VoltChannel, block.string2Volt);
updateState(string2WattChannel, block.string2Watt);
updateState(string3AmpereChannel, block.string3Ampere);
updateState(string3VoltChannel, block.string3Volt);
updateState(string3WattChannel, block.string3Watt);
} else {
logger.debug("Unable to get {} from provider {}", DataType.STRINGS, dataParser.toString());
}
}
listeners.forEach(l -> {
l.handle(result);
});
}
void handleDataFailure(AsyncModbusFailure<ModbusReadRequestBlueprint> result) {
if (dataRead != ReadStatus.READ_FAILED) {
// update status only if bit switches
dataRead = ReadStatus.READ_FAILED;
updateStatus();
}
listeners.forEach(l -> {
l.handleError(result);
});
}
@Override
public void dispose() {
ModbusCommunicationInterface localComms = comms;
if (localComms != null) {
PollTask localInfoPoller = infoPoller;
if (localInfoPoller != null) {
localComms.unregisterRegularPoll(localInfoPoller);
}
PollTask localDataPoller = dataPoller;
if (localDataPoller != null) {
localComms.unregisterRegularPoll(localDataPoller);
}
}
// Comms will be close()'d by endpoint thing handler
comms = null;
}
private void updateStatus() {
logger.debug("Status update: Info {} Data {} ", infoRead, dataRead);
if (infoRead != ReadStatus.NOT_RECEIVED && dataRead != ReadStatus.NOT_RECEIVED) {
if (infoRead == dataRead) {
// both reads are ok or else both failed
if (infoRead == ReadStatus.READ_SUCCESS) {
updateStatus(ThingStatus.ONLINE);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, INFO_DATA_READ_ERROR);
}
} else {
// either info or data read failed - update status with details
if (infoRead == ReadStatus.READ_FAILED) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, INFO_READ_ERROR);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, DATA_READ_ERROR);
}
}
} // else - one status isn't received yet - wait until both Modbus polls returns either success or error
}
@Override
public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) {
listeners.add((E3DCWallboxThingHandler) childHandler);
}
@Override
public void childHandlerDisposed(ThingHandler childHandler, Thing childThing) {
listeners.remove(childHandler);
}
}

View File

@@ -0,0 +1,259 @@
/**
* 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.modbus.e3dc.internal.handler;
import static org.openhab.binding.modbus.e3dc.internal.E3DCBindingConstants.*;
import static org.openhab.binding.modbus.e3dc.internal.modbus.E3DCModbusConstans.*;
import java.util.BitSet;
import java.util.Optional;
import java.util.OptionalInt;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.modbus.e3dc.internal.E3DCWallboxConfiguration;
import org.openhab.binding.modbus.e3dc.internal.dto.DataConverter;
import org.openhab.binding.modbus.e3dc.internal.dto.WallboxArray;
import org.openhab.binding.modbus.e3dc.internal.dto.WallboxBlock;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data.DataType;
import org.openhab.binding.modbus.e3dc.internal.modbus.Parser;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.openhab.io.transport.modbus.AsyncModbusFailure;
import org.openhab.io.transport.modbus.AsyncModbusReadResult;
import org.openhab.io.transport.modbus.ModbusCommunicationInterface;
import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint;
import org.openhab.io.transport.modbus.ModbusRegisterArray;
import org.openhab.io.transport.modbus.ModbusWriteRegisterRequestBlueprint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link E3DCWallboxThingHandler} Basic modbus connection towards the E3DC device
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class E3DCWallboxThingHandler extends BaseThingHandler {
public enum ReadWriteSuccess {
NOT_RECEIVED,
SUCCESS,
FAILED
}
private static final String READ_WRITE_ERROR = "Modbus Data Read/Write Error";
private static final String READ_ERROR = "Modbus Read Error";
private static final String WRITE_ERROR = "Modbus Write Error";
ChannelUID wbAvailableChannel;
ChannelUID wbSunmodeChannel;
ChannelUID wbChargingAbortedChannel;
ChannelUID wbChargingChannel;
ChannelUID wbJackLockedChannel;
ChannelUID wbJackPluggedChannel;
ChannelUID wbSchukoOnChannel;
ChannelUID wbSchukoPluggedChannel;
ChannelUID wbSchukoLockedChannel;
ChannelUID wbSchukoRelay16Channel;
ChannelUID wbRelay16Channel;
ChannelUID wbRelay32Channel;
ChannelUID wb1phaseChannel;
private final Logger logger = LoggerFactory.getLogger(E3DCWallboxThingHandler.class);
private final Parser dataParser = new Parser(DataType.DATA);
private ReadWriteSuccess dataRead = ReadWriteSuccess.NOT_RECEIVED;
private ReadWriteSuccess dataWrite = ReadWriteSuccess.NOT_RECEIVED;
private volatile BitSet currentBitSet = new BitSet(16);
private @Nullable E3DCWallboxConfiguration config;
private @Nullable E3DCThingHandler bridgeHandler;
public E3DCWallboxThingHandler(Thing thing) {
super(thing);
wbAvailableChannel = new ChannelUID(thing.getUID(), WB_AVAILABLE_CHANNEL);
wbSunmodeChannel = new ChannelUID(thing.getUID(), WB_SUNMODE_CHANNEL);
wbChargingAbortedChannel = new ChannelUID(thing.getUID(), WB_CHARGING_ABORTED_CHANNEL);
wbChargingChannel = new ChannelUID(thing.getUID(), WB_CHARGING_CHANNEL);
wbJackLockedChannel = new ChannelUID(thing.getUID(), WB_JACK_LOCKED_CHANNEL);
wbJackPluggedChannel = new ChannelUID(thing.getUID(), WB_JACK_PLUGGED_CHANNEL);
wbSchukoOnChannel = new ChannelUID(thing.getUID(), WB_SCHUKO_ON_CHANNEL);
wbSchukoPluggedChannel = new ChannelUID(thing.getUID(), WB_SCHUKO_PLUGGED_CHANNEL);
wbSchukoLockedChannel = new ChannelUID(thing.getUID(), WB_SCHUKO_LOCKED_CHANNEL);
wbSchukoRelay16Channel = new ChannelUID(thing.getUID(), WB_SCHUKO_RELAY_16A_CHANNEL);
wbRelay16Channel = new ChannelUID(thing.getUID(), WB_RELAY_16A_CHANNEL);
wbRelay32Channel = new ChannelUID(thing.getUID(), WB_RELAY_32A_CHANNEL);
wb1phaseChannel = new ChannelUID(thing.getUID(), WB_1PHASE_CHANNEL);
}
@Override
public void initialize() {
updateStatus(ThingStatus.UNKNOWN);
config = getConfigAs(E3DCWallboxConfiguration.class);
Bridge bridge = getBridge();
if (bridge != null) {
ThingHandler handler = bridge.getHandler();
if (handler != null) {
bridgeHandler = ((E3DCThingHandler) handler);
} else {
logger.warn("Thing Handler null");
}
} else {
logger.warn("Bridge null");
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof OnOffType) {
int writeValue = 0;
synchronized (this) {
if (channelUID.getIdWithoutGroup().equals(WB_SUNMODE_CHANNEL)) {
currentBitSet.set(WB_SUNMODE_BIT, command.equals(OnOffType.ON));
} else if (channelUID.getIdWithoutGroup().equals(WB_CHARGING_ABORTED_CHANNEL)) {
currentBitSet.set(WB_CHARGING_ABORTED_BIT, command.equals(OnOffType.ON));
} else if (channelUID.getIdWithoutGroup().equals(WB_SCHUKO_ON_CHANNEL)) {
currentBitSet.set(WB_SCHUKO_ON_BIT, command.equals(OnOffType.ON));
} else if (channelUID.getIdWithoutGroup().equals(WB_1PHASE_CHANNEL)) {
currentBitSet.set(WB_1PHASE_BIT, command.equals(OnOffType.ON));
}
writeValue = DataConverter.toInt(currentBitSet);
logger.debug("Wallbox write {}", writeValue);
}
OptionalInt wallboxId = getWallboxId(config);
if (wallboxId.isPresent()) {
wallboxSet(wallboxId.getAsInt(), writeValue);
}
}
}
/**
* Wallbox Settings can be changed with one Integer
*
* @param wallboxId needed to calculate right register
* @param writeValue integer to be written
*/
public void wallboxSet(int wallboxId, int writeValue) {
E3DCThingHandler localBridgeHandler = bridgeHandler;
if (localBridgeHandler != null) {
ModbusCommunicationInterface comms = localBridgeHandler.getComms();
if (comms != null) {
ModbusRegisterArray regArray = new ModbusRegisterArray(writeValue);
ModbusWriteRegisterRequestBlueprint writeBluePrint = new ModbusWriteRegisterRequestBlueprint(
localBridgeHandler.getSlaveId(), WALLBOX_REG_START + wallboxId, regArray, false, 3);
comms.submitOneTimeWrite(writeBluePrint, result -> {
if (dataWrite != ReadWriteSuccess.SUCCESS) {
dataWrite = ReadWriteSuccess.SUCCESS;
updateStatus();
}
logger.debug("E3DC Modbus write response! {}", result.getResponse().toString());
}, failure -> {
if (dataWrite != ReadWriteSuccess.FAILED) {
dataWrite = ReadWriteSuccess.FAILED;
updateStatus();
}
logger.warn("E3DC Modbus write error! {}", failure.getRequest().toString());
});
}
}
}
private OptionalInt getWallboxId(@Nullable E3DCWallboxConfiguration c) {
if (c != null) {
return OptionalInt.of(c.wallboxId);
} else {
return OptionalInt.empty();
}
}
public void handle(AsyncModbusReadResult result) {
if (dataRead != ReadWriteSuccess.SUCCESS) {
dataRead = ReadWriteSuccess.SUCCESS;
updateStatus();
}
dataParser.handle(result);
Optional<Data> wbArrayOpt = dataParser.parse(DataType.WALLBOX);
if (wbArrayOpt.isPresent()) {
WallboxArray wbArray = (WallboxArray) wbArrayOpt.get();
OptionalInt wallboxId = getWallboxId(config);
if (wallboxId.isPresent()) {
Optional<WallboxBlock> blockOpt = wbArray.getWallboxBlock(wallboxId.getAsInt());
if (blockOpt.isPresent()) {
WallboxBlock block = blockOpt.get();
synchronized (this) {
currentBitSet = block.getBitSet();
}
updateState(wbAvailableChannel, block.wbAvailable);
updateState(wbSunmodeChannel, block.wbSunmode);
updateState(wbChargingAbortedChannel, block.wbChargingAborted);
updateState(wbChargingChannel, block.wbCharging);
updateState(wbJackLockedChannel, block.wbJackLocked);
updateState(wbJackPluggedChannel, block.wbJackPlugged);
updateState(wbSchukoOnChannel, block.wbSchukoOn);
updateState(wbSchukoPluggedChannel, block.wbSchukoPlugged);
updateState(wbSchukoLockedChannel, block.wbSchukoLocked);
updateState(wbSchukoRelay16Channel, block.wbSchukoRelay16);
updateState(wbRelay16Channel, block.wbRelay16);
updateState(wbRelay32Channel, block.wbRelay32);
updateState(wb1phaseChannel, block.wb1phase);
} else {
logger.debug("Unable to get ID {} from WallboxArray", wallboxId);
}
} else {
logger.debug("Wallbox ID {} not valid", wallboxId);
}
} else {
logger.debug("Unable to get {} from Bridge", DataType.WALLBOX);
}
}
public void handleError(AsyncModbusFailure<ModbusReadRequestBlueprint> result) {
if (dataRead != ReadWriteSuccess.FAILED) {
dataRead = ReadWriteSuccess.FAILED;
updateStatus();
}
}
private void updateStatus() {
if (dataWrite == ReadWriteSuccess.NOT_RECEIVED) {
// read success / write not happened yet => go online / offline
if (dataRead == ReadWriteSuccess.SUCCESS) {
updateStatus(ThingStatus.ONLINE);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, READ_ERROR);
}
} else {
if (dataRead == dataWrite) {
// read and write same status - either go online or offline
if (dataRead == ReadWriteSuccess.SUCCESS) {
updateStatus(ThingStatus.ONLINE);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, READ_WRITE_ERROR);
}
} else {
// either read or write failed - go offline with detailed status
if (dataRead == ReadWriteSuccess.SUCCESS) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, WRITE_ERROR);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, READ_ERROR);
}
}
}
}
}

View File

@@ -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.modbus.e3dc.internal.modbus;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link Data} Marker Interface for delivered Modbus Data
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public interface Data {
public enum DataType {
INFO,
POWER,
WALLBOX,
EMERGENCY,
STRINGS,
DATA // marks all types besides INFO
}
}

View File

@@ -0,0 +1,70 @@
/**
* 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.modbus.e3dc.internal.modbus;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link E3DCModbusConstans} Variables for register handling.
* The numbers are taken from E3DC Modbus Spec Chapter 3.1 page 14 ff
* Registers start from 0 (not 1!) so from the documented registers subtract 1
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class E3DCModbusConstans {
// "String" registers at the beginning shall be read with very low frequency - 1 hour
public static final int INFO_POLL_REFRESH_TIME_MS = 60 * 60 * 1000;
// Constants where a certain Block starts and block size. Note: General offset is -1 so INFO_REG from E3DC Modbus
// Spec starts at 1 but it's Register 0!
public static final int INFO_REG_START = 0;
public static final int INFO_REG_SIZE = 67;
public static final int POWER_REG_START = 67;
public static final int POWER_REG_SIZE = 16;
public static final int EMS_REG_START = 83;
public static final int EMS_REG_SIZE = 2;
public static final int WALLBOX_REG_START = 87;
public static final int WALLBOX_REG_SIZE = 8;
public static final int STRINGS_REG_START = 95;
public static final int STRINGS_REG_SIZE = 9;
public static final int REGISTER_LENGTH = 104;
/*
* Some Registers are numbers but needs to be decoded into Bits
*/
// Wallbox Bit Definitions according to chapter 3.1.5 page 15
public static final int WB_AVAILABLE_BIT = 0;
public static final int WB_SUNMODE_BIT = 1;
public static final int WB_CHARGING_ABORTED_BIT = 2;
public static final int WB_CHARGING_BIT = 3;
public static final int WB_JACK_LOCKED_BIT = 4;
public static final int WB_JACK_PLUGGED_BIT = 5;
public static final int WB_SCHUKO_ON_BIT = 6;
public static final int WB_SCHUKO_PLUGGED_BIT = 7;
public static final int WB_SCHUKO_LOCKED_BIT = 8;
public static final int WB_SCHUKO_RELAY16A_BIT = 9;
public static final int WB_RELAY_16A_BIT = 10;
public static final int WB_RELAY_32A_BIT = 11;
public static final int WB_1PHASE_BIT = 12;
// EMS Bit Definitions according to chapter 3.1.3 page 17
public static final int EMS_CHARGING_LOCK_BIT = 0;
public static final int EMS_DISCHARGING_LOCK_BIT = 1;
public static final int EMS_AVAILABLE_BIT = 2;
public static final int EMS_WEATHER_CHARGING_BIT = 3;
public static final int EMS_REGULATION_BIT = 4;
public static final int EMS_CHARGE_LOCKTIME_BIT = 5;
public static final int EMS_DISCHARGE_LOCKTIME_BIT = 6;
}

View File

@@ -0,0 +1,129 @@
/**
* 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.modbus.e3dc.internal.modbus;
import static org.openhab.binding.modbus.e3dc.internal.modbus.E3DCModbusConstans.*;
import java.util.Arrays;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.e3dc.internal.dto.EmergencyBlock;
import org.openhab.binding.modbus.e3dc.internal.dto.InfoBlock;
import org.openhab.binding.modbus.e3dc.internal.dto.PowerBlock;
import org.openhab.binding.modbus.e3dc.internal.dto.StringBlock;
import org.openhab.binding.modbus.e3dc.internal.dto.WallboxArray;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data.DataType;
import org.openhab.io.transport.modbus.AsyncModbusReadResult;
import org.openhab.io.transport.modbus.ModbusRegister;
import org.openhab.io.transport.modbus.ModbusRegisterArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link InfoBlockCallback} class receives callbacks from modbus poller
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class Parser {
private static final int MEASURE_COUNT = 100;
private final Logger logger = LoggerFactory.getLogger(Parser.class);
private DataType callbackType;
private byte[] bArray;
private int size;
private int counter = 0;
private long maxDuration = Long.MIN_VALUE;
private long minDuration = Long.MAX_VALUE;
private long avgDuration = 0;
public Parser(DataType type) {
callbackType = type;
if (type.equals(DataType.INFO)) {
size = INFO_REG_SIZE * 2;
bArray = new byte[size];
} else {
size = (REGISTER_LENGTH - INFO_REG_SIZE) * 2;
bArray = new byte[size];
}
}
public void handle(AsyncModbusReadResult result) {
byte[] newArray = new byte[size];
long startTime = System.currentTimeMillis();
Optional<ModbusRegisterArray> opt = result.getRegisters();
if (opt.isPresent()) {
ModbusRegisterArray registers = opt.get();
int i = 0;
for (ModbusRegister reg : registers) {
System.arraycopy(reg.getBytes(), 0, newArray, i, 2);
i += 2;
}
setArray(newArray);
long duration = System.currentTimeMillis() - startTime;
avgDuration += duration;
minDuration = Math.min(minDuration, duration);
maxDuration = Math.max(maxDuration, duration);
counter++;
if (counter % MEASURE_COUNT == 0) {
logger.debug("Min {} Max {} Avg {}", minDuration, maxDuration, avgDuration / MEASURE_COUNT);
avgDuration = 0;
minDuration = Long.MAX_VALUE;
maxDuration = Long.MIN_VALUE;
}
} else {
logger.warn("Modbus read result doesn't return expected registers");
}
}
public synchronized void setArray(byte[] b) {
if (b.length != size) {
logger.warn("Wrong byte size received. Should be {} but is {}. Data maybe corrupted!", size, b.length);
}
bArray = b.clone();
}
public Optional<Data> parse(DataType type) {
synchronized (bArray) {
if (type.equals(DataType.INFO) && callbackType.equals(DataType.INFO)) {
return Optional.of(new InfoBlock(Arrays.copyOfRange(bArray, INFO_REG_START, INFO_REG_SIZE * 2)));
} else if (type.equals(DataType.POWER) && callbackType.equals(DataType.DATA)) {
int start = (POWER_REG_START - INFO_REG_SIZE) * 2;
int end = start + POWER_REG_SIZE * 2;
return Optional.of(new PowerBlock(Arrays.copyOfRange(bArray, start, end)));
} else if (type.equals(DataType.EMERGENCY) && callbackType.equals(DataType.DATA)) {
int start = (EMS_REG_START - INFO_REG_SIZE) * 2;
int end = start + EMS_REG_SIZE * 2;
return Optional.of(new EmergencyBlock(Arrays.copyOfRange(bArray, start, end)));
} else if (type.equals(DataType.WALLBOX) && callbackType.equals(DataType.DATA)) {
int start = (WALLBOX_REG_START - INFO_REG_SIZE) * 2;
int end = start + WALLBOX_REG_SIZE * 2;
return Optional.of(new WallboxArray(Arrays.copyOfRange(bArray, start, end)));
} else if (type.equals(DataType.STRINGS) && callbackType.equals(DataType.DATA)) {
int start = (STRINGS_REG_START - INFO_REG_SIZE) * 2;
int end = start + STRINGS_REG_SIZE * 2;
return Optional.of(new StringBlock(Arrays.copyOfRange(bArray, start, end)));
}
}
logger.warn("Wrong Block requested. Request is {} but type is {}", type, callbackType);
return Optional.empty();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getName()).append(":").append(callbackType);
return sb.toString();
}
}

View File

@@ -0,0 +1,81 @@
# thing types
thing-type.modbus.e3dc.label = E3DC Hauskraftwerk
thing-type.modbus.e3dc.description = Zeigt die Leistungswerte, String Details, Notstrom Zustand und generelle Details zu Ihrem E3DC Hauskraftwerk
thing-type.modbus.e3dc-wallbox.label = E3DC Wallbox
thing-type.modbus.e3dc-wallbox.description = Zeigt die Einstellungen der verbundenen Wallbox. Schalter wie "Sonnenmodus" oder "1-phasiges Laden" können geändert werden
# thing type config description
thing-type.config.modbus.e3dc.refresh.label = Zyklische Abfragezeit
thing-type.config.modbus.e3dc.refresh.description = Intervall in Millisekunden, wie oft die Werte abgerufen werden sollen
thing-type.config.modbus.e3dc-wallbox.wallboxId.label = Wallbox-Nummer
thing-type.config.modbus.e3dc-wallbox.wallboxId.description = Das E3DC Gerät unterstützt bis zu 8 Wallboxen - Wählen Sie einen Wert zwischen 0 und 7
# Channel group types
channel-group-type.modbus.info-values.label = Informationen
channel-group-type.modbus.info-values.description = Basisinformationen zum E3DC Hauskraftwerk wie Modellname, Seriennummer und Software-Versionen
channel-group-type.modbus.power-values.label = Leistungswerte
channel-group-type.modbus.power-values.description = Elektrische Werte der angeschlossenen Erzeuger (Photovoltaik, Batterie, ...) und Verbraucher (Haushaltsverbrauch, Wallbox,...)
channel-group-type.modbus.string-values.label = String Details
channel-group-type.modbus.string-values.description = Detaillierte Werte der angeschlossenen Photovoltaik Strings. Zeigt die einzelnen Werte jedes angeschlossenen Strings
channel-group-type.modbus.emergency-values.label = Notstrom Einstellungen
channel-group-type.modbus.emergency-values.description = Status und Werte der Notstromversorgung wie Batterie Lade- und Entladesperren, Einspeise-Abregelung
# Wallbox Channels
channel-type.modbus.wb-available-channel.label = Vorhanden
channel-type.modbus.wb-sunmode-channel.label = Sonnenmodus
channel-type.modbus.wb-charging-aborted-channel.label = Laden Abgebrochen
channel-type.modbus.wb-charging-channel.label = Auto lädt
channel-type.modbus.wb-jack-locked-channel.label = Ladekabel Verriegelt
channel-type.modbus.wb-jack-plugged-channel.label = Ladekabel Gesteckt
channel-type.modbus.wb-schuko-on-channel.label = Schuko-Steckdose An
channel-type.modbus.wb-schuko-plugged-channel.label = Schuko-Stecker Gesteckt
channel-type.modbus.wb-schuko-locked-channel.label = Schuko-Stecker Verriegelt
channel-type.modbus.wb-schuko-relay-16a-channel.label = Schuko-Steckdose 16A Relais An
channel-type.modbus.wb-relay-16a-channel.label = 16A Relais An
channel-type.modbus.wb-relay-32a-channel.label = 32A Relais An
channel-type.modbus.wb-1phase-channel.label = 1-phasiges Laden An
# Emergency Channels
channel-type.modbus.emergency-power-status-channel.label = Notstrom Status
channel-type.modbus.battery-charging-lock-channel.label = Batterie Laden Gesperrt
channel-type.modbus.battery-discharging-lock-channel.label = Batterie Entladen Gesperrt
channel-type.modbus.emergency-power-possible-channel.label = Notstrom Versorgung Möglich
channel-type.modbus.weather-predicted-charging-channel.label = Wetterbasiertes Laden
channel-type.modbus.regulation-status-channel.label = Einspeise Abregelung
channel-type.modbus.charge-lock-time-channel.label = Batterie Ladesperrzeiten Aktiv
channel-type.modbus.discharge-lock-time-channel.label = Batterie Entladesperrzeiten Aktiv
# Info Channels
channel-type.modbus.modbus-id-channel.label = Modbus ID
channel-type.modbus.modbus-firmware-channel.label = Modbus Firmware
channel-type.modbus.supported-registers-channel.label = Unterstützte Register
channel-type.modbus.manufacturer-name-channel.label = Hersteller
channel-type.modbus.model-name-channel.label = Modellname
channel-type.modbus.serial-number-channel.label = Seriennummer
channel-type.modbus.firmware-release-channel.label = Firmware
# Power Channels
channel-type.modbus.pv-power-supply-channel.label = Photovoltaik Leistung
channel-type.modbus.battery-power-supply-channel.label = Batterie Entladen
channel-type.modbus.battery-power-consumption-channel.label = Batterie Laden
channel-type.modbus.household-power-consumption-channel.label = Haushalt Verbrauch
channel-type.modbus.grid-power-consumption-channel.label = Stromnetz Verbrauch
channel-type.modbus.grid-power-supply-channel.label = Stromnetz Einspeisung
channel-type.modbus.external-power-supply-channel.label = Externer Stromproduzent
channel-type.modbus.wallbox-power-consumption-channel.label = Wallbox Ladestrom
channel-type.modbus.wallbox-pv-power-consumption-channel.label = Wallbox Photovoltaik Ladestrom
channel-type.modbus.autarky-channel.label = Autarkie in Prozent
channel-type.modbus.self-consumption-channel.label = Eigenverbrauch in Prozent
channel-type.modbus.battery-soc-channel.label = Batterie Ladestand in Prozent
# String Channels
channel-type.modbus.string1-dc-voltage-channel.label = String 1 Spannung
channel-type.modbus.string2-dc-voltage-channel.label = String 2 Spannung
channel-type.modbus.string3-dc-voltage-channel.label = String 3 Spannung
channel-type.modbus.string1-dc-current-channel.label = String 1 Stromstärke
channel-type.modbus.string2-dc-current-channel.label = String 2 Stromstärke
channel-type.modbus.string3-dc-current-channel.label = String 3 Stromstärke
channel-type.modbus.string1-dc-output-channel.label = String 1 Leistung
channel-type.modbus.string2-dc-output-channel.label = String 2 Leistung
channel-type.modbus.string3-dc-output-channel.label = String 3 Leistung

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<bridge-type id="e3dc">
<supported-bridge-type-refs>
<bridge-type-ref id="tcp"/>
</supported-bridge-type-refs>
<label>E3DC Home Power Plant</label>
<description>Provide Power values, String Details, Emergency Power Status and general Information of your E3DC Home
Power Plant</description>
<channel-groups>
<channel-group id="info" typeId="info-values"/>
<channel-group id="power" typeId="power-values"/>
<channel-group id="strings" typeId="string-values"/>
<channel-group id="emergency" typeId="emergency-values"/>
</channel-groups>
<config-description>
<parameter name="refresh" type="integer" min="1000" unit="ms">
<label>Refresh Interval</label>
<description>Refresh Rate of E3DC values in Milliseconds</description>
<default>2000</default>
</parameter>
</config-description>
</bridge-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<channel-group-type id="emergency-values">
<label>EMS Settings</label>
<description>Provides values of Emergency Power Status (EMS) and regulations like Battery charging / discharging
restrictions</description>
<channels>
<channel id="emergency-power-status" typeId="emergency-power-status-channel"/>
<channel id="battery-charging-lock" typeId="battery-charging-lock-channel"/>
<channel id="battery-discharging-lock" typeId="battery-discharging-lock-channel"/>
<channel id="emergency-power-possible" typeId="emergency-power-possible-channel"/>
<channel id="weather-predicted-charging" typeId="weather-predicted-charging-channel"/>
<channel id="regulation-status" typeId="regulation-status-channel"/>
<channel id="charge-lock-time" typeId="charge-lock-time-channel"/>
<channel id="discharge-lock-time" typeId="discharge-lock-time-channel"/>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<channel-type id="emergency-power-status-channel">
<item-type>String</item-type>
<label>Emergency Power Status</label>
<description>Indicates if Emergency Power Supply is possible or not, active or inactive</description>
</channel-type>
<channel-type id="battery-charging-lock-channel">
<item-type>Switch</item-type>
<label>Battery Charge Locked</label>
<description>Battery charging is locked</description>
</channel-type>
<channel-type id="battery-discharging-lock-channel">
<item-type>Switch</item-type>
<label>Battery Discharge Locked</label>
<description>Battery discharging is locked</description>
</channel-type>
<channel-type id="emergency-power-possible-channel">
<item-type>Switch</item-type>
<label>Emergency Power Possible</label>
<description>Emergency Power Supply is possible</description>
</channel-type>
<channel-type id="weather-predicted-charging-channel">
<item-type>Switch</item-type>
<label>Weather Predicted Battery Charging</label>
<description>Weather Predicted Battery Charging is activated</description>
</channel-type>
<channel-type id="regulation-status-channel">
<item-type>Switch</item-type>
<label>Grid Power Supply Regulation</label>
<description>Grid Power Supply is currently regulated</description>
</channel-type>
<channel-type id="charge-lock-time-channel">
<item-type>Switch</item-type>
<label>Charge Lock Time Active</label>
<description>Charge Lock Time is currently active</description>
</channel-type>
<channel-type id="discharge-lock-time-channel">
<item-type>Switch</item-type>
<label>Discharge Lock Time Active</label>
<description>Discharge Lock Time is currently active</description>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<channel-group-type id="info-values">
<label>Information</label>
<description>Basic Information of your E3DC Device like Model Name, Serial Number and Software Versions</description>
<channels>
<channel id="modbus-id" typeId="modbus-id-channel"/>
<channel id="modbus-firmware" typeId="modbus-firmware-channel"/>
<channel id="supported-registers" typeId="supported-registers-channel"/>
<channel id="manufacturer-name" typeId="manufacturer-name-channel"/>
<channel id="model-name" typeId="model-name-channel"/>
<channel id="serial-number" typeId="serial-number-channel"/>
<channel id="firmware-release" typeId="firmware-release-channel"/>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<channel-type id="modbus-id-channel">
<item-type>String</item-type>
<label>Modbus-ID</label>
<description>Modbus ID / Magic Byte of E3DC</description>
</channel-type>
<channel-type id="modbus-firmware-channel">
<item-type>String</item-type>
<label>Modbus Firmware</label>
<description>Version of Modbus Firmware</description>
</channel-type>
<channel-type id="supported-registers-channel">
<item-type>Number</item-type>
<label>Supported Registers</label>
<description>Number of registers supported by Modbus</description>
</channel-type>
<channel-type id="manufacturer-name-channel">
<item-type>String</item-type>
<label>Manufacturer Name</label>
<description>Name of the Device Manufacturer</description>
</channel-type>
<channel-type id="model-name-channel">
<item-type>String</item-type>
<label>Model Name</label>
<description>Name of the E3DC Model</description>
</channel-type>
<channel-type id="firmware-release-channel">
<item-type>String</item-type>
<label>Firmware Release</label>
<description>Firmware installed on this particular E3DC Device</description>
</channel-type>
<channel-type id="serial-number-channel">
<item-type>String</item-type>
<label>Serial Number</label>
<description>Serial Number of this particular E3DC Device</description>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<channel-group-type id="power-values">
<label>Power Values</label>
<description>Provides values of your attached electrical Producers (Photovoltaic, Battery, ... and Consumers
(Household, Wallbox, ...)</description>
<channels>
<channel id="pv-power-supply" typeId="pv-power-supply-channel"/>
<channel id="battery-power-supply" typeId="battery-power-supply-channel"/>
<channel id="battery-power-consumption" typeId="battery-power-consumption-channel"/>
<channel id="household-power-consumption" typeId="household-power-consumption-channel"/>
<channel id="grid-power-consumption" typeId="grid-power-consumption-channel"/>
<channel id="grid-power-supply" typeId="grid-power-supply-channel"/>
<channel id="external-power-supply" typeId="external-power-supply-channel"/>
<channel id="wallbox-power-consumption" typeId="wallbox-power-consumption-channel"/>
<channel id="wallbox-pv-power-consumption" typeId="wallbox-pv-power-consumption-channel"/>
<channel id="autarky" typeId="autarky-channel"/>
<channel id="self-consumption" typeId="self-consumption-channel"/>
<channel id="battery-soc" typeId="battery-soc-channel"/>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<channel-type id="pv-power-supply-channel">
<item-type>Number:Power</item-type>
<label>PV Output</label>
<description>Photovoltaic Power Production</description>
</channel-type>
<channel-type id="battery-power-supply-channel">
<item-type>Number:Power</item-type>
<label>Battery Discharge</label>
<description>Battery discharges and provides Power</description>
</channel-type>
<channel-type id="battery-power-consumption-channel">
<item-type>Number:Power</item-type>
<label>Battery Charge</label>
<description>Battery charges and consumes Power</description>
</channel-type>
<channel-type id="household-power-consumption-channel">
<item-type>Number:Power</item-type>
<label>Household Consumption</label>
<description>Household consuming Power</description>
</channel-type>
<channel-type id="grid-power-consumption-channel">
<item-type>Number:Power</item-type>
<label>Grid Power Consumption</label>
<description>Grid Power is needed in order to satisfy your overall Power consumption</description>
</channel-type>
<channel-type id="grid-power-supply-channel">
<item-type>Number:Power</item-type>
<label>Grid Power Supply</label>
<description>More Photovoltaic Power is produced than needed. Additional Power is provided towards the Grid</description>
</channel-type>
<channel-type id="external-power-supply-channel">
<item-type>Number:Power</item-type>
<label>External Power Supply</label>
<description>Power produced by an external device which is attached to your E3DC device</description>
</channel-type>
<channel-type id="wallbox-power-consumption-channel">
<item-type>Number:Power</item-type>
<label>Wallbox Power Consumption</label>
<description>Power consumption of attached Wallboxes</description>
</channel-type>
<channel-type id="wallbox-pv-power-consumption-channel">
<item-type>Number:Power</item-type>
<label>Wallbox PV Power Consumption</label>
<description>Photovoltaic Power consumption (PV plus Battery) of attached Wallboxes</description>
</channel-type>
<channel-type id="autarky-channel">
<item-type>Number:Dimensionless</item-type>
<label>Autarky</label>
<description>Your current Autarky Level in Percent</description>
</channel-type>
<channel-type id="self-consumption-channel">
<item-type>Number:Dimensionless</item-type>
<label>Self Consumtion</label>
<description>Your current Photovoltaic Self Consumption Level in Percent</description>
</channel-type>
<channel-type id="battery-soc-channel">
<item-type>Number:Dimensionless</item-type>
<label>Battery State Of Charge</label>
<description>Charge Level of your attached Battery in Percent</description>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<channel-group-type id="string-values">
<label>String Details</label>
<description>Provide detailed values of your attached Photovoltaic Strings. Evaluate how much Power each String
provides</description>
<channels>
<channel id="string1-dc-voltage" typeId="string1-dc-voltage-channel"/>
<channel id="string2-dc-voltage" typeId="string2-dc-voltage-channel"/>
<channel id="string3-dc-voltage" typeId="string3-dc-voltage-channel"/>
<channel id="string1-dc-current" typeId="string1-dc-current-channel"/>
<channel id="string2-dc-current" typeId="string2-dc-current-channel"/>
<channel id="string3-dc-current" typeId="string3-dc-current-channel"/>
<channel id="string1-dc-output" typeId="string1-dc-output-channel"/>
<channel id="string2-dc-output" typeId="string2-dc-output-channel"/>
<channel id="string3-dc-output" typeId="string3-dc-output-channel"/>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<channel-type id="string1-dc-voltage-channel">
<item-type>Number:ElectricPotential</item-type>
<label>String 1 Potential</label>
<description>Voltage on String 1</description>
</channel-type>
<channel-type id="string2-dc-voltage-channel">
<item-type>Number:ElectricPotential</item-type>
<label>String 2 Potential</label>
<description>Voltage on String 2</description>
</channel-type>
<channel-type id="string3-dc-voltage-channel">
<item-type>Number:ElectricPotential</item-type>
<label>String 3 Potential</label>
<description>Voltage on String 3</description>
</channel-type>
<channel-type id="string1-dc-current-channel">
<item-type>Number:ElectricCurrent</item-type>
<label>String 1 Current</label>
<description>Current on String 1</description>
</channel-type>
<channel-type id="string2-dc-current-channel">
<item-type>Number:ElectricCurrent</item-type>
<label>String 2 Current</label>
<description>Current on String 2</description>
</channel-type>
<channel-type id="string3-dc-current-channel">
<item-type>Number:ElectricCurrent</item-type>
<label>String 3 Current</label>
<description>Current on String 3</description>
</channel-type>
<channel-type id="string1-dc-output-channel">
<item-type>Number:Power</item-type>
<label>String 1 Power</label>
<description>Power produced by String 1</description>
</channel-type>
<channel-type id="string2-dc-output-channel">
<item-type>Number:Power</item-type>
<label>String 2 Power</label>
<description>Power produced by String 2</description>
</channel-type>
<channel-type id="string3-dc-output-channel">
<item-type>Number:Power</item-type>
<label>String 3 Power</label>
<description>Power produced by String 3</description>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="e3dc-wallbox">
<supported-bridge-type-refs>
<bridge-type-ref id="e3dc"/>
</supported-bridge-type-refs>
<label>E3DC Wallbox</label>
<description>Provide your Wallbox Settings. Switches like "Sunmode" or "1-Phase Charging" can be changed</description>
<channels>
<channel id="wb-available" typeId="wb-available-channel"/>
<channel id="wb-sunmode" typeId="wb-sunmode-channel"/>
<channel id="wb-charging-aborted" typeId="wb-charging-aborted-channel"/>
<channel id="wb-charging" typeId="wb-charging-channel"/>
<channel id="wb-jack-locked" typeId="wb-jack-locked-channel"/>
<channel id="wb-jack-plugged" typeId="wb-jack-plugged-channel"/>
<channel id="wb-schuko-on" typeId="wb-schuko-on-channel"/>
<channel id="wb-schuko-plugged" typeId="wb-schuko-plugged-channel"/>
<channel id="wb-schuko-locked" typeId="wb-schuko-locked-channel"/>
<channel id="wb-schuko-relay-16a" typeId="wb-schuko-relay-16a-channel"/>
<channel id="wb-relay-16a" typeId="wb-relay-16a-channel"/>
<channel id="wb-relay-32a" typeId="wb-relay-32a-channel"/>
<channel id="wb-1phase" typeId="wb-1phase-channel"/>
</channels>
<config-description>
<parameter name="wallboxId" type="integer" min="0" max="7" required="true">
<label>Wallbox ID</label>
<description>E3DC supports up to 8 Wallboxes - select a value from 0 to 7</description>
<default>0</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="modbus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<channel-type id="wb-available-channel">
<item-type>Switch</item-type>
<label>Available</label>
<description>Indicates if the Wallbox is attached. Check your Wallbox ID in offline case</description>
</channel-type>
<channel-type id="wb-sunmode-channel">
<item-type>Switch</item-type>
<label>Sun Mode</label>
<description>Activate / Deactivate Sun Mode. Off case takes Grid Power to ensure highest possible charging</description>
</channel-type>
<channel-type id="wb-charging-aborted-channel">
<item-type>Switch</item-type>
<label>Charging Aborted</label>
<description>Wallbox charging is aborted</description>
</channel-type>
<channel-type id="wb-charging-channel">
<item-type>Switch</item-type>
<label>Charging</label>
<description>Wallbox is charging</description>
</channel-type>
<channel-type id="wb-jack-locked-channel">
<item-type>Switch</item-type>
<label>Jack Locked</label>
<description>Jack is locked</description>
</channel-type>
<channel-type id="wb-jack-plugged-channel">
<item-type>Switch</item-type>
<label>Jack Plugged</label>
<description>Jack is plugged</description>
</channel-type>
<channel-type id="wb-schuko-on-channel">
<item-type>Switch</item-type>
<label>Schuko Socket On</label>
<description>If your Wallbox has an additional Schuko Socket it provides state ON or OFF</description>
</channel-type>
<channel-type id="wb-schuko-plugged-channel">
<item-type>Switch</item-type>
<label>Schuko Socket Plugged</label>
<description>If your Wallbox has an additional Schuko Socket it provides plugged state ON or OFF</description>
</channel-type>
<channel-type id="wb-schuko-locked-channel">
<item-type>Switch</item-type>
<label>Schuko Socket Locked</label>
<description>If your Wallbox has an additional Schuko Socket it provides locked state ON or OFF</description>
</channel-type>
<channel-type id="wb-schuko-relay-16a-channel">
<item-type>Switch</item-type>
<label>Schuko 16A Relay On</label>
<description>Schuko 16A Relay is ON</description>
</channel-type>
<channel-type id="wb-relay-16a-channel">
<item-type>Switch</item-type>
<label>16A Relay On</label>
<description>Wallbox 16A Relay is ON</description>
</channel-type>
<channel-type id="wb-relay-32a-channel">
<item-type>Switch</item-type>
<label>32A Relay On</label>
<description>Wallbox 32A Relay is ON</description>
</channel-type>
<channel-type id="wb-1phase-channel">
<item-type>Switch</item-type>
<label>1-Phase Charging</label>
<description>1-phase charging is activated. If OFF 3-phase charging is activated</description>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,121 @@
/**
* 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.modbus.e3dc.dto;
import static org.junit.Assert.*;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.openhab.binding.modbus.e3dc.internal.dto.EmergencyBlock;
import org.openhab.binding.modbus.e3dc.internal.dto.PowerBlock;
import org.openhab.binding.modbus.e3dc.internal.dto.StringBlock;
import org.openhab.binding.modbus.e3dc.internal.dto.WallboxArray;
import org.openhab.binding.modbus.e3dc.internal.dto.WallboxBlock;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data.DataType;
import org.openhab.binding.modbus.e3dc.internal.modbus.Parser;
import org.openhab.core.library.types.OnOffType;
/**
* The {@link DataBlockTest} Test Data Transfer Objects of frequent Data Block
*
* @author Bernd Weymann - Initial contribution
*/
public class DataBlockTest {
private Parser mc;
@Before
public void setup() {
byte[] dataBlock = new byte[] { 0, -14, 0, 0, -2, -47, -1, -1, 2, 47, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 99, 99, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
125, 2, 21, 0, 0, 0, 27, 0, 26, 0, 0, 0, 103, 0, -117, 0, 0 };
mc = new Parser(DataType.DATA);
mc.setArray(dataBlock);
}
@Test
public void testValidPowerBlock() {
Optional<Data> dataOpt = mc.parse(DataType.POWER);
assertTrue(dataOpt.isPresent());
PowerBlock b = (PowerBlock) dataOpt.get();
assertEquals("PV Supply", "242.0 W", b.pvPowerSupply.toString());
assertEquals("Grid Supply", "14.0 W", b.gridPowerSupply.toString());
assertEquals("Grid Consumption", "0.0 W", b.gridPowerConsumpition.toString());
assertEquals("Battery Supply", "303.0 W", b.batteryPowerSupply.toString());
}
@Test
public void testValidWallboxBlock() {
Optional<Data> wba = mc.parse(DataType.WALLBOX);
assertTrue(wba.isPresent());
WallboxArray a = (WallboxArray) wba.get();
assertNotNull(a);
Optional<WallboxBlock> o = a.getWallboxBlock(0);
WallboxBlock b = o.get();
assertNotNull(b);
assertEquals("Wallbox available", OnOffType.ON, b.wbAvailable);
assertEquals("Wallbox Sunmode", OnOffType.ON, b.wbSunmode);
assertEquals("Wallbox 1phase", OnOffType.OFF, b.wb1phase);
assertEquals("Wallbox charging", OnOffType.OFF, b.wbCharging);
}
@Test
public void testValidEmergency() {
Optional<Data> dataOpt = mc.parse(DataType.EMERGENCY);
assertTrue(dataOpt.isPresent());
EmergencyBlock b = (EmergencyBlock) dataOpt.get();
assertEquals("EMS Status", EmergencyBlock.EP_NOT_SUPPORTED, b.epStatus.toFullString());
assertEquals("Battery charging locked", OnOffType.OFF, b.batteryChargingLocked);
assertEquals("Battery discharging locked", OnOffType.OFF, b.batteryDischargingLocked);
assertEquals("EP possible", OnOffType.OFF, b.epPossible);
assertEquals("Weather Predicted charging", OnOffType.OFF, b.weatherPredictedCharging);
assertEquals("Regulation Status", OnOffType.OFF, b.regulationStatus);
assertEquals("Charge Lock Time", OnOffType.OFF, b.chargeLockTime);
assertEquals("Discharge Lock Time", OnOffType.OFF, b.dischargeLockTime);
}
@Test
public void testValidStringDetailsStringBlock() {
Optional<Data> dataOpt = mc.parse(DataType.STRINGS);
assertTrue(dataOpt.isPresent());
StringBlock b = (StringBlock) dataOpt.get();
assertEquals("String 1 V", 381, b.string1Volt.intValue());
assertEquals("String 1 V", "V", b.string1Volt.getUnit().toString());
assertEquals("String 2 V", 533, b.string2Volt.intValue());
assertEquals("String 1 V", "V", b.string2Volt.getUnit().toString());
assertEquals("String 3 V", 0, b.string3Volt.intValue());
assertEquals("String 1 V", "V", b.string3Volt.getUnit().toString());
assertEquals("String 1 A", 0.27, b.string1Ampere.doubleValue(), 0.01);
assertEquals("String 1 A", "A", b.string1Ampere.getUnit().toString());
assertEquals("String 2 A", 0.26, b.string2Ampere.doubleValue(), 0.01);
assertEquals("String 2 A", "A", b.string2Ampere.getUnit().toString());
assertEquals("String 3 A", 0, b.string3Ampere.doubleValue(), 0.01);
assertEquals("String 3 A", "A", b.string3Ampere.getUnit().toString());
assertEquals("String 1 W", 103, b.string1Watt.intValue());
assertEquals("String 1 W", "W", b.string1Watt.getUnit().toString());
assertEquals("String 2 W", 139, b.string2Watt.intValue());
assertEquals("String 2 W", "W", b.string2Watt.getUnit().toString());
assertEquals("String 3 W", 0, b.string3Watt.intValue());
assertEquals("String 3 W", "W", b.string3Watt.getUnit().toString());
}
@Test
public void testInvalidInfoblock() {
Optional<Data> infoOpt = mc.parse(DataType.INFO);
assertFalse(infoOpt.isPresent());
}
}

View File

@@ -0,0 +1,77 @@
/**
* 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.modbus.e3dc.dto;
import static org.junit.Assert.*;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.openhab.binding.modbus.e3dc.internal.dto.InfoBlock;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data.DataType;
import org.openhab.binding.modbus.e3dc.internal.modbus.Parser;
/**
* The {@link InfoTest} Test Data Transfer Objects of Information Block
*
* @author Bernd Weymann - Initial contribution
*/
public class InfoTest {
private Parser mc;
@Before
public void setup() {
byte[] infoBlock = new byte[] { -29, -36, 1, 2, 0, -120, 69, 51, 47, 68, 67, 32, 71, 109, 98, 72, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 49, 48, 32, 69, 32, 65, 73, 79, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 78, 73, 78, 73, 84, 73, 65, 76, 73, 90, 69, 68,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 49, 48, 95, 50, 48, 50, 48, 95, 48, 52, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
mc = new Parser(DataType.INFO);
mc.setArray(infoBlock);
}
@Test
public void testvalidInformationBlock() {
Optional<Data> infoOpt = mc.parse(DataType.INFO);
assertTrue(infoOpt.isPresent());
InfoBlock b = (InfoBlock) infoOpt.get();
assertNotNull(b);
assertEquals("MagicByte", "E3DC", b.modbusId.toString());
assertEquals("Model", "S10 E AIO", b.modelName.toString());
assertEquals("Firmware", "S10_2020_04", b.firmware.toString());
assertEquals("Manufacturer", "E3/DC GmbH", b.manufacturer.toString());
}
@Test
public void testWrongQuery() {
Optional<Data> dataOpt = mc.parse(DataType.POWER);
assertFalse(dataOpt.isPresent());
}
@Test
public void testInvalidBlockSize() {
byte[] infoBlock = new byte[] { -29, -36, 1, 2, 0, -120, 69, 51, 47, 68, 67, 32, 71, 109, 98, 72, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 49, 48, 32, 69, 32, 65, 73, 79, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 78, 73, 78, 73, 84, 73, 65, 76, 73, 90, 69, 68,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 49, 48, 95, 50, 48, 50, 48, 95, 48 };
Parser mc = new Parser(DataType.INFO);
mc.setArray(infoBlock);
Optional<Data> infoOpt = mc.parse(DataType.INFO);
InfoBlock b = (InfoBlock) infoOpt.get();
// block still valid but data maybe corrupted => logged in warnings
assertTrue(infoOpt.isPresent());
assertNotNull(b);
}
}

View File

@@ -0,0 +1,121 @@
/**
* 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.modbus.e3dc.internal.handler;
import static org.mockito.Mockito.*;
import java.nio.ByteBuffer;
import java.util.HashMap;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.mockito.ArgumentMatchers;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandlerCallback;
import org.openhab.io.transport.modbus.AsyncModbusFailure;
import org.openhab.io.transport.modbus.AsyncModbusReadResult;
import org.openhab.io.transport.modbus.ModbusReadRequestBlueprint;
import org.openhab.io.transport.modbus.ModbusRegister;
import org.openhab.io.transport.modbus.ModbusRegisterArray;
/**
* The {@link E3DCHandlerStateTest} Test State handling of Handler if different results occurs
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class E3DCHandlerStateTest {
ThingStatusInfo unknownStatus = new ThingStatusInfo(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, null);
ThingStatusInfo onlineStatus = new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
ThingStatusInfo offlineStatus = new ThingStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
E3DCThingHandler.DATA_READ_ERROR);
@Test
public void testStatusChain() {
Bridge bridge = mock(Bridge.class);
ThingUID uid = new ThingUID("modbus", "e3dc", "powerplant");
when(bridge.getUID()).thenReturn(uid);
ThingHandlerCallback callback = mock(ThingHandlerCallback.class);
E3DCThingHandler handler = new E3DCThingHandler(bridge);
handler.setCallback(callback);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("refresh", 2000);
Configuration config = new Configuration(map);
when(bridge.getConfiguration()).thenReturn(config);
handler.initialize();
verify(callback).statusUpdated(ArgumentMatchers.eq((Thing) bridge), ArgumentMatchers.eq(unknownStatus));
// Initializing is ongoing - now simulate info and data callback
handler.handleInfoResult(getInfoResult());
verify(callback).statusUpdated(ArgumentMatchers.eq((Thing) bridge), ArgumentMatchers.eq(unknownStatus));
handler.handleDataResult(getDataResult());
verify(callback, times(1)).statusUpdated(ArgumentMatchers.eq((Thing) bridge),
ArgumentMatchers.eq(onlineStatus));
// we are ONLINE!
// call it a few times - ensure at the end of the test that "ONLINE" status is raised only 2 times and not all
// the time
handler.handleDataResult(getDataResult());
handler.handleDataResult(getDataResult());
handler.handleDataResult(getDataResult());
// simulate one wrong data result
handler.handleDataFailure(getFailResult());
verify(callback).statusUpdated(ArgumentMatchers.eq((Thing) bridge), ArgumentMatchers.eq(offlineStatus));
// // go online again
handler.handleDataResult(getDataResult());
verify(callback, times(2)).statusUpdated(ArgumentMatchers.eq((Thing) bridge),
ArgumentMatchers.eq(onlineStatus));
}
private AsyncModbusReadResult getInfoResult() {
byte[] infoBlockBytes = new byte[] { -29, -36, 1, 2, 0, -120, 69, 51, 47, 68, 67, 32, 71, 109, 98, 72, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 49, 48, 32, 69, 32, 65, 73, 79, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 78, 73, 78, 73, 84, 73, 65, 76, 73, 90, 69,
68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 49, 48, 95, 50, 48, 50, 48, 95, 48, 52,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
ByteBuffer infoWrap = ByteBuffer.wrap(infoBlockBytes);
ModbusRegister[] infoBlock = new ModbusRegister[infoBlockBytes.length / 2];
for (int i = 0; i < infoBlock.length; i++) {
infoBlock[i] = new ModbusRegister(infoWrap.get(), infoWrap.get());
}
ModbusReadRequestBlueprint readRequest = mock(ModbusReadRequestBlueprint.class);
return new AsyncModbusReadResult(readRequest, new ModbusRegisterArray(infoBlock));
}
private AsyncModbusReadResult getDataResult() {
byte[] dataBlockBytes = new byte[] { 0, -14, 0, 0, -2, -47, -1, -1, 2, 47, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 99, 99, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 125, 2, 21, 0, 0, 0, 27, 0, 26, 0, 0, 0, 103, 0, -117, 0, 0 };
ByteBuffer dataWrap = ByteBuffer.wrap(dataBlockBytes);
ModbusRegister[] dataBlock = new ModbusRegister[dataBlockBytes.length / 2];
for (int i = 0; i < dataBlock.length; i++) {
dataBlock[i] = new ModbusRegister(dataWrap.get(), dataWrap.get());
}
ModbusReadRequestBlueprint readRequest = mock(ModbusReadRequestBlueprint.class);
return new AsyncModbusReadResult(readRequest, new ModbusRegisterArray(dataBlock));
}
private AsyncModbusFailure<ModbusReadRequestBlueprint> getFailResult() {
ModbusReadRequestBlueprint readRequest = mock(ModbusReadRequestBlueprint.class);
return new AsyncModbusFailure<ModbusReadRequestBlueprint>(readRequest, new Exception("Something failed!"));
}
}

View File

@@ -0,0 +1,40 @@
/**
* 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.modbus.e3dc.modbus;
import static org.junit.Assert.assertEquals;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.modbus.e3dc.internal.modbus.Data.DataType;
import org.openhab.binding.modbus.e3dc.internal.modbus.Parser;
/**
* The {@link ParserNameTest} Tests for ModbusCallbacks
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class ParserNameTest {
@Test
public void testDebugNames() {
Parser mcInfo = new Parser(DataType.INFO);
assertEquals("Debug Name Info", "org.openhab.binding.modbus.e3dc.internal.modbus.Parser:INFO",
mcInfo.toString());
Parser mcPower = new Parser(DataType.DATA);
assertEquals("Debug Name Power", "org.openhab.binding.modbus.e3dc.internal.modbus.Parser:DATA",
mcPower.toString());
}
}

View File

@@ -0,0 +1,61 @@
/**
* 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.modbus.e3dc.util;
import static org.junit.Assert.assertEquals;
import java.nio.ByteBuffer;
import java.util.BitSet;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.modbus.e3dc.internal.dto.DataConverter;
/**
* The {@link DataConverterTest} Test data conversions
*
* @author Bernd Weymann - Initial contribution
*/
@NonNullByDefault
public class DataConverterTest {
@Test
public void testE3DCSwapValueNegative() {
// Reg 69 value 65098 bytes [-2, 74]
// Reg 70 value 65535 bytes [-1, -1]
byte[] b = new byte[] { -2, -74, -1, -1 };
assertEquals("Negative Value", -330, DataConverter.getInt32Swap(ByteBuffer.wrap(b)));
}
@Test
public void testBitset() {
byte[] b = new byte[] { 3, 16 };
BitSet s = BitSet.valueOf(b);
assertEquals("Bit0", true, s.get(0));
assertEquals("Bit1", true, s.get(1));
assertEquals("Bit2", false, s.get(2));
assertEquals("Bit3", false, s.get(3));
assertEquals("Bit4", false, s.get(4));
assertEquals("Bit5", false, s.get(5));
assertEquals("Bit6", false, s.get(6));
assertEquals("Bit7", false, s.get(7));
assertEquals("Bit8", false, s.get(8));
assertEquals("Bit9", false, s.get(9));
assertEquals("Bit10", false, s.get(10));
assertEquals("Bit11", false, s.get(11));
assertEquals("Bit12", true, s.get(12));
assertEquals("Bit13", false, s.get(13));
assertEquals("Bit14", false, s.get(14));
assertEquals("Bit15", false, s.get(15));
}
}