mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-25 14:55:55 +01:00
[solax] Support for three phase inverter X3 Hybrid G4 (#15710)
Signed-off-by: Konstantin Polihronov <polychronov@gmail.com>
This commit is contained in:
parent
1881f17e3e
commit
24f4234e9b
@ -16,6 +16,9 @@ In case the parsed information that comes with the binding out of the box differ
|
||||
|------------------------|------------|-------------------------------------------------------------------------------------|
|
||||
| local-connect-inverter | Thing | This is model representation of inverter with all the data available as a channels |
|
||||
|
||||
Note: Channels may vary depending on the inverter type and the availability of information for parsing the raw data.
|
||||
If you're missing a channel this means that it's not supported for your inverter type.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
### Local Connect Inverter Configuration
|
||||
@ -28,12 +31,25 @@ In case the parsed information that comes with the binding out of the box differ
|
||||
|
||||
### 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] |
|
||||
| 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 electricity of the inverter [Hz] |
|
||||
| inverter-output-power-phase1 | Number:Power | The output power of phase 1 of the inverter [W] |
|
||||
| inverter-output-power-phase2 | Number:Power | The output power of phase 2 of the inverter [W] |
|
||||
| inverter-output-power-phase3 | Number:Power | The output power of phase 3 of the inverter [W] |
|
||||
| inverter-total-output-power | Number:Power | The total output power of all phases of the inverter [W] |
|
||||
| inverter-current-phase1 | Number:ElectricCurrent | The output current of phase 1 of the inverter [A] |
|
||||
| inverter-current-phase2 | Number:ElectricCurrent | The output current of phase 2 of the inverter [A] |
|
||||
| inverter-current-phase3 | Number:ElectricCurrent | The output current of phase 3 of the inverter [A] |
|
||||
| inverter-voltage-phase1 | Number:ElectricPotential | The output voltage of phase 1 of the inverter [V] |
|
||||
| inverter-voltage-phase2 | Number:ElectricPotential | The output voltage of phase 2 of the inverter [V] |
|
||||
| inverter-voltage-phase3 | Number:ElectricPotential | The output voltage of phase 3 of the inverter [V] |
|
||||
| inverter-frequency-phase1 | Number:Frequency | The frequency of phase 1 of the inverter [Hz] |
|
||||
| inverter-frequency-phase2 | Number:Frequency | The frequency of phase 2 of the inverter [Hz] |
|
||||
| inverter-frequency-phase3 | Number:Frequency | The frequency of phase 3 of the inverter [Hz] |
|
||||
|
||||
### Photovoltaic Panels Production Channels
|
||||
|
||||
@ -71,6 +87,23 @@ In case the parsed information that comes with the binding out of the box differ
|
||||
| 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 |
|
||||
|
||||
### Statistics / Usage related Channels
|
||||
|
||||
| Channel | Type | Description |
|
||||
|----------------------------------|----------------------------|-----------------------------------------------------------|
|
||||
| power-usage | Number:Power | Current power usage / consumption of the building [W] |
|
||||
| total-energy | Number:Energy | Total energy output from the inverter [kWh] |
|
||||
| total-battery-discharge-energy | Number:Energy | Total energy from the battery [kWh] |
|
||||
| total-battery-charge-energy | Number:Energy | Total energy to the battery [kWh] |
|
||||
| total-pv-energy | Number:Energy | Total energy from the PV [kWh] |
|
||||
| total-consumption | Number:Energy | Total energy consumed for the building [kWh] |
|
||||
| total-feed-in-energy | Number:Energy | Total energy consumed from the electricity provider [kWh] |
|
||||
| today-energy | Number:Energy | Energy output from the inverter for the day [kWh] |
|
||||
| today-battery-discharge-energy | Number:Energy | Total energy from the battery output for the day [kWh] |
|
||||
| today-battery-charge-energy | Number:Energy | Total energy charged to the battery for the day [kWh] |
|
||||
| today-feed-in-energy | Number:Energy | Total energy charged to the battery for the day [kWh] |
|
||||
| today-consumption | Number:Energy | Total energy consumed for the day [kWh] |
|
||||
|
||||
### Properties
|
||||
|
||||
| Property | Description |
|
||||
|
@ -39,32 +39,67 @@ public class SolaxBindingConstants {
|
||||
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";
|
||||
// Single phase specific
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_POWER = "inverter-output-power";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_CURRENT = "inverter-current";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_VOLTAGE = "inverter-voltage";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_FREQUENCY = "inverter-frequency";
|
||||
public static final Set<String> SINGLE_CHANNEL_SPECIFIC_CHANNEL_IDS = Set.of(CHANNEL_INVERTER_OUTPUT_POWER,
|
||||
CHANNEL_INVERTER_OUTPUT_CURRENT, CHANNEL_INVERTER_OUTPUT_VOLTAGE, CHANNEL_INVERTER_OUTPUT_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";
|
||||
// Three phase specific
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_POWER_PHASE1 = "inverter-output-power-phase1";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_POWER_PHASE2 = "inverter-output-power-phase2";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_POWER_PHASE3 = "inverter-output-power-phase3";
|
||||
public static final String CHANNEL_INVERTER_TOTAL_OUTPUT_POWER = "inverter-total-output-power";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_CURRENT_PHASE1 = "inverter-current-phase1";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_CURRENT_PHASE2 = "inverter-current-phase2";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_CURRENT_PHASE3 = "inverter-current-phase3";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_VOLTAGE_PHASE1 = "inverter-voltage-phase1";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_VOLTAGE_PHASE2 = "inverter-voltage-phase2";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_VOLTAGE_PHASE3 = "inverter-voltage-phase3";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_FREQUENCY_PHASE1 = "inverter-frequency-phase1";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_FREQUENCY_PHASE2 = "inverter-frequency-phase2";
|
||||
public static final String CHANNEL_INVERTER_OUTPUT_FREQUENCY_PHASE3 = "inverter-frequency-phase3";
|
||||
|
||||
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";
|
||||
// Generic
|
||||
public static final String CHANNEL_INVERTER_PV1_POWER = "pv1-power";
|
||||
public static final String CHANNEL_INVERTER_PV1_VOLTAGE = "pv1-voltage";
|
||||
public static final String CHANNEL_INVERTER_PV1_CURRENT = "pv1-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 CHANNEL_INVERTER_PV2_POWER = "pv2-power";
|
||||
public static final String CHANNEL_INVERTER_PV2_VOLTAGE = "pv2-voltage";
|
||||
public static final String CHANNEL_INVERTER_PV2_CURRENT = "pv2-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 CHANNEL_INVERTER_PV_TOTAL_POWER = "pv-total-power";
|
||||
public static final String CHANNEL_INVERTER_PV_TOTAL_CURRENT = "pv-total-current";
|
||||
|
||||
public static final String FEED_IN_POWER = "feed-in-power";
|
||||
public static final String CHANNEL_BATTERY_POWER = "battery-power";
|
||||
public static final String CHANNEL_BATTERY_VOLTAGE = "battery-voltage";
|
||||
public static final String CHANNEL_BATTERY_CURRENT = "battery-current";
|
||||
public static final String CHANNEL_BATTERY_TEMPERATURE = "battery-temperature";
|
||||
public static final String CHANNEL_BATTERY_STATE_OF_CHARGE = "battery-level";
|
||||
|
||||
public static final String TIMESTAMP = "last-update-time";
|
||||
public static final String RAW_DATA = "raw-data";
|
||||
public static final String CHANNEL_FEED_IN_POWER = "feed-in-power";
|
||||
|
||||
public static final String CHANNEL_TIMESTAMP = "last-update-time";
|
||||
public static final String CHANNEL_RAW_DATA = "raw-data";
|
||||
|
||||
// Totals
|
||||
public static final String CHANNEL_POWER_USAGE = "power-usage";
|
||||
public static final String CHANNEL_TOTAL_ENERGY = "total-energy";
|
||||
public static final String CHANNEL_TOTAL_BATTERY_DISCHARGE_ENERGY = "total-battery-discharge-energy";
|
||||
public static final String CHANNEL_TOTAL_BATTERY_CHARGE_ENERGY = "total-battery-charge-energy";
|
||||
public static final String CHANNEL_TOTAL_PV_ENERGY = "total-pv-energy";
|
||||
public static final String CHANNEL_TOTAL_FEED_IN_ENERGY = "total-feed-in-energy";
|
||||
public static final String CHANNEL_TOTAL_CONSUMPTION = "total-consumption";
|
||||
|
||||
// Today totals
|
||||
public static final String CHANNEL_TODAY_ENERGY = "today-energy";
|
||||
public static final String CHANNEL_TODAY_BATTERY_DISCHARGE_ENERGY = "today-battery-discharge-energy";
|
||||
public static final String CHANNEL_TODAY_BATTERY_CHARGE_ENERGY = "today-battery-charge-energy";
|
||||
public static final String CHANNEL_TODAY_FEED_IN_ENERGY = "today-feed-in-energy";
|
||||
public static final String CHANNEL_TODAY_CONSUMPTION = "today-consumption";
|
||||
|
||||
// I18N Keys
|
||||
protected static final String I18N_KEY_OFFLINE_COMMUNICATION_ERROR_JSON_CANNOT_BE_RETRIEVED = "@text/offline.communication-error.json-cannot-be-retrieved";
|
||||
|
@ -14,25 +14,35 @@ package org.openhab.binding.solax.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.measure.Quantity;
|
||||
import javax.measure.Unit;
|
||||
|
||||
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.binding.solax.internal.model.InverterType;
|
||||
import org.openhab.binding.solax.internal.model.parsers.RawDataParser;
|
||||
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.Channel;
|
||||
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.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -55,6 +65,10 @@ public class SolaxLocalAccessHandler extends BaseThingHandler {
|
||||
|
||||
private @Nullable ScheduledFuture<?> schedule;
|
||||
|
||||
private boolean alreadyRemovedUnsupportedChannels;
|
||||
|
||||
private final Set<String> unsupportedExistingChannels = new HashSet<String>();
|
||||
|
||||
public SolaxLocalAccessHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
@ -79,7 +93,7 @@ public class SolaxLocalAccessHandler extends BaseThingHandler {
|
||||
logger.debug("Raw data retrieved = {}", rawJsonData);
|
||||
|
||||
if (rawJsonData != null && !rawJsonData.isEmpty()) {
|
||||
updateData(rawJsonData);
|
||||
updateFromData(rawJsonData);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
SolaxBindingConstants.I18N_KEY_OFFLINE_COMMUNICATION_ERROR_JSON_CANNOT_BE_RETRIEVED);
|
||||
@ -90,68 +104,181 @@ public class SolaxLocalAccessHandler extends BaseThingHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateData(String rawJsonData) {
|
||||
private void updateFromData(String rawJsonData) {
|
||||
try {
|
||||
LocalConnectRawDataBean inverterParsedData = parseJson(rawJsonData);
|
||||
updateThing(inverterParsedData);
|
||||
LocalConnectRawDataBean rawDataBean = parseJson(rawJsonData);
|
||||
InverterType inverterType = calculateInverterType(rawDataBean);
|
||||
RawDataParser parser = inverterType.getParser();
|
||||
if (parser != null) {
|
||||
if (!alreadyRemovedUnsupportedChannels) {
|
||||
removeUnsupportedChannels(inverterType.getSupportedChannels());
|
||||
alreadyRemovedUnsupportedChannels = true;
|
||||
}
|
||||
|
||||
InverterData genericInverterData = parser.getData(rawDataBean);
|
||||
updateChannels(parser, genericInverterData);
|
||||
updateProperties(genericInverterData);
|
||||
|
||||
if (getThing().getStatus() != ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
} else {
|
||||
cancelSchedule();
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.configuration-error.parser-not-implemented [\"" + inverterType.name() + "\"]");
|
||||
}
|
||||
} 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());
|
||||
logger.debug("Received a new inverter JSON object. Data = {}", inverterParsedData.toString());
|
||||
return inverterParsedData;
|
||||
}
|
||||
|
||||
private void transferInverterDataToChannels(InverterData data) {
|
||||
updateProperty(Thing.PROPERTY_SERIAL_NUMBER, data.getWifiSerial());
|
||||
updateProperty(SolaxBindingConstants.PROPERTY_INVERTER_TYPE, data.getInverterType().name());
|
||||
private InverterType calculateInverterType(LocalConnectRawDataBean rawDataBean) {
|
||||
int type = rawDataBean.getType();
|
||||
return InverterType.fromIndex(type);
|
||||
}
|
||||
|
||||
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));
|
||||
private void updateProperties(InverterData genericInverterData) {
|
||||
updateProperty(Thing.PROPERTY_SERIAL_NUMBER, genericInverterData.getWifiSerial());
|
||||
updateProperty(SolaxBindingConstants.PROPERTY_INVERTER_TYPE, genericInverterData.getInverterType().name());
|
||||
}
|
||||
|
||||
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));
|
||||
private void updateChannels(RawDataParser parser, InverterData inverterData) {
|
||||
updateState(SolaxBindingConstants.CHANNEL_RAW_DATA, new StringType(inverterData.getRawData()));
|
||||
|
||||
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));
|
||||
Set<String> supportedChannels = parser.getSupportedChannels();
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_PV1_POWER, inverterData.getPV1Power(), Units.WATT,
|
||||
supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_PV1_CURRENT, inverterData.getPV1Current(), Units.AMPERE,
|
||||
supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_PV1_VOLTAGE, inverterData.getPV1Voltage(), Units.VOLT,
|
||||
supportedChannels);
|
||||
|
||||
updateState(SolaxBindingConstants.INVERTER_PV_TOTAL_POWER,
|
||||
new QuantityType<>(data.getPVTotalPower(), Units.WATT));
|
||||
updateState(SolaxBindingConstants.INVERTER_PV_TOTAL_CURRENT,
|
||||
new QuantityType<>(data.getPVTotalCurrent(), Units.AMPERE));
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_PV2_POWER, inverterData.getPV2Power(), Units.WATT,
|
||||
supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_PV2_CURRENT, inverterData.getPV2Current(), Units.AMPERE,
|
||||
supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_PV2_VOLTAGE, inverterData.getPV2Voltage(), Units.VOLT,
|
||||
supportedChannels);
|
||||
|
||||
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));
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_PV_TOTAL_POWER, inverterData.getPVTotalPower(), Units.WATT,
|
||||
supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_PV_TOTAL_CURRENT, inverterData.getPVTotalCurrent(),
|
||||
Units.AMPERE, supportedChannels);
|
||||
|
||||
updateState(SolaxBindingConstants.FEED_IN_POWER, new QuantityType<>(data.getFeedInPower(), Units.WATT));
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_BATTERY_POWER, inverterData.getBatteryPower(), Units.WATT,
|
||||
supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_BATTERY_CURRENT, inverterData.getBatteryCurrent(), Units.AMPERE,
|
||||
supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_BATTERY_VOLTAGE, inverterData.getBatteryVoltage(), Units.VOLT,
|
||||
supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_BATTERY_TEMPERATURE, inverterData.getBatteryTemperature(),
|
||||
SIUnits.CELSIUS, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_BATTERY_STATE_OF_CHARGE, inverterData.getBatteryLevel(),
|
||||
Units.PERCENT, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_FEED_IN_POWER, inverterData.getFeedInPower(), Units.WATT,
|
||||
supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_POWER_USAGE, inverterData.getPowerUsage(), Units.WATT,
|
||||
supportedChannels);
|
||||
|
||||
updateState(SolaxBindingConstants.TIMESTAMP, new DateTimeType(ZonedDateTime.now()));
|
||||
updateState(SolaxBindingConstants.RAW_DATA, new StringType(data.getRawData()));
|
||||
// Totals
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_TOTAL_ENERGY, inverterData.getTotalEnergy(), Units.KILOWATT_HOUR,
|
||||
supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_TOTAL_BATTERY_DISCHARGE_ENERGY,
|
||||
inverterData.getTotalBatteryDischargeEnergy(), Units.KILOWATT_HOUR, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_TOTAL_BATTERY_CHARGE_ENERGY,
|
||||
inverterData.getTotalBatteryChargeEnergy(), Units.KILOWATT_HOUR, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_TOTAL_PV_ENERGY, inverterData.getTotalPVEnergy(),
|
||||
Units.KILOWATT_HOUR, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_TOTAL_FEED_IN_ENERGY, inverterData.getTotalFeedInEnergy(),
|
||||
Units.KILOWATT_HOUR, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_TOTAL_CONSUMPTION, inverterData.getTotalConsumption(),
|
||||
Units.KILOWATT_HOUR, supportedChannels);
|
||||
|
||||
// Today's
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_TODAY_ENERGY, inverterData.getTodayEnergy(), Units.KILOWATT_HOUR,
|
||||
supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_TODAY_BATTERY_DISCHARGE_ENERGY,
|
||||
inverterData.getTodayBatteryDischargeEnergy(), Units.KILOWATT_HOUR, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_TODAY_BATTERY_CHARGE_ENERGY,
|
||||
inverterData.getTodayBatteryChargeEnergy(), Units.KILOWATT_HOUR, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_TODAY_FEED_IN_ENERGY, inverterData.getTodayFeedInEnergy(),
|
||||
Units.KILOWATT_HOUR, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_TODAY_CONSUMPTION, inverterData.getTodayConsumption(),
|
||||
Units.KILOWATT_HOUR, supportedChannels);
|
||||
|
||||
// Single phase specific channels
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_POWER, inverterData.getInverterOutputPower(),
|
||||
Units.WATT, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_CURRENT, inverterData.getInverterCurrent(),
|
||||
Units.AMPERE, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_VOLTAGE, inverterData.getInverterVoltage(),
|
||||
Units.VOLT, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_FREQUENCY, inverterData.getInverterFrequency(),
|
||||
Units.HERTZ, supportedChannels);
|
||||
|
||||
// Three phase specific channels
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_POWER_PHASE1, inverterData.getOutputPowerPhase1(),
|
||||
Units.WATT, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_POWER_PHASE2, inverterData.getOutputPowerPhase2(),
|
||||
Units.WATT, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_POWER_PHASE3, inverterData.getOutputPowerPhase3(),
|
||||
Units.WATT, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_TOTAL_OUTPUT_POWER, inverterData.getTotalOutputPower(),
|
||||
Units.WATT, supportedChannels);
|
||||
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_CURRENT_PHASE1, inverterData.getCurrentPhase1(),
|
||||
Units.AMPERE, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_CURRENT_PHASE2, inverterData.getCurrentPhase2(),
|
||||
Units.AMPERE, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_CURRENT_PHASE3, inverterData.getCurrentPhase3(),
|
||||
Units.AMPERE, supportedChannels);
|
||||
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_VOLTAGE_PHASE1, inverterData.getVoltagePhase1(),
|
||||
Units.VOLT, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_VOLTAGE_PHASE2, inverterData.getVoltagePhase2(),
|
||||
Units.VOLT, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_VOLTAGE_PHASE3, inverterData.getVoltagePhase3(),
|
||||
Units.VOLT, supportedChannels);
|
||||
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_FREQUENCY_PHASE1, inverterData.getFrequencyPhase1(),
|
||||
Units.HERTZ, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_FREQUENCY_PHASE2, inverterData.getFrequencyPhase2(),
|
||||
Units.HERTZ, supportedChannels);
|
||||
updateChannel(SolaxBindingConstants.CHANNEL_INVERTER_OUTPUT_FREQUENCY_PHASE3, inverterData.getFrequencyPhase3(),
|
||||
Units.HERTZ, supportedChannels);
|
||||
|
||||
// Binding provided data
|
||||
updateState(SolaxBindingConstants.CHANNEL_TIMESTAMP, new DateTimeType(ZonedDateTime.now()));
|
||||
}
|
||||
|
||||
private void removeUnsupportedChannels(Set<String> supportedChannels) {
|
||||
if (supportedChannels.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<Channel> channels = getThing().getChannels();
|
||||
List<Channel> channelsToRemove = channels.stream()
|
||||
.filter(channel -> !supportedChannels.contains(channel.getUID().getId())).toList();
|
||||
|
||||
if (!channelsToRemove.isEmpty()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logRemovedChannels(channelsToRemove);
|
||||
}
|
||||
updateThing(editThing().withoutChannels(channelsToRemove).build());
|
||||
}
|
||||
}
|
||||
|
||||
private void logRemovedChannels(List<Channel> channelsToRemove) {
|
||||
List<String> channelsToRemoveForLog = channelsToRemove.stream().map(channel -> channel.getUID().getId())
|
||||
.toList();
|
||||
logger.debug("Detected unsupported channels for the current inverter. Channels to be removed: {}",
|
||||
channelsToRemoveForLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -162,10 +289,29 @@ public class SolaxLocalAccessHandler extends BaseThingHandler {
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
cancelSchedule();
|
||||
}
|
||||
|
||||
private void cancelSchedule() {
|
||||
ScheduledFuture<?> schedule = this.schedule;
|
||||
if (schedule != null) {
|
||||
schedule.cancel(true);
|
||||
this.schedule = null;
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Quantity<T>> void updateChannel(String channelID, double value, Unit<T> unit,
|
||||
Set<String> supportedChannels) {
|
||||
if (supportedChannels.contains(channelID)) {
|
||||
if (value > Short.MIN_VALUE) {
|
||||
updateState(channelID, new QuantityType<>(value, unit));
|
||||
} else if (!unsupportedExistingChannels.contains(channelID)) {
|
||||
updateState(channelID, UnDefType.UNDEF);
|
||||
unsupportedExistingChannels.add(channelID);
|
||||
logger.warn(
|
||||
"Channel {} is marked as supported, but its value is out of the defined range. Value = {}. This is unexpected behaviour. Please file a bug.",
|
||||
channelID, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,7 @@ 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;
|
||||
@ -32,9 +28,7 @@ import com.google.gson.annotations.SerializedName;
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LocalConnectRawDataBean implements RawDataBean, InverterData {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LocalConnectRawDataBean.class);
|
||||
public class LocalConnectRawDataBean implements RawDataBean {
|
||||
|
||||
private @Nullable String sn;
|
||||
private @Nullable String ver;
|
||||
@ -113,143 +107,4 @@ public class LocalConnectRawDataBean implements RawDataBean, InverterData {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -14,16 +14,15 @@ 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.
|
||||
* The {@link InverterData} Interface for the parsed inverter data in meaningful format
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface InverterData extends RawDataBean {
|
||||
public interface InverterData {
|
||||
|
||||
@Nullable
|
||||
String getWifiSerial();
|
||||
|
||||
@ -32,61 +31,185 @@ public interface InverterData extends RawDataBean {
|
||||
|
||||
InverterType getInverterType();
|
||||
|
||||
short getInverterVoltage();
|
||||
@Nullable
|
||||
String getRawData();
|
||||
|
||||
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 double getPV1Voltage() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default short getPVTotalCurrent() {
|
||||
return (short) (getPV1Current() + getPV2Current());
|
||||
default double getPV1Current() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
short getBatteryVoltage(); // V / 100
|
||||
default short getPV1Power() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
short getBatteryCurrent(); // A / 100
|
||||
default double getPV2Voltage() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
short getBatteryPower(); // W
|
||||
default double getPV2Current() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
short getBatteryTemperature(); // temperature C
|
||||
default short getPV2Power() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
short getBatterySoC(); // % battery SoC
|
||||
default double getPVTotalPower() {
|
||||
return getPV1Power() + getPV2Power();
|
||||
}
|
||||
|
||||
long getOnGridTotalYield(); // KWh total Yeld from the sun (to the grid?)
|
||||
default double getPVTotalCurrent() {
|
||||
return getPV1Current() + getPV2Current();
|
||||
}
|
||||
|
||||
short getOnGridDailyYield(); // KWh daily Yeld from the sun (to the grid?)
|
||||
default double getBatteryVoltage() {
|
||||
return Short.MIN_VALUE;
|
||||
};
|
||||
|
||||
long getTotalFeedInEnergy(); // KWh all times
|
||||
default double getBatteryCurrent() {
|
||||
return Short.MIN_VALUE;
|
||||
};
|
||||
|
||||
long getTotalConsumption(); // KWh all times
|
||||
default short getBatteryPower() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
short getFeedInPower();
|
||||
default short getBatteryTemperature() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default short getBatteryLevel() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default short getFeedInPower() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default short getPowerUsage() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getTotalEnergy() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default short getTotalBatteryDischargeEnergy() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default short getTotalBatteryChargeEnergy() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getTotalPVEnergy() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default short getTotalFeedInEnergy() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getTotalConsumption() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getTodayEnergy() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getTodayFeedInEnergy() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getTodayConsumption() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getTodayBatteryDischargeEnergy() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getTodayBatteryChargeEnergy() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getInverterVoltage() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getInverterCurrent() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default short getInverterOutputPower() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getInverterFrequency() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getVoltagePhase1() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getVoltagePhase2() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getVoltagePhase3() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getCurrentPhase1() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getCurrentPhase2() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getCurrentPhase3() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default short getOutputPowerPhase1() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default short getOutputPowerPhase2() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default short getOutputPowerPhase3() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default short getTotalOutputPower() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getFrequencyPhase1() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getFrequencyPhase2() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
default double getFrequencyPhase3() {
|
||||
return Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
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.";
|
||||
+ getInverterType() + ", BatteryPower = " + getBatteryPower() + "W, Battery SoC = " + getBatteryLevel()
|
||||
+ "%, FeedIn Power = " + getFeedInPower() + "W, Total PV Power = " + (getPV1Power() + getPV2Power())
|
||||
+ "W";
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,15 @@
|
||||
*/
|
||||
package org.openhab.binding.solax.internal.model;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solax.internal.model.parsers.RawDataParser;
|
||||
import org.openhab.binding.solax.internal.model.parsers.X1HybridG4DataParser;
|
||||
import org.openhab.binding.solax.internal.model.parsers.X3HybridG4DataParser;
|
||||
|
||||
/**
|
||||
* The {@link InverterType} class is enum representing the different inverter types with a simple logic to convert from
|
||||
@ -38,18 +44,46 @@ public enum InverterType {
|
||||
A1_FIT(11),
|
||||
A1_GRID(12),
|
||||
J1_ESS(13),
|
||||
X3_HYBRID_G4(14),
|
||||
X1_HYBRID_G4(15),
|
||||
X3_HYBRID_G4(14, new X3HybridG4DataParser()),
|
||||
X1_HYBRID_G4(15, new X1HybridG4DataParser()),
|
||||
X3_MIC_OR_PRO_G2(16),
|
||||
X1_SPT(17),
|
||||
X1_BOOST_OR_MINI_G4(18),
|
||||
A1_HYB_G2(19),
|
||||
A1_AC_G2(20),
|
||||
A1_SMT_G2(21),
|
||||
X3_FTH(22),
|
||||
X3_MGA_G2(23),
|
||||
UNKNOWN(-1);
|
||||
|
||||
private int typeIndex;
|
||||
|
||||
private @Nullable RawDataParser parser;
|
||||
|
||||
private Set<String> supportedChannels = new HashSet<>();
|
||||
|
||||
InverterType(int typeIndex) {
|
||||
this(typeIndex, null);
|
||||
}
|
||||
|
||||
InverterType(int typeIndex, @Nullable RawDataParser parser) {
|
||||
this.typeIndex = typeIndex;
|
||||
this.parser = parser;
|
||||
if (parser != null) {
|
||||
this.supportedChannels = parser.getSupportedChannels();
|
||||
}
|
||||
}
|
||||
|
||||
public static InverterType fromIndex(int index) {
|
||||
InverterType[] values = InverterType.values();
|
||||
return Stream.of(values).filter(value -> value.typeIndex == index).findFirst().orElse(UNKNOWN);
|
||||
}
|
||||
|
||||
public @Nullable RawDataParser getParser() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
public Set<String> getSupportedChannels() {
|
||||
return supportedChannels;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 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.impl;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.solax.internal.connectivity.rawdata.LocalConnectRawDataBean;
|
||||
import org.openhab.binding.solax.internal.model.InverterData;
|
||||
import org.openhab.binding.solax.internal.model.InverterType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link CommonInverterData} is an abstract class that contains the common information, applicable for all
|
||||
* inverters.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class CommonInverterData implements InverterData {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(CommonInverterData.class);
|
||||
|
||||
private LocalConnectRawDataBean data;
|
||||
|
||||
public CommonInverterData(LocalConnectRawDataBean data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getRawData() {
|
||||
return data.getRawData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getWifiSerial() {
|
||||
return data.getSn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getWifiVersion() {
|
||||
return data.getVer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InverterType getInverterType() {
|
||||
return InverterType.fromIndex(data.getType());
|
||||
}
|
||||
|
||||
protected short getData(int index) {
|
||||
try {
|
||||
short[] dataArray = data.getData();
|
||||
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;
|
||||
}
|
||||
|
||||
public long packU16(int indexMajor, int indexMinor) {
|
||||
short major = getData(indexMajor);
|
||||
short minor = getData(indexMinor);
|
||||
if (major == 0) {
|
||||
return minor;
|
||||
}
|
||||
|
||||
return Integer.toUnsignedLong(major << 16 | minor & 0xFFFF);
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 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.impl;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solax.internal.connectivity.rawdata.LocalConnectRawDataBean;
|
||||
|
||||
/**
|
||||
* The {@link X1HybridG4InverterData} is an implementation of the single phased inverter data interface for X1 Hybrid G4
|
||||
* inverter.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class X1HybridG4InverterData extends CommonInverterData {
|
||||
|
||||
public X1HybridG4InverterData(LocalConnectRawDataBean data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getInverterVoltage() {
|
||||
return ((double) getData(0)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getInverterCurrent() {
|
||||
return ((double) getData(1)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getInverterOutputPower() {
|
||||
return getData(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getInverterFrequency() {
|
||||
return ((double) getData(3)) / 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getFeedInPower() {
|
||||
return getData(32);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getPV1Voltage() {
|
||||
return ((double) getData(4)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getPV2Voltage() {
|
||||
return ((double) getData(5)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getPV1Current() {
|
||||
return ((double) getData(6)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getPV2Current() {
|
||||
return ((double) getData(7)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getPV1Power() {
|
||||
return getData(8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getPV2Power() {
|
||||
return getData(9);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBatteryVoltage() {
|
||||
return ((double) getData(14)) / 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBatteryCurrent() {
|
||||
return ((double) getData(15)) / 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBatteryPower() {
|
||||
return getData(16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBatteryTemperature() {
|
||||
return getData(17);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBatteryLevel() {
|
||||
return getData(18);
|
||||
}
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
/**
|
||||
* 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.impl;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solax.internal.connectivity.rawdata.LocalConnectRawDataBean;
|
||||
|
||||
/**
|
||||
* The {@link X3HybridG4InverterData} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class X3HybridG4InverterData extends CommonInverterData {
|
||||
|
||||
public X3HybridG4InverterData(LocalConnectRawDataBean data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
// Inverter data
|
||||
|
||||
@Override
|
||||
public double getVoltagePhase1() {
|
||||
return ((double) getData(0)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getVoltagePhase2() {
|
||||
return ((double) getData(1)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getVoltagePhase3() {
|
||||
return ((double) getData(2)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCurrentPhase1() {
|
||||
return ((double) getData(3)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCurrentPhase2() {
|
||||
return ((double) getData(4)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCurrentPhase3() {
|
||||
return ((double) getData(5)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getOutputPowerPhase1() {
|
||||
return getData(6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getOutputPowerPhase2() {
|
||||
return getData(7);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getOutputPowerPhase3() {
|
||||
return getData(8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getTotalOutputPower() {
|
||||
return getData(9);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getPV1Voltage() {
|
||||
return ((double) getData(10)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getPV2Voltage() {
|
||||
return ((double) getData(11)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getPV1Current() {
|
||||
return ((double) getData(12)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getPV2Current() {
|
||||
return ((double) getData(13)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getPV1Power() {
|
||||
return getData(14);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getPV2Power() {
|
||||
return getData(15);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getFrequencyPhase1() {
|
||||
return ((double) getData(16)) / 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getFrequencyPhase2() {
|
||||
return ((double) getData(17)) / 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getFrequencyPhase3() {
|
||||
return ((double) getData(18)) / 100;
|
||||
}
|
||||
|
||||
// Battery
|
||||
|
||||
@Override
|
||||
public double getBatteryVoltage() {
|
||||
return ((double) getData(39)) / 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBatteryCurrent() {
|
||||
return ((double) getData(40)) / 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBatteryPower() {
|
||||
return getData(41);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBatteryTemperature() {
|
||||
return getData(105);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getBatteryLevel() {
|
||||
return getData(103);
|
||||
}
|
||||
|
||||
// Feed in power
|
||||
|
||||
@Override
|
||||
public short getFeedInPower() {
|
||||
return (short) (getData(34) - getData(35));
|
||||
}
|
||||
|
||||
// Totals
|
||||
|
||||
@Override
|
||||
public short getPowerUsage() {
|
||||
return getData(47);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTotalEnergy() {
|
||||
return ((double) getData(68)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getTotalBatteryDischargeEnergy() {
|
||||
return getData(74);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getTotalBatteryChargeEnergy() {
|
||||
return getData(76);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTotalPVEnergy() {
|
||||
return ((double) getData(80)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getTotalFeedInEnergy() {
|
||||
return getData(86);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTotalConsumption() {
|
||||
return ((double) getData(88)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTodayEnergy() {
|
||||
return ((double) getData(82)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTodayFeedInEnergy() {
|
||||
return ((double) getData(90)) / 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTodayConsumption() {
|
||||
return ((double) getData(92)) / 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTodayBatteryDischargeEnergy() {
|
||||
return ((double) getData(78)) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTodayBatteryChargeEnergy() {
|
||||
return ((double) getData(79)) / 10;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.parsers;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solax.internal.connectivity.rawdata.LocalConnectRawDataBean;
|
||||
import org.openhab.binding.solax.internal.model.InverterData;
|
||||
|
||||
/**
|
||||
* The {@link RawDataParser} declares generic parser implementation that parses raw data to generic inverter data which
|
||||
* is common for all inverters.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface RawDataParser {
|
||||
|
||||
InverterData getData(LocalConnectRawDataBean bean);
|
||||
|
||||
Set<String> getSupportedChannels();
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.parsers;
|
||||
|
||||
import static org.openhab.binding.solax.internal.SolaxBindingConstants.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solax.internal.connectivity.rawdata.LocalConnectRawDataBean;
|
||||
import org.openhab.binding.solax.internal.model.InverterData;
|
||||
import org.openhab.binding.solax.internal.model.impl.X1HybridG4InverterData;
|
||||
|
||||
/**
|
||||
* The {@link SinglePhaseDataParser} is the implementation that parses raw data into a SinglePhaseInverterData for the
|
||||
* X1 Hybrid G4 inverter.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class X1HybridG4DataParser implements RawDataParser {
|
||||
|
||||
private static final Set<String> X1_HYBRID_G4_SUPPORTED_CHANNELS = Set.of(CHANNEL_INVERTER_PV1_POWER,
|
||||
CHANNEL_INVERTER_PV1_VOLTAGE, CHANNEL_INVERTER_PV1_CURRENT, CHANNEL_INVERTER_PV2_POWER,
|
||||
CHANNEL_INVERTER_PV2_VOLTAGE, CHANNEL_INVERTER_PV2_CURRENT, CHANNEL_INVERTER_PV_TOTAL_POWER,
|
||||
CHANNEL_INVERTER_PV_TOTAL_CURRENT, CHANNEL_BATTERY_POWER, CHANNEL_BATTERY_VOLTAGE, CHANNEL_BATTERY_CURRENT,
|
||||
CHANNEL_BATTERY_TEMPERATURE, CHANNEL_BATTERY_STATE_OF_CHARGE, CHANNEL_FEED_IN_POWER, CHANNEL_TIMESTAMP,
|
||||
CHANNEL_RAW_DATA, CHANNEL_INVERTER_OUTPUT_POWER, CHANNEL_INVERTER_OUTPUT_CURRENT,
|
||||
CHANNEL_INVERTER_OUTPUT_VOLTAGE, CHANNEL_INVERTER_OUTPUT_FREQUENCY);
|
||||
|
||||
@Override
|
||||
public InverterData getData(LocalConnectRawDataBean rawData) {
|
||||
return new X1HybridG4InverterData(rawData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedChannels() {
|
||||
return X1_HYBRID_G4_SUPPORTED_CHANNELS;
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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.parsers;
|
||||
|
||||
import static org.openhab.binding.solax.internal.SolaxBindingConstants.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.solax.internal.connectivity.rawdata.LocalConnectRawDataBean;
|
||||
import org.openhab.binding.solax.internal.model.InverterData;
|
||||
import org.openhab.binding.solax.internal.model.impl.X3HybridG4InverterData;
|
||||
|
||||
/**
|
||||
* The {@link X3HybridG4DataParser} is the implementation that parses raw data into a SinglePhaseInverterData for the
|
||||
* X3 Hybrid G4 inverter.
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class X3HybridG4DataParser implements RawDataParser {
|
||||
|
||||
private static final Set<String> X3_HYBRID_G4_SUPPORTED_CHANNELS = Set.of(CHANNEL_INVERTER_PV1_POWER,
|
||||
CHANNEL_INVERTER_PV1_VOLTAGE, CHANNEL_INVERTER_PV1_CURRENT, CHANNEL_INVERTER_PV2_POWER,
|
||||
CHANNEL_INVERTER_PV2_VOLTAGE, CHANNEL_INVERTER_PV2_CURRENT, CHANNEL_INVERTER_PV_TOTAL_POWER,
|
||||
CHANNEL_INVERTER_PV_TOTAL_CURRENT, CHANNEL_BATTERY_POWER, CHANNEL_BATTERY_VOLTAGE, CHANNEL_BATTERY_CURRENT,
|
||||
CHANNEL_BATTERY_TEMPERATURE, CHANNEL_BATTERY_STATE_OF_CHARGE, CHANNEL_FEED_IN_POWER, CHANNEL_TIMESTAMP,
|
||||
CHANNEL_RAW_DATA, CHANNEL_INVERTER_OUTPUT_POWER_PHASE1, CHANNEL_INVERTER_OUTPUT_POWER_PHASE2,
|
||||
CHANNEL_INVERTER_OUTPUT_POWER_PHASE3, CHANNEL_INVERTER_TOTAL_OUTPUT_POWER,
|
||||
CHANNEL_INVERTER_OUTPUT_CURRENT_PHASE1, CHANNEL_INVERTER_OUTPUT_CURRENT_PHASE2,
|
||||
CHANNEL_INVERTER_OUTPUT_CURRENT_PHASE3, CHANNEL_INVERTER_OUTPUT_VOLTAGE_PHASE1,
|
||||
CHANNEL_INVERTER_OUTPUT_VOLTAGE_PHASE2, CHANNEL_INVERTER_OUTPUT_VOLTAGE_PHASE3,
|
||||
CHANNEL_INVERTER_OUTPUT_FREQUENCY_PHASE1, CHANNEL_INVERTER_OUTPUT_FREQUENCY_PHASE2,
|
||||
CHANNEL_INVERTER_OUTPUT_FREQUENCY_PHASE3, CHANNEL_POWER_USAGE, CHANNEL_TOTAL_ENERGY,
|
||||
CHANNEL_TOTAL_BATTERY_CHARGE_ENERGY, CHANNEL_TOTAL_PV_ENERGY, CHANNEL_TOTAL_CONSUMPTION,
|
||||
CHANNEL_TODAY_ENERGY, CHANNEL_TODAY_FEED_IN_ENERGY, CHANNEL_TODAY_CONSUMPTION,
|
||||
CHANNEL_TODAY_BATTERY_CHARGE_ENERGY, CHANNEL_TODAY_BATTERY_DISCHARGE_ENERGY);
|
||||
|
||||
@Override
|
||||
public InverterData getData(LocalConnectRawDataBean rawData) {
|
||||
return new X3HybridG4InverterData(rawData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedChannels() {
|
||||
return X3_HYBRID_G4_SUPPORTED_CHANNELS;
|
||||
}
|
||||
}
|
@ -17,14 +17,42 @@ thing-type.solax.local-connect-inverter.channel.battery-temperature.label = Batt
|
||||
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.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-current-phase1.label = Inverter Input/Output Current Phase 1
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-current-phase1.description = Current to/from the inverter phase 1
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-current-phase2.label = Inverter Input/Output Current Phase 2
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-current-phase2.description = Current to/from the inverter phase 2
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-current-phase3.label = Inverter Input/Output Current Phase 3
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-current-phase3.description = Current to/from the inverter phase 3
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-frequency-phase1.label = Inverter Voltage Phase 3
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-frequency-phase1.description = Voltage of the inverter's phase 3
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-frequency-phase2.label = Inverter Voltage Phase 2
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-frequency-phase2.description = Voltage of the inverter's phase 3
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-frequency-phase3.label = Inverter Voltage Phase 3
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-frequency-phase3.description = Voltage of the inverter's phase 3
|
||||
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-output-power-phase1.label = Inverter Input/Output Power Phase 1
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-output-power-phase1.description = Power to/from the inverter phase 1
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-output-power-phase2.label = Inverter Input/Output Power Phase 2
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-output-power-phase2.description = Power to/from the inverter phase 2
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-output-power-phase3.label = Inverter Input/Output Power Phase 3
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-output-power-phase3.description = Power to/from the inverter phase 3
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-total-output-power.label = Inverter Input/Output Total Power
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-total-output-power.description = Power to/from the inverter on all phases
|
||||
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.inverter-voltage-phase1.label = Inverter Voltage Phase 1
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-voltage-phase1.description = Voltage of the inverter's phase 1
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-voltage-phase2.label = Inverter Voltage Phase 2
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-voltage-phase2.description = Voltage of the inverter's phase 2
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-voltage-phase3.label = Inverter Voltage Phase 3
|
||||
thing-type.solax.local-connect-inverter.channel.inverter-voltage-phase3.description = Voltage of the inverter's phase 3
|
||||
thing-type.solax.local-connect-inverter.channel.power-usage.label = Power Usage
|
||||
thing-type.solax.local-connect-inverter.channel.power-usage.description = Current power consumption of the building
|
||||
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
|
||||
@ -41,6 +69,28 @@ 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-type.solax.local-connect-inverter.channel.today-battery-charge-energy.label = Today Battery Charge Energy
|
||||
thing-type.solax.local-connect-inverter.channel.today-battery-charge-energy.description = Total energy charged to the battery for the day
|
||||
thing-type.solax.local-connect-inverter.channel.today-battery-discharge-energy.label = Today Battery Discharge Energy
|
||||
thing-type.solax.local-connect-inverter.channel.today-battery-discharge-energy.description = Total energy from the battery output for the day
|
||||
thing-type.solax.local-connect-inverter.channel.today-consumption.label = Today Consumption
|
||||
thing-type.solax.local-connect-inverter.channel.today-consumption.description = Energy consumed for the day
|
||||
thing-type.solax.local-connect-inverter.channel.today-energy.label = Today Energy
|
||||
thing-type.solax.local-connect-inverter.channel.today-energy.description = Energy output from the inverter for the day
|
||||
thing-type.solax.local-connect-inverter.channel.today-feed-in-energy.label = Today Feed-In Energy
|
||||
thing-type.solax.local-connect-inverter.channel.today-feed-in-energy.description = Energy consumed from the electricity provider for the day
|
||||
thing-type.solax.local-connect-inverter.channel.total-battery-charge-energy.label = Total Battery Charge Energy
|
||||
thing-type.solax.local-connect-inverter.channel.total-battery-charge-energy.description = Total energy charged to the battery
|
||||
thing-type.solax.local-connect-inverter.channel.total-battery-discharge-energy.label = Total Battery Discharge Energy
|
||||
thing-type.solax.local-connect-inverter.channel.total-battery-discharge-energy.description = Total energy from the battery output
|
||||
thing-type.solax.local-connect-inverter.channel.total-consumption.label = Total Consumption
|
||||
thing-type.solax.local-connect-inverter.channel.total-consumption.description = Total energy consumed from the building
|
||||
thing-type.solax.local-connect-inverter.channel.total-energy.label = Total Energy
|
||||
thing-type.solax.local-connect-inverter.channel.total-energy.description = Total energy output from the inverter
|
||||
thing-type.solax.local-connect-inverter.channel.total-feed-in-energy.label = Total Feed-In Consumption
|
||||
thing-type.solax.local-connect-inverter.channel.total-feed-in-energy.description = Total energy consumed from the electricity provider
|
||||
thing-type.solax.local-connect-inverter.channel.total-pv-energy.label = Total PV Energy
|
||||
thing-type.solax.local-connect-inverter.channel.total-pv-energy.description = Total energy produced by the PV
|
||||
|
||||
# thing types config
|
||||
|
||||
@ -65,3 +115,4 @@ channel-type.solax.raw-data-type.description = The raw JSON data retrieved from
|
||||
# thing status descriptions
|
||||
|
||||
offline.communication-error.json-cannot-be-retrieved = JSON data could not be retrieved.
|
||||
offline.configuration-error.parser-not-implemented = Parser for inverter of type {0} is not implemented.
|
||||
|
@ -10,6 +10,7 @@
|
||||
<description>The inverter representation that supports local connections via HTTP</description>
|
||||
|
||||
<channels>
|
||||
<!-- Single phase specific channels -->
|
||||
<channel id="inverter-output-power" typeId="system.electric-power">
|
||||
<label>Inverter Input/Output Power</label>
|
||||
<description>Power to/from the inverter</description>
|
||||
@ -24,6 +25,61 @@
|
||||
</channel>
|
||||
<channel id="inverter-frequency" typeId="frequency"/>
|
||||
|
||||
<!-- Three phase specific channels -->
|
||||
<channel id="inverter-output-power-phase1" typeId="system.electric-power">
|
||||
<label>Inverter Input/Output Power Phase 1</label>
|
||||
<description>Power to/from the inverter phase 1</description>
|
||||
</channel>
|
||||
<channel id="inverter-output-power-phase2" typeId="system.electric-power">
|
||||
<label>Inverter Input/Output Power Phase 2</label>
|
||||
<description>Power to/from the inverter phase 2</description>
|
||||
</channel>
|
||||
<channel id="inverter-output-power-phase3" typeId="system.electric-power">
|
||||
<label>Inverter Input/Output Power Phase 3</label>
|
||||
<description>Power to/from the inverter phase 3</description>
|
||||
</channel>
|
||||
<channel id="inverter-total-output-power" typeId="system.electric-power">
|
||||
<label>Inverter Input/Output Total Power</label>
|
||||
<description>Power to/from the inverter on all phases</description>
|
||||
</channel>
|
||||
<channel id="inverter-current-phase1" typeId="system.electric-current">
|
||||
<label>Inverter Input/Output Current Phase 1</label>
|
||||
<description>Current to/from the inverter phase 1</description>
|
||||
</channel>
|
||||
<channel id="inverter-current-phase2" typeId="system.electric-current">
|
||||
<label>Inverter Input/Output Current Phase 2</label>
|
||||
<description>Current to/from the inverter phase 2</description>
|
||||
</channel>
|
||||
<channel id="inverter-current-phase3" typeId="system.electric-current">
|
||||
<label>Inverter Input/Output Current Phase 3</label>
|
||||
<description>Current to/from the inverter phase 3</description>
|
||||
</channel>
|
||||
<channel id="inverter-voltage-phase1" typeId="system.electric-voltage">
|
||||
<label>Inverter Voltage Phase 1</label>
|
||||
<description>Voltage of the inverter's phase 1</description>
|
||||
</channel>
|
||||
<channel id="inverter-voltage-phase2" typeId="system.electric-voltage">
|
||||
<label>Inverter Voltage Phase 2</label>
|
||||
<description>Voltage of the inverter's phase 2</description>
|
||||
</channel>
|
||||
<channel id="inverter-voltage-phase3" typeId="system.electric-voltage">
|
||||
<label>Inverter Voltage Phase 3</label>
|
||||
<description>Voltage of the inverter's phase 3</description>
|
||||
</channel>
|
||||
<channel id="inverter-frequency-phase1" typeId="frequency">
|
||||
<label>Inverter Voltage Phase 3</label>
|
||||
<description>Voltage of the inverter's phase 3</description>
|
||||
</channel>
|
||||
<channel id="inverter-frequency-phase2" typeId="frequency">
|
||||
<label>Inverter Voltage Phase 2</label>
|
||||
<description>Voltage of the inverter's phase 3</description>
|
||||
</channel>
|
||||
<channel id="inverter-frequency-phase3" typeId="frequency">
|
||||
<label>Inverter Voltage Phase 3</label>
|
||||
<description>Voltage of the inverter's phase 3</description>
|
||||
</channel>
|
||||
|
||||
<!-- Generic channels -->
|
||||
<channel id="pv1-voltage" typeId="system.electric-voltage">
|
||||
<label>PV 1 Voltage</label>
|
||||
<description>Electric voltage of PV String 1</description>
|
||||
@ -77,17 +133,69 @@
|
||||
<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>
|
||||
<label>Feed-In Power</label>
|
||||
<description>Power to/from the electricity network.</description>
|
||||
</channel>
|
||||
|
||||
<channel id="power-usage" typeId="system.electric-power">
|
||||
<label>Power Usage</label>
|
||||
<description>Current power consumption of the building</description>
|
||||
</channel>
|
||||
<channel id="total-energy" typeId="system.electric-energy">
|
||||
<label>Total Energy</label>
|
||||
<description>Total energy output from the inverter</description>
|
||||
</channel>
|
||||
<channel id="total-battery-discharge-energy" typeId="system.electric-energy">
|
||||
<label>Total Battery Discharge Energy</label>
|
||||
<description>Total energy from the battery output</description>
|
||||
</channel>
|
||||
<channel id="total-battery-charge-energy" typeId="system.electric-energy">
|
||||
<label>Total Battery Charge Energy</label>
|
||||
<description>Total energy charged to the battery</description>
|
||||
</channel>
|
||||
<channel id="total-pv-energy" typeId="system.electric-energy">
|
||||
<label>Total PV Energy</label>
|
||||
<description>Total energy produced by the PV</description>
|
||||
</channel>
|
||||
<channel id="total-consumption" typeId="system.electric-energy">
|
||||
<label>Total Consumption</label>
|
||||
<description>Total energy consumed from the building</description>
|
||||
</channel>
|
||||
<channel id="total-feed-in-energy" typeId="system.electric-energy">
|
||||
<label>Total Feed-In Consumption</label>
|
||||
<description>Total energy consumed from the electricity provider</description>
|
||||
</channel>
|
||||
<channel id="today-energy" typeId="system.electric-energy">
|
||||
<label>Today Energy</label>
|
||||
<description>Energy output from the inverter for the day</description>
|
||||
</channel>
|
||||
<channel id="today-battery-discharge-energy" typeId="system.electric-energy">
|
||||
<label>Today Battery Discharge Energy</label>
|
||||
<description>Total energy from the battery output for the day</description>
|
||||
</channel>
|
||||
<channel id="today-battery-charge-energy" typeId="system.electric-energy">
|
||||
<label>Today Battery Charge Energy</label>
|
||||
<description>Total energy charged to the battery for the day</description>
|
||||
</channel>
|
||||
<channel id="today-feed-in-energy" typeId="system.electric-energy">
|
||||
<label>Today Feed-In Energy</label>
|
||||
<description>Energy consumed from the electricity provider for the day</description>
|
||||
</channel>
|
||||
<channel id="today-consumption" typeId="system.electric-energy">
|
||||
<label>Today Consumption</label>
|
||||
<description>Energy consumed for the day</description>
|
||||
</channel>
|
||||
|
||||
<channel id="last-update-time" typeId="last-retrieve-time-stamp"/>
|
||||
|
||||
<channel id="raw-data" typeId="raw-data-type"/>
|
||||
</channels>
|
||||
|
||||
<properties>
|
||||
<property name="thingTypeVersion">1</property>
|
||||
</properties>
|
||||
|
||||
<config-description>
|
||||
<parameter name="refreshInterval" type="integer" min="1" max="600">
|
||||
<label>Refresh Interval</label>
|
||||
|
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
|
||||
<thing-type uid="solax:local-connect-inverter">
|
||||
<instruction-set targetVersion="1">
|
||||
<add-channel id="inverter-output-power-phase1">
|
||||
<type>system:electric-power</type>
|
||||
<label>Inverter Input/Output Power Phase 1</label>
|
||||
<description>Power to/from the inverter phase 1</description>
|
||||
</add-channel>
|
||||
<add-channel id="inverter-output-power-phase2">
|
||||
<type>system:electric-power</type>
|
||||
<label>Inverter Input/Output Power Phase 2</label>
|
||||
<description>Power to/from the inverter phase 2</description>
|
||||
</add-channel>
|
||||
<add-channel id="inverter-output-power-phase3">
|
||||
<type>system:electric-power</type>
|
||||
<label>Inverter Input/Output Power Phase 3</label>
|
||||
<description>Power to/from the inverter phase 3</description>
|
||||
</add-channel>
|
||||
<add-channel id="inverter-total-output-power">
|
||||
<type>system:electric-power</type>
|
||||
<label>Inverter Input/Output Total Power</label>
|
||||
<description>Power to/from the inverter on all phases</description>
|
||||
</add-channel>
|
||||
<add-channel id="inverter-current-phase1">
|
||||
<type>system:electric-current</type>
|
||||
<label>Inverter Input/Output Current Phase 1</label>
|
||||
<description>Current to/from the inverter phase 1</description>
|
||||
</add-channel>
|
||||
<add-channel id="inverter-current-phase2">
|
||||
<type>system:electric-current</type>
|
||||
<label>Inverter Input/Output Current Phase 2</label>
|
||||
<description>Current to/from the inverter phase 2</description>
|
||||
</add-channel>
|
||||
<add-channel id="inverter-current-phase3">
|
||||
<type>system:electric-current</type>
|
||||
<label>Inverter Input/Output Current Phase 3</label>
|
||||
<description>Current to/from the inverter phase 3</description>
|
||||
</add-channel>
|
||||
<add-channel id="inverter-voltage-phase1">
|
||||
<type>system:electric-voltage</type>
|
||||
<label>Inverter Voltage Phase 1</label>
|
||||
<description>Voltage of the inverter's phase 1</description>
|
||||
</add-channel>
|
||||
<add-channel id="inverter-voltage-phase2">
|
||||
<type>system:electric-voltage</type>
|
||||
<label>Inverter Voltage Phase 2</label>
|
||||
<description>Voltage of the inverter's phase 2</description>
|
||||
</add-channel>
|
||||
<add-channel id="inverter-voltage-phase3">
|
||||
<type>system:electric-voltage</type>
|
||||
<label>Inverter Voltage Phase 3</label>
|
||||
<description>Voltage of the inverter's phase 3</description>
|
||||
</add-channel>
|
||||
<add-channel id="inverter-frequency-phase1">
|
||||
<type>system:electric-voltage</type>
|
||||
<label>Inverter Voltage Phase 3</label>
|
||||
<description>Voltage of the inverter's phase 3</description>
|
||||
</add-channel>
|
||||
<add-channel id="inverter-frequency-phase2">
|
||||
<type>system:electric-voltage</type>
|
||||
<label>Inverter Voltage Phase 2</label>
|
||||
<description>Voltage of the inverter's phase 3</description>
|
||||
</add-channel>
|
||||
<add-channel id="inverter-frequency-phase3">
|
||||
<type>system:electric-voltage</type>
|
||||
<label>Inverter Voltage Phase 3</label>
|
||||
<description>Voltage of the inverter's phase 3</description>
|
||||
</add-channel>
|
||||
<add-channel id="power-usage">
|
||||
<type>system:electric-power</type>
|
||||
<label>Power Usage</label>
|
||||
<description>Current power consumption of the building</description>
|
||||
</add-channel>
|
||||
<add-channel id="total-energy">
|
||||
<type>system:electric-energy</type>
|
||||
<label>Total Energy</label>
|
||||
<description>Total energy output from the inverter</description>
|
||||
</add-channel>
|
||||
<add-channel id="total-battery-discharge-energy">
|
||||
<type>system:electric-energy</type>
|
||||
<label>Total Battery Discharge Energy</label>
|
||||
<description>Total energy from the battery output</description>
|
||||
</add-channel>
|
||||
<add-channel id="total-battery-charge-energy">
|
||||
<type>system:electric-energy</type>
|
||||
<label>Total Battery Charge Energy</label>
|
||||
<description>Total energy charged to the battery</description>
|
||||
</add-channel>
|
||||
<add-channel id="total-pv-energy">
|
||||
<type>system:electric-energy</type>
|
||||
<label>Total PV Energy</label>
|
||||
<description>Total energy produced by the PV</description>
|
||||
</add-channel>
|
||||
<add-channel id="total-consumption">
|
||||
<type>system:electric-energy</type>
|
||||
<label>Total Consumption</label>
|
||||
<description>Total energy consumed from the building</description>
|
||||
</add-channel>
|
||||
<add-channel id="total-feed-in-energy">
|
||||
<type>system:electric-energy</type>
|
||||
<label>Total Feed-In Consumption</label>
|
||||
<description>Total energy consumed from the electricity provider</description>
|
||||
</add-channel>
|
||||
<add-channel id="today-energy">
|
||||
<type>system:electric-energy</type>
|
||||
<label>Today Energy</label>
|
||||
<description>Energy output from the inverter for the day</description>
|
||||
</add-channel>
|
||||
<add-channel id="today-battery-discharge-energy">
|
||||
<type>system:electric-energy</type>
|
||||
<label>Today Battery Discharge Energy</label>
|
||||
<description>Total energy from the battery output for the day</description>
|
||||
</add-channel>
|
||||
<add-channel id="today-battery-charge-energy">
|
||||
<type>system:electric-energy</type>
|
||||
<label>Today Battery Charge Energy</label>
|
||||
<description>Total energy charged to the battery for the day</description>
|
||||
</add-channel>
|
||||
<add-channel id="today-feed-in-energy">
|
||||
<type>system:electric-energy</type>
|
||||
<label>Today Feed-In Energy</label>
|
||||
<description>Energy consumed from the electricity provider for the day</description>
|
||||
</add-channel>
|
||||
<add-channel id="today-consumption">
|
||||
<type>system:electric-energy</type>
|
||||
<label>Today Consumption</label>
|
||||
<description>Energy consumed for the day</description>
|
||||
</add-channel>
|
||||
</instruction-set>
|
||||
</thing-type>
|
||||
</update:update-descriptions>
|
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* 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.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.solax.internal.connectivity.rawdata.LocalConnectRawDataBean;
|
||||
import org.openhab.binding.solax.internal.model.InverterData;
|
||||
import org.openhab.binding.solax.internal.model.InverterType;
|
||||
import org.openhab.binding.solax.internal.model.parsers.RawDataParser;
|
||||
|
||||
/**
|
||||
* The {@link TestX1HybridG4Parser} Simple test that tests for proper parsing against a real data from the inverter
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TestX1HybridG4Parser {
|
||||
|
||||
private static final String RAW_DATA = """
|
||||
{
|
||||
sn:SOME_SERIAL_NUMBER,
|
||||
ver:3.008.10,
|
||||
type:15,
|
||||
Data:[
|
||||
2388,21,460,4998,4483,4483,10,1,487,65,
|
||||
2,59781,0,70,12180,500,605,33,99,12000,
|
||||
0,23159,0,57,100,0,39,4501,0,0,
|
||||
0,0,12,0,13240,0,63348,2,448,43,
|
||||
256,1314,900,0,350,311,279,33,33,279,1,1,652,0,708,1,65077,65535,65386,65535,0,0,0,0,0,0,0,0,0,0,0,0,65068,65535,4500,0,61036,65535,10,0,90,0,0,12,0,116,7,57,0,0,2320,0,110,0,0,0,0,0,0,12544,7440,5896,594,521,9252,0,0,0,0,0,1,1201,0,0,3342,3336,7296,54,21302,14389,18753,12852,16692,12355,13618,21302,14389,18753,12852,16692,12355,13618,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1025,4609,1026,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
|
||||
Information:[7.500,15,H4752TI1063020,8,1.24,0.00,1.21,1.03,0.00,1]}
|
||||
""";
|
||||
|
||||
@Test
|
||||
public void testParser() {
|
||||
LocalConnectRawDataBean bean = LocalConnectRawDataBean.fromJson(RAW_DATA);
|
||||
int type = bean.getType();
|
||||
InverterType inverterType = InverterType.fromIndex(type);
|
||||
assertEquals(InverterType.X1_HYBRID_G4, inverterType, "Inverter type not recognized properly");
|
||||
|
||||
RawDataParser parser = inverterType.getParser();
|
||||
assertNotNull(parser);
|
||||
|
||||
InverterData data = parser.getData(bean);
|
||||
assertEquals("SOME_SERIAL_NUMBER", data.getWifiSerial());
|
||||
assertEquals("3.008.10", data.getWifiVersion());
|
||||
|
||||
assertEquals(238.8, data.getInverterVoltage()); // [0]
|
||||
assertEquals(2.1, data.getInverterCurrent()); // [1]
|
||||
assertEquals(460, data.getInverterOutputPower()); // [2]
|
||||
assertEquals(49.98, data.getInverterFrequency()); // [3]
|
||||
|
||||
assertEquals(448.3, data.getPV1Voltage()); // [4]
|
||||
assertEquals(448.3, data.getPV2Voltage()); // [5]
|
||||
assertEquals(1, data.getPV1Current()); // [6]
|
||||
assertEquals(0.1, data.getPV2Current()); // [7]
|
||||
assertEquals(487, data.getPV1Power()); // [8]
|
||||
assertEquals(65, data.getPV2Power()); // [9]
|
||||
|
||||
assertEquals(121.8, data.getBatteryVoltage()); // [14]
|
||||
assertEquals(5, data.getBatteryCurrent()); // [15]
|
||||
assertEquals(605, data.getBatteryPower()); // [16]
|
||||
assertEquals(33, data.getBatteryTemperature()); // [17]
|
||||
assertEquals(99, data.getBatteryLevel()); // [18]
|
||||
|
||||
assertEquals(12, data.getFeedInPower()); // [32]
|
||||
}
|
||||
|
||||
// Yield_Today: Data[13] / 10,
|
||||
// Yield_Total: read32BitUnsigned(Data[11], Data[12]) / 10,
|
||||
// PowerDc1: Data[8],
|
||||
// PowerDc2: Data[9],
|
||||
// BAT_Power: read16BitSigned(Data[16]),
|
||||
// feedInPower: read32BitSigned(Data[32], Data[33]),
|
||||
// GridAPower: read16BitSigned(Data[2]),
|
||||
// FeedInEnergy: read32BitUnsigned(Data[34], Data[35]) / 100,
|
||||
// ConsumeEnergy: read32BitUnsigned(Data[36], Data[37]) / 100,
|
||||
// RunMode: Data[10],
|
||||
// EPSAPower: read16BitSigned(Data[28]),
|
||||
// Vdc1: Data[4] / 10,
|
||||
// Vdc2: Data[5] / 10,
|
||||
// Idc1: Data[6] / 10,
|
||||
// Idc2: Data[7] / 10,
|
||||
// EPSAVoltage: Data[29] / 10,
|
||||
// EPSACurrent: read16BitSigned(Data[30]) / 10,
|
||||
// BatteryCapacity: Data[18],
|
||||
// BatteryVoltage: Data[14] / 100,
|
||||
// BatteryTemperature: read16BitSigned(Data[17]),
|
||||
// GridAVoltage: Data[0] / 10,
|
||||
// GridACurrent: read16BitSigned(Data[1]) / 10,
|
||||
// FreqacA: Data[3] / 100,
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* 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.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.solax.internal.connectivity.rawdata.LocalConnectRawDataBean;
|
||||
import org.openhab.binding.solax.internal.model.InverterData;
|
||||
import org.openhab.binding.solax.internal.model.InverterType;
|
||||
import org.openhab.binding.solax.internal.model.parsers.RawDataParser;
|
||||
|
||||
/**
|
||||
* The {@link TestX3HybridG4Parser} simple test that tests for proper parsing against a real data from the inverter
|
||||
*
|
||||
* @author Konstantin Polihronov - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TestX3HybridG4Parser {
|
||||
|
||||
String rawData = """
|
||||
{
|
||||
sn:XYZ,
|
||||
ver:3.005.01,
|
||||
type:14,Data:[
|
||||
2316,2329,2315,18,18,18,372,363,365,1100,
|
||||
12,23,34,45,56,67,4996,4996,4996,2,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,1,65494,65535,0,0,0,31330,
|
||||
320,1034,3078,1,44,1100,256,1294,0,0,
|
||||
7445,5895,100,0,38,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,505,0,
|
||||
396,0,0,0,102,0,142,0,62,110,
|
||||
570,0,463,0,0,0,1925,0,369,0,
|
||||
506,1925,304,309,0,0,0,0,0,0,
|
||||
0,0,0,45,1,59,1,34,54,256,
|
||||
3504,2400,300,300,295,276,33,33,2,1620,779,15163,15163,14906,0,0,0,3270,3264,45581,0,20564,12339,18753,12353,18742,12356,13625,20564,12339,18754,12866,18743,14151,13104,20564,12339,18754,12866,18743,14151,12592,20564,12339,18754,12865,18738,12871,13620,0,0,0,0,0,0,0,1025,8195,769,259,0,31460,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
|
||||
Information:[12.000,14,XY,8,1.23,0.00,1.24,1.09,0.00,1]
|
||||
}
|
||||
""";
|
||||
|
||||
@Test
|
||||
public void testParser() {
|
||||
LocalConnectRawDataBean bean = LocalConnectRawDataBean.fromJson(rawData);
|
||||
int type = bean.getType();
|
||||
InverterType inverterType = InverterType.fromIndex(type);
|
||||
assertEquals(InverterType.X3_HYBRID_G4, inverterType, "Inverter type not recognized properly");
|
||||
|
||||
RawDataParser parser = inverterType.getParser();
|
||||
assertNotNull(parser);
|
||||
|
||||
InverterData data = parser.getData(bean);
|
||||
assertEquals("XYZ", data.getWifiSerial());
|
||||
assertEquals("3.005.01", data.getWifiVersion());
|
||||
|
||||
assertEquals(231.6, data.getVoltagePhase1()); // [0]
|
||||
assertEquals(232.9, data.getVoltagePhase2()); // [1]
|
||||
assertEquals(231.5, data.getVoltagePhase3()); // [2]
|
||||
|
||||
assertEquals(1.8, data.getCurrentPhase1()); // [3]
|
||||
assertEquals(1.8, data.getCurrentPhase2()); // [4]
|
||||
assertEquals(1.8, data.getCurrentPhase3()); // [5]
|
||||
|
||||
assertEquals(372, data.getOutputPowerPhase1()); // [6]
|
||||
assertEquals(363, data.getOutputPowerPhase2()); // [7]
|
||||
assertEquals(365, data.getOutputPowerPhase3()); // [8]
|
||||
|
||||
assertEquals(1100, data.getTotalOutputPower()); // [9]
|
||||
|
||||
assertEquals(1.2, data.getPV1Voltage()); // [10]
|
||||
assertEquals(2.3, data.getPV2Voltage()); // [11]
|
||||
assertEquals(3.4, data.getPV1Current()); // [12]
|
||||
assertEquals(4.5, data.getPV2Current()); // [13]
|
||||
assertEquals(56, data.getPV1Power()); // [14]
|
||||
assertEquals(67, data.getPV2Power()); // [15]
|
||||
|
||||
assertEquals(49.96, data.getFrequencyPhase1()); // [16]
|
||||
assertEquals(49.96, data.getFrequencyPhase2()); // [17]
|
||||
assertEquals(49.96, data.getFrequencyPhase3()); // [18]
|
||||
|
||||
assertEquals(-41, data.getFeedInPower()); // [34] - [35]
|
||||
|
||||
assertEquals(313.3, data.getBatteryVoltage()); // [39]
|
||||
assertEquals(3.2, data.getBatteryCurrent()); // [40]
|
||||
assertEquals(1034, data.getBatteryPower()); // [41]
|
||||
assertEquals(45, data.getBatteryLevel()); // [103]
|
||||
assertEquals(59, data.getBatteryTemperature()); // [105]
|
||||
|
||||
// Totals
|
||||
assertEquals(1294, data.getPowerUsage()); // [47]
|
||||
assertEquals(50.5, data.getTotalEnergy()); // [68]
|
||||
assertEquals(102, data.getTotalBatteryDischargeEnergy()); // [74]
|
||||
assertEquals(142, data.getTotalBatteryChargeEnergy()); // [76]
|
||||
assertEquals(57, data.getTotalPVEnergy()); // [80]
|
||||
assertEquals(1925, data.getTotalFeedInEnergy()); // [86]
|
||||
assertEquals(36.9, data.getTotalConsumption()); // [88]
|
||||
assertEquals(46.3, data.getTodayEnergy()); // [82] / 10
|
||||
assertEquals(5.06, data.getTodayFeedInEnergy()); // [90] / 100
|
||||
assertEquals(3.04, data.getTodayConsumption()); // [92] / 100
|
||||
assertEquals(6.2, data.getTodayBatteryDischargeEnergy()); // [78] / 100
|
||||
assertEquals(11, data.getTodayBatteryChargeEnergy()); // [79] / 100
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user