mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 07:02:02 +01:00
[solarwatt] Initial contribution for solarwatt energy manager (#10091)
* [ADD] First version which was tested with my local setup. Signed-off-by: Sven Carstens <s.carstens@gmx.de> Signed-off-by: Sven Carstens <sven.carstens@aoe.com> * [ADD] Refactoring, add calculated value for direct self consumption and prepare for more. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [ADD] Add chanel description to README and make some channels advanced. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Remove wrong colon in channel types. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Put colon at the right place in channel types. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Fix spelling of PVPlant in constants and things. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Separate channelName from energy manager tagName. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Reduce loglevels and fix findings from code-analysis. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Move all custom calculations to the handler instances, remove custom tracking of child handlers, fix wrong calculation of the "direct consumed" values. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Improve README and remove unnecessary Nullable and NotNull annotations. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Change wrong ItemType for power items in README Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Change modeConverter to Switch Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Relay stateDevice to Thing status, anything but "OK" means ThingStatus.OFFLINE Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Remove stateDevice from items as it is represented by the device status. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Improve README and remove unnecessary logging. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Improve README. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Improve README. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Allow child things to be configured by hand with a guid. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Allow child things to be configured by hand with a guid. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Improve README and move things config to separate config.xml Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Improve README and remove all trace/debug logging. Signed-off-by: Sven Carstens <s.carstens@gmx.de> * [MOD] Use real channel timestamp as the refresh trigger. Signed-off-by: Sven Carstens <s.carstens@gmx.de> Co-authored-by: Sven Carstens <sven.carstens@aoe.com>
This commit is contained in:
parent
39c4cd0a4d
commit
806e0a0287
@ -271,6 +271,7 @@
|
||||
/bundles/org.openhab.binding.snmp/ @openhab/add-ons-maintainers
|
||||
/bundles/org.openhab.binding.solaredge/ @alexf2015
|
||||
/bundles/org.openhab.binding.solarlog/ @johannrichard
|
||||
/bundles/org.openhab.binding.solarwatt/ @sven-carstens
|
||||
/bundles/org.openhab.binding.somfymylink/ @loungeflyz
|
||||
/bundles/org.openhab.binding.somfytahoma/ @octa22
|
||||
/bundles/org.openhab.binding.sonos/ @kgoderis @lolodomo
|
||||
|
@ -1331,6 +1331,11 @@
|
||||
<artifactId>org.openhab.binding.solarlog</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.solarwatt</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.somfymylink</artifactId>
|
||||
|
13
bundles/org.openhab.binding.solarwatt/NOTICE
Normal file
13
bundles/org.openhab.binding.solarwatt/NOTICE
Normal file
@ -0,0 +1,13 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
252
bundles/org.openhab.binding.solarwatt/README.md
Normal file
252
bundles/org.openhab.binding.solarwatt/README.md
Normal file
@ -0,0 +1,252 @@
|
||||
# Solarwatt Binding
|
||||
|
||||
Binding to query a [solarwatt](https://www.solarwatt.de/) [energy manager](https://www.solarwatt.de/energie-management/energymanager) and read the values of all attached devices.
|
||||
|
||||
All supported values and devices were discovered while playing with my own energy manager.
|
||||
|
||||
## Supported Things
|
||||
|
||||
| Thing Type ID | Devices |
|
||||
|------|---------------|
|
||||
| energymanager | EnergyManager itself. |
|
||||
| location | Location part of the EnergyManager. |
|
||||
| pvplant | Power producing part of the EnergyManager. |
|
||||
| gridflow | Grid interaction part of the EnergyManager. |
|
||||
| inverter | inverter producing AC current; e.g. MyReserve, Fronius |
|
||||
| batteryconverter | battery storage systems; e.g. MyReserve |
|
||||
| powermeter | powermeters; e.g. S0BusCounter, MyReserve |
|
||||
| evstation | electric-vehicle charging station; e.g. Keba Wallbox |
|
||||
|
||||
## Discovery
|
||||
|
||||
You have to enter the hostname or ip-address of the energymanager itself.
|
||||
The attached devices and supported channels are discovered automatically.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
### EnergyManager
|
||||
|
||||
| Property | Default | Required | Description |
|
||||
|----------|---------|----------|-------------|
|
||||
| hostname | None | Yes | hostname or ip-address of the energy manager. |
|
||||
| refresh | 30 | No | Refresh interval in seconds for the current values of the channels. |
|
||||
| rescan | 5 | No | Rescan interval in minutes for the redetection of channgels and things. |
|
||||
|
||||
### Child Things
|
||||
|
||||
| Property | Default | Required | Description |
|
||||
|----------|---------|----------|-------------|
|
||||
| guid | None | Yes | Guid of the device as used by the solarwatt energymanager. |
|
||||
|
||||
## Channels
|
||||
|
||||
### EnergyManager
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|-----------|-------------|
|
||||
|timestamp | Number | Milliseconds since the epoch set to the last NTP time sync |
|
||||
|datetime | DateTime | Date and time of the last NTP time sync in the timezone of the energy manager |
|
||||
|idTimezone | String | Timezone the energy manager is running in. All timestamps are milliseconds since the epoch within this timezone |
|
||||
|fractionCPULoadTotal | Number:Dimensionless | Total CPU load in % |
|
||||
|fractionCPULoadUser | Number:Dimensionless | Userspace CPU load in % |
|
||||
|fractionCPULoadKernel | Number:Dimensionless | Kernelspace CPU load in % |
|
||||
|fractionCPULoadAverageLastMinute | Number:Dimensionless | Average 1 minute CPU load in % |
|
||||
|fractionCPULoadAverageLastFiveMinutes | Number:Dimensionless | Average 5 minute CPU load in % |
|
||||
|fractionCPULoadAverageLastFifteenMinutes | Number:Dimensionless | Average 15 minute CPU load in % |
|
||||
|
||||
### PVPlant
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|-----------|-------------|
|
||||
| powerACOut | Number:Power | Energy produced by the PV in watts |
|
||||
| workACOut | Number:Energy | Energy produced by the PV in watt hours |
|
||||
|
||||
### Location
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|-----------|-------------|
|
||||
| powerBuffered | Number:Power | Power flow into the storage system
|
||||
| powerSelfConsumed | Number:Power | Power consumed direct from PV plus energy stored
|
||||
| powerSelfSupplied | Number:Power | Power consumed direct from PV plus energy consumed from storage
|
||||
| powerConsumedFromGrid | Number:Power | Power consumed from the grid
|
||||
| powerConsumedFromStorage | Number:Power | Power consumed from storage
|
||||
| powerConsumedUnmetered | Number:Power | Power consumed in the inner side (outer consumers are subtracted)
|
||||
| powerConsumed | Number:Power | Total power consumed. All inner and outer consumers.
|
||||
| powerDirectConsumed | Number:Power | Power consumed directly from PV without buffering
|
||||
| powerProduced | Number:Power | Power produced by the PV
|
||||
| powerOut | Number:Power | Power delivered to the grid
|
||||
| powerDirectConsumed | Number:Power | Power consumed directly without energy put into storage or taken from storage
|
||||
| workBuffered | Number:Energy | Energy flow into the storage system
|
||||
| workSelfConsumed | Number:Energy | Energy consumed direct from PV plus energy stored
|
||||
| workSelfSupplied | Number:Energy | Energy consumed direct from PV plus energy consumed from storage
|
||||
| workConsumedFromGrid | Number:Energy | Energy consumed from the grid
|
||||
| workConsumedFromStorage | Number:Energy | Energy consumed from storage
|
||||
| workConsumedUnmetered | Number:Energy | Energy consumed in the inner side (outer consumers are subtracted)
|
||||
| workConsumed | Number:Energy | Total energy consumed. All inner and outer consumers.
|
||||
| workDirectConsumed | Number:Energy | Energy consumed directly from PV without buffering
|
||||
| workProduced | Number:Energy | Energy produced by the PV
|
||||
| workOut | Number:Energy | Energy delivered to the grid
|
||||
| workDirectConsumed | Number:Energy | Energy consumed directly without energy put into storage or taken from storage
|
||||
|
||||
### PowerMeter, S0Counter, MyReservePowerMeter
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|-----------|-------------|
|
||||
| channelDirectionMetering | String | Representing which energy flow directions are metered. One off *IN*, *OUT*, *BIDIRECTIONAL*
|
||||
| powerIn | Number:Power | Power metered flowing into the consumer
|
||||
| powerOut | Number:Power | Power metered flowing out of the producer
|
||||
| workIn | Number:Energy | Energy metered flowing into the consumer
|
||||
| workOut | Number:Energy | Energy metered flowing out of the producer
|
||||
| consumptionEnergySum | Number:Energy | Total energy in watt hours
|
||||
|
||||
### Inverter, MyReserveInverter, SunSpecInverter
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|-----------|-------------|
|
||||
| powerACOutMax | Number:Power | Maximum power production
|
||||
| powerACOutLimit | Number:Power | Limit of power production
|
||||
| powerACOut | Number:Power | Power delivered by the inverter
|
||||
| workACOut | Number:Energy | Energy delivered by the inverter
|
||||
| powerInstallledPeak | Number:Power | Technical peak power available
|
||||
|
||||
### BatteryConverter, MyReserve
|
||||
|
||||
All of *Inverter* plus
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|-----------|-------------|
|
||||
| powerACIn | Number:Power | Power fed into battery
|
||||
| workACIn | Number:Energy | Energy fed into battery
|
||||
| stateOfCharge | Number | Charging state of battery in percent
|
||||
| stateOfHealth | Number | Internal health metric in percent
|
||||
| temperatureBattery | Number:Temperature | Temperature of the battery in celsius
|
||||
| modeConverter | Switch | Current mode of converter. *ON* or *OFF*
|
||||
| voltageBatteryCellMin | Number:Voltage | minimum voltage of all batteries
|
||||
| voltageBatteryCellMean | Number:Voltage | mean voltage of all batteries
|
||||
| voltageBatteryCellMax | Number:Voltage | maximum voltage of all batteries
|
||||
|
||||
### EVStation, KebaEv
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|-----------|-------------|
|
||||
| powerACIn | Number:Power | Power consumed by the charger
|
||||
| workACIn | Number:Energy | Energy consumed by the charger
|
||||
| workACInSession | Number:Energy | Work consumed during current/last charging session
|
||||
| modeStation | String | Current mode of the charger. One off *STANDBY*, *CHARGING*, *OFF*
|
||||
| connectivityStatus | String | Current state of the charging connection. One off *ONLINE* or *OFFLINE*
|
||||
|
||||
### GridFlow
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|-----------|-------------|
|
||||
| feedInLimit | Number:Dimensionless | Current derating setting in percent
|
||||
|
||||
## Example
|
||||
|
||||
demo.things:
|
||||
|
||||
```
|
||||
Bridge solarwatt:energymanager:56f4ac2fa2 [hostname="192.168.0.64", refresh=30, rescan=5]
|
||||
// the individual things configured with their energy manager guid
|
||||
Thing solarwatt:batteryconverter:56f4ac2fa2:5c7d5929-8fa4-42c5-8737-48bef77b61f5 [guid="5c7d5929-8fa4-42c5-8737-48bef77b61f5"] (solarwatt:energymanager:56f4ac2fa2)
|
||||
Thing solarwatt:gridflow:56f4ac2fa2:urn-kiwigrid-gridflow-ERC05-000008007 [guid="urn:kiwigrid:gridflow:ERC05-000008007"] (solarwatt:energymanager:56f4ac2fa2)
|
||||
Thing solarwatt:evstation:56f4ac2fa2:urn-keba-evstation-20652876 [guid="urn:keba:evstation:2065287"] (solarwatt:energymanager:56f4ac2fa2)
|
||||
```
|
||||
|
||||
demo.items:
|
||||
|
||||
```
|
||||
// Location DeviceClass com.kiwigrid.devices.location.Location Guid b4e4978b96404e61977bfacd3eab299d
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerBuffered "PowerBuffered [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerBuffered"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerBufferedFromGrid "PowerBufferedFromGrid [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerBufferedFromGrid"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerBufferedFromProducers "PowerBufferedFromProducers [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerBufferedFromProducers"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerConsumed "PowerConsumed [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerConsumed"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerConsumedUnmetered "PowerConsumedUnmetered [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:PowerConsumedUnmetered"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerDirectConsumed "PowerDirectConsumed [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerDirectConsumed"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerConsumedFromGrid "PowerConsumedFromGrid [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerConsumedFromGrid"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerConsumedFromStorage "PowerConsumedFromStorage [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerConsumedFromStorage"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerConsumedFromProducers "PowerConsumedFromProducers [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerConsumedFromProducers"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerIn "PowerIn [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerIn"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerProduced "PowerProduced [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerProduced"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerOut "PowerOut [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerOut"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerOutFromProducers "PowerOutFromProducers [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerOutFromProducers"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerOutFromStorage "PowerOutFromStorage [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerOutFromStorage"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerReleased "PowerReleased [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerReleased"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerSelfConsumed "PowerSelfConsumed [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerSelfConsumed"}
|
||||
Number:Power Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_PowerSelfSupplied "PowerSelfSupplied [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:powerSelfSupplied"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkBuffered "WorkBuffered [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workBuffered"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkBufferedFromGrid "WorkBufferedFromGrid [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workBufferedFromGrid"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkBufferedFromProducers "WorkBufferedFromProducers [%.2f Wh]" <energy> [""] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workBufferedFromProducers"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkConsumed "WorkConsumed [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workConsumed"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkConsumedUnmetered "WorkConsumedUnmetered [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:WorkConsumedUnmetered"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkDirectConsumed "WorkDirectConsumed [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workDirectConsumed"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkConsumedFromGrid "WorkConsumedFromGrid [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workConsumedFromGrid"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkConsumedFromStorage "WorkConsumedFromStorage [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workConsumedFromStorage"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkConsumedFromProducers "WorkConsumedFromProducers [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workConsumedFromProducers"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkIn "WorkIn [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workIn"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkProduced "WorkProduced [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workProduced"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkOut "WorkOut [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workOut"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkOutFromProducers "WorkOutFromProducers [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workOutFromProducers"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkOutFromStorage "WorkOutFromStorage [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workOutFromStorage"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkReleased "WorkReleased [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workReleased"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkSelfConsumed "WorkSelfConsumed [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workSelfConsumed"}
|
||||
Number:Energy Solarwatt_Location_b4e4978b96404e61977bfacd3eab299d_WorkSelfSupplied "WorkSelfSupplied [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:location:56f4ac2fa2:b4e4978b-9640-4e61-977b-facd3eab299d:workSelfSupplied"}
|
||||
|
||||
// Inverter Fronius com.kiwigrid.devices.inverter.Inverter
|
||||
Number:Power Solarwatt_Inverter_UrnSunspecFroniusInverter31414368_PowerACOut "PowerACOut [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:inverter:56f4ac2fa2:urn-sunspec-fronius-inverter-31414368:powerACOut"}
|
||||
Number:Power Solarwatt_Inverter_UrnSunspecFroniusInverter31414368_PowerACOutLimit "PowerACOutLimit [%.2f W]" <energy> ["Point", "Power"] {channel="solarwatt:inverter:56f4ac2fa2:urn-sunspec-fronius-inverter-31414368:powerACOutLimit"}
|
||||
Number:Energy Solarwatt_Inverter_UrnSunspecFroniusInverter31414368_WorkACOut "WorkACOut [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:inverter:56f4ac2fa2:urn-sunspec-fronius-inverter-31414368:workACOut"}
|
||||
|
||||
// MyReserve BatteryInverter com.kiwigrid.devices.bat…verter.BatteryConverter
|
||||
Switch Solarwatt_BatteryInverter_5c7d59298fa442c5873748bef77b61f5_ModeConverter "ModeConverter [%s]" <switch> ["Switch"] {channel="solarwatt:batteryconverter:56f4ac2fa2:5c7d5929-8fa4-42c5-8737-48bef77b61f5:modeConverter"}
|
||||
Number Solarwatt_BatteryInverter_5c7d59298fa442c5873748bef77b61f5_StateOfCharge "StateOfCharge [%.2f %%]" <status> ["Status"] {channel="solarwatt:batteryconverter:56f4ac2fa2:5c7d5929-8fa4-42c5-8737-48bef77b61f5:stateOfCharge"}
|
||||
Number Solarwatt_BatteryInverter_5c7d59298fa442c5873748bef77b61f5_StateOfHealth "StateOfHealth [%.2f %%]" <status> ["Status"] {channel="solarwatt:batteryconverter:56f4ac2fa2:5c7d5929-8fa4-42c5-8737-48bef77b61f5:stateOfHealth"}
|
||||
Number:Temperature Solarwatt_BatteryInverter_5c7d59298fa442c5873748bef77b61f5_TemperatureBattery "TemperatureBattery [%.1f °C]" <temperature> ["Measurement", "Temperature"] {channel="solarwatt:batteryconverter:56f4ac2fa2:5c7d5929-8fa4-42c5-8737-48bef77b61f5:temperatureBattery"}
|
||||
Number:Power Solarwatt_BatteryInverter_5c7d59298fa442c5873748bef77b61f5_PowerACIn "PowerACIn [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:batteryconverter:56f4ac2fa2:5c7d5929-8fa4-42c5-8737-48bef77b61f5:powerACIn"}
|
||||
Number:Power Solarwatt_BatteryInverter_5c7d59298fa442c5873748bef77b61f5_PowerACOut "PowerACOut [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:batteryconverter:56f4ac2fa2:5c7d5929-8fa4-42c5-8737-48bef77b61f5:powerACOut"}
|
||||
Number:Energy Solarwatt_BatteryInverter_5c7d59298fa442c5873748bef77b61f5_WorkACIn "WorkACIn [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:batteryconverter:56f4ac2fa2:5c7d5929-8fa4-42c5-8737-48bef77b61f5:workACIn"}
|
||||
Number:Energy Solarwatt_BatteryInverter_5c7d59298fa442c5873748bef77b61f5_WorkACOut "WorkACOut [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:batteryconverter:56f4ac2fa2:5c7d5929-8fa4-42c5-8737-48bef77b61f5:workACOut"}
|
||||
|
||||
// S0Bus Meter com.kiwigrid.devices.powermeter.PowerMeter / com.kiwigrid.devices.s0counter.S0Counter
|
||||
String Solarwatt_Meter_46bb4ee8a9744ecea11ef43c68263ae9_DirectionMetering "DirectionMetering [%s]" <status> ["Status"] {channel="solarwatt:powermeter:56f4ac2fa2:46bb4ee8-a974-4ece-a11e-f43c68263ae9:directionMetering"}
|
||||
Number:Power Solarwatt_Meter_46bb4ee8a9744ecea11ef43c68263ae9_PowerIn "PowerIn [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:powermeter:56f4ac2fa2:46bb4ee8-a974-4ece-a11e-f43c68263ae9:powerIn"}
|
||||
Number:Energy Solarwatt_Meter_46bb4ee8a9744ecea11ef43c68263ae9_WorkIn "WorkIn [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:powermeter:56f4ac2fa2:46bb4ee8-a974-4ece-a11e-f43c68263ae9:workIn"}
|
||||
Number:Energy Solarwatt_Meter_46bb4ee8a9744ecea11ef43c68263ae9_ConsumptionEnergySum "ConsumptionEnergySum [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:powermeter:56f4ac2fa2:46bb4ee8-a974-4ece-a11e-f43c68263ae9:consumptionEnergySum"}
|
||||
|
||||
// MyReservePowermeter Meter com.kiwigrid.devices.powermeter.PowerMeter
|
||||
String Solarwatt_Meter_2c5d089b98854f40ba8a3303bfb53e36_DirectionMetering "DirectionMetering [%s]" <status> ["Status"] {channel="solarwatt:powermeter:56f4ac2fa2:2c5d089b-9885-4f40-ba8a-3303bfb53e36:directionMetering"}
|
||||
Number:Power Solarwatt_Meter_2c5d089b98854f40ba8a3303bfb53e36_PowerIn "PowerIn [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:powermeter:56f4ac2fa2:2c5d089b-9885-4f40-ba8a-3303bfb53e36:powerIn"}
|
||||
Number:Power Solarwatt_Meter_2c5d089b98854f40ba8a3303bfb53e36_PowerOut "PowerOut [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:powermeter:56f4ac2fa2:2c5d089b-9885-4f40-ba8a-3303bfb53e36:powerOut"}
|
||||
Number:Energy Solarwatt_Meter_2c5d089b98854f40ba8a3303bfb53e36_WorkIn "WorkIn [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:powermeter:56f4ac2fa2:2c5d089b-9885-4f40-ba8a-3303bfb53e36:workIn"}
|
||||
Number:Energy Solarwatt_Meter_2c5d089b98854f40ba8a3303bfb53e36_WorkOut "WorkOut [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:powermeter:56f4ac2fa2:2c5d089b-9885-4f40-ba8a-3303bfb53e36:workOut"}
|
||||
|
||||
// Inverter MyReserve com.kiwigrid.devices.inverter.Inverter
|
||||
Number:Power Solarwatt_Inverter_4af659938b1149408a77ff87556389f3_PowerACOut "PowerACOut [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:inverter:56f4ac2fa2:4af65993-8b11-4940-8a77-ff87556389f3:powerACOut"}
|
||||
Number:Energy Solarwatt_Inverter_4af659938b1149408a77ff87556389f3_WorkACOut "WorkACOut [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:inverter:56f4ac2fa2:4af65993-8b11-4940-8a77-ff87556389f3:workACOut"}
|
||||
|
||||
// EVStation Keba com.kiwigrid.devices.evstation.EVStation
|
||||
String Solarwatt_EVStation_UrnKebaEvstation20652876_ModeStation "ModeStation [%s]" <status> ["Status"] {channel="solarwatt:evstation:56f4ac2fa2:urn-keba-evstation-20652876:modeStation"}
|
||||
String Solarwatt_EVStation_UrnKebaEvstation20652876_ConnectivityStatus "ConnectivityStatus [%s]" <status> ["Status"] {channel="solarwatt:evstation:56f4ac2fa2:urn-keba-evstation-20652876:connectivityStatus"}
|
||||
Number:Power Solarwatt_EVStation_UrnKebaEvstation20652876_PowerACIn "PowerACIn [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:evstation:56f4ac2fa2:urn-keba-evstation-20652876:powerACIn"}
|
||||
Number:Energy Solarwatt_EVStation_UrnKebaEvstation20652876_WorkACIn "WorkACIn [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:evstation:56f4ac2fa2:urn-keba-evstation-20652876:workACIn"}
|
||||
Number:Energy Solarwatt_EVStation_UrnKebaEvstation20652876_WorkACInSession "WorkACInSession [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:evstation:56f4ac2fa2:urn-keba-evstation-20652876:workACInSession"}
|
||||
|
||||
// PVPlant com.kiwigrid.devices.pvplant.PVPlant
|
||||
Number:Power Solarwatt_PVPlant_4575c19cfa0a4f21839a5db2ae06b4d_PowerACOut "PowerACOut [%.2f W]" <energy> ["Measurement", "Power"] {channel="solarwatt:pvplant:56f4ac2fa2:4575c19c-fa0a-4f21-839a-5db2ae06b4dc:powerACOut"}
|
||||
Number:Energy Solarwatt_PVPlant_4575c19cfa0a4f21839a5db2ae06b4d_WorkACOut "WorkACOut [%.2f Wh]" <energy> ["Measurement", "Energy"] {channel="solarwatt:pvplant:56f4ac2fa2:4575c19c-fa0a-4f21-839a-5db2ae06b4dc:workACOut"}
|
||||
|
||||
// Manager com.kiwigrid.devices.em.EnergyManager
|
||||
String Solarwatt_Manager_ERC05000008007_IdFirmware "IdFirmware [%s]" <status> ["Status"] {channel="solarwatt:energymanager:56f4ac2fa2:idFirmware"}
|
||||
Number Solarwatt_Manager_ERC05000008007_Timestamp "Timestamp [%d]" <time> ["Status", "Timestamp"] {channel="solarwatt:energymanager:56f4ac2fa2:timestamp"}
|
||||
DateTime Solarwatt_Manager_ERC05000008007_Datetime "Update [%1$tH:%1$tM:%1$tS]" <time> ["Status", "Timestamp"] {channel="solarwatt:energymanager:56f4ac2fa2:datetime"}
|
||||
Number Solarwatt_Manager_ERC05000008007_FractionCPULoadTotal "FractionCPULoadUser [%.2f]" <status> ["Measurement"] {channel="solarwatt:energymanager:56f4ac2fa2:fractionCPULoadTotal"}
|
||||
Number Solarwatt_Manager_ERC05000008007_FractionCPULoadUser "FractionCPULoadUser [%.2f]" <status> ["Measurement"] {channel="solarwatt:energymanager:56f4ac2fa2:fractionCPULoadUser"}
|
||||
Number Solarwatt_Manager_ERC05000008007_FractionCPULoadKernel "FractionCPULoadKernel [%.2f]" <status> ["Measurement"] {channel="solarwatt:energymanager:56f4ac2fa2:fractionCPULoadKernel"}
|
||||
Number Solarwatt_Manager_ERC05000008007_FractionCPULoadAverageLastMinute "FractionCPULoadAverageLastMinute [%.2f]" <status> ["Measurement"] {channel="solarwatt:energymanager:56f4ac2fa2:fractionCPULoadAverageLastMinute"}
|
||||
Number Solarwatt_Manager_ERC05000008007_FractionCPULoadAverageLastFiveMinutes "FractionCPULoadAverageLastFiveMinutes [%.2f]" <status> ["Measurement"] {channel="solarwatt:energymanager:56f4ac2fa2:fractionCPULoadAverageLastFiveMinutes"}
|
||||
Number Solarwatt_Manager_ERC05000008007_FractionCPULoadAverageLastFifteenMinutes "FractionCPULoadAverageLastFifteenMinutes [%.2f]" <status> ["Measurement"] {channel="solarwatt:energymanager:56f4ac2fa2:fractionCPULoadAverageLastFifteenMinutes"}
|
||||
|
||||
// Gridflow com.kiwigrid.kiwiapp.gridflow.GridFlow
|
||||
Number Solarwatt_Gridflow_UrnKiwigridGridflowERC05000008007_CurrentLimit "CurrentLimit [%d A]" <energy> ["Point"] {channel="solarwatt:gridflow:56f4ac2fa2:urn-kiwigrid-gridflow-ERC05-000008007:currentLimit"}
|
||||
Number Solarwatt_Gridflow_UrnKiwigridGridflowERC05000008007_FeedInLimit "FeedInLimit [%d %%]" <status> ["Point"] {channel="solarwatt:gridflow:56f4ac2fa2:urn-kiwigrid-gridflow-ERC05-000008007:feedInLimit"}
|
||||
```
|
17
bundles/org.openhab.binding.solarwatt/pom.xml
Normal file
17
bundles/org.openhab.binding.solarwatt/pom.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.solarwatt</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Solarwatt Binding</name>
|
||||
|
||||
</project>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.solarwatt-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-solarwatt" description="Solarwatt Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.solarwatt/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -0,0 +1,122 @@
|
||||
/**
|
||||
* 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.solarwatt.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.SolarwattTag;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link SolarwattBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SolarwattBindingConstants {
|
||||
|
||||
private SolarwattBindingConstants() {
|
||||
}
|
||||
|
||||
public static final String BINDING_ID = "solarwatt";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_ENERGY_MANAGER = new ThingTypeUID(BINDING_ID, "energymanager");
|
||||
public static final ThingTypeUID THING_TYPE_INVERTER = new ThingTypeUID(BINDING_ID, "inverter");
|
||||
public static final ThingTypeUID THING_TYPE_LOCATION = new ThingTypeUID(BINDING_ID, "location");
|
||||
public static final ThingTypeUID THING_TYPE_BATTERYCONVERTER = new ThingTypeUID(BINDING_ID, "batteryconverter");
|
||||
public static final ThingTypeUID THING_TYPE_POWERMETER = new ThingTypeUID(BINDING_ID, "powermeter");
|
||||
public static final ThingTypeUID THING_TYPE_EVSTATION = new ThingTypeUID(BINDING_ID, "evstation");
|
||||
public static final ThingTypeUID THING_TYPE_PVPLANT = new ThingTypeUID(BINDING_ID, "pvplant");
|
||||
public static final ThingTypeUID THING_TYPE_GRIDFLOW = new ThingTypeUID(BINDING_ID, "gridflow");
|
||||
|
||||
public static final String PROPERTY_ID_NAME = "IdName";
|
||||
public static final String PROPERTY_ID_FIRMWARE = "IdFirmware";
|
||||
public static final String PROPERTY_ID_MANUFACTURER = "IdManufacturer";
|
||||
|
||||
// List of all Channel ids, taken from the tagNames
|
||||
public static final SolarwattTag CHANNEL_WORK_AC_OUT = new SolarwattTag("WorkACOut");
|
||||
public static final SolarwattTag CHANNEL_WORK_AC_IN = new SolarwattTag("WorkACIn");
|
||||
public static final SolarwattTag CHANNEL_WORK_AC_IN_SESSION = new SolarwattTag("WorkACInSession");
|
||||
public static final SolarwattTag CHANNEL_POWER_INSTALLED_PEAK = new SolarwattTag("PowerInstalledPeak");
|
||||
public static final SolarwattTag CHANNEL_POWER_AC_OUT_MAX = new SolarwattTag("PowerACOutMax");
|
||||
public static final SolarwattTag CHANNEL_POWER_AC_OUT = new SolarwattTag("PowerACOut");
|
||||
public static final SolarwattTag CHANNEL_POWER_AC_IN = new SolarwattTag("PowerACIn");
|
||||
public static final SolarwattTag CHANNEL_POWER_AC_OUT_LIMIT = new SolarwattTag("PowerACOutLimit");
|
||||
public static final SolarwattTag CHANNEL_DIRECTION_METERING = new SolarwattTag("DirectionMetering");
|
||||
public static final SolarwattTag CHANNEL_POWER_IN = new SolarwattTag("PowerIn");
|
||||
public static final SolarwattTag CHANNEL_POWER_OUT = new SolarwattTag("PowerOut");
|
||||
public static final SolarwattTag CHANNEL_WORK_IN = new SolarwattTag("WorkIn");
|
||||
public static final SolarwattTag CHANNEL_WORK_OUT = new SolarwattTag("WorkOut");
|
||||
public static final SolarwattTag CHANNEL_CONSUMPTION_ENERGY_SUM = new SolarwattTag("ConsumptionEnergySum");
|
||||
public static final SolarwattTag CHANNEL_MODE_STATION = new SolarwattTag("ModeStation");
|
||||
public static final SolarwattTag CHANNEL_CONNECTIVITY_STATUS = new SolarwattTag("ConnectivityStatus");
|
||||
public static final SolarwattTag CHANNEL_TIMESTAMP = new SolarwattTag("Timestamp");
|
||||
public static final SolarwattTag CHANNEL_DATETIME = new SolarwattTag("Datetime");
|
||||
public static final SolarwattTag CHANNEL_IDTIMEZONE = new SolarwattTag("IdTimezone");
|
||||
public static final SolarwattTag CHANNEL_FRACTION_CPU_LOAD_TOTAL = new SolarwattTag("FractionCPULoadTotal");
|
||||
public static final SolarwattTag CHANNEL_FRACTION_CPU_LOAD_USER = new SolarwattTag("FractionCPULoadUser");
|
||||
public static final SolarwattTag CHANNEL_FRACTION_CPU_LOAD_KERNEL = new SolarwattTag("FractionCPULoadKernel");
|
||||
public static final SolarwattTag CHANNEL_FRACTION_CPU_LOAD_AVERAGE_LAST_MINUTE = new SolarwattTag(
|
||||
"FractionCPULoadAverageLastMinute");
|
||||
public static final SolarwattTag CHANNEL_FRACTION_CPU_LOAD_AVERAGE_LAST_FIVE_MINUTES = new SolarwattTag(
|
||||
"FractionCPULoadAverageLastFiveMinutes");
|
||||
public static final SolarwattTag CHANNEL_FRACTION_CPU_LOAD_AVERAGE_LAST_FIFTEEN_MINUTES = new SolarwattTag(
|
||||
"FractionCPULoadAverageLastFifteenMinutes");
|
||||
public static final SolarwattTag CHANNEL_MODE_CONVERTER = new SolarwattTag("ModeConverter");
|
||||
public static final SolarwattTag CHANNEL_STATE_OF_CHARGE = new SolarwattTag("StateOfCharge");
|
||||
public static final SolarwattTag CHANNEL_STATE_OF_HEALTH = new SolarwattTag("StateOfHealth");
|
||||
public static final SolarwattTag CHANNEL_TEMPERATURE_BATTERY = new SolarwattTag("TemperatureBattery");
|
||||
public static final SolarwattTag CHANNEL_POWER_BUFFERED = new SolarwattTag("PowerBuffered");
|
||||
public static final SolarwattTag CHANNEL_POWER_BUFFERED_FROM_GRID = new SolarwattTag("PowerBufferedFromGrid");
|
||||
public static final SolarwattTag CHANNEL_POWER_BUFFERED_FROM_PRODUCERS = new SolarwattTag(
|
||||
"PowerBufferedFromProducers");
|
||||
public static final SolarwattTag CHANNEL_POWER_CONSUMED = new SolarwattTag("PowerConsumed");
|
||||
public static final SolarwattTag CHANNEL_POWER_CONSUMED_UNMETERED = new SolarwattTag("PowerConsumedUnmetered");
|
||||
public static final SolarwattTag CHANNEL_POWER_CONSUMED_FROM_GRID = new SolarwattTag("PowerConsumedFromGrid");
|
||||
public static final SolarwattTag CHANNEL_POWER_CONSUMED_FROM_STORAGE = new SolarwattTag("PowerConsumedFromStorage");
|
||||
public static final SolarwattTag CHANNEL_POWER_CONSUMED_FROM_PRODUCERS = new SolarwattTag(
|
||||
"PowerConsumedFromProducers");
|
||||
public static final SolarwattTag CHANNEL_POWER_PRODUCED = new SolarwattTag("PowerProduced");
|
||||
public static final SolarwattTag CHANNEL_POWER_OUT_FROM_PRODUCERS = new SolarwattTag("PowerOutFromProducers");
|
||||
public static final SolarwattTag CHANNEL_POWER_OUT_FROM_STORAGE = new SolarwattTag("PowerOutFromStorage");
|
||||
public static final SolarwattTag CHANNEL_POWER_RELEASED = new SolarwattTag("PowerReleased");
|
||||
public static final SolarwattTag CHANNEL_POWER_SELF_CONSUMED = new SolarwattTag("PowerSelfConsumed");
|
||||
public static final SolarwattTag CHANNEL_POWER_DIRECT_CONSUMED = new SolarwattTag("PowerDirectConsumed");
|
||||
public static final SolarwattTag CHANNEL_POWER_SELF_SUPPLIED = new SolarwattTag("PowerSelfSupplied");
|
||||
public static final SolarwattTag CHANNEL_WORK_BUFFERED = new SolarwattTag("WorkBuffered");
|
||||
public static final SolarwattTag CHANNEL_WORK_BUFFERED_FROM_GRID = new SolarwattTag("WorkBufferedFromGrid");
|
||||
public static final SolarwattTag CHANNEL_WORK_BUFFERED_FROM_PRODUCERS = new SolarwattTag(
|
||||
"WorkBufferedFromProducers");
|
||||
public static final SolarwattTag CHANNEL_WORK_CONSUMED = new SolarwattTag("WorkConsumed");
|
||||
public static final SolarwattTag CHANNEL_WORK_CONSUMED_UNMETERED = new SolarwattTag("WorkConsumedUnmetered");
|
||||
public static final SolarwattTag CHANNEL_WORK_CONSUMED_FROM_GRID = new SolarwattTag("WorkConsumedFromGrid");
|
||||
public static final SolarwattTag CHANNEL_WORK_CONSUMED_FROM_STORAGE = new SolarwattTag("WorkConsumedFromStorage");
|
||||
public static final SolarwattTag CHANNEL_WORK_CONSUMED_FROM_PRODUCERS = new SolarwattTag(
|
||||
"WorkConsumedFromProducers");
|
||||
public static final SolarwattTag CHANNEL_WORK_PRODUCED = new SolarwattTag("WorkProduced");
|
||||
public static final SolarwattTag CHANNEL_WORK_OUT_FROM_PRODUCERS = new SolarwattTag("WorkOutFromProducers");
|
||||
public static final SolarwattTag CHANNEL_WORK_OUT_FROM_STORAGE = new SolarwattTag("WorkOutFromStorage");
|
||||
public static final SolarwattTag CHANNEL_WORK_RELEASED = new SolarwattTag("WorkReleased");
|
||||
public static final SolarwattTag CHANNEL_WORK_SELF_CONSUMED = new SolarwattTag("WorkSelfConsumed");
|
||||
public static final SolarwattTag CHANNEL_WORK_DIRECT_CONSUMED = new SolarwattTag("WorkDirectConsumed");
|
||||
public static final SolarwattTag CHANNEL_WORK_SELF_SUPPLIED = new SolarwattTag("WorkSelfSupplied");
|
||||
public static final SolarwattTag CHANNEL_CURRENT_LIMIT = new SolarwattTag("CurrentLimit");
|
||||
public static final SolarwattTag CHANNEL_FEED_IN_LIMIT = new SolarwattTag("FeedInLimit");
|
||||
public static final SolarwattTag CHANNEL_VOLTAGE_BATTERY_CELL_MAX = new SolarwattTag("VoltageBatteryCellMax");
|
||||
public static final SolarwattTag CHANNEL_VOLTAGE_BATTERY_CELL_MIN = new SolarwattTag("VoltageBatteryCellMin");
|
||||
public static final SolarwattTag CHANNEL_VOLTAGE_BATTERY_CELL_MEAN = new SolarwattTag("VoltageBatteryCellMean");
|
||||
|
||||
// thing configuration and properties keys
|
||||
public static final String THING_PROPERTIES_GUID = "guid";
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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.solarwatt.internal;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.solarwatt.internal.channel.SolarwattChannelTypeProvider;
|
||||
import org.openhab.binding.solarwatt.internal.handler.EnergyManagerHandler;
|
||||
import org.openhab.binding.solarwatt.internal.handler.LocationHandler;
|
||||
import org.openhab.binding.solarwatt.internal.handler.SimpleDeviceHandler;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link SolarwattHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.solarwatt", service = ThingHandlerFactory.class)
|
||||
public class SolarwattHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_ENERGY_MANAGER,
|
||||
THING_TYPE_INVERTER, THING_TYPE_POWERMETER, THING_TYPE_EVSTATION, THING_TYPE_BATTERYCONVERTER,
|
||||
THING_TYPE_LOCATION, THING_TYPE_PVPLANT, THING_TYPE_GRIDFLOW);
|
||||
|
||||
private final HttpClient commonHttpClient;
|
||||
private final SolarwattChannelTypeProvider channelTypeProvider;
|
||||
|
||||
@Activate
|
||||
public SolarwattHandlerFactory(final @Reference HttpClientFactory httpClientFactory,
|
||||
final @Reference SolarwattChannelTypeProvider channelTypeProvider) {
|
||||
this.commonHttpClient = httpClientFactory.getCommonHttpClient();
|
||||
this.channelTypeProvider = channelTypeProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (THING_TYPE_ENERGY_MANAGER.equals(thingTypeUID)) {
|
||||
// energy manager is a separate device as it is the bridge
|
||||
return new EnergyManagerHandler((Bridge) thing, this.channelTypeProvider, this.commonHttpClient);
|
||||
} else if (THING_TYPE_LOCATION.equals(thingTypeUID)) {
|
||||
return new LocationHandler(thing, this.channelTypeProvider);
|
||||
} else if (this.supportsThingType(thingTypeUID)) {
|
||||
// standard device handling
|
||||
return new SimpleDeviceHandler(thing, this.channelTypeProvider);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.channel;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solarwatt.internal.SolarwattBindingConstants;
|
||||
import org.openhab.binding.solarwatt.internal.domain.SolarwattChannel;
|
||||
import org.openhab.core.library.CoreItemFactory;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.type.ChannelType;
|
||||
import org.openhab.core.thing.type.ChannelTypeBuilder;
|
||||
import org.openhab.core.thing.type.ChannelTypeProvider;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.thing.type.StateChannelTypeBuilder;
|
||||
import org.openhab.core.types.StateDescriptionFragmentBuilder;
|
||||
import org.openhab.core.types.util.UnitUtils;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* A {@link ChannelTypeProvider} that creates {@link ChannelType}s according to
|
||||
* the requested tags. It creates one {@link ChannelType} per tag value.
|
||||
*
|
||||
* @author Matthias Steigenberger - Initial contribution
|
||||
* @author Sven Carstens - Adapted to solarwatt binding
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = { ChannelTypeProvider.class, SolarwattChannelTypeProvider.class })
|
||||
public class SolarwattChannelTypeProvider implements ChannelTypeProvider {
|
||||
|
||||
private final Map<String, ChannelType> channelMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public Collection<ChannelType> getChannelTypes(@Nullable Locale locale) {
|
||||
return this.channelMap.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ChannelType getChannelType(ChannelTypeUID channelTypeUID, @Nullable Locale locale) {
|
||||
return this.channelMap.values().stream().filter(channelType -> channelType.getUID().equals(channelTypeUID))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the {@link ChannelType} matching our requirements exists.
|
||||
*
|
||||
* Only create once for each tagname supplied via {@link SolarwattChannel}.
|
||||
*
|
||||
* @param solarwattChannel channeltype requirements
|
||||
* @return UID of existing channeltype
|
||||
*/
|
||||
public ChannelTypeUID assertChannelType(SolarwattChannel solarwattChannel) {
|
||||
ChannelType existingChannel = this.channelMap.get(solarwattChannel.getChannelName());
|
||||
if (existingChannel == null) {
|
||||
ChannelType createdChannel = this.getChannelType(solarwattChannel);
|
||||
this.channelMap.put(solarwattChannel.getChannelName(), createdChannel);
|
||||
return createdChannel.getUID();
|
||||
} else {
|
||||
return existingChannel.getUID();
|
||||
}
|
||||
}
|
||||
|
||||
private ChannelType getChannelType(SolarwattChannel solarwattChannel) {
|
||||
StateChannelTypeBuilder stateDescriptionBuilder;
|
||||
Unit<?> unit = solarwattChannel.getUnit();
|
||||
if (unit != null) {
|
||||
if ("switch".equals(solarwattChannel.getCategory())) {
|
||||
stateDescriptionBuilder = ChannelTypeBuilder
|
||||
.state(new ChannelTypeUID(SolarwattBindingConstants.BINDING_ID,
|
||||
solarwattChannel.getChannelName()), solarwattChannel.getChannelName(),
|
||||
CoreItemFactory.SWITCH)
|
||||
.withCategory(solarwattChannel.getCategory()).isAdvanced(solarwattChannel.getAdvanced())
|
||||
.withStateDescriptionFragment(
|
||||
StateDescriptionFragmentBuilder.create().withReadOnly(true).build());
|
||||
} else {
|
||||
String dimension = ":" + UnitUtils.getDimensionName(unit);
|
||||
String unitString = unit.toString();
|
||||
|
||||
if (Units.PERCENT.equals(unit)) {
|
||||
// strangely it is Angle
|
||||
dimension = ":Dimensionless";
|
||||
unitString = "%%";
|
||||
}
|
||||
|
||||
stateDescriptionBuilder = ChannelTypeBuilder
|
||||
.state(new ChannelTypeUID(SolarwattBindingConstants.BINDING_ID,
|
||||
solarwattChannel.getChannelName()), solarwattChannel.getChannelName(),
|
||||
CoreItemFactory.NUMBER + dimension)
|
||||
.withCategory(solarwattChannel.getCategory()).isAdvanced(solarwattChannel.getAdvanced())
|
||||
.withStateDescriptionFragment(StateDescriptionFragmentBuilder.create().withReadOnly(true)
|
||||
.withPattern("%.2f " + unitString).build());
|
||||
}
|
||||
} else {
|
||||
stateDescriptionBuilder = ChannelTypeBuilder
|
||||
.state(new ChannelTypeUID(SolarwattBindingConstants.BINDING_ID, solarwattChannel.getChannelName()),
|
||||
solarwattChannel.getChannelName(), CoreItemFactory.STRING)
|
||||
.withCategory(solarwattChannel.getCategory()).isAdvanced(solarwattChannel.getAdvanced())
|
||||
.withStateDescriptionFragment(StateDescriptionFragmentBuilder.create().withReadOnly(true).build());
|
||||
}
|
||||
return stateDescriptionBuilder.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.configuration;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link SolarwattBridgeConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SolarwattBridgeConfiguration {
|
||||
private static final int DEFAULT_RESCAN_MINUTES = 5;
|
||||
private static final int DEFAULT_REFRESH_SECONDS = 30;
|
||||
|
||||
/**
|
||||
* Hostname or ip where the solarwatt energymanager is reachable.
|
||||
*
|
||||
* Energy manager does not set a default name via DHCP.
|
||||
*/
|
||||
public String hostname = "";
|
||||
|
||||
/**
|
||||
* Refresh interval for updating devices data
|
||||
*/
|
||||
public int refresh = DEFAULT_REFRESH_SECONDS;
|
||||
|
||||
/**
|
||||
* Refresh interval for reading of devices (not the devices data)
|
||||
*/
|
||||
public int rescan = DEFAULT_RESCAN_MINUTES;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.configuration;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link SolarwattThingConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SolarwattThingConfiguration {
|
||||
/**
|
||||
* Guid for the thing that is used by the energy manager
|
||||
*/
|
||||
public String guid = "";
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.BatteryConverter;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.Device;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.EVStation;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.GridFlow;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.Inverter;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.Location;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.PVPlant;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.PowerMeter;
|
||||
import org.openhab.binding.solarwatt.internal.handler.EnergyManagerHandler;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Discovery service to discover devices attached to the energy manager.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SolarwattDevicesDiscoveryService extends AbstractDiscoveryService
|
||||
implements ThingHandlerService, DiscoveryService {
|
||||
|
||||
private static final int TIMEOUT_SECONDS = 20;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SolarwattDevicesDiscoveryService.class);
|
||||
private @Nullable EnergyManagerHandler energyManagerHandler;
|
||||
|
||||
/**
|
||||
* Job which will do the background scanning
|
||||
*/
|
||||
private final EnergymanagerScan scanningRunnable;
|
||||
|
||||
/**
|
||||
* Schedule for scanning
|
||||
*/
|
||||
private @Nullable ScheduledFuture<?> scanningJob;
|
||||
|
||||
public SolarwattDevicesDiscoveryService() {
|
||||
super(TIMEOUT_SECONDS);
|
||||
this.scanningRunnable = new EnergymanagerScan();
|
||||
|
||||
this.activate(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(final @Nullable ThingHandler handler) {
|
||||
if (handler instanceof EnergyManagerHandler) {
|
||||
this.energyManagerHandler = (EnergyManagerHandler) handler;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return this.energyManagerHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
this.stopBackgroundDiscovery();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startBackgroundDiscovery() {
|
||||
ScheduledFuture<?> localScanningJob = this.scanningJob;
|
||||
if (localScanningJob == null || localScanningJob.isCancelled()) {
|
||||
this.scanningJob = this.scheduler.scheduleWithFixedDelay(this.scanningRunnable, 5, 5 * 60,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopBackgroundDiscovery() {
|
||||
ScheduledFuture<?> localScanningJob = this.scanningJob;
|
||||
if (localScanningJob != null && !localScanningJob.isCancelled()) {
|
||||
localScanningJob.cancel(true);
|
||||
this.scanningJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void startScan() {
|
||||
this.removeOlderResults(this.getTimestampOfLastScan());
|
||||
final EnergyManagerHandler localEnergyManagerHandler = this.energyManagerHandler;
|
||||
|
||||
if (localEnergyManagerHandler == null
|
||||
|| localEnergyManagerHandler.getThing().getStatus() != ThingStatus.ONLINE) {
|
||||
this.logger.warn("Energymanager handler not available: {}", localEnergyManagerHandler);
|
||||
return;
|
||||
}
|
||||
this.scanForDeviceThings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans for device things.
|
||||
*
|
||||
* Walks through the list of devices and adds discovery results for the supported devices.
|
||||
*/
|
||||
private void scanForDeviceThings() {
|
||||
EnergyManagerHandler localEnergyManagerHandler = this.energyManagerHandler;
|
||||
if (localEnergyManagerHandler != null) {
|
||||
final Map<String, Device> devices = localEnergyManagerHandler.getDevices();
|
||||
|
||||
final ThingUID bridgeUID = localEnergyManagerHandler.getThing().getUID();
|
||||
|
||||
if (devices == null) {
|
||||
this.logger.warn("No device data for solarwatt devices in discovery for energy manager {}.", bridgeUID);
|
||||
} else {
|
||||
devices.forEach((key, entry) -> {
|
||||
if (entry instanceof BatteryConverter) {
|
||||
this.discover(bridgeUID, entry, THING_TYPE_BATTERYCONVERTER);
|
||||
} else if (entry instanceof Inverter) {
|
||||
this.discover(bridgeUID, entry, THING_TYPE_INVERTER);
|
||||
} else if (entry instanceof PowerMeter) {
|
||||
this.discover(bridgeUID, entry, THING_TYPE_POWERMETER);
|
||||
} else if (entry instanceof EVStation) {
|
||||
this.discover(bridgeUID, entry, THING_TYPE_EVSTATION);
|
||||
} else if (entry instanceof Location) {
|
||||
this.discover(bridgeUID, entry, THING_TYPE_LOCATION);
|
||||
} else if (entry instanceof PVPlant) {
|
||||
this.discover(bridgeUID, entry, THING_TYPE_PVPLANT);
|
||||
} else if (entry instanceof GridFlow) {
|
||||
this.discover(bridgeUID, entry, THING_TYPE_GRIDFLOW);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a discovery result and add to result.
|
||||
*
|
||||
* @param bridgeID to which this device belongs
|
||||
* @param entry describing the device
|
||||
* @param typeUID for matching thing
|
||||
*/
|
||||
private void discover(final ThingUID bridgeID, final Device entry, final ThingTypeUID typeUID) {
|
||||
final ThingUID thingUID = new ThingUID(typeUID, bridgeID, this.rewriteGuid(entry.getGuid()));
|
||||
final Map<String, Object> properties = new HashMap<>(5);
|
||||
|
||||
properties.put(THING_PROPERTIES_GUID, entry.getGuid());
|
||||
final DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withBridge(bridgeID)
|
||||
.withRepresentationProperty(THING_PROPERTIES_GUID).withProperties(properties)
|
||||
.withLabel("Solarwatt " + entry.getLabel()).build();
|
||||
this.thingDiscovered(discoveryResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite energy manager guids to be acceptable to openhab.
|
||||
*
|
||||
* @param emGuid from energy manager
|
||||
* @return guid for openhab
|
||||
*/
|
||||
private String rewriteGuid(String emGuid) {
|
||||
return emGuid.replaceAll(":", "-");
|
||||
}
|
||||
|
||||
public class EnergymanagerScan implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
SolarwattDevicesDiscoveryService.this.startScan();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.EnergyManagerDTO;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.Device;
|
||||
import org.openhab.binding.solarwatt.internal.factory.EnergyManagerDevicesFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Collection of all devices known to the energy manager including the energy manager itself.
|
||||
*
|
||||
* The {@link Device}s are generated from the {@link DeviceDTO}s inside of the {@link EnergyManagerDTO}
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EnergyManagerCollection {
|
||||
private Logger logger = LoggerFactory.getLogger(EnergyManagerCollection.class);
|
||||
|
||||
private Map<String, Device> devices;
|
||||
|
||||
public EnergyManagerCollection(EnergyManagerDTO energyManagerDTO) {
|
||||
this.devices = new HashMap<>();
|
||||
|
||||
energyManagerDTO.getItems().forEach(deviceDTO -> {
|
||||
try {
|
||||
Device device = EnergyManagerDevicesFactory.getEnergyManagerDevice(deviceDTO);
|
||||
|
||||
if (device != null) {
|
||||
this.devices.put(device.getGuid(), device);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
this.logger.error("Error setting up initial device {}: {}", deviceDTO.getGuid(),
|
||||
deviceDTO.getDeviceModel(), ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Map<String, Device> getDevices() {
|
||||
return this.devices;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Aggregation of the interesting parts to write into a channel.
|
||||
*
|
||||
* From this the {@link ChannelType}s are created.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SolarwattChannel {
|
||||
private final String channelName;
|
||||
private final @Nullable Unit<?> unit;
|
||||
private final String category;
|
||||
private final Boolean advanced;
|
||||
|
||||
public SolarwattChannel(String channelName, String category) {
|
||||
this(channelName, category, false);
|
||||
}
|
||||
|
||||
public SolarwattChannel(String channelName, Unit<?> unit, String category) {
|
||||
this(channelName, unit, category, false);
|
||||
}
|
||||
|
||||
public SolarwattChannel(String channelName, String category, Boolean advanced) {
|
||||
this(channelName, null, category, advanced);
|
||||
}
|
||||
|
||||
public SolarwattChannel(String channelName, @Nullable Unit<?> unit, String category, Boolean advanced) {
|
||||
this.channelName = channelName;
|
||||
this.unit = unit;
|
||||
this.category = category;
|
||||
this.advanced = advanced;
|
||||
}
|
||||
|
||||
public String getChannelName() {
|
||||
return this.channelName;
|
||||
}
|
||||
|
||||
public @Nullable Unit<?> getUnit() {
|
||||
return this.unit;
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
return this.category;
|
||||
}
|
||||
|
||||
public Boolean getAdvanced() {
|
||||
return this.advanced;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Helper to handle different character cases between energy manager tagnames
|
||||
* and openhab channel names.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SolarwattTag {
|
||||
private final String tagName;
|
||||
private final String channelName;
|
||||
|
||||
public SolarwattTag(String tagName) {
|
||||
this.tagName = tagName;
|
||||
char chars[] = tagName.toCharArray();
|
||||
chars[0] = Character.toLowerCase(chars[0]);
|
||||
this.channelName = new String(chars);
|
||||
}
|
||||
|
||||
public String getTagName() {
|
||||
return this.tagName;
|
||||
}
|
||||
|
||||
public String getChannelName() {
|
||||
return this.channelName;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.converter;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
/**
|
||||
* Interface bundling all converters from JsonElement to openhab State.
|
||||
*
|
||||
* We do not implement the interface but only pass closures.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface JsonStateConverter {
|
||||
State convert(JsonElement jsonElement);
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.dto;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solarwatt.internal.domain.converter.JsonStateConverter;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
/**
|
||||
* DTO class for the devices returned by the energy manager.
|
||||
*
|
||||
* Properties without setters are only filled by gson JSON parsing.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
public class DeviceDTO {
|
||||
private final Logger logger = LoggerFactory.getLogger(DeviceDTO.class);
|
||||
|
||||
private String guid;
|
||||
private Collection<DeviceModel> deviceModel;
|
||||
private Map<String, TagValueDTO> tagValues;
|
||||
|
||||
public String getGuid() {
|
||||
return this.guid;
|
||||
}
|
||||
|
||||
public Collection<String> getDeviceModelStrings() {
|
||||
return this.deviceModel.stream().map(DeviceModel::getDeviceClass).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Collection<DeviceModel> getDeviceModel() {
|
||||
return this.deviceModel;
|
||||
}
|
||||
|
||||
public Map<String, TagValueDTO> getTagValues() {
|
||||
return this.tagValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get a string value from the list of tag values.
|
||||
*
|
||||
* @param tagName name of tag to read
|
||||
* @return tag value
|
||||
*/
|
||||
public @Nullable String getStringTag(String tagName) {
|
||||
JsonPrimitive jsonPrimitive = this.getJsonPrimitiveFromTag(tagName);
|
||||
if (jsonPrimitive != null) {
|
||||
return jsonPrimitive.getAsString();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get a {@link JsonPrimitive} from the list of tag values.
|
||||
*
|
||||
* The primitves are later converted to the desired target type.
|
||||
*
|
||||
* @param tagName name of tag to read
|
||||
* @return raw json from tag value
|
||||
*/
|
||||
protected @Nullable JsonPrimitive getJsonPrimitiveFromTag(String tagName) {
|
||||
Map<String, TagValueDTO> localTagValues = this.getTagValues();
|
||||
if (localTagValues != null) {
|
||||
TagValueDTO localTag = localTagValues.get(tagName);
|
||||
if (localTag != null && localTag.getValue().isJsonPrimitive()) {
|
||||
return (JsonPrimitive) localTag.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get a {@link JsonObject} from the list of tag values.
|
||||
*
|
||||
* The objects are used by the concrete devices to read interesting
|
||||
* but deeply nested values.
|
||||
*
|
||||
* @param tagName name of tag to read
|
||||
* @return raw json from tag value
|
||||
*/
|
||||
public @Nullable JsonObject getJsonObjectFromTag(String tagName) {
|
||||
Map<String, TagValueDTO> localTagValues = this.getTagValues();
|
||||
if (localTagValues != null) {
|
||||
TagValueDTO localTag = localTagValues.get(tagName);
|
||||
if (localTag != null && localTag.getValue().isJsonObject()) {
|
||||
return (JsonObject) localTag.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get a {@link JsonObject} from a tag value which contains JSON.
|
||||
*
|
||||
* The objects are used by the concrete devices to read interesting
|
||||
* but deeply nested values.
|
||||
*
|
||||
* @param tagName name of tag to read
|
||||
* @return raw json from tag value
|
||||
*/
|
||||
public JsonPrimitive getJsonPrimitiveFromPath(String tagName, String path) {
|
||||
JsonElement jsonElement = this.getJsonFromPath(tagName, path);
|
||||
|
||||
if (jsonElement != null && jsonElement.isJsonPrimitive()) {
|
||||
return (JsonPrimitive) jsonElement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get a {@link JsonObject} from a tag value which contains JSON.
|
||||
*
|
||||
* The json path is traversed according to the supplied path. Only simple pathes
|
||||
* are supported.
|
||||
*
|
||||
* @param tagName name of tag to read
|
||||
* @return raw json from tag value
|
||||
*/
|
||||
public JsonElement getJsonFromPath(String tagName, String path) {
|
||||
JsonObject json = this.getJsonObjectFromTag(tagName);
|
||||
if (json != null) {
|
||||
String[] parts = path.split("\\.|\\[|\\]");
|
||||
JsonElement result = json;
|
||||
|
||||
for (String key : parts) {
|
||||
|
||||
key = key.trim();
|
||||
if (key.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
result = JsonNull.INSTANCE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result.isJsonObject()) {
|
||||
result = ((JsonObject) result).get(key);
|
||||
} else if (result.isJsonArray()) {
|
||||
int ix = Integer.valueOf(key) - 1;
|
||||
result = ((JsonArray) result).get(ix);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a value from a tag to a state.
|
||||
*
|
||||
* @param converter applied the the {@link JsonPrimitive}
|
||||
* @param tagName to find value
|
||||
* @return state for channel
|
||||
*/
|
||||
public State getState(JsonStateConverter converter, String tagName) {
|
||||
return this.getState(converter, tagName, tagName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a value specified via JSON path from a tag to a state.
|
||||
*
|
||||
* @param converter applied the the {@link JsonPrimitive}
|
||||
* @param channelName for the state
|
||||
* @param tagName to find value
|
||||
* @param jsonPath to find value
|
||||
* @return state for channel
|
||||
*/
|
||||
public State getState(JsonStateConverter converter, String channelName, String tagName, String jsonPath) {
|
||||
State state = UnDefType.UNDEF;
|
||||
try {
|
||||
JsonPrimitive jsonPrimitive = jsonPath == null ? this.getJsonPrimitiveFromTag(tagName)
|
||||
: this.getJsonPrimitiveFromPath(tagName, jsonPath);
|
||||
if (jsonPrimitive != null) {
|
||||
state = converter.convert(jsonPrimitive);
|
||||
} else {
|
||||
state = UnDefType.NULL;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
this.logger.warn("failed getting state for {}", channelName, ex);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
public static class DeviceModel {
|
||||
private String deviceClass;
|
||||
|
||||
public String getDeviceClass() {
|
||||
return this.deviceClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.deviceClass;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* DTO class for the complete structure delivered by the energy manager.
|
||||
*
|
||||
* Properties without setters are only filled by gson JSON parsing.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
public class EnergyManagerDTO {
|
||||
private Result result;
|
||||
|
||||
public Collection<DeviceDTO> getItems() {
|
||||
return this.result.getItems();
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
public Collection<DeviceDTO> getItems() {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
private Collection<DeviceDTO> items = new ArrayList<>();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.dto;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
/**
|
||||
* DTO class to encapsulate the tag values from the energy manager.
|
||||
*
|
||||
* Properties without setters are only filled by gson JSON parsing.
|
||||
* The concrete tag values can be anything. {@link com.google.gson.JsonPrimitive},
|
||||
* {@link com.google.gson.JsonObject} or even strings containing json structures.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
public class TagValueDTO {
|
||||
private String tagName;
|
||||
private String guid;
|
||||
private JsonElement value;
|
||||
|
||||
public String getTagName() {
|
||||
return this.tagName;
|
||||
}
|
||||
|
||||
public String getGuid() {
|
||||
return this.guid;
|
||||
}
|
||||
|
||||
public JsonElement getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Base class for everything supplying battery base power.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.devices.batteryconverter.BatteryConverter=[
|
||||
* PowerACIn,
|
||||
* UpTimePDG,
|
||||
* CurrentStringDCIn,
|
||||
* ResistanceBatteryMean,
|
||||
* CurrentBatteryIn,
|
||||
* VoltageBatteryCellMax,
|
||||
* VoltageGRMOut,
|
||||
* FactorForecast,
|
||||
* StateOfChargeMinimum,
|
||||
* StateEqualizingChargeRequiredIsSet,
|
||||
* WorkCharge,
|
||||
* VoltageBatteryCellMin,
|
||||
* VoltageBatteryCellMean,
|
||||
* StateOfHealth,
|
||||
* FactorForecastCAN,
|
||||
* StateOfCharge,
|
||||
* IdFirmwareGRM,
|
||||
* WorkCapacity,
|
||||
* CurrentGRMOut,
|
||||
* StatePDG,
|
||||
* TemperatureBatteryCellMax,
|
||||
* TemperatureGRM,
|
||||
* TemperatureBatteryMin,
|
||||
* ResistanceBatteryMin,
|
||||
* StateOfChargeMinimumLimit,
|
||||
* IdUrlPdg,
|
||||
* TemperatureBattery,
|
||||
* VoltageGRMIn,
|
||||
* CurrentGRMIn,
|
||||
* IdSerialNumberGRM,
|
||||
* ResistanceBatteryString,
|
||||
* VoltageBatteryString,
|
||||
* IdSerialNumberBatteryModules,
|
||||
* CountBatteryModules,
|
||||
* ModeConverter,
|
||||
* TemperatureBatteryMax,
|
||||
* TemperatureBatteryCellMin,
|
||||
* StateOfChargeReactivateDischarging,
|
||||
* IdMyReserveSetupRole,
|
||||
* ResistanceBatteryMax,
|
||||
* AvailableModes,
|
||||
* PowerACInMax,
|
||||
* PowerACInLimit,
|
||||
* StateOfChargeShutDownLimit,
|
||||
* CountBatteryContactor,
|
||||
* CurrentBatteryOut,
|
||||
* TimeEqualizingChargeRemaining,
|
||||
* WorkACIn,
|
||||
* MapInstallationDetails
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BatteryConverter extends Inverter {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.batteryconverter.BatteryConverter";
|
||||
|
||||
public BatteryConverter(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DeviceDTO deviceDTO) {
|
||||
super.update(deviceDTO);
|
||||
|
||||
this.addSwitchState(CHANNEL_MODE_CONVERTER, deviceDTO);
|
||||
this.addPercentQuantity(CHANNEL_STATE_OF_CHARGE, deviceDTO);
|
||||
this.addPercentQuantity(CHANNEL_STATE_OF_HEALTH, deviceDTO);
|
||||
this.addCelsiusQuantity(CHANNEL_TEMPERATURE_BATTERY, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_AC_IN, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_AC_IN, deviceDTO);
|
||||
this.addVoltageQuantity(CHANNEL_VOLTAGE_BATTERY_CELL_MIN, deviceDTO, true);
|
||||
this.addVoltageQuantity(CHANNEL_VOLTAGE_BATTERY_CELL_MEAN, deviceDTO, true);
|
||||
this.addVoltageQuantity(CHANNEL_VOLTAGE_BATTERY_CELL_MAX, deviceDTO, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "BatteryConverter";
|
||||
}
|
||||
}
|
@ -0,0 +1,315 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solarwatt.internal.domain.SolarwattChannel;
|
||||
import org.openhab.binding.solarwatt.internal.domain.SolarwattTag;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
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.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* Base class for all devices which are connected to the energy manager.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.lib.device.Device=[
|
||||
* IdFingerPrint,
|
||||
* IdInterfaceList,
|
||||
* IdName,
|
||||
* IdFirmware,
|
||||
* PasswordLock,
|
||||
* IdLabelSet,
|
||||
* StateDevice,
|
||||
* StateVisibleIsSet,
|
||||
* IdFingerPrintVersion,
|
||||
* IdDriver,
|
||||
* IdModelCode,
|
||||
* StateLockedIsSet,
|
||||
* IdManufacturer,
|
||||
* IdSerialNumber,
|
||||
* StateErrorList
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Device {
|
||||
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.lib.device.Device";
|
||||
public static final String WATT_HOUR_CATEGORY = "energy";
|
||||
public static final String WATT_CATEGORY = "energy";
|
||||
private final String guid;
|
||||
private @Nullable String idName;
|
||||
private @Nullable String idFirmware;
|
||||
private @Nullable String idManufacturer;
|
||||
private ThingStatus stateDevice = ThingStatus.UNINITIALIZED;
|
||||
protected final Map<String, State> stateValues;
|
||||
protected final Map<String, SolarwattChannel> solarwattChannelSet;
|
||||
|
||||
public Device(DeviceDTO deviceDTO) {
|
||||
this.stateValues = new HashMap<>();
|
||||
this.solarwattChannelSet = new HashMap<>();
|
||||
this.guid = deviceDTO.getGuid();
|
||||
|
||||
this.update(deviceDTO);
|
||||
}
|
||||
|
||||
public void update(DeviceDTO deviceDTO) {
|
||||
this.idName = deviceDTO.getStringTag("IdName");
|
||||
this.idFirmware = deviceDTO.getStringTag("IdFirmware");
|
||||
this.idManufacturer = deviceDTO.getStringTag("IdManufacturer");
|
||||
if ("OK".equals(deviceDTO.getStringTag("StateDevice"))) {
|
||||
this.stateDevice = ThingStatus.ONLINE;
|
||||
} else {
|
||||
this.stateDevice = ThingStatus.OFFLINE;
|
||||
}
|
||||
}
|
||||
|
||||
public BigDecimal getBigDecimalFromChannel(String channelName) {
|
||||
State state = this.getStateValues().get(channelName);
|
||||
if (state != null) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
QuantityType quantity = state.as(QuantityType.class);
|
||||
if (quantity != null) {
|
||||
return quantity.toBigDecimal();
|
||||
}
|
||||
}
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a channeltype to the known channel types.
|
||||
*
|
||||
* {@link org.openhab.core.thing.type.ChannelType} is only created if it does noct exist.
|
||||
*
|
||||
* @param tagName name for the channel
|
||||
* @param unit unit for channel
|
||||
* @param category text category
|
||||
* @param advanced wether or not to display only in advanced
|
||||
*/
|
||||
public void addChannel(String tagName, @Nullable Unit<?> unit, String category, Boolean advanced) {
|
||||
this.solarwattChannelSet.computeIfAbsent(tagName, s -> new SolarwattChannel(tagName, unit, category, advanced));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a state with unit and BigInteger as value.
|
||||
*
|
||||
* @param solarwattTag combined tag and channel name
|
||||
* @param deviceDTO raw device data
|
||||
* @param unit unit for value
|
||||
*/
|
||||
public void addStateBigInteger(SolarwattTag solarwattTag, DeviceDTO deviceDTO, Unit<?> unit) {
|
||||
this.addState(solarwattTag.getChannelName(), deviceDTO.getState(
|
||||
(jsonElement -> new QuantityType<>(jsonElement.getAsBigInteger(), unit)), solarwattTag.getTagName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a state from a json path with unit and BigInteger as value.
|
||||
*
|
||||
* @param channelName target channe
|
||||
* @param tagName tag for value
|
||||
* @param path to find value
|
||||
* @param deviceDTO raw device data
|
||||
* @param unit unit for value
|
||||
*/
|
||||
public void addStateBigInteger(String channelName, String tagName, String path, DeviceDTO deviceDTO, Unit<?> unit) {
|
||||
this.addState(channelName, deviceDTO.getState(
|
||||
(jsonElement -> new QuantityType<>(jsonElement.getAsBigInteger(), unit)), channelName, tagName, path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a state with unit and BigDecimal as value.
|
||||
*
|
||||
* @param solarwattTag combined tag and channel name
|
||||
* @param deviceDTO raw device data
|
||||
* @param unit unit for value
|
||||
*/
|
||||
public void addStateBigDecimal(SolarwattTag solarwattTag, DeviceDTO deviceDTO, Unit<?> unit) {
|
||||
this.addState(solarwattTag.getChannelName(), deviceDTO.getState(
|
||||
(jsonElement -> new QuantityType<>(jsonElement.getAsBigDecimal(), unit)), solarwattTag.getTagName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a state with unit and BigDecimal as value.
|
||||
*
|
||||
* @param solarwattTag combined tag and channel name
|
||||
* @param value BigDecimal value
|
||||
* @param unit unit for value
|
||||
*/
|
||||
public void addStateBigDecimal(SolarwattTag solarwattTag, BigDecimal value, Unit<?> unit) {
|
||||
this.addState(solarwattTag.getChannelName(), new QuantityType<>(value, unit));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a string state.
|
||||
*
|
||||
* @param solarwattTag combined tag and channel name
|
||||
* @param deviceDTO raw device data
|
||||
*/
|
||||
public void addStateString(SolarwattTag solarwattTag, DeviceDTO deviceDTO) {
|
||||
this.addState(solarwattTag.getChannelName(), deviceDTO
|
||||
.getState((jsonElement -> new StringType(jsonElement.getAsString())), solarwattTag.getTagName()));
|
||||
}
|
||||
|
||||
public void addStateSwitch(SolarwattTag solarwattTag, DeviceDTO deviceDTO) {
|
||||
this.addState(solarwattTag.getChannelName(), deviceDTO
|
||||
.getState((jsonElement -> OnOffType.from(jsonElement.getAsString())), solarwattTag.getTagName()));
|
||||
}
|
||||
|
||||
public ThingStatus getStateDevice() {
|
||||
return this.stateDevice;
|
||||
}
|
||||
|
||||
public Map<String, State> getStateValues() {
|
||||
return this.stateValues;
|
||||
}
|
||||
|
||||
public Map<String, SolarwattChannel> getSolarwattChannelSet() {
|
||||
return this.solarwattChannelSet;
|
||||
}
|
||||
|
||||
protected void addWattHourQuantity(SolarwattTag solarwattTag, DeviceDTO deviceDTO) {
|
||||
this.addWattHourQuantity(solarwattTag, deviceDTO, false);
|
||||
}
|
||||
|
||||
protected void addWattHourQuantity(SolarwattTag solarwattTag, DeviceDTO deviceDTO, Boolean advanced) {
|
||||
this.addChannel(solarwattTag.getChannelName(), Units.WATT_HOUR, WATT_HOUR_CATEGORY, advanced);
|
||||
|
||||
this.addStateBigDecimal(solarwattTag, deviceDTO, Units.WATT_HOUR);
|
||||
}
|
||||
|
||||
protected void addWattQuantity(SolarwattTag solarwattTag, DeviceDTO deviceDTO) {
|
||||
this.addWattQuantity(solarwattTag, deviceDTO, false);
|
||||
}
|
||||
|
||||
protected void addWattQuantity(SolarwattTag solarwattTag, BigDecimal value, Boolean advanced) {
|
||||
this.addChannel(solarwattTag.getChannelName(), Units.WATT, WATT_CATEGORY, advanced);
|
||||
|
||||
this.addStateBigDecimal(solarwattTag, value, Units.WATT);
|
||||
}
|
||||
|
||||
protected void addWattQuantity(SolarwattTag solarwattTag, DeviceDTO deviceDTO, Boolean advanced) {
|
||||
this.addChannel(solarwattTag.getChannelName(), Units.WATT, WATT_CATEGORY, advanced);
|
||||
|
||||
this.addStateBigDecimal(solarwattTag, deviceDTO, Units.WATT);
|
||||
}
|
||||
|
||||
protected void addSecondsQuantity(String channelName, String tagName, String path, DeviceDTO deviceDTO) {
|
||||
this.addChannel(channelName, Units.SECOND, "time", false);
|
||||
|
||||
this.addStateBigInteger(channelName, tagName, path, deviceDTO, Units.SECOND);
|
||||
}
|
||||
|
||||
protected void addPercentQuantity(SolarwattTag solarwattTag, DeviceDTO deviceDTO) {
|
||||
this.addChannel(solarwattTag.getChannelName(), Units.PERCENT, "status", false);
|
||||
|
||||
this.addStateBigDecimal(solarwattTag, deviceDTO, Units.PERCENT);
|
||||
}
|
||||
|
||||
protected void addCelsiusQuantity(SolarwattTag solarwattTag, DeviceDTO deviceDTO) {
|
||||
this.addChannel(solarwattTag.getChannelName(), SIUnits.CELSIUS, "temperature", false);
|
||||
|
||||
this.addStateBigDecimal(solarwattTag, deviceDTO, SIUnits.CELSIUS);
|
||||
}
|
||||
|
||||
protected void addAmpereQuantity(SolarwattTag solarwattTag, DeviceDTO deviceDTO) {
|
||||
this.addAmpereQuantity(solarwattTag, deviceDTO, false);
|
||||
}
|
||||
|
||||
protected void addAmpereQuantity(SolarwattTag solarwattTag, DeviceDTO deviceDTO, Boolean advanced) {
|
||||
this.addChannel(solarwattTag.getChannelName(), Units.AMPERE, "current", advanced);
|
||||
|
||||
this.addStateBigDecimal(solarwattTag, deviceDTO, Units.AMPERE);
|
||||
}
|
||||
|
||||
protected void addVoltageQuantity(SolarwattTag solarwattTag, DeviceDTO deviceDTO) {
|
||||
this.addVoltageQuantity(solarwattTag, deviceDTO, false);
|
||||
}
|
||||
|
||||
protected void addVoltageQuantity(SolarwattTag solarwattTag, DeviceDTO deviceDTO, Boolean advanced) {
|
||||
this.addChannel(solarwattTag.getChannelName(), Units.VOLT, "voltage", advanced);
|
||||
|
||||
this.addStateBigDecimal(solarwattTag, deviceDTO, Units.VOLT);
|
||||
}
|
||||
|
||||
protected void addStringState(SolarwattTag solarwattTag, DeviceDTO deviceDTO) {
|
||||
this.addChannel(solarwattTag.getChannelName(), null, "status", false);
|
||||
|
||||
this.addStateString(solarwattTag, deviceDTO);
|
||||
}
|
||||
|
||||
protected void addSwitchState(SolarwattTag solarwattTag, DeviceDTO deviceDTO) {
|
||||
this.addChannel(solarwattTag.getChannelName(), null, "switch", false);
|
||||
|
||||
this.addStateSwitch(solarwattTag, deviceDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add state to map and return it for further usage.
|
||||
*
|
||||
* @param channelName where to put the state
|
||||
* @param state to put
|
||||
*/
|
||||
public void addState(String channelName, @Nullable State state) {
|
||||
if (state != null) {
|
||||
this.stateValues.put(channelName, state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get state from map
|
||||
*
|
||||
* @param channelName state to return
|
||||
* @return {@link State} found
|
||||
*/
|
||||
public @Nullable State getState(String channelName) {
|
||||
return this.stateValues.get(channelName);
|
||||
}
|
||||
|
||||
public String getGuid() {
|
||||
return this.guid;
|
||||
}
|
||||
|
||||
public @Nullable String getIdName() {
|
||||
return this.idName;
|
||||
}
|
||||
|
||||
public @Nullable String getIdFirmware() {
|
||||
return this.idFirmware;
|
||||
}
|
||||
|
||||
public @Nullable String getIdManufacturer() {
|
||||
return this.idManufacturer;
|
||||
}
|
||||
|
||||
protected String getSolarWattLabel() {
|
||||
return "Device";
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return this.getSolarWattLabel() + " " + this.getIdName();
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Base class for a wallbox.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.devices.evstation.EVStation=[
|
||||
* PowerACOutMax,
|
||||
* PowerACIn,
|
||||
* VoltageACL1,
|
||||
* VoltageACL2,
|
||||
* VoltageACL3,
|
||||
* WorkACOut,
|
||||
* ConnectivityStatus,
|
||||
* StateOfChargeMinimum,
|
||||
* WorkACInLimitSession,
|
||||
* WorkCharge,
|
||||
* PowerACOut,
|
||||
* PowerACOutLimit,
|
||||
* AvailableModes,
|
||||
* PowerACInMax,
|
||||
* StateOfCharge,
|
||||
* PowerACInLimit,
|
||||
* CurrentACInLimit,
|
||||
* StateInfo,
|
||||
* ModeStation,
|
||||
* VehicleId,
|
||||
* CurrentACInMinimum,
|
||||
* WorkCapacity,
|
||||
* WorkACInSession,
|
||||
* UserId,
|
||||
* TemperatureBattery,
|
||||
* WorkACIn,
|
||||
* CurrentACInL1,
|
||||
* CurrentACInL3,
|
||||
* PowerACInMin,
|
||||
* CurrentACInL2
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EVStation extends Device {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.evstation.EVStation";
|
||||
|
||||
public EVStation(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DeviceDTO deviceDTO) {
|
||||
super.update(deviceDTO);
|
||||
|
||||
this.addStringState(CHANNEL_CONNECTIVITY_STATUS, deviceDTO);
|
||||
this.addStringState(CHANNEL_MODE_STATION, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_AC_IN, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_AC_IN, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_AC_IN_SESSION, deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "EVStation";
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* The energy manager itself which aggregates all other devices.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.devices.em.EnergyManager=[
|
||||
* IdInterfacesMap,
|
||||
* DateCloudLastSeen,
|
||||
* IdBootLoaderVersion,
|
||||
* URLProxy,
|
||||
* IdTimezone,
|
||||
* FractionCPULoadAverageLastFifteenMinutes,
|
||||
* FractionCPULoadAverageLastFiveMinutes,
|
||||
* IdSystemImageVersion,
|
||||
* VersionPackagesMap,
|
||||
* IdNotInstalledDevicesMap,
|
||||
* StatusMonitoringMap,
|
||||
* FractionCPULoadUser,
|
||||
* VersionExtensionsMap,
|
||||
* InstallConfiguration,
|
||||
* URLCloud,
|
||||
* SettingsProxyMap,
|
||||
* IdDevicesMap,
|
||||
* SettingsMap,
|
||||
* ReasonReboots,
|
||||
* IdDriverList,
|
||||
* TimeSinceStart,
|
||||
* ExchangeDevice,
|
||||
* SettingsPrivacyMap,
|
||||
* FractionTopFiveProcessesMap,
|
||||
* StateAction,
|
||||
* FractionCPULoadAverageLastMinute,
|
||||
* SettingsNetworkMap,
|
||||
* SettingsDatetimeMap,
|
||||
* FractionCPULoadKernel,
|
||||
* FractionCPULoadTotal,
|
||||
* IdRemoteAppSet,
|
||||
* IdOwner,
|
||||
* VersionLocalApplicationsMap,
|
||||
* AddressLocation,
|
||||
* Command,
|
||||
* DriverMap,
|
||||
* DateTagCollectorWatchdogEvents,
|
||||
* LocationGeographical
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EnergyManager extends Device {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.em.EnergyManager";
|
||||
|
||||
public EnergyManager(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DeviceDTO deviceDTO) {
|
||||
super.update(deviceDTO);
|
||||
|
||||
this.addSecondsQuantity(CHANNEL_TIMESTAMP.getChannelName(), "SettingsDatetimeMap", ".timestamp", deviceDTO);
|
||||
this.addStringState(CHANNEL_IDTIMEZONE, deviceDTO);
|
||||
this.addPercentQuantity(CHANNEL_FRACTION_CPU_LOAD_TOTAL, deviceDTO);
|
||||
this.addPercentQuantity(CHANNEL_FRACTION_CPU_LOAD_USER, deviceDTO);
|
||||
this.addPercentQuantity(CHANNEL_FRACTION_CPU_LOAD_KERNEL, deviceDTO);
|
||||
this.addPercentQuantity(CHANNEL_FRACTION_CPU_LOAD_AVERAGE_LAST_MINUTE, deviceDTO);
|
||||
this.addPercentQuantity(CHANNEL_FRACTION_CPU_LOAD_AVERAGE_LAST_FIVE_MINUTES, deviceDTO);
|
||||
this.addPercentQuantity(CHANNEL_FRACTION_CPU_LOAD_AVERAGE_LAST_FIFTEEN_MINUTES, deviceDTO);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Class for the weather forecast used by the energy manager to predict the produced power
|
||||
* and plan the battery charging.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.solarwatt.devices.forecast.Forecast=[
|
||||
* CorrectionFactors,
|
||||
* DiffuseCorrectionFactors,
|
||||
* DateNextYieldTrendScheduler,
|
||||
* ModePreventPVForecast,
|
||||
* WeatherForecast,
|
||||
* ForecastProperties,
|
||||
* DateNextConsumptionTrendScheduler,
|
||||
* DateNextFactorScheduler,
|
||||
* WeatherAPIKey,
|
||||
* WeatherHistory
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Forecast extends Device {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.solarwatt.devices.forecast.Forecast";
|
||||
|
||||
public Forecast(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "Forecast";
|
||||
}
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.CHANNEL_CURRENT_LIMIT;
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.CHANNEL_FEED_IN_LIMIT;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* Class planning the energy flow out/into the grid.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.kiwiapp.gridflow.GridFlow=[
|
||||
* ConfigTimeshifting,
|
||||
* ConfigEvStationControl,
|
||||
* FractionPVTestLimit,
|
||||
* ConfigInverterControl,
|
||||
* LogLevel,
|
||||
* PowerSetpoint,
|
||||
* ConfigPeakshaving,
|
||||
* ToEMRequestTag,
|
||||
* CurrentLimit,
|
||||
* ConfigBatteryControl,
|
||||
* ConfigForecastBatteryControl,
|
||||
* ConfigEvStationChargingControl,
|
||||
* ConfigSgReady,
|
||||
* ToCloudDataTag
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GridFlow extends Device {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.kiwiapp.gridflow.GridFlow";
|
||||
private final Logger logger = LoggerFactory.getLogger(GridFlow.class);
|
||||
|
||||
private @Nullable ConfigInverterControl configInverterControl;
|
||||
|
||||
public GridFlow(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DeviceDTO deviceDTO) {
|
||||
super.update(deviceDTO);
|
||||
|
||||
this.addAmpereQuantity(CHANNEL_CURRENT_LIMIT, deviceDTO, true);
|
||||
|
||||
try {
|
||||
JsonObject rawConfigInverterControl = deviceDTO.getJsonObjectFromTag("ConfigInverterControl");
|
||||
Gson gson = new GsonBuilder().create();
|
||||
this.configInverterControl = gson.fromJson(rawConfigInverterControl, GridFlow.ConfigInverterControl.class);
|
||||
} catch (Exception ex) {
|
||||
this.configInverterControl = null;
|
||||
this.logger.warn("Could not read ConfigInverterControl", ex);
|
||||
}
|
||||
|
||||
GridFlow.ConfigInverterControl localConfigInverterControl = this.configInverterControl;
|
||||
if (localConfigInverterControl != null) {
|
||||
// the only interesting value is the derailing (i.e. limit power flowing into the grid)
|
||||
BigDecimal feedInLimit = localConfigInverterControl.getFeedInLimit();
|
||||
if (feedInLimit != null) {
|
||||
QuantityType<?> state = new QuantityType<>(feedInLimit.multiply(BigDecimal.valueOf(100)),
|
||||
Units.PERCENT);
|
||||
this.stateValues.put(CHANNEL_FEED_IN_LIMIT.getChannelName(), state);
|
||||
|
||||
this.addChannel(CHANNEL_FEED_IN_LIMIT.getChannelName(), Units.PERCENT, "status", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "GridFlow";
|
||||
}
|
||||
|
||||
public static class ConfigInverterControl {
|
||||
private @Nullable BigDecimal testModeFeedInLimit;
|
||||
private @Nullable ControllerParameter controllerParameter;
|
||||
private @Nullable Boolean dynamicControllingOn;
|
||||
private @Nullable BigDecimal feedInLimit;
|
||||
private @Nullable DynamicControllerParameter dynamicControllerParameter;
|
||||
private @Nullable Boolean on;
|
||||
private @Nullable Boolean isErrorPVLimiting;
|
||||
private @Nullable Boolean activeTestMode;
|
||||
private @Nullable Boolean isPVPlantConfigured;
|
||||
private @Nullable String selectedRcr;
|
||||
private @Nullable Boolean limitByRcr;
|
||||
|
||||
public @Nullable BigDecimal getFeedInLimit() {
|
||||
return this.feedInLimit;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getTestModeFeedInLimit() {
|
||||
return this.testModeFeedInLimit;
|
||||
}
|
||||
|
||||
public @Nullable ControllerParameter getControllerParameter() {
|
||||
return this.controllerParameter;
|
||||
}
|
||||
|
||||
public @Nullable Boolean getDynamicControllingOn() {
|
||||
return this.dynamicControllingOn;
|
||||
}
|
||||
|
||||
public @Nullable DynamicControllerParameter getDynamicControllerParameter() {
|
||||
return this.dynamicControllerParameter;
|
||||
}
|
||||
|
||||
public @Nullable Boolean getOn() {
|
||||
return this.on;
|
||||
}
|
||||
|
||||
public @Nullable Boolean getErrorPVLimiting() {
|
||||
return this.isErrorPVLimiting;
|
||||
}
|
||||
|
||||
public @Nullable Boolean getActiveTestMode() {
|
||||
return this.activeTestMode;
|
||||
}
|
||||
|
||||
public @Nullable Boolean getPVPlantConfigured() {
|
||||
return this.isPVPlantConfigured;
|
||||
}
|
||||
|
||||
public @Nullable String getSelectedRcr() {
|
||||
return this.selectedRcr;
|
||||
}
|
||||
|
||||
public @Nullable Boolean getLimitByRcr() {
|
||||
return this.limitByRcr;
|
||||
}
|
||||
|
||||
public static class ControllerParameter {
|
||||
private @Nullable BigDecimal integrationRate;
|
||||
private @Nullable BigInteger outputRampRateLimit;
|
||||
private @Nullable BigDecimal differentialRate;
|
||||
private @Nullable BigDecimal proportionalRate;
|
||||
private @Nullable BigInteger outputValueLimit;
|
||||
private @Nullable BigInteger controlFaultSumLimit;
|
||||
|
||||
public @Nullable BigDecimal getIntegrationRate() {
|
||||
return this.integrationRate;
|
||||
}
|
||||
|
||||
public @Nullable BigInteger getOutputRampRateLimit() {
|
||||
return this.outputRampRateLimit;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getDifferentialRate() {
|
||||
return this.differentialRate;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getProportionalRate() {
|
||||
return this.proportionalRate;
|
||||
}
|
||||
|
||||
public @Nullable BigInteger getOutputValueLimit() {
|
||||
return this.outputValueLimit;
|
||||
}
|
||||
|
||||
public @Nullable BigInteger getControlFaultSumLimit() {
|
||||
return this.controlFaultSumLimit;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynamicControllerParameter {
|
||||
private @Nullable BigDecimal integrationRate;
|
||||
private @Nullable BigInteger outputRampRateLimit;
|
||||
private @Nullable BigDecimal differentialRate;
|
||||
private @Nullable BigDecimal proportionalRate;
|
||||
private @Nullable BigInteger outputValueLimit;
|
||||
private @Nullable BigInteger controlFaultSumLimit;
|
||||
|
||||
public @Nullable BigDecimal getIntegrationRate() {
|
||||
return this.integrationRate;
|
||||
}
|
||||
|
||||
public @Nullable BigInteger getOutputRampRateLimit() {
|
||||
return this.outputRampRateLimit;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getDifferentialRate() {
|
||||
return this.differentialRate;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getProportionalRate() {
|
||||
return this.proportionalRate;
|
||||
}
|
||||
|
||||
public @Nullable BigInteger getOutputValueLimit() {
|
||||
return this.outputValueLimit;
|
||||
}
|
||||
|
||||
public @Nullable BigInteger getControlFaultSumLimit() {
|
||||
return this.controlFaultSumLimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Base class for all inverters.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.devices.inverter.Inverter=[
|
||||
* WorkACOut,
|
||||
* PowerInstalledPeak,
|
||||
* PowerStringDCIn,
|
||||
* PowerACOutMax,
|
||||
* PowerACOut,
|
||||
* PowerACOutLimit,
|
||||
* ACPower,
|
||||
* PowerYieldSum
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Inverter extends Device {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.inverter.Inverter";
|
||||
|
||||
public Inverter(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DeviceDTO deviceDTO) {
|
||||
super.update(deviceDTO);
|
||||
|
||||
this.addWattHourQuantity(CHANNEL_WORK_AC_OUT, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_AC_OUT_MAX, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_AC_OUT, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_AC_OUT_LIMIT, deviceDTO);
|
||||
|
||||
this.addWattQuantity(CHANNEL_POWER_INSTALLED_PEAK, deviceDTO, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "Inverter";
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Specialised class for the Keba Wallbox.
|
||||
*
|
||||
* No additional fields where found.
|
||||
* com.kiwigrid.devices.keba.ev.KebaEv=[]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class KebaEv extends EVStation {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.keba.ev.KebaEv";
|
||||
|
||||
public KebaEv(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "KebaEVStation";
|
||||
}
|
||||
}
|
@ -0,0 +1,208 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Class that aggregates all devices which are found in one location
|
||||
* and are working together to produce power.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.devices.location.Location=[
|
||||
* WorkBufferedFromProducers,
|
||||
* WorkOutFromProducers,
|
||||
* PowerBufferedFromGrid,
|
||||
* WorkProduced,
|
||||
* WorkConsumedFromStorage,
|
||||
* PowerSelfConsumed,
|
||||
* PowerConsumedFromProducers,
|
||||
* PowerConsumedFromStorage,
|
||||
* PowerOutFromProducers,
|
||||
* DatePowerProductionForecastStart,
|
||||
* PowerOut,
|
||||
* PowerProductionForecastNow,
|
||||
* PowerOutFromStorage,
|
||||
* IdDevicesMap,
|
||||
* PowerBuffered,
|
||||
* TimePowerProductionForecastGranularity,
|
||||
* WorkOutFromStorage,
|
||||
* CountPersons,
|
||||
* DatePowerConsumptionForecastStart,
|
||||
* PowerConsumptionForecastNow,
|
||||
* PowerProduced,
|
||||
* WorkBuffered,
|
||||
* WorkConsumedFromProducers,
|
||||
* PowerConsumed,
|
||||
* WorkConsumedFromGrid,
|
||||
* PowerConsumptionForecastValues,
|
||||
* PowerSelfSupplied,
|
||||
* WorkReleased,
|
||||
* PowerConsumedFromGrid,
|
||||
* TimePowerConsumptionForecastGranularity,
|
||||
* WorkConsumed,
|
||||
* AddressLocation,
|
||||
* WorkIn,
|
||||
* PriceWorkIn,
|
||||
* PowerIn,
|
||||
* WorkBufferedFromGrid,
|
||||
* WorkSelfConsumed,
|
||||
* PowerProductionForecastValues,
|
||||
* LocationGeographical,
|
||||
* PowerBufferedFromProducers,
|
||||
* PowerReleased,
|
||||
* WorkOut,
|
||||
* WorkSelfSupplied
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Location extends Device {
|
||||
private final Logger logger = LoggerFactory.getLogger(Location.class);
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.location.Location";
|
||||
|
||||
private @Nullable IdDevicesMap devicesMap;
|
||||
|
||||
public Location(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DeviceDTO deviceDTO) {
|
||||
super.update(deviceDTO);
|
||||
|
||||
// values to put on a overview dashboard
|
||||
this.addWattQuantity(CHANNEL_POWER_BUFFERED, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_SELF_CONSUMED, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_SELF_SUPPLIED, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_CONSUMED_FROM_GRID, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_CONSUMED_FROM_STORAGE, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_CONSUMED, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_PRODUCED, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_OUT, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_BUFFERED, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_SELF_CONSUMED, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_SELF_SUPPLIED, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_CONSUMED_FROM_GRID, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_CONSUMED_FROM_STORAGE, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_CONSUMED, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_PRODUCED, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_OUT, deviceDTO);
|
||||
|
||||
// not necessary for a dashboard, so marked as advanced
|
||||
this.addWattQuantity(CHANNEL_POWER_BUFFERED_FROM_GRID, deviceDTO, true);
|
||||
this.addWattQuantity(CHANNEL_POWER_BUFFERED_FROM_PRODUCERS, deviceDTO, true);
|
||||
this.addWattQuantity(CHANNEL_POWER_CONSUMED_FROM_PRODUCERS, deviceDTO, true);
|
||||
this.addWattQuantity(CHANNEL_POWER_IN, deviceDTO, true);
|
||||
this.addWattQuantity(CHANNEL_POWER_OUT_FROM_PRODUCERS, deviceDTO, true);
|
||||
this.addWattQuantity(CHANNEL_POWER_OUT_FROM_STORAGE, deviceDTO, true);
|
||||
this.addWattQuantity(CHANNEL_POWER_RELEASED, deviceDTO, true);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_BUFFERED_FROM_GRID, deviceDTO, true);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_BUFFERED_FROM_PRODUCERS, deviceDTO, true);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_CONSUMED_FROM_PRODUCERS, deviceDTO, true);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_OUT_FROM_PRODUCERS, deviceDTO, true);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_OUT_FROM_STORAGE, deviceDTO, true);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_RELEASED, deviceDTO, true);
|
||||
|
||||
// read IdDevicesMap to find out which devices are located/metered where
|
||||
// to get the unmetered consumption we need for {@link LocationHandler} to take Location.(Work|Power)Consumed
|
||||
// and subtract the (Work|Power)(AC)In of the OUTER_CONSUMERs
|
||||
try {
|
||||
JsonObject rawDevicesMap = deviceDTO.getJsonObjectFromTag("IdDevicesMap");
|
||||
Gson gson = new GsonBuilder().create();
|
||||
this.devicesMap = gson.fromJson(rawDevicesMap, IdDevicesMap.class);
|
||||
} catch (Exception ex) {
|
||||
this.devicesMap = null;
|
||||
this.logger.warn("Could not read IdDevicesMap", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public IdDevicesMap getDevicesMap() {
|
||||
IdDevicesMap returnDevicesMap = this.devicesMap;
|
||||
if (returnDevicesMap != null) {
|
||||
return returnDevicesMap;
|
||||
}
|
||||
|
||||
return new IdDevicesMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "Location";
|
||||
}
|
||||
|
||||
public static class IdDevicesMap {
|
||||
@SerializedName("INNER_BUFFER")
|
||||
private @Nullable Set<String> innerBuffer;
|
||||
@SerializedName("INNER_CONSUMER")
|
||||
private @Nullable Set<String> innerConsumer;
|
||||
@SerializedName("POWERMETER_CONSUMPTION")
|
||||
private @Nullable Set<String> powermeterConsumption;
|
||||
@SerializedName("OUTER_CONSUMER")
|
||||
private @Nullable Set<String> outerConsumer;
|
||||
@SerializedName("OUTER_BUFFER")
|
||||
private @Nullable Set<String> outerBuffer;
|
||||
@SerializedName("POWERMETER_PRODUCTION")
|
||||
private @Nullable Set<String> powermeterProduction;
|
||||
@SerializedName("OUTER_PRODUCER")
|
||||
private @Nullable Set<String> outerProducer;
|
||||
@SerializedName("INNER_PRODUCER")
|
||||
private @Nullable Set<String> innerProducer;
|
||||
|
||||
public @Nullable Set<String> getInnerBuffer() {
|
||||
return this.innerBuffer;
|
||||
}
|
||||
|
||||
public @Nullable Set<String> getInnerConsumer() {
|
||||
return this.innerConsumer;
|
||||
}
|
||||
|
||||
public @Nullable Set<String> getPowermeterConsumption() {
|
||||
return this.powermeterConsumption;
|
||||
}
|
||||
|
||||
public @Nullable Set<String> getOuterConsumer() {
|
||||
return this.outerConsumer;
|
||||
}
|
||||
|
||||
public @Nullable Set<String> getOuterBuffer() {
|
||||
return this.outerBuffer;
|
||||
}
|
||||
|
||||
public @Nullable Set<String> getPowermeterProduction() {
|
||||
return this.powermeterProduction;
|
||||
}
|
||||
|
||||
public @Nullable Set<String> getOuterProducer() {
|
||||
return this.outerProducer;
|
||||
}
|
||||
|
||||
public @Nullable Set<String> getInnerProducer() {
|
||||
return this.innerProducer;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Specialised class for the MyReserve battery.
|
||||
*
|
||||
* The MyReserve also contains {@link MyReservePowerMeter} and {@link MyReserveInverter}.
|
||||
*
|
||||
* No additional fields where found.
|
||||
* com.kiwigrid.devices.solarwatt.MyReserve=[]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class MyReserve extends BatteryConverter {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.solarwatt.MyReserve";
|
||||
|
||||
public MyReserve(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "BatteryConverter";
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Specialised class for the MyReserve inverter.
|
||||
*
|
||||
* The MyReserve also contains {@link MyReservePowerMeter} and {@link MyReserve}.
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.devices.solarwatt.MyReserveInverter=[
|
||||
* PowerBatteryDC,
|
||||
* IdMyReserveSetupRole,
|
||||
* IdMyReserveSetup,
|
||||
* IdDcCoupledBatteriesList,
|
||||
* IdInverter,
|
||||
* Command
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class MyReserveInverter extends Inverter {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.solarwatt.MyReserveInverter";
|
||||
|
||||
public MyReserveInverter(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "MyReserveInverter";
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Specialised class for the MyReserve powermeter.
|
||||
*
|
||||
* The MyReserve also contains {@link MyReserve} and {@link MyReserveInverter}.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.devices.solarwatt.MyReservePowermeter=[
|
||||
* PpmScaleFactor,
|
||||
* IdAcsVersionNumber
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class MyReservePowerMeter extends PowerMeter {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.powermeter.PowerMeter";
|
||||
|
||||
public MyReservePowerMeter(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "MyReservePowerMeter";
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.CHANNEL_POWER_AC_OUT;
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.CHANNEL_WORK_AC_OUT;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Class to represent the producing parts of the photovoltaic installation.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.devices.pvplant.PVPlant=[
|
||||
* PowerACOutMax,
|
||||
* IdInverterList,
|
||||
* TimePowerOutForecastGranularity,
|
||||
* ForecastDateUpdate,
|
||||
* WorkACOut,
|
||||
* DegreeDirection,
|
||||
* ForecastPowerOut,
|
||||
* WorkAnnualYield,
|
||||
* PowerACOut,
|
||||
* DatePowerOutForecastStart,
|
||||
* PowerLimit,
|
||||
* IdMountingType,
|
||||
* FractionDeratingLimit,
|
||||
* DateInstallation,
|
||||
* ForecastWorkOut,
|
||||
* PowerOutForecastNow,
|
||||
* PriceProfitFeedin,
|
||||
* AddressLocation,
|
||||
* PowerOutForecastValues,
|
||||
* FractionConfigDeratingLimit,
|
||||
* PowerInstalledPeak,
|
||||
* LocationGeographical,
|
||||
* DegreeInclination
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PVPlant extends Device {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.pvplant.PVPlant";
|
||||
|
||||
public PVPlant(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(DeviceDTO deviceDTO) {
|
||||
super.update(deviceDTO);
|
||||
|
||||
this.addWattQuantity(CHANNEL_POWER_AC_OUT, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_AC_OUT, deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "PVPlant";
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Base class for all powermeters.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.devices.powermeter.PowerMeter=[
|
||||
* InductiveEnergySum,
|
||||
* ACCurrentConsumptionL1,
|
||||
* ACCurrentConsumptionL2,
|
||||
* ACCurrentN,
|
||||
* ACCurrentConsumptionL3,
|
||||
* ApparentPowerL2,
|
||||
* ConsumptionPowerL3,
|
||||
* ConsumptionPowerL2,
|
||||
* ApparentPowerL3,
|
||||
* ApparentPowerL1,
|
||||
* ConsumptionPowerNet,
|
||||
* ReactivePowerL1,
|
||||
* ReactivePowerL2,
|
||||
* InductiveEnergyL2,
|
||||
* InductiveEnergyL1,
|
||||
* ReactivePowerL3,
|
||||
* CapacitiveEnergyL2,
|
||||
* CapacitiveEnergyL1,
|
||||
* PhaseOfMaximumImbalance,
|
||||
* InjectionPowerL1,
|
||||
* ReactivePowerSum,
|
||||
* ActivePowerL3,
|
||||
* InjectionPowerL2,
|
||||
* InjectionPowerL3,
|
||||
* ActivePowerL1,
|
||||
* ConsumptionPowerL1,
|
||||
* InjectionEnergySum,
|
||||
* ActivePowerL2,
|
||||
* ImbalanceL1,
|
||||
* InjectionPowerNet,
|
||||
* ImbalanceL2,
|
||||
* ImbalanceL3,
|
||||
* CapacitiveEnergyL3,
|
||||
* DirectionMetering,
|
||||
* ConsumptionEnergySum,
|
||||
* PowerOut,
|
||||
* InjectionEnergyNet,
|
||||
* ACVoltageL1,
|
||||
* ACVoltageL2,
|
||||
* ACVoltageL3,
|
||||
* MaximumImbalance,
|
||||
* CosinusPhiL3,
|
||||
* CosinusPhiL2,
|
||||
* CosinusPhiL1,
|
||||
* FrequencyL1,
|
||||
* FrequencyL3,
|
||||
* FrequencyL2,
|
||||
* ACCurrentInjectionL3,
|
||||
* InjectionEnergyL3,
|
||||
* ACCurrentInjectionL2,
|
||||
* ConsumptionPowerSum,
|
||||
* ACCurrentInjectionL1,
|
||||
* InjectionEnergyL1,
|
||||
* InjectionEnergyL2,
|
||||
* ActivePowerSum,
|
||||
* ConsumptionEnergyL2,
|
||||
* ConsumptionEnergyL1,
|
||||
* PowerFactorL1,
|
||||
* PowerFactorL2,
|
||||
* InjectionPowerSum,
|
||||
* ConsumptionEnergyL3,
|
||||
* PowerFactorL3,
|
||||
* ACCurrentL3,
|
||||
* CapacitiveEnergySum,
|
||||
* WorkIn,
|
||||
* InductiveEnergyL3,
|
||||
* PowerIn,
|
||||
* ACCurrentL1,
|
||||
* ACCurrentL2,
|
||||
* FrequencyGrid,
|
||||
* ConsumptionEnergyNet,
|
||||
* ApparentPowerSum,
|
||||
* WorkOut
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PowerMeter extends Device {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.powermeter.PowerMeter";
|
||||
|
||||
public PowerMeter(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
|
||||
this.addStringState(CHANNEL_DIRECTION_METERING, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_IN, deviceDTO);
|
||||
this.addWattQuantity(CHANNEL_POWER_OUT, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_IN, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_WORK_OUT, deviceDTO);
|
||||
this.addWattHourQuantity(CHANNEL_CONSUMPTION_ENERGY_SUM, deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "PowerMeter";
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Class for things I haven't got a clue off.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.application.schedule.ProfileApp=[
|
||||
* IdPriorizedDeviceList,
|
||||
* ProfilesList,
|
||||
* IdProfileActive
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ProfileApp extends Device {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.application.schedule.ProfileApp";
|
||||
|
||||
public ProfileApp(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "ProfileApp";
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Specialised class for the powermeter connected via S0 bus.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.devices.s0counter.S0Counter=[
|
||||
* SettingRateImpulses,
|
||||
* CountPulses
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class S0Counter extends PowerMeter {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.s0counter.S0Counter";
|
||||
|
||||
public S0Counter(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "S0Counter";
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Class representing the scheduler of the energy manager.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.application.schedule.ScheduleApp=[
|
||||
* ScheduleEvents,
|
||||
* StateSchedule,
|
||||
* ExcessMinSleepTime,
|
||||
* ScheduleOverride,
|
||||
* ExcessMinRuntime,
|
||||
* ExcessMinRuntimePerDay,
|
||||
* PowerInAverage,
|
||||
* ExcessMinDuration,
|
||||
* PowerLimitDefaults,
|
||||
* SchedulesList,
|
||||
* Schedule
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ScheduleApp extends Device {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.application.schedule.ScheduleApp";
|
||||
|
||||
public ScheduleApp(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "ScheduleApp";
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Deprecated class.
|
||||
*
|
||||
* Was superseded by {@link ScheduleApp}.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.devices.simpleswitcher.SimpleSwitcher=[
|
||||
* MigratedToScheduleApp,
|
||||
* ScheduleSwitchStates
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SimpleSwitcher extends Device {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.simpleswitcher.SimpleSwitcher";
|
||||
|
||||
public SimpleSwitcher(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "SimpleSwitcher";
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Deprecated class.
|
||||
*
|
||||
* Was superseded by {@link ScheduleApp}.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.solarwatt.devices.sem.SmartEnergyManagement=[
|
||||
* FractionFeedInLimit,
|
||||
* FractionFeedInTestLimit,
|
||||
* ModeManagement,
|
||||
* ModeActive,
|
||||
* IdConsumerSettingsMap,
|
||||
* IdConsumerSelectionList,
|
||||
* ModeTestActive,
|
||||
* PowerInSwitchedOnDevices,
|
||||
* MigratedToScheduleApp,
|
||||
* IdDevicesMap,
|
||||
* IdConsumerManagementIntervalsMap,
|
||||
* IdManageableDeviceInfo
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SmartEnergyManagement extends Device {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.solarwatt.devices.sem.SmartEnergyManagement";
|
||||
|
||||
public SmartEnergyManagement(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "SmartEnergyManagement";
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.domain.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
|
||||
/**
|
||||
* Specialised class for inverters adhering to the sunspec modbus protocol.
|
||||
*
|
||||
* This fields have been identified to exist:
|
||||
* com.kiwigrid.devices.sunspec.SunSpecInverter=[
|
||||
* IdSunSpecBlocks
|
||||
* ]
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SunSpecInverter extends Inverter {
|
||||
public static final String SOLAR_WATT_CLASSNAME = "com.kiwigrid.devices.sunspec.SunSpecInverter";
|
||||
|
||||
public SunSpecInverter(DeviceDTO deviceDTO) {
|
||||
super(deviceDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSolarWattLabel() {
|
||||
return "SunSpecInverter";
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.exception;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Exception to be used whenever anything goes wrong talking to the energy manager.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SolarwattConnectionException extends Exception {
|
||||
static final long serialVersionUID = 3387516924229948L;
|
||||
|
||||
public SolarwattConnectionException(final @Nullable String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SolarwattConnectionException(final @Nullable String message, final Exception e) {
|
||||
super(message, e);
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.factory;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solarwatt.internal.domain.EnergyManagerCollection;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.DeviceDTO;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.EnergyManagerDTO;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.BatteryConverter;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.Device;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.EVStation;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.EnergyManager;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.Forecast;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.GridFlow;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.Inverter;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.KebaEv;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.Location;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.MyReserve;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.MyReserveInverter;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.MyReservePowerMeter;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.PVPlant;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.PowerMeter;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.ProfileApp;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.S0Counter;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.ScheduleApp;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.SimpleSwitcher;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.SmartEnergyManagement;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.SunSpecInverter;
|
||||
|
||||
/**
|
||||
* Factory to produce concrete instances which match the device structure returned by the energy manager.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EnergyManagerDevicesFactory {
|
||||
/**
|
||||
* Generate a concrete collection of devices which where discovered by the energy manager.
|
||||
*
|
||||
* @param energyManagerDTO raw transfer object generated from json
|
||||
* @return collection of all devices
|
||||
*/
|
||||
public static EnergyManagerCollection getEnergyManagerCollection(EnergyManagerDTO energyManagerDTO) {
|
||||
return new EnergyManagerCollection(energyManagerDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate one concrete device instance from one raw device.
|
||||
*
|
||||
* Specific implementation to use is determined by looking at the
|
||||
* deviceModels supported by the device and prioritising them according from the bottom up.
|
||||
*
|
||||
* @param deviceDTO raw transfer object for one device
|
||||
* @return device fille from the {@link DeviceDTO}
|
||||
*/
|
||||
public static @Nullable Device getEnergyManagerDevice(DeviceDTO deviceDTO) {
|
||||
// objects on level 3
|
||||
if (deviceDTO.getDeviceModelStrings().contains(MyReserve.SOLAR_WATT_CLASSNAME)) {
|
||||
return new MyReserve(deviceDTO);
|
||||
}
|
||||
// objects on level 2
|
||||
if (deviceDTO.getDeviceModelStrings().contains(S0Counter.SOLAR_WATT_CLASSNAME)) {
|
||||
return new S0Counter(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(KebaEv.SOLAR_WATT_CLASSNAME)) {
|
||||
return new KebaEv(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(MyReservePowerMeter.SOLAR_WATT_CLASSNAME)) {
|
||||
return new MyReservePowerMeter(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(SunSpecInverter.SOLAR_WATT_CLASSNAME)) {
|
||||
return new SunSpecInverter(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(MyReserveInverter.SOLAR_WATT_CLASSNAME)) {
|
||||
return new MyReserveInverter(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(BatteryConverter.SOLAR_WATT_CLASSNAME)) {
|
||||
return new BatteryConverter(deviceDTO);
|
||||
}
|
||||
// objects on level 1
|
||||
if (deviceDTO.getDeviceModelStrings().contains(ScheduleApp.SOLAR_WATT_CLASSNAME)) {
|
||||
return new ScheduleApp(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(SmartEnergyManagement.SOLAR_WATT_CLASSNAME)) {
|
||||
return new SmartEnergyManagement(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(EnergyManager.SOLAR_WATT_CLASSNAME)) {
|
||||
return new EnergyManager(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(Forecast.SOLAR_WATT_CLASSNAME)) {
|
||||
return new Forecast(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(Location.SOLAR_WATT_CLASSNAME)) {
|
||||
return new Location(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(EVStation.SOLAR_WATT_CLASSNAME)) {
|
||||
return new EVStation(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(PowerMeter.SOLAR_WATT_CLASSNAME)) {
|
||||
return new PowerMeter(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(SimpleSwitcher.SOLAR_WATT_CLASSNAME)) {
|
||||
return new SimpleSwitcher(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(GridFlow.SOLAR_WATT_CLASSNAME)) {
|
||||
return new GridFlow(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(PVPlant.SOLAR_WATT_CLASSNAME)) {
|
||||
return new PVPlant(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(Inverter.SOLAR_WATT_CLASSNAME)) {
|
||||
return new Inverter(deviceDTO);
|
||||
}
|
||||
if (deviceDTO.getDeviceModelStrings().contains(ProfileApp.SOLAR_WATT_CLASSNAME)) {
|
||||
return new ProfileApp(deviceDTO);
|
||||
}
|
||||
|
||||
// Objects on level 0
|
||||
if (deviceDTO.getDeviceModelStrings().contains(Device.SOLAR_WATT_CLASSNAME)) {
|
||||
return new Device(deviceDTO);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.handler;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.openhab.binding.solarwatt.internal.configuration.SolarwattBridgeConfiguration;
|
||||
import org.openhab.binding.solarwatt.internal.domain.EnergyManagerCollection;
|
||||
import org.openhab.binding.solarwatt.internal.domain.dto.EnergyManagerDTO;
|
||||
import org.openhab.binding.solarwatt.internal.exception.SolarwattConnectionException;
|
||||
import org.openhab.binding.solarwatt.internal.factory.EnergyManagerDevicesFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* Class to talk to the energy anager via HTTP and return the concrete device instances.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EnergyManagerConnector {
|
||||
private static final String PROTOCOL = "http://";
|
||||
private static final String WIZARD_DEVICES_URL = "/rest/kiwigrid/wizard/devices";
|
||||
private static final long CONNECT_TIMEOUT_SECONDS = 30;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(EnergyManagerConnector.class);
|
||||
private final Gson gson = new GsonBuilder().create();
|
||||
private final HttpClient httpClient;
|
||||
private @Nullable URI energyManagerURI;
|
||||
|
||||
public EnergyManagerConnector(final HttpClient httpClient) {
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass in the configuration to know which host to talk to.
|
||||
*
|
||||
* @param configuration containing the hostname.
|
||||
*/
|
||||
public void setConfiguration(final @Nullable SolarwattBridgeConfiguration configuration) {
|
||||
if (configuration != null) {
|
||||
String hostname = configuration.hostname;
|
||||
|
||||
if (!hostname.isEmpty()) {
|
||||
this.energyManagerURI = URI.create(PROTOCOL + hostname + WIZARD_DEVICES_URL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the collection of devices represented by the energy manager.
|
||||
*
|
||||
* Read the JSON and transform everything into concrete instances.
|
||||
*
|
||||
* @return wrapping the devices
|
||||
* @throws SolarwattConnectionException on any communication error
|
||||
*/
|
||||
public EnergyManagerCollection retrieveDevices() throws SolarwattConnectionException {
|
||||
try {
|
||||
final Request request = this.httpClient.newRequest(this.energyManagerURI).timeout(CONNECT_TIMEOUT_SECONDS,
|
||||
TimeUnit.SECONDS);
|
||||
final ContentResponse response = request.send();
|
||||
|
||||
return this.getEnergyManagerCollectionFromJson(response);
|
||||
} catch (final InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new SolarwattConnectionException("Interrupted");
|
||||
} catch (TimeoutException | ExecutionException e) {
|
||||
throw new SolarwattConnectionException("Connection problem", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse body content from energy manager from json into our DTO.
|
||||
*
|
||||
* @param response
|
||||
* @return collection containing all {@link DeviceDTO}s
|
||||
* @throws SolarwattConnectionException on communication errors
|
||||
*/
|
||||
private EnergyManagerCollection getEnergyManagerCollectionFromJson(ContentResponse response)
|
||||
throws SolarwattConnectionException {
|
||||
final String content = response.getContentAsString();
|
||||
|
||||
try {
|
||||
if (response.getStatus() == HttpStatus.OK_200) {
|
||||
EnergyManagerDTO energyManagerDTO = this.gson.fromJson(content, EnergyManagerDTO.class);
|
||||
if (energyManagerDTO == null) {
|
||||
throw new SolarwattConnectionException("No data received");
|
||||
}
|
||||
return EnergyManagerDevicesFactory.getEnergyManagerCollection(energyManagerDTO);
|
||||
} else {
|
||||
throw new SolarwattConnectionException(response.getReason());
|
||||
}
|
||||
} catch (final JsonSyntaxException e) {
|
||||
this.logger.warn("Error parsing json: {}", content, e);
|
||||
throw new SolarwattConnectionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,394 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.handler;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.solarwatt.internal.channel.SolarwattChannelTypeProvider;
|
||||
import org.openhab.binding.solarwatt.internal.configuration.SolarwattBridgeConfiguration;
|
||||
import org.openhab.binding.solarwatt.internal.configuration.SolarwattThingConfiguration;
|
||||
import org.openhab.binding.solarwatt.internal.discovery.SolarwattDevicesDiscoveryService;
|
||||
import org.openhab.binding.solarwatt.internal.domain.SolarwattChannel;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.Device;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.EnergyManager;
|
||||
import org.openhab.binding.solarwatt.internal.exception.SolarwattConnectionException;
|
||||
import org.openhab.core.cache.ExpiringCache;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link EnergyManagerHandler} is responsible for handling energy manager thing itself
|
||||
* and handle data retrieval for the child things.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EnergyManagerHandler extends BaseBridgeHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(EnergyManagerHandler.class);
|
||||
|
||||
private final EnergyManagerConnector connector;
|
||||
private final SolarwattChannelTypeProvider channelTypeProvider;
|
||||
|
||||
private @Nullable ExpiringCache<Map<String, Device>> devicesCache;
|
||||
private @Nullable ScheduledFuture<?> refreshJob;
|
||||
|
||||
private @Nullable ZoneId zoneId;
|
||||
|
||||
/**
|
||||
* Guid of this energy manager itself.
|
||||
*/
|
||||
private @Nullable String energyManagerGuid;
|
||||
|
||||
/**
|
||||
* Runner for the {@link ExpiringCache} refresh.
|
||||
*
|
||||
* Triggers update of all child things.
|
||||
*/
|
||||
private final Runnable refreshRunnable = () -> {
|
||||
EnergyManagerHandler.this.updateChannels();
|
||||
EnergyManagerHandler.this.updateAllChildThings();
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the handler.
|
||||
*
|
||||
* @param thing for which the handler is responsible
|
||||
* @param channelTypeProvider provider for the channels
|
||||
* @param httpClient connect to energy manager via this client
|
||||
*/
|
||||
public EnergyManagerHandler(final Bridge thing, final SolarwattChannelTypeProvider channelTypeProvider,
|
||||
final HttpClient httpClient) {
|
||||
super(thing);
|
||||
this.connector = new EnergyManagerConnector(httpClient);
|
||||
this.channelTypeProvider = channelTypeProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get services which are provided by this handler.
|
||||
*
|
||||
* Only service discovery is provided by
|
||||
*
|
||||
* @return collection containing our discovery service
|
||||
*/
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Collections.singleton(SolarwattDevicesDiscoveryService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the desired commands.
|
||||
*
|
||||
* Only refresh is supported and relayed to all childs of this thing.
|
||||
*
|
||||
* @param channelUID for which the command is issued
|
||||
* @param command command issued
|
||||
*/
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
this.updateChannels();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynnamically updates all known channel states of the energy manager.
|
||||
*/
|
||||
public void updateChannels() {
|
||||
Map<String, Device> devices = this.getDevices();
|
||||
if (devices != null) {
|
||||
if (this.energyManagerGuid == null) {
|
||||
try {
|
||||
this.findEnergyManagerGuid(devices);
|
||||
} catch (SolarwattConnectionException ex) {
|
||||
this.logger.warn("Failed updating EnergyManager channels: {}", ex.getMessage());
|
||||
}
|
||||
}
|
||||
EnergyManager energyManager = (EnergyManager) devices.get(this.energyManagerGuid);
|
||||
|
||||
if (energyManager != null) {
|
||||
this.calculateUpdates(energyManager);
|
||||
|
||||
energyManager.getStateValues().forEach((stateName, stateValue) -> {
|
||||
this.updateState(stateName, stateValue);
|
||||
});
|
||||
} else {
|
||||
this.logger.warn("updateChannels failed, missing device EnergyManager {}", this.energyManagerGuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateUpdates(EnergyManager energyManager) {
|
||||
State timezoneState = energyManager.getState(CHANNEL_IDTIMEZONE.getChannelName());
|
||||
if (timezoneState != null) {
|
||||
this.zoneId = ZoneId.of(timezoneState.toFullString());
|
||||
}
|
||||
|
||||
BigDecimal timestamp = energyManager.getBigDecimalFromChannel(CHANNEL_TIMESTAMP.getChannelName());
|
||||
if (timestamp.compareTo(BigDecimal.ONE) > 0) {
|
||||
energyManager.addState(CHANNEL_DATETIME.getChannelName(),
|
||||
new DateTimeType(this.getFromMilliTimestamp(timestamp)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial setup of the channels available for this thing.
|
||||
*
|
||||
* @param device which provides the channels
|
||||
*/
|
||||
protected void initDeviceChannels(Device device) {
|
||||
this.assertChannel(new SolarwattChannel(CHANNEL_DATETIME.getChannelName(), "time"));
|
||||
|
||||
device.getSolarwattChannelSet().forEach((channelTag, solarwattChannel) -> {
|
||||
this.assertChannel(solarwattChannel);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that all channels inside of our thing are well defined.
|
||||
*
|
||||
* Only channel which can not be found are created.
|
||||
*
|
||||
* @param solarwattChannel channel description with name and unit
|
||||
*/
|
||||
protected void assertChannel(SolarwattChannel solarwattChannel) {
|
||||
ChannelUID channelUID = new ChannelUID(this.getThing().getUID(), solarwattChannel.getChannelName());
|
||||
ChannelTypeUID channelType = this.channelTypeProvider.assertChannelType(solarwattChannel);
|
||||
if (this.getThing().getChannel(channelUID) == null) {
|
||||
ThingBuilder thingBuilder = this.editThing();
|
||||
thingBuilder.withChannel(
|
||||
SimpleDeviceHandler.getChannelBuilder(solarwattChannel, channelUID, channelType).build());
|
||||
|
||||
this.updateThing(thingBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the guid of the energy manager inside of the known devices.
|
||||
*
|
||||
* @param devices list with known devices
|
||||
* @throws SolarwattConnectionException if there is no energy manager available
|
||||
*/
|
||||
private void findEnergyManagerGuid(Map<String, Device> devices) throws SolarwattConnectionException {
|
||||
devices.forEach((guid, device) -> {
|
||||
if (device instanceof EnergyManager) {
|
||||
this.energyManagerGuid = guid;
|
||||
}
|
||||
});
|
||||
|
||||
if (this.energyManagerGuid == null) {
|
||||
throw new SolarwattConnectionException("unable to find energy manager");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the handler and trigger initial load via {@link EnergyManagerHandler::refreshDevices}.
|
||||
*
|
||||
* Web request against energy manager and loading of devices is deferred and will send the ONLINE
|
||||
* event after loading all devices.
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
SolarwattBridgeConfiguration localConfig = this.getConfigAs(SolarwattBridgeConfiguration.class);
|
||||
this.initRefresh(localConfig);
|
||||
this.initDeviceCache(localConfig);
|
||||
}
|
||||
|
||||
private void initDeviceCache(SolarwattBridgeConfiguration localConfig) {
|
||||
if (localConfig.hostname.isEmpty()) {
|
||||
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Hostname is not set");
|
||||
} else {
|
||||
this.updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
|
||||
"Waiting to retrieve devices.");
|
||||
this.connector.setConfiguration(localConfig);
|
||||
|
||||
this.devicesCache = new ExpiringCache<>(Duration.of(localConfig.refresh, ChronoUnit.SECONDS),
|
||||
this::refreshDevices);
|
||||
|
||||
ExpiringCache<Map<String, Device>> localDevicesCache = this.devicesCache;
|
||||
if (localDevicesCache != null) {
|
||||
// trigger initial load
|
||||
this.scheduler.execute(localDevicesCache::getValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the refresh job and remove devices.
|
||||
*/
|
||||
@Override
|
||||
public void dispose() {
|
||||
ScheduledFuture<?> localRefreshJob = this.refreshJob;
|
||||
if (localRefreshJob != null && !localRefreshJob.isCancelled()) {
|
||||
localRefreshJob.cancel(true);
|
||||
this.refreshJob = null;
|
||||
}
|
||||
|
||||
this.devicesCache = null;
|
||||
}
|
||||
|
||||
private synchronized void initRefresh(SolarwattBridgeConfiguration localConfig) {
|
||||
ScheduledFuture<?> localRefreshJob = this.refreshJob;
|
||||
if (localRefreshJob == null || localRefreshJob.isCancelled()) {
|
||||
this.refreshJob = this.scheduler.scheduleWithFixedDelay(this.refreshRunnable, 0, localConfig.refresh,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the map of devices from the cache.
|
||||
*
|
||||
* Used by all childs to get their values.
|
||||
*
|
||||
* @return map with all {@link Device}s
|
||||
*/
|
||||
public @Nullable Map<String, Device> getDevices() {
|
||||
ExpiringCache<Map<String, Device>> localDevicesCache = this.devicesCache;
|
||||
if (localDevicesCache != null) {
|
||||
Map<String, Device> cache = localDevicesCache.getValue();
|
||||
if (cache != null) {
|
||||
this.updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
this.updateStatus(ThingStatus.OFFLINE);
|
||||
}
|
||||
|
||||
return cache;
|
||||
} else {
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a device for a specific guid.
|
||||
*
|
||||
* @param guid to search for
|
||||
* @return device belonging to guid or null if not found.
|
||||
*/
|
||||
public @Nullable Device getDeviceFromGuid(String guid) {
|
||||
Map<String, Device> localDevices = this.getDevices();
|
||||
if (localDevices != null && localDevices.containsKey(guid)) {
|
||||
return localDevices.get(guid);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the energy manager millisecond timestamps to {@link ZonedDateTime}
|
||||
*
|
||||
* The energy manager is the only point that knows about the timezone and
|
||||
* it is available to all other devices. All timestamps used by all devices
|
||||
* are in milliseconds since the epoch.
|
||||
*
|
||||
* @param timestamp milliseconds since the epoch
|
||||
* @return date time in timezone
|
||||
*/
|
||||
public ZonedDateTime getFromMilliTimestamp(BigDecimal timestamp) {
|
||||
Map<String, Device> devices = this.getDevices();
|
||||
if (devices != null) {
|
||||
EnergyManager energyManager = (EnergyManager) devices.get(this.energyManagerGuid);
|
||||
if (energyManager != null) {
|
||||
BigDecimal[] bigDecimals = timestamp.divideAndRemainder(BigDecimal.valueOf(1_000));
|
||||
Instant instant = Instant.ofEpochSecond(bigDecimals[0].longValue(),
|
||||
bigDecimals[1].multiply(BigDecimal.valueOf(1_000_000)).longValue());
|
||||
|
||||
ZoneId localZoneID = this.zoneId;
|
||||
if (localZoneID != null) {
|
||||
return ZonedDateTime.ofInstant(instant, localZoneID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new DateTimeException("Timezone from energy manager missing.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload all devices from the energy manager.
|
||||
*
|
||||
* This method is called via the {@link ExpiringCache}.
|
||||
*
|
||||
* @return map from guid to {@link Device}}
|
||||
*/
|
||||
private @Nullable Map<String, Device> refreshDevices() {
|
||||
try {
|
||||
final Map<String, Device> devicesData = this.connector.retrieveDevices().getDevices();
|
||||
this.updateStatus(ThingStatus.ONLINE);
|
||||
|
||||
// trigger refresh of the available channels
|
||||
if (devicesData.containsKey(this.energyManagerGuid)) {
|
||||
Device device = devicesData.get(this.energyManagerGuid);
|
||||
if (device != null) {
|
||||
this.initDeviceChannels(device);
|
||||
}
|
||||
} else {
|
||||
this.logger.warn("{}: initDeviceChannels missing energy manager {}", this, this.getThing().getUID());
|
||||
}
|
||||
|
||||
return devicesData;
|
||||
} catch (final SolarwattConnectionException e) {
|
||||
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger an update on all child things of this bridge.
|
||||
*/
|
||||
private void updateAllChildThings() {
|
||||
this.getThing().getThings().forEach(childThing -> {
|
||||
try {
|
||||
ThingHandler childHandler = childThing.getHandler();
|
||||
if (childHandler != null) {
|
||||
childHandler.handleCommand(new ChannelUID(childThing.getUID(), CHANNEL_TIMESTAMP.getChannelName()),
|
||||
RefreshType.REFRESH);
|
||||
} else {
|
||||
this.logger.warn("no handler found for thing/device {}",
|
||||
childThing.getConfiguration().as(SolarwattThingConfiguration.class).guid);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
this.logger.warn("Error processing child with uid {}", childThing.getUID(), ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.handler;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solarwatt.internal.channel.SolarwattChannelTypeProvider;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.Device;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.EVStation;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.Location;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.PowerMeter;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The concrete device handlers process the location specific commands.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LocationHandler extends SimpleDeviceHandler {
|
||||
|
||||
public LocationHandler(Thing thing, SolarwattChannelTypeProvider channelTypeProvider) {
|
||||
super(thing, channelTypeProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add calculated states for unmetered consum.
|
||||
*
|
||||
* First calculate and then call super to submit the state
|
||||
*/
|
||||
@Override
|
||||
protected void updateDeviceChannels() {
|
||||
// add calculated states
|
||||
this.updateCalculated();
|
||||
|
||||
// submits all states
|
||||
super.updateDeviceChannels();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add calculated channels for unmetered consum.
|
||||
*
|
||||
* First calculate and then call super to submit the channels
|
||||
*/
|
||||
@Override
|
||||
protected void initDeviceChannels() {
|
||||
// add calculated channels
|
||||
final EnergyManagerHandler bridgeHandler = this.getEnergyManagerHandler();
|
||||
if (bridgeHandler != null) {
|
||||
// update the unmetered channel via subtracting the outerconsumers
|
||||
// from the powerConsumed
|
||||
Location locationDevice = (Location) this.getDevice();
|
||||
if (locationDevice != null) {
|
||||
locationDevice.addChannel(CHANNEL_POWER_DIRECT_CONSUMED.getChannelName(), Units.WATT,
|
||||
Device.WATT_CATEGORY, false);
|
||||
locationDevice.addChannel(CHANNEL_WORK_DIRECT_CONSUMED.getChannelName(), Units.WATT_HOUR,
|
||||
Device.WATT_HOUR_CATEGORY, false);
|
||||
locationDevice.addChannel(CHANNEL_POWER_CONSUMED_UNMETERED.getChannelName(), Units.WATT,
|
||||
Device.WATT_CATEGORY, false);
|
||||
locationDevice.addChannel(CHANNEL_WORK_CONSUMED_UNMETERED.getChannelName(), Units.WATT_HOUR,
|
||||
Device.WATT_HOUR_CATEGORY, false);
|
||||
}
|
||||
}
|
||||
|
||||
// submit all channels
|
||||
super.initDeviceChannels();
|
||||
}
|
||||
|
||||
private void updateCalculated() {
|
||||
final EnergyManagerHandler bridgeHandler = this.getEnergyManagerHandler();
|
||||
final Location locationDevice = (Location) this.getDevice();
|
||||
if (bridgeHandler != null && locationDevice != null) {
|
||||
this.calculateDirectConsumption(locationDevice);
|
||||
this.calculateUnmeteredConsumption(bridgeHandler, locationDevice);
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateUnmeteredConsumption(EnergyManagerHandler bridgeHandler, Location locationDevice) {
|
||||
// update the unmetered channels via subtracting
|
||||
// the outerconsumers from the powerConsumed
|
||||
BigDecimal powerConsumed = locationDevice.getBigDecimalFromChannel(CHANNEL_POWER_CONSUMED.getChannelName());
|
||||
BigDecimal workConsumed = locationDevice.getBigDecimalFromChannel(CHANNEL_WORK_CONSUMED.getChannelName());
|
||||
|
||||
final List<BigDecimal> powerOuter = new ArrayList<>();
|
||||
final List<BigDecimal> workOuter = new ArrayList<>();
|
||||
|
||||
Set<String> outerConsumers = locationDevice.getDevicesMap().getOuterConsumer();
|
||||
if (outerConsumers != null) {
|
||||
outerConsumers.stream().map(bridgeHandler::getDeviceFromGuid).forEach(outerDevice -> {
|
||||
if (outerDevice instanceof PowerMeter) {
|
||||
powerOuter.add(outerDevice.getBigDecimalFromChannel(CHANNEL_POWER_IN.getChannelName()));
|
||||
workOuter.add(outerDevice.getBigDecimalFromChannel(CHANNEL_WORK_IN.getChannelName()));
|
||||
} else if (outerDevice instanceof EVStation) {
|
||||
powerOuter.add(outerDevice.getBigDecimalFromChannel(CHANNEL_POWER_AC_IN.getChannelName()));
|
||||
workOuter.add(outerDevice.getBigDecimalFromChannel(CHANNEL_WORK_AC_IN.getChannelName()));
|
||||
}
|
||||
});
|
||||
|
||||
BigDecimal powerConsumedUnmetered = powerOuter.stream().reduce(powerConsumed, BigDecimal::subtract);
|
||||
if (powerConsumedUnmetered.compareTo(BigDecimal.ONE) > 0) {
|
||||
// sometimes the powerConsumed is exactly the power of the unmetered devices
|
||||
// the resulting zero for unmetered consumption is not correct
|
||||
locationDevice.addStateBigDecimal(CHANNEL_POWER_CONSUMED_UNMETERED, powerConsumedUnmetered, Units.WATT);
|
||||
}
|
||||
locationDevice.addStateBigDecimal(CHANNEL_WORK_CONSUMED_UNMETERED,
|
||||
workOuter.stream().reduce(workConsumed, BigDecimal::subtract), Units.WATT_HOUR);
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateDirectConsumption(Location locationDevice) {
|
||||
// calculate direct consumption for display purposes
|
||||
locationDevice.addState(CHANNEL_POWER_DIRECT_CONSUMED.getChannelName(),
|
||||
this.calculateQuantityDifference(locationDevice.getState(CHANNEL_POWER_SELF_CONSUMED.getChannelName()),
|
||||
locationDevice.getState(CHANNEL_POWER_BUFFERED_FROM_PRODUCERS.getChannelName())));
|
||||
|
||||
locationDevice.addState(CHANNEL_WORK_DIRECT_CONSUMED.getChannelName(),
|
||||
this.calculateQuantityDifference(locationDevice.getState(CHANNEL_WORK_SELF_CONSUMED.getChannelName()),
|
||||
locationDevice.getState(CHANNEL_WORK_BUFFERED_FROM_PRODUCERS.getChannelName())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to generate a new state calculated from the difference between two states.
|
||||
*
|
||||
* channelTarget = channelValue - channelSubtract
|
||||
*
|
||||
* @param stateValue value from which we subtract
|
||||
* @param stateSubtract value to substrct
|
||||
* @return {@link State} of calculated value
|
||||
*/
|
||||
private @Nullable State calculateQuantityDifference(@Nullable State stateValue, @Nullable State stateSubtract) {
|
||||
if (stateValue != null && stateSubtract != null) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
QuantityType quantityValue = stateValue.as(QuantityType.class);
|
||||
@SuppressWarnings("rawtypes")
|
||||
QuantityType quantitySubtract = stateSubtract.as(QuantityType.class);
|
||||
|
||||
if (quantityValue != null && quantitySubtract != null) {
|
||||
return quantityValue.subtract(quantitySubtract);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,250 @@
|
||||
/**
|
||||
* 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.solarwatt.internal.handler;
|
||||
|
||||
import static org.openhab.binding.solarwatt.internal.SolarwattBindingConstants.*;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solarwatt.internal.channel.SolarwattChannelTypeProvider;
|
||||
import org.openhab.binding.solarwatt.internal.configuration.SolarwattThingConfiguration;
|
||||
import org.openhab.binding.solarwatt.internal.domain.SolarwattChannel;
|
||||
import org.openhab.binding.solarwatt.internal.domain.model.Device;
|
||||
import org.openhab.core.library.CoreItemFactory;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.BridgeHandler;
|
||||
import org.openhab.core.thing.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.thing.type.ChannelKind;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.util.UnitUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link SimpleDeviceHandler} bundles everything related to generic talking to devices.
|
||||
*
|
||||
* @author Sven Carstens - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SimpleDeviceHandler extends BaseThingHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(SimpleDeviceHandler.class);
|
||||
|
||||
private final SolarwattChannelTypeProvider channelTypeProvider;
|
||||
|
||||
public SimpleDeviceHandler(Thing thing, SolarwattChannelTypeProvider channelTypeProvider) {
|
||||
super(thing);
|
||||
this.channelTypeProvider = channelTypeProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bring the thing online and update state from the bridge.
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
final EnergyManagerHandler bridgeHandler = this.getEnergyManagerHandler();
|
||||
if (bridgeHandler != null) {
|
||||
this.initDeviceChannels();
|
||||
this.updateDeviceProperties();
|
||||
this.updateDeviceChannels();
|
||||
} else {
|
||||
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the command for this thing.
|
||||
*
|
||||
* Only refresh is supported in this case.
|
||||
*
|
||||
* @param channelUID channel for which the command was issued
|
||||
* @param command to execute
|
||||
*/
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
final EnergyManagerHandler bridgeHandler = this.getEnergyManagerHandler();
|
||||
if (bridgeHandler != null) {
|
||||
if (command instanceof RefreshType) {
|
||||
this.updateDeviceProperties();
|
||||
this.updateDeviceChannels();
|
||||
}
|
||||
} else {
|
||||
this.logger.warn("Thing {} has no bridgeHandler for Bridge {}", this.getThing().getUID(),
|
||||
this.getThing().getBridgeUID());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the state of all channels.
|
||||
*/
|
||||
protected void updateDeviceChannels() {
|
||||
// find device for the thing
|
||||
Device device = this.getDevice();
|
||||
|
||||
if (device != null) {
|
||||
device.getStateValues().forEach(this::updateState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that all {@link org.openhab.core.thing.type.ChannelType}s are registered for this thing.
|
||||
*/
|
||||
protected void initDeviceChannels() {
|
||||
// find device for the thing
|
||||
Device device = this.getDevice();
|
||||
|
||||
if (device != null) {
|
||||
device.getSolarwattChannelSet().forEach((channelTag, solarwattChannel) -> {
|
||||
this.assertChannel(solarwattChannel);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the properties for this device.
|
||||
*/
|
||||
protected void updateDeviceProperties() {
|
||||
// find device for the thing
|
||||
Device device = this.getDevice();
|
||||
|
||||
if (device != null) {
|
||||
// update properties
|
||||
Map<String, String> properties = this.editProperties();
|
||||
this.putProperty(properties, PROPERTY_ID_NAME, device.getIdName());
|
||||
this.putProperty(properties, PROPERTY_ID_FIRMWARE, device.getIdFirmware());
|
||||
this.putProperty(properties, PROPERTY_ID_MANUFACTURER, device.getIdManufacturer());
|
||||
this.updateProperties(properties);
|
||||
|
||||
// relay state of device to status
|
||||
this.updateStatus(device.getStateDevice());
|
||||
}
|
||||
}
|
||||
|
||||
private void putProperty(Map<String, String> properties, String name, @Nullable String value) {
|
||||
if (value != null) {
|
||||
properties.put(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that all channels inside of our thing are well defined.
|
||||
*
|
||||
* Only channels which can not be found are created.
|
||||
*
|
||||
* @param solarwattChannel channel description with name and unit
|
||||
*/
|
||||
protected void assertChannel(SolarwattChannel solarwattChannel) {
|
||||
ChannelUID channelUID = new ChannelUID(this.getThing().getUID(), solarwattChannel.getChannelName());
|
||||
ChannelTypeUID channelType = this.channelTypeProvider.assertChannelType(solarwattChannel);
|
||||
if (this.getThing().getChannel(channelUID) == null) {
|
||||
ThingBuilder thingBuilder = this.editThing();
|
||||
thingBuilder.withChannel(getChannelBuilder(solarwattChannel, channelUID, channelType).build());
|
||||
|
||||
this.updateThing(thingBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a builder for a channel type according to the {@link SolarwattChannel}
|
||||
*
|
||||
* @param solarwattChannel channel type definition
|
||||
* @param channelUID uid of the channel
|
||||
* @param channelType uid of the channel type
|
||||
* @return builder for that channel type
|
||||
*/
|
||||
public static ChannelBuilder getChannelBuilder(SolarwattChannel solarwattChannel, ChannelUID channelUID,
|
||||
ChannelTypeUID channelType) {
|
||||
String itemType = CoreItemFactory.STRING;
|
||||
Unit<?> unit = solarwattChannel.getUnit();
|
||||
if (unit != null) {
|
||||
String dimension = UnitUtils.getDimensionName(unit);
|
||||
|
||||
if (Units.PERCENT.equals(unit)) {
|
||||
// strangely it is Angle
|
||||
dimension = ":Dimensionless";
|
||||
}
|
||||
|
||||
itemType = CoreItemFactory.NUMBER;
|
||||
if (dimension != null && !dimension.isEmpty()) {
|
||||
itemType = CoreItemFactory.NUMBER + ":" + dimension;
|
||||
}
|
||||
}
|
||||
ChannelBuilder channelBuilder = ChannelBuilder.create(channelUID, itemType);
|
||||
|
||||
channelBuilder.withLabel(solarwattChannel.getChannelName()).withType(channelType).withDescription(MessageFormat
|
||||
.format("Value for {0} with Unit: {1}", solarwattChannel.getChannelName(), solarwattChannel.getUnit()))
|
||||
.withKind(ChannelKind.STATE);
|
||||
return channelBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link EnergyManagerHandler}.
|
||||
*
|
||||
* Only the {@link EnergyManagerHandler} has knowledge about the devices itself.
|
||||
*
|
||||
* @return instance responsible for this handler
|
||||
*/
|
||||
protected @Nullable EnergyManagerHandler getEnergyManagerHandler() {
|
||||
Bridge bridge = this.getBridge();
|
||||
if (bridge != null) {
|
||||
BridgeHandler bridgeHandler = bridge.getHandler();
|
||||
if (bridgeHandler instanceof EnergyManagerHandler) {
|
||||
return (EnergyManagerHandler) bridgeHandler;
|
||||
} else {
|
||||
// happens while dynamically reloading the binding
|
||||
this.logger.warn("BridgeHandler is not implementing EnergyManagerHandler {}", bridgeHandler);
|
||||
}
|
||||
} else {
|
||||
// this handler can't work without a bridge
|
||||
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing!");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Device} from the {@link EnergyManagerHandler}.
|
||||
*
|
||||
* @return model with values
|
||||
*/
|
||||
protected @Nullable Device getDevice() {
|
||||
final EnergyManagerHandler bridgeHandler = this.getEnergyManagerHandler();
|
||||
|
||||
if (bridgeHandler != null) {
|
||||
Map<String, Device> bridgeDevices = bridgeHandler.getDevices();
|
||||
if (bridgeDevices != null) {
|
||||
return bridgeDevices.get(this.getConfigAs(SolarwattThingConfiguration.class).guid);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.warn("Device not found for thing with guid {}",
|
||||
this.getConfigAs(SolarwattThingConfiguration.class).guid);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="solarwatt" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>Solarwatt Binding</name>
|
||||
<description>This is the binding for Solarwatt Energymanager.</description>
|
||||
|
||||
</binding:binding>
|
@ -0,0 +1,37 @@
|
||||
<?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:solarwatt:energymanager">
|
||||
<parameter name="hostname" type="text">
|
||||
<label>Host Name</label>
|
||||
<description>The host name/ip address of the solarwatt energymanager.</description>
|
||||
<context>network-address</context>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" unit="s">
|
||||
<label>Refresh Data Period</label>
|
||||
<description>Period between updates to the devices data in seconds.
|
||||
</description>
|
||||
<default>30</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="rescan" type="integer" unit="min">
|
||||
<label>Redetect Devices Period</label>
|
||||
<description>Period between updates to the detected devices in minutes.
|
||||
</description>
|
||||
<default>5</default>
|
||||
<unitLabel>min</unitLabel>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
<config-description uri="thing-type:solarwatt:device">
|
||||
<parameter name="guid" type="text">
|
||||
<label>Guid of Device</label>
|
||||
<description>Guid of the device as used by the solarwatt energymanager.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</config-description:config-descriptions>
|
@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="solarwatt"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<bridge-type id="energymanager">
|
||||
<label>Solarwatt Energymanager</label>
|
||||
<description>Solarwatt Energymanager is the bridge to all things attached to the PV production system.
|
||||
</description>
|
||||
|
||||
<representation-property>hostname</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:solarwatt:energymanager"/>
|
||||
</bridge-type>
|
||||
|
||||
<thing-type id="evstation">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="energymanager"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>EV Station</label>
|
||||
<description>Electric vehicle charger station</description>
|
||||
|
||||
<representation-property>IdName</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:solarwatt:device"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="batteryconverter">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="energymanager"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Battery Converter</label>
|
||||
<description>Battery converter to supply AC from battery storage.</description>
|
||||
|
||||
<representation-property>IdName</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:solarwatt:device"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="location">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="energymanager"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Location</label>
|
||||
<description>Location aggregates all things taking part in the production process.</description>
|
||||
|
||||
<representation-property>IdName</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:solarwatt:device"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="pvplant">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="energymanager"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>PV Plant</label>
|
||||
<description>Photovoltaic plant generating DC from solar energy.</description>
|
||||
|
||||
<representation-property>IdName</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:solarwatt:device"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="gridflow">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="energymanager"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Gridflow</label>
|
||||
<description>Gridflow regulates interaction with the external power grid.</description>
|
||||
|
||||
<representation-property>IdName</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:solarwatt:device"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="powermeter">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="energymanager"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Power Meter</label>
|
||||
<description>Power meter for produced or consumed energy</description>
|
||||
|
||||
<representation-property>IdName</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:solarwatt:device"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="inverter">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="energymanager"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Inverter</label>
|
||||
<description>Inverter supplying AC from DC.</description>
|
||||
|
||||
<representation-property>IdName</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:solarwatt:device"/>
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -303,6 +303,7 @@
|
||||
<module>org.openhab.binding.snmp</module>
|
||||
<module>org.openhab.binding.solaredge</module>
|
||||
<module>org.openhab.binding.solarlog</module>
|
||||
<module>org.openhab.binding.solarwatt</module>
|
||||
<module>org.openhab.binding.somfymylink</module>
|
||||
<module>org.openhab.binding.somfytahoma</module>
|
||||
<module>org.openhab.binding.sonos</module>
|
||||
|
Loading…
Reference in New Issue
Block a user