[kostalinverter] Add Second Generation (Piko10-20) type inverters (#8574)

* Binding redesigned 20200923 by Örjan Backsell

Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>


This is the upgraded version of Kostal Inverter extended with
functionality for the Inverter type of Second generation PIKO 10-20
[kostalinverter], regarded OH3.
[WIP]

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20200923 by Örjan Backsell

Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>


This is the upgraded version of Kostal Inverter extended with
functionality for the Inverter type of Second generation PIKO 10-20
[kostalinverter] regarded oH3
[WIP]

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20200923 by Örjan Backsell

Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>


This is the upgraded version of Kostal Inverter extended with
functionality for the Inverter type of Second generation PIKO 10-20
[kostalinverter] regarded oH3
[WIP]

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20200923 by Örjan Backsell

Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>


This is the upgraded version of Kostal Inverter extended with
functionality for the Inverter type of Second generation PIKO 10-20
[kostalinverter] regarded oH3
[WIP]

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20200924 by Örjan Backsell

Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>


This is the upgraded version of Kostal Inverter extended with
functionality for the Inverter type of Second generation PIKO 10-20
[kostalinverter] regarded oH3
[WIP]

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20200924 by Örjan Backsell

Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>

Changes made in
org.openhab.binding.internal.kostal.inverter.secondgeneration.SecondGenerationHandler.java
found by Travis tests.

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201007 by Örjan Backsell

Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>

Done changes in:
Channels.xml
PIKO1020.xml
README.md
SecondGeneration.xml
SecondGenerationChannelConfiguration.java

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201008 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201012 by Örjan Backsell, regarded to @fwolter
requested changes

Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>
Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201028 by Örjan Backsell, regarded to @cpmeister
requested changes.

Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>
Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201105 by Örjan Backsell

Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>
Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20200923 by Örjan Backsell

'
Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>
'
Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201111 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201117 by Örjan Backsell

'
Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>


This is the upgraded version of Kostal Inverter extended with
functionality for the Inverter type of Second generation PIKO 10-20
[kostalinverter]
[WIP]
'

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201119 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201125 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201130 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201130, 1630 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201202 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201204 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Redesigned 20201204 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20201010 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20210112 by Örjan Backsell

'
Signed-off-by: basse04 orjan.backsell@gmail.com
Also-by: Christian Schneider <>
Also-by: René Stakemeier <>
Also-by: Christoph Weitkamp <>

This is the upgraded version of Kostal Inverter extended with
functionality for the Inverter type of Second generation PIKO 10-20
[kostalinverter]
'

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20210114 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20210119 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding (KostalInverterFactory.java)redesigned 20210119 by Örjan
Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20210125 by Örjan Backsell

* Binding redesigned 20200923 by Örjan Backsell

(KostalInverterFactory.java)

Signed-off-by: basse04 <orjan.backsell@gmail.com>

* Binding redesigned 20210125 by Örjan Backsell

Signed-off-by: basse04 <orjan.backsell@gmail.com>
This commit is contained in:
basse04 2021-02-04 23:17:04 +01:00 committed by GitHub
parent 6878384df9
commit 9498590edb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1693 additions and 4 deletions

View File

@ -4,13 +4,19 @@ Scrapes the web interface of the inverter for the metrics of the supported chann
![Kostal Pico](doc/kostalpico.jpg)
![Kostal Piko 10-20](doc/kostalpiko10_20.jpg)
![Kostal PLENTICORE / PIKI IQ](doc/plenticore.jpg)
## Supported Things
### First generation devices (PIKO)
Tested with Kostal Inverter PIKO but might work with other inverters from kostal too.
Tested with Kostal Inverter PIKO but might work with other inverters from Kostal too.
### Second generation devices (PIKO 10-20, PIKO NEW GENERATION)
Tested with Kostal Inverter PIKO 10-20, PIKO NEW GENERATION.
### Third generation devices (PIKO IQ / PLENTICORE plus)
@ -59,6 +65,78 @@ None
- l3Voltage
- l3Power
### Second generation devices (PIKO 10-20, PIKO NEW GENERATION)
| Channel Type ID | Item Type | Description | Read Write |
|------------------------------------------|--------------------------|----------------------------------------------------------------------------------|:----------:|
| device-local-grid-output-power | Number:Power | Current output power to the grid | R |
| statistic-yield-day-second-gen | Number:Energy | Total produced power today | R |
| statistic-yield-total-second-gen | Number:Energy | Total produced power | R |
| device-local-operating-status | Number:Dimensionless | Current operating status, 0 = Standby, 3 = WO-IDLE | R |
| device-local-grid-voltage-l1 | Number:ElectricPotential | Current output voltage to the grid, L1 | R |
| device-local-grid-current-l1 | Number:ElectricCurrent | Current output current to the grid, L1 | R |
| device-local-grid-power-l1 | Number:Power | Current output power to the grid, L1 | R |
| device-local-grid-voltage-l2 | Number:ElectricPotential | Current output voltage to the grid, L2 | R |
| device-local-grid-current-l2 | Number:ElectricCurrent | Current output current to the grid, L2 | R |
| device-local-grid-power-l2 | Number:Power | Current output power to the grid, L2 | R |
| device-local-grid-voltage-l3 | Number:ElectricPotential | Current output voltage to the grid, L3 | R |
| device-local-grid-current-l3 | Number:ElectricCurrent | Current output current to the grid, L3 | R |
| device-local-grid-power-l3 | Number:Power | Current output power to the grid, L3 | R |
| device-local-dc-power-pv | Number:Power | Current power from all solar panels | R |
| device-local-dc1-voltage | Number:ElectricPotential | Current voltage from solar panels, Dc1 | R |
| device-local-dc1-current | Number:ElectricCurrent | Current current from solar panels, Dc1 | R |
| device-local-dc1-power | Number:Power | Current power from solar panels, Dc1 | R |
| device-local-dc2-voltage | Number:ElectricPotential | Current voltage from solar panels, Dc2 | R |
| device-local-dc2-current | Number:ElectricCurrent | Current current from solar panels, Dc2 | R |
| device-local-dc2-power | Number:Power | Current power from solar panels, Dc2 | R |
| device-local-dc3-voltage | Number:ElectricPotential | Current voltage from solar panels, Dc3 | R |
| device-local-dc3-current | Number:ElectricCurrent | Current current from solar panels, Dc3 | R |
| device-local-dc3-power | Number:Power | Current power from solar panels, Dc3 | R |
| device-local-akt-home-consumption-solar | Number:Power | Current consumption from solar panels | R |
| device-local-akt-home-consumption-bat | Number:Power | Current consumption from battery | R |
| device-local-akt-home-consumption-grid | Number:Power | Current consumption from grid | R |
| device-local-phase-sel-home-consump-l1 | Number:Power | Current home consumption, L1 | R |
| device-local-phase-sel-home-consump-l2 | Number:Power | Current home consumption, L2 | R |
| device-local-phase-sel-home-consump-l3 | Number:Power | Current home consumption, L3 | R |
| device-local-grid-freq | Number:Frequency | Current frequency on grid | R |
| device-local-grid-cos-phi | Number:Angle | Current power factor on grid | R |
| statistic-home-consumption-day | Number:Energy | Total home consumption today | R |
| statistic-own-consumption-day | Number:Energy | Total own consumption today | R |
| statistic-own-cons-rate-day | Number:Dimensionless | Total own consumption rate today | R |
| statistic-autonomy-degree-day | Number:Dimensionless | Total autonomy degree today | R |
| statistic-home-consumption-total | Number:Energy | Total home consumption | R |
| statistic-own-consumption-total | Number:Energy | Total own consumption | R |
| statistic-operating-time-total | Number:Time | Total operating time | R |
| device-local-current | Number:ElectricCurrent | Current | R |
| device-local-current-dir | Number:Dimensionless | Current direction of loading/unloading the battery | R |
| device-local-charge-cycles | Number:Dimensionless | Total number of charge cycles | R |
| device-local-battery-temperature | Number:Temperature | Battery current temperature | R |
| device-local-loginterval | Number:Time | Value for loginterval | R |
| device-local-s0-inpulse-cnt | Number:Dimensionless | S0-pulse counter | R |
| statistic-own-cons-rate-total | Number:Dimensionless | Total own comsumption rate | R |
| statistic-autonomy-degree-total | Number:Dimensionless | Total autonomy degree | R |
| device-local-battery-voltage | Number:ElectricPotential | Battery current voltage | R |
| device-local-bat-state-of-charge | Number:Dimensionless | Battery current charge state | R |
| device-local-self-consumption | Number:Power | Current self consumption | R |
| device-local-battery-usage-consumption | Number:Power | Battery usage consumption | R |
| device-local-smart-battery-control | Switch | Smart battery control | R |
| device-local-shadow-management | Number:Dimensionless | Shadow management | R |
| device-local-external-module-control | Number:Dimensionless | External module control | R |
The following Channels are writeable
| Channel Type ID | Item Type | Description | Read Write |
|------------------------------------------|--------------------------|----------------------------------------------------------------------------------|:----------:|
| device-local-battery-usage-consumption-set| String | Battery usage consumption level for power-consumption from battery, value = 100 (W) | W |
| device-local-battery-usage-strategy-set | String | Battery usage strategy, Value = 1 = Automatic, Value = 2 = Automatic economical | W |
| device-local-smart-battery-control-set | Switch | Smart battery control, Value = OFF / ON | W |
| device-local-battery-charge-time-from-set| String | Battery charge time from, Value = 00:00 | W |
| device-local-battery-charge-time-to-set | String | Battery charge time to, Value = 23:59 | W |
| device-local-max-depth-of-discharge-set | String | Max depth of discharge (SoC), Value = 10 | W |
| device-local-shadow-management-set | String | Shadow management, Value = 0 = No shadow management enabled, Value = 1 = Shadow management enabled for DC-Input String 1, Value = 2 = Shadow management enabled for DC-Input String 2, Value = 3 = Shadow management enabled for DC-Input String 1 and 2 | W |
| device-local-external-module-control-set | String | External module control, Value = 0 = Not Activated, Value = 1 = Activated | W |
### Third generation devices (PIKO IQ / PLENTICORE plus)
| Channel Type ID | Item Type | Description | Read Write |
@ -148,6 +226,31 @@ If the thing goes online then the connection to the web interface is successful.
In case it is offline you should see an error message.
You optionally can define a `userName` and a `password` parameter if the access to the webinterface is protected and a desired `refreshInterval` (the time interval between updates, default 60 seconds).
### Second generation devices (PIKO 10-20, PIKO NEW GENERATION)
Second generation inverters require 5 mandatory parameters:
| Parameter | Description | Type | Unit | Default value | Example value |
|--------------------------|--------------------------------------------------------|---------|---------|---------------|---------------|
| url | Host name or IP address of your device | Text | --- | --- | 192.168.0.2 |
| username | Username for your inverter | Text | --- | --- | myUsername |
| password | Password for your inverter | Text | --- | --- | myPassword |
| refreshInterval | Pollingintervall of your inverter | Integer | Seconds | 60 | 60 |
| hasBattery | Type of PIKO 10-20 inverter, with or without battery | boolean | --- | -- | false/true |
demo.things
```
Thing kostalinverter:piko1020:mypiko1020 [ url="http://'inverter-ip'", username="'myUsername'", password="'myPassword'", refreshInterval=60, hasBattery=false]
```
You can define which type of PIKO10-20 inverter you will connect to with parameter hasBattery.
### Third generation devices (PIKO IQ / PLENTICORE plus)
All third generation inverters require to define 3 mandatory configuration parameters:
@ -182,11 +285,76 @@ Number:Energy SolarTotalEnergy "Solar total energy [%.3f %unit%]" <energy> { cha
String SolarStatus "Solar status [%s]" <energy> { channel="kostalinverter:kostalinverter:inverter:status" }
```
### Second generation devices (PIKO NEW GENERATION)
demo.items:
```
Number:Power GridOutputPower "PV Output Power" <energy> { channel="kostalinverter:piko1020:mypiko1020:gridOutputPower" }
Number:Energy YieldDaySecondGen "PV Output Power Day" <energy> { channel="kostalinverter:piko1020:mypiko1020:yieldDaySecondGen" }
Number:Energy YieldTotalSecondGen "PV Output Power Total" <energy> { channel="kostalinverter:piko1020:mypiko1020:yieldTotalSecondgen" }
Number:Dimensionless OperatingStatus "Operating Status" <energy> { channel="kostalinverter:piko1020:mypiko1020:operatingStatus" }
Number:ElectricPotential GridVoltageL1 "Grid Voltage L1" <energy> { channel="kostalinverter:piko1020:mypiko1020:gridVoltageL1" }
Number:ElectricCurrent GridCurrentL1 "Grid Current L1" <energy> { channel="kostalinverter:piko1020:mypiko1020:gridCurrentL1" }
Number:Power GridPowerL1 "Grid Power L1" <energy> { channel="kostalinverter:piko1020:mypiko1020:gridPowerL1" }
Number:ElectricPotential GridVoltageL2 "Grid Voltage L2" <energy> { channel="kostalinverter:piko1020:mypiko1020:gridVoltageL2" }
Number:ElectricCurrent GridCurrentL2 "Grid Current L2" <energy> { channel="kostalinverter:piko1020:mypiko1020:gridCurrentL2" }
Number:Power GridPowerL2 "Grid Power L2" <energy> { channel="kostalinverter:piko1020:mypiko1020:gridPowerL2" }
Number:ElectricPotential GridVoltageL3 "Grid Voltage L3" <energy> { channel="kostalinverter:piko1020:mypiko1020:gridVoltageL3" }
Number:ElectricCurrent GridCurrentL3 "Grid Current L3" <energy> { channel="kostalinverter:piko1020:mypiko1020:gridCurrentL3" }
Number:Power GridPowerL3 "Grid Power L3" <energy> { channel="kostalinverter:piko1020:mypiko1020:gridPowerL3" }
Number:Power DcPvPower "DC Power Pv" <energy> { channel="kostalinverter:piko1020:mypiko1020:dcPowerPV" }
Number:ElectricPotential Dc1Voltage "DC1 Voltage" <energy> { channel="kostalinverter:piko1020:mypiko1020:dc1Voltage" }
Number:ElectricCurrent Dc1Current "DC1 Current" <energy> { channel="kostalinverter:piko1020:mypiko1020:dc1Current" }
Number:Power Dc1Power "DC1 Power" <energy> { channel="kostalinverter:piko1020:mypiko1020:dc1Power" }
Number:ElectricPotential Dc2Voltage "DC2 Voltage" <energy> { channel="kostalinverter:piko1020:mypiko1020:dc2Voltage" }
Number:ElectricCurrent Dc2Current "DC2 Current" <energy> { channel="kostalinverter:piko1020:mypiko1020:dc2Current" }
Number:Power Dc2Power "DC2 Power" <energy> { channel="kostalinverter:piko1020:mypiko1020:dc2Power" }
Number:ElectricPotential Dc3Voltage "DC3 Voltage" <energy> { channel="kostalinverter:piko1020:mypiko1020:dc3Voltage" }
Number:ElectricCurrent Dc3Current "DC3 Current" <energy> { channel="kostalinverter:piko1020:mypiko1020:dc3Current" }
Number:Power Dc3Power "DC3 Power" <energy> { channel="kostalinverter:piko1020:mypiko1020:dc3Power" }
Number:Power AktHomeConsumptionSolar "Akt Home Consumption Solar" <energy> { channel="kostalinverter:piko1020:mypiko1020:aktHomeConsumptionSolar" }
Number:Power AktHomeConsumptionBat "Akt Home Consumption Battery" <energy> { channel="kostalinverter:piko1020:mypiko1020:aktHomeConsumptionBat" }
Number:Power AktHomeConsumptionGrid "Akt Home Consumption Grid" <energy> { channel="kostalinverter:piko1020:mypiko1020:aktHomeConsumptionGrid" }
Number:Power PhaseSelHomeConsumpL1 "Phase Sel Home Consump L1" <energy> { channel="kostalinverter:piko1020:mypiko1020:phaseSelHomeConsumpL1" }
Number:Power PhaseSelHomeConsumpL2 "Phase Sel Home Consump L2" <energy> { channel="kostalinverter:piko1020:mypiko1020:phaseSelHomeConsumpL2" }
Number:Power PhaseSelHomeConsumpL3 "Phase Sel Home Consump L3" <energy> { channel="kostalinverter:piko1020:mypiko1020:phaseSelHomeConsumpL3" }
Number:Frequency GridFreq "Grid Freq" <energy> { channel="kostalinverter:piko1020:mypiko1020:gridFreq" }
Number:Angle GridCosPhi "Grid Cos Phi" <energy> { channel="kostalinverter:piko1020:mypiko1020:gridCosPhi" }
Number:Energy HomeConsumptionDay "Home Consumption Day" <energy> { channel="kostalinverter:piko1020:mypiko1020:homeConsumptionDay" }
Number:Energy OwnConsumptionDay "Own Consumption Day" <energy> { channel="kostalinverter:piko1020:mypiko1020:ownConsumptionDay" }
Number:Dimensionless OwnConsRateDay "Own Cons Rate Day <energy> { channel="kostalinverter:piko1020:mypiko1020:ownConsRateDay" }
Number:Dimensionless AutonomyDegreeDay "Autonomy Degree Day" <energy> { channel="kostalinverter:piko1020:mypiko1020:autonomyDegreeDay" }
Number:Energy HomeConsumptionTotal "Home Consumption Total" <energy> { channel="kostalinverter:piko1020:mypiko1020:homeConsumptionTotal" }
Number:Energy OwnConsumptionTotal "Own Consumption Total" <energy> { channel="kostalinverter:piko1020:mypiko1020:ownConsumptionTotal" }
Number:Time OperatingTimeTotal "Operating Time Total" <energy> { channel="kostalinverter:piko1020:mypiko1020:operatingTimeTotal" }
Number:ElectricCurrent Current "Current" <energy> { channel="kostalinverter:piko1020:mypiko1020:current" }
Number:Dimensionless CurrentDir "Current Dir" <energy> { channel="kostalinverter:piko1020:mypiko1020:currentDir" }
Number:Dimensionless ChargeCycles "Charge Cycles" <energy> { channel="kostalinverter:piko1020:mypiko1020:chargeCycles" }
Number:Temperature BatteryTemperature "BatteryTemperature" <energy> { channel="kostalinverter:piko1020:mypiko1020:batteryTemperature" }
Number:Time Loginterval "Log Interval" <energy> { channel="kostalinverter:piko1020:mypiko1020:loginterval" }
Number:Dimensionless S0InPulseCnt "S0 InPulse Cnt" <energy> { channel="kostalinverter:piko1020:mypiko1020:s0InPulseCnt" }
Number:Dimensionless OwnConsRateTotal "Own Cons Rate Total" <energy> { channel="kostalinverter:piko1020:mypiko1020:ownConsRateTotal" }
Number:Dimensionless AutonomyDegreeTotal "Autonomy Degree Total" <energy> { channel="kostalinverter:piko1020:mypiko1020:autonomyDegreeTotal" }
Number:ElectricPotential BatteryVoltage "Battery Voltage" <energy> { channel="kostalinverter:piko1020:mypiko1020:batteryVoltage" }
Number:Dimensionless BatStateOfCharge "Bat State Of Charge" <energy> { channel="kostalinverter:piko1020:mypiko1020:batStateOfCharge" }
Number:Power SelfConsumption "Self Consumption" <energy> { channel="kostalinverter:piko1020:mypiko1020:selfConsumption" }
Number:Dimensionless BatteryUsageConsumption "Battery Usage Consumption" <energy> { channel="kostalinverter:piko1020:mypiko1020:batteryUsageConsumption" }
Switch SmartBatteryControl "Smart Battery Control" <energy> { channel="kostalinverter:piko1020:mypiko1020:smartBatteryControl" }
Number:Dimensionless MaxDepthOfDischarge "Max Depth Of Discharge" <energy> { channel="kostalinverter:piko1020:mypiko1020:maxDepthOfDischarge" }
Number:Dimensionless ShadowManagement "Shadow Management" <energy> { channel="kostalinverter:piko1020:mypiko1020:shadowManagement" }
Number:Dimensionless ExternalModuleControl "External Module Control" <energy> { channel="kostalinverter:piko1020:mypiko1020:externalModuleControl" }
```
### Third generation devices (PIKO IQ / PLENTICORE plus)
demo.items:
```
Number:Energy MyPlentiCore100WithBattery_DEVICE_LOCAL_DC_POWER <energy> { channel="kostalinverter:PLENTICOREPLUS100WITHBATTERY:MyPlentiCore100WithBattery:deviceLocalDCPower"}
Number:Energy MyPlentiCore100WithBattery_DEVICE_LOCAL_HOMECONSUMPTION_FROM_BATTERY <energy> { channel="kostalinverter:PLENTICOREPLUS100WITHBATTERY:MyPlentiCore100WithBattery:deviceLocalHomeconsumptionFromBattery"}
Number:Energy MyPlentiCore100WithBattery_DEVICE_LOCAL_HOMECONSUMPTION_FROM_GRID <energy> { channel="kostalinverter:PLENTICOREPLUS100WITHBATTERY:MyPlentiCore100WithBattery:deviceLocalHomeconsumptionFromGrid"}
@ -256,3 +424,28 @@ Number:Energy MyPlentiCore100WithBattery_STATISTIC_YIELD_TOTAL
Number:Energy MyPlentiCore100WithBattery_STATISTIC_YIELD_YEAR <energy> { channel="kostalinverter:PLENTICOREPLUS100WITHBATTERY:MyPlentiCore100WithBattery:statisticYieldYear"}
```
### Rules
Second generation devices (PIKO 10-20, PIKO NEW GENERATION)
```
Ex. Set Smart battery control OFF with cron trigger:
triggers:
id: "1"
configuration:
cronExpression: 0 0/2 * * * ? *
type: timer.GenericCronTrigger
conditions: []
actions:
inputs: {}
id: "2"
configuration:
type: application/vnd.openhab.dsl.rule
script: KOSTALPIKO1020_SmartBatteryControlSet.sendCommand("OFF")
type: script.ScriptAction

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -21,6 +21,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.kostalinverter.internal.firstgeneration.WebscrapeHandler;
import org.openhab.binding.kostalinverter.internal.secondgeneration.SecondGenerationHandler;
import org.openhab.binding.kostalinverter.internal.thirdgeneration.ThirdGenerationHandler;
import org.openhab.binding.kostalinverter.internal.thirdgeneration.ThirdGenerationInverterTypes;
import org.openhab.core.io.net.http.HttpClientFactory;
@ -36,6 +37,7 @@ import org.osgi.service.component.annotations.Reference;
/**
* @author Christian Schneider - Initial contribution (as WebscrapeHandlerFactory.java)
* @author René Stakemeier - extension for the third generation of KOSTAL inverters
* @author Örjan Backsell - extension for the second generation of KOSTAL inverters
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.kostalinverter")
@NonNullByDefault
@ -72,6 +74,8 @@ public class KostalInverterFactory extends BaseThingHandlerFactory {
public static final ThingTypeUID FIRST_GENERATION_INVERTER = new ThingTypeUID("kostalinverter", "kostalinverter");
public static final ThingTypeUID SECOND_GENERATION_INVERTER = new ThingTypeUID("kostalinverter", "piko1020");
private final HttpClient httpClient;
@Activate
@ -81,7 +85,7 @@ public class KostalInverterFactory extends BaseThingHandlerFactory {
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return thingTypeUID.equals(FIRST_GENERATION_INVERTER)
return thingTypeUID.equals(FIRST_GENERATION_INVERTER) || thingTypeUID.equals(SECOND_GENERATION_INVERTER)
|| SUPPORTED_THIRD_GENERATION_THING_TYPES_UIDS.keySet().contains(thingTypeUID);
}
@ -91,6 +95,10 @@ public class KostalInverterFactory extends BaseThingHandlerFactory {
if (FIRST_GENERATION_INVERTER.equals(thing.getThingTypeUID())) {
return new WebscrapeHandler(thing);
}
// second generation
if (SECOND_GENERATION_INVERTER.equals(thing.getThingTypeUID())) {
return new SecondGenerationHandler(thing, httpClient);
}
// third generation
ThirdGenerationInverterTypes inverterType = SUPPORTED_THIRD_GENERATION_THING_TYPES_UIDS
.get(thing.getThingTypeUID());

View File

@ -0,0 +1,100 @@
/**
* Copyright (c) 2010-2021 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.kostalinverter.internal.secondgeneration;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link SecondGenerationBindingConstants} class defines channel constants, which are
* used in the second generation part of the binding.
*
* @author Örjan Backsell - Initial contribution Piko1020, Piko New Generation
*/
@NonNullByDefault
public class SecondGenerationBindingConstants {
private static final String BINDING_ID = "kostalinverter";
// List of all Thing Type UIDs
public static final ThingTypeUID SECOND_GENERATION_INVERTER = new ThingTypeUID(BINDING_ID, "piko1020");
// List of all Channel ids
public static final String CHANNEL_GRIDOUTPUTPOWER = "gridOutputPower";
public static final String CHANNEL_YIELD_DAY_SECOND_GEN = "yieldDaySecondGen";
public static final String CHANNEL_YIELD_TOTAL_SECOND_GEN = "yieldTotalSecondGen";
public static final String CHANNEL_OPERATING_STATUS = "operatingStatus";
public static final String CHANNEL_GRIDVOLTAGEL1 = "gridVoltageL1";
public static final String CHANNEL_GRIDCURRENTL1 = "gridCurrentL1";
public static final String CHANNEL_GRIDPOWERL1 = "gridPowerL1";
public static final String CHANNEL_GRIDVOLTAGEL2 = "gridVoltageL2";
public static final String CHANNEL_GRIDCURRENTL2 = "gridCurrentL2";
public static final String CHANNEL_GRIDPOWERL2 = "gridPowerL2";
public static final String CHANNEL_GRIDVOLTAGEL3 = "gridVoltageL3";
public static final String CHANNEL_GRIDCURRENTL3 = "gridCurrentL3";
public static final String CHANNEL_GRIDPOWERL3 = "gridPowerL3";
public static final String CHANNEL_DCPOWERPV = "dcPowerPV";
public static final String CHANNEL_DC1VOLTAGE = "dc1Voltage";
public static final String CHANNEL_DC1CURRENT = "dc1Current";
public static final String CHANNEL_DC1POWER = "dc1Power";
public static final String CHANNEL_DC2VOLTAGE = "dc2Voltage";
public static final String CHANNEL_DC2CURRENT = "dc2Current";
public static final String CHANNEL_DC2POWER = "dc2Power";
public static final String CHANNEL_DC3VOLTAGE = "dc3Voltage";
public static final String CHANNEL_DC3CURRENT = "dc3Current";
public static final String CHANNEL_DC3POWER = "dc3Power";
public static final String CHANNEL_AKTHOMECONSUMTIONSOLAR = "aktHomeConsumptionSolar";
public static final String CHANNEL_AKTHOMECONSUMPTIONBAT = "aktHomeConsumptionBat";
public static final String CHANNEL_AKTHOMECONSUMPTIONGRID = "aktHomeConsumptionGrid";
public static final String CHANNEL_PHASESELHOMECONSUMPL1 = "phaseSelHomeConsumpL1";
public static final String CHANNEL_PHASESELHOMECONSUMPL2 = "phaseSelHomeConsumpL2";
public static final String CHANNEL_PHASESELHOMECONSUMPL3 = "phaseSelHomeConsumpL3";
public static final String CHANNEL_GRIDFREQ = "gridFreq";
public static final String CHANNEL_GRIDCOSPHI = "gridCosPhi";
public static final String CHANNEL_HOMECONSUMPTION_DAY = "homeConsumptionDay";
public static final String CHANNEL_OWNCONSUMPTION_DAY = "ownConsumptionDay";
public static final String CHANNEL_OWNCONSRATE_DAY = "ownConsRateDay";
public static final String CHANNEL_AUTONOMYDEGREE_DAY = "autonomyDegreeDay";
public static final String CHANNEL_HOMECONSUMPTION_TOTAL = "homeConsumptionTotal";
public static final String CHANNEL_OWNCONSUMPTION_TOTAL = "ownConsumptionTotal";
public static final String CHANNEL_OPERATINGTIME_TOTAL = "operatingTimeTotal";
public static final String CHANNEL_CURRENT = "current";
public static final String CHANNEL_CURRENTDIR = "currentDir";
public static final String CHANNEL_CHARGECYCLES = "chargeCycles";
public static final String CHANNEL_BATTERYTEMPERATURE = "batteryTemperature";
public static final String CHANNEL_LOGINTERVAL = "loginterval";
public static final String CHANNEL_S0INPULSECNT = "s0InPulseCnt";
public static final String CHANNEL_OWNCONSRATE_TOTAL = "ownConsRateTotal";
public static final String CHANNEL_AUTONOMYDEGREE_TOTAL = "autonomyDegreeTotal";
public static final String CHANNEL_BATTERYVOLTAGE = "batteryVoltage";
public static final String CHANNEL_BATSTATEOFCHARGE = "batStateOfCharge";
public static final String CHANNEL_SELFCONSUMPTION = "selfConsumption";
public static final String CHANNEL_BATTERYUSAGECONSUMPTION = "batteryUsageConsumption";
public static final String CHANNEL_SMARTBATTERYCONTROL = "smartBatteryControl";
public static final String CHANNEL_MAXDEPTHOFDISCHARGE = "maxDepthOfDischarge";
public static final String CHANNEL_SHADOWMANAGEMENT = "shadowManagement";
public static final String CHANNEL_EXTERNALMODULECONTROL = "externalModuleControl";
public static final String CHANNEL_BATTERYUSAGECONSUMPTIONSET = "batteryUsageConsumptionSet";
public static final String CHANNEL_BATTERYUSAGESTRATEGYSET = "batteryUsageStrategySet";
public static final String CHANNEL_SMARTBATTERYCONTROLSET = "smartBatteryControlSet";
public static final String CHANNEL_BATTERYCHARGETIMEFROMSET = "batteryChargeTimeFromSet";
public static final String CHANNEL_BATTERYCHARGETIMETOSET = "batteryChargeTimeToSet";
public static final String CHANNEL_MAXDEPTHOFDISCHARGESET = "maxDepthOfDischargeSet";
public static final String CHANNEL_SHADOWMANAGEMENTSET = "shadowManagementSet";
public static final String CHANNEL_EXTERNALMODULECONTROLSET = "externalModuleControlSet";
}

View File

@ -0,0 +1,185 @@
/**
* Copyright (c) 2010-2021 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.kostalinverter.internal.secondgeneration;
import java.util.ArrayList;
import java.util.List;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
/**
* The {@link SecondGenerationChannelConfiguration} class defines methods, which set up channel configuration,
* used in the second generation part of the binding.
*
*
* @author Christian Schneider - Initial contribution
* @author Christoph Weitkamp - Incorporated new QuantityType (Units of Measurement)
* @author Örjan Backsell - Added channels for (Piko1020, Piko New Generation)
*/
@NonNullByDefault
public class SecondGenerationChannelConfiguration {
public String id;
public String tag;
public int num;
public Unit<?> unit;
public String dxsEntries;
public SecondGenerationChannelConfiguration(String id, String tag, int num, Unit<?> unit, String dxsEntries) {
this.id = id;
this.tag = tag;
this.num = num;
this.unit = unit;
this.dxsEntries = dxsEntries;
}
public static List<SecondGenerationChannelConfiguration> getChannelConfiguration() {
final List<SecondGenerationChannelConfiguration> channelConfiguration = new ArrayList<>();
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_GRIDOUTPUTPOWER, "td", 4, Units.WATT, "67109120"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_YIELD_DAY_SECOND_GEN, "td", 7, Units.WATT_HOUR, "251658754"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_YIELD_TOTAL_SECOND_GEN, "td", 10, Units.KILOWATT_HOUR,
"251658753"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_OPERATING_STATUS, "td", 13, Units.ONE, "16780032"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_GRIDVOLTAGEL1, "td", 16, Units.VOLT, "67109378"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_GRIDCURRENTL1, "td", 19, Units.AMPERE, "67109377"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_GRIDPOWERL1, "td", 22, Units.WATT, "67109379"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_GRIDVOLTAGEL2, "td", 25, Units.VOLT, "67109634"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_GRIDCURRENTL2, "td", 28, Units.AMPERE, "67109633"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_GRIDPOWERL2, "td", 31, Units.WATT, "67109635"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_GRIDVOLTAGEL3, "td", 34, Units.VOLT, "67109890"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_GRIDCURRENTL3, "td", 37, Units.AMPERE, "67109889"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_GRIDPOWERL3, "td", 40, Units.WATT, "67109891"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_DCPOWERPV, "td", 43, Units.WATT, "33556736"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_DC1VOLTAGE, "td", 46, Units.VOLT, "33555202"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_DC1CURRENT, "td", 49, Units.AMPERE, "33555201"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_DC1POWER, "td", 52, Units.WATT, "33555203"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_DC2VOLTAGE, "td", 55, Units.VOLT, "33555458"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_DC2CURRENT, "td", 58, Units.AMPERE, "33555457"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_DC2POWER, "td", 61, Units.WATT, "33555459"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_DC3VOLTAGE, "td", 64, Units.VOLT, "33555714"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_DC3CURRENT, "td", 67, Units.AMPERE, "33555713"));
channelConfiguration.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_DC3POWER, "td", 70, Units.WATT, "33555715"));
return channelConfiguration;
}
public static List<SecondGenerationChannelConfiguration> getChannelConfigurationExt() {
final List<SecondGenerationChannelConfiguration> channelConfigurationExt = new ArrayList<>();
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_AKTHOMECONSUMTIONSOLAR, "td", 73, Units.WATT, "83886336"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_AKTHOMECONSUMPTIONBAT, "td", 76, Units.WATT, "83886592"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_AKTHOMECONSUMPTIONGRID, "td", 79, Units.WATT, "83886848"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_PHASESELHOMECONSUMPL1, "td", 82, Units.WATT, "83887106"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_PHASESELHOMECONSUMPL2, "td", 85, Units.WATT, "83887362"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_PHASESELHOMECONSUMPL3, "td", 88, Units.WATT, "83887618"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_GRIDFREQ, "td", 91, Units.HERTZ, "67110400"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_GRIDCOSPHI, "td", 94, Units.DEGREE_ANGLE, "67110656"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_HOMECONSUMPTION_DAY, "td", 97, Units.WATT_HOUR, "251659010"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_OWNCONSUMPTION_DAY, "td", 100, Units.WATT_HOUR, "251659266"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_OWNCONSRATE_DAY, "td", 103, Units.PERCENT, "251659278"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_AUTONOMYDEGREE_DAY, "td", 106, Units.PERCENT, "251659279"));
channelConfigurationExt.add(
new SecondGenerationChannelConfiguration(SecondGenerationBindingConstants.CHANNEL_HOMECONSUMPTION_TOTAL,
"td", 109, Units.WATT_HOUR, "251659009"));
channelConfigurationExt.add(
new SecondGenerationChannelConfiguration(SecondGenerationBindingConstants.CHANNEL_OWNCONSUMPTION_TOTAL,
"td", 112, Units.WATT_HOUR, "251659265"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_OPERATINGTIME_TOTAL, "td", 115, Units.HOUR, "251658496"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_CURRENT, "td", 118, Units.AMPERE, "33556238"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_CURRENTDIR, "td", 121, Units.ONE, "33556230"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_CHARGECYCLES, "td", 124, Units.ONE, "33556228"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_BATTERYTEMPERATURE, "td", 127, SIUnits.CELSIUS, "33556227"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_LOGINTERVAL, "td", 130, Units.MINUTE, "150995968"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_S0INPULSECNT, "td", 133, Units.ONE, "184549632"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_OWNCONSRATE_TOTAL, "td", 136, Units.PERCENT, "251659280"));
channelConfigurationExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_AUTONOMYDEGREE_TOTAL, "td", 139, Units.PERCENT, "251659281"));
return channelConfigurationExt;
}
public static List<SecondGenerationChannelConfiguration> getChannelConfigurationExtExt() {
final List<SecondGenerationChannelConfiguration> channelConfigurationExtExt = new ArrayList<>();
channelConfigurationExtExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_BATTERYVOLTAGE, "td", 142, Units.VOLT, "33556226"));
channelConfigurationExtExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_BATSTATEOFCHARGE, "td", 145, Units.PERCENT, "33556229"));
channelConfigurationExtExt.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_SELFCONSUMPTION, "td", 148, Units.WATT, "83888128"));
return channelConfigurationExtExt;
}
public static List<SecondGenerationChannelConfiguration> getChannelConfigurationConfigurable() {
final List<SecondGenerationChannelConfiguration> channelConfigurationConfigurable = new ArrayList<>();
channelConfigurationConfigurable.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_BATTERYUSAGECONSUMPTION, "td", 151, Units.WATT, "33556249"));
channelConfigurationConfigurable.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_SMARTBATTERYCONTROL, "td", 154, Units.ONE, "33556484"));
channelConfigurationConfigurable.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_MAXDEPTHOFDISCHARGE, "td", 157, Units.ONE, "33556247"));
channelConfigurationConfigurable.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_SHADOWMANAGEMENT, "td", 160, Units.ONE, "33556483"));
channelConfigurationConfigurable.add(new SecondGenerationChannelConfiguration(
SecondGenerationBindingConstants.CHANNEL_EXTERNALMODULECONTROL, "td", 163, Units.ONE, "33556482"));
return channelConfigurationConfigurable;
}
}

