mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 07:02:02 +01:00
[solax] Initial contribution (#14880)
Signed-off-by: Konstantin Polihronov <polychronov@gmail.com>
This commit is contained in:
parent
ab135421a0
commit
17978b8625
@ -324,6 +324,7 @@
|
||||
/bundles/org.openhab.binding.solarlog/ @johannrichard
|
||||
/bundles/org.openhab.binding.solarmax/ @jamietownsend
|
||||
/bundles/org.openhab.binding.solarwatt/ @sven-carstens
|
||||
/bundles/org.openhab.binding.solax/ @theater
|
||||
/bundles/org.openhab.binding.somfymylink/ @loungeflyz
|
||||
/bundles/org.openhab.binding.somfytahoma/ @octa22
|
||||
/bundles/org.openhab.binding.somneo/ @0x4d4d
|
||||
|
@ -1606,6 +1606,11 @@
|
||||
<artifactId>org.openhab.binding.solarwatt</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.solax</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.somfymylink</artifactId>
|
||||
|
13
bundles/org.openhab.binding.solax/NOTICE
Normal file
13
bundles/org.openhab.binding.solax/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
|
189
bundles/org.openhab.binding.solax/README.md
Normal file
189
bundles/org.openhab.binding.solax/README.md
Normal file
@ -0,0 +1,189 @@
|
||||
# Solax Binding
|
||||
|
||||
This is a binding for Solax solar power inverters.
|
||||
|
||||
Solax Wi-Fi module with direct connection via HTTP is supported.
|
||||
Wi-Fi module firmware version 3.x+ is required.
|
||||
Please note that earlier firmware releases do not support direct connection, therefore the binding will not work in its current state.
|
||||
|
||||
The binding retrieves a structured data from the inverter's Wi-Fi module, parses it and pushes it into the inverter Thing where each channel represents a specific information (inverter output power, voltage, PV1 power, etc.)
|
||||
|
||||
In case the parsed information that comes with the binding out of the box differs, the raw data channel can be used with a combination of JSON Path transformation to map the proper values to the necessary items.
|
||||
|
||||
## Supported Things
|
||||
|
||||
| Thing | Thing Type | Description |
|
||||
|------------------------|------------|-------------------------------------------------------------------------------------|
|
||||
| local-connect-inverter | Thing | This is model representation of inverter with all the data available as a channels |
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
### Local Connect Inverter Configuration
|
||||
|
||||
| Parameter | Description |
|
||||
|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| refreshInterval | Defines the refresh interval when the binding polls from the inverter's Wi-Fi module (in seconds). Optional parameter. Default 10 seconds. |
|
||||
| password | Password for accessing the Wi-Fi module (the serial number of the wifi). Mandatory parameter. |
|
||||
| hostname | IP address or hostname of your Wi-Fi module. If hostname is used must be resolvable by OpenHAB. Mandatory parameter. |
|
||||
|
||||
### Inverter Output Channels
|
||||
|
||||
| Channel | Type | Description |
|
||||
|--------------------------|----------------------------|--------------------------------------------------|
|
||||
| inverter-output-power | Number:Power | The output power of the inverter [W] |
|
||||
| inverter-current | Number:ElectricCurrent | The output current of the inverter [A] |
|
||||
| inverter-voltage | Number:ElectricPotential | The output voltage of the inverter [V] |
|
||||
| inverter-frequency | Number:Frequency | The frequency of the output voltage [Hz] |
|
||||
|
||||
### Photovoltaic Panels Production Channels
|
||||
|
||||
| Channel | Type | Description |
|
||||
|--------------------------|----------------------------|-------------------------------------------------|
|
||||
| pv1-voltage | Number:ElectricPotential | The voltage of PV1 string [V] |
|
||||
| pv2-voltage | Number:ElectricPotential | The voltage of PV2 string [V] |
|
||||
| pv1-current | Number:ElectricCurrent | The current of PV1 string [A] |
|
||||
| pv2-current | Number:ElectricCurrent | The current of PV2 string [A] |
|
||||
| pv1-power | Number:Power | The output power PV1 string [W] |
|
||||
| pv2-power | Number:Power | The output power PV2 string [W] |
|
||||
| pv-total-power | Number:Power | The total output power of both PV strings [W] |
|
||||
| pv-total-current | Number:ElectricCurrent | The total current of both PV strings [A] |
|
||||
|
||||
### Battery channels
|
||||
|
||||
| Channel | Type | Description |
|
||||
|---------------------------|----------------------------|------------------------------------------------------------------------------------------------|
|
||||
| battery-power | Number:Power | The power to / from battery (negative means power is pulled from battery and vice-versa) [W] |
|
||||
| battery-current | Number:ElectricCurrent | The current to / from battery (negative means power is pulled from battery and vice-versa) [A] |
|
||||
| battery-voltage | Number:ElectricPotential | The voltage of the battery [V] |
|
||||
| battery-temperature | Number:Temperature | The temperature of the battery [C/F] |
|
||||
| battery-state-of-charge | Number | The state of charge of the battery [%] |
|
||||
|
||||
### Grid related channels
|
||||
|
||||
| Channel | Type | Description |
|
||||
|--------------------------|----------------------------|------------------------------------------------------------------------------------------------|
|
||||
| feed-in-power | Number:Power | The power to / from grid (negative means power is pulled from the grid and vice-versa) [W] |
|
||||
|
||||
### General channels
|
||||
|
||||
| Channel | Type | Description |
|
||||
|--------------------------|----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| last-update-time | DateTime | Last time when a call has been made to the inverter |
|
||||
| raw-data | String | The raw data retrieved from inverter in JSON format. (Usable for channels not implemented. Can be consumed with the JSONpath transformation |
|
||||
|
||||
### Properties
|
||||
|
||||
| Property | Description |
|
||||
|-------------------|-------------------------------------------|
|
||||
| serialNumber | The serial number of the Wi-Fi module |
|
||||
| inverterType | Inverter Type (for example X1_HYBRID_G4) |
|
||||
|
||||
## Full Example
|
||||
|
||||
Here are some file based examples.
|
||||
|
||||
### Thing Configuration
|
||||
|
||||
```java
|
||||
// The local connect inverter thing
|
||||
Thing solax:local-connect-inverter:localInverter [ refreshInterval=10, password="<SERIAL NUMBER OF THE WIFI MODULE>", hostname="<local IP/hostname in the network>" ]
|
||||
```
|
||||
|
||||
### Item Configuration
|
||||
|
||||
```java
|
||||
Group gSolaxInverter "Solax Inverter" <energy> (boilerRoom)
|
||||
Group solarPanels "Solar panels" <energy> (gSolaxInverter)
|
||||
|
||||
Number solaxPowerWest "West [%.0f W]" <solarplant> (gsolax_inverter,EveryChangePersist,solarPanels){ channel="solax:localConnectInverter:localInverter:pv1-power" }
|
||||
Number solaxPowerEast "East [%.0f W]" <solarplant> (gsolax_inverter,EveryChangePersist,solarPanels){ channel="solax:localConnectInverter:localInverter:pv2-power" }
|
||||
Number solaxBatteryPower "Battery power [%.0f W]" <energy> (gsolax_inverter,EveryChangePersist) { channel="solax:localConnectInverter:localInverter:battery-power" }
|
||||
Number solaxBatterySoc "Battery SoC [%.0f %%]" <batterylevel> (gsolax_inverter,EveryChangePersist) { channel="solax:localConnectInverter:localInverter:battery-state-of-charge" }
|
||||
|
||||
Number solaxFeedInPower "Feed-in power (CEZ) [%.0f W]" <energy> (gsolax_inverter,EveryChangePersist) { channel="solax:localConnectInverter:localInverter:feed-in-power" }
|
||||
Number solaxAcPower "Invertor output power [%.0f W]" <energy> (gsolax_inverter,EveryChangePersist){ channel="solax:localConnectInverter:localInverter:inverter-output-power" }
|
||||
|
||||
String solaxInverterType "Inverter Type [%s]" <energy> (gsolax_inverter) { channel="solax:localConnectInverter:localInverter:inverter-type"}
|
||||
String solaxUploadTime "Last update time [%s]" <calendar> (gsolax_inverter) { channel="solax:localConnectInverter:localInverter:last-update-time" }
|
||||
String solaxRawData "Raw data [%s]" <data> (gsolax_inverter) { channel="solax:localConnectInverter:localInverter:raw-data" }
|
||||
```
|
||||
|
||||
### Sitemap Configuration
|
||||
|
||||
```perl
|
||||
Frame label="Solar power strings" {
|
||||
Text item=solaxPowerEast valuecolor=[<=30="gray",<=300="red", <1500="orange", >=1500="green"] {
|
||||
Text item=solaxPowerEast icon="energy" valuecolor=[<=30="gray",<=300="red", <1500="orange", >=1500="green"]
|
||||
Text item=solaxPowerWest icon="energy" valuecolor=[<=30="gray",<=300="red", <1500="orange", >=1500="green"]
|
||||
Switch item=Chart_Period label="Chart Period" mappings=[0="H", 1="D", 2="W", 3="M", 4="Y"]
|
||||
Chart item=solarPanels period=h refresh=600 visibility=[Chart_Period==0]
|
||||
Chart item=solarPanels period=D refresh=3600 visibility=[Chart_Period==1]
|
||||
Chart item=solarPanels period=W refresh=3600 visibility=[Chart_Period==2, Chart_Period==Uninitialized]
|
||||
Chart item=solarPanels period=M refresh=3600 visibility=[Chart_Period==3]
|
||||
Chart item=solarPanels period=Y refresh=3600 visibility=[Chart_Period==4]
|
||||
}
|
||||
Text item=solaxPowerWest valuecolor=[<=30="gray",<=300="red", <1500="orange", >=1500="green"] {
|
||||
Text item=solaxPowerEast icon="energy" valuecolor=[<=30="gray",<=300="red", <1500="orange", >=1500="green"]
|
||||
Text item=solaxPowerWest icon="energy" valuecolor=[<=30="gray",<=300="red", <1500="orange", >=1500="green"]
|
||||
Switch item=Chart_Period label="Chart Period" mappings=[0="H", 1="D", 2="W", 3="M", 4="Y"]
|
||||
Chart item=solarPanels period=h refresh=600 visibility=[Chart_Period==0]
|
||||
Chart item=solarPanels period=D refresh=3600 visibility=[Chart_Period==1]
|
||||
Chart item=solarPanels period=W refresh=3600 visibility=[Chart_Period==2, Chart_Period==Uninitialized]
|
||||
Chart item=solarPanels period=M refresh=3600 visibility=[Chart_Period==3]
|
||||
Chart item=solarPanels period=Y refresh=3600 visibility=[Chart_Period==4]
|
||||
}
|
||||
Text item=solaxGenerationTotal valuecolor=[<=100="gray",<=500="red", <2000="orange", >=2000="green"] {
|
||||
Text item=solaxPowerEast icon="energy" valuecolor=[<=30="gray",<=300="red", <1500="orange", >=1500="green"]
|
||||
Text item=solaxPowerWest icon="energy" valuecolor=[<=30="gray",<=300="red", <1500="orange", >=1500="green"]
|
||||
Text item=solaxGenerationTotal icon="energy" valuecolor=[<=30="gray",<=300="red", <1500="orange", >=1500="green"]
|
||||
Switch item=Chart_Period label="Chart Period" mappings=[0="H", 1="D", 2="W", 3="M", 4="Y"]
|
||||
Chart item=solarPanels period=h refresh=600 visibility=[Chart_Period==0]
|
||||
Chart item=solarPanels period=D refresh=3600 visibility=[Chart_Period==1]
|
||||
Chart item=solarPanels period=W refresh=3600 visibility=[Chart_Period==2, Chart_Period==Uninitialized]
|
||||
Chart item=solarPanels period=M refresh=3600 visibility=[Chart_Period==3]
|
||||
Chart item=solarPanels period=Y refresh=3600 visibility=[Chart_Period==4]
|
||||
}
|
||||
}
|
||||
Frame label="Consumption" {
|
||||
Text item=solaxAcPower valuecolor=[<=30="gray", <800="green", <1500="orange", >=1500="red"] {
|
||||
Switch item=Chart_Period label="Chart Period" mappings=[0="H", 1="D", 2="W", 3="M", 4="Y"]
|
||||
Text item=solaxAcPower icon="energy" valuecolor=[<=30="gray", <800="green", <1500="orange", >=1500="red"]
|
||||
Chart item=solaxAcPower period=h refresh=600 visibility=[Chart_Period==0]
|
||||
Chart item=solaxAcPower period=D refresh=3600 visibility=[Chart_Period==1]
|
||||
Chart item=solaxAcPower period=W refresh=3600 visibility=[Chart_Period==2, Chart_Period==Uninitialized]
|
||||
Chart item=solaxAcPower period=M refresh=3600 visibility=[Chart_Period==3]
|
||||
Chart item=solaxAcPower period=Y refresh=3600 visibility=[Chart_Period==4]
|
||||
}
|
||||
Text item=solaxFeedInPower valuecolor=[<=30="gray", <800="green", <1500="orange", >=1500="red"] {
|
||||
Switch item=Chart_Period label="Chart Period" mappings=[0="H", 1="D", 2="W", 3="M", 4="Y"]
|
||||
Text item=solaxFeedInPower icon="energy" valuecolor=[<=30="gray", <800="green", <1500="orange", >=1500="red"]
|
||||
Chart item=solaxFeedInPower period=h refresh=600 visibility=[Chart_Period==0]
|
||||
Chart item=solaxFeedInPower period=D refresh=3600 visibility=[Chart_Period==1]
|
||||
Chart item=solaxFeedInPower period=W refresh=3600 visibility=[Chart_Period==2, Chart_Period==Uninitialized]
|
||||
Chart item=solaxFeedInPower period=M refresh=3600 visibility=[Chart_Period==3]
|
||||
Chart item=solaxFeedInPower period=Y refresh=3600 visibility=[Chart_Period==4]
|
||||
}
|
||||
}
|
||||
Frame label="Battery" {
|
||||
Text item=solaxBatteryPower valuecolor=[<=-500="red", <0="orange", ==0="gray", >0="green"] {
|
||||
Switch item=Chart_Period label="Chart Period" mappings=[0="H", 1="D", 2="W", 3="M", 4="Y"]
|
||||
Text item=solaxBatteryPower icon="energy" valuecolor=[<-800="red", <0="orange", ==0="gray", >=0="green"]
|
||||
Chart item=solaxBatteryPower period=h refresh=600 visibility=[Chart_Period==0]
|
||||
Chart item=solaxBatteryPower period=D refresh=3600 visibility=[Chart_Period==1]
|
||||
Chart item=solaxBatteryPower period=W refresh=3600 visibility=[Chart_Period==2, Chart_Period==Uninitialized]
|
||||
Chart item=solaxBatteryPower period=M refresh=3600 visibility=[Chart_Period==3]
|
||||
Chart item=solaxBatteryPower period=Y refresh=3600 visibility=[Chart_Period==4]
|
||||
}
|
||||
Text item=solaxBatterySoc valuecolor=[<=30="red", <50="orange", >=50="green"] {
|
||||
Switch item=Chart_Period label="Chart Period" mappings=[0="H", 1="D", 2="W", 3="M", 4="Y"]
|
||||
Text item=solaxBatterySoc valuecolor=[<=30="red", <50="orange", >=50="green"]
|
||||
Chart item=solaxBatterySoc period=h refresh=600 visibility=[Chart_Period==0]
|
||||
Chart item=solaxBatterySoc period=D refresh=3600 visibility=[Chart_Period==1]
|
||||
Chart item=solaxBatterySoc period=W refresh=3600 visibility=[Chart_Period==2, Chart_Period==Uninitialized]
|
||||
Chart item=solaxBatterySoc period=M refresh=3600 visibility=[Chart_Period==3]
|
||||
Chart item=solaxBatterySoc period=Y refresh=3600 visibility=[Chart_Period==4]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
17
bundles/org.openhab.binding.solax/pom.xml
Normal file
17
bundles/org.openhab.binding.solax/pom.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 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.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.solax</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Solax Binding</name>
|
||||
|
||||
</project>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.solax-${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-solax" description="solax Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.solax/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.solax.internal;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link SolaxBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SolaxBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "solax";
|
||||
private static final String THING_LOCAL_CONNECT_INVERTER_ID = "local-connect-inverter";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_LOCAL_CONNECT_INVERTER = new ThingTypeUID(BINDING_ID,
|
||||
THING_LOCAL_CONNECT_INVERTER_ID);
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_LOCAL_CONNECT_INVERTER);
|
||||
|
||||
// List of properties
|
||||
public static final String PROPERTY_INVERTER_TYPE = "inverterType";
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String INVERTER_OUTPUT_POWER = "inverter-output-power";
|
||||
public static final String INVERTER_OUTPUT_CURRENT = "inverter-current";
|
||||
public static final String INVERTER_OUTPUT_VOLTAGE = "inverter-voltage";
|
||||
public static final String INVERTER_OUTPUT_FREQUENCY = "inverter-frequency";
|
||||
|
||||
public static final String INVERTER_PV1_POWER = "pv1-power";
|
||||
public static final String INVERTER_PV1_VOLTAGE = "pv1-voltage";
|
||||
public static final String INVERTER_PV1_CURRENT = "pv1-current";
|
||||
|
||||
public static final String INVERTER_PV2_POWER = "pv2-power";
|
||||
public static final String INVERTER_PV2_VOLTAGE = "pv2-voltage";
|
||||
public static final String INVERTER_PV2_CURRENT = "pv2-current";
|
||||
|
||||
public static final String INVERTER_PV_TOTAL_POWER = "pv-total-power";
|
||||
public static final String INVERTER_PV_TOTAL_CURRENT = "pv-total-current";
|
||||
|
||||
public static final String BATTERY_POWER = "battery-power";
|
||||
public static final String BATTERY_VOLTAGE = "battery-voltage";
|
||||
public static final String BATTERY_CURRENT = "battery-current";
|
||||
public static final String BATTERY_TEMPERATURE = "battery-temperature";
|
||||
public static final String BATTERY_STATE_OF_CHARGE = "battery-level";
|
||||
|
||||
public static final String FEED_IN_POWER = "feed-in-power";
|
||||
|
||||
public static final String TIMESTAMP = "last-update-time";
|
||||
public static final String RAW_DATA = "raw-data";
|
||||
|
||||
// I18N Keys
|
||||
protected static final String I18N_KEY_OFFLINE_COMMUNICATION_ERROR_JSON_CANNOT_BE_RETRIEVED = "@text/offline.communication-error.json-cannot-be-retrieved";
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.solax.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link SolaxConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SolaxConfiguration {
|
||||
|
||||
public String hostname = "";
|
||||
public String password = "";
|
||||
public int refreshInterval = 10;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.solax.internal;
|
||||
|
||||
import static org.openhab.binding.solax.internal.SolaxBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* The {@link SolaxHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.solax", service = ThingHandlerFactory.class)
|
||||
public class SolaxHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
if (THING_TYPE_LOCAL_CONNECT_INVERTER.equals(thingTypeUID)) {
|
||||
return new SolaxLocalAccessHandler(thing);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.solax.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.ZonedDateTime;
|
||||
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.solax.internal.connectivity.LocalHttpConnector;
|
||||
import org.openhab.binding.solax.internal.connectivity.rawdata.LocalConnectRawDataBean;
|
||||
import org.openhab.binding.solax.internal.model.InverterData;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
/**
|
||||
* The {@link SolaxLocalAccessHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SolaxLocalAccessHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SolaxLocalAccessHandler.class);
|
||||
|
||||
private static final int INITIAL_SCHEDULE_DELAY_SECONDS = 5;
|
||||
|
||||
private @NonNullByDefault({}) LocalHttpConnector localHttpConnector;
|
||||
|
||||
private @Nullable ScheduledFuture<?> schedule;
|
||||
|
||||
public SolaxLocalAccessHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
SolaxConfiguration config = getConfigAs(SolaxConfiguration.class);
|
||||
localHttpConnector = new LocalHttpConnector(config.password, config.hostname);
|
||||
int refreshInterval = config.refreshInterval;
|
||||
TimeUnit timeUnit = TimeUnit.SECONDS;
|
||||
|
||||
logger.debug("Scheduling regular interval retrieval every {} {}", refreshInterval, timeUnit);
|
||||
schedule = scheduler.scheduleWithFixedDelay(this::retrieveData, INITIAL_SCHEDULE_DELAY_SECONDS, refreshInterval,
|
||||
timeUnit);
|
||||
}
|
||||
|
||||
private void retrieveData() {
|
||||
try {
|
||||
String rawJsonData = localHttpConnector.retrieveData();
|
||||
logger.debug("Raw data retrieved = {}", rawJsonData);
|
||||
|
||||
if (rawJsonData != null && !rawJsonData.isEmpty()) {
|
||||
updateData(rawJsonData);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
SolaxBindingConstants.I18N_KEY_OFFLINE_COMMUNICATION_ERROR_JSON_CANNOT_BE_RETRIEVED);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.debug("Exception received while attempting to retrieve data via HTTP", e);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateData(String rawJsonData) {
|
||||
try {
|
||||
LocalConnectRawDataBean inverterParsedData = parseJson(rawJsonData);
|
||||
updateThing(inverterParsedData);
|
||||
} catch (JsonParseException e) {
|
||||
logger.debug("Unable to deserialize from JSON.", e);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateThing(LocalConnectRawDataBean inverterParsedData) {
|
||||
transferInverterDataToChannels(inverterParsedData);
|
||||
|
||||
if (getThing().getStatus() != ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
}
|
||||
|
||||
private LocalConnectRawDataBean parseJson(String rawJsonData) {
|
||||
LocalConnectRawDataBean inverterParsedData = LocalConnectRawDataBean.fromJson(rawJsonData);
|
||||
logger.debug("Received a new inverter data object. Data = {}", inverterParsedData.toStringDetailed());
|
||||
return inverterParsedData;
|
||||
}
|
||||
|
||||
private void transferInverterDataToChannels(InverterData data) {
|
||||
updateProperty(Thing.PROPERTY_SERIAL_NUMBER, data.getWifiSerial());
|
||||
updateProperty(SolaxBindingConstants.PROPERTY_INVERTER_TYPE, data.getInverterType().name());
|
||||
|
||||
updateState(SolaxBindingConstants.INVERTER_OUTPUT_POWER,
|
||||
new QuantityType<>(data.getInverterOutputPower(), Units.WATT));
|
||||
updateState(SolaxBindingConstants.INVERTER_OUTPUT_CURRENT,
|
||||
new QuantityType<>(data.getInverterCurrent(), Units.AMPERE));
|
||||
updateState(SolaxBindingConstants.INVERTER_OUTPUT_VOLTAGE,
|
||||
new QuantityType<>(data.getInverterVoltage(), Units.VOLT));
|
||||
updateState(SolaxBindingConstants.INVERTER_OUTPUT_FREQUENCY,
|
||||
new QuantityType<>(data.getInverterFrequency(), Units.HERTZ));
|
||||
|
||||
updateState(SolaxBindingConstants.INVERTER_PV1_POWER, new QuantityType<>(data.getPV1Power(), Units.WATT));
|
||||
updateState(SolaxBindingConstants.INVERTER_PV1_CURRENT, new QuantityType<>(data.getPV1Current(), Units.AMPERE));
|
||||
updateState(SolaxBindingConstants.INVERTER_PV1_VOLTAGE, new QuantityType<>(data.getPV1Voltage(), Units.VOLT));
|
||||
|
||||
updateState(SolaxBindingConstants.INVERTER_PV2_POWER, new QuantityType<>(data.getPV2Power(), Units.WATT));
|
||||
updateState(SolaxBindingConstants.INVERTER_PV2_CURRENT, new QuantityType<>(data.getPV2Current(), Units.AMPERE));
|
||||
updateState(SolaxBindingConstants.INVERTER_PV2_VOLTAGE, new QuantityType<>(data.getPV2Voltage(), Units.VOLT));
|
||||
|
||||
updateState(SolaxBindingConstants.INVERTER_PV_TOTAL_POWER,
|
||||
new QuantityType<>(data.getPVTotalPower(), Units.WATT));
|
||||
updateState(SolaxBindingConstants.INVERTER_PV_TOTAL_CURRENT,
|
||||
new QuantityType<>(data.getPVTotalCurrent(), Units.AMPERE));
|
||||
|
||||
updateState(SolaxBindingConstants.BATTERY_POWER, new QuantityType<>(data.getBatteryPower(), Units.WATT));
|
||||
updateState(SolaxBindingConstants.BATTERY_CURRENT, new QuantityType<>(data.getBatteryCurrent(), Units.AMPERE));
|
||||
updateState(SolaxBindingConstants.BATTERY_VOLTAGE, new QuantityType<>(data.getBatteryVoltage(), Units.VOLT));
|
||||
updateState(SolaxBindingConstants.BATTERY_TEMPERATURE,
|
||||
new QuantityType<>(data.getBatteryTemperature(), SIUnits.CELSIUS));
|
||||
updateState(SolaxBindingConstants.BATTERY_STATE_OF_CHARGE,
|
||||
new QuantityType<>(data.getBatterySoC(), Units.PERCENT));
|
||||
|
||||
updateState(SolaxBindingConstants.FEED_IN_POWER, new QuantityType<>(data.getFeedInPower(), Units.WATT));
|
||||
|
||||
updateState(SolaxBindingConstants.TIMESTAMP, new DateTimeType(ZonedDateTime.now()));
|
||||
updateState(SolaxBindingConstants.RAW_DATA, new StringType(data.getRawData()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
// Nothing to do here as of now. Maybe implement a REFRESH command in the future.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
ScheduledFuture<?> schedule = this.schedule;
|
||||
if (schedule != null) {
|
||||
schedule.cancel(true);
|
||||
this.schedule = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.solax.internal.connectivity;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link LocalHttpConnector} class uses HttpUtil to retrieve the raw JSON data from Inverter's Wi-Fi module.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LocalHttpConnector implements SolaxConnector {
|
||||
|
||||
private static final int HTTP_REQUEST_TIME_OUT = 5000;
|
||||
|
||||
private static final String CONTENT_TYPE = "text/html; charset=utf-8";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LocalHttpConnector.class);
|
||||
|
||||
private static final String OPT_TYPE = "optType";
|
||||
private static final String READ_REALTIME_DATA = "ReadRealTimeData";
|
||||
|
||||
private static final String PASSWORD = "pwd";
|
||||
// The serial number of the Wifi dongle is the password for the connection (default)
|
||||
private String passwordValue;
|
||||
private String uri;
|
||||
|
||||
public LocalHttpConnector(String passwordValue, String host) {
|
||||
this.passwordValue = passwordValue;
|
||||
this.uri = "http://" + host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String retrieveData() throws IOException {
|
||||
String requestBody = createRequestBody();
|
||||
logger.trace("Uri: {}, Request body: {}", uri, requestBody);
|
||||
String result = HttpUtil.executeUrl(HttpMethod.POST.name(), uri,
|
||||
new ByteArrayInputStream(requestBody.getBytes(StandardCharsets.UTF_8)), CONTENT_TYPE,
|
||||
HTTP_REQUEST_TIME_OUT);
|
||||
logger.trace("Retrieved content = {}", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private String createRequestBody() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(OPT_TYPE).append("=").append(READ_REALTIME_DATA);
|
||||
sb.append("&");
|
||||
sb.append(PASSWORD).append("=").append(passwordValue);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.solax.internal.connectivity;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link SolaxConnector} is interface for connecting to the Solax endpoints (cloud API or local IP)
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface SolaxConnector {
|
||||
|
||||
@Nullable
|
||||
String retrieveData() throws IOException;
|
||||
}
|
@ -0,0 +1,255 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.solax.internal.connectivity.rawdata;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solax.internal.model.InverterData;
|
||||
import org.openhab.binding.solax.internal.model.InverterType;
|
||||
import org.openhab.binding.solax.internal.util.GsonSupplier;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link LocalConnectRawDataBean} collects the raw data and the specific implementation to return the parsed data.
|
||||
* If there are differences between the inverters probably would be wise to split the parsing in seprate class(es)
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LocalConnectRawDataBean implements RawDataBean, InverterData {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LocalConnectRawDataBean.class);
|
||||
|
||||
private @Nullable String sn;
|
||||
private @Nullable String ver;
|
||||
private int type;
|
||||
@SerializedName("Data")
|
||||
private short @Nullable [] data;
|
||||
@SerializedName("Information")
|
||||
private String @Nullable [] information;
|
||||
private @Nullable String rawData;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LocalConnectRawDataBean [sn=" + sn + ", ver=" + ver + ", type=" + type + ", Information="
|
||||
+ Arrays.toString(information) + ", Data=" + Arrays.toString(data) + "]";
|
||||
}
|
||||
|
||||
public @Nullable String getSn() {
|
||||
return sn;
|
||||
}
|
||||
|
||||
public void setSn(@Nullable String sn) {
|
||||
this.sn = sn;
|
||||
}
|
||||
|
||||
public @Nullable String getVer() {
|
||||
return ver;
|
||||
}
|
||||
|
||||
public void setVer(@Nullable String ver) {
|
||||
this.ver = ver;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public short @Nullable [] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(short @Nullable [] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public String @Nullable [] getInformation() {
|
||||
return information;
|
||||
}
|
||||
|
||||
public void setInformation(String @Nullable [] information) {
|
||||
this.information = information;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getRawData() {
|
||||
return rawData;
|
||||
}
|
||||
|
||||
public void setRawData(String rawData) {
|
||||
this.rawData = rawData;
|
||||
}
|
||||
|
||||
public static LocalConnectRawDataBean fromJson(String json) {
|
||||
if (json.isEmpty()) {
|
||||
throw new IllegalArgumentException("JSON payload should not be empty");
|
||||
}
|
||||
|
||||
Gson gson = GsonSupplier.getInstance();
|
||||
LocalConnectRawDataBean deserializedObject = gson.fromJson(json, LocalConnectRawDataBean.class);
|
||||
if (deserializedObject == null) {
|
||||
throw new IllegalStateException("Unexpected null result when deserializing JSON");
|
||||
}
|
||||
deserializedObject.setRawData(json);
|
||||
return deserializedObject;
|
||||
}
|
||||
|
||||
// Parsed inverter data interface implementation starts here
|
||||
|
||||
@Override
|
||||
public @Nullable String getWifiSerial() {
|
||||
return getSn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getWifiVersion() {
|
||||
return getVer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InverterType getInverterType() {
|
||||
return InverterType.fromIndex(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getInverterVoltage() {
|
||||
return (short) (getData(0) / 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getInverterCurrent() {
|
||||
return (short) (getData(1) / 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getInverterOutputPower() {
|
||||
return getData(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getInverterFrequency() {
|
||||
return (short) (getData(3) / 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getPV1Voltage() {
|
||||
return (short) (getData(4) / 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getPV1Current() {
|
||||
return (short) (getData(6) / 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getPV1Power() {
|
||||
return getData(8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getPV2Voltage() {
|
||||
return (short) (getData(5) / 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getPV2Current() {
|
||||
return (short) (getData(7) / 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getPV2Power() {
|
||||
return getData(9);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBatteryVoltage() {
|
||||
return (short) (getData(14) / 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBatteryCurrent() {
|
||||
return (short) (getData(15) / 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBatteryPower() {
|
||||
return getData(16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBatteryTemperature() {
|
||||
return getData(17);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBatterySoC() {
|
||||
return getData(18);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getOnGridTotalYield() {
|
||||
return packU16(11, 12) / 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getOnGridDailyYield() {
|
||||
return (short) (getData(13) / 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getFeedInPower() {
|
||||
return getData(32);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalFeedInEnergy() {
|
||||
return packU16(34, 35) / 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalConsumption() {
|
||||
return packU16(36, 37) / 100;
|
||||
}
|
||||
|
||||
private short getData(int index) {
|
||||
try {
|
||||
short[] dataArray = data;
|
||||
if (dataArray != null) {
|
||||
return dataArray[index];
|
||||
}
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
logger.debug("Tried to get data out of bounds of the raw data array.", e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long packU16(int indexMajor, int indexMinor) {
|
||||
short major = getData(indexMajor);
|
||||
short minor = getData(indexMinor);
|
||||
if (major == 0) {
|
||||
return minor;
|
||||
}
|
||||
|
||||
return ((major << 16) & 0xFFFF0000) | minor & 0xFFFF;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.solax.internal.connectivity.rawdata;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link RawDataBean} is interface which should be implemented by all types of raw information that is retrieved
|
||||
* (the idea is to retrieve a raw data from a Solax inverter locally or their cloud API)
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface RawDataBean {
|
||||
@Nullable
|
||||
String getRawData();
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.solax.internal.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solax.internal.connectivity.rawdata.RawDataBean;
|
||||
|
||||
/**
|
||||
* The {@link InverterData} interface should implement the interface that returns the parsed data in human readable code
|
||||
* and format.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface InverterData extends RawDataBean {
|
||||
@Nullable
|
||||
String getWifiSerial();
|
||||
|
||||
@Nullable
|
||||
String getWifiVersion();
|
||||
|
||||
InverterType getInverterType();
|
||||
|
||||
short getInverterVoltage();
|
||||
|
||||
short getInverterCurrent();
|
||||
|
||||
short getInverterOutputPower();
|
||||
|
||||
short getInverterFrequency();
|
||||
|
||||
short getPV1Voltage();
|
||||
|
||||
short getPV1Current();
|
||||
|
||||
short getPV1Power();
|
||||
|
||||
short getPV2Voltage();
|
||||
|
||||
short getPV2Current();
|
||||
|
||||
short getPV2Power();
|
||||
|
||||
default short getPVTotalPower() {
|
||||
return (short) (getPV1Power() + getPV2Power());
|
||||
}
|
||||
|
||||
default short getPVTotalCurrent() {
|
||||
return (short) (getPV1Current() + getPV2Current());
|
||||
}
|
||||
|
||||
short getBatteryVoltage(); // V / 100
|
||||
|
||||
short getBatteryCurrent(); // A / 100
|
||||
|
||||
short getBatteryPower(); // W
|
||||
|
||||
short getBatteryTemperature(); // temperature C
|
||||
|
||||
short getBatterySoC(); // % battery SoC
|
||||
|
||||
long getOnGridTotalYield(); // KWh total Yeld from the sun (to the grid?)
|
||||
|
||||
short getOnGridDailyYield(); // KWh daily Yeld from the sun (to the grid?)
|
||||
|
||||
long getTotalFeedInEnergy(); // KWh all times
|
||||
|
||||
long getTotalConsumption(); // KWh all times
|
||||
|
||||
short getFeedInPower();
|
||||
|
||||
default String toStringDetailed() {
|
||||
return "WifiSerial = " + getWifiSerial() + ", WifiVersion = " + getWifiVersion() + ", InverterType = "
|
||||
+ getInverterType() + ", InverterVoltage = " + getInverterVoltage() + "V, InverterCurrent = "
|
||||
+ getInverterCurrent() + "A, InverterPower = " + getInverterOutputPower() + "W, BatteryPower = "
|
||||
+ getBatteryPower() + "W, Battery SoC = " + getBatterySoC() + "%, FeedIn Power = " + getFeedInPower()
|
||||
+ "W, Total PV Power = " + (getPV1Power() + getPV2Power()) + "W, Total Consumption = "
|
||||
+ getTotalConsumption() + "kWh, Total Feed-in Energy = " + getTotalFeedInEnergy()
|
||||
+ "kWh, Total On-Grid Yield = " + getOnGridTotalYield() + "kWh.";
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.solax.internal.model;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link InverterType} class is enum representing the different inverter types with a simple logic to convert from
|
||||
* int(coming from the JSON) to a more meaningful enum value.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum InverterType {
|
||||
|
||||
X1_LX(1),
|
||||
X_HYBRID(2),
|
||||
X1_HYBRID_FIT(3),
|
||||
X1_BOOST_AIR_MINI(4),
|
||||
X3_HYBRID_FIT(5),
|
||||
X3_20K_30K(6),
|
||||
X3_MIC_PRO(7),
|
||||
X1_SMART(8),
|
||||
X1_AC(9),
|
||||
A1_HYBRID(10),
|
||||
A1_FIT(11),
|
||||
A1_GRID(12),
|
||||
J1_ESS(13),
|
||||
X3_HYBRID_G4(14),
|
||||
X1_HYBRID_G4(15),
|
||||
UNKNOWN(-1);
|
||||
|
||||
private int typeIndex;
|
||||
|
||||
InverterType(int typeIndex) {
|
||||
this.typeIndex = typeIndex;
|
||||
}
|
||||
|
||||
public static InverterType fromIndex(int index) {
|
||||
InverterType[] values = InverterType.values();
|
||||
return Stream.of(values).filter(value -> value.typeIndex == index).findFirst().orElse(UNKNOWN);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 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.solax.internal.util;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* The {@link GsonSupplier} provides a singleton instance of a Gson object
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GsonSupplier {
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
private GsonSupplier() {
|
||||
};
|
||||
|
||||
public static Gson getInstance() {
|
||||
return GSON;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<addon:addon id="solax" 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>Solax Binding</name>
|
||||
<description>This is the binding for Solax inverters.</description>
|
||||
<connection>local</connection>
|
||||
|
||||
</addon:addon>
|
@ -0,0 +1,67 @@
|
||||
# add-on
|
||||
|
||||
addon.solax.name = Solax Binding
|
||||
addon.solax.description = This is the binding for Solax inverters.
|
||||
|
||||
# thing types
|
||||
|
||||
thing-type.solax.local-connect-inverter.label = Local Connect Inverter
|
||||
thing-type.solax.local-connect-inverter.description = The inverter representation that supports local connections via HTTP
|
||||
thing-type.solax.local-connect-inverter.channel.battery-current.label = Battery Current
|
||||
thing-type.solax.local-connect-inverter.channel.battery-current.description = Electric current to/from the battery
|
||||
thing-type.solax.local-connect-inverter.channel.battery-level.label = Battery Level
|
||||
thing-type.solax.local-connect-inverter.channel.battery-level.description = The battery state of charge in percent
|
||||
thing-type.solax.local-connect-inverter.channel.battery-power.label = Battery Power
|
||||
thing-type.solax.local-connect-inverter.channel.battery-power.description = Power to/from the battery
|
||||
thing-type.solax.local-connect-inverter.channel.battery-temperature.label = Battery Temperature
|
||||
thing-type.solax.local-connect-inverter.channel.battery-temperature.description = Temperature of the battery
|
||||
thing-type.solax.local-connect-inverter.channel.battery-voltage.label = Battery Voltage
|
||||
thing-type.solax.local-connect-inverter.channel.battery-voltage.description = Electric voltage of the battery
|
||||
thing-type.solax.local-connect-inverter.channel.feed-in-power.label = Feed-in Power
|
||||
thing-type.solax.local-connect-inverter.channel.feed-in-power.description = Power to/from the electricity network.
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-current.label = Inverter Input/Output Current
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-current.description = Current to/from the inverter
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-output-power.label = Inverter Input/Output Power
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-output-power.description = Power to/from the inverter
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-voltage.label = Inverter Voltage
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-voltage.description = Voltage of the inverter
|
||||
thing-type.solax.local-connect-inverter.channel.pv-total-current.label = PV Total Current
|
||||
thing-type.solax.local-connect-inverter.channel.pv-total-current.description = The sum of PV currents from all strings
|
||||
thing-type.solax.local-connect-inverter.channel.pv-total-power.label = PV Total Power
|
||||
thing-type.solax.local-connect-inverter.channel.pv-total-power.description = The sum of PV powers from all strings
|
||||
thing-type.solax.local-connect-inverter.channel.pv1-current.label = PV 1 Current
|
||||
thing-type.solax.local-connect-inverter.channel.pv1-current.description = Electric current of PV String 1
|
||||
thing-type.solax.local-connect-inverter.channel.pv1-power.label = PV 1 Power
|
||||
thing-type.solax.local-connect-inverter.channel.pv1-power.description = Electric power of PV String 1
|
||||
thing-type.solax.local-connect-inverter.channel.pv1-voltage.label = PV 1 Voltage
|
||||
thing-type.solax.local-connect-inverter.channel.pv1-voltage.description = Electric voltage of PV String 1
|
||||
thing-type.solax.local-connect-inverter.channel.pv2-current.label = PV 2 Current
|
||||
thing-type.solax.local-connect-inverter.channel.pv2-current.description = Electric current of PV String 2
|
||||
thing-type.solax.local-connect-inverter.channel.pv2-power.label = PV 2 Power
|
||||
thing-type.solax.local-connect-inverter.channel.pv2-power.description = Electric power of PV String 2
|
||||
thing-type.solax.local-connect-inverter.channel.pv2-voltage.label = PV 2 Voltage
|
||||
thing-type.solax.local-connect-inverter.channel.pv2-voltage.description = Electric voltage of PV String 2
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.solax.local-connect-inverter.hostname.label = Network Address
|
||||
thing-type.config.solax.local-connect-inverter.hostname.description = IP address or the host name of the Wi-Fi module
|
||||
thing-type.config.solax.local-connect-inverter.password.label = Password
|
||||
thing-type.config.solax.local-connect-inverter.password.description = Password for accessing the Wi-Fi module (the serial number of the Wi-Fi module)
|
||||
thing-type.config.solax.local-connect-inverter.refreshInterval.label = Refresh Interval
|
||||
thing-type.config.solax.local-connect-inverter.refreshInterval.description = Specifies the refresh interval in seconds.
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.solax.battery-temperature.label = Battery Temperature
|
||||
channel-type.solax.battery-temperature.description = Battery Temperature
|
||||
channel-type.solax.frequency.label = Electric Frequency
|
||||
channel-type.solax.frequency.description = Frequency of the electricity to/from the inverter
|
||||
channel-type.solax.last-retrieve-time-stamp.label = Last Retrieve Time Stamp
|
||||
channel-type.solax.last-retrieve-time-stamp.description = Last time with a successful retrieval of data
|
||||
channel-type.solax.raw-data-type.label = Raw Data
|
||||
channel-type.solax.raw-data-type.description = The raw JSON data retrieved from the inverter's Wi-Fi module.
|
||||
|
||||
# thing status descriptions
|
||||
|
||||
offline.communication-error.json-cannot-be-retrieved = JSON data could not be retrieved.
|
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="solax"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<channel-type id="frequency">
|
||||
<item-type>Number:Frequency</item-type>
|
||||
<label>Electric Frequency</label>
|
||||
<description>Frequency of the electricity to/from the inverter</description>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Frequency</tag>
|
||||
</tags>
|
||||
<state pattern="%d %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="battery-temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Battery Temperature</label>
|
||||
<description>Battery Temperature</description>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Temperature</tag>
|
||||
</tags>
|
||||
<state pattern="%d %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="last-retrieve-time-stamp">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Last Retrieve Time Stamp</label>
|
||||
<description>Last time with a successful retrieval of data</description>
|
||||
<category>Time</category>
|
||||
<state pattern="yyyy-MM-dd HH:mm:ss" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="raw-data-type" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Raw Data</label>
|
||||
<description>The raw JSON data retrieved from the inverter's Wi-Fi module.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="solax"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<thing-type id="local-connect-inverter">
|
||||
|
||||
<label>Local Connect Inverter</label>
|
||||
<description>The inverter representation that supports local connections via HTTP</description>
|
||||
|
||||
<channels>
|
||||
<channel id="inverter-output-power" typeId="system.electric-power">
|
||||
<label>Inverter Input/Output Power</label>
|
||||
<description>Power to/from the inverter</description>
|
||||
</channel>
|
||||
<channel id="inverter-current" typeId="system.electric-current">
|
||||
<label>Inverter Input/Output Current</label>
|
||||
<description>Current to/from the inverter</description>
|
||||
</channel>
|
||||
<channel id="inverter-voltage" typeId="system.electric-voltage">
|
||||
<label>Inverter Voltage</label>
|
||||
<description>Voltage of the inverter</description>
|
||||
</channel>
|
||||
<channel id="inverter-frequency" typeId="frequency"/>
|
||||
|
||||
<channel id="pv1-voltage" typeId="system.electric-voltage">
|
||||
<label>PV 1 Voltage</label>
|
||||
<description>Electric voltage of PV String 1</description>
|
||||
</channel>
|
||||
<channel id="pv2-voltage" typeId="system.electric-voltage">
|
||||
<label>PV 2 Voltage</label>
|
||||
<description>Electric voltage of PV String 2</description>
|
||||
</channel>
|
||||
<channel id="pv1-current" typeId="system.electric-current">
|
||||
<label>PV 1 Current</label>
|
||||
<description>Electric current of PV String 1</description>
|
||||
</channel>
|
||||
<channel id="pv2-current" typeId="system.electric-current">
|
||||
<label>PV 2 Current</label>
|
||||
<description>Electric current of PV String 2</description>
|
||||
</channel>
|
||||
<channel id="pv1-power" typeId="system.electric-power">
|
||||
<label>PV 1 Power</label>
|
||||
<description>Electric power of PV String 1</description>
|
||||
</channel>
|
||||
<channel id="pv2-power" typeId="system.electric-power">
|
||||
<label>PV 2 Power</label>
|
||||
<description>Electric power of PV String 2</description>
|
||||
</channel>
|
||||
<channel id="pv-total-power" typeId="system.electric-power">
|
||||
<label>PV Total Power</label>
|
||||
<description>The sum of PV powers from all strings</description>
|
||||
</channel>
|
||||
<channel id="pv-total-current" typeId="system.electric-current">
|
||||
<label>PV Total Current</label>
|
||||
<description>The sum of PV currents from all strings</description>
|
||||
</channel>
|
||||
|
||||
<channel id="battery-power" typeId="system.electric-power">
|
||||
<label>Battery Power</label>
|
||||
<description>Power to/from the battery</description>
|
||||
</channel>
|
||||
<channel id="battery-current" typeId="system.electric-current">
|
||||
<label>Battery Current</label>
|
||||
<description>Electric current to/from the battery</description>
|
||||
</channel>
|
||||
<channel id="battery-voltage" typeId="system.electric-voltage">
|
||||
<label>Battery Voltage</label>
|
||||
<description>Electric voltage of the battery</description>
|
||||
</channel>
|
||||
<channel id="battery-temperature" typeId="battery-temperature">
|
||||
<label>Battery Temperature</label>
|
||||
<description>Temperature of the battery</description>
|
||||
</channel>
|
||||
<channel id="battery-level" typeId="system.battery-level">
|
||||
<label>Battery Level</label>
|
||||
<description>The battery state of charge in percent</description>
|
||||
</channel>
|
||||
|
||||
<channel id="feed-in-power" typeId="system.electric-power">
|
||||
<label>Feed-in Power</label>
|
||||
<description>Power to/from the electricity network.</description>
|
||||
</channel>
|
||||
|
||||
<channel id="last-update-time" typeId="last-retrieve-time-stamp"/>
|
||||
|
||||
<channel id="raw-data" typeId="raw-data-type"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="refreshInterval" type="integer" min="1" max="600">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Specifies the refresh interval in seconds.</description>
|
||||
<default>10</default>
|
||||
</parameter>
|
||||
<parameter name="password" type="text" required="true">
|
||||
<label>Password</label>
|
||||
<description>Password for accessing the Wi-Fi module (the serial number of the Wi-Fi module)</description>
|
||||
<context>password</context>
|
||||
</parameter>
|
||||
<parameter name="hostname" type="text" required="true">
|
||||
<label>Network Address</label>
|
||||
<description>IP address or the host name of the Wi-Fi module</description>
|
||||
<context>network-address</context>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
@ -356,6 +356,7 @@
|
||||
<module>org.openhab.binding.solarlog</module>
|
||||
<module>org.openhab.binding.solarmax</module>
|
||||
<module>org.openhab.binding.solarwatt</module>
|
||||
<module>org.openhab.binding.solax</module>
|
||||
<module>org.openhab.binding.somfymylink</module>
|
||||
<module>org.openhab.binding.somfytahoma</module>
|
||||
<module>org.openhab.binding.somneo</module>
|
||||
|
Loading…
Reference in New Issue
Block a user