From 9e3f92eeb43d345d59ddb6d673ad65afcfe2411a Mon Sep 17 00:00:00 2001 From: Gijsbert Date: Sun, 17 Mar 2024 17:11:42 +0100 Subject: [PATCH] Redo registers --- metrics/power_meter.go | 8 - modbus/consts.go | 136 +++++++------ modbus/modbus.go | 449 +++++------------------------------------ 3 files changed, 124 insertions(+), 469 deletions(-) diff --git a/metrics/power_meter.go b/metrics/power_meter.go index afadc35..fb68db5 100644 --- a/metrics/power_meter.go +++ b/metrics/power_meter.go @@ -101,12 +101,4 @@ var powerMeterMetrics = []Metric{ "phase", }, }, - { - Namespace: "power_meter", - Name: "model_result", - Help: "The power meter model result", - Fields: []string{ - "inverter", - }, - }, } diff --git a/modbus/consts.go b/modbus/consts.go index 9e44fbf..de4f0ee 100644 --- a/modbus/consts.go +++ b/modbus/consts.go @@ -1,67 +1,87 @@ package modbus -// uint16 -> ReadRegister -// int32 -> ReadUint32 +type RegisterType uint8 + +type Register struct { + Namespace string + Name string + Fields map[string]string + Address uint16 + Unit string + Gain float64 + Quantity uint16 + Type RegisterType + Writeable bool +} const ( - // Sun2000 Inverter - MODBUS_ADDRESS_INVERTER_PV1_VOLTAGE = 32016 // int16 readonly - MODBUS_ADDRESS_INVERTER_PV1_CURRENT = 32017 // int16 readonly - MODBUS_ADDRESS_INVERTER_PV2_VOLTAGE = 32018 // int16 readonly - MODBUS_ADDRESS_INVERTER_PV2_CURRENT = 32019 // int16 readonly + RegisterTypeUint16 RegisterType = iota + RegisterTypeUint32 + RegisterTypeInt16 + RegisterTypeInt32 +) - MODBUS_ADDRESS_INVERTER_STATE_1 = 32000 // uint16 readonly - MODBUS_ADDRESS_INVERTER_DEVICE_STATUS = 32089 // uint16 readonly - MODBUS_ADDRESS_INVERTER_INPUT_POWER = 32064 // int32 readonly +const ( + MODBUS_STATE_BATTERY_1_FORCIBLE_CHARGE_DISCHARGE_STOP uint16 = iota + MODBUS_STATE_BATTERY_1_FORCIBLE_CHARGE_DISCHARGE_CHARGE + MODBUS_STATE_BATTERY_1_FORCIBLE_CHARGE_DISCHARGE_DISCHARGE +) - MODBUS_ADDRESS_INVERTER_PHASE_A_VOLTAGE = 32069 // uint16 readonly - MODBUS_ADDRESS_INVERTER_PHASE_B_VOLTAGE = 32070 // uint16 readonly - MODBUS_ADDRESS_INVERTER_PHASE_C_VOLTAGE = 32071 // uint16 readonly - MODBUS_ADDRESS_INVERTER_PHASE_A_CURRENT = 32072 // int32 readonly - MODBUS_ADDRESS_INVERTER_PHASE_B_CURRENT = 32074 // int32 readonly - MODBUS_ADDRESS_INVERTER_PHASE_C_CURRENT = 32076 // int32 readonly - MODBUS_ADDRESS_INVERTER_ACTIVE_POWER = 32080 // int32 readonly - MODBUS_ADDRESS_INVERTER_REACTIVE_POWER = 32082 // int32 readonly - MODBUS_ADDRESS_INVERTER_POWER_FACTOR = 32084 // int16 readonly - MODBUS_ADDRESS_INVERTER_FREQUENCY = 32085 // uint16 readonly - MODBUS_ADDRESS_INVERTER_INVERTER_EFFICIENCY = 32086 // uint16 readonly - MODBUS_ADDRESS_INVERTER_CABINET_TEMPERATURE = 32087 // int16 readonly - MODBUS_ADDRESS_INVERTER_INSULATION_RESISTANCE = 32088 // uint16 readonly +var ( + sun2000Registers = map[string]Register{ + "pv_voltage_string_1": Register{Namespace: "sun2000", Name: "pv_voltage", Fields: map[string]string{"string": "1"}, Address: 32016, Unit: "V", Gain: 10, Quantity: 1, Type: RegisterTypeInt16, Writeable: false}, + "pv_current_string_1": Register{Namespace: "sun2000", Name: "pv_current", Fields: map[string]string{"string": "1"}, Address: 32017, Unit: "A", Gain: 100, Quantity: 1, Type: RegisterTypeInt16, Writeable: false}, + "pv_voltage_string_2": Register{Namespace: "sun2000", Name: "pv_voltage", Fields: map[string]string{"string": "2"}, Address: 32018, Unit: "V", Gain: 10, Quantity: 1, Type: RegisterTypeInt16, Writeable: false}, + "pv_current_string_2": Register{Namespace: "sun2000", Name: "pv_current", Fields: map[string]string{"string": "2"}, Address: 32019, Unit: "A", Gain: 100, Quantity: 1, Type: RegisterTypeInt16, Writeable: false}, + "device_status": Register{Namespace: "sun2000", Name: "device_status", Fields: map[string]string{}, Address: 32089, Unit: "", Gain: 1, Quantity: 1, Type: RegisterTypeUint16, Writeable: false}, + "input_power": Register{Namespace: "sun2000", Name: "input_power", Fields: map[string]string{}, Address: 32064, Unit: "kW", Gain: 1000, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "phase_voltage_phase_a": Register{Namespace: "sun2000", Name: "phase_voltage", Fields: map[string]string{"phase": "A"}, Address: 32069, Unit: "V", Gain: 10, Quantity: 1, Type: RegisterTypeUint16, Writeable: false}, + "phase_voltage_phase_b": Register{Namespace: "sun2000", Name: "phase_voltage", Fields: map[string]string{"phase": "B"}, Address: 32070, Unit: "V", Gain: 10, Quantity: 1, Type: RegisterTypeUint16, Writeable: false}, + "phase_voltage_phase_c": Register{Namespace: "sun2000", Name: "phase_voltage", Fields: map[string]string{"phase": "C"}, Address: 32071, Unit: "V", Gain: 10, Quantity: 1, Type: RegisterTypeUint16, Writeable: false}, + "phase_current_phase_a": Register{Namespace: "sun2000", Name: "phase_current", Fields: map[string]string{"phase": "A"}, Address: 32072, Unit: "A", Gain: 1000, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "phase_current_phase_b": Register{Namespace: "sun2000", Name: "phase_current", Fields: map[string]string{"phase": "B"}, Address: 32074, Unit: "A", Gain: 1000, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "phase_current_phase_c": Register{Namespace: "sun2000", Name: "phase_current", Fields: map[string]string{"phase": "C"}, Address: 32076, Unit: "A", Gain: 1000, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "active_power": Register{Namespace: "sun2000", Name: "active_power", Fields: map[string]string{}, Address: 32080, Unit: "kW", Gain: 1000, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "reactive_power": Register{Namespace: "sun2000", Name: "reactive_power", Fields: map[string]string{}, Address: 32082, Unit: "kVar", Gain: 1000, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "power_factor": Register{Namespace: "sun2000", Name: "power_factor", Fields: map[string]string{}, Address: 32084, Unit: "", Gain: 1000, Quantity: 1, Type: RegisterTypeInt16, Writeable: false}, + "grid_frequency": Register{Namespace: "sun2000", Name: "grid_frequency", Fields: map[string]string{}, Address: 32085, Unit: "Hz", Gain: 100, Quantity: 100, Type: RegisterTypeUint16, Writeable: false}, + "inverter_efficiency": Register{Namespace: "sun2000", Name: "inverter_efficiency", Fields: map[string]string{}, Address: 32086, Unit: "%", Gain: 100, Quantity: 1, Type: RegisterTypeUint16, Writeable: false}, + "cabinet_temperature": Register{Namespace: "sun2000", Name: "cabinet_temperature", Fields: map[string]string{}, Address: 32087, Unit: "°C", Gain: 10, Quantity: 1, Type: RegisterTypeInt16, Writeable: false}, + "isulation_resistance": Register{Namespace: "sun2000", Name: "isulation_resistance", Fields: map[string]string{}, Address: 32088, Unit: "MΩ", Gain: 1000, Quantity: 1, Type: RegisterTypeUint16, Writeable: false}, + } - // Luna Battery - MODBUS_ADDRESS_BATTERY_1_RUNNING_STATUS = 37000 // uint16 readonly - 0: offline, 1: standby, 2: running, 3: fault, 4: sleep - MODBUS_ADDRESS_BATTERY_1_CHARGING_STATUS = 37001 // int32 readonly - >0: charging, <0: discharging - MODBUS_ADDRESS_BATTERY_1_BUS_VOLTAGE = 37003 // uint16 readonly - MODBUS_ADDRESS_BATTERY_1_CAPACITY = 37004 // uint16 readonly - MODBUS_ADDRESS_BATTERY_1_TOTAL_CHARGE = 37066 // int32 readonly - MODBUS_ADDRESS_BATTERY_1_TOTAL_DISCHARGE = 37068 // int32 readonly - MODBUS_ADDRESS_BATTERY_1_FORCIBLE_CHARGE_DISCHARGE = 47100 // uint16 readwrite - 0: stop, 1: charge, 2: discharge - MODBUS_STATE_BATTERY_1_FORCIBLE_CHARGE_DISCHARGE_STOP = 0 - MODBUS_STATE_BATTERY_1_FORCIBLE_CHARGE_DISCHARGE_CHARGE = 1 - MODBUS_STATE_BATTERY_1_FORCIBLE_CHARGE_DISCHARGE_DISCHARGE = 2 - MODBUS_ADDRESS_BATTERY_1_FORCIBLE_CHARGE_POWER = 47247 // int32 readwrite - MODBUS_ADDRESS_BATTERY_1_FORCIBLE_DISCHARGE_POWER = 47249 // int32 readwrite + luna2000Registers = map[string]Register{ + "running_status_battery_1": Register{Namespace: "luna2000", Name: "running_status", Fields: map[string]string{"battery": "1"}, Address: 37000, Unit: "", Gain: 1, Quantity: 1, Type: RegisterTypeUint16, Writeable: false}, + "charging_status_battery_1": Register{Namespace: "luna2000", Name: "charging_status", Fields: map[string]string{"battery": "1"}, Address: 37001, Unit: "W", Gain: 1, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "bus_voltage_battery_1": Register{Namespace: "luna2000", Name: "bus_voltage", Fields: map[string]string{"battery": "1"}, Address: 37003, Unit: "V", Gain: 10, Quantity: 1, Type: RegisterTypeUint16, Writeable: false}, + "battery_capacity_battery_1": Register{Namespace: "luna2000", Name: "battery_capacity", Fields: map[string]string{"battery": "1"}, Address: 37004, Unit: "%", Gain: 10, Quantity: 1, Type: RegisterTypeUint16, Writeable: false}, + "total_charge_battery_1": Register{Namespace: "luna2000", Name: "total_charge", Fields: map[string]string{"battery": "1"}, Address: 37066, Unit: "kWh", Gain: 100, Quantity: 2, Type: RegisterTypeUint32, Writeable: false}, + "total_discharge_battery_1": Register{Namespace: "luna2000", Name: "total_discharge", Fields: map[string]string{"battery": "1"}, Address: 37068, Unit: "kWh", Gain: 100, Quantity: 2, Type: RegisterTypeUint32, Writeable: false}, + "forcible_charge_discharge_battery_1": Register{Namespace: "luna2000", Name: "forcible_charge_discharge", Fields: map[string]string{"battery": "1"}, Address: 47100, Unit: "", Gain: 1, Quantity: 1, Type: RegisterTypeUint16, Writeable: true}, + "forcible_charge_power_battery_1": Register{Namespace: "luna2000", Name: "forcible_charge_power", Fields: map[string]string{"battery": "1"}, Address: 47247, Unit: "kW", Gain: 1000, Quantity: 2, Type: RegisterTypeUint32, Writeable: true}, + "forcible_discharge_power_battery_1": Register{Namespace: "luna2000", Name: "forcible_discharge_power", Fields: map[string]string{"battery": "1"}, Address: 47249, Unit: "kW", Gain: 1000, Quantity: 2, Type: RegisterTypeUint32, Writeable: true}, + } - // Power meter - MODBUS_ADDRESS_POWER_METER_STATUS = 37100 // uint16 readonly - 0: offline, 1: normal - MODBUS_ADDRESS_POWER_METER_PHASE_A_VOLTAGE = 37101 // int32 readonly - MODBUS_ADDRESS_POWER_METER_PHASE_B_VOLTAGE = 37103 // int32 readonly - MODBUS_ADDRESS_POWER_METER_PHASE_C_VOLTAGE = 37105 // int32 readonly - MODBUS_ADDRESS_POWER_METER_PHASE_A_CURRENT = 37107 // int32 readonly - MODBUS_ADDRESS_POWER_METER_PHASE_B_CURRENT = 37109 // int32 readonly - MODBUS_ADDRESS_POWER_METER_PHASE_C_CURRENT = 37111 // int32 readonly - MODBUS_ADDRESS_POWER_METER_ACTIVE_POWER = 37113 // int32 readonly - MODBUS_ADDRESS_POWER_METER_REACTIVE_POWER = 37115 // int32 readonly - MODBUS_ADDRESS_POWER_METER_POWER_FACTOR = 37117 // int16 readonly - MODBUS_ADDRESS_POWER_METER_FREQUENCY = 37118 // uint16 readonly - MODBUS_ADDRESS_POWER_METER_POSITIVE_ACTIVE_ELECTRICITY = 37119 // int32 readonly - MODBUS_ADDRESS_POWER_METER_REVERSE_ACTIVE_POWER = 37121 // int32 readonly - MODBUS_ADDRESS_POWER_METER_ACCUMULATED_REACTIVE_POWER = 37123 // int32 readonly - MODBUS_ADDRESS_POWER_METER_AB_LINE_VOLTAGE = 37126 // int32 readonly - MODBUS_ADDRESS_POWER_METER_BC_LINE_VOLTAGE = 37128 // int32 readonly - MODBUS_ADDRESS_POWER_METER_CA_LINE_VOLTAGE = 37130 // int32 readonly - MODBUS_ADDRESS_POWER_METER_PHASE_A_ACTIVE_POWER = 37132 // int32 readonly - MODBUS_ADDRESS_POWER_METER_PHASE_B_ACTIVE_POWER = 37134 // int32 readonly - MODBUS_ADDRESS_POWER_METER_PHASE_C_ACTIVE_POWER = 37136 // int32 readonly - MODBUS_ADDRESS_POWER_METER_MODEL_RESULT = 37138 // uint16 readonly + powerMeterRegisters = map[string]Register{ + "status": Register{Namespace: "power_meter", Name: "status", Fields: map[string]string{}, Address: 37100, Unit: "", Gain: 1, Quantity: 1, Type: RegisterTypeUint16, Writeable: false}, + "phase_voltage_phase_a": Register{Namespace: "power_meter", Name: "phase_voltage", Fields: map[string]string{"phase": "A"}, Address: 37101, Unit: "V", Gain: 10, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "phase_voltage_phase_b": Register{Namespace: "power_meter", Name: "phase_voltage", Fields: map[string]string{"phase": "B"}, Address: 37103, Unit: "V", Gain: 10, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "phase_voltage_phase_c": Register{Namespace: "power_meter", Name: "phase_voltage", Fields: map[string]string{"phase": "C"}, Address: 37105, Unit: "V", Gain: 10, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "phase_current_phase_a": Register{Namespace: "power_meter", Name: "phase_current", Fields: map[string]string{"phase": "A"}, Address: 37107, Unit: "A", Gain: 100, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "phase_current_phase_b": Register{Namespace: "power_meter", Name: "phase_current", Fields: map[string]string{"phase": "B"}, Address: 37109, Unit: "A", Gain: 100, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "phase_current_phase_c": Register{Namespace: "power_meter", Name: "phase_current", Fields: map[string]string{"phase": "C"}, Address: 37111, Unit: "A", Gain: 100, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "active_power": Register{Namespace: "power_meter", Name: "active_power", Fields: map[string]string{}, Address: 37113, Unit: "W", Gain: 1, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "reactive_power": Register{Namespace: "power_meter", Name: "reactive_power", Fields: map[string]string{}, Address: 37115, Unit: "Var", Gain: 1, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "power_factor": Register{Namespace: "power_meter", Name: "power_factor", Fields: map[string]string{}, Address: 37117, Unit: "", Gain: 1000, Quantity: 1, Type: RegisterTypeInt16, Writeable: false}, + "frequency": Register{Namespace: "power_meter", Name: "frequency", Fields: map[string]string{}, Address: 37118, Unit: "Hz", Gain: 100, Quantity: 1, Type: RegisterTypeInt16, Writeable: false}, + "positive_active_electricity": Register{Namespace: "power_meter", Name: "positive_active_electricity", Fields: map[string]string{}, Address: 37119, Unit: "kWh", Gain: 100, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "reverse_active_power": Register{Namespace: "power_meter", Name: "reverse_active_power", Fields: map[string]string{}, Address: 37121, Unit: "kWh", Gain: 100, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "accumulated_reactive_power": Register{Namespace: "power_meter", Name: "accumulated_reactive_power", Fields: map[string]string{}, Address: 37123, Unit: "kVarh", Gain: 100, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "line_voltage_line_ab": Register{Namespace: "power_meter", Name: "line_voltage", Fields: map[string]string{"line": "AB"}, Address: 37126, Unit: "V", Gain: 10, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "line_voltage_line_bc": Register{Namespace: "power_meter", Name: "line_voltage", Fields: map[string]string{"line": "BC"}, Address: 37128, Unit: "V", Gain: 10, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "line_voltage_line_ca": Register{Namespace: "power_meter", Name: "line_voltage", Fields: map[string]string{"line": "CA"}, Address: 37130, Unit: "V", Gain: 10, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "phase_active_power_phase_a": Register{Namespace: "power_meter", Name: "phase_active_power", Fields: map[string]string{"phase": "A"}, Address: 37132, Unit: "W", Gain: 1, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "phase_active_power_phase_b": Register{Namespace: "power_meter", Name: "phase_active_power", Fields: map[string]string{"phase": "B"}, Address: 37134, Unit: "W", Gain: 1, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + "phase_active_power_phase_c": Register{Namespace: "power_meter", Name: "phase_active_power", Fields: map[string]string{"phase": "C"}, Address: 37136, Unit: "W", Gain: 1, Quantity: 2, Type: RegisterTypeInt32, Writeable: false}, + } ) diff --git a/modbus/modbus.go b/modbus/modbus.go index a98599b..0af2dda 100644 --- a/modbus/modbus.go +++ b/modbus/modbus.go @@ -1,11 +1,10 @@ package modbus import ( - "context" "fmt" "time" + "context" - "gijs.eu/vonkje/utils" "gijs.eu/vonkje/metrics" "github.com/sirupsen/logrus" @@ -78,7 +77,7 @@ func New( return nil, err } - err := client.SetEncoding(modbus.BIG_ENDIAN, modbus.HIGH_WORD_FIRST) + err = client.SetEncoding(modbus.BIG_ENDIAN, modbus.HIGH_WORD_FIRST) if err != nil { return nil, err } @@ -150,18 +149,18 @@ func (m *Modbus) ChangeBatteryForceCharge(inverter string, battery string, state switch state { case MODBUS_STATE_BATTERY_1_FORCIBLE_CHARGE_DISCHARGE_CHARGE: - err = connection.client.WriteUint32(MODBUS_ADDRESS_BATTERY_1_FORCIBLE_CHARGE_POWER, uint32(watts)) + err = connection.client.WriteUint32(luna2000Registers["forcible_charge_power_battery_1"].Address, uint32(watts)) if err != nil { return err } case MODBUS_STATE_BATTERY_1_FORCIBLE_CHARGE_DISCHARGE_DISCHARGE: - err = connection.client.WriteUint32(MODBUS_ADDRESS_BATTERY_1_FORCIBLE_DISCHARGE_POWER, uint32(watts)) + err = connection.client.WriteUint32(luna2000Registers["forcible_discharge_power_battery_1"].Address, uint32(watts)) if err != nil { return err } } - err = connection.client.WriteRegister(MODBUS_ADDRESS_BATTERY_1_FORCIBLE_CHARGE_DISCHARGE, state) + err = connection.client.WriteRegister(luna2000Registers["forcible_charge_discharge_battery_1"].Address, state) if err != nil { return err } @@ -196,20 +195,20 @@ func (m *Modbus) getConnection(inverter string) (*Connection, error) { func (m *Modbus) updateMetrics() { for _, connection := range m.connections { for _, inverter := range connection.config.Inverters { - err := m.updateSun2000Metrics(connection, inverter) + err := m.updateMetricsRegisters(connection, inverter, sun2000Registers) if err != nil { m.errChannel <- err } if inverter.Luna2000 { - err = m.updateLuna2000Metrics(connection, inverter) + err := m.updateMetricsRegisters(connection, inverter, luna2000Registers) if err != nil { m.errChannel <- err } } if inverter.PowerMeter { - err = m.updatePowerMeterMetrics(connection, inverter) + err := m.updateMetricsRegisters(connection, inverter, powerMeterRegisters) if err != nil { m.errChannel <- err } @@ -218,415 +217,59 @@ func (m *Modbus) updateMetrics() { } } -func (m *Modbus) updateLuna2000Metrics(connection *Connection, inverter Inverter) error { - m.logger.Infof("Updating luna2000 metrics for %s", inverter.Name) - +func (m *Modbus) updateMetricsRegisters(connection *Connection, inverter Inverter, registers map[string]Register) error { err := connection.client.SetUnitId(inverter.UnitId) if err != nil { return err } - runningStatus, err := connection.client.ReadRegister(MODBUS_ADDRESS_BATTERY_1_RUNNING_STATUS, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("luna2000", "running_status", map[string]string{"inverter": inverter.Name, "battery": "1"}, float64(runningStatus)) - - chargingStatus, err := connection.client.ReadUint32(MODBUS_ADDRESS_BATTERY_1_CHARGING_STATUS, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - if chargingStatus > 999999 { - metrics.SetMetricValue("luna2000", "charging_status", map[string]string{"inverter": inverter.Name, "battery": "1"}, 0) - } else { - metrics.SetMetricValue("luna2000", "charging_status", map[string]string{"inverter": inverter.Name, "battery": "1"}, float64(chargingStatus)) - } - - busVoltage, err := connection.client.ReadRegister(MODBUS_ADDRESS_BATTERY_1_BUS_VOLTAGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("luna2000", "bus_voltage", map[string]string{"inverter": inverter.Name, "battery": "1"}, float64(busVoltage) / 10) - - batteryCapacity, err := connection.client.ReadRegister(MODBUS_ADDRESS_BATTERY_1_CAPACITY, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("luna2000", "battery_capacity", map[string]string{"inverter": inverter.Name, "battery": "1"}, float64(batteryCapacity) / 10) - - totalCharge, err := connection.client.ReadUint32(MODBUS_ADDRESS_BATTERY_1_TOTAL_CHARGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("luna2000", "total_charge", map[string]string{"inverter": inverter.Name, "battery": "1"}, float64(totalCharge) / 100) - - totalDischarge, err := connection.client.ReadUint32(MODBUS_ADDRESS_BATTERY_1_TOTAL_DISCHARGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("luna2000", "total_discharge", map[string]string{"inverter": inverter.Name, "battery": "1"}, float64(totalDischarge) / 100) - - return nil -} - -func (m *Modbus) updatePowerMeterMetrics(connection *Connection, inverter Inverter) error { - m.logger.Infof("Updating power meter metrics for %s", inverter.Name) - - err := connection.client.SetUnitId(inverter.UnitId) - if err != nil { - return err - } - - status, err := connection.client.ReadRegister(MODBUS_ADDRESS_POWER_METER_STATUS, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "status", map[string]string{"inverter": inverter.Name}, float64(status)) - - powerMeterPhaseAVoltage, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_PHASE_A_VOLTAGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "phase_voltage", map[string]string{"inverter": inverter.Name, "phase": "A"}, float64(powerMeterPhaseAVoltage) / 10) - - var powerMeterPhaseACurrentResult uint32 - powerMeterPhaseACurrent, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_PHASE_A_CURRENT, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - if powerMeterPhaseACurrent > 999999 { - powerMeterPhaseACurrentBytes, err := connection.client.ReadBytes(MODBUS_ADDRESS_POWER_METER_PHASE_A_CURRENT, 4, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - - powerMeterPhaseACurrentResult = utils.ConvertTooLargeNumber(powerMeterPhaseACurrentBytes) - } else { - powerMeterPhaseACurrentResult = powerMeterPhaseACurrent - } - metrics.SetMetricValue("power_meter", "phase_current", map[string]string{"inverter": inverter.Name, "phase": "A"}, float64(powerMeterPhaseACurrentResult) / 100) - - powerMeterPhaseBVoltage, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_PHASE_B_VOLTAGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "phase_voltage", map[string]string{"inverter": inverter.Name, "phase": "B"}, float64(powerMeterPhaseBVoltage) / 10) - - var powerMeterPhaseBCurrentResult uint32 - powerMeterPhaseBCurrent, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_PHASE_B_CURRENT, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - if powerMeterPhaseBCurrent > 999999 { - powerMeterPhaseBCurrentBytes, err := connection.client.ReadBytes(MODBUS_ADDRESS_POWER_METER_PHASE_B_CURRENT, 4, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - - powerMeterPhaseBCurrentResult = utils.ConvertTooLargeNumber(powerMeterPhaseBCurrentBytes) - } else { - powerMeterPhaseBCurrentResult = powerMeterPhaseBCurrent - } - metrics.SetMetricValue("power_meter", "phase_current", map[string]string{"inverter": inverter.Name, "phase": "B"}, float64(powerMeterPhaseBCurrentResult) / 100) - - powerMeterPhaseCVoltage, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_PHASE_C_VOLTAGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "phase_voltage", map[string]string{"inverter": inverter.Name, "phase": "C"}, float64(powerMeterPhaseCVoltage) / 10) - - var powerMeterPhaseCCurrentResult uint32 - powerMeterPhaseCCurrent, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_PHASE_C_CURRENT, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - if powerMeterPhaseCCurrent > 999999 { - powerMeterPhaseCCurrentBytes, err := connection.client.ReadBytes(MODBUS_ADDRESS_POWER_METER_PHASE_C_CURRENT, 4, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - - powerMeterPhaseCCurrentResult = utils.ConvertTooLargeNumber(powerMeterPhaseCCurrentBytes) - } else { - powerMeterPhaseCCurrentResult = powerMeterPhaseCCurrent - } - metrics.SetMetricValue("power_meter", "phase_current", map[string]string{"inverter": inverter.Name, "phase": "C"}, float64(powerMeterPhaseCCurrentResult) / 100) - - var powerMeterActivePowerResult uint32 - powerMeterActivePower, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_ACTIVE_POWER, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - if powerMeterActivePower > 999999 { - powerMeterActivePowerBytes, err := connection.client.ReadBytes(MODBUS_ADDRESS_POWER_METER_ACTIVE_POWER, 4, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - - powerMeterActivePowerResult = utils.ConvertTooLargeNumber(powerMeterActivePowerBytes) - } else { - powerMeterActivePowerResult = powerMeterActivePower - } - metrics.SetMetricValue("power_meter", "active_power", map[string]string{"inverter": inverter.Name}, float64(powerMeterActivePowerResult) / 100) + for _, register := range registers { + var result int - powerMeterReactivePower, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_REACTIVE_POWER, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "reactive_power", map[string]string{"inverter": inverter.Name}, float64(powerMeterReactivePower) / 100) - - powerMeterPowerFactor, err := connection.client.ReadRegister(MODBUS_ADDRESS_POWER_METER_POWER_FACTOR, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "power_factor", map[string]string{"inverter": inverter.Name}, float64(powerMeterPowerFactor) / 1000) - - powerMeterFrequency, err := connection.client.ReadRegister(MODBUS_ADDRESS_POWER_METER_FREQUENCY, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "frequency", map[string]string{"inverter": inverter.Name}, float64(powerMeterFrequency) / 100) - - positiveActiveElectricity, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_POSITIVE_ACTIVE_ELECTRICITY, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "positive_active_electricity", map[string]string{"inverter": inverter.Name}, float64(positiveActiveElectricity) / 100) - - reverseActivePower, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_REVERSE_ACTIVE_POWER, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "reverse_active_power", map[string]string{"inverter": inverter.Name}, float64(reverseActivePower) / 100) - - accumulatedReactivePower, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_ACCUMULATED_REACTIVE_POWER, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "accumulated_reactive_power", map[string]string{"inverter": inverter.Name}, float64(accumulatedReactivePower) / 100) - - abLineVoltage, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_AB_LINE_VOLTAGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "line_voltage", map[string]string{"inverter": inverter.Name, "line": "AB"}, float64(abLineVoltage) / 10) - - bcLineVoltage, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_BC_LINE_VOLTAGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "line_voltage", map[string]string{"inverter": inverter.Name, "line": "BC"}, float64(bcLineVoltage) / 10) + switch register.Type { + case RegisterTypeUint16: + var reg uint16 + reg, err = connection.client.ReadRegister(register.Address, modbus.HOLDING_REGISTER) + if err != nil { + return err + } - caLineVoltage, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_CA_LINE_VOLTAGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "line_voltage", map[string]string{"inverter": inverter.Name, "line": "CA"}, float64(caLineVoltage) / 10) + result = int(reg) + case RegisterTypeUint32: + var reg uint32 + reg, err = connection.client.ReadUint32(register.Address, modbus.HOLDING_REGISTER) + if err != nil { + return err + } - var phaseAActivePowerResult uint32 - powerMeterPhaseAActivePower, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_PHASE_A_ACTIVE_POWER, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - if powerMeterPhaseAActivePower > 999999 { - powerMeterPhaseAActivePowerBytes, err := connection.client.ReadBytes(MODBUS_ADDRESS_POWER_METER_PHASE_A_ACTIVE_POWER, 4, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - - phaseAActivePowerResult = utils.ConvertTooLargeNumber(powerMeterPhaseAActivePowerBytes) - } else { - phaseAActivePowerResult = powerMeterPhaseAActivePower - } - metrics.SetMetricValue("power_meter", "phase_active_power", map[string]string{"inverter": inverter.Name, "phase": "A"}, float64(phaseAActivePowerResult) / 100) + result = int(reg) + case RegisterTypeInt16: + var res int16 + reg, err := connection.client.ReadRegister(register.Address, modbus.HOLDING_REGISTER) + if err != nil { + return err + } - var phaseBActivePowerResult uint32 - powerMeterPhaseBActivePower, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_PHASE_B_ACTIVE_POWER, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - if powerMeterPhaseBActivePower > 999999 { - powerMeterPhaseBActivePowerBytes, err := connection.client.ReadBytes(MODBUS_ADDRESS_POWER_METER_PHASE_B_ACTIVE_POWER, 4, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - - phaseBActivePowerResult = utils.ConvertTooLargeNumber(powerMeterPhaseBActivePowerBytes) - } else { - phaseBActivePowerResult = powerMeterPhaseBActivePower - } - metrics.SetMetricValue("power_meter", "phase_active_power", map[string]string{"inverter": inverter.Name, "phase": "B"}, float64(phaseBActivePowerResult) / 100) + res = int16(reg) + result = int(res) + case RegisterTypeInt32: + var res int32 + reg, err := connection.client.ReadUint32(register.Address, modbus.HOLDING_REGISTER) + if err != nil { + return err + } - var phaseCActivePowerResult uint32 - powerMeterPhaseCActivePower, err := connection.client.ReadUint32(MODBUS_ADDRESS_POWER_METER_PHASE_C_ACTIVE_POWER, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - if powerMeterPhaseCActivePower > 999999 { - powerMeterPhaseCActivePowerBytes, err := connection.client.ReadBytes(MODBUS_ADDRESS_POWER_METER_PHASE_C_ACTIVE_POWER, 4, modbus.HOLDING_REGISTER) - if err != nil { - return err + res = int32(reg) + result = int(res) } - - phaseCActivePowerResult = utils.ConvertTooLargeNumber(powerMeterPhaseCActivePowerBytes) - } else { - phaseCActivePowerResult = powerMeterPhaseCActivePower - } - metrics.SetMetricValue("power_meter", "phase_active_power", map[string]string{"inverter": inverter.Name, "phase": "C"}, float64(phaseCActivePowerResult) / 100) - powerMeterModelResult, err := connection.client.ReadRegister(MODBUS_ADDRESS_POWER_METER_MODEL_RESULT, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("power_meter", "model_result", map[string]string{"inverter": inverter.Name}, float64(powerMeterModelResult)) - - return nil -} - -func (m *Modbus) updateSun2000Metrics(connection *Connection, inverter Inverter) error { - m.logger.Infof("Updating sun2000 metrics for %s", inverter.Name) - - err := connection.client.SetUnitId(inverter.UnitId) - if err != nil { - return err - } - - // string 1 - pv1Voltage, err := connection.client.ReadRegister(MODBUS_ADDRESS_INVERTER_PV1_VOLTAGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "pv_voltage", map[string]string{"inverter": inverter.Name, "string": "1"}, float64(pv1Voltage) / 10) - - pv1Current, err := connection.client.ReadRegister(MODBUS_ADDRESS_INVERTER_PV1_CURRENT, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "pv_current", map[string]string{"inverter": inverter.Name, "string": "1"}, float64(pv1Current) / 100) - - // string 2 - pv2Voltage, err := connection.client.ReadRegister(MODBUS_ADDRESS_INVERTER_PV2_VOLTAGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "pv_voltage", map[string]string{"inverter": inverter.Name, "string": "2"}, float64(pv2Voltage) / 10) - - pv2Current, err := connection.client.ReadRegister(MODBUS_ADDRESS_INVERTER_PV2_CURRENT, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "pv_current", map[string]string{"inverter": inverter.Name, "string": "2"}, float64(pv2Current) / 100) - - - // phase A - phaseAVoltage, err := connection.client.ReadRegister(MODBUS_ADDRESS_INVERTER_PHASE_A_VOLTAGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "phase_voltage", map[string]string{"inverter": inverter.Name, "phase": "A"}, float64(phaseAVoltage) / 10) - - phaseACurrent, err := connection.client.ReadUint32(MODBUS_ADDRESS_INVERTER_PHASE_A_CURRENT, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "phase_current", map[string]string{"inverter": inverter.Name, "phase": "A"}, float64(phaseACurrent) / 1000) - - // phase B - phaseBVoltage, err := connection.client.ReadRegister(MODBUS_ADDRESS_INVERTER_PHASE_B_VOLTAGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "phase_voltage", map[string]string{"inverter": inverter.Name, "phase": "B"}, float64(phaseBVoltage) / 10) - - phaseBCurrent, err := connection.client.ReadUint32(MODBUS_ADDRESS_INVERTER_PHASE_B_CURRENT, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "phase_current", map[string]string{"inverter": inverter.Name, "phase": "B"}, float64(phaseBCurrent) / 1000) - - // phase C - phaseCVoltage, err := connection.client.ReadRegister(MODBUS_ADDRESS_INVERTER_PHASE_C_VOLTAGE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "phase_voltage", map[string]string{"inverter": inverter.Name, "phase": "C"}, float64(phaseCVoltage) / 10) - - phaseCCurrent, err := connection.client.ReadUint32(MODBUS_ADDRESS_INVERTER_PHASE_C_CURRENT, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "phase_current", map[string]string{"inverter": inverter.Name, "phase": "C"}, float64(phaseCCurrent) / 1000) - - inputPower, err := connection.client.ReadUint32(MODBUS_ADDRESS_INVERTER_INPUT_POWER, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "input_power", map[string]string{"inverter": inverter.Name}, float64(inputPower) / 1000) - - stateOne, err := connection.client.ReadUint32(MODBUS_ADDRESS_INVERTER_STATE_1, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "state", map[string]string{"inverter": inverter.Name, "state": "1"}, float64(stateOne)) - - inverterDeviceStatus, err := connection.client.ReadUint32(MODBUS_ADDRESS_INVERTER_DEVICE_STATUS, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "device_status", map[string]string{"inverter": inverter.Name}, float64(inverterDeviceStatus)) - - var activePowerResult uint32 - activePower, err := connection.client.ReadUint32(MODBUS_ADDRESS_INVERTER_ACTIVE_POWER, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - if activePower > 999999 { - activePowerBytes, err := connection.client.ReadBytes(MODBUS_ADDRESS_INVERTER_ACTIVE_POWER, 4, modbus.HOLDING_REGISTER) - if err != nil { - return err + fields := map[string]string{"inverter": inverter.Name} + for k, v := range register.Fields { + fields[k] = v } - - activePowerResult = utils.ConvertTooLargeNumber(activePowerBytes) - } else { - activePowerResult = activePower - } - metrics.SetMetricValue("sun2000", "active_power", map[string]string{"inverter": inverter.Name}, float64(activePowerResult) / 1000) - - reactivePower, err := connection.client.ReadUint32(MODBUS_ADDRESS_INVERTER_REACTIVE_POWER, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "reactive_power", map[string]string{"inverter": inverter.Name}, float64(reactivePower) / 1000) - - powerFactor, err := connection.client.ReadRegister(MODBUS_ADDRESS_INVERTER_POWER_FACTOR, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "power_factor", map[string]string{"inverter": inverter.Name}, float64(powerFactor) / 1000) - gridFrequency, err := connection.client.ReadRegister(MODBUS_ADDRESS_INVERTER_FREQUENCY, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "frequency", map[string]string{"inverter": inverter.Name}, float64(gridFrequency) / 100) - - inverterEfficiency, err := connection.client.ReadRegister(MODBUS_ADDRESS_INVERTER_FREQUENCY, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "efficiency", map[string]string{"inverter": inverter.Name}, float64(inverterEfficiency) / 100) - - cabinetTemperature, err := connection.client.ReadRegister(MODBUS_ADDRESS_INVERTER_CABINET_TEMPERATURE, modbus.HOLDING_REGISTER) - if err != nil { - return err - } - metrics.SetMetricValue("sun2000", "cabinet_temperature", map[string]string{"inverter": inverter.Name}, float64(cabinetTemperature) / 10) - - isulationResistance, err := connection.client.ReadRegister(MODBUS_ADDRESS_INVERTER_INSULATION_RESISTANCE, modbus.HOLDING_REGISTER) - if err != nil { - return err + metrics.SetMetricValue(register.Namespace, register.Name, fields, float64(result) / register.Gain) } - metrics.SetMetricValue("sun2000", "isulation_resistance", map[string]string{"inverter": inverter.Name}, float64(isulationResistance) / 10) return nil }