View File

@ -0,0 +1,161 @@
/**
* Copyright (c) 2010-2021 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.kostalinverter.internal.secondgeneration;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonArray;
import com.google.gson.JsonIOException;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
* The {@link SecondGenerationConfigurationHandler} is responsible for configuration changes,
* regarded to second generation part of the binding.
*
* @author Örjan Backsell - Initial contribution Piko1020, Piko New Generation
*/
@NonNullByDefault
public class SecondGenerationConfigurationHandler {
public static void executeConfigurationChanges(HttpClient httpClient, String url, String username, String password,
String dxsId, String value)
throws InterruptedException, ExecutionException, TimeoutException, NoSuchAlgorithmException {
String urlLogin = url + "/api/login.json?";
String salt = "";
String sessionId = "";
Logger logger = LoggerFactory.getLogger(SecondGenerationConfigurationHandler.class);
String getAuthenticateResponse = httpClient.GET(urlLogin).getContentAsString();
try {
JsonObject getAuthenticateResponseJsonObject = (JsonObject) new JsonParser()
.parse(transformJsonResponse(getAuthenticateResponse));
sessionId = extractSessionId(getAuthenticateResponseJsonObject);
JsonObject authenticateJsonObject = new JsonParser().parse(getAuthenticateResponse.toString())
.getAsJsonObject();
salt = authenticateJsonObject.get("salt").getAsString();
String saltedPassword = new StringBuilder(password).append(salt).toString();
MessageDigest mDigest = MessageDigest.getInstance("SHA1");
byte[] mDigestedPassword = mDigest.digest(saltedPassword.getBytes(StandardCharsets.UTF_8));
StringBuilder loginPostStringBuilder = new StringBuilder();
for (int i = 0; i < mDigestedPassword.length; i++) {
loginPostStringBuilder.append(Integer.toString((mDigestedPassword[i] & 0xff) + 0x100, 16).substring(1));
}
String saltedmDigestedPwd = Base64.getEncoder().encodeToString(mDigest.digest(saltedPassword.getBytes()));
String loginPostJsonData = "{\"mode\":1,\"userId\":\"" + username + "\",\"pwh\":\"" + saltedmDigestedPwd
+ "\"}";
Request loginPostJsonResponse = httpClient.POST(urlLogin + "?sessionId=" + sessionId);
loginPostJsonResponse.header(HttpHeader.CONTENT_TYPE, "application/json");
loginPostJsonResponse.content(new StringContentProvider(loginPostJsonData));
ContentResponse loginPostJsonDataContentResponse = loginPostJsonResponse.send();
String loginPostResponse = new String(loginPostJsonDataContentResponse.getContent(),
StandardCharsets.UTF_8);
JsonObject loginPostJsonObject = (JsonObject) new JsonParser()
.parse(transformJsonResponse(loginPostResponse));
sessionId = extractSessionId(loginPostJsonObject);
// Part for sending data to Inverter
String postJsonData = "{\"dxsEntries\":[{\"dxsId\":" + dxsId + ",\"value\":" + value + "}]}";
Request postJsonDataRequest = httpClient.POST(url + "/api/dxs.json?sessionId=" + sessionId);
postJsonDataRequest.header(HttpHeader.CONTENT_TYPE, "application/json");
postJsonDataRequest.content(new StringContentProvider(postJsonData));
postJsonDataRequest.send();
} catch (JsonIOException getAuthenticateResponseException) {
logger.debug("Could not read the response: {}", getAuthenticateResponseException.getMessage());
}
}
static String transformJsonResponse(String jsonResponse) {
// Method transformJsonResponse converts response,due to missing [] in ContentResponse
// postJsonDataContentResponse.
int sessionStartPosition = jsonResponse.indexOf("session");
int statusStartPosition = jsonResponse.indexOf("status");
StringBuilder transformStringBuilder = new StringBuilder();
transformStringBuilder.append(jsonResponse);
transformStringBuilder.insert(sessionStartPosition + 9, '[');
int roleIdStartPosition = jsonResponse.indexOf("roleId");
transformStringBuilder.insert(roleIdStartPosition + 11, ']');
transformStringBuilder.insert(statusStartPosition + 10, '[');
int codeStartPosition = jsonResponse.indexOf("code");
transformStringBuilder.insert(codeStartPosition + 11, ']');
String transformJsonObject = transformStringBuilder.toString();
return transformJsonObject;
}
// Method extractSessionId extracts sessionId from JsonObject
static String extractSessionId(JsonObject extractJsonObjectSessionId) {
Logger sessionIdLogger = LoggerFactory.getLogger(SecondGenerationConfigurationHandler.class);
String extractSessionId = "";
JsonArray extractJsonArraySessionId = extractJsonObjectSessionId.getAsJsonArray("session");
int size = extractJsonArraySessionId.size();
if (size > 0) {
extractSessionId = extractJsonArraySessionId.get(size - 1).getAsJsonObject().get("sessionId").getAsString();
}
if (extractSessionId == "0") {
sessionIdLogger.debug(" Login Post Json Reponse not OK! , inverter answered with sessionId like: {}",
extractSessionId);
}
return extractSessionId;
}
// Method extractCode extracts code from JsonObject
static String extractCode(JsonObject extractJsonObjectCode) {
Logger codeLogger = LoggerFactory.getLogger(SecondGenerationConfigurationHandler.class);
String extractCode = "";
JsonArray extractJsonArrayCode = extractJsonObjectCode.getAsJsonArray("status");
int size = extractJsonArrayCode.size();
if (size > 0) {
extractCode = extractJsonArrayCode.get(size - 1).getAsJsonObject().get("code").getAsString();
}
if (extractCode != "0") {
codeLogger.debug(" Login Post Json Reponse not OK! , inverter answered with status code like: {}",
extractCode);
}
return extractCode;
}
}

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2021 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.kostalinverter.internal.secondgeneration;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link SecondGenerationDxsEntries} class defines methods, which are
* used in the second generation part of the binding.
*
* @author Örjan Backsell - Initial contribution Piko1020, Piko New Generation
*/
@NonNullByDefault
public class SecondGenerationDxsEntries {
private String dxsId = "";
private String value = "";
public String getId() {
return dxsId;
}
public String getName() {
return value;
}
}

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2010-2021 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.kostalinverter.internal.secondgeneration;
import java.util.List;
/**
* The {@link SecondGenerationDxsEntriesContainer} class defines an Container, which is
* used in the second generation part of the binding.
*
* @author Örjan Backsell - Initial contribution Piko1020, Piko New Generation
*/
public class SecondGenerationDxsEntriesContainerDTO {
public List<SecondGenerationDxsEntries> dxsEntries;
}

