mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 07:02:02 +01:00
[sunsynk] Initial contribution (#16753)
* Initial Signed-off-by: LeeC77 <lee.charlton00@gmail.com>
This commit is contained in:
parent
c1dbc33cf3
commit
fd70c5d6ef
@ -360,6 +360,7 @@
|
||||
/bundles/org.openhab.binding.speedtest/ @MikeTheTux
|
||||
/bundles/org.openhab.binding.spotify/ @Hilbrand
|
||||
/bundles/org.openhab.binding.squeezebox/ @digitaldan @mhilbush
|
||||
/bundles/org.openhab.binding.sunsynk/ @leeC77
|
||||
/bundles/org.openhab.binding.surepetcare/ @renescherer @HerzScheisse
|
||||
/bundles/org.openhab.binding.synopanalyzer/ @clinique
|
||||
/bundles/org.openhab.binding.systeminfo/ @mherwege
|
||||
|
@ -1796,6 +1796,11 @@
|
||||
<artifactId>org.openhab.binding.squeezebox</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.sunsynk</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.surepetcare</artifactId>
|
||||
|
13
bundles/org.openhab.binding.sunsynk/NOTICE
Normal file
13
bundles/org.openhab.binding.sunsynk/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
|
202
bundles/org.openhab.binding.sunsynk/README.md
Normal file
202
bundles/org.openhab.binding.sunsynk/README.md
Normal file
@ -0,0 +1,202 @@
|
||||
# SunSynk Binding
|
||||
|
||||
This binding integrates the [Sun Synk Connect web services](https://www.sunsynk.net/).
|
||||
This binding is used to connect your openHAB system with Sun Synk Connect (where you log in and find Your Inverters).
|
||||
From the binding, you will get status of your inverters and also command channels where you can control them.
|
||||
Since the binding uses a polling mechanism, there may be some latency depending on your setting regarding refresh time.
|
||||
|
||||
## Introduction
|
||||
|
||||
You will require to have installed a Sun Synk inverter with a WiFi [Data logger](https://www.sunsynk.org/remote-monitoring) (or [e-linter](https://www.e-linter.com/)) connected to the Sun Synk App or Connect.
|
||||
See [Data Logger set up](https://www.sunsynk.org/_files/ugd/39fbfb_a325b6884e684c4ba1a3ad80afd5da20.pdf) or [Sun Synk Web](https://www.sunsynk.org/remote-monitoring).
|
||||
It is recommended, but not necessary that the "data interval" of your Gateway is set via Sun Synk Connect to 60s for best latency.
|
||||
If you do not have that setting available you can request it set via Sun Synk, your installer or you can ask for an [User Level Access Change Request](https://www.sunsynk.org/remote-monitoring)
|
||||
|
||||
This binding uses your Sun Synk Connect credentials to access Sun Synk's web services via an openHAB Bridge (SunSynk Account).
|
||||
The bridge manages the account authentication and the discovery of SunSynk Inverter Things. Only the Inverter Thing is currently supported.
|
||||
|
||||
Acknowledgements:
|
||||
|
||||
- [Power Forum](https://powerforum.co.za/topic/12604-sunsynk-wifi-dongle-hacking/page/3/)
|
||||
- [AsTheSeaRises](https://github.com/AsTheSeaRises/SunSynk_API)
|
||||
- [jamesridgway](https://github.com/jamesridgway/sunsynk-api-client/tree/main)
|
||||
- [kellerza](https://github.com/kellerza/sunsynk)
|
||||
|
||||
## Supported Things
|
||||
|
||||
|Name | Thing type | Thing Id |
|
||||
|----------------|---------------|------------|
|
||||
|SunSynk Account | Bridge Thing | account |
|
||||
|SunSynk Inverter| Thing | inverter |
|
||||
|
||||
## Discovery
|
||||
|
||||
The binding supports discovery via configuring your login and password in an openHAB bridge.
|
||||
|
||||
1. Add the sunsynk binding.
|
||||
1. Add a new thing of type SunSynk Account via the SunSynk Binding and configure with username and password.
|
||||
1. Go to Inbox press \[+\] and via the SunSynk Account start discovery \[Scan\] of inverters.
|
||||
1. Inverters should appear in your inbox!
|
||||
|
||||
The SunSynk Account bridge thing will discover connected inverters through the UI Scan service.
|
||||
When using the UI Scan service all the parameters for an Inverter Thing are discovered.
|
||||
|
||||
- Inverter Serial maps to the Sun Synk Connect inverter serial number
|
||||
- Inverter Name maps to the Sun Synk Connect inverter alias
|
||||
- Refresh time (advanced) default 60s; determines the interval between polls of Sun Synk Connect. A value above 60 is enforced. When setting this remember your inverter values are only published by Sun Synk Connect at the rate set by "data interval".
|
||||
|
||||
The refresh rate is limited to once every 60s to prevent too many requests from the Sun Synk Connect API, although there is no rate limit, the Sun Synk data is fully refreshed at the "data interval" set in Sun Synk Connect, at best that is every 60s.
|
||||
This can mean the data in openHAB is more than 1 minute delayed from real-time.
|
||||
Commands sent (from openHAB) to Sun Synk are buffered up until the next refresh interval and as they take a while to propagate through to your inverter, some channels are not refreshed (read back) from Sun Synk Connect until the next minute.
|
||||
|
||||
The SunSynk Account requires the user e-mail address and password used to login to Sun Synk Connect.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
### `sunsynk:account` Bridge Thing Configuration
|
||||
|
||||
| Name | Type | Description | Default | Required | Advanced |
|
||||
|-----------------|---------|-------------------------------------------------|---------|----------|----------|
|
||||
| email | text | Email address used to login Sun Synk Connect | N/A | yes | no |
|
||||
| password | text | Password to access the Sun Synk Connect account | N/A | yes | no |
|
||||
|
||||
### `sunsynk:inverter:` Thing Configuration
|
||||
|
||||
| Name | Type | Description | Default | Required | Advanced |
|
||||
|--------------|---------|---------------------------------------------|---------|----------|----------|
|
||||
| alias | text | The Sun Synk Connect inverter alias | N/A | yes | no |
|
||||
| serialnumber | text | The Sun Synk Connect inverter serial number | N/A | yes | no |
|
||||
| refresh | integer | Interval the device is polled in sec | 60 | yes | yes |
|
||||
|
||||
## Channels
|
||||
|
||||
The SunSynk Account has no channels.
|
||||
The SunSynk Inverter has the following channels.
|
||||
|
||||
| Channel | Type | R/W | Description | Advanced |
|
||||
|--------------------------------|-------------------------|-----|-----------------------------------|----------|
|
||||
|battery-soc |Number:Dimensionless | R | Inverter battery % charge | no |
|
||||
|battery-grid-voltage |Number:ElectricPotential | R | Battery dc electric-voltage | no |
|
||||
|battery-grid-current |Number:ElectricCurrent | R | Battery dc electric-current | no |
|
||||
|battery-grid-power |Number:Power | R | Battery dc electric-power | no |
|
||||
|battery-temperature |Number:Temperature | R | Battery temperature | no |
|
||||
|inverter-ac-temperature |Number:Temperature | R | Inverter ac temperature | no |
|
||||
|inverter-dc-temperature |Number:Temperature | R | Inverter dc temperature | no |
|
||||
|inverter-grid-power |Number:Power | R | Inverter ac electric-power | no |
|
||||
|inverter-grid-voltage |Number:ElectricPotential | R | Inverter ac electric-voltage | no |
|
||||
|inverter-grid-current |Number:ElectricCurrent | R | Inverter ac electric-current | no |
|
||||
|inverter-solar-energy-today |Number:Energy | R | Solar dc energy generated today | no |
|
||||
|inverter-solar-energy-total |Number:Energy | R | Solar dc energy generated to date | no |
|
||||
|inverter-solar-power-now |Number:Power | R | Solar dc electric-current | no |
|
||||
|interval-1-grid-charge |Switch | R/W | Interval 1 grid charge on/off | yes |
|
||||
|interval-1-grid-time |DateTime | R/W | Interval 1 start grid charge time | yes |
|
||||
|interval-1-grid-capacity |Number:Dimensionless | R/W | Interval 1 battery charge target | yes |
|
||||
|interval-1-grid-power-limit |Number:Power | R/W | Interval 1 charge power limit | yes |
|
||||
|interval-2-grid-charge |Switch | R/W | Interval 2 grid charge on/off | yes |
|
||||
|interval-2-grid-time |DateTime | R/W | Interval 2 start grid charge time | yes |
|
||||
|interval-2-grid-capacity |Number:Dimensionless | R/W | Interval 2 battery charge target | yes |
|
||||
|interval-2-grid-power-limit |Number:Power | R/W | Interval 2 charge power limit | yes |
|
||||
|interval-3-grid-charge |Switch | R/W | Interval 3 grid charge on/off | yes |
|
||||
|interval-3-grid-time |DateTime | R/W | Interval 3 start grid charge time | yes |
|
||||
|interval-3-grid-capacity |Number:Dimensionless | R/W | Interval 3 battery charge target | yes |
|
||||
|interval-3-grid-power-limit |Number:Power | R/W | Interval 3 charge power limit | yes |
|
||||
|interval-4-grid-charge |Switch | R/W | Interval 4 grid charge on/off | yes |
|
||||
|interval-4-grid-time |DateTime | R/W | Interval 4 start grid charge time | yes |
|
||||
|interval-4-grid-capacity |Number:Dimensionless | R/W | Interval 4 battery charge target | yes |
|
||||
|interval-4-grid-power-limit |Number:Power | R/W | Interval 4 charge power limit | yes |
|
||||
|interval-5-grid-charge |Switch | R/W | Interval 5 grid charge on/off | yes |
|
||||
|interval-5-grid-time |DateTime | R/W | Interval 5 start grid charge time | yes |
|
||||
|interval-5-grid-capacity |Number:Dimensionless | R/W | Interval 5 battery charge target | yes |
|
||||
|interval-5-grid-power-limit |Number:Power | R/W | Interval 5 charge power limit | yes |
|
||||
|interval-6-grid-charge |Switch | R/W | Interval 6 grid charge on/off | yes |
|
||||
|interval-6-grid-time |DateTime | R/W | Interval 6 start grid charge time | yes |
|
||||
|interval-6-grid-capacity |Number:Dimensionless | R/W | Interval 6 battery charge target | yes |
|
||||
|interval-6-grid-power-limit |Number:Power | R/W | Interval 6 charge power limit | yes |
|
||||
|interval-1-gen-charge |Switch | R/W | Interval 1 generator charge on/of | yes |
|
||||
|interval-2-gen-charge |Switch | R/W | Interval 2 generator charge on/of | yes |
|
||||
|interval-3-gen-charge |Switch | R/W | Interval 3 generator charge on/of | yes |
|
||||
|interval-4-gen-charge |Switch | R/W | Interval 4 generator charge on/of | yes |
|
||||
|interval-5-gen-charge |Switch | R/W | Interval 5 generator charge on/of | yes |
|
||||
|interval-6-gen-charge |Switch | R/W | Interval 6 generator charge on/of | yes |
|
||||
|inverter-control-timer |Switch | R/W | Inverter control timer on/off | yes |
|
||||
|inverter-control-work-mode |String | R/W | Inverter work mode 1, 2 or 3 | yes |
|
||||
|inverter-control-energy-pattern |String | R/W | Inverter energy pattern 1 or 2 | yes |
|
||||
|
||||
### Full Example
|
||||
|
||||
#### sunsynk.things
|
||||
|
||||
```java
|
||||
Bridge sunsynk:account:xxx @ "Loft" [email= "user.symbol@domain.", password="somepassword"]{
|
||||
Thing inverter E1234567R1231234567890 @ "Loft" [alias= "My Inverter", serialnumber= "1234567890", refresh= 60]
|
||||
}
|
||||
```
|
||||
|
||||
#### sunsynk.items
|
||||
|
||||
```java
|
||||
Switch Interval1GridCharge "Switch on Grid Charge for Interval 1" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-1-grid-charge"}
|
||||
Switch Interval2GridCharge "Switch on Grid Charge for Interval 2" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-2-grid-charge"}
|
||||
Switch Interval3GridCharge "Switch on Grid Charge for Interval 3" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-3-grid-charge"}
|
||||
Switch Interval4GridCharge "Switch on Grid Charge for Interval 4" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-4-grid-charge"}
|
||||
Switch Interval5GridCharge "Switch on Grid Charge for Interval 5" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-5-grid-charge"}
|
||||
Switch Interval6GridCharge "Switch on Grid Charge for Interval 6" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-6-grid-charge"}
|
||||
|
||||
Switch Interval1GenCharge "Switch on Generator Charge for Interval 1" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-1-gen-charge"}
|
||||
Switch Interval2GenCharge "Switch on Generator Charge for Interval 2" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-2-gen-charge"}
|
||||
Switch Interval3GenCharge "Switch on Generator Charge for Interval 3" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-3-gen-charge"}
|
||||
Switch Interval4GenCharge "Switch on Generator Charge for Interval 4" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-4-gen-charge"}
|
||||
Switch Interval5GenCharge "Switch on Generator Charge for Interval 5" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-5-gen-charge"}
|
||||
Switch Interval6GenCharge "Switch on Generator Charge for Interval 6" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-6-gen-charge"}
|
||||
|
||||
DateTime Interval1GridTime "Time for Interval 1" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-1-grid-time", widget="widget:rlk_datetime_standalone"[label="Time Picker"]}
|
||||
DateTime Interval2GridTime "Time for Interval 2" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-2-grid-time", widget="widget:rlk_datetime_standalone"[label="Time Picker"]}
|
||||
DateTime Interval3GridTime "Time for Interval 3" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-3-grid-time", widget="widget:rlk_datetime_standalone"[label="Time Picker"]}
|
||||
DateTime Interval4GridTime "Time for Interval 4" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-4-grid-time", widget="widget:rlk_datetime_standalone"[label="Time Picker"]}
|
||||
DateTime Interval5GridTime "Time for Interval 5" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-5-grid-time", widget="widget:rlk_datetime_standalone"[label="Time Picker"]}
|
||||
DateTime Interval6GridTime "Time for Interval 6" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-6-grid-time", widget="widget:rlk_datetime_standalone"[label="Time Picker"]}
|
||||
|
||||
Number:Dimensionless Interval1GridCapacity "Charge Target Interval 1" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-1-grid-capacity", widget="oh-slider-card",listWidget="oh-slider-item"[title="Target SOC",subtitle="Set % SOC"]}
|
||||
Number:Dimensionless Interval2GridCapacity "Charge Target Interval 2" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-2-grid-capacity", widget="oh-slider-card",listWidget="oh-slider-item"[title="Target SOC",subtitle="Set % SOC"]}
|
||||
Number:Dimensionless Interval3GridCapacity "Charge Target Interval 3" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-3-grid-capacity", widget="oh-slider-card",listWidget="oh-slider-item"[title="Target SOC",subtitle="Set % SOC"]}
|
||||
Number:Dimensionless Interval4GridCapacity "Charge Target Interval 4" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-4-grid-capacity", widget="oh-slider-card",listWidget="oh-slider-item"[title="Target SOC",subtitle="Set % SOC"]}
|
||||
Number:Dimensionless Interval5GridCapacity "Charge Target Interval 5" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-5-grid-capacity", widget="oh-slider-card",listWidget="oh-slider-item"[title="Target SOC",subtitle="Set % SOC"]}
|
||||
Number:Dimensionless Interval6GridCapacity "Charge Target Interval 6" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-6-grid-capacity", widget="oh-slider-card",listWidget="oh-slider-item"[title="Target SOC",subtitle="Set % SOC"]}
|
||||
|
||||
Number:Power Interval1GridPowerLimit "Max Charge Power Interval 1" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-1-grid-power-limit", listWidget="oh-slider-item"[title="Target Power Limit",subtitle="Set Limit in Watts", min=0, max=8000,step=1000]}
|
||||
Number:Power Interval2GridPowerLimit "Max Charge Power Interval 2" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-2-grid-power-limit", listWidget="oh-slider-item"[title="Target Power Limit",subtitle="Set Limit in Watts", min=0, max=8000,step=1000]}
|
||||
Number:Power Interval3GridPowerLimit "Max Charge Power Interval 3" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-3-grid-power-limit", listWidget="oh-slider-item"[title="Target Power Limit",subtitle="Set Limit in Watts", min=0, max=8000,step=1000]}
|
||||
Number:Power Interval4GridPowerLimit "Max Charge Power Interval 4" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-4-grid-power-limit", listWidget="oh-slider-item"[title="Target Power Limit",subtitle="Set Limit in Watts", min=0, max=8000,step=1000]}
|
||||
Number:Power Interval5GridPowerLimit "Max Charge Power Interval 5" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-5-grid-power-limit", listWidget="oh-slider-item"[title="Target Power Limit",subtitle="Set Limit in Watts", min=0, max=8000,step=1000]}
|
||||
Number:Power Interval6GridPowerLimit "Max Charge Power Interval 6" {channel="sunsynk:inverter:xxx:1234567R1231234567890:interval-6-grid-power-limit", listWidget="oh-slider-item"[title="Target Power Limit",subtitle="Set Limit in Watts", min=0, max=8000,step=1000]}
|
||||
|
||||
Number:Dimensionless BatterySOC "Battery SOC [%s]" {channel ="sunsynk:inverter:xxx:1234567R1231234567890:battery-soc"}
|
||||
Number:ElectricPotential BatteryGridVoltage "Battery Grid Voltage" {channel="sunsynk:inverter:xxx:1234567R1231234567890:battery-grid-voltage"}
|
||||
Number:ElectricCurrent BatteryGridCurrent "Battery Grid Current" {channel="sunsynk:inverter:xxx:1234567R1231234567890:battery-grid-current"}
|
||||
Number:Power BatteryGridPdower "Battery Grid Power" {channel="sunsynk:inverter:xxx:1234567R1231234567890:battery-grid-power"}
|
||||
Number:Temperature BatteryTemperature "Battery Temperatue " {channel="sunsynk:inverter:xxx:1234567R1231234567890:battery-temperature"}
|
||||
Number:Temperature InverterACTemperature "Inverter AC Temperature" {channel="sunsynk:inverter:xxx:1234567R1231234567890:inverter-ac-temperature"}
|
||||
Number:Temperature InverterDCTemperature "Inverter DC Temperature" {channel="sunsynk:inverter:xxx:1234567R1231234567890:inverter-dc-temperature"}
|
||||
Number:Power InverterGridPower "Inverter Grid Power" {channel="sunsynk:inverter:xxx:1234567R1231234567890:inverter-grid-power"}
|
||||
Number:ElectricPotential InverterGridVoltage "Inverter Grid Voltage" {channel="sunsynk:inverter:xxx:1234567R1231234567890:inverter-grid-voltage"}
|
||||
Number:ElectricCurrent InverterGridCurrent "Inverter Grid Current" {channel="sunsynk:inverter:xxx:1234567R1231234567890:inverter-grid-current"}
|
||||
Number:Energy InverterSolarEnergyToday "Inverter Energy Today" {channel="sunsynk:inverter:xxx:1234567R1231234567890:inverter-solar-energy-today"}
|
||||
Number:Energy InverterSolarEnergyTotal "Inverter Enery Gross" {channel="sunsynk:inverter:xxx:1234567R1231234567890:inverter-solar-energy-total"}
|
||||
Number:Power InverterSolarPowerNow "Inverter Power" {channel="sunsynk:inverter:xxx:1234567R1231234567890:inverter-solar-power-now"}
|
||||
|
||||
Switch Interval6ControlTimer "Switch on System Mode Timer" {channel="sunsynk:inverter:xxx:1234567R1231234567890:inverter-control-timer"}
|
||||
String InverterControlWorkMode "System Work Mode 0, 1 or 2" {channel="sunsynk:inverter:a1a6340bc0:E4701229R3312211229948:inverter-control-work-mode"}
|
||||
String InverterControlPattern "System Mode Energy Pattern 0 or 1" {channel="sunsynk:inverter:a1a6340bc0:E4701229R3312211229948:inverter-control-energy-pattern"}
|
||||
```
|
||||
|
||||
## DateTime Widget
|
||||
|
||||
The items file above adds Metadata: Default Standalone widget: [rlk_datetime_standalone](https://community.openhab.org/t/datetime-standalone-widget/127966) to the DateTime items. Only the time portion of the DateTime item is important.
|
||||
|
||||
Be sure to understand the time zone set up for the inverter, this can either be synchronised with Sun Synk servers, which in the UK at least applies daylight saving, or free-wheeling locally.
|
||||
The times set in the DateTime items using the widget are not adjusted to any time zone and are sent to the SunSynk API as Strings where they will be applied directly to your inverter.
|
||||
This is in contrast to other solar / energy APIs that use Zulu (GMT) time.
|
||||
|
||||
## Debugging
|
||||
|
||||
After installation, to gain further information on any issues you encounter you can turn on Debug [Logging](https://www.openhab.org/docs/administration/logging.html) either through the [karaf console](https://www.openhab.org/docs/administration/console.html) or through the openHAB UI.
|
16
bundles/org.openhab.binding.sunsynk/pom.xml
Normal file
16
bundles/org.openhab.binding.sunsynk/pom.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>4.3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.sunsynk</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: SunSynk Binding</name>
|
||||
</project>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.sunsynk-${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-sunsynk" description="SunSynk Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.sunsynk/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "sunsynk";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID BRIDGE_TYPE_ACCOUNT = new ThingTypeUID(BINDING_ID, "account");
|
||||
public static final ThingTypeUID THING_TYPE_INVERTER = new ThingTypeUID(BINDING_ID, "inverter");
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_1_GRID_CHARGE = "interval-1-grid-charge";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_2_GRID_CHARGE = "interval-2-grid-charge";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_3_GRID_CHARGE = "interval-3-grid-charge";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_4_GRID_CHARGE = "interval-4-grid-charge";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_5_GRID_CHARGE = "interval-5-grid-charge";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_6_GRID_CHARGE = "interval-6-grid-charge";
|
||||
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_1_GEN_CHARGE = "interval-1-gen-charge";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_2_GEN_CHARGE = "interval-2-gen-charge";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_3_GEN_CHARGE = "interval-3-gen-charge";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_4_GEN_CHARGE = "interval-4-gen-charge";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_5_GEN_CHARGE = "interval-5-gen-charge";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_6_GEN_CHARGE = "interval-6-gen-charge";
|
||||
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_1_TIME = "interval-1-grid-time";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_2_TIME = "interval-2-grid-time";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_3_TIME = "interval-3-grid-time";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_4_TIME = "interval-4-grid-time";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_5_TIME = "interval-5-grid-time";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_6_TIME = "interval-6-grid-time";
|
||||
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_1_CAPACITY = "interval-1-grid-capacity";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_2_CAPACITY = "interval-2-grid-capacity";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_3_CAPACITY = "interval-3-grid-capacity";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_4_CAPACITY = "interval-4-grid-capacity";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_5_CAPACITY = "interval-5-grid-capacity";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_6_CAPACITY = "interval-6-grid-capacity";
|
||||
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_1_POWER_LIMIT = "interval-1-grid-power-limit";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_2_POWER_LIMIT = "interval-2-grid-power-limit";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_3_POWER_LIMIT = "interval-3-grid-power-limit";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_4_POWER_LIMIT = "interval-4-grid-power-limit";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_5_POWER_LIMIT = "interval-5-grid-power-limit";
|
||||
public static final String CHANNEL_BATTERY_INTERVAL_6_POWER_LIMIT = "interval-6-grid-power-limit";
|
||||
|
||||
public static final String CHANNEL_INVERTER_GRID_POWER = "inverter-grid-power";
|
||||
public static final String CHANNEL_INVERTER_GRID_VOLTAGE = "inverter-grid-voltage";
|
||||
public static final String CHANNEL_INVERTER_GRID_CURRENT = "inverter-grid-current";
|
||||
|
||||
public static final String CHANNEL_INVERTER_AC_TEMPERATURE = "inverter-ac-temperature";
|
||||
public static final String CHANNEL_INVERTER_DC_TEMPERATURE = "inverter-dc-temperature";
|
||||
|
||||
public static final String CHANNEL_BATTERY_VOLTAGE = "battery-grid-voltage";
|
||||
public static final String CHANNEL_BATTERY_CURRENT = "battery-grid-current";
|
||||
public static final String CHANNEL_BATTERY_POWER = "battery-grid-power";
|
||||
public static final String CHANNEL_BATTERY_SOC = "battery-soc";
|
||||
public static final String CHANNEL_BATTERY_TEMPERATURE = "battery-temperature";
|
||||
|
||||
public static final String CHANNEL_INVERTER_SOLAR_ENERGY_TODAY = "inverter-solar-energy-today";
|
||||
public static final String CHANNEL_INVERTER_SOLAR_ENERGY_TOTAL = "inverter-solar-energy-total";
|
||||
public static final String CHANNEL_INVERTER_SOLAR_POWER_NOW = "inverter-solar-power-now";
|
||||
|
||||
public static final String CHANNEL_INVERTER_CONTROL_TIMER = "inverter-control-timer";
|
||||
public static final String CHANNEL_INVERTER_CONTROL_ENERGY_PATTERN = "inverter-control-energy-pattern";
|
||||
public static final String CHANNEL_INVERTER_CONTROL_WORK_MODE = "inverter-control-work-mode";
|
||||
|
||||
// Thing Discovery
|
||||
public static final String CONFIG_GATE_SERIAL = "gsn";
|
||||
public static final String CONFIG_SERIAL = "serialnumber";
|
||||
public static final String CONFIG_NAME = "alias";
|
||||
}
|
@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.sunsynk.internal.api;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.APIdata;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Client;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Details;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Inverter;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.SunSynkLogin;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.TokenRefresh;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkAuthenticateException;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkInverterDiscoveryException;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkTokenException;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link AccountController} is the internal class for a Sunsynk Connect
|
||||
* Account.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class AccountController {
|
||||
private static final int TIMEOUT_IN_MS = 4000;
|
||||
private final Logger logger = LoggerFactory.getLogger(AccountController.class);
|
||||
private static final String BEARER_TYPE = "Bearer ";
|
||||
private Client sunAccount = new Client();
|
||||
|
||||
public AccountController() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticates a Sunsynk Connect API account using a username and password.
|
||||
*
|
||||
* @param username The username you use with Sunsynk Connect App
|
||||
* @param password The password you use with Sunsynk Connect App
|
||||
* @throws SunSynkAuthenticateException
|
||||
* @throws SunSynkTokenException
|
||||
*/
|
||||
public void authenticate(String username, String password)
|
||||
throws SunSynkAuthenticateException, SunSynkTokenException {
|
||||
String payload = makeLoginBody(username, password);
|
||||
sendHttp(payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a Sunsynk Connect account token is expired and gets a new one if required.
|
||||
*
|
||||
* @param username
|
||||
* @throws SunSynkAuthenticateException
|
||||
* @throws SunSynkTokenException
|
||||
*/
|
||||
public void refreshAccount(String username) throws SunSynkAuthenticateException, SunSynkTokenException {
|
||||
Long expiresIn = this.sunAccount.getExpiresIn();
|
||||
Long issuedAt = this.sunAccount.getIssuedAt();
|
||||
if ((issuedAt + expiresIn) - Instant.now().getEpochSecond() > 30) { // > 30 seconds
|
||||
logger.debug("Account configuration token not expired.");
|
||||
return;
|
||||
}
|
||||
logger.debug("Account configuration token expired : {}", this.sunAccount.getData().toString());
|
||||
String payload = makeRefreshBody(username, this.sunAccount.getRefreshTokenString());
|
||||
sendHttp(payload);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused") // We need client to be nullable. Then we check for null. Without this compiler warns of
|
||||
// unsed block under null check
|
||||
private void sendHttp(String payload) throws SunSynkAuthenticateException, SunSynkTokenException {
|
||||
Gson gson = new Gson();
|
||||
String response = "";
|
||||
String httpsURL = makeLoginURL("oauth/token");
|
||||
Properties headers = new Properties();
|
||||
headers.setProperty(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
|
||||
InputStream stream = new ByteArrayInputStream(payload.getBytes(StandardCharsets.UTF_8));
|
||||
try {
|
||||
response = HttpUtil.executeUrl(HttpMethod.POST.asString(), httpsURL, headers, stream,
|
||||
MediaType.APPLICATION_JSON, TIMEOUT_IN_MS);
|
||||
|
||||
@Nullable
|
||||
Client client = gson.fromJson(response, Client.class);
|
||||
if (client == null) {
|
||||
throw new SunSynkAuthenticateException(
|
||||
"Sun Synk Account could not be authenticated: Try re-enabling account");
|
||||
}
|
||||
this.sunAccount = client;
|
||||
} catch (IOException | JsonSyntaxException e) {
|
||||
throw new SunSynkAuthenticateException("Sun Synk Account could not be authenticated", e);
|
||||
}
|
||||
if (this.sunAccount.getCode() == 102) {
|
||||
logger.debug("Sun Synk Account could not be authenticated: {}.", this.sunAccount.getMsg());
|
||||
throw new SunSynkAuthenticateException(
|
||||
"Sun Synk Accountfailed to authenticate: Check your password or email.");
|
||||
}
|
||||
if (this.sunAccount.getStatus() == 404) {
|
||||
logger.debug("Sun Synk Account could not be authenticated: 404 {} {}.", this.sunAccount.getError(),
|
||||
this.sunAccount.getPath());
|
||||
throw new SunSynkAuthenticateException("Sun Synk Accountfailed to authenticate: 404 Not Found.");
|
||||
}
|
||||
getToken();
|
||||
}
|
||||
|
||||
private void getToken() throws SunSynkAuthenticateException {
|
||||
APIdata data = this.sunAccount.getData();
|
||||
APIdata.staticAccessToken = data.getAccessToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers a list of all inverter tied to a Sunsynk Connect Account
|
||||
*
|
||||
* @return List of connected inveters
|
||||
* @throws SunSynkInverterDiscoveryException
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public ArrayList<Inverter> getDetails() throws SunSynkInverterDiscoveryException {
|
||||
Details output = new Details();
|
||||
ArrayList<Inverter> inverters = new ArrayList<>();
|
||||
try {
|
||||
Gson gson = new Gson();
|
||||
Properties headers = new Properties();
|
||||
String response = "";
|
||||
|
||||
String httpsURL = makeLoginURL(
|
||||
"api/v1/inverters?page=1&limit=10&total=0&status=-1&sn=&plantId=&type=-2&softVer=&hmiVer=&agentCompanyId=-1&gsn=");
|
||||
headers.setProperty(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
|
||||
headers.setProperty(HttpHeaders.AUTHORIZATION, BEARER_TYPE + APIdata.staticAccessToken);
|
||||
response = HttpUtil.executeUrl(HttpMethod.GET.asString(), httpsURL, headers, null,
|
||||
MediaType.APPLICATION_JSON, TIMEOUT_IN_MS);
|
||||
@Nullable
|
||||
Details maybeDeats = gson.fromJson(response, Details.class);
|
||||
if (maybeDeats == null) {
|
||||
throw new SunSynkInverterDiscoveryException("Failed to discover Inverters");
|
||||
}
|
||||
output = maybeDeats;
|
||||
} catch (IOException | JsonSyntaxException e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
String message = Objects.requireNonNullElse(e.getMessage(), "unkown error message");
|
||||
Throwable cause = e.getCause();
|
||||
String causeMessage = cause != null ? Objects.requireNonNullElse(cause.getMessage(), "unkown cause")
|
||||
: "unkown cause";
|
||||
logger.debug("Error attempting to find inverters registered to account: Msg = {}. Cause = {}.", message,
|
||||
causeMessage);
|
||||
}
|
||||
throw new SunSynkInverterDiscoveryException("Failed to discover Inverters", e);
|
||||
}
|
||||
inverters = output.getInverters(APIdata.staticAccessToken);
|
||||
return inverters;
|
||||
}
|
||||
|
||||
private static String makeLoginURL(String path) {
|
||||
return "https://api.sunsynk.net" + "/" + path;
|
||||
}
|
||||
|
||||
private static String makeLoginBody(String username, String password) {
|
||||
Gson gson = new Gson();
|
||||
SunSynkLogin login = new SunSynkLogin(username, password);
|
||||
return gson.toJson(login);
|
||||
}
|
||||
|
||||
private static String makeRefreshBody(String username, String refreshToken) {
|
||||
Gson gson = new Gson();
|
||||
TokenRefresh refresh = new TokenRefresh(username, refreshToken);
|
||||
return gson.toJson(refresh);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return this.sunAccount.getData().toString();
|
||||
} catch (SunSynkAuthenticateException e) {
|
||||
return "Tried to print client data, value is null.";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,271 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.api;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.APIdata;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Battery;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Daytemps;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Grid;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.RealTimeInData;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Settings;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkDeviceControllerException;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkGetStatusException;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkSendCommandException;
|
||||
import org.openhab.binding.sunsynk.internal.config.SunSynkInverterConfig;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link DeviceController} class defines methods that control
|
||||
* communication with the inverter.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class DeviceController {
|
||||
|
||||
private static final int TIMEOUT_IN_MS = 4000;
|
||||
private final Logger logger = LoggerFactory.getLogger(DeviceController.class);
|
||||
private static final String BEARER_TYPE = "Bearer ";
|
||||
private String sn = "";
|
||||
private String alias = "";
|
||||
private Settings batterySettings = new Settings();
|
||||
private Battery realTimeBattery = new Battery();
|
||||
private Grid grid = new Grid();
|
||||
private Daytemps inverterDayTemperatures = new Daytemps();
|
||||
private RealTimeInData realTimeDataIn = new RealTimeInData();
|
||||
public Settings tempInverterChargeSettings = new Settings(); // Holds modified battery settings.
|
||||
|
||||
public DeviceController() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identity of the device (inverter) according to the configuration parameters;
|
||||
* serial number and alias.
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
public DeviceController(SunSynkInverterConfig config) {
|
||||
this.sn = config.getSerialnumber();
|
||||
this.alias = config.getAlias();
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry method to get status of the concrete device (inverter) and update the internal state.
|
||||
*
|
||||
* @param batterySettingsUpdate used to skip the battery charge settings status
|
||||
* @throws SunSynkGetStatusException
|
||||
* @throws JsonSyntaxException
|
||||
* @throws SunSynkDeviceControllerException
|
||||
* @see Settings
|
||||
* @see Grid
|
||||
* @see Battery
|
||||
* @see Daytemps
|
||||
* @see RealTimeInData
|
||||
*/
|
||||
public void sendGetState(boolean batterySettingsUpdate)
|
||||
throws SunSynkGetStatusException, JsonSyntaxException, SunSynkDeviceControllerException {
|
||||
logger.debug("Will get STATE for Inverter {} serial {}", this.alias, this.sn);
|
||||
try {
|
||||
if (!batterySettingsUpdate) { // normally get settings to track changes made by other UIs
|
||||
getCommonSettings(); // battery charge settings
|
||||
}
|
||||
getGridRealTime(); // grid status
|
||||
getBatteryRealTime(); // battery status
|
||||
getInverterACDCTemperatures(); // get Inverter temperatures
|
||||
getRealTimeIn(); // Used for solar power now
|
||||
} catch (IOException e) {
|
||||
String message = Objects.requireNonNullElse(e.getMessage(), "unkown error message");
|
||||
logger.debug("Failed to send to Inverter API: {} ", message);
|
||||
int found = message.indexOf("Authentication challenge without WWW-Authenticate header");
|
||||
if (found > -1) {
|
||||
throw new SunSynkGetStatusException("Authentication token failed", e);
|
||||
}
|
||||
throw new SunSynkGetStatusException("Unknown athentication fail", e);
|
||||
}
|
||||
logger.debug("Successfully got and parsed new data for Inverter {} serial {}", this.alias, this.sn);
|
||||
}
|
||||
|
||||
public Settings getBatteryChargeSettings() {
|
||||
return this.batterySettings;
|
||||
}
|
||||
|
||||
public Battery getRealTimeBatteryState() {
|
||||
return this.realTimeBattery;
|
||||
}
|
||||
|
||||
public Grid getRealTimeGridStatus() {
|
||||
return this.grid;
|
||||
}
|
||||
|
||||
public Daytemps getInverterTemperatureHistory() {
|
||||
return this.inverterDayTemperatures;
|
||||
}
|
||||
|
||||
public RealTimeInData getRealtimeSolarStatus() {
|
||||
return this.realTimeDataIn;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void getCommonSettings() throws IOException, JsonSyntaxException, SunSynkDeviceControllerException {
|
||||
logger.debug("Trying Common Settings");
|
||||
String response = apiGetMethod(makeURL("api/v1/common/setting/" + this.sn + "/read"),
|
||||
APIdata.staticAccessToken);
|
||||
Gson gson = new Gson();
|
||||
@Nullable
|
||||
Settings settings = gson.fromJson(response, Settings.class);
|
||||
if (settings == null) {
|
||||
throw new SunSynkDeviceControllerException("Could not retrieve battery charge settings");
|
||||
}
|
||||
this.batterySettings = settings;
|
||||
this.batterySettings.buildLists();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void getGridRealTime() throws IOException, JsonSyntaxException, SunSynkDeviceControllerException {
|
||||
logger.debug("Trying Grid Real Time Settings");
|
||||
String response = apiGetMethod(makeURL("api/v1/inverter/grid/" + this.sn + "/realtime?sn=") + this.sn,
|
||||
APIdata.staticAccessToken);
|
||||
Gson gson = new Gson();
|
||||
@Nullable
|
||||
Grid grid = gson.fromJson(response, Grid.class);
|
||||
if (grid == null) {
|
||||
throw new SunSynkDeviceControllerException("Could not retrieve grid state");
|
||||
}
|
||||
this.grid = grid;
|
||||
this.grid.sumVIP();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void getBatteryRealTime() throws IOException, JsonSyntaxException, SunSynkDeviceControllerException {
|
||||
logger.debug("Trying Battery Real Time Settings");
|
||||
String response = apiGetMethod(
|
||||
makeURL("api/v1/inverter/battery/" + this.sn + "/realtime?sn=" + this.sn + "&lan"),
|
||||
APIdata.staticAccessToken);
|
||||
Gson gson = new Gson();
|
||||
@Nullable
|
||||
Battery battery = gson.fromJson(response, Battery.class);
|
||||
if (battery == null) {
|
||||
throw new SunSynkDeviceControllerException("Could not retrieve battery state");
|
||||
}
|
||||
this.realTimeBattery = battery;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void getInverterACDCTemperatures()
|
||||
throws IOException, JsonSyntaxException, SunSynkDeviceControllerException {
|
||||
logger.debug("Trying Temperature History");
|
||||
String date = getAPIFormatDate();
|
||||
String response = apiGetMethod(
|
||||
makeURL("api/v1/inverter/" + this.sn + "/output/day?lan=en&date=" + date + "&column=dc_temp,igbt_temp"),
|
||||
APIdata.staticAccessToken);
|
||||
Gson gson = new Gson();
|
||||
@Nullable
|
||||
Daytemps daytemps = gson.fromJson(response, Daytemps.class);
|
||||
if (daytemps == null) {
|
||||
throw new SunSynkDeviceControllerException("Could not retrieve device temperatures");
|
||||
}
|
||||
this.inverterDayTemperatures = daytemps;
|
||||
this.inverterDayTemperatures.getLastValue();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void getRealTimeIn() throws IOException, JsonSyntaxException, SunSynkDeviceControllerException { // Get URL
|
||||
// Respnse
|
||||
logger.debug("Trying Real Time Solar");
|
||||
String response = apiGetMethod(makeURL("api/v1/inverter/" + this.sn + "/realtime/input"),
|
||||
APIdata.staticAccessToken);
|
||||
Gson gson = new Gson();
|
||||
@Nullable
|
||||
RealTimeInData realTimeInData = gson.fromJson(response, RealTimeInData.class);
|
||||
if (realTimeInData == null) {
|
||||
throw new SunSynkDeviceControllerException("Could not retrieve solar state");
|
||||
}
|
||||
this.realTimeDataIn = realTimeInData;
|
||||
this.realTimeDataIn.sumPVIV();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the internal battery charge and discharge settings to the concrete device (inverter)
|
||||
* of a Sun Synk Connect Account
|
||||
*
|
||||
* @param settings
|
||||
* @throws SunSynkSendCommandException
|
||||
*/
|
||||
public void sendSettings(Settings settings) throws SunSynkSendCommandException {
|
||||
String body = settings.buildBody();
|
||||
sendCommandToSunSynk(body);
|
||||
}
|
||||
|
||||
private void sendCommandToSunSynk(String body) throws SunSynkSendCommandException {
|
||||
String path = "api/v1/common/setting/" + this.sn + "/set";
|
||||
|
||||
try {
|
||||
apiPostMethod(makeURL(path), body, APIdata.staticAccessToken);
|
||||
} catch (IOException e) {
|
||||
String message = Objects.requireNonNullElse(e.getMessage(), "unkown error message");
|
||||
logger.debug("Failed to send to Inverter API: {} ", message);
|
||||
int found = message.indexOf("Authentication challenge without WWW-Authenticate header");
|
||||
if (found > -1) {
|
||||
throw new SunSynkSendCommandException("Authentication token failed", e);
|
||||
}
|
||||
throw new SunSynkSendCommandException("Unknown athentication fail", e);
|
||||
}
|
||||
logger.debug("Sent command: to inverter {}.", this.sn);
|
||||
}
|
||||
|
||||
private String apiPostMethod(String httpsURL, String body, String accessToken) throws IOException {
|
||||
Properties headers = new Properties();
|
||||
headers.setProperty(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
|
||||
headers.setProperty(HttpHeaders.AUTHORIZATION, BEARER_TYPE + accessToken);
|
||||
InputStream stream = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8));
|
||||
return HttpUtil.executeUrl(HttpMethod.POST.asString(), httpsURL, headers, stream, MediaType.APPLICATION_JSON,
|
||||
TIMEOUT_IN_MS);
|
||||
}
|
||||
|
||||
private String apiGetMethod(String httpsURL, String accessToken) throws IOException {
|
||||
Properties headers = new Properties();
|
||||
headers.setProperty(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
|
||||
headers.setProperty(HttpHeaders.AUTHORIZATION, BEARER_TYPE + accessToken);
|
||||
return HttpUtil.executeUrl(HttpMethod.GET.asString(), httpsURL, headers, null, MediaType.APPLICATION_JSON,
|
||||
TIMEOUT_IN_MS);
|
||||
}
|
||||
|
||||
private String makeURL(String path) {
|
||||
return "https://api.sunsynk.net" + "/" + path;
|
||||
}
|
||||
|
||||
private String getAPIFormatDate() {
|
||||
return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link APIdata} is the internal class for a Sun Synk Connect
|
||||
* Account.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class APIdata {
|
||||
@SerializedName("static_access_token")
|
||||
public static String staticAccessToken = "";
|
||||
@SerializedName("access_token")
|
||||
private String accessToken = "";
|
||||
@SerializedName("refresh_token")
|
||||
private String refreshToken = "";
|
||||
@SerializedName("token_type")
|
||||
private String tokenType = "";
|
||||
@SerializedName("expires_in")
|
||||
private Long expiresIn = 0000L;
|
||||
private String scope = "";
|
||||
private Long issuedAt = Instant.now().getEpochSecond();
|
||||
|
||||
public Long getExpiresIn() {
|
||||
return this.expiresIn;
|
||||
}
|
||||
|
||||
public String getRefreshToken() {
|
||||
return this.refreshToken;
|
||||
}
|
||||
|
||||
public String getTokenType() {
|
||||
return this.tokenType;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return this.scope;
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return this.accessToken;
|
||||
}
|
||||
|
||||
public Long getIssuedAt() {
|
||||
return this.issuedAt;
|
||||
}
|
||||
|
||||
public void setIssuedAt(Long issuedAt) {
|
||||
this.issuedAt = issuedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[access token: " + this.accessToken + ", refresh_token: " + this.refreshToken + ", expires_in: "
|
||||
+ this.expiresIn + ", issued_at: " + this.issuedAt + "]";
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link Battery} is the internal class for battery information
|
||||
* from a Sun Synk Connect Account.
|
||||
* Currently only Lithium SunSynk batteries are known to work.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@NonNullByDefault
|
||||
public class Battery {
|
||||
private int code;
|
||||
private String msg = "";
|
||||
private boolean success;
|
||||
private Data data = new Data();
|
||||
|
||||
class Data {
|
||||
private String time = "";
|
||||
private double etodayChg;
|
||||
private double etodayDischg;
|
||||
private double emonthChg;
|
||||
private double emonthDischg;
|
||||
private double eyearChg;
|
||||
private double eyearDischg;
|
||||
private double etotalChg;
|
||||
private double etotalDischg;
|
||||
private int type;
|
||||
private int power;
|
||||
private double capacity;
|
||||
private double correctCap;
|
||||
private double bmsSoc;
|
||||
private double bmsVolt;
|
||||
private double bmsCurrent;
|
||||
private double bmsTemp;
|
||||
private double current;
|
||||
private double voltage;
|
||||
private double temp;
|
||||
private double soc;
|
||||
private double chargeVolt;
|
||||
private double dischargeVolt;
|
||||
private double chargeCurrentLimit;
|
||||
private double dischargeCurrentLimit;
|
||||
private double maxChargeCurrentLimit;
|
||||
private double maxDischargeCurrentLimit;
|
||||
private int bms1Version1;
|
||||
private int bms1Version2;
|
||||
private String current2 = "";
|
||||
private String voltage2 = "";
|
||||
private String temp2 = "";
|
||||
private String soc2 = "";
|
||||
private String chargeVolt2 = "";
|
||||
private String dischargeVolt2 = "";
|
||||
private String chargeCurrentLimit2 = "";
|
||||
private String dischargeCurrentLimit2 = "";
|
||||
private String maxChargeCurrentLimit2 = "";
|
||||
private String maxDischargeCurrentLimit2 = "";
|
||||
private String bms2Version1 = "";
|
||||
private String bms2Version2 = "";
|
||||
private int status;
|
||||
private double batterySoc1;
|
||||
private double batteryCurrent1;
|
||||
private double batteryVolt1;
|
||||
private double batteryPower1;
|
||||
private double batteryTemp1;
|
||||
private double batteryStatus2;
|
||||
private String batterySoc2 = "";
|
||||
private String batteryCurrent2 = "";
|
||||
private String batteryVolt2 = "";
|
||||
private String batteryPower2 = "";
|
||||
private String batteryTemp2 = "";
|
||||
private String numberOfBatteries = "";
|
||||
private String batt1Factory = "";
|
||||
private String batt2Factory = "";
|
||||
}
|
||||
|
||||
public double getBatteryVoltage() {
|
||||
return this.data.voltage;
|
||||
}
|
||||
|
||||
public double getBatteryCurrent() { // -ve if charging battery.
|
||||
return this.data.current;
|
||||
}
|
||||
|
||||
public double getBatteryPower() {
|
||||
return this.data.power;
|
||||
}
|
||||
|
||||
public double getBatteryCapacity() {
|
||||
return this.data.capacity;
|
||||
}
|
||||
|
||||
public double getBatterySOC() {
|
||||
return this.data.soc;
|
||||
}
|
||||
|
||||
public double getBatteryTemperature() {
|
||||
return this.data.temp;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Content [code=" + code + ", msg=" + msg + "sucess=" + success + ", data=" + data + "]";
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkAuthenticateException;
|
||||
|
||||
/**
|
||||
* The {@link Client} is the internal class for client information
|
||||
* from a Sun Synk Connect Account.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class Client {
|
||||
private int code; // 102 username or password probloem
|
||||
private String msg = "";
|
||||
private boolean success;
|
||||
@Nullable
|
||||
private APIdata data = new APIdata();
|
||||
private int status;
|
||||
private String error = ""; // "{"timestamp":"2024-06-16T11:21:17.690+00:00","status":404,"error":"Not
|
||||
// Found","path":"/oauth/toke"}"
|
||||
private String path = "";
|
||||
private String timestamp = "";
|
||||
|
||||
public Client() {
|
||||
}
|
||||
|
||||
public static String getAccessTokenString() {
|
||||
return APIdata.staticAccessToken;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return this.error;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
public String getTimeStamp() {
|
||||
return this.timestamp;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return this.msg;
|
||||
}
|
||||
|
||||
public void setAccessTokenString(String token) {
|
||||
APIdata.staticAccessToken = token;
|
||||
}
|
||||
|
||||
public Long getExpiresIn() throws SunSynkAuthenticateException {
|
||||
return this.getData().getExpiresIn();
|
||||
}
|
||||
|
||||
public String getRefreshTokenString() throws SunSynkAuthenticateException {
|
||||
return this.getData().getRefreshToken();
|
||||
}
|
||||
|
||||
public Long getIssuedAt() throws SunSynkAuthenticateException {
|
||||
return this.getData().getIssuedAt();
|
||||
}
|
||||
|
||||
public void setIssuedAt(Long issuedAt) throws SunSynkAuthenticateException {
|
||||
this.getData().setIssuedAt(issuedAt);
|
||||
}
|
||||
|
||||
public APIdata getData() throws SunSynkAuthenticateException {
|
||||
APIdata data = this.data; // Nullable inherited from APIdata
|
||||
if (data != null) {
|
||||
return data;
|
||||
} else {
|
||||
throw new SunSynkAuthenticateException("Empty client data.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Content [code=" + code + ", msg=" + msg + "sucess=" + success + ", data=" + data + "]";
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link Daytemps} is the internal class for Inverter temperature history information
|
||||
* from a Sun Synk Connect Account.
|
||||
* The minute following midnight returns an empty array.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class Daytemps {
|
||||
private int code;
|
||||
private String msg = "";
|
||||
private boolean success;
|
||||
private Data data = new Data();
|
||||
private boolean responseStatus = true;
|
||||
private double dcTemperature;
|
||||
private double acTemperature;
|
||||
|
||||
class Data {
|
||||
private @Nullable List<Infos> infos = new ArrayList<Infos>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
class Infos {
|
||||
private String unit = "";
|
||||
private @Nullable List<Record> records = new ArrayList<Record>();
|
||||
private String id = "";
|
||||
private String label = "";
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
class Record {
|
||||
private String time = "";
|
||||
private double value;
|
||||
private String updateTime = "";
|
||||
}
|
||||
|
||||
public void getLastValue() {
|
||||
List<Infos> infos = this.data.infos;
|
||||
if (infos != null) { // Sometimes after midnight infos or records are empty
|
||||
if (!infos.isEmpty()) {
|
||||
List<Record> dcRecord = infos.get(0).records;
|
||||
List<Record> acRecord = infos.get(1).records;
|
||||
if (dcRecord != null && acRecord != null) {
|
||||
this.dcTemperature = dcRecord.get(dcRecord.size() - 1).value;
|
||||
this.acTemperature = acRecord.get(acRecord.size() - 1).value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.responseStatus = false;
|
||||
// do nothing leave dc_ and ac_ temperature values as they are.
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Content [code=" + code + ", msg=" + msg + "sucess=" + success + ", data=" + data + "]";
|
||||
}
|
||||
|
||||
public Daytempsreturn inverterTemperatures() {
|
||||
return new Daytempsreturn(this.responseStatus, this.dcTemperature, this.acTemperature);
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link Daytempsretun} is the internal class for inverter temperature history information
|
||||
* from a Sun Synk Connect Account.
|
||||
* The minute following midnight returns an empty array
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class Daytempsreturn {
|
||||
private boolean status;
|
||||
public double dc;
|
||||
public double ac;
|
||||
|
||||
public Daytempsreturn(boolean status, double dc, double ac) {
|
||||
this.status = status;
|
||||
this.dc = dc;
|
||||
this.ac = ac;
|
||||
}
|
||||
|
||||
public boolean getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public double getACTemperature() {
|
||||
return this.dc;
|
||||
}
|
||||
|
||||
public double getDCTemperature() {
|
||||
return this.ac;
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link Details} is the internal class for account detail information from a
|
||||
* Sun Synk Connect Account.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
@SuppressWarnings("unused")
|
||||
public class Details {
|
||||
private int code;
|
||||
private String msg = "";
|
||||
private boolean success;
|
||||
private Inverterdata data = new Inverterdata();
|
||||
|
||||
public Details() {
|
||||
}
|
||||
|
||||
public List<Inverterdata.InverterInfo> getInverters() {
|
||||
return this.data.getInverters();
|
||||
}
|
||||
|
||||
public ArrayList<String> getInverterUIDList() { // not used
|
||||
ArrayList<String> inverters = new ArrayList<String>();
|
||||
for (Details.Inverterdata.InverterInfo inv : getInverters()) {
|
||||
String uid = inv.getgsn() + inv.getsn();
|
||||
inverters.add(uid);
|
||||
}
|
||||
return inverters;
|
||||
}
|
||||
|
||||
public ArrayList<Inverter> getInverters(String accessToken) {
|
||||
ArrayList<Inverter> inverters = new ArrayList<>();
|
||||
for (Details.Inverterdata.InverterInfo inv : getInverters()) {
|
||||
Inverter temp = new Inverter();
|
||||
String serialNo = inv.getsn();
|
||||
String gateSerialNo = inv.getgsn();
|
||||
temp.setGateSerialNo(gateSerialNo);
|
||||
temp.setSerialNo(serialNo);
|
||||
temp.setUID(gateSerialNo + serialNo);
|
||||
temp.setToken(accessToken);
|
||||
temp.setAlias(inv.getAlias());
|
||||
temp.setID(inv.getID());
|
||||
inverters.add(temp);
|
||||
}
|
||||
return inverters;
|
||||
}
|
||||
|
||||
class Inverterdata {
|
||||
private int pageSize;
|
||||
private int pageNumber;
|
||||
private int total;
|
||||
private List<InverterInfo> infos = new ArrayList<InverterInfo>();
|
||||
|
||||
public List<InverterInfo> getInverters() {
|
||||
return this.infos;
|
||||
}
|
||||
|
||||
class InverterInfo {
|
||||
private int id;
|
||||
private String sn = "";
|
||||
private String alias = "";
|
||||
private String gsn = "";
|
||||
private int status;
|
||||
private int type;
|
||||
private String commTypeName = "";
|
||||
private String custCode = "";
|
||||
private Version version = new Version();
|
||||
private String model = "";
|
||||
private String equipMode = "";
|
||||
private int pac;
|
||||
private double etoday;
|
||||
private double etotal;
|
||||
private String updateAt = "";
|
||||
private int opened;
|
||||
private Plant plant = new Plant();
|
||||
|
||||
public String getgsn() {
|
||||
return this.gsn;
|
||||
}
|
||||
|
||||
public String getsn() {
|
||||
return sn;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return String.valueOf(id);
|
||||
}
|
||||
|
||||
public double getetoday() {
|
||||
return this.etoday;
|
||||
}
|
||||
|
||||
public double getetotal() {
|
||||
return this.etotal;
|
||||
}
|
||||
|
||||
class Plant {
|
||||
private int id;
|
||||
private String name = "";
|
||||
private int type;
|
||||
private String master = "";
|
||||
private String installer = "";
|
||||
private String email = "";
|
||||
private String phone = "";
|
||||
private GatewayVO gatewayVO = new GatewayVO();
|
||||
private boolean sunsynkEquip;
|
||||
private int protocolIdentifier;
|
||||
private int equipType;
|
||||
|
||||
class GatewayVO {
|
||||
private String gsn = "";
|
||||
private int status;
|
||||
}
|
||||
}
|
||||
|
||||
class Version {
|
||||
private String masterVer = "";
|
||||
private String softVer = "";
|
||||
private String hardVer = "";
|
||||
private String bmsVer = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link Grid} is the internal class for inverter real time grid information
|
||||
* from the a Sun Synk Connect Account.
|
||||
*
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class Grid {
|
||||
private int code;
|
||||
private String msg = "";
|
||||
private boolean success;
|
||||
private Data data = new Data();
|
||||
private double power;
|
||||
private double voltage;
|
||||
private double current;
|
||||
|
||||
class Data {
|
||||
private List<VIP> vip = new ArrayList<VIP>();
|
||||
private int pac;
|
||||
private int qac;
|
||||
private double fac;
|
||||
private double pf;
|
||||
private int status;
|
||||
private double etodayFrom;
|
||||
private double etodayTo;
|
||||
private double etotalFrom;
|
||||
private double etotalTo;
|
||||
private List<Integer> limiterPowerArr = new ArrayList<Integer>();
|
||||
private int limiterTotalPowerArr;
|
||||
|
||||
String content() {
|
||||
return "[pac: " + pac + "fac: " + fac + " quac: " + qac + " pf: " + pf + " status: " + status + "etoday: {"
|
||||
+ etodayFrom + ", " + etodayTo + "} etotal: {" + etotalFrom + ", " + etotalTo
|
||||
+ "} limiterPowerArr: " + limiterPowerArr + " limiterTotalPowerArr:" + limiterTotalPowerArr + "]";
|
||||
}
|
||||
}
|
||||
|
||||
class VIP {
|
||||
private double volt;
|
||||
private double current;
|
||||
private double power;
|
||||
}
|
||||
|
||||
public void sumVIP() {
|
||||
double sumPower = 0.0;
|
||||
double sumVoltage = 0.0;
|
||||
double sumCurrent = 0.0;
|
||||
for (VIP x : this.data.vip) {
|
||||
sumPower = sumPower + x.power;
|
||||
sumVoltage = sumVoltage + x.volt;
|
||||
sumCurrent = sumCurrent + x.current;
|
||||
}
|
||||
this.power = sumPower;
|
||||
this.voltage = sumVoltage;
|
||||
this.current = sumCurrent;
|
||||
}
|
||||
|
||||
public double getGridPower() {
|
||||
return this.power;
|
||||
}
|
||||
|
||||
public double getGridVoltage() {
|
||||
return this.voltage;
|
||||
}
|
||||
|
||||
public double getGridCurrent() {
|
||||
return this.current;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Content [code=" + code + ", msg=" + msg + "sucess=" + success + ", data=" + data.content() + "]";
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link Inverter} is the internal class for OpenHAB inverter identity information
|
||||
* from a Sun Synk Connect account.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class Inverter {
|
||||
private String uid = "";
|
||||
@SerializedName("secret_key")
|
||||
private String token = "";
|
||||
private String serialNo = "";
|
||||
private String gateSerialNo = "";
|
||||
private String id = "";
|
||||
private String alias = "";
|
||||
private int refresh;
|
||||
|
||||
public void setUID(String uid) {
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public void setSerialNo(String serialNo) {
|
||||
this.serialNo = serialNo;
|
||||
}
|
||||
|
||||
public void setGateSerialNo(String gateSerialNo) {
|
||||
this.gateSerialNo = gateSerialNo;
|
||||
}
|
||||
|
||||
public void setID(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setAlias(String alias) {
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
public void setRefresh(int refresh) {
|
||||
this.refresh = refresh;
|
||||
}
|
||||
|
||||
public String getUID() {
|
||||
return this.uid;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
public String getSerialNo() {
|
||||
return this.serialNo;
|
||||
}
|
||||
|
||||
public String getGateSerialNo() {
|
||||
return this.gateSerialNo;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return this.alias;
|
||||
}
|
||||
|
||||
public int getRefresh() {
|
||||
return this.refresh;
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link RealTimeInData} is the internal class for inverter real time information
|
||||
* from a Sun Synk Connect Account.
|
||||
* Use for solar status.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class RealTimeInData {
|
||||
private int code;
|
||||
private String msg = "";
|
||||
private boolean success;
|
||||
private Data data = new Data();
|
||||
private double solarPower;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
class Data {
|
||||
private int pac;
|
||||
@SerializedName("grid_tip_power")
|
||||
private String gridTipPower = "";
|
||||
private double etoday;
|
||||
private double etotal;
|
||||
private List<PVIV> pvIV = new ArrayList<PVIV>();
|
||||
private List<MPPTIV> mpptIV = new ArrayList<MPPTIV>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private class PVIV {
|
||||
private String id = "";
|
||||
private int pvNo;
|
||||
private double vpv;
|
||||
private double ipv;
|
||||
private double ppv; // sum for all power
|
||||
private double todayPv;
|
||||
private String sn = "";
|
||||
private String time = "";
|
||||
}
|
||||
|
||||
public RealTimeInData() {
|
||||
}
|
||||
|
||||
class MPPTIV { // Empty; no solar panels
|
||||
}
|
||||
|
||||
public double getetoday() {
|
||||
return this.data.etoday;
|
||||
}
|
||||
|
||||
public double getetotal() {
|
||||
return this.data.etotal;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Content [code=" + code + ", msg=" + msg + "sucess=" + success + ", data=" + data + "]";
|
||||
}
|
||||
|
||||
public void sumPVIV() {
|
||||
double solarPower = 0.0;
|
||||
for (PVIV x : this.data.pvIV) {
|
||||
this.solarPower = solarPower + x.ppv;
|
||||
}
|
||||
}
|
||||
|
||||
public double getPVIV() {
|
||||
return this.solarPower;
|
||||
}
|
||||
}
|
@ -0,0 +1,551 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* The {@link Settings} is the internal class for inverter common settings information
|
||||
* (grid and solar charge / battery discharge schedule) from a Sun Synk Account.
|
||||
*
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class Settings {
|
||||
private int code;
|
||||
private String msg = "";
|
||||
private boolean success;
|
||||
private Data data = new Data();
|
||||
List<Boolean> gridTimeron = new ArrayList<Boolean>();
|
||||
List<Integer> batteryCapacity = new ArrayList<Integer>();
|
||||
List<Boolean> genTimeron = new ArrayList<Boolean>();
|
||||
List<String> timerTime = new ArrayList<String>();
|
||||
List<Integer> batteryPowerLimit = new ArrayList<Integer>();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
class Data {
|
||||
private boolean time1on;
|
||||
private boolean time2on;
|
||||
private boolean time3on;
|
||||
private boolean time4on;
|
||||
private boolean time5on;
|
||||
private boolean time6on;
|
||||
//
|
||||
private int time1On;
|
||||
private int time2On;
|
||||
private int time3On;
|
||||
private int time4On;
|
||||
private int time5On;
|
||||
private int time6On;
|
||||
// 00:05 min reslution; sets time interval of charging, send with quotes e.g. "01:05"
|
||||
private String sellTime1 = "";
|
||||
private String sellTime2 = "";
|
||||
private String sellTime3 = "";
|
||||
private String sellTime4 = "";
|
||||
private String sellTime5 = "";
|
||||
private String sellTime6 = "";
|
||||
// false or true; sets gen charging interval on, send without quotes e.g. true
|
||||
private boolean genTime1on;
|
||||
private boolean genTime2on;
|
||||
private boolean genTime3on;
|
||||
private boolean genTime4on;
|
||||
private boolean genTime5on;
|
||||
private boolean genTime6on;
|
||||
//
|
||||
private String beep = "";
|
||||
private String attOverExitFreqStopDelay = "";
|
||||
private String exMeterCtSwitch = "";
|
||||
private String sdChargeOn = "";
|
||||
private String lockInVoltVar = "";
|
||||
private String batWarn = "";
|
||||
private String wattVarEnable = "";
|
||||
private String reconnMinVolt = "";
|
||||
private String caFStart = "";
|
||||
private String pvMaxLimit = "";
|
||||
private String sensorsCheck = "";
|
||||
private String wattUnderExitFreq = "";
|
||||
private String overVolt1 = "";
|
||||
private String overVolt2 = "";
|
||||
private String genPeakPower = "";
|
||||
private String meterA = "";
|
||||
private String meterB = "";
|
||||
private String meterC = "";
|
||||
private String eeprom = "";
|
||||
private String comSet = "";
|
||||
private String varQac1 = "";
|
||||
private String varQac2 = "";
|
||||
private String varQac3 = "";
|
||||
private String caVoltPressureEnable = "";
|
||||
private String wattUnderFreq1 = "";
|
||||
private String solarMaxSellPower = "";
|
||||
private String acCoupleOnGridSideEnable = "";
|
||||
private String mondayOn = "";
|
||||
private String tuesdayOn = "";
|
||||
private String wednesdayOn = "";
|
||||
private String thursdayOn = "";
|
||||
private String fridayOn = "";
|
||||
private String saturdayOn = "";
|
||||
private String sundayOn = "";
|
||||
private String batteryRestartCap = "";
|
||||
private String overFreq1Delay = "";
|
||||
private String bmsErrStop = "";
|
||||
private String checkTime = "";
|
||||
private String atsSwitch = "";
|
||||
// private String tempUp;
|
||||
private String acCurrentUp = "";
|
||||
private String sacPowerControl = "";
|
||||
private String rsd = "";
|
||||
private String batteryOn = "";
|
||||
private String volt1 = "";
|
||||
private String volt2 = "";
|
||||
private String volt3 = "";
|
||||
private String volt4 = "";
|
||||
private String volt5 = "";
|
||||
private String volt6 = "";
|
||||
private String volt7 = "";
|
||||
private String volt8 = "";
|
||||
private String volt9 = "";
|
||||
private String volt10 = "";
|
||||
private String volt11 = "";
|
||||
private String volt12 = "";
|
||||
private String wattUnderFreq1StartDelay = "";
|
||||
private String rcd = "";
|
||||
private String chargeVolt = "";
|
||||
private String floatVolt = "";
|
||||
private String workState = "";
|
||||
private String loadMode = "";
|
||||
private int sysWorkMode;
|
||||
private String sn = "";
|
||||
private String genCoolingTime = "";
|
||||
private String genPeakShaving = "";
|
||||
private String current4 = "";
|
||||
private String current3 = "";
|
||||
private String current2 = "";
|
||||
private String current1 = "";
|
||||
private String current8 = "";
|
||||
private String current7 = "";
|
||||
private String current6 = "";
|
||||
private String current5 = "";
|
||||
private String current9 = "";
|
||||
private String current10 = "";
|
||||
private String current11 = "";
|
||||
private String current12 = "";
|
||||
private String wattV1 = "";
|
||||
private String wattV2 = "";
|
||||
private String wattV3 = "";
|
||||
private String wattV4 = "";
|
||||
private String batteryEfficiency = "";
|
||||
private String genAndGridSignal = "";
|
||||
private String acFreqLow = "";
|
||||
private String reactivePowerControl = "";
|
||||
private String batteryEmptyV = "";
|
||||
private String open = "";
|
||||
private String reconnMaxFreq = "";
|
||||
private String standard = "";
|
||||
private String wattVarReactive1 = "";
|
||||
private String wattVarReactive2 = "";
|
||||
private String wattVarReactive3 = "";
|
||||
private String wattVarReactive4 = "";
|
||||
private String disableFloatCharge = "";
|
||||
private String inverterType = "";
|
||||
private String solarPSU = "";
|
||||
// SOC for battery
|
||||
private int cap1;
|
||||
private int cap2;
|
||||
private int cap3;
|
||||
private int cap4;
|
||||
private int cap5;
|
||||
private int cap6;
|
||||
//
|
||||
private String generatorForcedStart = "";
|
||||
private String overLongVolt = "";
|
||||
private String batteryChargeType = "";
|
||||
private String genOffVolt = "";
|
||||
private String absorptionVolt = "";
|
||||
private String genToLoad = "";
|
||||
private String mpptNum = "";
|
||||
private String underFreq1 = "";
|
||||
private String underFreq2 = "";
|
||||
private String wattPfEnable = "";
|
||||
private String remoteLock = "";
|
||||
private String generatorStartCap = "";
|
||||
private String batteryMaxCurrentCharge = "";
|
||||
private String overFreq1 = "";
|
||||
private String overFreq2 = "";
|
||||
private String genOnVolt = "";
|
||||
private String solar2WindInputEnable = "";
|
||||
private String caVStop = "";
|
||||
private String battMode = "";
|
||||
private String genOnCap = "";
|
||||
private String gridAlwaysOn = "";
|
||||
private String batteryLowVolt = "";
|
||||
private String acFreqUp = "";
|
||||
private String chargeLimit = "";
|
||||
private String generatorStartVolt = "";
|
||||
private String overVolt1Delay = "";
|
||||
//
|
||||
private int sellTime1Pac;
|
||||
private int sellTime2Pac;
|
||||
private int sellTime3Pac;
|
||||
private int sellTime4Pac;
|
||||
private int sellTime5Pac;
|
||||
private int sellTime6Pac;
|
||||
//
|
||||
private String californiaFreqPressureEnable = "";
|
||||
private String activePowerControl = "";
|
||||
private String batteryRestartVolt = "";
|
||||
private String zeroExportPower = "";
|
||||
private String overVolt2Delay = "";
|
||||
private String equChargeCycle = "";
|
||||
private String dischargeCurrent = "";
|
||||
private String solarSell = "";
|
||||
private String mpptVoltLow = "";
|
||||
// private String time3on;
|
||||
private String wattVoltEnable = "";
|
||||
private String caFwEnable = "";
|
||||
private String maxOperatingTimeOfGen = "";
|
||||
//
|
||||
private String maxExportGridOff = "";
|
||||
private String pvLine = "";
|
||||
private String three41 = "";
|
||||
private String caVwEnable = "";
|
||||
private String batteryShutdownVolt = "";
|
||||
private String startVoltUp = "";
|
||||
private String riso = "";
|
||||
private String sellTime1Volt = "";
|
||||
private String sellTime2Volt = "";
|
||||
private String sellTime3Volt = "";
|
||||
private String sellTime4Volt = "";
|
||||
private String sellTime5Volt = "";
|
||||
private String sellTime6Volt = "";
|
||||
private String facLowProtect = "";
|
||||
private String wattOverFreq1 = "";
|
||||
private String wattPf1 = "";
|
||||
private String wattPf2 = "";
|
||||
private String wattPf3 = "";
|
||||
private String wattPf4 = "";
|
||||
private String lowNoiseMode = "";
|
||||
private String tempco = "";
|
||||
private String arcFactFrz = "";
|
||||
private String meterSelect = "";
|
||||
private String genChargeOn = "";
|
||||
private String externalCtRatio = "";
|
||||
private String gridMode = "";
|
||||
private String lowThrough = "";
|
||||
private String drmEnable = "";
|
||||
private String underFreq1Delay = "";
|
||||
private String underFreq2Delay = "";
|
||||
private int energyMode;
|
||||
private String ampm = "";
|
||||
private String gridPeakShaving = "";
|
||||
private String fac = "";
|
||||
private String vacLowProtect = "";
|
||||
private String chargeCurrentLimit = "";
|
||||
private String caLv3 = "";
|
||||
private String specialFunction = "";
|
||||
private String batteryImpedance = "";
|
||||
private String safetyType = "";
|
||||
private String varVolt4 = "";
|
||||
private String varVolt3 = "";
|
||||
private String varVolt2 = "";
|
||||
private String varVolt1 = "";
|
||||
private String commAddr = "";
|
||||
private String dischargeLimit = "";
|
||||
private String atsEnable = "";
|
||||
private String exMeterCt = "";
|
||||
private String overFreq2Delay = "";
|
||||
private String phase = "";
|
||||
private String autoDim = "";
|
||||
private String batteryWorkStatus = "";
|
||||
private String genToLoadOn = "";
|
||||
private String timeSync = "";
|
||||
private String wattOverWgralFreq = "";
|
||||
private String sdBatteryCurrent = "";
|
||||
private int peakAndVallery;
|
||||
private String batteryEmptyVolt = "";
|
||||
private String batteryLowCap = "";
|
||||
private String underVolt2Delay = "";
|
||||
private String equChargeTime = "";
|
||||
private String battType = "";
|
||||
private String gridPeakPower = "";
|
||||
private String reset = "";
|
||||
private String vacHighProtect = "";
|
||||
private String pwm = "";
|
||||
private String highThrough = "";
|
||||
private String lockOutVoltVar = "";
|
||||
private String lockInWattPF = "";
|
||||
private String caVStart = "";
|
||||
private String acVoltUp = "";
|
||||
private String wattFreqEnable = "";
|
||||
private String wattOverExitFreq = "";
|
||||
private String caFStop = "";
|
||||
private String lowPowerMode = "";
|
||||
private String varVoltEnable = "";
|
||||
private String acCoupleFreqUpper = "";
|
||||
private String impedanceLow = "";
|
||||
private String acType = "";
|
||||
private String facHighProtect = "";
|
||||
private String recoveryTime = "";
|
||||
private String lithiumMode = "";
|
||||
private String gridSignal = "";
|
||||
private String wattOverFreq1StartDelay = "";
|
||||
private String testCommand = "";
|
||||
private String signalIslandModeEnable = "";
|
||||
private String upsStandard = "";
|
||||
private String reconnMinFreq = "";
|
||||
private String parallelRegister2 = "";
|
||||
private String parallelRegister1 = "";
|
||||
private String startVoltLow = "";
|
||||
private String smartLoadOpenDelay = "";
|
||||
private String wattVarActive1 = "";
|
||||
private String wattVarActive2 = "";
|
||||
private String wattVarActive3 = "";
|
||||
private String wattVarActive4 = "";
|
||||
private String genConnectGrid = "";
|
||||
private String flag2 = "";
|
||||
private String softStart = "";
|
||||
private String lockOutWattPF = "";
|
||||
private String sdStartCap = "";
|
||||
private String gfdi = "";
|
||||
private String checkSelfTime = "";
|
||||
private String limit = "";
|
||||
private String wattW1 = "";
|
||||
private String wattW2 = "";
|
||||
private String wattW3 = "";
|
||||
private String wattW4 = "";
|
||||
private String externalCurrent = "";
|
||||
private String vnResponseTime = "";
|
||||
private String batteryShutdownCap = "";
|
||||
private String wattUnderExitFreqStopDelay = "";
|
||||
private String offset = "";
|
||||
private String wattActivePf1 = "";
|
||||
private String wattActivePf2 = "";
|
||||
private String wattActivePf3 = "";
|
||||
private String wattActivePf4 = "";
|
||||
private String dischargeVolt = "";
|
||||
private String qvResponseTime = "";
|
||||
private String four19 = "";
|
||||
private String micExportAll = "";
|
||||
private String batteryMaxCurrentDischarge = "";
|
||||
private String isletProtect = "";
|
||||
private String californiaVoltPressureEnable = "";
|
||||
private String equVoltCharge = "";
|
||||
private String batteryCap = "";
|
||||
private String genOffCap = "";
|
||||
private String powerFactor = "";
|
||||
private String acCoupleOnLoadSideEnable = "";
|
||||
private String sdStartVolt = "";
|
||||
private String generatorBatteryCurrent = "";
|
||||
private String reconnMaxVolt = "";
|
||||
private String modbusSn = "";
|
||||
private String inverterOutputVoltage = "";
|
||||
private String chargeCurrent = "";
|
||||
private String solar1WindInputEnable = "";
|
||||
private String dcVoltUp = "";
|
||||
private String parallel = "";
|
||||
private String limter = "";
|
||||
private String batErr = "";
|
||||
private String backupDelay = "";
|
||||
private String dischargeCurrentLimit = "";
|
||||
private String arcFactB = "";
|
||||
private String arcFactC = "";
|
||||
private String arcFactD = "";
|
||||
private String arcFactF = "";
|
||||
private String arcFactI = "";
|
||||
private String arcFactT = "";
|
||||
private String wattUnderWgalFreq = "";
|
||||
private String commBaudRate = "";
|
||||
private String equipMode = "";
|
||||
private String gridSideINVMeter2 = "";
|
||||
private String underVolt1Delay = "";
|
||||
private String arcFaultType = "";
|
||||
private String normalUpwardSlope = "";
|
||||
private String pf = "";
|
||||
private String genMinSolar = "";
|
||||
private String acVoltLow = "";
|
||||
private String genSignal = "";
|
||||
}
|
||||
|
||||
public void buildLists() {
|
||||
this.gridTimeron = Arrays.asList(this.data.time1on, this.data.time2on, this.data.time3on, this.data.time4on,
|
||||
this.data.time5on, this.data.time6on);
|
||||
this.batteryCapacity = Arrays.asList(this.data.cap1, this.data.cap2, this.data.cap3, this.data.cap4,
|
||||
this.data.cap5, this.data.cap6);
|
||||
this.genTimeron = Arrays.asList(this.data.genTime1on, this.data.genTime2on, this.data.genTime3on,
|
||||
this.data.genTime4on, this.data.genTime5on, this.data.genTime6on);
|
||||
this.timerTime = Arrays.asList(this.data.sellTime1, this.data.sellTime2, this.data.sellTime3,
|
||||
this.data.sellTime4, this.data.sellTime5, this.data.sellTime6);
|
||||
this.batteryPowerLimit = Arrays.asList(this.data.sellTime1Pac, this.data.sellTime2Pac, this.data.sellTime3Pac,
|
||||
this.data.sellTime4Pac, this.data.sellTime5Pac, this.data.sellTime6Pac);
|
||||
}
|
||||
|
||||
public String getsn() {
|
||||
return this.data.sn;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return APIdata.staticAccessToken;
|
||||
}
|
||||
|
||||
public List<Boolean> getIntervalGridTimerOn() {
|
||||
return this.gridTimeron;
|
||||
}
|
||||
|
||||
public List<String> getIntervalTime() {
|
||||
return this.timerTime;
|
||||
}
|
||||
|
||||
public List<Boolean> getIntervalGenTimerOn() {
|
||||
return this.genTimeron;
|
||||
}
|
||||
|
||||
public List<Integer> getIntervalBatteryCapacity() {
|
||||
return this.batteryCapacity;
|
||||
}
|
||||
|
||||
public List<Integer> getIntervalBatteryPowerLimit() {
|
||||
return this.batteryPowerLimit;
|
||||
}
|
||||
|
||||
public Integer getPeakAndValley() {
|
||||
return this.data.peakAndVallery;
|
||||
}
|
||||
|
||||
public String getEnergyMode() {
|
||||
return String.valueOf(this.data.energyMode);
|
||||
}
|
||||
|
||||
public String getSysWorkMode() {
|
||||
return String.valueOf(this.data.sysWorkMode);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Content [code=" + code + ", msg=" + msg + "sucess=" + success + ", data=" + data + "]";
|
||||
}
|
||||
|
||||
public void setIntervalGridTimerOn(Boolean state, int interval) {
|
||||
this.gridTimeron.set(interval - 1, state);
|
||||
return;
|
||||
}
|
||||
|
||||
public void setIntervalTime(String state, int interval) {
|
||||
this.timerTime.set(interval - 1, asAPITime(state));
|
||||
return;
|
||||
}
|
||||
|
||||
private String asAPITime(String state) {
|
||||
String workerString = state.split("T")[1].substring(0, 5);
|
||||
int minsLS = Integer.valueOf(workerString.substring(4, 5));
|
||||
if ((minsLS < 5) & (minsLS > 0)) {
|
||||
minsLS = 0;
|
||||
} else if ((minsLS > 5)) {
|
||||
minsLS = 5;
|
||||
}
|
||||
return workerString.substring(0, 4) + minsLS;
|
||||
}
|
||||
|
||||
public void setIntervalGenTimerOn(Boolean state, int interval) {
|
||||
this.genTimeron.set(interval - 1, state);
|
||||
return;
|
||||
}
|
||||
|
||||
public void setIntervalBatteryCapacity(int state, int interval) {
|
||||
this.batteryCapacity.set(interval - 1, state);
|
||||
return;
|
||||
}
|
||||
|
||||
public void setIntervalBatteryPowerLimit(int state, int interval) {
|
||||
this.batteryPowerLimit.set(interval - 1, state);
|
||||
return;
|
||||
}
|
||||
|
||||
public void setPeakAndValley(int state) {
|
||||
this.data.peakAndVallery = state;
|
||||
}
|
||||
|
||||
public void setEnergyMode(int state) {
|
||||
this.data.energyMode = state;
|
||||
}
|
||||
|
||||
public void setSysWorkMode(int state) {
|
||||
this.data.sysWorkMode = state;
|
||||
}
|
||||
|
||||
public String buildBody() {
|
||||
Gson gson = new Gson();
|
||||
SettingsCommand commandBody = new SettingsCommand();
|
||||
commandBody.sn = this.data.sn;
|
||||
commandBody.safetyType = this.data.safetyType;
|
||||
commandBody.battMode = this.data.battMode;
|
||||
commandBody.solarSell = this.data.solarSell;
|
||||
commandBody.pvMaxLimit = this.data.pvMaxLimit;
|
||||
commandBody.energyMode = this.data.energyMode;
|
||||
commandBody.peakAndVallery = this.data.peakAndVallery;
|
||||
commandBody.sysWorkMode = this.data.sysWorkMode;
|
||||
commandBody.sellTime1 = this.timerTime.get(0);
|
||||
commandBody.sellTime2 = this.timerTime.get(1);
|
||||
commandBody.sellTime3 = this.timerTime.get(2);
|
||||
commandBody.sellTime4 = this.timerTime.get(3);
|
||||
commandBody.sellTime5 = this.timerTime.get(4);
|
||||
commandBody.sellTime6 = this.timerTime.get(5);
|
||||
commandBody.sellTime1Pac = this.batteryPowerLimit.get(0);
|
||||
commandBody.sellTime2Pac = this.batteryPowerLimit.get(1);
|
||||
commandBody.sellTime3Pac = this.batteryPowerLimit.get(2);
|
||||
commandBody.sellTime4Pac = this.batteryPowerLimit.get(3);
|
||||
commandBody.sellTime5Pac = this.batteryPowerLimit.get(4);
|
||||
commandBody.sellTime6Pac = this.batteryPowerLimit.get(5);
|
||||
commandBody.cap1 = this.batteryCapacity.get(0);
|
||||
commandBody.cap2 = this.batteryCapacity.get(1);
|
||||
commandBody.cap3 = this.batteryCapacity.get(2);
|
||||
commandBody.cap4 = this.batteryCapacity.get(3);
|
||||
commandBody.cap5 = this.batteryCapacity.get(4);
|
||||
commandBody.cap6 = this.batteryCapacity.get(5);
|
||||
commandBody.sellTime1Volt = this.data.sellTime1Volt;
|
||||
commandBody.sellTime2Volt = this.data.sellTime2Volt;
|
||||
commandBody.sellTime3Volt = this.data.sellTime3Volt;
|
||||
commandBody.sellTime4Volt = this.data.sellTime4Volt;
|
||||
commandBody.sellTime5Volt = this.data.sellTime5Volt;
|
||||
commandBody.sellTime6Volt = this.data.sellTime6Volt;
|
||||
commandBody.zeroExportPower = this.data.zeroExportPower;
|
||||
commandBody.solarMaxSellPower = this.data.solarMaxSellPower;
|
||||
commandBody.mondayOn = this.data.mondayOn;
|
||||
commandBody.tuesdayOn = this.data.tuesdayOn;
|
||||
commandBody.wednesdayOn = this.data.wednesdayOn;
|
||||
commandBody.thursdayOn = this.data.thursdayOn;
|
||||
commandBody.fridayOn = this.data.fridayOn;
|
||||
commandBody.saturdayOn = this.data.saturdayOn;
|
||||
commandBody.sundayOn = this.data.sundayOn;
|
||||
commandBody.time1on = this.gridTimeron.get(0);
|
||||
commandBody.time2on = this.gridTimeron.get(1);
|
||||
commandBody.time3on = this.gridTimeron.get(2);
|
||||
commandBody.time4on = this.gridTimeron.get(3);
|
||||
commandBody.time5on = this.gridTimeron.get(4);
|
||||
commandBody.time6on = this.gridTimeron.get(5);
|
||||
commandBody.genTime1on = this.genTimeron.get(0);
|
||||
commandBody.genTime2on = this.genTimeron.get(1);
|
||||
commandBody.genTime3on = this.genTimeron.get(2);
|
||||
commandBody.genTime4on = this.genTimeron.get(3);
|
||||
commandBody.genTime5on = this.genTimeron.get(4);
|
||||
commandBody.genTime6on = this.genTimeron.get(5);
|
||||
return gson.toJson(commandBody);
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link SettingsCommand} is the internal class for sending a
|
||||
* Charge setting command to a Sun Synk Connect Account.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SettingsCommand {
|
||||
protected String sn = "";
|
||||
protected String safetyType = "";
|
||||
protected String battMode = "";
|
||||
protected String solarSell = "";
|
||||
protected String pvMaxLimit = "";
|
||||
protected int energyMode;
|
||||
protected int peakAndVallery;
|
||||
protected int sysWorkMode;
|
||||
protected String sellTime1 = "";
|
||||
protected String sellTime2 = "";
|
||||
protected String sellTime3 = "";
|
||||
protected String sellTime4 = "";
|
||||
protected String sellTime5 = "";
|
||||
protected String sellTime6 = "";
|
||||
protected int sellTime1Pac;
|
||||
protected int sellTime2Pac;
|
||||
protected int sellTime3Pac;
|
||||
protected int sellTime4Pac;
|
||||
protected int sellTime5Pac;
|
||||
protected int sellTime6Pac;
|
||||
protected int cap1;
|
||||
protected int cap2;
|
||||
protected int cap3;
|
||||
protected int cap4;
|
||||
protected int cap5;
|
||||
protected int cap6;
|
||||
protected String sellTime1Volt = "";
|
||||
protected String sellTime2Volt = "";
|
||||
protected String sellTime3Volt = "";
|
||||
protected String sellTime4Volt = "";
|
||||
protected String sellTime5Volt = "";
|
||||
protected String sellTime6Volt = "";
|
||||
protected String zeroExportPower = "";
|
||||
protected String solarMaxSellPower = "";
|
||||
protected String mondayOn = "";
|
||||
protected String tuesdayOn = "";
|
||||
protected String wednesdayOn = "";
|
||||
protected String thursdayOn = "";
|
||||
protected String fridayOn = "";
|
||||
protected String saturdayOn = "";
|
||||
protected String sundayOn = "";
|
||||
protected Boolean time1on = false;
|
||||
protected Boolean time2on = false;
|
||||
protected Boolean time3on = false;
|
||||
protected Boolean time4on = false;
|
||||
protected Boolean time5on = false;
|
||||
protected Boolean time6on = false;
|
||||
protected Boolean genTime1on = false;
|
||||
protected Boolean genTime2on = false;
|
||||
protected Boolean genTime3on = false;
|
||||
protected Boolean genTime4on = false;
|
||||
protected Boolean genTime5on = false;
|
||||
protected Boolean genTime6on = false;
|
||||
|
||||
protected SettingsCommand() {
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkLogin} is the internal class for inital connection
|
||||
* to a Sun Synk Connect Account.
|
||||
* Login via Username and Password
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkLogin {
|
||||
// {"username":"xxx", "password":"xxx", "grant_type":"password", "client_id":"csp-web"}
|
||||
@SerializedName("username")
|
||||
private String userName = "";
|
||||
@SerializedName("password")
|
||||
private String passWord = "";
|
||||
@SerializedName("grant_type")
|
||||
private String grantType = "password";
|
||||
@SerializedName("client_id")
|
||||
private String clientId = "csp-web";
|
||||
|
||||
public SunSynkLogin(String UserName, String PassWord) {
|
||||
this.userName = UserName;
|
||||
this.passWord = PassWord;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link TokenRefresh} is the internal class for for reconnection
|
||||
* to a Sun Synk Connect Account.
|
||||
* Login via Username and Refresh Token
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class TokenRefresh {
|
||||
// {"grant_type":"refresh_token", "username":"xxx", "refresh_token":"xxx", "client_id\":"csp-web\"}
|
||||
@SerializedName("grant_type")
|
||||
private String grantType = "refresh_token";
|
||||
@SerializedName("username")
|
||||
private String userName = "";
|
||||
@SerializedName("refresh_token")
|
||||
private String refreshToken = "";
|
||||
@SerializedName("client_id")
|
||||
private String clientId = "csp-web";
|
||||
|
||||
public TokenRefresh(String UserName, String RefreshToken) {
|
||||
this.userName = UserName;
|
||||
this.refreshToken = RefreshToken;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.sunsynk.internal.api.exception;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkAuthenticateException} represents a binding specific {@link Exception}
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkAuthenticateException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SunSynkAuthenticateException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SunSynkAuthenticateException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SunSynkAuthenticateException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.sunsynk.internal.api.exception;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkDeviceControllerException} represents a binding specific {@link Exception}
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkDeviceControllerException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
public SunSynkDeviceControllerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SunSynkDeviceControllerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SunSynkDeviceControllerException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.sunsynk.internal.api.exception;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkGetStatusException} represents a binding specific {@link Exception}
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkGetStatusException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 3L;
|
||||
|
||||
public SunSynkGetStatusException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SunSynkGetStatusException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SunSynkGetStatusException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.sunsynk.internal.api.exception;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkInverterDiscoveryException} represents a binding specific {@link Exception}
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkInverterDiscoveryException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 4L;
|
||||
|
||||
public SunSynkInverterDiscoveryException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SunSynkInverterDiscoveryException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SunSynkInverterDiscoveryException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.sunsynk.internal.api.exception;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkSendCommandException} represents a binding specific {@link Exception}
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkSendCommandException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 5L;
|
||||
|
||||
public SunSynkSendCommandException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SunSynkSendCommandException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SunSynkSendCommandException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.sunsynk.internal.api.exception;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkTokenException} represents a binding specific {@link Exception}
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkTokenException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 6L;
|
||||
|
||||
public SunSynkTokenException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SunSynkTokenException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SunSynkTokenException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.sunsynk.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Parameters used for bridge configuration.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkAccountConfig {
|
||||
|
||||
private String email = "";
|
||||
private String password = "";
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.binding.sunsynk.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkInverterConfig} Parameters used for Inverterconfiguration.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkInverterConfig {
|
||||
|
||||
private String alias = "";
|
||||
private String serialnumber = "";
|
||||
private int refresh;
|
||||
|
||||
public String getSerialnumber() {
|
||||
return this.serialnumber;
|
||||
}
|
||||
|
||||
public int getRefresh() {
|
||||
return this.refresh;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return this.alias;
|
||||
}
|
||||
|
||||
public void setRefresh(int refresh) {
|
||||
this.refresh = refresh;
|
||||
}
|
||||
|
||||
public void setAlias(String alias) {
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
public void setSerialnumber(String sn) {
|
||||
this.serialnumber = sn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InverterConfig [alias=" + alias + ", serial=" + serialnumber + ", refresh=" + refresh + "]";
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.discovery;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
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.sunsynk.internal.SunSynkBindingConstants;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Inverter;
|
||||
import org.openhab.binding.sunsynk.internal.handler.SunSynkAccountHandler;
|
||||
import org.openhab.binding.sunsynk.internal.handler.SunSynkHandlerFactory;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkAccountDiscoveryService} is responsible for starting the discovery procedure
|
||||
* that connects to SunSynk Web and imports all registered inverters.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkAccountDiscoveryService extends AbstractDiscoveryService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SunSynkAccountDiscoveryService.class);
|
||||
private static final int TIMEOUT = 15;
|
||||
private final SunSynkAccountHandler handler;
|
||||
private final ThingUID bridgeUID;
|
||||
private @Nullable ScheduledFuture<?> scanTask;
|
||||
|
||||
public SunSynkAccountDiscoveryService(SunSynkAccountHandler handler) {
|
||||
super(SunSynkHandlerFactory.DISCOVERABLE_THING_TYPE_UIDS, TIMEOUT);
|
||||
this.handler = handler;
|
||||
this.bridgeUID = handler.getThing().getUID();
|
||||
}
|
||||
|
||||
private void findInverters() {
|
||||
List<Inverter> inverters = handler.getInvertersFromSunSynk();
|
||||
for (Inverter inverter : inverters) {
|
||||
addThing(inverter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startBackgroundDiscovery() {
|
||||
findInverters();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
this.scanTask = scheduler.schedule(this::findInverters, 0, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopScan() {
|
||||
super.stopScan();
|
||||
ScheduledFuture<?> scanTask = this.scanTask;
|
||||
if (scanTask != null) {
|
||||
scanTask.cancel(true);
|
||||
this.scanTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void addThing(Inverter inverter) {
|
||||
logger.debug("addThing(): Adding new SunSynk Inverter unit ({}) to the inbox", inverter.getAlias());
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
ThingUID thingUID = new ThingUID(SunSynkBindingConstants.THING_TYPE_INVERTER, bridgeUID, inverter.getUID());
|
||||
properties.put(SunSynkBindingConstants.CONFIG_GATE_SERIAL, inverter.getGateSerialNo());
|
||||
properties.put(SunSynkBindingConstants.CONFIG_SERIAL, inverter.getSerialNo());
|
||||
properties.put(Thing.PROPERTY_MODEL_ID, inverter.getID());
|
||||
properties.put(SunSynkBindingConstants.CONFIG_NAME, inverter.getAlias());
|
||||
thingDiscovered(DiscoveryResultBuilder.create(thingUID).withLabel(inverter.getAlias()).withBridge(bridgeUID)
|
||||
.withProperty("serialnumber", inverter.getSerialNo()).withRepresentationProperty("serialnumber")
|
||||
.withProperties(properties).build());
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.handler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
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.sunsynk.internal.api.AccountController;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Inverter;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkAuthenticateException;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkInverterDiscoveryException;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkTokenException;
|
||||
import org.openhab.binding.sunsynk.internal.config.SunSynkAccountConfig;
|
||||
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.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkAccountHandler} is responsible for handling the SunSynk Account Bridge
|
||||
*
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkAccountHandler extends BaseBridgeHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(SunSynkAccountHandler.class);
|
||||
private AccountController sunAccount = new AccountController();
|
||||
private @Nullable ScheduledFuture<?> discoverApiKeyJob;
|
||||
private @Nullable SunSynkAccountConfig accountConfig;
|
||||
|
||||
public SunSynkAccountHandler(Bridge bridge) {
|
||||
super(bridge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
accountConfig = getConfigAs(SunSynkAccountConfig.class);
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
logger.debug("SunSynk Handler Intialised attempting to retrieve configuration");
|
||||
discoverApiKeyJob = scheduler.schedule(this::configAccount, 0, TimeUnit.SECONDS); // calls account config
|
||||
// asynchronously
|
||||
}
|
||||
|
||||
public void setBridgeOnline() {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
public void setBridgeOffline() {
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
}
|
||||
|
||||
public List<Inverter> getInvertersFromSunSynk() {
|
||||
logger.debug("Attempting to find inverters tied to account");
|
||||
ArrayList<Inverter> inverters = new ArrayList<>();
|
||||
try {
|
||||
inverters = sunAccount.getDetails();
|
||||
} catch (SunSynkInverterDiscoveryException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Error attempting to find inverters registered to account");
|
||||
}
|
||||
return inverters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Disposing sunsynk bridge handler.");
|
||||
ScheduledFuture<?> discoverApiKeyJob = this.discoverApiKeyJob;
|
||||
if (discoverApiKeyJob != null) {
|
||||
discoverApiKeyJob.cancel(true);
|
||||
this.discoverApiKeyJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void configAccount() {
|
||||
SunSynkAccountConfig accountConfig = this.accountConfig;
|
||||
if (accountConfig == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No account config provided.");
|
||||
return;
|
||||
}
|
||||
if (accountConfig.getEmail().isBlank() | accountConfig.getPassword().isBlank()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"E-mail address or Password missing in account configuration");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.sunAccount.authenticate(accountConfig.getEmail(), accountConfig.getPassword());
|
||||
} catch (SunSynkAuthenticateException | SunSynkTokenException e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
String message = Objects.requireNonNullElse(e.getMessage(), "unkown error message");
|
||||
Throwable cause = e.getCause();
|
||||
String causeMessage = cause != null ? Objects.requireNonNullElse(cause.getMessage(), "unkown cause")
|
||||
: "unkown cause";
|
||||
logger.debug("Error attempting to authenticate account Msg = {} Cause = {}", message, causeMessage);
|
||||
}
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Error attempting to authenticate account");
|
||||
return;
|
||||
}
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
public boolean refreshAccount() throws SunSynkAuthenticateException {
|
||||
try {
|
||||
SunSynkAccountConfig accountConfig = this.accountConfig;
|
||||
if (accountConfig == null) {
|
||||
throw new SunSynkTokenException("No account config");
|
||||
}
|
||||
this.sunAccount.refreshAccount(accountConfig.getEmail());
|
||||
} catch (SunSynkTokenException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Error attempting to refresh token");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.handler;
|
||||
|
||||
import static org.openhab.binding.sunsynk.internal.SunSynkBindingConstants.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.sunsynk.internal.discovery.SunSynkAccountDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
|
||||
@Component(configurationPid = "binding.sunsynk", service = ThingHandlerFactory.class)
|
||||
public class SunSynkHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SunSynkHandlerFactory.class);
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPE_UIDS = Collections
|
||||
.unmodifiableSet(Stream.of(BRIDGE_TYPE_ACCOUNT, THING_TYPE_INVERTER).collect(Collectors.toSet()));
|
||||
|
||||
public static final Set<ThingTypeUID> DISCOVERABLE_THING_TYPE_UIDS = Set.of(THING_TYPE_INVERTER);
|
||||
|
||||
private Map<ThingUID, ServiceRegistration<DiscoveryService>> discoveryServiceRegistrations = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (thingTypeUID.equals(THING_TYPE_INVERTER)) {
|
||||
logger.debug("SunSynkHandlerFactory created Inverter Handler ");
|
||||
return new SunSynkInverterHandler(thing);
|
||||
} else if (thingTypeUID.equals(BRIDGE_TYPE_ACCOUNT)) {
|
||||
SunSynkAccountHandler handler = new SunSynkAccountHandler((Bridge) thing);
|
||||
registerAccountDiscoveryService(handler);
|
||||
logger.debug("SunSynkHandlerFactory created Account Handler ");
|
||||
return handler;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeHandler(ThingHandler thingHandler) {
|
||||
ServiceRegistration<DiscoveryService> serviceRegistration = discoveryServiceRegistrations
|
||||
.get(thingHandler.getThing().getUID());
|
||||
|
||||
if (serviceRegistration != null) {
|
||||
serviceRegistration.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
private void registerAccountDiscoveryService(SunSynkAccountHandler handler) {
|
||||
SunSynkAccountDiscoveryService discoveryService = new SunSynkAccountDiscoveryService(handler);
|
||||
|
||||
ServiceRegistration<DiscoveryService> serviceRegistration = this.bundleContext
|
||||
.registerService(DiscoveryService.class, discoveryService, null);
|
||||
|
||||
discoveryServiceRegistrations.put(handler.getThing().getUID(), serviceRegistration);
|
||||
}
|
||||
}
|
@ -0,0 +1,413 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.sunsynk.internal.handler;
|
||||
|
||||
import static org.openhab.binding.sunsynk.internal.SunSynkBindingConstants.*;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
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.sunsynk.internal.api.DeviceController;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Battery;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Daytemps;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Daytempsreturn;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Grid;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.RealTimeInData;
|
||||
import org.openhab.binding.sunsynk.internal.api.dto.Settings;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkAuthenticateException;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkDeviceControllerException;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkGetStatusException;
|
||||
import org.openhab.binding.sunsynk.internal.api.exception.SunSynkSendCommandException;
|
||||
import org.openhab.binding.sunsynk.internal.config.SunSynkInverterConfig;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
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.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link SunSynkInverterHandler} is responsible for handling commands, which are
|
||||
* sent to one of the Inverter channels.
|
||||
*
|
||||
* @author Lee Charlton - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class SunSynkInverterHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SunSynkInverterHandler.class);
|
||||
private @Nullable ZonedDateTime lockoutTimer = null;
|
||||
private DeviceController inverter = new DeviceController();
|
||||
private @Nullable ScheduledFuture<?> refreshTask;
|
||||
private boolean batterySettingsUpdated = false;
|
||||
private SunSynkInverterConfig config = new SunSynkInverterConfig();
|
||||
public Settings tempInverterChargeSettings = inverter.tempInverterChargeSettings; // Holds modified
|
||||
// battery settings.
|
||||
|
||||
public SunSynkInverterHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
Optional<SunSynkAccountHandler> checkBridge = getSafeBridge();
|
||||
if (!checkBridge.isPresent()) {
|
||||
logger.debug("Failed to find associated SunSynk Bridge.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
refreshStateAndUpdate();
|
||||
} else {
|
||||
this.tempInverterChargeSettings = inverter.getBatteryChargeSettings();
|
||||
switch (channelUID.getIdWithoutGroup()) {
|
||||
// Grid charge
|
||||
case CHANNEL_BATTERY_INTERVAL_1_GRID_CHARGE:
|
||||
this.tempInverterChargeSettings.setIntervalGridTimerOn(command.equals(OnOffType.ON), 1);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_2_GRID_CHARGE:
|
||||
this.tempInverterChargeSettings.setIntervalGridTimerOn(command.equals(OnOffType.ON), 2);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_3_GRID_CHARGE:
|
||||
this.tempInverterChargeSettings.setIntervalGridTimerOn(command.equals(OnOffType.ON), 3);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_4_GRID_CHARGE:
|
||||
this.tempInverterChargeSettings.setIntervalGridTimerOn(command.equals(OnOffType.ON), 4);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_5_GRID_CHARGE:
|
||||
this.tempInverterChargeSettings.setIntervalGridTimerOn(command.equals(OnOffType.ON), 5);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_6_GRID_CHARGE:
|
||||
this.tempInverterChargeSettings.setIntervalGridTimerOn(command.equals(OnOffType.ON), 6);
|
||||
break;
|
||||
// Gen charge
|
||||
case CHANNEL_BATTERY_INTERVAL_1_GEN_CHARGE:
|
||||
this.tempInverterChargeSettings.setIntervalGenTimerOn(command.equals(OnOffType.ON), 1);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_2_GEN_CHARGE:
|
||||
this.tempInverterChargeSettings.setIntervalGenTimerOn(command.equals(OnOffType.ON), 2);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_3_GEN_CHARGE:
|
||||
this.tempInverterChargeSettings.setIntervalGenTimerOn(command.equals(OnOffType.ON), 3);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_4_GEN_CHARGE:
|
||||
this.tempInverterChargeSettings.setIntervalGenTimerOn(command.equals(OnOffType.ON), 4);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_5_GEN_CHARGE:
|
||||
this.tempInverterChargeSettings.setIntervalGenTimerOn(command.equals(OnOffType.ON), 5);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_6_GEN_CHARGE:
|
||||
this.tempInverterChargeSettings.setIntervalGenTimerOn(command.equals(OnOffType.ON), 6);
|
||||
break;
|
||||
// Interval time
|
||||
case CHANNEL_BATTERY_INTERVAL_1_TIME:
|
||||
this.tempInverterChargeSettings.setIntervalTime(command.toString(), 1);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_2_TIME:
|
||||
this.tempInverterChargeSettings.setIntervalTime(command.toString(), 2);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_3_TIME:
|
||||
this.tempInverterChargeSettings.setIntervalTime(command.toString(), 3);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_4_TIME:
|
||||
this.tempInverterChargeSettings.setIntervalTime(command.toString(), 4);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_5_TIME:
|
||||
this.tempInverterChargeSettings.setIntervalTime(command.toString(), 5);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_6_TIME:
|
||||
this.tempInverterChargeSettings.setIntervalTime(command.toString(), 6);
|
||||
break;
|
||||
// Charge target
|
||||
case CHANNEL_BATTERY_INTERVAL_1_CAPACITY:
|
||||
this.tempInverterChargeSettings.setIntervalBatteryCapacity(Integer.valueOf(command.toString()), 1);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_2_CAPACITY:
|
||||
this.tempInverterChargeSettings.setIntervalBatteryCapacity(Integer.valueOf(command.toString()), 2);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_3_CAPACITY:
|
||||
this.tempInverterChargeSettings.setIntervalBatteryCapacity(Integer.valueOf(command.toString()), 3);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_4_CAPACITY:
|
||||
this.tempInverterChargeSettings.setIntervalBatteryCapacity(Integer.valueOf(command.toString()), 4);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_5_CAPACITY:
|
||||
this.tempInverterChargeSettings.setIntervalBatteryCapacity(Integer.valueOf(command.toString()), 5);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_6_CAPACITY:
|
||||
this.tempInverterChargeSettings.setIntervalBatteryCapacity(Integer.valueOf(command.toString()), 6);
|
||||
break;
|
||||
// Battery charging power limit
|
||||
case CHANNEL_BATTERY_INTERVAL_1_POWER_LIMIT:
|
||||
this.tempInverterChargeSettings.setIntervalBatteryPowerLimit(Integer.valueOf(command.toString()),
|
||||
1);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_2_POWER_LIMIT:
|
||||
this.tempInverterChargeSettings.setIntervalBatteryPowerLimit(Integer.valueOf(command.toString()),
|
||||
2);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_3_POWER_LIMIT:
|
||||
this.tempInverterChargeSettings.setIntervalBatteryPowerLimit(Integer.valueOf(command.toString()),
|
||||
3);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_4_POWER_LIMIT:
|
||||
this.tempInverterChargeSettings.setIntervalBatteryPowerLimit(Integer.valueOf(command.toString()),
|
||||
4);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_5_POWER_LIMIT:
|
||||
this.tempInverterChargeSettings.setIntervalBatteryPowerLimit(Integer.valueOf(command.toString()),
|
||||
5);
|
||||
break;
|
||||
case CHANNEL_BATTERY_INTERVAL_6_POWER_LIMIT:
|
||||
this.tempInverterChargeSettings.setIntervalBatteryPowerLimit(Integer.valueOf(command.toString()),
|
||||
6);
|
||||
break;
|
||||
// Inverter control
|
||||
case CHANNEL_INVERTER_CONTROL_TIMER:
|
||||
this.tempInverterChargeSettings.setPeakAndValley(Integer.valueOf(command.toString()));
|
||||
break;
|
||||
case CHANNEL_INVERTER_CONTROL_ENERGY_PATTERN:
|
||||
this.tempInverterChargeSettings.setEnergyMode(Integer.valueOf(command.toString()));
|
||||
break;
|
||||
case CHANNEL_INVERTER_CONTROL_WORK_MODE:
|
||||
this.tempInverterChargeSettings.setSysWorkMode(Integer.valueOf(command.toString()));
|
||||
break;
|
||||
}
|
||||
|
||||
this.batterySettingsUpdated = true; // true = update battery settings from API at next interval
|
||||
}
|
||||
}
|
||||
|
||||
private void sendSettingsCommandToInverter() {
|
||||
try {
|
||||
inverter.sendSettings(this.tempInverterChargeSettings);
|
||||
} catch (SunSynkSendCommandException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Could not send command to inverter " + config.getAlias() + ". Authentication Failure !");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Running dispose()");
|
||||
ScheduledFuture<?> refreshTask = this.refreshTask;
|
||||
if (refreshTask != null) {
|
||||
refreshTask.cancel(true);
|
||||
this.refreshTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
config = getThing().getConfiguration().as(SunSynkInverterConfig.class);
|
||||
logger.debug("Inverter Config: {}", config);
|
||||
|
||||
if (config.getRefresh() < 60) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Refresh time " + config.getRefresh() + " is not valid. Refresh time must be at least 60 seconds.");
|
||||
return;
|
||||
}
|
||||
this.batterySettingsUpdated = false;
|
||||
inverter = new DeviceController(config);
|
||||
startAutomaticRefresh();
|
||||
}
|
||||
|
||||
private Optional<SunSynkAccountHandler> getSafeBridge() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null && bridge.getHandler() instanceof SunSynkAccountHandler bridgeHandler) {
|
||||
return Optional.of(bridgeHandler);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void refreshStateAndUpdate() {
|
||||
ZonedDateTime lockoutTimer = this.lockoutTimer;
|
||||
|
||||
if (lockoutTimer != null && lockoutTimer.isAfter(ZonedDateTime.now())) { // lockout calls that come
|
||||
// too fast
|
||||
logger.debug("API call too frequent, ignored {} ", lockoutTimer);
|
||||
return;
|
||||
}
|
||||
lockoutTimer = ZonedDateTime.now().plusMinutes(1); // lockout time 1 min
|
||||
|
||||
Optional<SunSynkAccountHandler> checkBridge = getSafeBridge();
|
||||
if (!checkBridge.isPresent()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "No SunSynk Account");
|
||||
return;
|
||||
}
|
||||
SunSynkAccountHandler bridgeHandler = checkBridge.get();
|
||||
try {
|
||||
bridgeHandler.refreshAccount(); // check account token
|
||||
} catch (SunSynkAuthenticateException e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
String message = Objects.requireNonNullElse(e.getMessage(), "unkown error message");
|
||||
Throwable cause = e.getCause();
|
||||
String causeMessage = cause != null ? Objects.requireNonNullElse(cause.getMessage(), "unkown cause")
|
||||
: "unkown cause";
|
||||
logger.debug("Sun Synk account refresh failed: Msg = {}. Cause = {}.", message, causeMessage);
|
||||
}
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "Sun Synk account refresh failed");
|
||||
bridgeHandler.setBridgeOffline();
|
||||
return;
|
||||
}
|
||||
if (this.batterySettingsUpdated) { // have the settings been modified locally
|
||||
sendSettingsCommandToInverter(); // update the battery settings
|
||||
}
|
||||
try {
|
||||
inverter.sendGetState(this.batterySettingsUpdated); // get inverter settings
|
||||
} catch (SunSynkGetStatusException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Could not get state of inverter " + config.getAlias() + ". Authentication Failure !");
|
||||
return;
|
||||
} catch (JsonSyntaxException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Could not get state of inverter " + config.getAlias() + ". JSON parsing Failure !");
|
||||
return;
|
||||
} catch (SunSynkDeviceControllerException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Could not get state of inverter " + config.getAlias() + ". DeviceController Failure !");
|
||||
return;
|
||||
}
|
||||
logger.debug("Retrieved state of inverter {}.", config.getAlias());
|
||||
this.batterySettingsUpdated = false; // set to get settings from API
|
||||
bridgeHandler.setBridgeOnline();
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
publishChannels();
|
||||
}
|
||||
|
||||
private void startAutomaticRefresh() {
|
||||
this.refreshTask = scheduler.scheduleWithFixedDelay(this::refreshStateAndUpdate, 0, config.getRefresh(),
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void publishChannels() {
|
||||
logger.debug("Updating Channels");
|
||||
updateSettings();
|
||||
updateGrid();
|
||||
updateBattery();
|
||||
updateTemperature();
|
||||
updateSolar();
|
||||
}
|
||||
|
||||
private void updateSettings() {
|
||||
Settings inverterChargeSettings = inverter.getBatteryChargeSettings();
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_1_GRID_CHARGE,
|
||||
OnOffType.from(inverterChargeSettings.getIntervalGridTimerOn().get(0)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_2_GRID_CHARGE,
|
||||
OnOffType.from(inverterChargeSettings.getIntervalGridTimerOn().get(1)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_3_GRID_CHARGE,
|
||||
OnOffType.from(inverterChargeSettings.getIntervalGridTimerOn().get(2)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_4_GRID_CHARGE,
|
||||
OnOffType.from(inverterChargeSettings.getIntervalGridTimerOn().get(3)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_5_GRID_CHARGE,
|
||||
OnOffType.from(inverterChargeSettings.getIntervalGridTimerOn().get(4)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_6_GRID_CHARGE,
|
||||
OnOffType.from(inverterChargeSettings.getIntervalGridTimerOn().get(5)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_1_GEN_CHARGE,
|
||||
OnOffType.from(inverterChargeSettings.getIntervalGenTimerOn().get(0)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_2_GEN_CHARGE,
|
||||
OnOffType.from(inverterChargeSettings.getIntervalGenTimerOn().get(1)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_3_GEN_CHARGE,
|
||||
OnOffType.from(inverterChargeSettings.getIntervalGenTimerOn().get(2)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_4_GEN_CHARGE,
|
||||
OnOffType.from(inverterChargeSettings.getIntervalGenTimerOn().get(3)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_5_GEN_CHARGE,
|
||||
OnOffType.from(inverterChargeSettings.getIntervalGenTimerOn().get(4)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_6_GEN_CHARGE,
|
||||
OnOffType.from(inverterChargeSettings.getIntervalGenTimerOn().get(5)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_1_CAPACITY,
|
||||
new DecimalType(inverterChargeSettings.getIntervalBatteryCapacity().get(0)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_2_CAPACITY,
|
||||
new DecimalType(inverterChargeSettings.getIntervalBatteryCapacity().get(1)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_3_CAPACITY,
|
||||
new DecimalType(inverterChargeSettings.getIntervalBatteryCapacity().get(2)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_4_CAPACITY,
|
||||
new DecimalType(inverterChargeSettings.getIntervalBatteryCapacity().get(3)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_5_CAPACITY,
|
||||
new DecimalType(inverterChargeSettings.getIntervalBatteryCapacity().get(4)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_6_CAPACITY,
|
||||
new DecimalType(inverterChargeSettings.getIntervalBatteryCapacity().get(5)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_1_TIME, new StringType(inverterChargeSettings.getIntervalTime().get(0)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_2_TIME, new StringType(inverterChargeSettings.getIntervalTime().get(1)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_3_TIME, new StringType(inverterChargeSettings.getIntervalTime().get(2)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_4_TIME, new StringType(inverterChargeSettings.getIntervalTime().get(3)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_5_TIME, new StringType(inverterChargeSettings.getIntervalTime().get(4)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_6_TIME, new StringType(inverterChargeSettings.getIntervalTime().get(5)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_1_POWER_LIMIT,
|
||||
new DecimalType(inverterChargeSettings.getIntervalBatteryPowerLimit().get(0)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_2_POWER_LIMIT,
|
||||
new DecimalType(inverterChargeSettings.getIntervalBatteryPowerLimit().get(1)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_3_POWER_LIMIT,
|
||||
new DecimalType(inverterChargeSettings.getIntervalBatteryPowerLimit().get(2)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_4_POWER_LIMIT,
|
||||
new DecimalType(inverterChargeSettings.getIntervalBatteryPowerLimit().get(3)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_5_POWER_LIMIT,
|
||||
new DecimalType(inverterChargeSettings.getIntervalBatteryPowerLimit().get(4)));
|
||||
updateState(CHANNEL_BATTERY_INTERVAL_6_POWER_LIMIT,
|
||||
new DecimalType(inverterChargeSettings.getIntervalBatteryPowerLimit().get(5)));
|
||||
updateState(CHANNEL_INVERTER_CONTROL_TIMER, new DecimalType(inverterChargeSettings.getPeakAndValley()));
|
||||
updateState(CHANNEL_INVERTER_CONTROL_ENERGY_PATTERN, new StringType(inverterChargeSettings.getEnergyMode()));
|
||||
updateState(CHANNEL_INVERTER_CONTROL_WORK_MODE, new StringType(inverterChargeSettings.getSysWorkMode()));
|
||||
}
|
||||
|
||||
private void updateGrid() {
|
||||
Grid inverterGrid = inverter.getRealTimeGridStatus();
|
||||
updateState(CHANNEL_INVERTER_GRID_POWER, new DecimalType(inverterGrid.getGridPower()));
|
||||
updateState(CHANNEL_INVERTER_GRID_VOLTAGE, new DecimalType(inverterGrid.getGridVoltage()));
|
||||
updateState(CHANNEL_INVERTER_GRID_CURRENT, new DecimalType(inverterGrid.getGridCurrent()));
|
||||
}
|
||||
|
||||
private void updateBattery() {
|
||||
Battery batteryState = inverter.getRealTimeBatteryState();
|
||||
updateState(CHANNEL_BATTERY_VOLTAGE, new DecimalType(batteryState.getBatteryVoltage()));
|
||||
updateState(CHANNEL_BATTERY_CURRENT, new DecimalType(batteryState.getBatteryCurrent()));
|
||||
updateState(CHANNEL_BATTERY_POWER, new DecimalType(batteryState.getBatteryPower()));
|
||||
updateState(CHANNEL_BATTERY_SOC, new DecimalType(batteryState.getBatterySOC()));
|
||||
updateState(CHANNEL_BATTERY_TEMPERATURE, new DecimalType(batteryState.getBatteryTemperature()));
|
||||
}
|
||||
|
||||
private void updateTemperature() {
|
||||
Daytemps batteryTempHist = inverter.getInverterTemperatureHistory();
|
||||
Daytempsreturn batteryTemps = batteryTempHist.inverterTemperatures();
|
||||
if (!batteryTemps.getStatus()) {
|
||||
logger.debug("Failed to get inverter and battery temperatures");
|
||||
return;
|
||||
}
|
||||
updateState(CHANNEL_INVERTER_AC_TEMPERATURE, new DecimalType(batteryTemps.getDCTemperature()));
|
||||
updateState(CHANNEL_INVERTER_DC_TEMPERATURE, new DecimalType(batteryTemps.getACTemperature()));
|
||||
}
|
||||
|
||||
private void updateSolar() {
|
||||
RealTimeInData solar = inverter.getRealtimeSolarStatus();
|
||||
updateState(CHANNEL_INVERTER_SOLAR_ENERGY_TODAY, new DecimalType(solar.getetoday()));
|
||||
updateState(CHANNEL_INVERTER_SOLAR_ENERGY_TOTAL, new DecimalType(solar.getetotal()));
|
||||
updateState(CHANNEL_INVERTER_SOLAR_POWER_NOW, new DecimalType(solar.getPVIV()));
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<addon:addon id="sunsynk" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
|
||||
<type>binding</type>
|
||||
<name>SunSynk Binding</name>
|
||||
<description>This is the binding for SunSynk Connect.</description>
|
||||
<connection>cloud</connection>
|
||||
</addon:addon>
|
@ -0,0 +1,123 @@
|
||||
# add-on
|
||||
|
||||
addon.sunsynk.name = SunSynk Binding
|
||||
addon.sunsynk.description = This is the binding for SunSynk Connect.
|
||||
|
||||
# thing types
|
||||
|
||||
thing-type.sunsynk.account.label = SunSynk Account
|
||||
thing-type.sunsynk.account.description = Access to SunSynk Account. Used to discover plants and inverters tied to account.
|
||||
thing-type.sunsynk.inverter.label = SunSynk Inverter
|
||||
thing-type.sunsynk.inverter.description = Inverter thing for SunSynk Binding.
|
||||
thing-type.sunsynk.inverter.channel.battery-dc-current.label = Battery Current
|
||||
thing-type.sunsynk.inverter.channel.battery-dc-current.description = Measured current of the battery.
|
||||
thing-type.sunsynk.inverter.channel.battery-dc-power.label = Battery Power
|
||||
thing-type.sunsynk.inverter.channel.battery-dc-power.description = Measured power of the battery.
|
||||
thing-type.sunsynk.inverter.channel.battery-dc-voltage.label = Battery Voltage
|
||||
thing-type.sunsynk.inverter.channel.battery-dc-voltage.description = Measured voltage of the battery.
|
||||
thing-type.sunsynk.inverter.channel.battery-temperature.label = Battery Temperature
|
||||
thing-type.sunsynk.inverter.channel.battery-temperature.description = Temperature of the battery reported by the BMS.
|
||||
thing-type.sunsynk.inverter.channel.interval-1-gen-charge.label = Interval 1 Generator Charge
|
||||
thing-type.sunsynk.inverter.channel.interval-1-grid-capacity.label = Interval 1 Charge Target
|
||||
thing-type.sunsynk.inverter.channel.interval-1-grid-charge.label = Interval 1 Grid Charge
|
||||
thing-type.sunsynk.inverter.channel.interval-1-grid-power-limit.label = Interval 1 Maximum Charge Rate
|
||||
thing-type.sunsynk.inverter.channel.interval-1-grid-time.label = Interval 1 Start Time
|
||||
thing-type.sunsynk.inverter.channel.interval-2-gen-charge.label = Interval 2 Generator Charge
|
||||
thing-type.sunsynk.inverter.channel.interval-2-grid-capacity.label = Interval 2 Charge Target
|
||||
thing-type.sunsynk.inverter.channel.interval-2-grid-charge.label = Interval 2 Grid Charge
|
||||
thing-type.sunsynk.inverter.channel.interval-2-grid-power-limit.label = Interval 2 Maximum Charge Rate
|
||||
thing-type.sunsynk.inverter.channel.interval-2-grid-time.label = Interval 2 Start Time
|
||||
thing-type.sunsynk.inverter.channel.interval-3-gen-charge.label = Interval 3 Generator Charge
|
||||
thing-type.sunsynk.inverter.channel.interval-3-grid-capacity.label = Interval 3 Charge Target
|
||||
thing-type.sunsynk.inverter.channel.interval-3-grid-charge.label = Interval 3 Grid Charge
|
||||
thing-type.sunsynk.inverter.channel.interval-3-grid-power-limit.label = Interval 3 Maximum Charge Rate
|
||||
thing-type.sunsynk.inverter.channel.interval-3-grid-time.label = Interval 3 Start Time
|
||||
thing-type.sunsynk.inverter.channel.interval-4-gen-charge.label = Interval 4 Generator Charge
|
||||
thing-type.sunsynk.inverter.channel.interval-4-grid-capacity.label = Interval 4 Charge Target
|
||||
thing-type.sunsynk.inverter.channel.interval-4-grid-charge.label = Interval 4 Grid Charge
|
||||
thing-type.sunsynk.inverter.channel.interval-4-grid-power-limit.label = Interval 4 Maximum Charge Rate
|
||||
thing-type.sunsynk.inverter.channel.interval-4-grid-time.label = Interval 4 Start Time
|
||||
thing-type.sunsynk.inverter.channel.interval-5-gen-charge.label = Interval 5 Generator Charge
|
||||
thing-type.sunsynk.inverter.channel.interval-5-grid-capacity.label = Interval 5 Charge Target
|
||||
thing-type.sunsynk.inverter.channel.interval-5-grid-charge.label = Interval 5 Grid Charge
|
||||
thing-type.sunsynk.inverter.channel.interval-5-grid-power-limit.label = Interval 5 Maximum Charge Rate
|
||||
thing-type.sunsynk.inverter.channel.interval-5-grid-time.label = Interval 5 Start Time
|
||||
thing-type.sunsynk.inverter.channel.interval-6-gen-charge.label = Interval 6 Generator Charge
|
||||
thing-type.sunsynk.inverter.channel.interval-6-grid-capacity.label = Interval 6 Charge Target
|
||||
thing-type.sunsynk.inverter.channel.interval-6-grid-charge.label = Interval 6 Grid Charge
|
||||
thing-type.sunsynk.inverter.channel.interval-6-grid-power-limit.label = Interval 6 Maximum Charge Rate
|
||||
thing-type.sunsynk.inverter.channel.interval-6-grid-time.label = Interval 6 Start Time
|
||||
thing-type.sunsynk.inverter.channel.inverter-ac-temperature.label = Inverter AC Temperature
|
||||
thing-type.sunsynk.inverter.channel.inverter-ac-temperature.description = Temperature of the inverter ac side.
|
||||
thing-type.sunsynk.inverter.channel.inverter-dc-temperature.label = Inverter DC Temperature
|
||||
thing-type.sunsynk.inverter.channel.inverter-dc-temperature.description = Temperature of the inverter dc side.
|
||||
thing-type.sunsynk.inverter.channel.inverter-grid-current.label = Grid Current
|
||||
thing-type.sunsynk.inverter.channel.inverter-grid-current.description = Measured current of the grid.
|
||||
thing-type.sunsynk.inverter.channel.inverter-grid-power.label = Grid Power
|
||||
thing-type.sunsynk.inverter.channel.inverter-grid-power.description = Grid power import/export.
|
||||
thing-type.sunsynk.inverter.channel.inverter-grid-voltage.label = Grid Voltage
|
||||
thing-type.sunsynk.inverter.channel.inverter-grid-voltage.description = Measured voltage of the grid.
|
||||
thing-type.sunsynk.inverter.channel.inverter-solar-energy-today.label = Solar Energy Today
|
||||
thing-type.sunsynk.inverter.channel.inverter-solar-energy-today.description = Solar energy generted today.
|
||||
thing-type.sunsynk.inverter.channel.inverter-solar-energy-total.label = Solar Energy Total
|
||||
thing-type.sunsynk.inverter.channel.inverter-solar-energy-total.description = Total solar energy generted.
|
||||
thing-type.sunsynk.inverter.channel.inverter-solar-power-now.label = Solar Power
|
||||
thing-type.sunsynk.inverter.channel.inverter-solar-power-now.description = Solar power being generted.
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.sunsynk.account.email.label = E-mail Address
|
||||
thing-type.config.sunsynk.account.email.description = E-mail address for your SunSynk Connect account.
|
||||
thing-type.config.sunsynk.account.password.label = Password
|
||||
thing-type.config.sunsynk.account.password.description = Password for your SunSynk Connect account.
|
||||
thing-type.config.sunsynk.inverter.alias.label = Inverter Name
|
||||
thing-type.config.sunsynk.inverter.alias.description = Name of inverter from Sun Synk Connect.
|
||||
thing-type.config.sunsynk.inverter.refresh.label = Refresh Interval
|
||||
thing-type.config.sunsynk.inverter.refresh.description = Time in seconds to retrieve status from Sun Synk Connect services. Greater than 60 seconds.
|
||||
thing-type.config.sunsynk.inverter.serialnumber.label = Inverter Serial Number
|
||||
thing-type.config.sunsynk.inverter.serialnumber.description = Serial number of the inverter from Sun Synk Connect.
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.sunsynk.battery-target.label = Target Charge Level
|
||||
channel-type.sunsynk.battery-target.description = The desired charge level of the battery (%).
|
||||
channel-type.sunsynk.control-pattern.label = System Energy Pattern
|
||||
channel-type.sunsynk.control-pattern.description = Set the system mode energy pattern to '0' Priority Battery or '1' Priority Load.
|
||||
channel-type.sunsynk.control-pattern.command.option.0 = Priority Battery
|
||||
channel-type.sunsynk.control-pattern.command.option.1 = Priority Load
|
||||
channel-type.sunsynk.control-timer.label = System Timer
|
||||
channel-type.sunsynk.control-timer.description = Use the system mode timer to control battery charge discharge.
|
||||
channel-type.sunsynk.control-work-mode.label = System Work Mode
|
||||
channel-type.sunsynk.control-work-mode.description = Set the work mode to '0' Selling First; '1' Zero-Export + Limted to Load or '2' Limited to Home.
|
||||
channel-type.sunsynk.control-work-mode.command.option.0 = Selling First
|
||||
channel-type.sunsynk.control-work-mode.command.option.1 = "Zero-Export + Limted to Load"
|
||||
channel-type.sunsynk.control-work-mode.command.option.2 = Limited to Home
|
||||
channel-type.sunsynk.gen-charge.label = Generator (AUX) Charge
|
||||
channel-type.sunsynk.gen-charge.description = Charge the inverter battery from the generator (auxilary) during this interval.
|
||||
channel-type.sunsynk.grid-charge.label = Grid Charge
|
||||
channel-type.sunsynk.grid-charge.description = Charge the inverter battery from the grid during this interval.
|
||||
channel-type.sunsynk.grid-time.label = Grid Charge Time
|
||||
channel-type.sunsynk.grid-time.description = "Grid charging interval start time. Use 24hr time. 00:00 to 23:55 are valid in 5 min increments with leading zero on the hour and minute. Interval times must be in ascending order."
|
||||
channel-type.sunsynk.grid-time.state.pattern = %1$tH:%1$tM
|
||||
channel-type.sunsynk.power-charge-limit.label = Maximum Charge Rate
|
||||
channel-type.sunsynk.power-charge-limit.description = maximum charge power desired (limited by inverter capability).
|
||||
|
||||
# add-in
|
||||
|
||||
thing-type.sunsynk.sunsynkccount.label = SunSynk Account
|
||||
thing-type.sunsynk.sunsynkccount.description = Access to SunSynk Account. Used to discover plants and inverters tied to account.
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.sunsynk.sunsynkaccount.email.label = E-mail Address
|
||||
thing-type.config.sunsynk.sunsynkaccount.email.description = E-mail address for your SunSynk Connect account.
|
||||
thing-type.config.sunsynk.sunsynkaccount.password.label = Password
|
||||
thing-type.config.sunsynk.sunsynkaccount.password.description = Password for your SunSynk Connect account.
|
||||
thing-type.config.sunsynk.sunsynkaccount.accessToken.label = SunSynk Secret
|
||||
thing-type.config.sunsynk.sunsynkaccount.accessToken.description = Secret for accessing SunSynk Connect services.
|
||||
thing-type.config.sunsynk.sunsynkaccount.refreshToken.label = SunSynk Refresh Secret
|
||||
thing-type.config.sunsynk.sunsynkaccount.refreshToken.description = SunSynk Connect services refresh secret.
|
||||
thing-type.config.sunsynk.sunsynkaccount.expiresIn.label = SunSynk Secret expiry
|
||||
thing-type.config.sunsynk.sunsynkaccount.expiresIn.description = SunSynk Connect services token expiry in seconds.
|
||||
thing-type.config.sunsynk.sunsynkaccount.issuedAt.label = SunSynk Secret issue time stamp
|
||||
thing-type.config.sunsynk.sunsynkaccount.issuedAt.description = SunSynk Connect services token issue time stamp.
|
@ -0,0 +1,274 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="sunsynk"
|
||||
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="account">
|
||||
<label>SunSynk Account</label>
|
||||
<description>Access to SunSynk Account. Used to discover plants and inverters tied to account.</description>
|
||||
<properties>
|
||||
<property name="vendor">SunSynk</property>
|
||||
</properties>
|
||||
<config-description>
|
||||
<parameter name="email" type="text" required="true">
|
||||
<label>E-mail Address</label>
|
||||
<description>E-mail address for your SunSynk Connect account.</description>
|
||||
<context>email</context>
|
||||
</parameter>
|
||||
<parameter name="password" type="text" required="true">
|
||||
<label>Password</label>
|
||||
<description>Password for your SunSynk Connect account.</description>
|
||||
<context>password</context>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</bridge-type>
|
||||
|
||||
<thing-type id="inverter">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="account"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>SunSynk Inverter</label>
|
||||
<description>Inverter thing for SunSynk Binding.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="interval-1-grid-charge" typeId="grid-charge">
|
||||
<label>Interval 1 Grid Charge</label>
|
||||
</channel>
|
||||
<channel id="interval-1-grid-time" typeId="grid-time">
|
||||
<label>Interval 1 Start Time</label>
|
||||
</channel>
|
||||
<channel id="interval-1-grid-capacity" typeId="battery-target">
|
||||
<label>Interval 1 Charge Target</label>
|
||||
</channel>
|
||||
<channel id="interval-1-grid-power-limit" typeId="power-charge-limit">
|
||||
<label>Interval 1 Maximum Charge Rate</label>
|
||||
</channel>
|
||||
<channel id="interval-2-grid-charge" typeId="grid-charge">
|
||||
<label>Interval 2 Grid Charge </label>
|
||||
</channel>
|
||||
<channel id="interval-2-grid-time" typeId="grid-time">
|
||||
<label>Interval 2 Start Time</label>
|
||||
</channel>
|
||||
<channel id="interval-2-grid-capacity" typeId="battery-target">
|
||||
<label>Interval 2 Charge Target</label>
|
||||
</channel>
|
||||
<channel id="interval-2-grid-power-limit" typeId="power-charge-limit">
|
||||
<label>Interval 2 Maximum Charge Rate</label>
|
||||
</channel>
|
||||
<channel id="interval-3-grid-charge" typeId="grid-charge">
|
||||
<label>Interval 3 Grid Charge</label>
|
||||
</channel>
|
||||
<channel id="interval-3-grid-time" typeId="grid-time">
|
||||
<label>Interval 3 Start Time</label>
|
||||
</channel>
|
||||
<channel id="interval-3-grid-capacity" typeId="battery-target">
|
||||
<label>Interval 3 Charge Target</label>
|
||||
</channel>
|
||||
<channel id="interval-3-grid-power-limit" typeId="power-charge-limit">
|
||||
<label>Interval 3 Maximum Charge Rate</label>
|
||||
</channel>
|
||||
<channel id="interval-4-grid-charge" typeId="grid-charge">
|
||||
<label>Interval 4 Grid Charge</label>
|
||||
</channel>
|
||||
<channel id="interval-4-grid-time" typeId="grid-time">
|
||||
<label>Interval 4 Start Time</label>
|
||||
</channel>
|
||||
<channel id="interval-4-grid-capacity" typeId="battery-target">
|
||||
<label>Interval 4 Charge Target</label>
|
||||
</channel>
|
||||
<channel id="interval-4-grid-power-limit" typeId="power-charge-limit">
|
||||
<label>Interval 4 Maximum Charge Rate</label>
|
||||
</channel>
|
||||
<channel id="interval-5-grid-charge" typeId="grid-charge">
|
||||
<label>Interval 5 Grid Charge</label>
|
||||
</channel>
|
||||
<channel id="interval-5-grid-time" typeId="grid-time">
|
||||
<label>Interval 5 Start Time</label>
|
||||
</channel>
|
||||
<channel id="interval-5-grid-capacity" typeId="battery-target">
|
||||
<label>Interval 5 Charge Target</label>
|
||||
</channel>
|
||||
<channel id="interval-5-grid-power-limit" typeId="power-charge-limit">
|
||||
<label>Interval 5 Maximum Charge Rate</label>
|
||||
</channel>
|
||||
<channel id="interval-6-grid-charge" typeId="grid-charge">
|
||||
<label>Interval 6 Grid Charge</label>
|
||||
</channel>
|
||||
<channel id="interval-6-grid-time" typeId="grid-time">
|
||||
<label>Interval 6 Start Time</label>
|
||||
</channel>
|
||||
<channel id="interval-6-grid-capacity" typeId="battery-target">
|
||||
<label>Interval 6 Charge Target</label>
|
||||
</channel>
|
||||
<channel id="interval-6-grid-power-limit" typeId="power-charge-limit">
|
||||
<label>Interval 6 Maximum Charge Rate</label>
|
||||
</channel>
|
||||
<channel id="interval-1-gen-charge" typeId="gen-charge">
|
||||
<label>Interval 1 Generator Charge</label>
|
||||
</channel>
|
||||
<channel id="interval-2-gen-charge" typeId="gen-charge">
|
||||
<label>Interval 2 Generator Charge</label>
|
||||
</channel>
|
||||
<channel id="interval-3-gen-charge" typeId="gen-charge">
|
||||
<label>Interval 3 Generator Charge</label>
|
||||
</channel>
|
||||
<channel id="interval-4-gen-charge" typeId="gen-charge">
|
||||
<label>Interval 4 Generator Charge</label>
|
||||
</channel>
|
||||
<channel id="interval-5-gen-charge" typeId="gen-charge">
|
||||
<label>Interval 5 Generator Charge</label>
|
||||
</channel>
|
||||
<channel id="interval-6-gen-charge" typeId="gen-charge">
|
||||
<label>Interval 6 Generator Charge</label>
|
||||
</channel>
|
||||
<channel id="battery-soc" typeId="system.battery-level"/>
|
||||
<channel id="battery-dc-voltage" typeId="system.electric-voltage">
|
||||
<label>Battery Voltage</label>
|
||||
<description>Measured voltage of the battery.</description>
|
||||
</channel>
|
||||
<channel id="battery-dc-current" typeId="system.electric-current">
|
||||
<label>Battery Current</label>
|
||||
<description>Measured current of the battery.</description>
|
||||
</channel>
|
||||
<channel id="battery-dc-power" typeId="system.electric-power">
|
||||
<label>Battery Power</label>
|
||||
<description>Measured power of the battery.</description>
|
||||
</channel>
|
||||
<channel id="battery-temperature" typeId="system.indoor-temperature">
|
||||
<label>Battery Temperature</label>
|
||||
<description>Temperature of the battery reported by the BMS.</description>
|
||||
</channel>
|
||||
<channel id="inverter-ac-temperature" typeId="system.indoor-temperature">
|
||||
<label>Inverter AC Temperature</label>
|
||||
<description>Temperature of the inverter ac side.</description>
|
||||
</channel>
|
||||
<channel id="inverter-dc-temperature" typeId="system.indoor-temperature">
|
||||
<label>Inverter DC Temperature</label>
|
||||
<description>Temperature of the inverter dc side.</description>
|
||||
</channel>
|
||||
<channel id="inverter-grid-power" typeId="system.electric-power">
|
||||
<label>Grid Power</label>
|
||||
<description>Grid power import/export.</description>
|
||||
</channel>
|
||||
<channel id="inverter-grid-voltage" typeId="system.electric-voltage">
|
||||
<label>Grid Voltage</label>
|
||||
<description>Measured voltage of the grid.</description>
|
||||
</channel>
|
||||
<channel id="inverter-grid-current" typeId="system.electric-current">
|
||||
<label>Grid Current</label>
|
||||
<description>Measured current of the grid.</description>
|
||||
</channel>
|
||||
<channel id="inverter-solar-energy-today" typeId="system.electric-energy">
|
||||
<label>Solar Energy Today</label>
|
||||
<description>Solar energy generted today.</description>
|
||||
</channel>
|
||||
<channel id="inverter-solar-energy-total" typeId="system.electric-energy">
|
||||
<label>Solar Energy Total</label>
|
||||
<description>Total solar energy generted.</description>
|
||||
</channel>
|
||||
<channel id="inverter-solar-power-now" typeId="system.electric-current">
|
||||
<label>Solar Power</label>
|
||||
<description>Solar power being generted.</description>
|
||||
</channel>
|
||||
<channel id="inverter-control-timer" typeId="control-timer"/>
|
||||
<channel id="inverter-control-energy-pattern" typeId="control-pattern"/>
|
||||
<channel id="inverter-control-work-mode" typeId="control-work-mode"/>
|
||||
</channels>
|
||||
|
||||
<properties>
|
||||
<property name="vendor">SunSynk</property>
|
||||
</properties>
|
||||
<representation-property>serialnumber</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="serialnumber" type="text" required="true">
|
||||
<label>Inverter Serial Number</label>
|
||||
<description>Serial number of the inverter from Sun Synk Connect.</description>
|
||||
</parameter>
|
||||
<parameter name="alias" type="text" required="true">
|
||||
<label>Inverter Name</label>
|
||||
<description>Name of inverter from Sun Synk Connect.</description>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" required="true">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Time in seconds to retrieve status from Sun Synk Connect services. Greater than 60 seconds.</description>
|
||||
<default>60</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="grid-time" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Grid Charge Time</label>
|
||||
<description>"Grid charging interval start time. Use 24hr time. 00:00 to 23:55 are valid in 5 min increments with
|
||||
leading zero on the hour and minute. Interval times must be in ascending order."</description>
|
||||
<state readOnly="false" pattern="%1$tH:%1$tM"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="grid-charge" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Grid Charge</label>
|
||||
<description>Charge the inverter battery from the grid during this interval.</description>
|
||||
<state readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="gen-charge" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Generator (AUX) Charge</label>
|
||||
<description>Charge the inverter battery from the generator (auxilary) during this interval.</description>
|
||||
<state readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="battery-target" advanced="true">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Target Charge Level</label>
|
||||
<description>The desired charge level of the battery (%).</description>
|
||||
<category>Battery</category>
|
||||
<state min="0" max="100" step="1" pattern="%d %%" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="power-charge-limit" advanced="true">
|
||||
<item-type>Number:Power</item-type>
|
||||
<label>Maximum Charge Rate</label>
|
||||
<description>maximum charge power desired (limited by inverter capability).</description>
|
||||
<category>Inverter</category>
|
||||
<state pattern="%d %unit%" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="control-timer" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>System Timer</label>
|
||||
<description>Use the system mode timer to control battery charge discharge.</description>
|
||||
<state readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="control-pattern" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>System Energy Pattern</label>
|
||||
<description>Set the system mode energy pattern to '0' Priority Battery or '1' Priority Load.</description>
|
||||
<command>
|
||||
<options>
|
||||
<option value="0">Priority Battery</option>
|
||||
<option value="1">Priority Load</option>
|
||||
</options>
|
||||
</command>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="control-work-mode" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>System Work Mode</label>
|
||||
<description>Set the work mode to '0' Selling First; '1' Zero-Export + Limted to Load or '2' Limited to Home.</description>
|
||||
<command>
|
||||
<options>
|
||||
<option value="0">Selling First</option>
|
||||
<option value="1">"Zero-Export + Limted to Load"</option>
|
||||
<option value="2">Limited to Home</option>
|
||||
</options>
|
||||
</command>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -396,6 +396,7 @@
|
||||
<module>org.openhab.binding.speedtest</module>
|
||||
<module>org.openhab.binding.spotify</module>
|
||||
<module>org.openhab.binding.squeezebox</module>
|
||||
<module>org.openhab.binding.sunsynk</module>
|
||||
<module>org.openhab.binding.surepetcare</module>
|
||||
<module>org.openhab.binding.synopanalyzer</module>
|
||||
<module>org.openhab.binding.systeminfo</module>
|
||||
|
Loading…
Reference in New Issue
Block a user