diff --git a/bundles/org.openhab.binding.growatt/README.md b/bundles/org.openhab.binding.growatt/README.md index 2ff4e17136d..ecfb0adb0e9 100644 --- a/bundles/org.openhab.binding.growatt/README.md +++ b/bundles/org.openhab.binding.growatt/README.md @@ -142,6 +142,25 @@ The list of all possible channels is as follows: | charge-va | Number:Power | Charging reactive power. | yes | | inverter-clock-offset | Number:Time | Time offset of inverter clock vs. OH system clock. | yes | | inverter-fan-speed | Number:Dimensionless | Inverter fan speed percent. | yes | +| pv3-voltage | Number:ElectricPotential | Voltage from solar panel string #3. | yes | +| pv3-current | Number:ElectricCurrent | Current from solar panel string #3. | yes | +| pv3-power | Number:Power | Power from solar panel string #3. | yes | +| pv4-voltage | Number:ElectricPotential | Voltage from solar panel string #4. | yes | +| pv4-current | Number:ElectricCurrent | Current from solar panel string #4. | yes | +| pv4-power | Number:Power | Power from solar panel string #4. | yes | +| pv3-energy-today | Number:Energy | Solar DC energy collected by string #3 today. | yes | +| pv3-energy-total | Number:Energy | Total solar DC energy collected by string #3. | yes | +| power-factor | Number:Percent | Electrical power factor | yes | +| eps-voltage-r | Number:ElectricPotential | Emergency Power Supply voltage (phase #R). | yes | +| eps-voltage-s | Number:ElectricPotential | Emergency Power Supply voltage (phase #S). | yes | +| eps-voltage-t | Number:ElectricPotential | Emergency Power Supply voltage (phase #T). | yes | +| eps-current-r | Number:ElectricCurrent | Emergency Power Supply current (phase #R). | yes | +| eps-current-s | Number:ElectricCurrent | Emergency Power Supply current (phase #S). | yes | +| eps-current-t | Number:ElectricCurrent | Emergency Power Supply current (phase #T). | yes | +| eps-power | Number:Power | Total Emergency Power Supply power. | yes | +| eps-power-r | Number:Power | Emergency Power Supply power (phase #R). | yes | +| eps-power-s | Number:Power | Emergency Power Supply power (phase #S). | yes | +| eps-power-t | Number:Power | Emergency Power Supply power (phase #T). | yes | ## Rule Actions diff --git a/bundles/org.openhab.binding.growatt/src/main/java/org/openhab/binding/growatt/internal/GrowattChannels.java b/bundles/org.openhab.binding.growatt/src/main/java/org/openhab/binding/growatt/internal/GrowattChannels.java index 09ad616fe35..ec20af235c3 100644 --- a/bundles/org.openhab.binding.growatt/src/main/java/org/openhab/binding/growatt/internal/GrowattChannels.java +++ b/bundles/org.openhab.binding.growatt/src/main/java/org/openhab/binding/growatt/internal/GrowattChannels.java @@ -14,6 +14,9 @@ package org.openhab.binding.growatt.internal; import java.util.AbstractMap; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.measure.Unit; @@ -206,11 +209,158 @@ public class GrowattChannels { // inverter new AbstractMap.SimpleEntry("inverter-current", new UoM(Units.AMPERE, 10)), - new AbstractMap.SimpleEntry("inverter-fan-speed", new UoM(Units.PERCENT, 1)) + new AbstractMap.SimpleEntry("inverter-fan-speed", new UoM(Units.PERCENT, 1)), + + /* + * ============== CHANNELS ADDED IN PR #17810 ============== + */ + + // DC electric data for strings #3 and #4 + new AbstractMap.SimpleEntry("pv3-voltage", new UoM(Units.VOLT, 10)), + new AbstractMap.SimpleEntry("pv3-current", new UoM(Units.AMPERE, 10)), + new AbstractMap.SimpleEntry("pv3-power", new UoM(Units.WATT, 10)), + + new AbstractMap.SimpleEntry("pv4-voltage", new UoM(Units.VOLT, 10)), + new AbstractMap.SimpleEntry("pv4-current", new UoM(Units.AMPERE, 10)), + new AbstractMap.SimpleEntry("pv4-power", new UoM(Units.WATT, 10)), + + // solar DC pv energy + new AbstractMap.SimpleEntry("pv3-energy-today", new UoM(Units.KILOWATT_HOUR, 10)), + new AbstractMap.SimpleEntry("pv3-energy-total", new UoM(Units.KILOWATT_HOUR, 10)), + + // power factor + new AbstractMap.SimpleEntry("power-factor", new UoM(Units.PERCENT, 10)), + + // emergency power supply (eps) + new AbstractMap.SimpleEntry("eps-voltage-r", new UoM(Units.VOLT, 10)), + new AbstractMap.SimpleEntry("eps-voltage-s", new UoM(Units.VOLT, 10)), + new AbstractMap.SimpleEntry("eps-voltage-t", new UoM(Units.VOLT, 10)), + + new AbstractMap.SimpleEntry("eps-current-r", new UoM(Units.AMPERE, 10)), + new AbstractMap.SimpleEntry("eps-current-s", new UoM(Units.AMPERE, 10)), + new AbstractMap.SimpleEntry("eps-current-t", new UoM(Units.AMPERE, 10)), + + new AbstractMap.SimpleEntry("eps-power", new UoM(Units.WATT, 10)), + new AbstractMap.SimpleEntry("eps-power-r", new UoM(Units.WATT, 10)), + new AbstractMap.SimpleEntry("eps-power-s", new UoM(Units.WATT, 10)), + new AbstractMap.SimpleEntry("eps-power-t", new UoM(Units.WATT, 10)) + // ); public static Map getMap() { return GrowattChannels.CHANNEL_ID_UOM_MAP; } + + /** + * Map of Growatt JSON field names that are not used in the creation of device Channels. + */ + @SuppressWarnings("unchecked") + public static final Map> UNUSED_FIELDS = Stream.of(new Object[][] { + // @formatter:off + + // simple inverter + { "simple", Set.of( + "datalogserial", + "pvserial") }, + + // sph inverter + { "sph", Set.of( + "datalogserial", + "pvserial") }, + + // spf inverter + { "spf", Set.of( + "datalogserial", + "pvserial") }, + + // mid inverter + { "mid", Set.of( + "datalogserial", + "pvserial", + "deratingmode", + "iso", + "dcir", + "dcis", + "dcit", + "gfci", + "ipf", + "realoppercent", + "opfullwatt", + "standbyflag", + "warningcode", + "invstartdelaytime", + "bdconoffstate", + "drycontactstate", + "priority", + "epsfac", + "dcv", + "bdc1_sysstatemode", + "bdc1_faultcode", + "bdc1_warncode", + "bdc1_vbat", + "bdc1_ibat", + "bdc1_soc", + "bdc1_vbus1", + "bdc1_vbus2", + "bdc1_ibb", + "bdc1_illc", + "bdc1_tempb", + "bdc1_edischrtotal", + "bdc1_echrtotal", + "bdc1_flag", + "bdc2_sysstatemode", + "bdc2_faultcode", + "bdc2_warncode", + "bdc2_vbat", + "bdc2_ibat", + "bdc2_soc", + "bdc2_vbus1", + "bdc2_vbus2", + "bdc2_ibb", + "bdc2_illc", + "bdc2_tempa", + "bdc2_tempb", + "bdc2_pdischr", + "bdc2_pchr", + "bdc2_edischrtotal", + "bdc2_echrtotal", + "bdc2_flag", + "bms_status", + "bms_error", + "bms_warninfo", + "bms_batterycurr", + "bms_batterytemp", + "bms_maxcurr", + "bms_deltavolt", + "bms_cyclecnt", + "bms_soh", + "bms_constantvolt", + "bms_bms_info", + "bms_packinfo", + "bms_usingcap", + "bms_fw", + "bms_mcuversion", + "bms_commtype") }, + + // smart meter + { "meter", Set.of( + "datalogserial", + "pvserial", + "pvstatus", + "app_power_l1", + "app_power_l2", + "app_power_l3", + "react_power_l1", + "react_power_l2", + "react_power_l3", + "powerfactor_l1", + "powerfactor_l2", + "powerfactor_l3", + "pos_act_power", + "rev_act_power", + "app_power") }, + + // @formatter:on + }).collect(Collectors.toMap(objects -> (String) objects[0], objects -> (Set) objects[1])); } diff --git a/bundles/org.openhab.binding.growatt/src/main/java/org/openhab/binding/growatt/internal/dto/GrottValues.java b/bundles/org.openhab.binding.growatt/src/main/java/org/openhab/binding/growatt/internal/dto/GrottValues.java index ad419e26914..ef1f17be195 100644 --- a/bundles/org.openhab.binding.growatt/src/main/java/org/openhab/binding/growatt/internal/dto/GrottValues.java +++ b/bundles/org.openhab.binding.growatt/src/main/java/org/openhab/binding/growatt/internal/dto/GrottValues.java @@ -58,7 +58,7 @@ public class GrottValues { public @Nullable @SerializedName(value = "pv2watt", alternate = { "ppv2" }) Integer pv2_power; // AC mains electric data (1-phase resp. 3-phase) - public @Nullable @SerializedName(value = "pvfrequentie", alternate = { "line_freq", "outputfreq" }) Integer grid_frequency; + public @Nullable @SerializedName(value = "pvfrequentie", alternate = { "line_freq", "outputfreq", "frequency" }) Integer grid_frequency; public @Nullable @SerializedName(value = "pvgridvoltage", alternate = { "grid_volt", "outputvolt", "voltage_l1" }) Integer grid_voltage_r; public @Nullable @SerializedName(value = "pvgridvoltage2", alternate = { "voltage_l2" }) Integer grid_voltage_s; public @Nullable @SerializedName(value = "pvgridvoltage3", alternate = { "voltage_l3" }) Integer grid_voltage_t; @@ -110,10 +110,10 @@ public class GrottValues { // solar DC pv energy public @Nullable @SerializedName(value = "epvtoday") Integer pv_energy_today; - public @Nullable @SerializedName(value = "epv1today", alternate = { "epv1tod" }) Integer pv1_energy_today; + public @Nullable @SerializedName(value = "epv1today", alternate = { "epv1tod", "epv1today " }) Integer pv1_energy_today; // alternate intentionally has trailing space public @Nullable @SerializedName(value = "epv2today", alternate = { "epv2tod" }) Integer pv2_energy_today; - public @Nullable @SerializedName(value = "epvtotal") Integer pv_energy_total; + public @Nullable @SerializedName(value = "epvtotal", alternate = { "epvtotal " }) Integer pv_energy_total; // alternate intentionally has trailing space public @Nullable @SerializedName(value = "epv1total", alternate = { "epv1tot" }) Integer pv1_energy_total; public @Nullable @SerializedName(value = "epv2total", alternate = { "epv2tot" }) Integer pv2_energy_total; @@ -202,5 +202,39 @@ public class GrottValues { public @Nullable @SerializedName(value = "Inv_Curr") Integer inverter_current; public @Nullable @SerializedName(value = "invfanspeed") Integer inverter_fan_speed; + /* + * ============== CHANNELS ADDED IN PR #17810 ============== + */ + + // DC electric data for strings #3 and #4 + public @Nullable @SerializedName(value = "pv3voltage") Integer pv3_voltage; + public @Nullable @SerializedName(value = "pv3current") Integer pv3_current; + public @Nullable @SerializedName(value = "pv3watt") Integer pv3_power; + + public @Nullable @SerializedName(value = "pv4voltage") Integer pv4_voltage; + public @Nullable @SerializedName(value = "pv4current") Integer pv4_current; + public @Nullable @SerializedName(value = "pv4watt") Integer pv4_power; + + // solar DC pv energy + public @Nullable @SerializedName(value = "epv3today") Integer pv3_energy_today; + public @Nullable @SerializedName(value = "epv3total") Integer pv3_energy_total; + + // power factor + public @Nullable @SerializedName(value = "pf", alternate = { "powerfactor" }) Integer power_factor; + + // emergency power supply (eps) + public @Nullable @SerializedName(value = "epsvac1") Integer eps_voltage_r; + public @Nullable @SerializedName(value = "epsvac2") Integer eps_voltage_s; + public @Nullable @SerializedName(value = "epsvac3") Integer eps_voltage_t; + + public @Nullable @SerializedName(value = "epsiac1") Integer eps_current_r; + public @Nullable @SerializedName(value = "epsiac2") Integer eps_current_s; + public @Nullable @SerializedName(value = "epsiac3") Integer eps_current_t; + + public @Nullable @SerializedName(value = "epspac") Integer eps_power; + public @Nullable @SerializedName(value = "epspac1") Integer eps_power_r; + public @Nullable @SerializedName(value = "epspac2") Integer eps_power_s; + public @Nullable @SerializedName(value = "epspac3") Integer eps_power_t; + // @formatter:on } diff --git a/bundles/org.openhab.binding.growatt/src/main/resources/OH-INF/i18n/growatt.properties b/bundles/org.openhab.binding.growatt/src/main/resources/OH-INF/i18n/growatt.properties index 055bf3b1ccc..585ab4e7c7a 100644 --- a/bundles/org.openhab.binding.growatt/src/main/resources/OH-INF/i18n/growatt.properties +++ b/bundles/org.openhab.binding.growatt/src/main/resources/OH-INF/i18n/growatt.properties @@ -45,6 +45,26 @@ thing-type.growatt.inverter.channel.discharge-power.label = Discharge Power thing-type.growatt.inverter.channel.discharge-power.description = Discharge power from battery. thing-type.growatt.inverter.channel.discharge-va.label = Discharge VA thing-type.growatt.inverter.channel.discharge-va.description = Discharge VA from battery. +thing-type.growatt.inverter.channel.eps-current-r.label = EPS Current #R +thing-type.growatt.inverter.channel.eps-current-r.description = Emergency Power Supply current (phase #R). +thing-type.growatt.inverter.channel.eps-current-s.label = EPS Current #S +thing-type.growatt.inverter.channel.eps-current-s.description = Emergency Power Supply current (phase #S). +thing-type.growatt.inverter.channel.eps-current-t.label = EPS Current #T +thing-type.growatt.inverter.channel.eps-current-t.description = Emergency Power Supply current (phase #T). +thing-type.growatt.inverter.channel.eps-power.label = EPS Power +thing-type.growatt.inverter.channel.eps-power.description = Total Emergency Power Supply power. +thing-type.growatt.inverter.channel.eps-power-r.label = EPS Power #R +thing-type.growatt.inverter.channel.eps-power-r.description = Emergency Power Supply power (phase #R). +thing-type.growatt.inverter.channel.eps-power-s.label = EPS Power #S +thing-type.growatt.inverter.channel.eps-power-s.description = Emergency Power Supply power (phase #S). +thing-type.growatt.inverter.channel.eps-power-t.label = EPS Power #T +thing-type.growatt.inverter.channel.eps-power-t.description = Emergency Power Supply power (phase #T). +thing-type.growatt.inverter.channel.eps-voltage-r.label = EPS Voltage #R +thing-type.growatt.inverter.channel.eps-voltage-r.description = Emergency Power Supply voltage (phase #R). +thing-type.growatt.inverter.channel.eps-voltage-s.label = EPS Voltage #S +thing-type.growatt.inverter.channel.eps-voltage-s.description = Emergency Power Supply voltage (phase #S). +thing-type.growatt.inverter.channel.eps-voltage-t.label = EPS Voltage #T +thing-type.growatt.inverter.channel.eps-voltage-t.description = Emergency Power Supply voltage (phase #T). thing-type.growatt.inverter.channel.erac-today.label = Reactive Energy Today thing-type.growatt.inverter.channel.erac-today.description = Reactive energy supplied today. thing-type.growatt.inverter.channel.erac-total.label = Total Reactive Energy @@ -137,6 +157,8 @@ thing-type.growatt.inverter.channel.n-bus-voltage.label = N Bus Voltage thing-type.growatt.inverter.channel.n-bus-voltage.description = N Bus voltage. thing-type.growatt.inverter.channel.p-bus-voltage.label = P Bus Voltage thing-type.growatt.inverter.channel.p-bus-voltage.description = P Bus voltage. +thing-type.growatt.inverter.channel.power-factor.label = Power Factor +thing-type.growatt.inverter.channel.power-factor.description = Electrical power factor thing-type.growatt.inverter.channel.pv-boost-temperature.label = Boost Temperature thing-type.growatt.inverter.channel.pv-boost-temperature.description = Boost temperature. thing-type.growatt.inverter.channel.pv-energy-today.label = DC Energy Today @@ -171,6 +193,22 @@ thing-type.growatt.inverter.channel.pv2-temperature.label = Solar Panel Temperat thing-type.growatt.inverter.channel.pv2-temperature.description = Temperature of the solar panels (string #2). thing-type.growatt.inverter.channel.pv2-voltage.label = String #2 Voltage thing-type.growatt.inverter.channel.pv2-voltage.description = Voltage from solar panel string #2. +thing-type.growatt.inverter.channel.pv3-current.label = String #3 Current +thing-type.growatt.inverter.channel.pv3-current.description = Current from solar panel string #3. +thing-type.growatt.inverter.channel.pv3-energy-today.label = DC Energy #3 Today +thing-type.growatt.inverter.channel.pv3-energy-today.description = Solar DC energy collected by string #3. +thing-type.growatt.inverter.channel.pv3-energy-total.label = DC Energy #3 Total +thing-type.growatt.inverter.channel.pv3-energy-total.description = Total solar DC energy collected by string #3. +thing-type.growatt.inverter.channel.pv3-power.label = String #3 Power +thing-type.growatt.inverter.channel.pv3-power.description = Power from solar panel string #3. +thing-type.growatt.inverter.channel.pv3-voltage.label = String #3 Voltage +thing-type.growatt.inverter.channel.pv3-voltage.description = Voltage from solar panel string #3. +thing-type.growatt.inverter.channel.pv4-current.label = String #4 Current +thing-type.growatt.inverter.channel.pv4-current.description = Current from solar panel string #4. +thing-type.growatt.inverter.channel.pv4-power.label = String #4 Power +thing-type.growatt.inverter.channel.pv4-power.description = Power from solar panel string #4. +thing-type.growatt.inverter.channel.pv4-voltage.label = String #4 Voltage +thing-type.growatt.inverter.channel.pv4-voltage.description = Voltage from solar panel string #4. thing-type.growatt.inverter.channel.rac.label = Reactive Power thing-type.growatt.inverter.channel.rac.description = Reactive power output. thing-type.growatt.inverter.channel.sp-bus-voltage.label = SP Bus Voltage diff --git a/bundles/org.openhab.binding.growatt/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.growatt/src/main/resources/OH-INF/thing/thing-types.xml index 5b99ab7f495..c5c5f531110 100644 --- a/bundles/org.openhab.binding.growatt/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.growatt/src/main/resources/OH-INF/thing/thing-types.xml @@ -480,10 +480,99 @@ Inverter fan speed. + + + + + + Voltage from solar panel string #3. + + + + Current from solar panel string #3. + + + + Power from solar panel string #3. + + + + + Voltage from solar panel string #4. + + + + Current from solar panel string #4. + + + + Power from solar panel string #4. + + + + + + Solar DC energy collected by string #3 today. + + + + Total solar DC energy collected by string #3. + + + + + + Electrical power factor + + + + + + Emergency Power Supply voltage (phase #R). + + + + Emergency Power Supply voltage (phase #S). + + + + Emergency Power Supply voltage (phase #T). + + + + + Emergency Power Supply current (phase #R). + + + + Emergency Power Supply current (phase #S). + + + + Emergency Power Supply current (phase #T). + + + + + Total Emergency Power Supply power. + + + + Emergency Power Supply power (phase #R). + + + + Emergency Power Supply power (phase #S). + + + + Emergency Power Supply power (phase #T). + + - 1 + 2 diff --git a/bundles/org.openhab.binding.growatt/src/main/resources/OH-INF/update/instructions.xml b/bundles/org.openhab.binding.growatt/src/main/resources/OH-INF/update/instructions.xml index 3856eed4cd4..36fec773012 100644 --- a/bundles/org.openhab.binding.growatt/src/main/resources/OH-INF/update/instructions.xml +++ b/bundles/org.openhab.binding.growatt/src/main/resources/OH-INF/update/instructions.xml @@ -49,6 +49,107 @@ Inverter fan speed. + + + + + + growatt:advanced-electric-voltage + + Voltage from solar panel string #3. + + + growatt:advanced-electric-current + + Current from solar panel string #3. + + + growatt:advanced-electric-power + + Power from solar panel string #3. + + + growatt:advanced-electric-voltage + + Voltage from solar panel string #4. + + + growatt:advanced-electric-current + + Current from solar panel string #4. + + + growatt:advanced-electric-power + + Power from solar panel string #4. + + + growatt:advanced-electric-energy + + Solar DC energy collected by string #3 today. + + + growatt:advanced-electric-energy + + Total solar DC energy collected by string #3. + + + growatt:advanced-percent + + Electrical power factor + + + growatt:advanced-electric-voltage + + Emergency Power Supply voltage (phase #R). + + + growatt:advanced-electric-voltage + + Emergency Power Supply voltage (phase #S). + + + growatt:advanced-electric-voltage + + Emergency Power Supply voltage (phase #T). + + + growatt:advanced-electric-current + + Emergency Power Supply current (phase #R). + + + growatt:advanced-electric-current + + Emergency Power Supply current (phase #S). + + + growatt:advanced-electric-current + + Emergency Power Supply current (phase #T). + + + growatt:advanced-electric-power + + Total Emergency Power Supply power. + + + growatt:advanced-electric-power + + Emergency Power Supply power (phase #R). + + + growatt:advanced-electric-power + + Emergency Power Supply power (phase #S). + + + growatt:advanced-electric-power + + Emergency Power Supply power (phase #T). + + + diff --git a/bundles/org.openhab.binding.growatt/src/test/java/org/openhab/binding/growatt/test/GrowattTest.java b/bundles/org.openhab.binding.growatt/src/test/java/org/openhab/binding/growatt/test/GrowattTest.java index 45f790c614e..528c9ce2c59 100644 --- a/bundles/org.openhab.binding.growatt/src/test/java/org/openhab/binding/growatt/test/GrowattTest.java +++ b/bundles/org.openhab.binding.growatt/src/test/java/org/openhab/binding/growatt/test/GrowattTest.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.stream.Collectors; import javax.net.ssl.SSLSession; @@ -240,6 +241,8 @@ public class GrowattTest { testJsonFieldsMappedToDto("simple"); testJsonFieldsMappedToDto("sph"); testJsonFieldsMappedToDto("spf"); + testJsonFieldsMappedToDto("meter"); + testJsonFieldsMappedToDto("mid"); } /** @@ -255,7 +258,8 @@ public class GrowattTest { String json = load(fileName); JsonParser.parseString(json).getAsJsonObject().get("values").getAsJsonObject().entrySet().forEach(e -> { String key = e.getKey(); - if (!"datalogserial".equals(key) && !"pvserial".equals(key)) { + assertTrue(GrowattChannels.UNUSED_FIELDS.containsKey(fileName)); + if (!Objects.requireNonNull(GrowattChannels.UNUSED_FIELDS.get(fileName)).contains(key)) { JsonObject testJsonObject = new JsonObject(); testJsonObject.add(key, e.getValue()); GrottValues testDto = gson.fromJson(testJsonObject, GrottValues.class); @@ -362,7 +366,7 @@ public class GrowattTest { Map> channelStates = GrottValuesHelper.getChannelStates(grottValues); assertNotNull(channelStates); - assertEquals(64, channelStates.size()); + assertEquals(85, channelStates.size()); assertEquals(QuantityType.valueOf(-36.5, Units.WATT), channelStates.get("inverter-power")); assertEquals(QuantityType.valueOf(11, Units.PERCENT), channelStates.get("battery-soc")); @@ -379,7 +383,7 @@ public class GrowattTest { Map> channelStates = GrottValuesHelper.getChannelStates(grottValues); assertNotNull(channelStates); - assertEquals(16, channelStates.size()); + assertEquals(18, channelStates.size()); assertEquals(QuantityType.valueOf(809.8, Units.WATT), channelStates.get("import-power")); assertEquals(QuantityType.valueOf(171.0, Units.WATT), channelStates.get("import-power-s"));