View File

@ -0,0 +1,401 @@
/**
* Copyright (c) 2010-2021 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.kostalinverter.internal.secondgeneration;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
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.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
* The {@link SecondGenerationHandler} is responsible for handling commands, which are
* sent to one of the channels, and initiation and refreshing regarded to second generation part of the binding.
*
*
* @author Christian Schneider - Initial contribution
* @author Christoph Weitkamp - Incorporated new QuantityType (Units of Measurement)
* @author Örjan Backsell - Redesigned regarding Piko1020, Piko New Generation
*/
@NonNullByDefault
public class SecondGenerationHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(SecondGenerationHandler.class);
private @Nullable ScheduledFuture<?> secondGenerationPoller;
private final HttpClient httpClient;
private List<SecondGenerationChannelConfiguration> channelConfigs = new ArrayList<>();
private List<SecondGenerationChannelConfiguration> channelConfigsExt = new ArrayList<>();
private List<SecondGenerationChannelConfiguration> channelConfigsExtExt = new ArrayList<>();
private List<SecondGenerationChannelConfiguration> channelConfigsConfigurable = new ArrayList<>();
private List<SecondGenerationChannelConfiguration> channelConfigsAll = new ArrayList<>();
private List<String> channelPostsTemp = new ArrayList<>();
private List<String> channelPostsTempExt = new ArrayList<>();
private List<String> channelPostsTempExtExt = new ArrayList<>();
private List<String> channelPostsTempAll = new ArrayList<>();
private SecondGenerationInverterConfig inverterConfig = new SecondGenerationInverterConfig();
private Gson gson = new GsonBuilder().setPrettyPrinting().create();
public SecondGenerationHandler(Thing thing, HttpClient httpClient) {
super(thing);
this.httpClient = httpClient;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
String url = inverterConfig.url;
String username = inverterConfig.username;
String password = inverterConfig.password;
String valueConfiguration = "";
String dxsEntriesConf = "";
if (inverterConfig.hasBattery) {
switch (channelUID.getId()) {
case SecondGenerationBindingConstants.CHANNEL_BATTERYUSAGECONSUMPTIONSET:
valueConfiguration = command.toString();
dxsEntriesConf = "33556249";
preSetExecuteConfigurationChanges(httpClient, url, username, password, dxsEntriesConf,
valueConfiguration);
break;
case SecondGenerationBindingConstants.CHANNEL_BATTERYUSAGESTRATEGYSET:
valueConfiguration = command.toString();
dxsEntriesConf = "83888896";
preSetExecuteConfigurationChanges(httpClient, url, username, password, dxsEntriesConf,
valueConfiguration);
break;
case SecondGenerationBindingConstants.CHANNEL_SMARTBATTERYCONTROLSET:
if (command.toString().equals("ON")) {
valueConfiguration = "true";
}
if (command.toString().equals("OFF")) {
valueConfiguration = "false";
}
dxsEntriesConf = "33556484";
preSetExecuteConfigurationChanges(httpClient, url, username, password, dxsEntriesConf,
valueConfiguration);
break;
case SecondGenerationBindingConstants.CHANNEL_BATTERYCHARGETIMEFROMSET:
valueConfiguration = command.toString();
String valueConfigurationFromTransformed = String.valueOf(stringToSeconds(valueConfiguration));
dxsEntriesConf = "33556239";
preSetExecuteConfigurationChanges(httpClient, url, username, password, dxsEntriesConf,
valueConfigurationFromTransformed);
break;
case SecondGenerationBindingConstants.CHANNEL_BATTERYCHARGETIMETOSET:
valueConfiguration = command.toString();
String valueConfigurationToTransformed = String.valueOf(stringToSeconds(valueConfiguration));
dxsEntriesConf = "33556240";
preSetExecuteConfigurationChanges(httpClient, url, username, password, dxsEntriesConf,
valueConfigurationToTransformed);
break;
case SecondGenerationBindingConstants.CHANNEL_MAXDEPTHOFDISCHARGESET:
valueConfiguration = command.toString();
dxsEntriesConf = "33556247";
preSetExecuteConfigurationChanges(httpClient, url, username, password, dxsEntriesConf,
valueConfiguration);
break;
case SecondGenerationBindingConstants.CHANNEL_SHADOWMANAGEMENTSET:
valueConfiguration = command.toString();
dxsEntriesConf = "33556483";
preSetExecuteConfigurationChanges(httpClient, url, username, password, dxsEntriesConf,
valueConfiguration);
break;
case SecondGenerationBindingConstants.CHANNEL_EXTERNALMODULECONTROLSET:
valueConfiguration = command.toString();
dxsEntriesConf = "33556482";
preSetExecuteConfigurationChanges(httpClient, url, username, password, dxsEntriesConf,
valueConfiguration);
break;
}
}
}
@Override
public void initialize() {
// Set channel configuration parameters
channelConfigs = SecondGenerationChannelConfiguration.getChannelConfiguration();
channelConfigsExt = SecondGenerationChannelConfiguration.getChannelConfigurationExt();
channelConfigsExtExt = SecondGenerationChannelConfiguration.getChannelConfigurationExtExt();
channelConfigsConfigurable = SecondGenerationChannelConfiguration.getChannelConfigurationConfigurable();
// Set inverter configuration parameters
final SecondGenerationInverterConfig inverterConfig = getConfigAs(SecondGenerationInverterConfig.class);
this.inverterConfig = inverterConfig;
// Temporary value during initializing
updateStatus(ThingStatus.UNKNOWN);
// Start update as configured
secondGenerationPoller = scheduler.scheduleWithFixedDelay(() -> {
try {
refresh();
updateStatus(ThingStatus.ONLINE);
} catch (RuntimeException scheduleWithFixedDelayException) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
scheduleWithFixedDelayException.getClass().getName() + ":"
+ scheduleWithFixedDelayException.getMessage());
} catch (InterruptedException interruptedException) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
interruptedException.getClass().getName() + ":" + interruptedException.getMessage());
} catch (ExecutionException executionException) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
executionException.getClass().getName() + ":" + executionException.getMessage());
} catch (TimeoutException timeoutException) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
timeoutException.getClass().getName() + ":" + timeoutException.getMessage());
}
}, 0, SecondGenerationInverterConfig.REFRESHINTERVAL_SEC, TimeUnit.SECONDS);
}
@Override
public void dispose() {
final ScheduledFuture<?> secondGenerationLocalPoller = secondGenerationPoller;
if (secondGenerationLocalPoller != null) {
secondGenerationLocalPoller.cancel(true);
secondGenerationPoller = null;
}
}
private void refresh() throws InterruptedException, ExecutionException, TimeoutException {
// Build posts for dxsEntries part
String dxsEntriesCall = inverterConfig.url + "/api/dxs.json?dxsEntries=" + channelConfigs.get(0).dxsEntries;
for (int i = 1; i < channelConfigs.size(); i++) {
dxsEntriesCall += ("&dxsEntries=" + channelConfigs.get(i).dxsEntries);
}
String jsonDxsEntriesResponse = callURL(dxsEntriesCall);
SecondGenerationDxsEntriesContainerDTO dxsEntriesContainer = gson.fromJson(jsonDxsEntriesResponse,
SecondGenerationDxsEntriesContainerDTO.class);
String[] channelPosts = new String[23];
int channelPostsCounter = 0;
for (SecondGenerationDxsEntries dxsentries : dxsEntriesContainer.dxsEntries) {
channelPosts[channelPostsCounter] = dxsentries.getName();
channelPostsCounter++;
}
channelPostsTemp = List.of(channelPosts);
// Build posts for dxsEntriesExt part
String dxsEntriesCallExt = inverterConfig.url + "/api/dxs.json?dxsEntries="
+ channelConfigsExt.get(0).dxsEntries;
for (int i = 1; i < channelConfigs.size(); i++) {
dxsEntriesCallExt += ("&dxsEntries=" + channelConfigsExt.get(i).dxsEntries);
}
String jsonDxsEntriesResponseExt = callURL(dxsEntriesCallExt);
SecondGenerationDxsEntriesContainerDTO dxsEntriesContainerExt = gson.fromJson(jsonDxsEntriesResponseExt,
SecondGenerationDxsEntriesContainerDTO.class);
String[] channelPostsExt = new String[23];
int channelPostsCounterExt = 0;
for (SecondGenerationDxsEntries dxsentriesExt : dxsEntriesContainerExt.dxsEntries) {
channelPostsExt[channelPostsCounterExt] = dxsentriesExt.getName();
channelPostsCounterExt++;
}
channelPostsTempExt = List.of(channelPostsExt);
// Build posts for dxsEntriesExtExt part
String dxsEntriesCallExtExt = inverterConfig.url + "/api/dxs.json?dxsEntries="
+ channelConfigsExtExt.get(0).dxsEntries;
for (int i = 1; i < channelConfigsExtExt.size(); i++) {
dxsEntriesCallExtExt += ("&dxsEntries=" + channelConfigsExtExt.get(i).dxsEntries);
}
String jsonDxsEntriesResponseExtExt = callURL(dxsEntriesCallExtExt);
SecondGenerationDxsEntriesContainerDTO dxsEntriesContainerExtExt = gson.fromJson(jsonDxsEntriesResponseExtExt,
SecondGenerationDxsEntriesContainerDTO.class);
String[] channelPostsExtExt = new String[3];
int channelPostsCounterExtExt = 0;
for (SecondGenerationDxsEntries dxsentriesExtExt : dxsEntriesContainerExtExt.dxsEntries) {
channelPostsExtExt[channelPostsCounterExtExt] = dxsentriesExtExt.getName();
channelPostsCounterExtExt++;
}
channelPostsTempExtExt = List.of(channelPostsExtExt);
// Concatenate posts for all parts except configurable channels
channelPostsTempAll = combinePostsLists(channelPostsTemp, channelPostsTempExt, channelPostsTempExtExt);
String[] channelPostsTempAll1 = channelPostsTempAll.toArray(new String[0]);
// Build posts for dxsEntriesConfigureable part
String dxsEntriesCallConfigurable = inverterConfig.url + "/api/dxs.json?dxsEntries="
+ channelConfigsConfigurable.get(0).dxsEntries;
for (int i = 1; i < channelConfigsConfigurable.size(); i++) {
dxsEntriesCallConfigurable += ("&dxsEntries=" + channelConfigsConfigurable.get(i).dxsEntries);
}
String jsonDxsEntriesResponseConfigurable = callURL(dxsEntriesCallConfigurable);
SecondGenerationDxsEntriesContainerDTO dxsEntriesContainerConfigurable = gson
.fromJson(jsonDxsEntriesResponseConfigurable, SecondGenerationDxsEntriesContainerDTO.class);
String[] channelPostsConfigurable = new String[5];
int channelPostsCounterConfigurable = 0;
for (SecondGenerationDxsEntries dxsentriesConfigurable : dxsEntriesContainerConfigurable.dxsEntries) {
channelPostsConfigurable[channelPostsCounterConfigurable] = dxsentriesConfigurable.getName();
channelPostsCounterConfigurable++;
}
// Create and update actual values for non-configurable channels
if (!inverterConfig.hasBattery) {
channelConfigsAll = combineChannelConfigLists(channelConfigs, channelConfigsExt, channelConfigsExtExt);
int channelValuesCounterAll = 0;
for (SecondGenerationChannelConfiguration cConfig : channelConfigsAll) {
String channel = cConfig.id;
updateState(channel, getState(channelPostsTempAll1[channelValuesCounterAll], cConfig.unit));
channelValuesCounterAll++;
}
}
// Create and update actual values for all channels
if (inverterConfig.hasBattery) {
// Part for updating non-configurable channels
channelConfigsAll = combineChannelConfigLists(channelConfigs, channelConfigsExt, channelConfigsExtExt);
// Update the non-configurable channels
int channelValuesCounterAll = 0;
for (SecondGenerationChannelConfiguration cConfig : channelConfigsAll) {
String channel = cConfig.id;
updateState(channel, getState(channelPostsTempAll1[channelValuesCounterAll], cConfig.unit));
channelValuesCounterAll++;
}
// Part for updating configurable channels
int channelValuesCounterConfigurable = 0;
for (SecondGenerationChannelConfiguration cConfig : channelConfigsConfigurable) {
String channel = cConfig.id;
String value = channelPostsConfigurable[channelValuesCounterConfigurable];
int dxsEntriesCheckCounter = 3;
if (cConfig.dxsEntries.equals("33556484")) {
dxsEntriesCheckCounter = 1;
}
if (cConfig.dxsEntries.equals("33556482")) {
dxsEntriesCheckCounter = 2;
}
switch (dxsEntriesCheckCounter) {
case 1:
if (value.equals("false")) {
updateState(channel, OnOffType.OFF);
}
if (value.equals("true")) {
updateState(channel, OnOffType.ON);
}
channelValuesCounterConfigurable++;
break;
case 2:
if (value.equals("false")) {
State stateFalse = new StringType("0");
updateState(channel, stateFalse);
}
if (value.equals("true")) {
State stateTrue = new StringType("1");
updateState(channel, stateTrue);
}
channelValuesCounterConfigurable++;
break;
case 3:
State stateOther = getState(channelPostsConfigurable[channelValuesCounterConfigurable],
cConfig.unit);
updateState(channel, stateOther);
channelValuesCounterConfigurable++;
break;
}
}
}
}
// Help method of handleCommand to with SecondGenerationConfigurationHandler.executeConfigurationChanges method send
// configuration changes.
private final void preSetExecuteConfigurationChanges(HttpClient httpClient, String url, String username,
String password, String dxsEntriesConf, String valueConfiguration) {
try {
SecondGenerationConfigurationHandler.executeConfigurationChanges(httpClient, url, username, password,
dxsEntriesConf, valueConfiguration);
} catch (Exception handleCommandException) {
logger.debug("Handle command for {} on channel {}: {}: {}: {}: {}", thing.getUID(), httpClient, url,
dxsEntriesConf, valueConfiguration, handleCommandException.getMessage());
}
}
// Method callURL connect to inverter for value scraping
private final String callURL(String dxsEntriesCall)
throws InterruptedException, ExecutionException, TimeoutException {
String jsonDxsResponse = httpClient.GET(dxsEntriesCall).getContentAsString();
return jsonDxsResponse;
}
// Method getState is used for non-configurable values
private State getState(String value, @Nullable Unit<?> unit) {
if (unit == null) {
return new StringType(value);
} else {
try {
return new QuantityType<>(new BigDecimal(value), unit);
} catch (NumberFormatException getStateException) {
logger.debug("Error parsing value '{}: {}'", value, getStateException.getMessage());
return UnDefType.UNDEF;
}
}
}
// Method stringToSeconds transform given time in 00:16 syntax to seconds syntax
private static long stringToSeconds(String stringTime) {
long secondsMin = Long.parseLong(stringTime.substring(3, 5)) * 60;
long secondsHrs = Long.parseLong(stringTime.substring(0, 2)) * 3600;
return secondsMin + secondsHrs;
}
// Method to concatenate channelConfigs Lists to one List
@SafeVarargs
private final List<SecondGenerationChannelConfiguration> combineChannelConfigLists(
List<SecondGenerationChannelConfiguration>... args) {
List<SecondGenerationChannelConfiguration> combinedChannelConfigLists = new ArrayList<>();
for (List<SecondGenerationChannelConfiguration> list : args) {
for (SecondGenerationChannelConfiguration i : list) {
combinedChannelConfigLists.add(i);
}
}
return combinedChannelConfigLists;
}
// Method to concatenate channelPosts Lists to one List
@SafeVarargs
private final List<String> combinePostsLists(List<String>... args) {
List<String> combinedPostsLists = new ArrayList<>();
for (List<String> list : args) {
for (String i : list) {
combinedPostsLists.add(i);
}
}
return combinedPostsLists;
}
}

