
+
+

## 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)
- 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 |
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:
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"}
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
+
+
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;
/**
* @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
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
@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);
}
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());
--- /dev/null
+/**
+ * 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";
+}
--- /dev/null
+/**
+ * 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;
+ }
+}
--- /dev/null
+/**
+ * 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;
+ }
+}
--- /dev/null
+/**
+ * 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;
+ }
+}
--- /dev/null
+/**
+ * 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;
+}
--- /dev/null
+/**
+ * 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;
+ }
+}
--- /dev/null
+/**
+ * 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;
+}
--- /dev/null
+<?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>
<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>
<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>
<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>
--- /dev/null
+<?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>