diff --git a/cnf/build.bnd b/cnf/build.bnd index 56e785b3827..cd02958c8e5 100644 --- a/cnf/build.bnd +++ b/cnf/build.bnd @@ -85,7 +85,7 @@ testpath: \ Edge_Controller_PVinverter;member=${filter;${p};io\.openems\.edge\.controller\.pvinverter\..*},\ Edge_Ess;member=${filter;${p};io\.openems\.edge\.ess\..*},\ Edge_Evcs;member=${filter;${p};io\.openems\.edge\.evcs\..*|io\.openems\.wrapper\.eu\.chargetime\.ocpp},\ - Edge_Multiple;member=${filter;${p};io\.openems\.edge\.fenecon\..*|io\.openems\.edge\.goodwe\..et|io\.openems\.edge\.kostal\.piko|io\.openems\.edge\.tesla\.*|io\.openems\.edge\.solaredge},\ + Edge_Multiple;member=${filter;${p};io\.openems\.edge\.fenecon\..*|io\.openems\.edge\.goodwe|io\.openems\.edge\.kostal\.piko|io\.openems\.edge\.tesla\.*|io\.openems\.edge\.solaredge},\ Edge_IO;member=${filter;${p};io\.openems\.edge\.io\..*|io\.openems\.edge\.controller\.channelthreshold|io\.openems\.edge\.controller\.chp\..*|io\.openems\.edge\.controller\.highloadtimeslot},\ Edge_Meter;member=${filter;${p};io\.openems\.edge\.meter\..*},\ Edge_Predictor;member=${filter;${p};io\.openems\.edge\.predictor\..*},\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index f81379b20c9..bb84a5462e1 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -103,7 +103,7 @@ bnd.identity;id='io.openems.edge.fenecon.dess',\ bnd.identity;id='io.openems.edge.fenecon.mini',\ bnd.identity;id='io.openems.edge.fenecon.pro',\ - bnd.identity;id='io.openems.edge.goodwe.et',\ + bnd.identity;id='io.openems.edge.goodwe',\ bnd.identity;id='io.openems.edge.io.kmtronic',\ bnd.identity;id='io.openems.edge.io.revpi',\ bnd.identity;id='io.openems.edge.io.shelly',\ @@ -229,7 +229,7 @@ io.openems.edge.fenecon.dess;version=snapshot,\ io.openems.edge.fenecon.mini;version=snapshot,\ io.openems.edge.fenecon.pro;version=snapshot,\ - io.openems.edge.goodwe.et;version=snapshot,\ + io.openems.edge.goodwe;version=snapshot,\ io.openems.edge.io.api;version=snapshot,\ io.openems.edge.io.kmtronic;version=snapshot,\ io.openems.edge.io.revpi;version=snapshot,\ diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/EssChannelId.java b/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/EssChannelId.java deleted file mode 100644 index 5cc003c67c2..00000000000 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/EssChannelId.java +++ /dev/null @@ -1,680 +0,0 @@ -package io.openems.edge.goodwe.et.ess; - -import io.openems.common.channel.AccessMode; -import io.openems.common.channel.Level; -import io.openems.common.channel.Unit; -import io.openems.common.types.OpenemsType; -import io.openems.edge.common.channel.ChannelId; -import io.openems.edge.common.channel.Doc; - -public enum EssChannelId implements ChannelId { - MODBUS_PROTOCOL_VERSION(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - RATED_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - AC_OUTPUT_TYPE(Doc.of(OutputTypeAC.values())), // - SERIAL_NUMBER(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - DEVICE_TYPE(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - DSP1_SOFTWARE_VERSION(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - DSP2_SOFTWARE_VERSION(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - DSP_SPN_VERSION(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - ARM_SOFTWARE_VERSION(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - ARM_SVN_VERSION(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - DSP_INTERNAL_FIRMWARE_VERSION(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - ARM_INTERNAL_FIRMWARE_VERSION(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - SIMCCID(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - - // Running Data - RTC_YEAR_MONTH(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - RTC_DATE_HOUR(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - RTC_MINUTE_SECOND(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), - V_PV3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), - I_PV3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.AMPERE).accessMode(AccessMode.READ_ONLY)), - P_PV3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), - V_PV4(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), - I_PV4(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.AMPERE).accessMode(AccessMode.READ_ONLY)), - P_PV4(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), - PV_MODE(Doc.of(WorkMode.values())), // - TOTAL_INV_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - AC_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - AC_REACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT_AMPERE_REACTIVE).accessMode(AccessMode.READ_ONLY)), // - AC_APPARENT_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT_AMPERE).accessMode(AccessMode.READ_ONLY)), // - BACK_UP_V_LOAD_R(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), - BACK_UP_I_LOAD_R(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.AMPERE).accessMode(AccessMode.READ_ONLY)), - BACK_UP_F_LOAD_R(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HERTZ).accessMode(AccessMode.READ_ONLY)), - LOAD_MODE_R(Doc.of(LoadMode.values())), // - BACK_UP_P_LOAD_R(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), - BACK_UP_V_LOAD_S(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), - BACK_UP_I_LOAD_S(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.AMPERE).accessMode(AccessMode.READ_ONLY)), - BACK_UP_F_LOAD_S(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HERTZ).accessMode(AccessMode.READ_ONLY)), - LOAD_MODE_S(Doc.of(LoadMode.values())), // - BACK_UP_P_LOAD_S(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), - BACK_UP_V_LOAD_T(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), - BACK_UP_I_LOAD_T(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.AMPERE).accessMode(AccessMode.READ_ONLY)), - BACK_UP_F_LOAD_T(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HERTZ).accessMode(AccessMode.READ_ONLY)), - LOAD_MODE_T(Doc.of(LoadMode.values())), // - BACK_UP_P_LOAD_T(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), - P_LOAD_R(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - P_LOAD_S(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - P_LOAD_T(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - TOTAL_BACK_UP_LOAD(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - TOTAL_LOAD_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - UPS_LOAD_PERCENT(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.READ_ONLY)), // - AIR_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.DEGREE_CELSIUS).accessMode(AccessMode.READ_ONLY)), // - MODULE_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.DEGREE_CELSIUS).accessMode(AccessMode.READ_ONLY)), // - RADIATOR_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.DEGREE_CELSIUS).accessMode(AccessMode.READ_ONLY)), // - FUNCTION_BIT_VALUE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - BUS_VOLTAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), // - NBUS_VOLTAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), // - V_BATTERY1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), // - I_BATTERY1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), // - P_BATTERY1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - BATTERY_MODE(Doc.of(BatteryMode.values())), // - WARNING_CODE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - SAFETY_COUNTRY(Doc.of(SafetyCountry.values())), // . - WORK_MODE(Doc.of(WorkMode.values())), // - OPERATION_MODE(Doc.of(OperationMode.values())), // - - // Error Message - STATE_0(Doc.of(Level.FAULT).text("The GFCI detecting circuit is abnormal")), // - STATE_1(Doc.of(Level.FAULT).text("The output current sensor is abnormal")), // - STATE_2(Doc.of(Level.WARNING).text("TBD")), // - STATE_3(Doc.of(Level.FAULT).text("DCI Consistency Failure")), // - STATE_4(Doc.of(Level.FAULT).text("GFCI Consistency Failure")), // - STATE_5(Doc.of(Level.WARNING).text("TBD")), // - STATE_6(Doc.of(Level.FAULT).text("GFCI Device Failure")), // - STATE_7(Doc.of(Level.FAULT).text("Relay Device Failure")), // - STATE_8(Doc.of(Level.FAULT).text("AC HCT Failure")), // - STATE_9(Doc.of(Level.FAULT).text("Utility Loss")), // - STATE_10(Doc.of(Level.FAULT).text("Gournd I Failure")), // - STATE_11(Doc.of(Level.WARNING).text("DC Bus High")), // - STATE_12(Doc.of(Level.FAULT).text("Internal Fan Failure(Back-Up Over Load for ES)")), // - STATE_13(Doc.of(Level.WARNING).text("Over Temperature")), // - STATE_14(Doc.of(Level.FAULT).text("Auto Test Failure")), // - STATE_15(Doc.of(Level.WARNING).text("PV Over Voltage")), // - STATE_16(Doc.of(Level.FAULT).text("External Fan Failure")), // - STATE_17(Doc.of(Level.FAULT).text("Vac Failure")), // - STATE_18(Doc.of(Level.FAULT).text("Isolation Failure")), // - STATE_19(Doc.of(Level.WARNING).text("DC Injection High")), // - STATE_20(Doc.of(Level.WARNING).text("TBD")), // - STATE_21(Doc.of(Level.WARNING).text("TBD")), // - STATE_22(Doc.of(Level.FAULT).text("Fac Consistency Failure")), // - STATE_23(Doc.of(Level.FAULT).text("Vac Consistency Failure")), // - STATE_24(Doc.of(Level.WARNING).text("TBD")), // - STATE_25(Doc.of(Level.WARNING).text("Relay Check Failure")), // - STATE_26(Doc.of(Level.WARNING).text("TBD")), // - STATE_27(Doc.of(Level.WARNING).text("TBD")), // - STATE_28(Doc.of(Level.WARNING).text("TBD")), // - STATE_29(Doc.of(Level.FAULT).text("Fac Failure")), // - STATE_30(Doc.of(Level.FAULT).text("EEPROM R/W Failure")), // - STATE_31(Doc.of(Level.FAULT).text("Internal Communication Failure")), // - - PV_E_TOTAL(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - PV_E_DAY(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - E_TOTAL(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - H_TOTAL(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HOUR).accessMode(AccessMode.READ_ONLY)), // - E_DAY_SELL(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - E_TOTAL_BUY(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - E_DAY_BUY(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - E_TOTAL_LOAD(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - E_LOAD_DAY(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - E_BATTERY_CHARGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - E_CHARGE_DAY(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - E_BATTERY_DISCHARGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - E_DISCHARGE_DAY(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - BATT_STRINGS(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - CPLD_WARNING_CODE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - W_CHARGER_CTRL_FLAG(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - DERATE_FLAG(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - DERATE_FROZEN_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - DIAG_STATUS_H(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - DIAG_STATUS_L(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - - // External Communication Data (ARM) - COM_MODE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - RSSI(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - MANIFACTURE_CODE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - B_METER_COMMUNICATE_STATUS(Doc.of(MeterConnectStatus.values())), // - METER_COMMUNICATE_STATUS(Doc.of(MeterCommunicateStatus.values())), // - MT_ACTIVE_POWER_R(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - MT_ACTIVE_POWER_S(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - MT_ACTIVE_POWER_T(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - MT_TOTAL_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - MT_TOTAL_REACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // - METER_PF_R(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - METER_PF_S(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - METER_PF_T(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - METER_POWER_FACTOR(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - METER_FREQUENCE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - E_TOTAL_SELL(Doc.of(OpenemsType.FLOAT) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - E_TOTAL_BUY2(Doc.of(OpenemsType.FLOAT) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // - - STATE_32(Doc.of(Level.WARNING).text("DRM0")), // - STATE_33(Doc.of(Level.WARNING).text("DRM1")), // - STATE_34(Doc.of(Level.WARNING).text("DRM2")), // - STATE_35(Doc.of(Level.WARNING).text("DRM3")), // - STATE_36(Doc.of(Level.WARNING).text("DRM4")), // - STATE_37(Doc.of(Level.WARNING).text("DRM5")), // - STATE_38(Doc.of(Level.WARNING).text("DRM6")), // - STATE_39(Doc.of(Level.WARNING).text("DRM7")), // - STATE_40(Doc.of(Level.WARNING).text("DRM8")), // - STATE_41(Doc.of(Level.WARNING).text("DRED Connect Status")), // - - BATTERY_TYPE_INDEX(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - BMS_STATUS(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - BMS_PACK_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.DEGREE_CELSIUS).accessMode(AccessMode.READ_ONLY)), // - BMS_CHARGE_IMAX(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - BMS_DISCHARGE_IMAX(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - - STATE_42(Doc.of(Level.WARNING).text("Charging over-voltage2")), // - STATE_43(Doc.of(Level.WARNING).text("Discharging under-voltage2")), // - STATE_44(Doc.of(Level.WARNING).text("CellHigh temperature2")), // - STATE_45(Doc.of(Level.WARNING).text("CellLow temperature2")), // - STATE_46(Doc.of(Level.WARNING).text("Charging overcurrent2")), // - STATE_47(Doc.of(Level.WARNING).text("Discharging overcurrent2")), // - STATE_48(Doc.of(Level.WARNING).text("Precharge fault")), // - STATE_49(Doc.of(Level.WARNING).text("DC bus fault")), // - STATE_50(Doc.of(Level.WARNING).text("Battery break")), // - STATE_51(Doc.of(Level.WARNING).text("Battery Lock")), // - STATE_52(Doc.of(Level.WARNING).text("Discharge circuit Fault")), // - STATE_53(Doc.of(Level.WARNING).text("Charging circuit Failure")), // - STATE_54(Doc.of(Level.WARNING).text("Communication failure2")), // - STATE_55(Doc.of(Level.WARNING).text("Cell High temperature3")), // - STATE_56(Doc.of(Level.WARNING).text("Discharging under-voltage3")), // - STATE_57(Doc.of(Level.WARNING).text("Charging over-voltage3")), // - - BMS_SOH(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.READ_ONLY)), - BMS_BATTERY_STRINGS(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - - STATE_58(Doc.of(Level.WARNING).text("Charging over-voltage1")), // - STATE_59(Doc.of(Level.WARNING).text("Discharging under-voltage1")), // - STATE_60(Doc.of(Level.WARNING).text("Cell High temperature1")), // - STATE_61(Doc.of(Level.WARNING).text("Cell Low temperature1")), // - STATE_62(Doc.of(Level.WARNING).text("Charging over-current1")), // - STATE_63(Doc.of(Level.WARNING).text("Discharging over-current1")), // - STATE_64(Doc.of(Level.WARNING).text("communication failure1")), // - STATE_65(Doc.of(Level.WARNING).text("System Reboot")), // - STATE_66(Doc.of(Level.WARNING).text("Cell- imbalance")), // - STATE_67(Doc.of(Level.WARNING).text("System Low temperature1")), // - STATE_68(Doc.of(Level.WARNING).text("System Low temperature2")), // - STATE_69(Doc.of(Level.WARNING).text("System High temperature")), // - - BATTERY_PROTOCOL(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // - - // Setting Parameter - USER_PASSWORD1(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - USER_PASSWORD2(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - USER_PASSWORD3(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - ROUTER_SSID(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - ROUTER_PASSWORD(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - ROUTER_ENCRYPTION_METHOD(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - DOMAIN1(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - PORT_NUMBER1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - DOMAIN2(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - PORT_NUMBER2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - MODBUS_ADDRESS(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - MODBUS_MANUFACTURER(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - MODBUS_BADRATE_485(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - RTC_YEAR_MONTH_2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - RTC_DAY_HOUR_2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - RTC_MINUTE_SECOND_2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - SERIAL_NUMBER_2(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - DEVICE_TYPE_2(Doc.of(OpenemsType.STRING) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - RESUME_FACTORY_SETTING(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - CLEAR_DATA(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - START(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // - STOP(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // - RESET(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // - RESET_SPS(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // - PV_E_TOTAL_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // - PV_E_DAY_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // - E_TOTAL_SELL_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // - H_TOTAL_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HOUR).accessMode(AccessMode.READ_WRITE)), // - E_DAY_SELL_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // - E_TOTAL_BUY_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // - E_DAY_BUY_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // - E_TOTAL_LOAD_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // - E_LOAD_DAY_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // - E_BATTERY_CHARGE_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // - E_CHARGE_DAY_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // - E_BATTERY_DISCHARGE_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // - E_DISCHARGE_DAY_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // - LANGUAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - SAFETY_COUNTRY_CODE(Doc.of(SafetyCountry.values())), // - ISO(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - LVRT(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - ISLANDING(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BURN_IN_RESET_TIME(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MINUTE).accessMode(AccessMode.READ_WRITE)), // - PV_START_VOLTAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - ENABLE_MPPT_4SHADOW(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BACK_UP_ENABLE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - AUTO_START_BACKUP(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - GRID_WAVE_CHECK_LEVEL(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - REPAID_CUT_OFF(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BACKUP_START_DLY(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - UPS_STD_VOLT_TYPE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - UNDER_ATS(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BURN_IN_MODE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BACKUP_OVERLOAD_DELAY(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - UPSPHASE_TYPE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - DERATE_RATE_VDE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - LEAD_BAT_CAPACITY(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BATTERY_STRINGS(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BATT_CHARGE_VOLT_MAX(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BATT_CHARGE_CURR_MAX(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BATT_VOLT_UNDER_MIN(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BATT_DISCHARGE_CURR_MAX(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BATT_SOC_UNDER_MIN(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BATT_OFF_LINE_VOLT_UNDER_MIN(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BATT_OFFLINE_SOC_UNDER_MIN(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - CLEAR_BATTERY_SETTING(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // - - // CosPhi curve - ENABLE_CURVE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - POINT_A_VALUE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // - POINT_A_PF(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // - POINT_B_VALUE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // - POINT_B_PF(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // - POINT_C_VALUE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // - POINT_C_PF(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // - LOCK_IN_VOLTAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - LOCK_OUT_VOLTAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - LOCK_OUT_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // - - // Power and frequency curve - STATE_70(Doc.of(Level.INFO).text("ON/OFF")), // - STATE_71(Doc.of(Level.INFO).text("response mode")), // - - FFROZEN_DCH(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // - FFROZEN_CH(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // - FSTOP_DCH(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // - FSTOP_CH(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // - RECOVERY_WAITING_TIME(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.SECONDS).accessMode(AccessMode.READ_WRITE)), // - RECOVERY_FREQURNCY1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // - RECOVERY_FREQUENCY2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // - RECOVERY_SLOPE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - FFROZEN_DCH_SLOPE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // - FFROZEN_CH_SLOPE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // - DOWN_SLOPE_POWER_REFERENCE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - DOWN_SLOP(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - - // QU curve - ENABLE_CURVE_QU(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - LOCK_IN_POWER_QU(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // - LOCK_OUT_POWER_QU(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // - V1_VOLTAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - V1_VALUE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // - V2_VOLTAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - V2_VALUE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // - V3_VOLTAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - V3_VALUE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // - V4_VOLTAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - V4_VALUE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // - K_VALUE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - TIME_CONSTANT(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - MISCELLANEA(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - RATED_VOLTAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - RESPONSE_TIME(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - - // PU curve - PU_CURVE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - POWER_CHANGE_RATE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - V1_VOLTAGE_PU(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - V1_VALUE_PU(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - V2_VOLTAGE_PU(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - V2_VALUE_PU(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - V3_VOLTAGE_PU(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - V3_VALUE_PU(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - V4_VOLTAGE_PU(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - V4_VALUE_PU(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - FIXED_POWER_FACTOR(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - FIXED_REACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - FIXED_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - GRID_LIMIT_BY_VOLT_START_VOL(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - GRID_LIMIT_BY_VOLT_START_PER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // - GRID_LIMIT_BY_VOLT_SLOPE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.WRITE_ONLY)), // - AUTO_TEST_ENABLE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // - AUTO_TEST_STEP(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // - UW_ITALY_FREQ_MODE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - - // Meter Control ARM - APP_MODE_INDEX(Doc.of(AppModeIndex.values())), // - METER_CHECK_VALUE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - WMETER_CONNECT_CHECK_FLAG(Doc.of(MeterConnectCheckFlag.values())), // - SIMULATE_METER_POWER(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BREEZE_ON_OFF(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - LOG_DATA_ENABLE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - DATA_SEND_INTERVAL(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.SECONDS).accessMode(AccessMode.READ_WRITE)), // - - // Battery Control Data ARM - STOP_SOC_PROTECT(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BATTERY_FLOAT_VOLT(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - BATTERY_FLOAT_CURRENT(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.AMPERE).accessMode(AccessMode.READ_WRITE)), // - BATTERY_FLOAT_TIME(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.MINUTE).accessMode(AccessMode.READ_WRITE)), // - BATTERY_TYPE_INDEX_ARM(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - MANUFACTURE_CODE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - DC_VOLT_OUTPUT(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BAT_AVG_CHG_VOLT(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - BAT_AVG_CHG_HOURS(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.HOUR).accessMode(AccessMode.READ_WRITE)), // - FEED_POWER_ENABLE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - FEED_POWER_PARA(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // - EMS_POWER_MODE(Doc.of(PowerModeEms.values()) // - .accessMode(AccessMode.READ_WRITE)), // - EMS_POWER_SET(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BAT_BMS_CURR_LMT_COFF(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BATTERY_PROTOCOL_ARM(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - START_TIME_1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - END_TIME_1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BAT_POWER_PERCENT_1(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // - - STATE_72(Doc.of(Level.INFO).text("SUNDAY")), // - STATE_73(Doc.of(Level.WARNING).text("MONDAY")), // - STATE_74(Doc.of(Level.WARNING).text("TUESDAY")), // - STATE_75(Doc.of(Level.WARNING).text("Wednesday")), // - STATE_76(Doc.of(Level.WARNING).text("Thursday")), // - STATE_77(Doc.of(Level.WARNING).text("Friday")), // - STATE_78(Doc.of(Level.WARNING).text("Saturday")), // - - START_TIME_2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - END_TIME_2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BAT_POWER_PERCENT_2(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // - START_TIME_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - END_TIME_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BAT_POWER_PERCENT_3(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // - START_TIME_4(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - END_TIME_4(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BAT_POWER_PERCENT_4(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // - SOC_START_TO_FORCE_CHARGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - SOC_STOP_TO_FORCE_CHARGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - CLEAR_ALL_ECONOMIC_MODE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // - - // BMS for RS485 - BMS_VERSION(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - BATT_STRINGS_RS485(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // - WBMS_BAT_CHARGE_VMAX(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - WBMS_BAT_CHARGE_IMAX(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.AMPERE).accessMode(AccessMode.READ_WRITE)), // - WBMS_BAT_DISCHARGE_VMIN(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - WBMS_BAT_DISCHARGE_IMAX(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.AMPERE).accessMode(AccessMode.READ_WRITE)), // - WBMS_BAT_VOLTAGE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // - WBMS_BAT_CURRENT(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.AMPERE).accessMode(AccessMode.READ_WRITE)), // - WBMS_BAT_SOC(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // - WBMS_BAT_SOH(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // - WBMS_BAT_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.DEGREE_CELSIUS).accessMode(AccessMode.READ_WRITE)), // - - // BMS_STATUS(), // - STATE_79(Doc.of(Level.INFO).text("force to charge")), // - STATE_80(Doc.of(Level.INFO).text("Stop charging")), // TODO can be removed? - STATE_81(Doc.of(Level.INFO).text("Stop discharging")); - - private final Doc doc; - - private EssChannelId(Doc doc) { - this.doc = doc; - } - - @Override - public Doc doc() { - return this.doc; - } -} \ No newline at end of file diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/GoodWeEtBatteryInverter.java b/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/GoodWeEtBatteryInverter.java deleted file mode 100644 index df85b15cecc..00000000000 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/GoodWeEtBatteryInverter.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.openems.edge.goodwe.et.ess; - -import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.ess.api.SymmetricEss; -import io.openems.edge.goodwe.et.charger.AbstractGoodWeEtCharger; - -public interface GoodWeEtBatteryInverter extends SymmetricEss, OpenemsComponent { - - public Integer getUnitId(); - - public String getModbusBridgeId(); - - public void addCharger(AbstractGoodWeEtCharger charger); - - public void removeCharger(AbstractGoodWeEtCharger charger); - -} diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/GoodWeEtBatteryInverterImpl.java b/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/GoodWeEtBatteryInverterImpl.java deleted file mode 100644 index 428c34aebc8..00000000000 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/GoodWeEtBatteryInverterImpl.java +++ /dev/null @@ -1,570 +0,0 @@ -package io.openems.edge.goodwe.et.ess; - -import java.util.HashSet; -import java.util.Set; - -import org.osgi.service.cm.ConfigurationAdmin; -import org.osgi.service.component.ComponentContext; -import org.osgi.service.component.annotations.Activate; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.ConfigurationPolicy; -import org.osgi.service.component.annotations.Deactivate; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; -import org.osgi.service.component.annotations.ReferencePolicyOption; -import org.osgi.service.event.Event; -import org.osgi.service.event.EventConstants; -import org.osgi.service.event.EventHandler; -import org.osgi.service.metatype.annotations.Designate; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.types.OpenemsType; -import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; -import io.openems.edge.bridge.modbus.api.BridgeModbus; -import io.openems.edge.bridge.modbus.api.ElementToChannelConverter; -import io.openems.edge.bridge.modbus.api.ModbusProtocol; -import io.openems.edge.bridge.modbus.api.element.BitsWordElement; -import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement; -import io.openems.edge.bridge.modbus.api.element.SignedWordElement; -import io.openems.edge.bridge.modbus.api.element.UnsignedDoublewordElement; -import io.openems.edge.bridge.modbus.api.element.UnsignedWordElement; -import io.openems.edge.bridge.modbus.api.task.FC16WriteRegistersTask; -import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; -import io.openems.edge.common.channel.Channel; -import io.openems.edge.common.channel.EnumReadChannel; -import io.openems.edge.common.channel.EnumWriteChannel; -import io.openems.edge.common.channel.IntegerWriteChannel; -import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.event.EdgeEventConstants; -import io.openems.edge.common.sum.GridMode; -import io.openems.edge.common.taskmanager.Priority; -import io.openems.edge.common.type.TypeUtils; -import io.openems.edge.ess.api.HybridEss; -import io.openems.edge.ess.api.ManagedSymmetricEss; -import io.openems.edge.ess.api.SymmetricEss; -import io.openems.edge.ess.power.api.Constraint; -import io.openems.edge.ess.power.api.Phase; -import io.openems.edge.ess.power.api.Power; -import io.openems.edge.ess.power.api.Pwr; -import io.openems.edge.ess.power.api.Relationship; -import io.openems.edge.goodwe.et.charger.AbstractGoodWeEtCharger; -import io.openems.edge.timedata.api.Timedata; -import io.openems.edge.timedata.api.TimedataProvider; -import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; - -@Designate(ocd = Config.class, factory = true) -@Component(// - name = "GoodWe.ET.Battery-Inverter", // - immediate = true, // - configurationPolicy = ConfigurationPolicy.REQUIRE, // - property = EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE // -) // -public class GoodWeEtBatteryInverterImpl extends AbstractOpenemsModbusComponent implements GoodWeEtBatteryInverter, - HybridEss, ManagedSymmetricEss, SymmetricEss, OpenemsComponent, TimedataProvider, EventHandler { - - protected EnumWriteChannel setEmsPowerMode; - - private Config config; - - @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) - private volatile Timedata timedata = null; - - @Reference - protected ConfigurationAdmin cm; - - @Reference - private Power power; - - private final CalculateEnergyFromPower calculateAcChargeEnergy = new CalculateEnergyFromPower(this, - SymmetricEss.ChannelId.ACTIVE_CHARGE_ENERGY); - private final CalculateEnergyFromPower calculateAcDischargeEnergy = new CalculateEnergyFromPower(this, - SymmetricEss.ChannelId.ACTIVE_DISCHARGE_ENERGY); - - private final Set chargers = new HashSet<>(); - - @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) - protected void setModbus(BridgeModbus modbus) { - super.setModbus(modbus); - } - - @Activate - void activate(ComponentContext context, Config config) throws OpenemsNamedException { - if (super.activate(context, config.id(), config.alias(), config.enabled(), config.unit_id(), this.cm, "Modbus", - config.modbus_id())) { - return; - } - this.config = config; - this._setCapacity(this.config.capacity()); - } - - @Deactivate - protected void deactivate() { - super.deactivate(); - } - - public GoodWeEtBatteryInverterImpl() throws OpenemsNamedException { - super(// - OpenemsComponent.ChannelId.values(), // - SymmetricEss.ChannelId.values(), // - ManagedSymmetricEss.ChannelId.values(), // - HybridEss.ChannelId.values(), // - EssChannelId.values() // - ); - } - - public String getModbusBridgeId() { - return this.config.modbus_id(); - } - - @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { - return new ModbusProtocol(this, // - - new FC3ReadRegistersTask(35001, Priority.ONCE, // - m(SymmetricEss.ChannelId.MAX_APPARENT_POWER, new UnsignedWordElement(35001))), // - - new FC3ReadRegistersTask(35111, Priority.LOW, // - m(EssChannelId.V_PV3, new UnsignedWordElement(35111), - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - m(EssChannelId.I_PV3, new UnsignedWordElement(35112), - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - new DummyRegisterElement(35113, 35114), // - m(EssChannelId.V_PV4, new UnsignedWordElement(35115), - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - m(EssChannelId.I_PV4, new UnsignedWordElement(35116), - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - new DummyRegisterElement(35117, 35118), // - m(EssChannelId.PV_MODE, new UnsignedDoublewordElement(35119))), // - - new FC3ReadRegistersTask(35136, Priority.HIGH, // - m(SymmetricEss.ChannelId.GRID_MODE, new UnsignedWordElement(35136), // - new ElementToChannelConverter((value) -> { - Integer intValue = TypeUtils.getAsType(OpenemsType.INTEGER, value); - if (intValue != null) { - switch (intValue) { - case 0: - return GridMode.OFF_GRID; - case 1: - return GridMode.ON_GRID; - case 2: - return GridMode.UNDEFINED; - } - } - return GridMode.UNDEFINED; - }))), // - new FC3ReadRegistersTask(35138, Priority.LOW, // - m(EssChannelId.TOTAL_INV_POWER, new SignedWordElement(35138)), // - new DummyRegisterElement(35139), // - m(EssChannelId.AC_ACTIVE_POWER, new SignedWordElement(35140), // - ElementToChannelConverter.INVERT), // - new DummyRegisterElement(35141), // - m(EssChannelId.AC_REACTIVE_POWER, new SignedWordElement(35142), // - ElementToChannelConverter.INVERT), // - new DummyRegisterElement(35143), // - m(EssChannelId.AC_APPARENT_POWER, new SignedWordElement(35144), // - ElementToChannelConverter.INVERT), // - m(EssChannelId.BACK_UP_V_LOAD_R, new UnsignedWordElement(35145), // - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - m(EssChannelId.BACK_UP_I_LOAD_R, new UnsignedWordElement(35146), - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - m(EssChannelId.BACK_UP_F_LOAD_R, new UnsignedWordElement(35147), - ElementToChannelConverter.SCALE_FACTOR_MINUS_2), // - m(EssChannelId.LOAD_MODE_R, new UnsignedWordElement(35148)), // - new DummyRegisterElement(35149), // - m(EssChannelId.BACK_UP_P_LOAD_R, new SignedWordElement(35150)), // - m(EssChannelId.BACK_UP_V_LOAD_S, new UnsignedWordElement(35151), - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - m(EssChannelId.BACK_UP_I_LOAD_S, new UnsignedWordElement(35152), - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - m(EssChannelId.BACK_UP_F_LOAD_S, new UnsignedWordElement(35153), - ElementToChannelConverter.SCALE_FACTOR_MINUS_2), // - m(EssChannelId.LOAD_MODE_S, new UnsignedWordElement(35154)), // - new DummyRegisterElement(35155), // - m(EssChannelId.BACK_UP_P_LOAD_S, new SignedWordElement(35156)), // - m(EssChannelId.BACK_UP_V_LOAD_T, new UnsignedWordElement(35157), - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - m(EssChannelId.BACK_UP_I_LOAD_T, new UnsignedWordElement(35158), - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - m(EssChannelId.BACK_UP_F_LOAD_T, new UnsignedWordElement(35159), - ElementToChannelConverter.SCALE_FACTOR_MINUS_2), // - m(EssChannelId.LOAD_MODE_T, new UnsignedWordElement(35160)), // - new DummyRegisterElement(35161), // - m(EssChannelId.BACK_UP_P_LOAD_T, new SignedWordElement(35162)), // - new DummyRegisterElement(35163), // - m(EssChannelId.P_LOAD_R, new SignedWordElement(35164)), // - new DummyRegisterElement(35165), // - m(EssChannelId.P_LOAD_S, new SignedWordElement(35166)), // - new DummyRegisterElement(35167), // - m(EssChannelId.P_LOAD_T, new SignedWordElement(35168)), // - new DummyRegisterElement(35169), // - m(EssChannelId.TOTAL_BACK_UP_LOAD, new SignedWordElement(35170)), // - new DummyRegisterElement(35171), // - m(EssChannelId.TOTAL_LOAD_POWER, new SignedWordElement(35172)), // - m(EssChannelId.UPS_LOAD_PERCENT, new UnsignedWordElement(35173), - ElementToChannelConverter.SCALE_FACTOR_MINUS_2)), // - - new FC3ReadRegistersTask(35180, Priority.HIGH, // - m(EssChannelId.V_BATTERY1, new UnsignedWordElement(35180), - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - m(EssChannelId.I_BATTERY1, new SignedWordElement(35181), - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - new DummyRegisterElement(35182), // - m(EssChannelId.P_BATTERY1, new SignedWordElement(35183)), // - m(EssChannelId.BATTERY_MODE, new UnsignedWordElement(35184))), // - - new FC3ReadRegistersTask(35185, Priority.LOW, // - m(EssChannelId.WARNING_CODE, new UnsignedWordElement(35185)), // - m(EssChannelId.SAFETY_COUNTRY, new UnsignedWordElement(35186)), // - m(EssChannelId.WORK_MODE, new UnsignedWordElement(35187)), // - m(EssChannelId.OPERATION_MODE, new UnsignedDoublewordElement(35188))), // - - new FC3ReadRegistersTask(35206, Priority.LOW, // - m(HybridEss.ChannelId.DC_CHARGE_ENERGY, new UnsignedDoublewordElement(35206), // - ElementToChannelConverter.SCALE_FACTOR_2), // - new DummyRegisterElement(35208), // - m(HybridEss.ChannelId.DC_DISCHARGE_ENERGY, new UnsignedDoublewordElement(35209), - ElementToChannelConverter.SCALE_FACTOR_2)), // - - new FC3ReadRegistersTask(36003, Priority.LOW, // - m(EssChannelId.B_METER_COMMUNICATE_STATUS, new UnsignedWordElement(36003)), // - m(EssChannelId.METER_COMMUNICATE_STATUS, new UnsignedWordElement(36004))), // - - new FC3ReadRegistersTask(37001, Priority.LOW, - m(EssChannelId.BATTERY_TYPE_INDEX, new UnsignedWordElement(37001)), // - m(EssChannelId.BMS_STATUS, new UnsignedWordElement(37002)), // - m(EssChannelId.BMS_PACK_TEMPERATURE, new UnsignedWordElement(37003), - ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // - m(EssChannelId.BMS_CHARGE_IMAX, new UnsignedWordElement(37004)), // - m(EssChannelId.BMS_DISCHARGE_IMAX, new UnsignedWordElement(37005))), // - - new FC3ReadRegistersTask(37007, Priority.HIGH, // - m(SymmetricEss.ChannelId.SOC, new UnsignedWordElement(37007), new ElementToChannelConverter( - // element -> channel - value -> { - // Set SoC to undefined if there is No Battery - EnumReadChannel batteryModeChannel = this.channel(EssChannelId.BATTERY_MODE); - BatteryMode batteryMode = batteryModeChannel.value().asEnum(); - if (batteryMode == BatteryMode.NO_BATTERY || batteryMode == BatteryMode.UNDEFINED) { - return null; - } else { - return value; - } - }, - // channel -> element - value -> value))), // - new FC3ReadRegistersTask(37008, Priority.LOW, // - m(EssChannelId.BMS_SOH, new UnsignedWordElement(37008)), // - m(EssChannelId.BMS_BATTERY_STRINGS, new UnsignedWordElement(37009))), // - - new FC16WriteRegistersTask(47000, // - m(EssChannelId.APP_MODE_INDEX, new UnsignedWordElement(47000)), // - m(EssChannelId.METER_CHECK_VALUE, new UnsignedWordElement(47001)), // - m(EssChannelId.WMETER_CONNECT_CHECK_FLAG, new UnsignedWordElement(47002))), // - - new FC3ReadRegistersTask(47000, Priority.LOW, // - m(EssChannelId.APP_MODE_INDEX, new UnsignedWordElement(47000)), // - m(EssChannelId.METER_CHECK_VALUE, new UnsignedWordElement(47001)), // - m(EssChannelId.WMETER_CONNECT_CHECK_FLAG, new UnsignedWordElement(47002))), // - - new FC16WriteRegistersTask(47500, // - m(EssChannelId.STOP_SOC_PROTECT, new UnsignedWordElement(47500)), // - new DummyRegisterElement(47501, 47508), // - m(EssChannelId.FEED_POWER_ENABLE, new UnsignedWordElement(47509)), // - m(EssChannelId.FEED_POWER_PARA, new UnsignedWordElement(47510)), // - m(EssChannelId.EMS_POWER_MODE, new UnsignedWordElement(47511)), // - m(EssChannelId.EMS_POWER_SET, new UnsignedWordElement(47512))), // - - new FC16WriteRegistersTask(47531, // - m(EssChannelId.SOC_START_TO_FORCE_CHARGE, new UnsignedWordElement(47531)), // - m(EssChannelId.SOC_STOP_TO_FORCE_CHARGE, new UnsignedWordElement(47532)), // - m(EssChannelId.CLEAR_ALL_ECONOMIC_MODE, new UnsignedWordElement(47533))), // - - new FC3ReadRegistersTask(47500, Priority.LOW, - m(EssChannelId.STOP_SOC_PROTECT, new UnsignedWordElement(47500)), // - new DummyRegisterElement(47501, 47508), // - m(EssChannelId.FEED_POWER_ENABLE, new UnsignedWordElement(47509)), // - m(EssChannelId.FEED_POWER_PARA, new UnsignedWordElement(47510))), // - - new FC3ReadRegistersTask(47511, Priority.HIGH, - m(EssChannelId.EMS_POWER_MODE, new UnsignedWordElement(47511)), // - m(EssChannelId.EMS_POWER_SET, new UnsignedWordElement(47512))), // - - new FC3ReadRegistersTask(47531, Priority.LOW, - m(EssChannelId.SOC_START_TO_FORCE_CHARGE, new UnsignedWordElement(47531)), // - m(EssChannelId.SOC_STOP_TO_FORCE_CHARGE, new UnsignedWordElement(47532))), // - - new FC16WriteRegistersTask(47900, // - m(EssChannelId.BMS_VERSION, new UnsignedWordElement(47900)), // - m(EssChannelId.BATT_STRINGS_RS485, new UnsignedWordElement(47901)), // - m(EssChannelId.WBMS_BAT_CHARGE_VMAX, new UnsignedWordElement(47902)), // - m(EssChannelId.WBMS_BAT_CHARGE_IMAX, new UnsignedWordElement(47903)), // - m(EssChannelId.WBMS_BAT_DISCHARGE_VMIN, new UnsignedWordElement(47904)), // - m(EssChannelId.WBMS_BAT_DISCHARGE_IMAX, new UnsignedWordElement(47905)), // - m(EssChannelId.WBMS_BAT_VOLTAGE, new UnsignedWordElement(47906)), // - m(EssChannelId.WBMS_BAT_CURRENT, new UnsignedWordElement(47907)), // - m(EssChannelId.WBMS_BAT_SOC, new UnsignedWordElement(47908)), // - m(EssChannelId.WBMS_BAT_SOH, new UnsignedWordElement(47909)), // - m(EssChannelId.WBMS_BAT_TEMPERATURE, new UnsignedWordElement(47910)), // - m(new BitsWordElement(47911, this) // - .bit(0, EssChannelId.STATE_58) // - .bit(1, EssChannelId.STATE_59) // - .bit(2, EssChannelId.STATE_60) // - .bit(3, EssChannelId.STATE_61) // - .bit(4, EssChannelId.STATE_62) // - .bit(5, EssChannelId.STATE_63) // - .bit(6, EssChannelId.STATE_64) // - .bit(7, EssChannelId.STATE_65) // - .bit(8, EssChannelId.STATE_66) // - .bit(9, EssChannelId.STATE_67) // - .bit(10, EssChannelId.STATE_68) // - .bit(11, EssChannelId.STATE_69)), // - new DummyRegisterElement(47912), // - m(new BitsWordElement(47913, this) // - .bit(0, EssChannelId.STATE_42) // - .bit(1, EssChannelId.STATE_43) // - .bit(2, EssChannelId.STATE_44) // - .bit(3, EssChannelId.STATE_45) // - .bit(4, EssChannelId.STATE_46) // - .bit(5, EssChannelId.STATE_47) // - .bit(6, EssChannelId.STATE_48) // - .bit(7, EssChannelId.STATE_49) // - .bit(8, EssChannelId.STATE_50) // - .bit(9, EssChannelId.STATE_51) // - .bit(10, EssChannelId.STATE_52) // - .bit(11, EssChannelId.STATE_53) // - .bit(12, EssChannelId.STATE_54) // - .bit(13, EssChannelId.STATE_55) // - .bit(14, EssChannelId.STATE_56) // - .bit(15, EssChannelId.STATE_57)), // - new DummyRegisterElement(47914), // - m(new BitsWordElement(47915, this) // - .bit(0, EssChannelId.STATE_79) // - .bit(1, EssChannelId.STATE_80) // - .bit(2, EssChannelId.STATE_81))), // - - new FC3ReadRegistersTask(47902, Priority.LOW, // - m(EssChannelId.WBMS_BAT_CHARGE_VMAX, new UnsignedWordElement(47902)), // - m(EssChannelId.WBMS_BAT_CHARGE_IMAX, new UnsignedWordElement(47903)), // - m(EssChannelId.WBMS_BAT_DISCHARGE_VMIN, new UnsignedWordElement(47904)), // - m(EssChannelId.WBMS_BAT_DISCHARGE_IMAX, new UnsignedWordElement(47905)), // - m(EssChannelId.WBMS_BAT_VOLTAGE, new UnsignedWordElement(47906)), // - m(EssChannelId.WBMS_BAT_CURRENT, new UnsignedWordElement(47907)), // - m(EssChannelId.WBMS_BAT_SOC, new UnsignedWordElement(47908)), // - m(EssChannelId.WBMS_BAT_SOH, new UnsignedWordElement(47909)), // - m(EssChannelId.WBMS_BAT_TEMPERATURE, new UnsignedWordElement(47910)), // - m(new BitsWordElement(47911, this) // - .bit(0, EssChannelId.STATE_58) // - .bit(1, EssChannelId.STATE_59) // - .bit(2, EssChannelId.STATE_60) // - .bit(3, EssChannelId.STATE_61) // - .bit(4, EssChannelId.STATE_62) // - .bit(5, EssChannelId.STATE_63) // - .bit(6, EssChannelId.STATE_64) // - .bit(7, EssChannelId.STATE_65) // - .bit(8, EssChannelId.STATE_66) // - .bit(9, EssChannelId.STATE_67) // - .bit(10, EssChannelId.STATE_68) // - .bit(11, EssChannelId.STATE_69)), // - new DummyRegisterElement(47912), // - m(new BitsWordElement(47913, this) // - .bit(0, EssChannelId.STATE_42) // - .bit(1, EssChannelId.STATE_43) // - .bit(2, EssChannelId.STATE_44) // - .bit(3, EssChannelId.STATE_45) // - .bit(4, EssChannelId.STATE_46) // - .bit(5, EssChannelId.STATE_47) // - .bit(6, EssChannelId.STATE_48) // - .bit(7, EssChannelId.STATE_49) // - .bit(8, EssChannelId.STATE_50) // - .bit(9, EssChannelId.STATE_51) // - .bit(10, EssChannelId.STATE_52) // - .bit(11, EssChannelId.STATE_53) // - .bit(12, EssChannelId.STATE_54) // - .bit(13, EssChannelId.STATE_55) // - .bit(14, EssChannelId.STATE_56) // - .bit(15, EssChannelId.STATE_57)), // - new DummyRegisterElement(47914), // - m(new BitsWordElement(47915, this) // - .bit(0, EssChannelId.STATE_79) // - .bit(1, EssChannelId.STATE_80) // - .bit(2, EssChannelId.STATE_81)))); - } - - @Override - public void applyPower(int activePower, int reactivePower) throws OpenemsNamedException { - final PowerModeEms nextPowerMode; - - if (this.config.readOnlyMode()) { - // Read-Only-Mode: fall-back to internal self-consumption optimization - nextPowerMode = PowerModeEms.AUTO; - activePower = 0; - } else { - if (activePower <= 0) { - // ActivePower is negative or zero -> CHARGE - nextPowerMode = PowerModeEms.CHARGE_BAT; - - } else { - // ActivePower is positive -> DISCHARGE - - /* - * Check if PV is available. Discharge mode changes according to availability of - * PV - * - * TODO PV mode is not working, need an update from GoodWe for this. - */ - Integer productionPower = null; - for (AbstractGoodWeEtCharger charger : this.chargers) { - productionPower = TypeUtils.sum(productionPower, charger.getActualPower().get()); - } - if (productionPower == null) { - // No PV-Power -> required to put on SELL_POWER - nextPowerMode = PowerModeEms.SELL_POWER; - } else { - // PV-Power exists -> set DISCHARGE_BAT - nextPowerMode = PowerModeEms.DISCHARGE_BAT; - } - } - } - - // Set the PowerMode and PowerSet - IntegerWriteChannel emsPowerSetChannel = this.channel(EssChannelId.EMS_POWER_SET); - - Integer essPowerSet = emsPowerSetChannel.value().get(); - if (essPowerSet == null || activePower != essPowerSet) { - // Set to new power mode only if the previous activePower is different or - // undefined - emsPowerSetChannel.setNextWriteValue(Math.abs(activePower)); - } - - EnumWriteChannel emsPowerModeChannel = this.channel(EssChannelId.EMS_POWER_MODE); - PowerModeEms emsPowerMode = emsPowerModeChannel.value().asEnum(); - if (emsPowerMode != nextPowerMode) { - // Set to new power mode only if the previous mode is different - emsPowerModeChannel.setNextWriteValue(nextPowerMode); - } - // TODO : Add Reactive Power Register - } - - @Override - public String debugLog() { - return "SoC:" + this.getSoc().asString() // - + "|L:" + this.getActivePower().asString() // - + "|" + this.getGridModeChannel().value().asOptionString()// - + "|Allowed:" + this.getAllowedChargePower().asStringWithoutUnit() + ";" - + this.getAllowedDischargePower().asString(); - } - - @Override - public void addCharger(AbstractGoodWeEtCharger charger) { - this.chargers.add(charger); - } - - @Override - public void removeCharger(AbstractGoodWeEtCharger charger) { - this.chargers.remove(charger); - } - - @Override - public void handleEvent(Event event) { - if (!this.isEnabled()) { - return; - } - - switch (event.getTopic()) { - case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: - this.updatechannels(); - break; - } - } - - private void updatechannels() { - /* - * Update ActivePower from P_BATTERY1 and chargers ACTUAL_POWER - */ - final Channel batteryPower = this.channel(EssChannelId.P_BATTERY1); - Integer activePower = batteryPower.getNextValue().get(); - for (AbstractGoodWeEtCharger charger : this.chargers) { - activePower = TypeUtils.sum(activePower, charger.getActualPowerChannel().getNextValue().get()); - } - this._setActivePower(activePower); - - /* - * Calculate AC Energy - */ - if (activePower == null) { - // Not available - this.calculateAcChargeEnergy.update(null); - this.calculateAcDischargeEnergy.update(null); - } else if (activePower > 0) { - // Discharge - this.calculateAcChargeEnergy.update(0); - this.calculateAcDischargeEnergy.update(activePower); - } else { - // Charge - this.calculateAcChargeEnergy.update(activePower * -1); - this.calculateAcDischargeEnergy.update(0); - } - - /* - * Update Allowed charge and Allowed discharge - */ - Integer soc = this.getSoc().get(); - Integer maxApparentPower = this.getMaxApparentPower().get(); - - if (soc == null || soc >= 99) { - this._setAllowedChargePower(0); - } else { - this._setAllowedChargePower(TypeUtils.multiply(maxApparentPower, -1)); - } - if (soc == null || soc <= 0) { - this._setAllowedDischargePower(0); - } else { - this._setAllowedDischargePower(maxApparentPower); - } - } - - @Override - public Power getPower() { - return this.power; - } - - @Override - public int getPowerPrecision() { - return 1; - } - - @Override - public Constraint[] getStaticConstraints() throws OpenemsNamedException { - // Handle Read-Only mode -> no charge/discharge - if (this.config.readOnlyMode()) { - return new Constraint[] { // - this.createPowerConstraint("Read-Only-Mode", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 0), // - this.createPowerConstraint("Read-Only-Mode", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, 0) // - }; - } - return Power.NO_CONSTRAINTS; - } - - @Override - public Timedata getTimedata() { - return this.timedata; - } - - @Override - public Integer getSurplusPower() { - if (this.getSoc().orElse(0) < 99) { - return null; - } - Integer productionPower = null; - for (AbstractGoodWeEtCharger charger : this.chargers) { - productionPower = TypeUtils.sum(productionPower, charger.getActualPower().get()); - } - if (productionPower == null || productionPower < 100) { - return null; - } - return productionPower; - } - -} diff --git a/io.openems.edge.goodwe.et/.classpath b/io.openems.edge.goodwe/.classpath similarity index 100% rename from io.openems.edge.goodwe.et/.classpath rename to io.openems.edge.goodwe/.classpath diff --git a/io.openems.edge.goodwe.et/.gitignore b/io.openems.edge.goodwe/.gitignore similarity index 100% rename from io.openems.edge.goodwe.et/.gitignore rename to io.openems.edge.goodwe/.gitignore diff --git a/io.openems.edge.goodwe.et/.project b/io.openems.edge.goodwe/.project similarity index 92% rename from io.openems.edge.goodwe.et/.project rename to io.openems.edge.goodwe/.project index 1d5fa09ac5b..11f2ddc1a2c 100644 --- a/io.openems.edge.goodwe.et/.project +++ b/io.openems.edge.goodwe/.project @@ -1,6 +1,6 @@ - io.openems.edge.goodwe.et + io.openems.edge.goodwe diff --git a/io.openems.edge.goodwe.et/bnd.bnd b/io.openems.edge.goodwe/bnd.bnd similarity index 91% rename from io.openems.edge.goodwe.et/bnd.bnd rename to io.openems.edge.goodwe/bnd.bnd index ae28dcb026e..6410f917d14 100644 --- a/io.openems.edge.goodwe.et/bnd.bnd +++ b/io.openems.edge.goodwe/bnd.bnd @@ -13,4 +13,5 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.timedata.api -testpath: \ - ${testpath} + ${testpath},\ + com.ghgande.j2mod diff --git a/io.openems.edge.goodwe.et/readme.adoc b/io.openems.edge.goodwe/readme.adoc similarity index 59% rename from io.openems.edge.goodwe.et/readme.adoc rename to io.openems.edge.goodwe/readme.adoc index 9ecf14a9f96..2019464189d 100644 --- a/io.openems.edge.goodwe.et/readme.adoc +++ b/io.openems.edge.goodwe/readme.adoc @@ -1,10 +1,10 @@ -= GoodWe ET-Series += GoodWe ET and BT-Series Hybrid Inverters -Battery-Inverter: +Ess: - SymmetricEss -Charger: +Charger: (ET only) - EssDcCharger @@ -13,4 +13,4 @@ Grid-Meter: - SymmetricMeter - AsymmetricMeter -https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.goodwe.et[Source Code icon:github[]] \ No newline at end of file +https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.goodwe[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/GoodWeEtConstants.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/GoodWeConstants.java similarity index 50% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/GoodWeEtConstants.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/GoodWeConstants.java index 666166cf269..88eda3aa8f4 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/GoodWeEtConstants.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/GoodWeConstants.java @@ -1,6 +1,6 @@ -package io.openems.edge.goodwe.et; +package io.openems.edge.goodwe; -public class GoodWeEtConstants { +public class GoodWeConstants { public static final int DEFAULT_UNIT_ID = 0xF7; // 0xF7 -> 247 } diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/AbstractGoodWeEtCharger.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/AbstractGoodWeEtCharger.java similarity index 58% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/AbstractGoodWeEtCharger.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/AbstractGoodWeEtCharger.java index c7c7b3090e8..ba74ffbc1f2 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/AbstractGoodWeEtCharger.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/AbstractGoodWeEtCharger.java @@ -1,4 +1,7 @@ -package io.openems.edge.goodwe.et.charger; +package io.openems.edge.goodwe.charger; + +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; @@ -8,11 +11,17 @@ import io.openems.edge.bridge.modbus.api.element.UnsignedWordElement; import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.common.taskmanager.Priority; import io.openems.edge.ess.dccharger.api.EssDcCharger; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; public abstract class AbstractGoodWeEtCharger extends AbstractOpenemsModbusComponent - implements EssDcCharger, OpenemsComponent { + implements EssDcCharger, OpenemsComponent, TimedataProvider, EventHandler { + + private final CalculateEnergyFromPower calculateActualEnergy = new CalculateEnergyFromPower(this, + EssDcCharger.ChannelId.ACTUAL_ENERGY); protected AbstractGoodWeEtCharger() { super(// @@ -26,7 +35,7 @@ protected AbstractGoodWeEtCharger() { protected ModbusProtocol defineModbusProtocol() throws OpenemsException { int startAddress = this.getStartAddress(); return new ModbusProtocol(this, // - new FC3ReadRegistersTask(startAddress, Priority.HIGH, // + new FC3ReadRegistersTask(startAddress, Priority.LOW, // m(PvChannelId.V, new UnsignedWordElement(startAddress), // ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // m(PvChannelId.I, new UnsignedWordElement(startAddress + 1), @@ -35,6 +44,30 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { m(EssDcCharger.ChannelId.ACTUAL_POWER, new UnsignedDoublewordElement(startAddress + 2)))); } + @Override + public void handleEvent(Event event) { + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: + this.calculateEnergy(); + break; + } + } + + /** + * Calculate the Energy values from ActivePower. + */ + private void calculateEnergy() { + Integer actualPower = this.getActualPower().get(); + if (actualPower == null) { + // Not available + this.calculateActualEnergy.update(null); + } else if (actualPower > 0) { + this.calculateActualEnergy.update(actualPower); + } else { + this.calculateActualEnergy.update(0); + } + } + @Override public final String debugLog() { return "L:" + this.getActualPower().asString(); diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/ConfigPV1.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/ConfigPV1.java similarity index 66% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/ConfigPV1.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/ConfigPV1.java index 3481f3f6e4a..901c92bdcc0 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/ConfigPV1.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/ConfigPV1.java @@ -1,9 +1,9 @@ -package io.openems.edge.goodwe.et.charger; +package io.openems.edge.goodwe.charger; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; -import io.openems.edge.goodwe.et.GoodWeEtConstants; +import io.openems.edge.goodwe.GoodWeConstants; @ObjectClassDefinition(// name = "GoodWe ET Charger PV1", // @@ -19,17 +19,20 @@ @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") boolean enabled() default true; - @AttributeDefinition(name = "GoodWe ET Battery-Inverter", description = "ID of GoodWe ET Battery-Inverter device.") + @AttributeDefinition(name = "GoodWe ET ESS", description = "ID of GoodWe ET Energy Storage System.") String ess_id() default "ess0"; - @AttributeDefinition(name = "GoodWe ET Battery-Inverter target filter", description = "This is auto-generated by 'GoodWe ET Battery-Inverter-ID'.") + @AttributeDefinition(name = "GoodWe ET ESS target filter", description = "This is auto-generated by 'GoodWe ET ESS'.") String Ess_target() default ""; @AttributeDefinition(name = "Modbus Unit-id", description = "Unit-id") - int unit_id() default GoodWeEtConstants.DEFAULT_UNIT_ID; + int unit_id() default GoodWeConstants.DEFAULT_UNIT_ID; @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus bridge.") String modbus_id() default "modbus0"; + @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") + String Modbus_target() default ""; + String webconsole_configurationFactory_nameHint() default "GoodWe ET Charger PV1 [{id}]"; } \ No newline at end of file diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/ConfigPV2.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/ConfigPV2.java similarity index 66% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/ConfigPV2.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/ConfigPV2.java index b97a1d00b6c..04d9e26bef8 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/ConfigPV2.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/ConfigPV2.java @@ -1,9 +1,9 @@ -package io.openems.edge.goodwe.et.charger; +package io.openems.edge.goodwe.charger; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; -import io.openems.edge.goodwe.et.GoodWeEtConstants; +import io.openems.edge.goodwe.GoodWeConstants; @ObjectClassDefinition(// name = "GoodWe ET Charger PV2", // @@ -19,17 +19,20 @@ @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") boolean enabled() default true; - @AttributeDefinition(name = "GoodWe ET Battery-Inverter", description = "ID of GoodWe ET Battery-Inverter device.") + @AttributeDefinition(name = "GoodWe ET ESS", description = "ID of GoodWe ET Energy Storage System.") String ess_id() default "ess0"; - @AttributeDefinition(name = "GoodWe ET Battery-Inverter target filter", description = "This is auto-generated by 'GoodWe ET Battery-Inverter-ID'.") + @AttributeDefinition(name = "GoodWe ET ESS target filter", description = "This is auto-generated by 'GoodWe ET ESS'.") String Ess_target() default ""; @AttributeDefinition(name = "Modbus Unit-id", description = "Unit-id") - int unit_id() default GoodWeEtConstants.DEFAULT_UNIT_ID; + int unit_id() default GoodWeConstants.DEFAULT_UNIT_ID; @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus bridge.") String modbus_id() default "modbus0"; + @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") + String Modbus_target() default ""; + String webconsole_configurationFactory_nameHint() default "GoodWe ET Charger PV2 [{id}]"; } \ No newline at end of file diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/GoodWeEtChargerPv1.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/GoodWeChargerPv1.java similarity index 62% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/GoodWeEtChargerPv1.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/GoodWeChargerPv1.java index b07b5e56612..ea12527cf61 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/GoodWeEtChargerPv1.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/GoodWeChargerPv1.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.charger; +package io.openems.edge.goodwe.charger; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -10,57 +10,48 @@ import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.EventConstants; +import org.osgi.service.event.EventHandler; import org.osgi.service.metatype.annotations.Designate; import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.api.BridgeModbus; -import io.openems.edge.bridge.modbus.api.ElementToChannelConverter; -import io.openems.edge.bridge.modbus.api.ModbusProtocol; -import io.openems.edge.bridge.modbus.api.element.UnsignedDoublewordElement; -import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.taskmanager.Priority; +import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.ess.dccharger.api.EssDcCharger; -import io.openems.edge.goodwe.et.ess.GoodWeEtBatteryInverter; +import io.openems.edge.goodwe.ess.GoodWeEss; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; @Designate(ocd = ConfigPV1.class, factory = true) @Component(// - name = "GoodWe.ET.Charger-PV1", // + name = "GoodWe.Charger-PV1", // immediate = true, // - configurationPolicy = ConfigurationPolicy.REQUIRE // -) -public class GoodWeEtChargerPv1 extends AbstractGoodWeEtCharger implements EssDcCharger, OpenemsComponent { + configurationPolicy = ConfigurationPolicy.REQUIRE, // + property = { // + EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // + }) +public class GoodWeChargerPv1 extends AbstractGoodWeEtCharger + implements EssDcCharger, OpenemsComponent, EventHandler, TimedataProvider { @Reference protected ConfigurationAdmin cm; @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) - private GoodWeEtBatteryInverter ess; + private GoodWeEss ess; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata = null; @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) protected void setModbus(BridgeModbus modbus) { super.setModbus(modbus); } - public GoodWeEtChargerPv1() { + public GoodWeChargerPv1() { super(); } - /* - * Energy values since we don't have individual energy values. // - * - * TODO update required from GoodWe regarding individual energy registers. - */ - @Override - protected ModbusProtocol defineModbusProtocol() throws OpenemsException { - - ModbusProtocol protocol = super.defineModbusProtocol(); - protocol.addTask(new FC3ReadRegistersTask(35191, Priority.LOW, // - m(EssDcCharger.ChannelId.ACTUAL_ENERGY, new UnsignedDoublewordElement(35191), - ElementToChannelConverter.SCALE_FACTOR_2))); - return protocol; - } - @Activate void activate(ComponentContext context, ConfigPV1 config) throws OpenemsException { if (super.activate(context, config.id(), config.alias(), config.enabled(), config.unit_id(), this.cm, "Modbus", @@ -91,4 +82,9 @@ protected int getStartAddress() { return 35103; } + @Override + public Timedata getTimedata() { + return this.timedata; + } + } diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/GoodWeEtChargerPv2.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/GoodWeChargerPv2.java similarity index 67% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/GoodWeEtChargerPv2.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/GoodWeChargerPv2.java index 721028c763d..7f78a42e8ee 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/GoodWeEtChargerPv2.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/GoodWeChargerPv2.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.charger; +package io.openems.edge.goodwe.charger; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -10,34 +10,45 @@ import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.EventConstants; +import org.osgi.service.event.EventHandler; import org.osgi.service.metatype.annotations.Designate; import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.api.BridgeModbus; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.ess.dccharger.api.EssDcCharger; -import io.openems.edge.goodwe.et.ess.GoodWeEtBatteryInverter; +import io.openems.edge.goodwe.ess.GoodWeEss; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; @Designate(ocd = ConfigPV2.class, factory = true) @Component(// - name = "GoodWe.ET.Charger-PV2", // + name = "GoodWe.Charger-PV2", // immediate = true, // - configurationPolicy = ConfigurationPolicy.REQUIRE // -) -public class GoodWeEtChargerPv2 extends AbstractGoodWeEtCharger implements EssDcCharger, OpenemsComponent { + configurationPolicy = ConfigurationPolicy.REQUIRE, // + property = { // + EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // + }) +public class GoodWeChargerPv2 extends AbstractGoodWeEtCharger + implements EssDcCharger, OpenemsComponent, EventHandler, TimedataProvider { @Reference protected ConfigurationAdmin cm; @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) - private GoodWeEtBatteryInverter ess; + private GoodWeEss ess; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata = null; @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) protected void setModbus(BridgeModbus modbus) { super.setModbus(modbus); } - public GoodWeEtChargerPv2() { + public GoodWeChargerPv2() { super(); } @@ -70,4 +81,9 @@ protected void deactivate() { protected int getStartAddress() { return 35107; } + + @Override + public Timedata getTimedata() { + return this.timedata; + } } diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/PvChannelId.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/PvChannelId.java similarity index 93% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/PvChannelId.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/PvChannelId.java index a0001c98277..a036d2419ac 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/charger/PvChannelId.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/charger/PvChannelId.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.charger; +package io.openems.edge.goodwe.charger; import io.openems.common.channel.AccessMode; import io.openems.common.channel.Unit; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/Config.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/Config.java similarity index 74% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/Config.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/Config.java index 93510dc795e..4ca80396c26 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/Config.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/Config.java @@ -1,13 +1,13 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; -import io.openems.edge.goodwe.et.GoodWeEtConstants; +import io.openems.edge.goodwe.GoodWeConstants; @ObjectClassDefinition(// - name = "GoodWe ET Battery-Inverter", // - description = "Implements the GoodWe ET-Series battery inverter.") + name = "GoodWe ET ESS", // + description = "Implements the GoodWe ET Energy Storage System.") @interface Config { @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") @@ -23,16 +23,19 @@ boolean readOnlyMode() default true; @AttributeDefinition(name = "Modbus Unit-id", description = "Unit-id") - int unit_id() default GoodWeEtConstants.DEFAULT_UNIT_ID; + int unit_id() default GoodWeConstants.DEFAULT_UNIT_ID; @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus bridge.") String modbus_id() default "modbus0"; - - @AttributeDefinition(name = "Capacity", description = "Capacity of the battery in Wh") + + @AttributeDefinition(name = "Capacity", description = "Capacity of the battery in [Wh]") int capacity() default 9_000; + @AttributeDefinition(name = "Maximum power", description = "Maximum charge/discharge power in [W]") + int maxBatteryPower() default 5_200; + @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") String Modbus_target() default ""; - String webconsole_configurationFactory_nameHint() default "GoodWe ET Battery-Inverter [{id}]"; + String webconsole_configurationFactory_nameHint() default "GoodWe ET ESS [{id}]"; } diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/GoodWeEss.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/GoodWeEss.java new file mode 100644 index 00000000000..562b0e14b07 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/GoodWeEss.java @@ -0,0 +1,729 @@ +package io.openems.edge.goodwe.ess; + +import io.openems.common.channel.AccessMode; +import io.openems.common.channel.Level; +import io.openems.common.channel.Unit; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.goodwe.charger.AbstractGoodWeEtCharger; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine; +import io.openems.edge.goodwe.ess.enums.AppModeIndex; +import io.openems.edge.goodwe.ess.enums.BatteryMode; +import io.openems.edge.goodwe.ess.enums.GoodweType; +import io.openems.edge.goodwe.ess.enums.LoadMode; +import io.openems.edge.goodwe.ess.enums.MeterCommunicateStatus; +import io.openems.edge.goodwe.ess.enums.MeterConnectCheckFlag; +import io.openems.edge.goodwe.ess.enums.MeterConnectStatus; +import io.openems.edge.goodwe.ess.enums.OperationMode; +import io.openems.edge.goodwe.ess.enums.OutputTypeAC; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; +import io.openems.edge.goodwe.ess.enums.SafetyCountry; +import io.openems.edge.goodwe.ess.enums.WorkMode; + +public interface GoodWeEss extends SymmetricEss, OpenemsComponent { + + public Integer getUnitId(); + + public String getModbusBridgeId(); + + public void addCharger(AbstractGoodWeEtCharger charger); + + public void removeCharger(AbstractGoodWeEtCharger charger); + + public static enum ChannelId implements io.openems.edge.common.channel.ChannelId { + APPLY_POWER_STATE_MACHINE(Doc.of(ApplyPowerStateMachine.State.values())), + + MODBUS_PROTOCOL_VERSION(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + RATED_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + AC_OUTPUT_TYPE(Doc.of(OutputTypeAC.values())), // + SERIAL_NUMBER(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + GOODWE_TYPE(Doc.of(GoodweType.values()) // + .accessMode(AccessMode.READ_ONLY)), + DSP1_SOFTWARE_VERSION(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + DSP2_SOFTWARE_VERSION(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + DSP_SPN_VERSION(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + ARM_SOFTWARE_VERSION(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + ARM_SVN_VERSION(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + DSP_INTERNAL_FIRMWARE_VERSION(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + ARM_INTERNAL_FIRMWARE_VERSION(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + SIMCCID(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + + // Running Data + RTC_YEAR_MONTH(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + RTC_DATE_HOUR(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + RTC_MINUTE_SECOND(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), + V_PV3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), + I_PV3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE).accessMode(AccessMode.READ_ONLY)), + P_PV3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), + V_PV4(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), + I_PV4(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE).accessMode(AccessMode.READ_ONLY)), + P_PV4(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), + PV_MODE(Doc.of(WorkMode.values())), // + TOTAL_INV_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + AC_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + AC_REACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE_REACTIVE).accessMode(AccessMode.READ_ONLY)), // + AC_APPARENT_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE).accessMode(AccessMode.READ_ONLY)), // + BACK_UP_V_LOAD_R(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), + BACK_UP_I_LOAD_R(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE).accessMode(AccessMode.READ_ONLY)), + BACK_UP_F_LOAD_R(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HERTZ).accessMode(AccessMode.READ_ONLY)), + LOAD_MODE_R(Doc.of(LoadMode.values())), // + BACK_UP_P_LOAD_R(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), + BACK_UP_V_LOAD_S(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), + BACK_UP_I_LOAD_S(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE).accessMode(AccessMode.READ_ONLY)), + BACK_UP_F_LOAD_S(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HERTZ).accessMode(AccessMode.READ_ONLY)), + LOAD_MODE_S(Doc.of(LoadMode.values())), // + BACK_UP_P_LOAD_S(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), + BACK_UP_V_LOAD_T(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), + BACK_UP_I_LOAD_T(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE).accessMode(AccessMode.READ_ONLY)), + BACK_UP_F_LOAD_T(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HERTZ).accessMode(AccessMode.READ_ONLY)), + LOAD_MODE_T(Doc.of(LoadMode.values())), // + BACK_UP_P_LOAD_T(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), + P_LOAD_R(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + P_LOAD_S(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + P_LOAD_T(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + TOTAL_BACK_UP_LOAD(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + TOTAL_LOAD_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + UPS_LOAD_PERCENT(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.READ_ONLY)), // + AIR_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.DEGREE_CELSIUS).accessMode(AccessMode.READ_ONLY)), // + MODULE_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.DEGREE_CELSIUS).accessMode(AccessMode.READ_ONLY)), // + RADIATOR_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.DEGREE_CELSIUS).accessMode(AccessMode.READ_ONLY)), // + FUNCTION_BIT_VALUE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + BUS_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), // + NBUS_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), // + V_BATTERY1(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), // + I_BATTERY1(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_ONLY)), // + P_BATTERY1(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + BATTERY_MODE(Doc.of(BatteryMode.values())), // + WARNING_CODE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + SAFETY_COUNTRY(Doc.of(SafetyCountry.values())), // . + WORK_MODE(Doc.of(WorkMode.values())), // + OPERATION_MODE(Doc.of(OperationMode.values())), // + + // Error Message + STATE_0(Doc.of(Level.FAULT).text("The GFCI detecting circuit is abnormal")), // + STATE_1(Doc.of(Level.FAULT).text("The output current sensor is abnormal")), // + STATE_2(Doc.of(Level.WARNING).text("TBD")), // + STATE_3(Doc.of(Level.FAULT).text("DCI Consistency Failure")), // + STATE_4(Doc.of(Level.FAULT).text("GFCI Consistency Failure")), // + STATE_5(Doc.of(Level.WARNING).text("TBD")), // + STATE_6(Doc.of(Level.FAULT).text("GFCI Device Failure")), // + STATE_7(Doc.of(Level.FAULT).text("Relay Device Failure")), // + STATE_8(Doc.of(Level.FAULT).text("AC HCT Failure")), // + STATE_9(Doc.of(Level.FAULT).text("Utility Loss")), // + STATE_10(Doc.of(Level.FAULT).text("Gournd I Failure")), // + STATE_11(Doc.of(Level.WARNING).text("DC Bus High")), // + STATE_12(Doc.of(Level.FAULT).text("Internal Fan Failure(Back-Up Over Load for ES)")), // + STATE_13(Doc.of(Level.WARNING).text("Over Temperature")), // + STATE_14(Doc.of(Level.FAULT).text("Auto Test Failure")), // + STATE_15(Doc.of(Level.WARNING).text("PV Over Voltage")), // + STATE_16(Doc.of(Level.FAULT).text("External Fan Failure")), // + STATE_17(Doc.of(Level.FAULT).text("Vac Failure")), // + STATE_18(Doc.of(Level.FAULT).text("Isolation Failure")), // + STATE_19(Doc.of(Level.WARNING).text("DC Injection High")), // + STATE_20(Doc.of(Level.WARNING).text("TBD")), // + STATE_21(Doc.of(Level.WARNING).text("TBD")), // + STATE_22(Doc.of(Level.FAULT).text("Fac Consistency Failure")), // + STATE_23(Doc.of(Level.FAULT).text("Vac Consistency Failure")), // + STATE_24(Doc.of(Level.WARNING).text("TBD")), // + STATE_25(Doc.of(Level.WARNING).text("Relay Check Failure")), // + STATE_26(Doc.of(Level.WARNING).text("TBD")), // + STATE_27(Doc.of(Level.WARNING).text("TBD")), // + STATE_28(Doc.of(Level.WARNING).text("TBD")), // + STATE_29(Doc.of(Level.FAULT).text("Fac Failure")), // + STATE_30(Doc.of(Level.FAULT).text("EEPROM R/W Failure")), // + STATE_31(Doc.of(Level.FAULT).text("Internal Communication Failure")), // + + PV_E_TOTAL(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + PV_E_DAY(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + E_TOTAL(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + H_TOTAL(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HOUR).accessMode(AccessMode.READ_ONLY)), // + E_DAY_SELL(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + E_TOTAL_BUY(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + E_DAY_BUY(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + E_TOTAL_LOAD(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + E_LOAD_DAY(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + E_BATTERY_CHARGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + E_CHARGE_DAY(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + E_BATTERY_DISCHARGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + E_DISCHARGE_DAY(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + BATT_STRINGS(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + CPLD_WARNING_CODE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + W_CHARGER_CTRL_FLAG(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + DERATE_FLAG(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + DERATE_FROZEN_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + DIAG_STATUS_H(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + DIAG_STATUS_L(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + + // External Communication Data (ARM) + COM_MODE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + RSSI(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + MANIFACTURE_CODE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + B_METER_COMMUNICATE_STATUS(Doc.of(MeterConnectStatus.values())), // + METER_COMMUNICATE_STATUS(Doc.of(MeterCommunicateStatus.values())), // + MT_ACTIVE_POWER_R(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + MT_ACTIVE_POWER_S(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + MT_ACTIVE_POWER_T(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + MT_TOTAL_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + MT_TOTAL_REACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_ONLY)), // + METER_PF_R(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + METER_PF_S(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + METER_PF_T(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + METER_POWER_FACTOR(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + METER_FREQUENCE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + E_TOTAL_SELL(Doc.of(OpenemsType.FLOAT) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + E_TOTAL_BUY2(Doc.of(OpenemsType.FLOAT) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_ONLY)), // + + STATE_32(Doc.of(Level.WARNING).text("DRM0")), // + STATE_33(Doc.of(Level.WARNING).text("DRM1")), // + STATE_34(Doc.of(Level.WARNING).text("DRM2")), // + STATE_35(Doc.of(Level.WARNING).text("DRM3")), // + STATE_36(Doc.of(Level.WARNING).text("DRM4")), // + STATE_37(Doc.of(Level.WARNING).text("DRM5")), // + STATE_38(Doc.of(Level.WARNING).text("DRM6")), // + STATE_39(Doc.of(Level.WARNING).text("DRM7")), // + STATE_40(Doc.of(Level.WARNING).text("DRM8")), // + STATE_41(Doc.of(Level.WARNING).text("DRED Connect Status")), // + + BATTERY_TYPE_INDEX(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + BMS_STATUS(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + BMS_PACK_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.DEGREE_CELSIUS).accessMode(AccessMode.READ_ONLY)), // + BMS_CHARGE_IMAX(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + BMS_DISCHARGE_IMAX(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + + STATE_42(Doc.of(Level.WARNING).text("Charging over-voltage2")), // + STATE_43(Doc.of(Level.WARNING).text("Discharging under-voltage2")), // + STATE_44(Doc.of(Level.WARNING).text("CellHigh temperature2")), // + STATE_45(Doc.of(Level.WARNING).text("CellLow temperature2")), // + STATE_46(Doc.of(Level.WARNING).text("Charging overcurrent2")), // + STATE_47(Doc.of(Level.WARNING).text("Discharging overcurrent2")), // + STATE_48(Doc.of(Level.WARNING).text("Precharge fault")), // + STATE_49(Doc.of(Level.WARNING).text("DC bus fault")), // + STATE_50(Doc.of(Level.WARNING).text("Battery break")), // + STATE_51(Doc.of(Level.WARNING).text("Battery Lock")), // + STATE_52(Doc.of(Level.WARNING).text("Discharge circuit Fault")), // + STATE_53(Doc.of(Level.WARNING).text("Charging circuit Failure")), // + STATE_54(Doc.of(Level.WARNING).text("Communication failure2")), // + STATE_55(Doc.of(Level.WARNING).text("Cell High temperature3")), // + STATE_56(Doc.of(Level.WARNING).text("Discharging under-voltage3")), // + STATE_57(Doc.of(Level.WARNING).text("Charging over-voltage3")), // + + BMS_SOH(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.READ_ONLY)), + BMS_BATTERY_STRINGS(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + + STATE_58(Doc.of(Level.WARNING).text("Charging over-voltage1")), // + STATE_59(Doc.of(Level.WARNING).text("Discharging under-voltage1")), // + STATE_60(Doc.of(Level.WARNING).text("Cell High temperature1")), // + STATE_61(Doc.of(Level.WARNING).text("Cell Low temperature1")), // + STATE_62(Doc.of(Level.WARNING).text("Charging over-current1")), // + STATE_63(Doc.of(Level.WARNING).text("Discharging over-current1")), // + STATE_64(Doc.of(Level.WARNING).text("communication failure1")), // + STATE_65(Doc.of(Level.WARNING).text("System Reboot")), // + STATE_66(Doc.of(Level.WARNING).text("Cell- imbalance")), // + STATE_67(Doc.of(Level.WARNING).text("System Low temperature1")), // + STATE_68(Doc.of(Level.WARNING).text("System Low temperature2")), // + STATE_69(Doc.of(Level.WARNING).text("System High temperature")), // + + BATTERY_PROTOCOL(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_ONLY)), // + + // Setting Parameter + USER_PASSWORD1(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + USER_PASSWORD2(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + USER_PASSWORD3(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + ROUTER_SSID(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + ROUTER_PASSWORD(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + ROUTER_ENCRYPTION_METHOD(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + DOMAIN1(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + PORT_NUMBER1(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + DOMAIN2(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + PORT_NUMBER2(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + MODBUS_ADDRESS(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + MODBUS_MANUFACTURER(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + MODBUS_BADRATE_485(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + RTC_YEAR_MONTH_2(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + RTC_DAY_HOUR_2(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + RTC_MINUTE_SECOND_2(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + SERIAL_NUMBER_2(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + DEVICE_TYPE_2(Doc.of(OpenemsType.STRING) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + RESUME_FACTORY_SETTING(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + CLEAR_DATA(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + START(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // + STOP(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // + RESET(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // + RESET_SPS(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // + PV_E_TOTAL_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // + PV_E_DAY_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // + E_TOTAL_SELL_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // + H_TOTAL_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HOUR).accessMode(AccessMode.READ_WRITE)), // + E_DAY_SELL_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // + E_TOTAL_BUY_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // + E_DAY_BUY_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // + E_TOTAL_LOAD_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // + E_LOAD_DAY_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // + E_BATTERY_CHARGE_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // + E_CHARGE_DAY_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // + E_BATTERY_DISCHARGE_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // + E_DISCHARGE_DAY_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS).accessMode(AccessMode.READ_WRITE)), // + LANGUAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + SAFETY_COUNTRY_CODE(Doc.of(SafetyCountry.values())), // + ISO(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + LVRT(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + ISLANDING(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BURN_IN_RESET_TIME(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.MINUTE).accessMode(AccessMode.READ_WRITE)), // + PV_START_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + ENABLE_MPPT_4SHADOW(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BACK_UP_ENABLE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + AUTO_START_BACKUP(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + GRID_WAVE_CHECK_LEVEL(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + REPAID_CUT_OFF(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BACKUP_START_DLY(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + UPS_STD_VOLT_TYPE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + UNDER_ATS(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BURN_IN_MODE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BACKUP_OVERLOAD_DELAY(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + UPSPHASE_TYPE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + DERATE_RATE_VDE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + LEAD_BAT_CAPACITY(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BATTERY_STRINGS(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BATT_CHARGE_VOLT_MAX(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BATT_CHARGE_CURR_MAX(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BATT_VOLT_UNDER_MIN(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BATT_DISCHARGE_CURR_MAX(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BATT_SOC_UNDER_MIN(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BATT_OFF_LINE_VOLT_UNDER_MIN(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BATT_OFFLINE_SOC_UNDER_MIN(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + CLEAR_BATTERY_SETTING(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // + + // CosPhi curve + ENABLE_CURVE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + POINT_A_VALUE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // + POINT_A_PF(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // + POINT_B_VALUE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // + POINT_B_PF(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // + POINT_C_VALUE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // + POINT_C_PF(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // + LOCK_IN_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + LOCK_OUT_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + LOCK_OUT_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // + + // Power and frequency curve + STATE_70(Doc.of(Level.INFO).text("ON/OFF")), // + STATE_71(Doc.of(Level.INFO).text("response mode")), // + + FFROZEN_DCH(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // + FFROZEN_CH(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // + FSTOP_DCH(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // + FSTOP_CH(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // + RECOVERY_WAITING_TIME(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.SECONDS).accessMode(AccessMode.READ_WRITE)), // + RECOVERY_FREQURNCY1(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // + RECOVERY_FREQUENCY2(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // + RECOVERY_SLOPE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + FFROZEN_DCH_SLOPE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // + FFROZEN_CH_SLOPE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HERTZ).accessMode(AccessMode.READ_WRITE)), // + DOWN_SLOPE_POWER_REFERENCE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + DOWN_SLOP(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + + // QU curve + ENABLE_CURVE_QU(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + LOCK_IN_POWER_QU(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // + LOCK_OUT_POWER_QU(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // + V1_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + V1_VALUE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // + V2_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + V2_VALUE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // + V3_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + V3_VALUE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // + V4_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + V4_VALUE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // + K_VALUE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + TIME_CONSTANT(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + MISCELLANEA(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + RATED_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + RESPONSE_TIME(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + + // PU curve + PU_CURVE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + POWER_CHANGE_RATE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + V1_VOLTAGE_PU(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + V1_VALUE_PU(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + V2_VOLTAGE_PU(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + V2_VALUE_PU(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + V3_VOLTAGE_PU(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + V3_VALUE_PU(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + V4_VOLTAGE_PU(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + V4_VALUE_PU(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + FIXED_POWER_FACTOR(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + FIXED_REACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + FIXED_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + GRID_LIMIT_BY_VOLT_START_VOL(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + GRID_LIMIT_BY_VOLT_START_PER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // + GRID_LIMIT_BY_VOLT_SLOPE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.WRITE_ONLY)), // + AUTO_TEST_ENABLE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // + AUTO_TEST_STEP(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // + UW_ITALY_FREQ_MODE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + + // Meter Control ARM + APP_MODE_INDEX(Doc.of(AppModeIndex.values())), // + METER_CHECK_VALUE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + WMETER_CONNECT_CHECK_FLAG(Doc.of(MeterConnectCheckFlag.values())), // + SIMULATE_METER_POWER(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BREEZE_ON_OFF(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + LOG_DATA_ENABLE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + DATA_SEND_INTERVAL(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.SECONDS).accessMode(AccessMode.READ_WRITE)), // + + // Battery Control Data ARM + STOP_SOC_PROTECT(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BATTERY_FLOAT_VOLT(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + BATTERY_FLOAT_CURRENT(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE).accessMode(AccessMode.READ_WRITE)), // + BATTERY_FLOAT_TIME(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.MINUTE).accessMode(AccessMode.READ_WRITE)), // + BATTERY_TYPE_INDEX_ARM(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + MANUFACTURE_CODE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + DC_VOLT_OUTPUT(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BAT_AVG_CHG_VOLT(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + BAT_AVG_CHG_HOURS(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.HOUR).accessMode(AccessMode.READ_WRITE)), // + FEED_POWER_ENABLE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + FEED_POWER_PARA(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.WATT).accessMode(AccessMode.READ_WRITE)), // + EMS_POWER_MODE(Doc.of(PowerModeEms.values()) // + .accessMode(AccessMode.READ_WRITE)), // + EMS_POWER_SET(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BAT_BMS_CURR_LMT_COFF(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BATTERY_PROTOCOL_ARM(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + START_TIME_1(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + END_TIME_1(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BAT_POWER_PERCENT_1(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // + + STATE_72(Doc.of(Level.INFO).text("SUNDAY")), // + STATE_73(Doc.of(Level.WARNING).text("MONDAY")), // + STATE_74(Doc.of(Level.WARNING).text("TUESDAY")), // + STATE_75(Doc.of(Level.WARNING).text("Wednesday")), // + STATE_76(Doc.of(Level.WARNING).text("Thursday")), // + STATE_77(Doc.of(Level.WARNING).text("Friday")), // + STATE_78(Doc.of(Level.WARNING).text("Saturday")), // + + START_TIME_2(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + END_TIME_2(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BAT_POWER_PERCENT_2(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // + START_TIME_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + END_TIME_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BAT_POWER_PERCENT_3(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // + START_TIME_4(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + END_TIME_4(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BAT_POWER_PERCENT_4(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // + SOC_START_TO_FORCE_CHARGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + SOC_STOP_TO_FORCE_CHARGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + CLEAR_ALL_ECONOMIC_MODE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.WRITE_ONLY)), // + + // BMS for RS485 + BMS_VERSION(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + BATT_STRINGS_RS485(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.NONE).accessMode(AccessMode.READ_WRITE)), // + WBMS_BAT_CHARGE_VMAX(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + WBMS_BAT_CHARGE_IMAX(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE).accessMode(AccessMode.READ_WRITE)), // + WBMS_BAT_DISCHARGE_VMIN(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + WBMS_BAT_DISCHARGE_IMAX(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE).accessMode(AccessMode.READ_WRITE)), // + WBMS_BAT_VOLTAGE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.VOLT).accessMode(AccessMode.READ_WRITE)), // + WBMS_BAT_CURRENT(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.AMPERE).accessMode(AccessMode.READ_WRITE)), // + WBMS_BAT_SOC(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // + WBMS_BAT_SOH(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.PERCENT).accessMode(AccessMode.READ_WRITE)), // + WBMS_BAT_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.DEGREE_CELSIUS).accessMode(AccessMode.READ_WRITE)), // + + // BMS_STATUS(), // + STATE_79(Doc.of(Level.INFO).text("force to charge")), // + STATE_80(Doc.of(Level.INFO).text("Stop charging")), // TODO can be removed? + STATE_81(Doc.of(Level.INFO).text("Stop discharging")); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Channel for {@link ChannelId#GOODWE_TYPE}. + * + * @return the Channel + */ + public default Channel getGoodweTypeChannel() { + return this.channel(GoodWeEss.ChannelId.GOODWE_TYPE); + } + + /** + * Gets the Device Type. See {@link ChannelId#GOODWE_TYPE}. + * + * @return the Channel {@link Value} + */ + public default GoodweType getGoodweType() { + return this.getGoodweTypeChannel().value().asEnum(); + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/GoodWeEssImpl.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/GoodWeEssImpl.java new file mode 100644 index 00000000000..f037d4b3bfb --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/GoodWeEssImpl.java @@ -0,0 +1,608 @@ +package io.openems.edge.goodwe.ess; + +import java.util.HashSet; +import java.util.Set; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventConstants; +import org.osgi.service.event.EventHandler; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.types.OpenemsType; +import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; +import io.openems.edge.bridge.modbus.api.BridgeModbus; +import io.openems.edge.bridge.modbus.api.ElementToChannelConverter; +import io.openems.edge.bridge.modbus.api.ModbusProtocol; +import io.openems.edge.bridge.modbus.api.element.BitsWordElement; +import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement; +import io.openems.edge.bridge.modbus.api.element.SignedWordElement; +import io.openems.edge.bridge.modbus.api.element.StringWordElement; +import io.openems.edge.bridge.modbus.api.element.UnsignedDoublewordElement; +import io.openems.edge.bridge.modbus.api.element.UnsignedWordElement; +import io.openems.edge.bridge.modbus.api.task.FC16WriteRegistersTask; +import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.EnumReadChannel; +import io.openems.edge.common.channel.EnumWriteChannel; +import io.openems.edge.common.channel.IntegerWriteChannel; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.common.sum.GridMode; +import io.openems.edge.common.taskmanager.Priority; +import io.openems.edge.common.type.TypeUtils; +import io.openems.edge.ess.api.HybridEss; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.power.api.Constraint; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Power; +import io.openems.edge.ess.power.api.Pwr; +import io.openems.edge.ess.power.api.Relationship; +import io.openems.edge.goodwe.charger.AbstractGoodWeEtCharger; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine; +import io.openems.edge.goodwe.ess.applypower.Context; +import io.openems.edge.goodwe.ess.enums.BatteryMode; +import io.openems.edge.goodwe.ess.enums.GoodweType; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "GoodWe.Ess", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE, // + property = EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE // +) // +public class GoodWeEssImpl extends AbstractOpenemsModbusComponent implements GoodWeEss, HybridEss, ManagedSymmetricEss, + SymmetricEss, OpenemsComponent, TimedataProvider, EventHandler { + + private final Logger log = LoggerFactory.getLogger(GoodWeEssImpl.class); + + private Config config; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata = null; + + @Reference + protected ConfigurationAdmin cm; + + @Reference + private Power power; + + private final CalculateEnergyFromPower calculateAcChargeEnergy = new CalculateEnergyFromPower(this, + SymmetricEss.ChannelId.ACTIVE_CHARGE_ENERGY); + private final CalculateEnergyFromPower calculateAcDischargeEnergy = new CalculateEnergyFromPower(this, + SymmetricEss.ChannelId.ACTIVE_DISCHARGE_ENERGY); + + private final Set chargers = new HashSet<>(); + + private final ApplyPowerStateMachine applyPowerStateMachine = new ApplyPowerStateMachine( + ApplyPowerStateMachine.State.UNDEFINED); + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + protected void setModbus(BridgeModbus modbus) { + super.setModbus(modbus); + } + + @Activate + void activate(ComponentContext context, Config config) throws OpenemsNamedException { + super.activate(context, config.id(), config.alias(), config.enabled(), config.unit_id(), this.cm, "Modbus", + config.modbus_id()); + this.config = config; + this._setCapacity(this.config.capacity()); + } + + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + public GoodWeEssImpl() throws OpenemsNamedException { + super(// + OpenemsComponent.ChannelId.values(), // + SymmetricEss.ChannelId.values(), // + ManagedSymmetricEss.ChannelId.values(), // + HybridEss.ChannelId.values(), // + GoodWeEss.ChannelId.values() // + ); + } + + public String getModbusBridgeId() { + return this.config.modbus_id(); + } + + @Override + protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + return new ModbusProtocol(this, // + + new FC3ReadRegistersTask(35001, Priority.ONCE, // + m(SymmetricEss.ChannelId.MAX_APPARENT_POWER, new UnsignedWordElement(35001)), // + new DummyRegisterElement(35002), // + m(GoodWeEss.ChannelId.SERIAL_NUMBER, new StringWordElement(35003, 8)), // + m(GoodWeEss.ChannelId.GOODWE_TYPE, new StringWordElement(35011, 5), + new ElementToChannelConverter((value) -> { + String stringValue = TypeUtils.getAsType(OpenemsType.STRING, value); + switch (stringValue) { + case "GW10K-BT": + this.logInfo(this.log, "Identified GoodWe GW10K-BT"); + return GoodweType.GOODWE_10K_BT; + case "GW10K-ET": + this.logInfo(this.log, "Identified GoodWe GW10K-ET"); + return GoodweType.GOODWE_10K_ET; + default: + this.logError(this.log, "Unable to identify GoodWe [" + stringValue + "]"); + return GoodweType.UNDEFINED; + } + }))), // + + new FC3ReadRegistersTask(35111, Priority.LOW, // + m(GoodWeEss.ChannelId.V_PV3, new UnsignedWordElement(35111), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + m(GoodWeEss.ChannelId.I_PV3, new UnsignedWordElement(35112), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + new DummyRegisterElement(35113, 35114), // + m(GoodWeEss.ChannelId.V_PV4, new UnsignedWordElement(35115), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + m(GoodWeEss.ChannelId.I_PV4, new UnsignedWordElement(35116), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + new DummyRegisterElement(35117, 35118), // + m(GoodWeEss.ChannelId.PV_MODE, new UnsignedDoublewordElement(35119))), // + + new FC3ReadRegistersTask(35136, Priority.LOW, // + m(SymmetricEss.ChannelId.GRID_MODE, new UnsignedWordElement(35136), // + new ElementToChannelConverter((value) -> { + Integer intValue = TypeUtils.getAsType(OpenemsType.INTEGER, value); + if (intValue != null) { + switch (intValue) { + case 0: + return GridMode.OFF_GRID; + case 1: + return GridMode.ON_GRID; + case 2: + return GridMode.UNDEFINED; + } + } + return GridMode.UNDEFINED; + }))), // + new FC3ReadRegistersTask(35138, Priority.LOW, // + m(GoodWeEss.ChannelId.TOTAL_INV_POWER, new SignedWordElement(35138)), // + new DummyRegisterElement(35139), // + m(GoodWeEss.ChannelId.AC_ACTIVE_POWER, new SignedWordElement(35140), // + ElementToChannelConverter.INVERT), // + new DummyRegisterElement(35141), // + m(GoodWeEss.ChannelId.AC_REACTIVE_POWER, new SignedWordElement(35142), // + ElementToChannelConverter.INVERT), // + new DummyRegisterElement(35143), // + m(GoodWeEss.ChannelId.AC_APPARENT_POWER, new SignedWordElement(35144), // + ElementToChannelConverter.INVERT), // + m(GoodWeEss.ChannelId.BACK_UP_V_LOAD_R, new UnsignedWordElement(35145), // + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + m(GoodWeEss.ChannelId.BACK_UP_I_LOAD_R, new UnsignedWordElement(35146), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + m(GoodWeEss.ChannelId.BACK_UP_F_LOAD_R, new UnsignedWordElement(35147), + ElementToChannelConverter.SCALE_FACTOR_MINUS_2), // + m(GoodWeEss.ChannelId.LOAD_MODE_R, new UnsignedWordElement(35148)), // + new DummyRegisterElement(35149), // + m(GoodWeEss.ChannelId.BACK_UP_P_LOAD_R, new SignedWordElement(35150)), // + m(GoodWeEss.ChannelId.BACK_UP_V_LOAD_S, new UnsignedWordElement(35151), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + m(GoodWeEss.ChannelId.BACK_UP_I_LOAD_S, new UnsignedWordElement(35152), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + m(GoodWeEss.ChannelId.BACK_UP_F_LOAD_S, new UnsignedWordElement(35153), + ElementToChannelConverter.SCALE_FACTOR_MINUS_2), // + m(GoodWeEss.ChannelId.LOAD_MODE_S, new UnsignedWordElement(35154)), // + new DummyRegisterElement(35155), // + m(GoodWeEss.ChannelId.BACK_UP_P_LOAD_S, new SignedWordElement(35156)), // + m(GoodWeEss.ChannelId.BACK_UP_V_LOAD_T, new UnsignedWordElement(35157), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + m(GoodWeEss.ChannelId.BACK_UP_I_LOAD_T, new UnsignedWordElement(35158), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + m(GoodWeEss.ChannelId.BACK_UP_F_LOAD_T, new UnsignedWordElement(35159), + ElementToChannelConverter.SCALE_FACTOR_MINUS_2), // + m(GoodWeEss.ChannelId.LOAD_MODE_T, new UnsignedWordElement(35160)), // + new DummyRegisterElement(35161), // + m(GoodWeEss.ChannelId.BACK_UP_P_LOAD_T, new SignedWordElement(35162)), // + new DummyRegisterElement(35163), // + m(GoodWeEss.ChannelId.P_LOAD_R, new SignedWordElement(35164)), // + new DummyRegisterElement(35165), // + m(GoodWeEss.ChannelId.P_LOAD_S, new SignedWordElement(35166)), // + new DummyRegisterElement(35167), // + m(GoodWeEss.ChannelId.P_LOAD_T, new SignedWordElement(35168)), // + new DummyRegisterElement(35169), // + m(GoodWeEss.ChannelId.TOTAL_BACK_UP_LOAD, new SignedWordElement(35170)), // + new DummyRegisterElement(35171), // + m(GoodWeEss.ChannelId.TOTAL_LOAD_POWER, new SignedWordElement(35172)), // + m(GoodWeEss.ChannelId.UPS_LOAD_PERCENT, new UnsignedWordElement(35173), + ElementToChannelConverter.SCALE_FACTOR_MINUS_2)), // + + new FC3ReadRegistersTask(35180, Priority.HIGH, // + m(GoodWeEss.ChannelId.V_BATTERY1, new UnsignedWordElement(35180), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + m(GoodWeEss.ChannelId.I_BATTERY1, new SignedWordElement(35181), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + new DummyRegisterElement(35182), // + m(GoodWeEss.ChannelId.P_BATTERY1, new SignedWordElement(35183)), // required for ActivePower + m(GoodWeEss.ChannelId.BATTERY_MODE, new UnsignedWordElement(35184))), // + + new FC3ReadRegistersTask(35185, Priority.LOW, // + m(GoodWeEss.ChannelId.WARNING_CODE, new UnsignedWordElement(35185)), // + m(GoodWeEss.ChannelId.SAFETY_COUNTRY, new UnsignedWordElement(35186)), // + m(GoodWeEss.ChannelId.WORK_MODE, new UnsignedWordElement(35187)), // + m(GoodWeEss.ChannelId.OPERATION_MODE, new UnsignedDoublewordElement(35188))), // + + new FC3ReadRegistersTask(35206, Priority.LOW, // + m(HybridEss.ChannelId.DC_CHARGE_ENERGY, new UnsignedDoublewordElement(35206), // + ElementToChannelConverter.SCALE_FACTOR_2), // + new DummyRegisterElement(35208), // + m(HybridEss.ChannelId.DC_DISCHARGE_ENERGY, new UnsignedDoublewordElement(35209), + ElementToChannelConverter.SCALE_FACTOR_2)), // + + new FC3ReadRegistersTask(36003, Priority.LOW, // + m(GoodWeEss.ChannelId.B_METER_COMMUNICATE_STATUS, new UnsignedWordElement(36003)), // + m(GoodWeEss.ChannelId.METER_COMMUNICATE_STATUS, new UnsignedWordElement(36004))), // + + new FC3ReadRegistersTask(37001, Priority.LOW, + m(GoodWeEss.ChannelId.BATTERY_TYPE_INDEX, new UnsignedWordElement(37001)), // + m(GoodWeEss.ChannelId.BMS_STATUS, new UnsignedWordElement(37002)), // + m(GoodWeEss.ChannelId.BMS_PACK_TEMPERATURE, new UnsignedWordElement(37003), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + m(GoodWeEss.ChannelId.BMS_CHARGE_IMAX, new UnsignedWordElement(37004)), // + m(GoodWeEss.ChannelId.BMS_DISCHARGE_IMAX, new UnsignedWordElement(37005))), // + + new FC3ReadRegistersTask(37007, Priority.LOW, // + m(SymmetricEss.ChannelId.SOC, new UnsignedWordElement(37007), new ElementToChannelConverter( + // element -> channel + value -> { + // Set SoC to undefined if there is No Battery + EnumReadChannel batteryModeChannel = this.channel(GoodWeEss.ChannelId.BATTERY_MODE); + BatteryMode batteryMode = batteryModeChannel.value().asEnum(); + if (batteryMode == BatteryMode.NO_BATTERY || batteryMode == BatteryMode.UNDEFINED) { + return null; + } else { + return value; + } + }, + // channel -> element + value -> value))), // + + new FC3ReadRegistersTask(37008, Priority.LOW, // + m(GoodWeEss.ChannelId.BMS_SOH, new UnsignedWordElement(37008)), // + m(GoodWeEss.ChannelId.BMS_BATTERY_STRINGS, new UnsignedWordElement(37009))), // + + new FC16WriteRegistersTask(47000, // + m(GoodWeEss.ChannelId.APP_MODE_INDEX, new UnsignedWordElement(47000)), // + m(GoodWeEss.ChannelId.METER_CHECK_VALUE, new UnsignedWordElement(47001)), // + m(GoodWeEss.ChannelId.WMETER_CONNECT_CHECK_FLAG, new UnsignedWordElement(47002))), // + + new FC3ReadRegistersTask(47000, Priority.LOW, // + m(GoodWeEss.ChannelId.APP_MODE_INDEX, new UnsignedWordElement(47000)), // + m(GoodWeEss.ChannelId.METER_CHECK_VALUE, new UnsignedWordElement(47001)), // + m(GoodWeEss.ChannelId.WMETER_CONNECT_CHECK_FLAG, new UnsignedWordElement(47002))), // + + new FC16WriteRegistersTask(47500, // + m(GoodWeEss.ChannelId.STOP_SOC_PROTECT, new UnsignedWordElement(47500)), // + new DummyRegisterElement(47501, 47508), // + m(GoodWeEss.ChannelId.FEED_POWER_ENABLE, new UnsignedWordElement(47509)), // + m(GoodWeEss.ChannelId.FEED_POWER_PARA, new UnsignedWordElement(47510)), // + m(GoodWeEss.ChannelId.EMS_POWER_MODE, new UnsignedWordElement(47511)), // + m(GoodWeEss.ChannelId.EMS_POWER_SET, new UnsignedWordElement(47512))), // + + new FC16WriteRegistersTask(47531, // + m(GoodWeEss.ChannelId.SOC_START_TO_FORCE_CHARGE, new UnsignedWordElement(47531)), // + m(GoodWeEss.ChannelId.SOC_STOP_TO_FORCE_CHARGE, new UnsignedWordElement(47532)), // + m(GoodWeEss.ChannelId.CLEAR_ALL_ECONOMIC_MODE, new UnsignedWordElement(47533))), // + + new FC3ReadRegistersTask(47500, Priority.LOW, + m(GoodWeEss.ChannelId.STOP_SOC_PROTECT, new UnsignedWordElement(47500)), // + new DummyRegisterElement(47501, 47508), // + m(GoodWeEss.ChannelId.FEED_POWER_ENABLE, new UnsignedWordElement(47509)), // + m(GoodWeEss.ChannelId.FEED_POWER_PARA, new UnsignedWordElement(47510))), // + + new FC3ReadRegistersTask(47511, Priority.LOW, + m(GoodWeEss.ChannelId.EMS_POWER_MODE, new UnsignedWordElement(47511)), // + m(GoodWeEss.ChannelId.EMS_POWER_SET, new UnsignedWordElement(47512))), // + + new FC3ReadRegistersTask(47531, Priority.LOW, + m(GoodWeEss.ChannelId.SOC_START_TO_FORCE_CHARGE, new UnsignedWordElement(47531)), // + m(GoodWeEss.ChannelId.SOC_STOP_TO_FORCE_CHARGE, new UnsignedWordElement(47532))), // + + new FC16WriteRegistersTask(47900, // + m(GoodWeEss.ChannelId.BMS_VERSION, new UnsignedWordElement(47900)), // + m(GoodWeEss.ChannelId.BATT_STRINGS_RS485, new UnsignedWordElement(47901)), // + m(GoodWeEss.ChannelId.WBMS_BAT_CHARGE_VMAX, new UnsignedWordElement(47902)), // + m(GoodWeEss.ChannelId.WBMS_BAT_CHARGE_IMAX, new UnsignedWordElement(47903)), // + m(GoodWeEss.ChannelId.WBMS_BAT_DISCHARGE_VMIN, new UnsignedWordElement(47904)), // + m(GoodWeEss.ChannelId.WBMS_BAT_DISCHARGE_IMAX, new UnsignedWordElement(47905)), // + m(GoodWeEss.ChannelId.WBMS_BAT_VOLTAGE, new UnsignedWordElement(47906)), // + m(GoodWeEss.ChannelId.WBMS_BAT_CURRENT, new UnsignedWordElement(47907)), // + m(GoodWeEss.ChannelId.WBMS_BAT_SOC, new UnsignedWordElement(47908)), // + m(GoodWeEss.ChannelId.WBMS_BAT_SOH, new UnsignedWordElement(47909)), // + m(GoodWeEss.ChannelId.WBMS_BAT_TEMPERATURE, new UnsignedWordElement(47910)), // + m(new BitsWordElement(47911, this) // + .bit(0, GoodWeEss.ChannelId.STATE_58) // + .bit(1, GoodWeEss.ChannelId.STATE_59) // + .bit(2, GoodWeEss.ChannelId.STATE_60) // + .bit(3, GoodWeEss.ChannelId.STATE_61) // + .bit(4, GoodWeEss.ChannelId.STATE_62) // + .bit(5, GoodWeEss.ChannelId.STATE_63) // + .bit(6, GoodWeEss.ChannelId.STATE_64) // + .bit(7, GoodWeEss.ChannelId.STATE_65) // + .bit(8, GoodWeEss.ChannelId.STATE_66) // + .bit(9, GoodWeEss.ChannelId.STATE_67) // + .bit(10, GoodWeEss.ChannelId.STATE_68) // + .bit(11, GoodWeEss.ChannelId.STATE_69)), // + new DummyRegisterElement(47912), // + m(new BitsWordElement(47913, this) // + .bit(0, GoodWeEss.ChannelId.STATE_42) // + .bit(1, GoodWeEss.ChannelId.STATE_43) // + .bit(2, GoodWeEss.ChannelId.STATE_44) // + .bit(3, GoodWeEss.ChannelId.STATE_45) // + .bit(4, GoodWeEss.ChannelId.STATE_46) // + .bit(5, GoodWeEss.ChannelId.STATE_47) // + .bit(6, GoodWeEss.ChannelId.STATE_48) // + .bit(7, GoodWeEss.ChannelId.STATE_49) // + .bit(8, GoodWeEss.ChannelId.STATE_50) // + .bit(9, GoodWeEss.ChannelId.STATE_51) // + .bit(10, GoodWeEss.ChannelId.STATE_52) // + .bit(11, GoodWeEss.ChannelId.STATE_53) // + .bit(12, GoodWeEss.ChannelId.STATE_54) // + .bit(13, GoodWeEss.ChannelId.STATE_55) // + .bit(14, GoodWeEss.ChannelId.STATE_56) // + .bit(15, GoodWeEss.ChannelId.STATE_57)), // + new DummyRegisterElement(47914), // + m(new BitsWordElement(47915, this) // + .bit(0, GoodWeEss.ChannelId.STATE_79) // + .bit(1, GoodWeEss.ChannelId.STATE_80) // + .bit(2, GoodWeEss.ChannelId.STATE_81))), // + + new FC3ReadRegistersTask(47902, Priority.LOW, // + m(GoodWeEss.ChannelId.WBMS_BAT_CHARGE_VMAX, new UnsignedWordElement(47902)), // + m(GoodWeEss.ChannelId.WBMS_BAT_CHARGE_IMAX, new UnsignedWordElement(47903)), // + m(GoodWeEss.ChannelId.WBMS_BAT_DISCHARGE_VMIN, new UnsignedWordElement(47904)), // + m(GoodWeEss.ChannelId.WBMS_BAT_DISCHARGE_IMAX, new UnsignedWordElement(47905)), // + m(GoodWeEss.ChannelId.WBMS_BAT_VOLTAGE, new UnsignedWordElement(47906)), // + m(GoodWeEss.ChannelId.WBMS_BAT_CURRENT, new UnsignedWordElement(47907)), // + m(GoodWeEss.ChannelId.WBMS_BAT_SOC, new UnsignedWordElement(47908)), // + m(GoodWeEss.ChannelId.WBMS_BAT_SOH, new UnsignedWordElement(47909)), // + m(GoodWeEss.ChannelId.WBMS_BAT_TEMPERATURE, new UnsignedWordElement(47910)), // + m(new BitsWordElement(47911, this) // + .bit(0, GoodWeEss.ChannelId.STATE_58) // + .bit(1, GoodWeEss.ChannelId.STATE_59) // + .bit(2, GoodWeEss.ChannelId.STATE_60) // + .bit(3, GoodWeEss.ChannelId.STATE_61) // + .bit(4, GoodWeEss.ChannelId.STATE_62) // + .bit(5, GoodWeEss.ChannelId.STATE_63) // + .bit(6, GoodWeEss.ChannelId.STATE_64) // + .bit(7, GoodWeEss.ChannelId.STATE_65) // + .bit(8, GoodWeEss.ChannelId.STATE_66) // + .bit(9, GoodWeEss.ChannelId.STATE_67) // + .bit(10, GoodWeEss.ChannelId.STATE_68) // + .bit(11, GoodWeEss.ChannelId.STATE_69)), // + new DummyRegisterElement(47912), // + m(new BitsWordElement(47913, this) // + .bit(0, GoodWeEss.ChannelId.STATE_42) // + .bit(1, GoodWeEss.ChannelId.STATE_43) // + .bit(2, GoodWeEss.ChannelId.STATE_44) // + .bit(3, GoodWeEss.ChannelId.STATE_45) // + .bit(4, GoodWeEss.ChannelId.STATE_46) // + .bit(5, GoodWeEss.ChannelId.STATE_47) // + .bit(6, GoodWeEss.ChannelId.STATE_48) // + .bit(7, GoodWeEss.ChannelId.STATE_49) // + .bit(8, GoodWeEss.ChannelId.STATE_50) // + .bit(9, GoodWeEss.ChannelId.STATE_51) // + .bit(10, GoodWeEss.ChannelId.STATE_52) // + .bit(11, GoodWeEss.ChannelId.STATE_53) // + .bit(12, GoodWeEss.ChannelId.STATE_54) // + .bit(13, GoodWeEss.ChannelId.STATE_55) // + .bit(14, GoodWeEss.ChannelId.STATE_56) // + .bit(15, GoodWeEss.ChannelId.STATE_57)), // + new DummyRegisterElement(47914), // + m(new BitsWordElement(47915, this) // + .bit(0, GoodWeEss.ChannelId.STATE_79) // + .bit(1, GoodWeEss.ChannelId.STATE_80) // + .bit(2, GoodWeEss.ChannelId.STATE_81)))); + } + + @Override + public void applyPower(int activePower, int reactivePower) throws OpenemsNamedException { + int pvProduction = getPvProduction(); + int soc = this.getSoc().orElse(0); + ApplyPowerStateMachine.State state = ApplyPowerStateMachine.evaluateState(this.getGoodweType(), + config.readOnlyMode(), pvProduction, soc, activePower); + + // Store the current State + this.channel(GoodWeEss.ChannelId.APPLY_POWER_STATE_MACHINE).setNextValue(state); + + // Prepare Context + Context context = new Context(this, pvProduction, activePower); + + this.applyPowerStateMachine.forceNextState(state); + this.applyPowerStateMachine.run(context); // apply the force next state + this.applyPowerStateMachine.run(context); // execute correct handler + + IntegerWriteChannel emsPowerSetChannel = this.channel(GoodWeEss.ChannelId.EMS_POWER_SET); + emsPowerSetChannel.setNextWriteValue(context.getEssPowerSet()); + + EnumWriteChannel emsPowerModeChannel = this.channel(GoodWeEss.ChannelId.EMS_POWER_MODE); + emsPowerModeChannel.setNextWriteValue(context.getNextPowerMode()); + } + + @Override + public String debugLog() { + return "SoC:" + this.getSoc().asString() // + + "|L:" + this.getActivePower().asString() // + + "|" + this.getGridModeChannel().value().asOptionString()// + + "|Allowed:" + this.getAllowedChargePower().asStringWithoutUnit() + ";" + + this.getAllowedDischargePower().asString(); + } + + @Override + public void addCharger(AbstractGoodWeEtCharger charger) { + this.chargers.add(charger); + } + + @Override + public void removeCharger(AbstractGoodWeEtCharger charger) { + this.chargers.remove(charger); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: + this.updatechannels(); + break; + } + } + + private void updatechannels() { + /* + * Update ActivePower from P_BATTERY1 and chargers ACTUAL_POWER + */ + final Channel batteryPower = this.channel(GoodWeEss.ChannelId.P_BATTERY1); + Integer productionPower = null; + for (AbstractGoodWeEtCharger charger : this.chargers) { + productionPower = TypeUtils.sum(productionPower, charger.getActualPower().get()); + } + Integer activePower = TypeUtils.sum(productionPower, batteryPower.value().get()); + this._setActivePower(activePower); + + /* + * Calculate AC Energy + */ + if (activePower == null) { + // Not available + this.calculateAcChargeEnergy.update(null); + this.calculateAcDischargeEnergy.update(null); + } else if (activePower > 0) { + // Discharge + this.calculateAcChargeEnergy.update(0); + this.calculateAcDischargeEnergy.update(activePower); + } else { + // Charge + this.calculateAcChargeEnergy.update(activePower * -1); + this.calculateAcDischargeEnergy.update(0); + } + + /* + * Update Allowed charge and Allowed discharge + */ + + Integer soc = this.getSoc().get(); + Integer maxBatteryPower = this.config.maxBatteryPower(); + + Integer allowedCharge = null; + Integer allowedDischarge = null; + + if (productionPower == null) { + productionPower = 0; + } + + if (soc == null) { + + allowedCharge = 0; + allowedDischarge = 0; + + } else if (soc == 100) { + + allowedDischarge = maxBatteryPower + productionPower; + allowedCharge = 0; + + } else if (soc > 0) { + + allowedDischarge = maxBatteryPower + productionPower; + allowedCharge = maxBatteryPower; + + } else if (soc == 0) { + + allowedDischarge = productionPower; + allowedCharge = maxBatteryPower; + + } + + // to avoid charging when production is greater than maximum battery power. + if (allowedCharge < 0) { + allowedCharge = 0; + } + + this._setAllowedChargePower(TypeUtils.multiply(allowedCharge * -1)); + this._setAllowedDischargePower(allowedDischarge); + } + + @Override + public Power getPower() { + return this.power; + } + + @Override + public int getPowerPrecision() { + return 1; + } + + @Override + public Constraint[] getStaticConstraints() throws OpenemsNamedException { + // Handle Read-Only mode -> no charge/discharge + if (this.config.readOnlyMode()) { + return new Constraint[] { // + this.createPowerConstraint("Read-Only-Mode", Phase.ALL, Pwr.ACTIVE, Relationship.EQUALS, 0), // + this.createPowerConstraint("Read-Only-Mode", Phase.ALL, Pwr.REACTIVE, Relationship.EQUALS, 0) // + }; + } + + return Power.NO_CONSTRAINTS; + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + @Override + public Integer getSurplusPower() { + if (this.getSoc().orElse(0) < 99) { + return null; + } + Integer productionPower = null; + for (AbstractGoodWeEtCharger charger : this.chargers) { + productionPower = TypeUtils.sum(productionPower, charger.getActualPower().get()); + } + if (productionPower == null || productionPower < 100) { + return null; + } + return productionPower; + } + + /** + * Gets the PV production. Returns 0 if the PV production is not available. + * + * @return production power + */ + private int getPvProduction() { + int productionPower = 0; + for (AbstractGoodWeEtCharger charger : this.chargers) { + productionPower = TypeUtils.sum(productionPower, charger.getActualPower().get()); + } + + return productionPower; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/ApplyPowerStateMachine.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/ApplyPowerStateMachine.java new file mode 100644 index 00000000000..544a0646e89 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/ApplyPowerStateMachine.java @@ -0,0 +1,180 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.common.types.OptionsEnum; +import io.openems.edge.common.statemachine.AbstractStateMachine; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.enums.GoodweType; + +public class ApplyPowerStateMachine extends AbstractStateMachine { + + public enum State implements io.openems.edge.common.statemachine.State, OptionsEnum { + UNDEFINED(-1), // + + READ_ONLY(10), // + + /* + * GoodWe ET handling + */ + ET_FULL_POSITIVE_DISCHARGE(20), // + ET_FULL_POSITIVE_CURTAIL(21), // + ET_FULL_NEGATIVE_CURTAIL(21), // + + ET_EMPTY_POSITIVE_PV(30), // + ET_EMPTY_NEGATIVE_CHARGE(31), // + + ET_INBETWEEN_POSITIVE_DISCHARGE(41), // + ET_INBETWEEN_POSITIVE_CHARGE(42), // + ET_INBETWEEN_NEGATIVE_CHARGE(43), // + + /* + * GoodWe BT handling + */ + BT_CHARGE(50), // + BT_DISCHARGE(51), // + ; + + private final int value; + + private State(int value) { + this.value = value; + } + + @Override + public int getValue() { + return this.value; + } + + @Override + public String getName() { + return this.name(); + } + + @Override + public OptionsEnum getUndefined() { + return UNDEFINED; + } + + @Override + public State[] getStates() { + return State.values(); + } + } + + public ApplyPowerStateMachine(State initialState) { + super(initialState); + } + + @Override + public StateHandler getStateHandler(State state) { + switch (state) { + case UNDEFINED: + return new UndefinedHandler(); + case READ_ONLY: + return new ReadOnlyHandler(); + + case ET_EMPTY_NEGATIVE_CHARGE: + return new EtEmptyNegativeChargeHandler(); + case ET_EMPTY_POSITIVE_PV: + return new EtEmptyPositivePvHandler(); + case ET_FULL_NEGATIVE_CURTAIL: + return new EtFullNegativeCurtailHandler(); + case ET_FULL_POSITIVE_CURTAIL: + return new EtFullPositiveCurtailHandler(); + case ET_FULL_POSITIVE_DISCHARGE: + return new EtFullPositiveDischargeHandler(); + case ET_INBETWEEN_NEGATIVE_CHARGE: + return new EtInbetweenNegativeChargeHandler(); + case ET_INBETWEEN_POSITIVE_CHARGE: + return new EtInbetweenPositiveChargeHandler(); + case ET_INBETWEEN_POSITIVE_DISCHARGE: + return new EtInbetweenPositiveDischargeHandler(); + + case BT_CHARGE: + return new BtChargeHandler(); + case BT_DISCHARGE: + return new BtDischargeHandler(); + } + throw new IllegalArgumentException("Unknown State [" + state + "]"); + } + + /** + * Evaluates the State we are currently in. + * + * @param readOnlyMode + * @param pvProduction + * @param soc + * @param activePowerSetPoint + * @return + */ + public static State evaluateState(GoodweType goodweType, boolean readOnlyMode, int pvProduction, int soc, + int activePowerSetPoint) { + if (readOnlyMode) { + // Read-Only-Mode: fall-back to internal self-consumption optimization + return State.READ_ONLY; + + } else { + switch (goodweType) { + case GOODWE_10K_BT: + if (activePowerSetPoint > 0) { + // Set-Point is positive + return State.BT_DISCHARGE; + } else { + // Set-Point is negative or zero + return State.BT_CHARGE; + } + + case GOODWE_10K_ET: + if (soc > 99) { + // battery is full + if (activePowerSetPoint > 0) { + // Set-Point is positive -> take power either from pv or battery + if (activePowerSetPoint > pvProduction) { + return State.ET_FULL_POSITIVE_DISCHARGE; + + } else { + return State.ET_FULL_POSITIVE_CURTAIL; + } + } else { + return State.ET_FULL_NEGATIVE_CURTAIL; + } + + } else if (soc < 1) { + // battery is empty + // TODO define when battery is empty + if (activePowerSetPoint > 0) { + return State.ET_EMPTY_POSITIVE_PV; + + } else { + // Set-Point is negative or zero -> 'charge' from pv production and grid + return State.ET_EMPTY_NEGATIVE_CHARGE; + } + + } else { + // battery is neither empty nor full + if (activePowerSetPoint > 0) { + // Set-Point is positive + if (activePowerSetPoint > pvProduction) { + return State.ET_INBETWEEN_POSITIVE_DISCHARGE; + + } else { + return State.ET_INBETWEEN_POSITIVE_CHARGE; + + } + + } else { + // Set-Point is negative or zero + return State.ET_INBETWEEN_NEGATIVE_CHARGE; + } + } + + case UNDEFINED: + // This should not stay for long on bootup... + return State.UNDEFINED; + } + + } + + // should not come here + return State.UNDEFINED; + } +} \ No newline at end of file diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/BtChargeHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/BtChargeHandler.java new file mode 100644 index 00000000000..ce00c57bfd7 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/BtChargeHandler.java @@ -0,0 +1,17 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine.State; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class BtChargeHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + + context.setMode(PowerModeEms.CHARGE_BAT, context.activePowerSetPoint * -1); + + return State.BT_CHARGE; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/BtDischargeHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/BtDischargeHandler.java new file mode 100644 index 00000000000..e3698e6e6a9 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/BtDischargeHandler.java @@ -0,0 +1,17 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine.State; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class BtDischargeHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + + context.setMode(PowerModeEms.DISCHARGE_BAT, context.activePowerSetPoint); + + return State.BT_DISCHARGE; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/Context.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/Context.java new file mode 100644 index 00000000000..dea9add5d9e --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/Context.java @@ -0,0 +1,34 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.goodwe.ess.GoodWeEssImpl; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class Context { + + protected final GoodWeEssImpl component; + protected final int pvProduction; + protected final int activePowerSetPoint; + + private PowerModeEms nextPowerMode; + private int essPowerSet; + + public Context(GoodWeEssImpl component, int pvProduction, int activePowerSetPoint) { + super(); + this.component = component; + this.pvProduction = pvProduction; + this.activePowerSetPoint = activePowerSetPoint; + } + + protected void setMode(PowerModeEms nextPowerMode, int essPowerSet) { + this.nextPowerMode = nextPowerMode; + this.essPowerSet = essPowerSet; + } + + public int getEssPowerSet() { + return essPowerSet; + } + + public PowerModeEms getNextPowerMode() { + return nextPowerMode; + } +} \ No newline at end of file diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtEmptyNegativeChargeHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtEmptyNegativeChargeHandler.java new file mode 100644 index 00000000000..f9715dab111 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtEmptyNegativeChargeHandler.java @@ -0,0 +1,17 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine.State; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class EtEmptyNegativeChargeHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + + context.setMode(PowerModeEms.CHARGE_BAT, context.pvProduction - context.activePowerSetPoint); + + return State.ET_EMPTY_NEGATIVE_CHARGE; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtEmptyPositivePvHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtEmptyPositivePvHandler.java new file mode 100644 index 00000000000..1637f64757f --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtEmptyPositivePvHandler.java @@ -0,0 +1,17 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine.State; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class EtEmptyPositivePvHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + + context.setMode(PowerModeEms.CHARGE_BAT, context.pvProduction - context.activePowerSetPoint); + + return State.ET_EMPTY_POSITIVE_PV; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtFullNegativeCurtailHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtFullNegativeCurtailHandler.java new file mode 100644 index 00000000000..f7231e7cb24 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtFullNegativeCurtailHandler.java @@ -0,0 +1,17 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine.State; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class EtFullNegativeCurtailHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + + context.setMode(PowerModeEms.EXPORT_AC, 0); + + return State.ET_FULL_NEGATIVE_CURTAIL; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtFullPositiveCurtailHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtFullPositiveCurtailHandler.java new file mode 100644 index 00000000000..045709a0bee --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtFullPositiveCurtailHandler.java @@ -0,0 +1,17 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine.State; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class EtFullPositiveCurtailHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + + context.setMode(PowerModeEms.EXPORT_AC, context.activePowerSetPoint); + + return State.ET_FULL_POSITIVE_CURTAIL; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtFullPositiveDischargeHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtFullPositiveDischargeHandler.java new file mode 100644 index 00000000000..08c8eeb54d7 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtFullPositiveDischargeHandler.java @@ -0,0 +1,16 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine.State; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class EtFullPositiveDischargeHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + context.setMode(PowerModeEms.DISCHARGE_BAT, context.activePowerSetPoint - context.pvProduction); + + return State.ET_FULL_POSITIVE_DISCHARGE; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtInbetweenNegativeChargeHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtInbetweenNegativeChargeHandler.java new file mode 100644 index 00000000000..7902440f3a2 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtInbetweenNegativeChargeHandler.java @@ -0,0 +1,17 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine.State; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class EtInbetweenNegativeChargeHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + + context.setMode(PowerModeEms.CHARGE_BAT, context.pvProduction - context.activePowerSetPoint); + + return State.ET_INBETWEEN_NEGATIVE_CHARGE; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtInbetweenPositiveChargeHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtInbetweenPositiveChargeHandler.java new file mode 100644 index 00000000000..6fb043faf95 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtInbetweenPositiveChargeHandler.java @@ -0,0 +1,17 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine.State; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class EtInbetweenPositiveChargeHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + + context.setMode(PowerModeEms.CHARGE_BAT, context.pvProduction - context.activePowerSetPoint); + + return State.ET_INBETWEEN_POSITIVE_CHARGE; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtInbetweenPositiveDischargeHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtInbetweenPositiveDischargeHandler.java new file mode 100644 index 00000000000..144ec6e9a40 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/EtInbetweenPositiveDischargeHandler.java @@ -0,0 +1,16 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine.State; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class EtInbetweenPositiveDischargeHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + context.setMode(PowerModeEms.DISCHARGE_PV, context.activePowerSetPoint - context.pvProduction); + + return State.ET_INBETWEEN_POSITIVE_DISCHARGE; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/ReadOnlyHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/ReadOnlyHandler.java new file mode 100644 index 00000000000..0a0917b5cc4 --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/ReadOnlyHandler.java @@ -0,0 +1,16 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine.State; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class ReadOnlyHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + context.setMode(PowerModeEms.AUTO, 0); + + return State.READ_ONLY; + } + +} diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/UndefinedHandler.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/UndefinedHandler.java new file mode 100644 index 00000000000..d6d91d0c2ea --- /dev/null +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/applypower/UndefinedHandler.java @@ -0,0 +1,16 @@ +package io.openems.edge.goodwe.ess.applypower; + +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.goodwe.ess.applypower.ApplyPowerStateMachine.State; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class UndefinedHandler extends StateHandler { + + @Override + public State runAndGetNextState(Context context) { + context.setMode(PowerModeEms.AUTO, 0); + + return State.UNDEFINED; + } + +} diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/AppModeIndex.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/AppModeIndex.java similarity index 93% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/AppModeIndex.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/AppModeIndex.java index 8f8a87bcfce..eb04b2314c9 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/AppModeIndex.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/AppModeIndex.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess.enums; import io.openems.common.types.OptionsEnum; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/BatteryMode.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/BatteryMode.java similarity index 94% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/BatteryMode.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/BatteryMode.java index 4e546e5c8c5..8bf0b628c03 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/BatteryMode.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/BatteryMode.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess.enums; import io.openems.common.types.OptionsEnum; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/GridMode.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/GoodweType.java similarity index 58% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/GridMode.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/GoodweType.java index 5dbe73f552e..c3368bfcf3f 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/GridMode.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/GoodweType.java @@ -1,17 +1,16 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess.enums; import io.openems.common.types.OptionsEnum; -public enum GridMode implements OptionsEnum { +public enum GoodweType implements OptionsEnum { UNDEFINED(-1, "Undefined"), // - OFF_GRID(0, "Loss, inverter disconnects to Grid"), // - ON_GRID(1, "OK, inverter connects to Grid"), // - FAULT(2, "Fault,something is wrong"); // + GOODWE_10K_BT(1, "GoodWe GW10K-BT"), // + GOODWE_10K_ET(2, "GoodWe GW10K-ET"); private final int value; private final String option; - private GridMode(int value, String option) { + private GoodweType(int value, String option) { this.value = value; this.option = option; } diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/LoadMode.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/LoadMode.java similarity index 93% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/LoadMode.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/LoadMode.java index 17b32883bae..e60143a3181 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/LoadMode.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/LoadMode.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess.enums; import io.openems.common.types.OptionsEnum; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/MeterCommunicateStatus.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/MeterCommunicateStatus.java similarity index 92% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/MeterCommunicateStatus.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/MeterCommunicateStatus.java index b71e17079b7..79d97754608 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/MeterCommunicateStatus.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/MeterCommunicateStatus.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess.enums; import io.openems.common.types.OptionsEnum; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/MeterConnectCheckFlag.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/MeterConnectCheckFlag.java similarity index 93% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/MeterConnectCheckFlag.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/MeterConnectCheckFlag.java index ce4668f4c4a..52f33f53663 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/MeterConnectCheckFlag.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/MeterConnectCheckFlag.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess.enums; import io.openems.common.types.OptionsEnum; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/MeterConnectStatus.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/MeterConnectStatus.java similarity index 94% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/MeterConnectStatus.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/MeterConnectStatus.java index 1ce05dd4902..80480cae2bb 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/MeterConnectStatus.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/MeterConnectStatus.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess.enums; import io.openems.common.types.OptionsEnum; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/OperationMode.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/OperationMode.java similarity index 94% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/OperationMode.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/OperationMode.java index 18d4324c767..c7336161e9b 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/OperationMode.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/OperationMode.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess.enums; import io.openems.common.types.OptionsEnum; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/OutputTypeAC.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/OutputTypeAC.java similarity index 93% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/OutputTypeAC.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/OutputTypeAC.java index 5d18e356d9c..53e712651d9 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/OutputTypeAC.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/OutputTypeAC.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess.enums; import io.openems.common.types.OptionsEnum; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/PowerModeEms.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/PowerModeEms.java similarity index 96% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/PowerModeEms.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/PowerModeEms.java index 8836e8229d7..5e120c788a2 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/PowerModeEms.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/PowerModeEms.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess.enums; import io.openems.common.types.OptionsEnum; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/SafetyCountry.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/SafetyCountry.java similarity index 98% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/SafetyCountry.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/SafetyCountry.java index c34d240bc01..3c0216fad16 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/SafetyCountry.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/SafetyCountry.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess.enums; import io.openems.common.types.OptionsEnum; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/WorkMode.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/WorkMode.java similarity index 94% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/WorkMode.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/WorkMode.java index 1e33bf64948..14ee073b2fb 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/ess/WorkMode.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/ess/enums/WorkMode.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.ess; +package io.openems.edge.goodwe.ess.enums; import io.openems.common.types.OptionsEnum; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/gridmeter/Config.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/Config.java similarity index 96% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/gridmeter/Config.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/Config.java index 5d85153e1b0..104bc944786 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/gridmeter/Config.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/Config.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.gridmeter; +package io.openems.edge.goodwe.gridmeter; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/gridmeter/GoodWeEtGridMeter.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/GoodWeGridMeter.java similarity index 89% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/gridmeter/GoodWeEtGridMeter.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/GoodWeGridMeter.java index 9553ae03ec9..0527294eb42 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/gridmeter/GoodWeEtGridMeter.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/GoodWeGridMeter.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.gridmeter; +package io.openems.edge.goodwe.gridmeter; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -36,14 +36,14 @@ @Designate(ocd = Config.class, factory = true) @Component(// - name = "GoodWe.ET.Grid-Meter", // + name = "GoodWe.Grid-Meter", // immediate = true, // configurationPolicy = ConfigurationPolicy.REQUIRE, // property = { // EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE, // "type=GRID" // }) -public class GoodWeEtGridMeter extends AbstractOpenemsModbusComponent +public class GoodWeGridMeter extends AbstractOpenemsModbusComponent implements AsymmetricMeter, SymmetricMeter, OpenemsComponent, TimedataProvider, EventHandler { @Reference @@ -62,7 +62,7 @@ protected void setModbus(BridgeModbus modbus) { private final CalculateEnergyFromPower calculateConsumptionEnergy = new CalculateEnergyFromPower(this, SymmetricMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY); - public GoodWeEtGridMeter() { + public GoodWeGridMeter() { super(// OpenemsComponent.ChannelId.values(), // AsymmetricMeter.ChannelId.values(), // @@ -130,21 +130,6 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { ElementToChannelConverter.SCALE_FACTOR_MINUS_2), // m(SymmetricMeter.ChannelId.FREQUENCY, new UnsignedWordElement(36014), ElementToChannelConverter.SCALE_FACTOR_MINUS_2))); // - - // Energy values - /* - * NOTE: Energy values are calculated manually from ActivePower, because the - * data in registers 35200 and 35195 is not correct. GoodWe is informed, - * acknowledged the problem and is working on fixing it. - */ - // new FC3ReadRegistersTask(35200, Priority.LOW, // - // m(SymmetricMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY, new - // UnsignedDoublewordElement(35200), - // ElementToChannelConverter.SCALE_FACTOR_2)), // - // new FC3ReadRegistersTask(35195, Priority.LOW, // - // m(SymmetricMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY, new - // UnsignedDoublewordElement(35195), - // ElementToChannelConverter.SCALE_FACTOR_2))) } @Override diff --git a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/gridmeter/GridMeterChannelId.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/GridMeterChannelId.java similarity index 94% rename from io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/gridmeter/GridMeterChannelId.java rename to io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/GridMeterChannelId.java index aaba6597a49..3658978dd34 100644 --- a/io.openems.edge.goodwe.et/src/io/openems/edge/goodwe/et/gridmeter/GridMeterChannelId.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/gridmeter/GridMeterChannelId.java @@ -1,4 +1,4 @@ -package io.openems.edge.goodwe.et.gridmeter; +package io.openems.edge.goodwe.gridmeter; import io.openems.common.channel.AccessMode; import io.openems.common.channel.Unit; diff --git a/io.openems.edge.goodwe.et/test/.gitignore b/io.openems.edge.goodwe/test/.gitignore similarity index 100% rename from io.openems.edge.goodwe.et/test/.gitignore rename to io.openems.edge.goodwe/test/.gitignore diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/GoodWeChargerPv1Test.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/GoodWeChargerPv1Test.java new file mode 100644 index 00000000000..a78d6f9dd2b --- /dev/null +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/GoodWeChargerPv1Test.java @@ -0,0 +1,26 @@ +package io.openems.edge.goodwe.charger; + +import org.junit.Test; + +import io.openems.edge.bridge.modbus.test.DummyModbusBridge; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyConfigurationAdmin; + +public class GoodWeChargerPv1Test { + + private static final String MODBUS_ID = "modbus0"; + private static final String ESS_ID = "ess0"; + private static final String CHARGER_ID = "charger0"; + + @Test + public void test() throws Exception { + new ComponentTest(new GoodWeChargerPv1()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .activate(MyConfig.create() // + .setId(CHARGER_ID) // + .setEssId(ESS_ID) // + .setModbusId(MODBUS_ID) // + .build()); + } +} diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/GoodWeChargerPv2Test.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/GoodWeChargerPv2Test.java new file mode 100644 index 00000000000..1f889975748 --- /dev/null +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/GoodWeChargerPv2Test.java @@ -0,0 +1,26 @@ +package io.openems.edge.goodwe.charger; + +import org.junit.Test; + +import io.openems.edge.bridge.modbus.test.DummyModbusBridge; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyConfigurationAdmin; + +public class GoodWeChargerPv2Test { + + private static final String MODBUS_ID = "modbus0"; + private static final String ESS_ID = "ess0"; + private static final String CHARGER_ID = "charger0"; + + @Test + public void test() throws Exception { + new ComponentTest(new GoodWeChargerPv2()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .activate(MyConfig.create() // + .setId(CHARGER_ID) // + .setEssId(ESS_ID) // + .setModbusId(MODBUS_ID) // + .build()); + } +} diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/MyConfig.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/MyConfig.java new file mode 100644 index 00000000000..10576652bd6 --- /dev/null +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/charger/MyConfig.java @@ -0,0 +1,85 @@ +package io.openems.edge.goodwe.charger; + +import io.openems.common.utils.ConfigUtils; +import io.openems.edge.common.test.AbstractComponentConfig; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements ConfigPV1, ConfigPV2 { + + public static class Builder { + private String id = null; + public String essId; + public int unitId; + public String modbusId; + + private Builder() { + + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setEssId(String essId) { + this.essId = essId; + return this; + } + + public Builder setModbusId(String modbusId) { + this.modbusId = modbusId; + return this; + } + + public Builder setUnitId(int unitId) { + this.unitId = unitId; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(ConfigPV1.class, builder.id); + this.builder = builder; + } + + @Override + public int unit_id() { + return this.builder.unitId; + } + + @Override + public String modbus_id() { + return this.builder.modbusId; + } + + @Override + public String Modbus_target() { + return ConfigUtils.generateReferenceTargetFilter(this.id(), this.modbus_id()); + } + + @Override + public String ess_id() { + return this.builder.essId; + } + + @Override + public String Ess_target() { + return ConfigUtils.generateReferenceTargetFilter(this.id(), this.ess_id()); + } + +} \ No newline at end of file diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/ess/GoodWeEtBatteryInverterImplTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/ess/GoodWeEtBatteryInverterImplTest.java new file mode 100644 index 00000000000..bf9129cdbd2 --- /dev/null +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/ess/GoodWeEtBatteryInverterImplTest.java @@ -0,0 +1,124 @@ +package io.openems.edge.goodwe.ess; + +import org.junit.Test; + +import io.openems.common.types.ChannelAddress; +import io.openems.edge.bridge.modbus.test.DummyModbusBridge; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.ess.test.DummyPower; +import io.openems.edge.ess.test.ManagedSymmetricEssTest; +import io.openems.edge.goodwe.GoodWeConstants; +import io.openems.edge.goodwe.charger.GoodWeChargerPv1; +import io.openems.edge.goodwe.ess.enums.GoodweType; +import io.openems.edge.goodwe.ess.enums.PowerModeEms; + +public class GoodWeEtBatteryInverterImplTest { + + private static final String MODBUS_ID = "modbus0"; + + private static final String ESS_ID = "ess0"; + private static final ChannelAddress ESS_GOODWE_TYPE = new ChannelAddress(ESS_ID, "GoodweType"); + private static final ChannelAddress ESS_SET_ACTIVE_POWER_EQUALS = new ChannelAddress(ESS_ID, + "SetActivePowerEquals"); + private static final ChannelAddress ESS_SOC = new ChannelAddress(ESS_ID, "Soc"); + private static final ChannelAddress ESS_EMS_POWER_MODE = new ChannelAddress(ESS_ID, "EmsPowerMode"); + private static final ChannelAddress ESS_EMS_POWER_SET = new ChannelAddress(ESS_ID, "EmsPowerSet"); + + private static final String CHARGER_ID = "charger0"; + private static final ChannelAddress CHARGER_ACTUAL_POWER = new ChannelAddress(CHARGER_ID, "ActualPower"); + + @Test + public void testEt() throws Exception { + GoodWeChargerPv1 charger = new GoodWeChargerPv1(); + new ComponentTest(charger) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .activate(io.openems.edge.goodwe.charger.MyConfig.create() // + .setId(CHARGER_ID) // + .setEssId(ESS_ID) // + .setModbusId(MODBUS_ID) // + .setUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .build()); + + GoodWeEssImpl ess = new GoodWeEssImpl(); + ess.addCharger(charger); + new ManagedSymmetricEssTest(ess) // + .addReference("power", new DummyPower()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .addComponent(charger) // + .activate(MyConfig.create() // + .setId(ESS_ID) // + .setModbusId(MODBUS_ID) // + .setUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setCapacity(9_000) // + .setMaxBatteryPower(5_200) // + .setReadOnlyMode(false) // + .build()) // + .next(new TestCase("Scenario 1: (set-point is positive && set-point is lower than pv production)") // + .input(ESS_GOODWE_TYPE, GoodweType.GOODWE_10K_ET) // + .input(CHARGER_ACTUAL_POWER, 5_000) // + .input(ESS_SOC, 50) // + .input(ESS_SET_ACTIVE_POWER_EQUALS, 3_000) // + .output(ESS_EMS_POWER_MODE, PowerModeEms.CHARGE_BAT) // + .output(ESS_EMS_POWER_SET, 2000)) // + .next(new TestCase("Scenario 2: (set-point is positive && set-Point is bigger than pv production)") // + .input(CHARGER_ACTUAL_POWER, 5_000) // + .input(ESS_SOC, 50) // + .input(ESS_SET_ACTIVE_POWER_EQUALS, 8_000) // + .output(ESS_EMS_POWER_MODE, PowerModeEms.DISCHARGE_PV) // + .output(ESS_EMS_POWER_SET, 3000)) // + .next(new TestCase( + "Scenario 3: (set-point is negative && PV-Power is smaller than max charge power of the battery)") // + .input(CHARGER_ACTUAL_POWER, 3_000) // + .input(ESS_SOC, 50) // + .input(ESS_SET_ACTIVE_POWER_EQUALS, -2_000) // + .output(ESS_EMS_POWER_MODE, PowerModeEms.CHARGE_BAT) // + .output(ESS_EMS_POWER_SET, 5_000)) // + .next(new TestCase("Scenario 5: (set-point is positive && set-point is higher than pv production)") // + .input(CHARGER_ACTUAL_POWER, 3_000) // + .input(ESS_SOC, 100) // + .input(ESS_SET_ACTIVE_POWER_EQUALS, 8_000) // + .output(ESS_EMS_POWER_MODE, PowerModeEms.DISCHARGE_BAT) // + .output(ESS_EMS_POWER_SET, 5_000)) // + .next(new TestCase("Scenario 6: (set-point is positive && set-point is lower than pv production)") // + .input(CHARGER_ACTUAL_POWER, 5_000) // + .input(ESS_SOC, 100) // + .input(ESS_SET_ACTIVE_POWER_EQUALS, 3_000) // + .output(ESS_EMS_POWER_MODE, PowerModeEms.EXPORT_AC) // + .output(ESS_EMS_POWER_SET, 3_000)) // + ; + } + + @Test + public void testBt() throws Exception { + GoodWeEssImpl ess = new GoodWeEssImpl(); + new ManagedSymmetricEssTest(ess) // + .addReference("power", new DummyPower()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .activate(MyConfig.create() // + .setId(ESS_ID) // + .setModbusId(MODBUS_ID) // + .setUnitId(GoodWeConstants.DEFAULT_UNIT_ID) // + .setCapacity(9_000) // + .setMaxBatteryPower(5_200) // + .setReadOnlyMode(false) // + .build()) // + .next(new TestCase("Scenario 1: (set-point is positive)") // + .input(ESS_GOODWE_TYPE, GoodweType.GOODWE_10K_BT) // + .input(ESS_SOC, 50) // + .input(ESS_SET_ACTIVE_POWER_EQUALS, 3_000) // + .output(ESS_EMS_POWER_MODE, PowerModeEms.DISCHARGE_BAT) // + .output(ESS_EMS_POWER_SET, 3000)) // + .next(new TestCase("Scenario 2: (set-point is negative)") // + .input(ESS_SOC, 50) // + .input(ESS_SET_ACTIVE_POWER_EQUALS, -4000) // + .output(ESS_EMS_POWER_MODE, PowerModeEms.CHARGE_BAT) // + .output(ESS_EMS_POWER_SET, 4000)) // + ; + } + +} diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/ess/MyConfig.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/ess/MyConfig.java new file mode 100644 index 00000000000..e40242a5608 --- /dev/null +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/ess/MyConfig.java @@ -0,0 +1,103 @@ +package io.openems.edge.goodwe.ess; + +import io.openems.common.utils.ConfigUtils; +import io.openems.edge.common.test.AbstractComponentConfig; +import io.openems.edge.goodwe.ess.Config; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id = null; + public boolean readOnlyMode; + public int unitId; + public String modbusId; + public int capacity; + public int maxBatteryPower; + + private Builder() { + + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setCapacity(int capacity) { + this.capacity = capacity; + return this; + } + + public Builder setMaxBatteryPower(int maxBatteryPower) { + this.maxBatteryPower = maxBatteryPower; + return this; + } + + public Builder setModbusId(String modbusId) { + this.modbusId = modbusId; + return this; + } + + public Builder setReadOnlyMode(boolean readOnlyMode) { + this.readOnlyMode = readOnlyMode; + return this; + } + + public Builder setUnitId(int unitId) { + this.unitId = unitId; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public boolean readOnlyMode() { + return this.builder.readOnlyMode; + } + + @Override + public int unit_id() { + return this.builder.unitId; + } + + @Override + public String modbus_id() { + return this.builder.modbusId; + } + + @Override + public int capacity() { + return this.builder.capacity; + } + + @Override + public int maxBatteryPower() { + return this.builder.maxBatteryPower; + } + + @Override + public String Modbus_target() { + return ConfigUtils.generateReferenceTargetFilter(this.id(), this.modbus_id()); + } + +} \ No newline at end of file diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/gridmeter/GoodWeGridMeterTest.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/gridmeter/GoodWeGridMeterTest.java new file mode 100644 index 00000000000..b2d88caf901 --- /dev/null +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/gridmeter/GoodWeGridMeterTest.java @@ -0,0 +1,25 @@ +package io.openems.edge.goodwe.gridmeter; + +import org.junit.Test; + +import io.openems.edge.bridge.modbus.test.DummyModbusBridge; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyConfigurationAdmin; + +public class GoodWeGridMeterTest { + + private static final String MODBUS_ID = "modbus0"; + + private static final String METER_ID = "meter0"; + + @Test + public void test() throws Exception { + new ComponentTest(new GoodWeGridMeter()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .activate(MyConfig.create() // + .setId(METER_ID) // + .setModbusId(MODBUS_ID) // + .build()); + } +} diff --git a/io.openems.edge.goodwe/test/io/openems/edge/goodwe/gridmeter/MyConfig.java b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/gridmeter/MyConfig.java new file mode 100644 index 00000000000..1f6fb74baf4 --- /dev/null +++ b/io.openems.edge.goodwe/test/io/openems/edge/goodwe/gridmeter/MyConfig.java @@ -0,0 +1,70 @@ +package io.openems.edge.goodwe.gridmeter; + +import io.openems.common.utils.ConfigUtils; +import io.openems.edge.common.test.AbstractComponentConfig; +import io.openems.edge.goodwe.charger.ConfigPV1; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + public static class Builder { + private String id = null; + public int unitId; + public String modbusId; + + private Builder() { + + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setModbusId(String modbusId) { + this.modbusId = modbusId; + return this; + } + + public Builder setUnitId(int unitId) { + this.unitId = unitId; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(ConfigPV1.class, builder.id); + this.builder = builder; + } + + @Override + public int unit_id() { + return this.builder.unitId; + } + + @Override + public String modbus_id() { + return this.builder.modbusId; + } + + @Override + public String Modbus_target() { + return ConfigUtils.generateReferenceTargetFilter(this.id(), this.modbus_id()); + } + +} \ No newline at end of file