View File

@ -0,0 +1,36 @@
/**
* Copyright (c) 2010-2021 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.kostalinverter.internal.secondgeneration;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link SecondGenerationInverterConfig} class defines constants, which are
* used in the second generation part of the binding.
*
* @author Christian Schneider - Initial contribution
* @author Örjan Backsell - Added parameters for configuration options Piko1020, Piko New Generation
*
*/
@NonNullByDefault
public class SecondGenerationInverterConfig {
public static final long REFRESHINTERVAL_SEC = 60;
public String url = "";
public String username = "";
public String password = "";
public String dxsIdConf = "";
public String valueConf = "";
public boolean hasBattery;
}

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<config-description:config-descriptions
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
<config-description uri="thing-type:kostalpiko1020_config">
<parameter name="url" type="text" required="true">
<label>IP Address</label>
<description>IP address of the inverter.</description>
<context>url</context>
</parameter>
<parameter name="username" type="text" required="true">
<label>Username</label>
<description>The username to the inverter.</description>
</parameter>
<parameter name="password" type="text" required="true">
<label>Password</label>
<description>The password to the inverter.</description>
<context>password</context>
</parameter>
<parameter name="refreshInterval" type="integer" min="1" unit="s" required="true">
<label>Refresh Interval</label>
<description>Refresh Interval in seconds.</description>
<default>60</default>
</parameter>
<parameter name="hasBattery" type="boolean" required="true">
<label>Inverter Type</label>
<description>Type of inverter, with/without battery.</description>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@ -32,7 +32,7 @@
<channel-type id="device-local-ownconsumption">
<item-type>Number:Power</item-type>
<label>Own Consumption</label>
<description>Current own comsumption</description>
<description>Current own consumption</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
@ -46,7 +46,7 @@
<channel-type id="device-local-homeconsumption-total">
<item-type>Number:Power</item-type>
<label>Home Consumption</label>
<description>Current total homeconsumption</description>
<description>Current total home consumption</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
@ -484,4 +484,438 @@
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-grid-output-power">
<item-type>Number:Power</item-type>
<label>Grid Output Power</label>
<description>Current output power to the grid</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="statistic-yield-day-second-gen">
<item-type>Number:Energy</item-type>
<label>Yield Day</label>
<description>Total produced power day</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="statistic-yield-total-second-gen">
<item-type>Number:Energy</item-type>
<label>Yield Total</label>
<description>Total produced power</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-operating-status">
<item-type>Number:Dimensionless</item-type>
<label>Operating Status</label>
<description>Operating status</description>
<category>Energy</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="device-local-grid-voltage-l1">
<item-type>Number:ElectricPotential</item-type>
<label>Grid Voltage L1</label>
<description>Current output voltage to the grid, L1</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-grid-current-l1">
<item-type>Number:ElectricCurrent</item-type>
<label>Grid Amperage L1</label>
<description>Current output amperage to the grid, L1</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-grid-power-l1">
<item-type>Number:Power</item-type>
<label>Grid Power L1</label>
<description>Current output power to the grid, L1</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-grid-voltage-l2">
<item-type>Number:ElectricPotential</item-type>
<label>Grid Voltage L2</label>
<description>Current output voltage to the grid, L2</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-grid-current-l2">
<item-type>Number:ElectricCurrent</item-type>
<label>Grid Amperage L2</label>
<description>Current output amperage to the grid, L2</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-grid-power-l2">
<item-type>Number:Power</item-type>
<label>Grid Power L2</label>
<description>Current output power to the grid, L2</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-grid-voltage-l3">
<item-type>Number:ElectricPotential</item-type>
<label>Grid Voltage L3</label>
<description>Current output voltage to the grid, L3</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-grid-current-l3">
<item-type>Number:ElectricCurrent</item-type>
<label>Grid Amperage L3</label>
<description>Current output amperage to the grid, L3</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-grid-power-l3">
<item-type>Number:Power</item-type>
<label>Grid Power L3</label>
<description>Current output power to the grid, L3</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-dc-power-pv">
<item-type>Number:Power</item-type>
<label>DC Power PV</label>
<description>Current power from solar panels</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-dc1-voltage">
<item-type>Number:ElectricPotential</item-type>
<label>DC1 Voltage</label>
<description>Current voltage from solar panels, DC1</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-dc1-current">
<item-type>Number:ElectricCurrent</item-type>
<label>DC1 Amperage</label>
<description>Current amperage from solar panels, DC1</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-dc1-power">
<item-type>Number:Power</item-type>
<label>DC1 Power</label>
<description>Current power from solar panels, DC1</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-dc2-voltage">
<item-type>Number:ElectricPotential</item-type>
<label>DC2 Voltage</label>
<description>Current voltage from solar panels, DC2</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-dc2-current">
<item-type>Number:ElectricCurrent</item-type>
<label>DC2 Amperage</label>
<description>Current amperage from solar panels, DC2</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-dc2-power">
<item-type>Number:Power</item-type>
<label>DC2 Power</label>
<description>Current power from solar panels, DC2</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-dc3-voltage">
<item-type>Number:ElectricPotential</item-type>
<label>DC3 Voltage</label>
<description>Current voltage from solar panels, DC3</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-dc3-current">
<item-type>Number:ElectricCurrent</item-type>
<label>DC3 Amperage</label>
<description>Current amperage from solar panels, DC3</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-dc3-power">
<item-type>Number:Power</item-type>
<label>DC3 Power</label>
<description>Current power from solar panels, DC3</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-akt-home-consumption-solar">
<item-type>Number:Power</item-type>
<label>Home Consumption PV</label>
<description>Current consumption from solar panels</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-akt-home-consumption-bat">
<item-type>Number:Power</item-type>
<label>Home Consumption Bat</label>
<description>Current consumption from battery</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-akt-home-consumption-grid">
<item-type>Number:Power</item-type>
<label>Home Consumption Grid</label>
<description>Current consumption from grid</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-phase-sel-home-consump-l1">
<item-type>Number:Power</item-type>
<label>Home Consumption L1</label>
<description>Current home consumption, L1</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-phase-sel-home-consump-l2">
<item-type>Number:Power</item-type>
<label>Home Consumption L2</label>
<description>Current home consumption, L2</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-phase-sel-home-consump-l3">
<item-type>Number:Power</item-type>
<label>Home Consumption L3</label>
<description>Current home consumption, L3</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-grid-freq">
<item-type>Number:Frequency</item-type>
<label>Grid Freq</label>
<description>Current frequency on grid</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-grid-cos-phi">
<item-type>Number:Angle</item-type>
<label>Grid Cos Phi</label>
<description>Current power factor on grid</description>
<category>Energy</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="statistic-home-consumption-day">
<item-type>Number:Energy</item-type>
<label>Home Consumption Day</label>
<description>Total home consumption day</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="statistic-own-consumption-day">
<item-type>Number:Energy</item-type>
<label>Own Consumption Day</label>
<description>Total own consumption day</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="statistic-own-cons-rate-day">
<item-type>Number:Dimensionless</item-type>
<label>Own Cons Rate Day</label>
<description>Total own consumption rate day</description>
<category>Energy</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="statistic-autonomy-degree-day">
<item-type>Number:Dimensionless</item-type>
<label>Autonomy Degree Day</label>
<description>Total autonomy degree day</description>
<category>Energy</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="statistic-home-consumption-total">
<item-type>Number:Energy</item-type>
<label>Home Consumption Total</label>
<description>Total home consumption</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="statistic-own-consumption-total">
<item-type>Number:Energy</item-type>
<label>Own Consumption Total</label>
<description>Total own consumptionl</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="statistic-operating-time-total">
<item-type>Number:Time</item-type>
<label>Operating Time Total</label>
<description>Total operating time</description>
<category>Energy</category>
<state readOnly="true" pattern="%d %unit%"/>
</channel-type>
<channel-type id="device-local-current">
<item-type>Number:ElectricCurrent</item-type>
<label>Current</label>
<description>Current</description>
<category>Energy</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="device-local-current-dir">
<item-type>Number:Dimensionless</item-type>
<label>Current Dir</label>
<description>Current direction</description>
<category>Energy</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="device-local-charge-cycles">
<item-type>Number:Dimensionless</item-type>
<label>Charge Cycles</label>
<description>Total number of charge cycles</description>
<category>Energy</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="device-local-battery-temperature">
<item-type>Number:Temperature</item-type>
<label>Battery Temperature</label>
<description>Current battery temperature</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-loginterval">
<item-type>Number:Time</item-type>
<label>Loginterval</label>
<description>Value for log interval</description>
<category>Energy</category>
<state readOnly="true" pattern="%d %unit%"/>
</channel-type>
<channel-type id="device-local-s0-inpulse-cnt">
<item-type>Number:Dimensionless</item-type>
<label>S0 Inpulse Cnt</label>
<description>S0-pulse counter</description>
<category>Energy</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="statistic-own-cons-rate-total">
<item-type>Number:Dimensionless</item-type>
<label>Own Cons Rate Total</label>
<description>Total own consumption rate</description>
<category>Energy</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="statistic-autonomy-degree-total">
<item-type>Number:Dimensionless</item-type>
<label>Autonomy Degree Total</label>
<description>Total autonomy degree</description>
<category>Energy</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="device-local-battery-voltage">
<item-type>Number:ElectricalPotential</item-type>
<label>Battery Voltage</label>
<description>Current battery voltage</description>
<category>Energy</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="device-local-bat-state-of-charge">
<item-type>Number:Dimensionless</item-type>
<label>Bat State of Charge</label>
<description>Current battery charge state</description>
<category>Energy</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="device-local-self-consumption">
<item-type>Number:Power</item-type>
<label>Self Consumption</label>
<description>Current self consumption</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-battery-usage-consumption">
<item-type>Number:Power</item-type>
<label>Battery Usage Consumption</label>
<description>Battery usage consumption</description>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="device-local-smart-battery-control">
<item-type>Switch</item-type>
<label>Smart Battery Control</label>
<description>Smart battery control</description>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="device-local-max-depth-of-discharge">
<item-type>Number:Dimensionless</item-type>
<label>Max Depth of Discharge</label>
<description>Max depth of discharge</description>
<category>Energy</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="device-local-shadow-management">
<item-type>Number:Dimensionless</item-type>
<label>Shadow Management</label>
<description>Shadow management</description>
<category>Energy</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="device-local-external-module-control">
<item-type>Number:Dimensionless</item-type>
<label>External Module Control</label>
<description>External Module Control</description>
<category>Energy</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="device-local-battery-usage-consumption-set">
<item-type>String</item-type>
<label>Battery Usage Consumption Set</label>
<description>Set battery usage consumption</description>
<category>Energy</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="device-local-battery-usage-strategy-set">
<item-type>String</item-type>
<label>Battery Usage Strategy Set</label>
<description>Set battery usage strategy</description>
<category>Energy</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="device-local-smart-battery-control-set">
<item-type>Switch</item-type>
<label>Smart Battery Control Set</label>
<description>Set smart battery control</description>
<category>Energy</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="device-local-battery-charge-time-from-set">
<item-type>String</item-type>
<label>Battery Charge Time from Set</label>
<description>Set battery charge time from</description>
<category>Energy</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="device-local-battery-charge-time-to-set">
<item-type>String</item-type>
<label>Battery Charge Time to Set</label>
<description>Set battery charge time to</description>
<category>Energy</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="device-local-max-depth-of-discharge-set">
<item-type>String</item-type>
<label>Max Depth of Discharge Set</label>
<description>Set max depth of discharge</description>
<category>Energy</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="device-local-shadow-management-set">
<item-type>String</item-type>
<label>Shadow Management Set</label>
<description>Set shadow management</description>
<category>Energy</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="device-local-external-module-control-set">
<item-type>String</item-type>
<label>External Module Control Set</label>
<description>Set External Module Control</description>
<category>Energy</category>
<state readOnly="false"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="kostalinverter"
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="piko1020">
<label>KOSTAL PIKO 10-20</label>
<description>Bindings for the KOSTAL PIKO 10-20</description>
<category>Inverter</category>
<channels>
<channel typeId="device-local-grid-output-power" id="gridOutputPower"/>
<channel typeId="statistic-yield-day-second-gen" id="yieldDaySecondGen"/>
<channel typeId="statistic-yield-total-second-gen" id="yieldTotalSecondGen"/>
<channel typeId="device-local-operating-status" id="operatingStatus"/>
<channel typeId="device-local-grid-voltage-l1" id="gridVoltageL1"/>
<channel typeId="device-local-grid-current-l1" id="gridCurrentL1"/>
<channel typeId="device-local-grid-power-l1" id="gridPowerL1"/>
<channel typeId="device-local-grid-voltage-l2" id="gridVoltageL2"/>
<channel typeId="device-local-grid-current-l2" id="gridCurrentL2"/>
<channel typeId="device-local-grid-power-l2" id="gridPowerL2"/>
<channel typeId="device-local-grid-voltage-l3" id="gridVoltageL3"/>
<channel typeId="device-local-grid-current-l3" id="gridCurrentL3"/>
<channel typeId="device-local-grid-power-l3" id="gridPowerL3"/>
<channel typeId="device-local-dc-power-pv" id="dcPowerPV"/>
<channel typeId="device-local-dc1-voltage" id="dc1Voltage"/>
<channel typeId="device-local-dc1-current" id="dc1Current"/>
<channel typeId="device-local-dc1-power" id="dc1Power"/>
<channel typeId="device-local-dc2-voltage" id="dc2Voltage"/>
<channel typeId="device-local-dc2-current" id="dc2Current"/>
<channel typeId="device-local-dc2-power" id="dc2Power"/>
<channel typeId="device-local-dc3-voltage" id="dc3Voltage"/>
<channel typeId="device-local-dc3-current" id="dc3Current"/>
<channel typeId="device-local-dc3-power" id="dc3Power"/>
<channel typeId="device-local-akt-home-consumption-solar" id="aktHomeConsumptionSolar"/>
<channel typeId="device-local-akt-home-consumption-bat" id="aktHomeConsumptionBat"/>
<channel typeId="device-local-akt-home-consumption-grid" id="aktHomeConsumptionGrid"/>
<channel typeId="device-local-phase-sel-home-consump-l1" id="phaseSelHomeConsumpL1"/>
<channel typeId="device-local-phase-sel-home-consump-l2" id="phaseSelHomeConsumpL2"/>
<channel typeId="device-local-phase-sel-home-consump-l3" id="phaseSelHomeConsumpL3"/>
<channel typeId="device-local-grid-freq" id="gridFreq"/>
<channel typeId="device-local-grid-cos-phi" id="gridCosPhi"/>
<channel typeId="statistic-home-consumption-day" id="homeConsumptionDay"/>
<channel typeId="statistic-own-consumption-day" id="ownConsumptionDay"/>
<channel typeId="statistic-own-cons-rate-day" id="ownConsRateDay"/>
<channel typeId="statistic-autonomy-degree-day" id="autonomyDegreeDay"/>
<channel typeId="statistic-home-consumption-total" id="homeConsumptionTotal"/>
<channel typeId="statistic-own-consumption-total" id="ownConsumptionTotal"/>
<channel typeId="statistic-operating-time-total" id="operatingTimeTotal"/>
<channel typeId="device-local-current" id="current"/>
<channel typeId="device-local-current-dir" id="currentDir"/>
<channel typeId="device-local-charge-cycles" id="chargeCycles"/>
<channel typeId="device-local-battery-temperature" id="batteryTemperature"/>
<channel typeId="device-local-loginterval" id="loginterval"/>
<channel typeId="device-local-s0-inpulse-cnt" id="s0InPulseCnt"/>
<channel typeId="statistic-own-cons-rate-total" id="ownConsRateTotal"/>
<channel typeId="statistic-autonomy-degree-total" id="autonomyDegreeTotal"/>
<channel typeId="device-local-battery-voltage" id="batteryVoltage"/>
<channel typeId="device-local-bat-state-of-charge" id="batStateOfCharge"/>
<channel typeId="device-local-self-consumption" id="selfConsumption"/>
<channel typeId="device-local-battery-usage-consumption" id="batteryUsageConsumption"/>
<channel typeId="device-local-smart-battery-control" id="smartBatteryControl"/>
<channel typeId="device-local-max-depth-of-discharge" id="maxDepthOfDischarge"/>
<channel typeId="device-local-shadow-management" id="shadowManagement"/>
<channel typeId="device-local-external-module-control" id="externalModuleControl"/>
<channel typeId="device-local-battery-usage-consumption-set" id="batteryUsageConsumptionSet"/>
<channel typeId="device-local-battery-usage-strategy-set" id="batteryUsageStrategySet"/>
<channel typeId="device-local-smart-battery-control-set" id="smartBatteryControlSet"/>
<channel typeId="device-local-battery-charge-time-from-set" id="batteryChargeTimeFromSet"/>
<channel typeId="device-local-battery-charge-time-to-set" id="batteryChargeTimeToSet"/>
<channel typeId="device-local-max-depth-of-discharge-set" id="maxDepthOfDischargeSet"/>
<channel typeId="device-local-shadow-management-set" id="shadowManagementSet"/>
<channel typeId="device-local-external-module-control-set" id="externalModuleControlSet"/>
</channels>
<properties>
<property name="vendor">KOSTAL Solar Electric GmbH</property>
</properties>
<config-description-ref uri="thing-type:kostalpiko1020_config"/>
</thing-type>
</thing:thing-descriptions>