Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[solax] Add support for x1 mini inverter local connection #16412

Merged
merged 3 commits into from
Feb 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.solax.internal.model.local.parsers.RawDataParser;
import org.openhab.binding.solax.internal.model.local.parsers.X1BoostAirMiniDataParser;
import org.openhab.binding.solax.internal.model.local.parsers.X1HybridG4DataParser;
import org.openhab.binding.solax.internal.model.local.parsers.X3HybridG4DataParser;
import org.openhab.binding.solax.internal.model.local.parsers.X3MicOrProG2DataParser;
Expand All @@ -35,7 +36,7 @@ public enum InverterType {
X1_LX(1),
X_HYBRID(2),
X1_HYBRID_FIT(3),
X1_BOOST_AIR_MINI(4),
X1_BOOST_AIR_MINI(4, new X1BoostAirMiniDataParser()),
X3_HYBRID_FIT(5),
X3_20K_30K(6),
X3_MIC_PRO(7),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* Copyright (c) 2010-2024 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.solax.internal.model.local;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.solax.internal.connectivity.rawdata.local.LocalConnectRawDataBean;

/**
* The {@link X1BoostAirMiniInverterData} is an implementation of the single phased inverter data interface for X1 Mini
* / X1 Air Mini or X1 Boost Mini inverter.
*
* @author Konstantin Polihronov - Initial contribution
*/
@NonNullByDefault
public class X1BoostAirMiniInverterData extends CommonLocalInverterData {

public X1BoostAirMiniInverterData(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 getPV1Voltage() {
return (double) getData(3) / 10;
}

@Override
public double getPV2Voltage() {
return (double) getData(4) / 10;
}

@Override
public double getPV1Current() {
return (double) getData(5) / 10;
}

@Override
public double getPV2Current() {
return (double) getData(6) / 10;
}

@Override
public short getPV1Power() {
return getData(7);
}

@Override
public short getPV2Power() {
return getData(8);
}

@Override
public double getInverterFrequency() {
return (double) getData(9) / 100;
}

@Override
public double getTotalEnergy() {
return (double) getData(11) / 10;
}

@Override
public double getTodayEnergy() {
return (double) getData(13) / 10;
}

@Override
public short getPowerUsage() {
return (short) Math.round((double) getData(43) / 10);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright (c) 2010-2024 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.solax.internal.model.local.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.local.LocalConnectRawDataBean;
import org.openhab.binding.solax.internal.model.local.LocalInverterData;
import org.openhab.binding.solax.internal.model.local.X1BoostAirMiniInverterData;

/**
* The {@link X1BoostAirMiniDataParser} is the implementation that parses raw data into a LocalInverterData for the
* X1 Mini / X1 Air Mini or X1 Boost Mini inverter.
*
* @author Konstantin Polihronov - Initial contribution
*/
@NonNullByDefault
public class X1BoostAirMiniDataParser implements RawDataParser {

private static final Set<String> X1_BOOST_AIR_MINI_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_TIMESTAMP, CHANNEL_RAW_DATA, CHANNEL_INVERTER_OUTPUT_POWER,
CHANNEL_INVERTER_OUTPUT_CURRENT, CHANNEL_INVERTER_OUTPUT_VOLTAGE, CHANNEL_INVERTER_OUTPUT_FREQUENCY,
CHANNEL_TOTAL_ENERGY, CHANNEL_TODAY_ENERGY, CHANNEL_POWER_USAGE);

@Override
public LocalInverterData getData(LocalConnectRawDataBean bean) {
return new X1BoostAirMiniInverterData(bean);
}

@Override
public Set<String> getSupportedChannels() {
return X1_BOOST_AIR_MINI_SUPPORTED_CHANNELS;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import org.openhab.binding.solax.internal.model.local.X1HybridG4InverterData;

/**
* The {@link SinglePhaseDataParser} is the implementation that parses raw data into a SinglePhaseInverterData for the
* The {@link X1HybridG4DataParser} is the implementation that parses raw data into a LocalInverterData for the
* X1 Hybrid G4 inverter.
*
* @author Konstantin Polihronov - Initial contribution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import org.openhab.binding.solax.internal.model.local.X3HybridG4InverterData;

/**
* The {@link X3HybridG4DataParser} is the implementation that parses raw data into a SinglePhaseInverterData for the
* The {@link X3HybridG4DataParser} is the implementation that parses raw data into a LocalInverterData for the
* X3 Hybrid G4 inverter.
*
* @author Konstantin Polihronov - Initial contribution
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* Copyright (c) 2010-2024 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.solax.internal.local;

import static org.junit.jupiter.api.Assertions.*;

import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.openhab.binding.solax.internal.connectivity.rawdata.local.LocalConnectRawDataBean;
import org.openhab.binding.solax.internal.model.InverterType;
import org.openhab.binding.solax.internal.model.local.LocalInverterData;
import org.openhab.binding.solax.internal.model.local.parsers.RawDataParser;

/**
* The {@link AbstractParserTest} Abstract class defining the common logic for testing local connections to the various
* inverters and their parsers
*
* @author Konstantin Polihronov - Initial contribution
*/
@NonNullByDefault
public abstract class AbstractParserTest {
@Test
public void testParser() {
LocalConnectRawDataBean bean = LocalConnectRawDataBean.fromJson(getRawData());
int type = bean.getType();
InverterType inverterType = InverterType.fromIndex(type);
assertEquals(getInverterType(), inverterType, "Inverter type not recognized properly");

RawDataParser parser = inverterType.getParser();
assertNotNull(parser);

Set<String> supportedChannels = parser.getSupportedChannels();
assertFalse(supportedChannels.isEmpty());

LocalInverterData data = parser.getData(bean);
assertParserSpecific(data);
}

protected abstract InverterType getInverterType();

protected abstract String getRawData();

protected abstract void assertParserSpecific(LocalInverterData data);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* Copyright (c) 2010-2024 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.solax.internal.local;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.solax.internal.model.InverterType;
import org.openhab.binding.solax.internal.model.local.LocalInverterData;

/**
* The {@link TestX1BoostAirMiniDataParser} Simple test that tests for proper parsing against a real data from the
* inverter
*
* @author Konstantin Polihronov - Initial contribution
*/
@NonNullByDefault
public class TestX1BoostAirMiniDataParser extends AbstractParserTest {

private static final String RAW_DATA = """
{
sn:SR***,
ver:3.006.04,
type:4,
Data:[
2263,7,128,1519,0,9,0,138,0,5000,
2,15569,0,7,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,13,
0,4071,0,3456,0,0,0,0,0,0,
0,0,0,0,0,23,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:[1.500,4,XM3A15IA669518,8,2.27,0.00,1.43,0.00,0.00,1]}
""";

@Override
protected String getRawData() {
return RAW_DATA;
}

@Override
protected void assertParserSpecific(LocalInverterData data) {
assertEquals("SR***", data.getWifiSerial());
assertEquals("3.006.04", data.getWifiVersion());

assertEquals(226.3, data.getInverterVoltage()); // [0]
assertEquals(0.7, data.getInverterCurrent()); // [1]
assertEquals(128, data.getInverterOutputPower()); // [2]

assertEquals(151.9, data.getPV1Voltage()); // [3]
assertEquals(0, data.getPV2Voltage()); // [4]
assertEquals(0.9, data.getPV1Current()); // [5]
assertEquals(0, data.getPV2Current()); // [6]
assertEquals(138, data.getPV1Power()); // [7]
assertEquals(0, data.getPV2Power()); // [8]

assertEquals(50, data.getInverterFrequency()); // [9]

assertEquals(1556.9, data.getTotalEnergy()); // [11]
assertEquals(0.7, data.getTodayEnergy()); // [13]

assertEquals(346, data.getPowerUsage()); // [43]
}

@Override
protected InverterType getInverterType() {
return InverterType.X1_BOOST_AIR_MINI;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,19 @@
*/
package org.openhab.binding.solax.internal.local;

import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.openhab.binding.solax.internal.connectivity.rawdata.local.LocalConnectRawDataBean;
import org.openhab.binding.solax.internal.model.InverterType;
import org.openhab.binding.solax.internal.model.local.LocalInverterData;
import org.openhab.binding.solax.internal.model.local.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 {
public class TestX1HybridG4Parser extends AbstractParserTest {

private static final String RAW_DATA = """
{
Expand All @@ -43,17 +40,13 @@ public class TestX1HybridG4Parser {
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);
@Override
protected InverterType getInverterType() {
return InverterType.X1_HYBRID_G4;
}

LocalInverterData data = parser.getData(bean);
@Override
protected void assertParserSpecific(LocalInverterData data) {
assertEquals("SOME_SERIAL_NUMBER", data.getWifiSerial());
assertEquals("3.008.10", data.getWifiVersion());

Expand Down Expand Up @@ -81,6 +74,11 @@ public void testParser() {
assertEquals(12, data.getFeedInPower()); // [32]
}

@Override
protected String getRawData() {
return RAW_DATA;
}

// Yield_Today: Data[13] / 10,
// Yield_Total: read32BitUnsigned(Data[11], Data[12]) / 10,
// PowerDc1: Data[8],
Expand Down