diff --git a/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/InverterType.java b/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/InverterType.java index e24f1346445..d2d3fb96653 100644 --- a/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/InverterType.java +++ b/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/InverterType.java @@ -19,6 +19,7 @@ import java.util.stream.Stream; 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; @@ -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), diff --git a/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/X1BoostAirMiniInverterData.java b/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/X1BoostAirMiniInverterData.java new file mode 100644 index 00000000000..9c4e9511806 --- /dev/null +++ b/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/X1BoostAirMiniInverterData.java @@ -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); + } +} diff --git a/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/parsers/X1BoostAirMiniDataParser.java b/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/parsers/X1BoostAirMiniDataParser.java new file mode 100644 index 00000000000..4b680b609fc --- /dev/null +++ b/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/parsers/X1BoostAirMiniDataParser.java @@ -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 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 getSupportedChannels() { + return X1_BOOST_AIR_MINI_SUPPORTED_CHANNELS; + } +} diff --git a/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/parsers/X1HybridG4DataParser.java b/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/parsers/X1HybridG4DataParser.java index dc6ac43f264..2804f1dbbff 100644 --- a/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/parsers/X1HybridG4DataParser.java +++ b/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/parsers/X1HybridG4DataParser.java @@ -22,7 +22,7 @@ import org.openhab.binding.solax.internal.model.local.LocalInverterData; 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 diff --git a/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/parsers/X3HybridG4DataParser.java b/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/parsers/X3HybridG4DataParser.java index 781a5de752f..3cc4f11f5e1 100644 --- a/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/parsers/X3HybridG4DataParser.java +++ b/bundles/org.openhab.binding.solax/src/main/java/org/openhab/binding/solax/internal/model/local/parsers/X3HybridG4DataParser.java @@ -22,7 +22,7 @@ import org.openhab.binding.solax.internal.model.local.LocalInverterData; 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 diff --git a/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/AbstractParserTest.java b/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/AbstractParserTest.java new file mode 100644 index 00000000000..791e304ba42 --- /dev/null +++ b/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/AbstractParserTest.java @@ -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 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); +} diff --git a/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/TestX1BoostAirMiniDataParser.java b/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/TestX1BoostAirMiniDataParser.java new file mode 100644 index 00000000000..66f6f4bcff3 --- /dev/null +++ b/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/TestX1BoostAirMiniDataParser.java @@ -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; + } +} diff --git a/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/TestX1HybridG4Parser.java b/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/TestX1HybridG4Parser.java index a2dcc3400a4..f2d20324693 100644 --- a/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/TestX1HybridG4Parser.java +++ b/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/TestX1HybridG4Parser.java @@ -12,14 +12,11 @@ */ 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 @@ -27,7 +24,7 @@ import org.openhab.binding.solax.internal.model.local.parsers.RawDataParser; * @author Konstantin Polihronov - Initial contribution */ @NonNullByDefault -public class TestX1HybridG4Parser { +public class TestX1HybridG4Parser extends AbstractParserTest { private static final String RAW_DATA = """ { @@ -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"); + @Override + protected InverterType getInverterType() { + return InverterType.X1_HYBRID_G4; + } - RawDataParser parser = inverterType.getParser(); - assertNotNull(parser); - - LocalInverterData data = parser.getData(bean); + @Override + protected void assertParserSpecific(LocalInverterData data) { assertEquals("SOME_SERIAL_NUMBER", data.getWifiSerial()); assertEquals("3.008.10", data.getWifiVersion()); @@ -81,6 +74,11 @@ public class TestX1HybridG4Parser { 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], diff --git a/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/TestX3HybridG4Parser.java b/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/TestX3HybridG4Parser.java index 951d725d1a8..a30172c9818 100644 --- a/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/TestX3HybridG4Parser.java +++ b/bundles/org.openhab.binding.solax/src/test/java/org/openhab/binding/solax/internal/local/TestX3HybridG4Parser.java @@ -12,14 +12,11 @@ */ 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 TestX3HybridG4Parser} simple test that tests for proper parsing against a real data from the inverter @@ -27,9 +24,9 @@ import org.openhab.binding.solax.internal.model.local.parsers.RawDataParser; * @author Konstantin Polihronov - Initial contribution */ @NonNullByDefault -public class TestX3HybridG4Parser { +public class TestX3HybridG4Parser extends AbstractParserTest { - String rawData = """ + private static final String RAW_DATA = """ { sn:XYZ, ver:3.005.01, @@ -50,17 +47,13 @@ public class TestX3HybridG4Parser { } """; - @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"); + @Override + protected InverterType getInverterType() { + return InverterType.X3_HYBRID_G4; + } - RawDataParser parser = inverterType.getParser(); - assertNotNull(parser); - - LocalInverterData data = parser.getData(bean); + @Override + protected void assertParserSpecific(LocalInverterData data) { assertEquals("XYZ", data.getWifiSerial()); assertEquals("3.005.01", data.getWifiVersion()); @@ -114,4 +107,9 @@ public class TestX3HybridG4Parser { assertEquals(6.2, data.getTodayBatteryDischargeEnergy()); // [78] / 100 assertEquals(11, data.getTodayBatteryChargeEnergy()); // [79] / 100 } + + @Override + protected String getRawData() { + return RAW_DATA; + } }