diff --git a/cmd/daemon/main.go b/cmd/daemon/main.go index c46c1c3..2fb5680 100644 --- a/cmd/daemon/main.go +++ b/cmd/daemon/main.go @@ -60,9 +60,16 @@ func main() { continue } - reqBody, err := json.Marshal(runtimeData) + meterData, err := inv.MeterData(context.Background(), conn) if err != nil { - log.Printf("error encoding runtime data: %s", err) + log.Printf("error fetching meter data: %s", err) + continue + } + + frame := inverter.ETDataFrame{ETRuntimeData: runtimeData, ETMeterData: meterData} + reqBody, err := json.Marshal(frame) + if err != nil { + log.Printf("error encoding frame: %s", err) continue } diff --git a/gateway/handler/handler.go b/gateway/handler/handler.go index f882ab1..399d4b1 100644 --- a/gateway/handler/handler.go +++ b/gateway/handler/handler.go @@ -12,7 +12,7 @@ import ( const timestampMinimumYear = 2022 type Store interface { - InsertETRuntimeData(*inverter.ETRuntimeData) error + InsertDataFrame(*inverter.ETDataFrame) error } type Handler struct { @@ -48,7 +48,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var runtimeData inverter.ETRuntimeData err = json.Unmarshal(body, &runtimeData) if err != nil { - log.Printf("could not unmarshal body: %v", err) + log.Printf("could not unmarshal runtime data body: %v", err) http.Error(w, "unexpected error", http.StatusInternalServerError) return } @@ -59,7 +59,16 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - if err = h.store.InsertETRuntimeData(&runtimeData); err != nil { + var meterData inverter.ETMeterData + err = json.Unmarshal(body, &meterData) + if err != nil { + log.Printf("could not unmarshal meterData body: %v", err) + http.Error(w, "unexpected error", http.StatusInternalServerError) + return + } + + dataFrame := inverter.ETDataFrame{ETRuntimeData: &runtimeData, ETMeterData: &meterData} + if err = h.store.InsertDataFrame(&dataFrame); err != nil { log.Printf("error storing data: %v", err) http.Error(w, "unexpected error", http.StatusInternalServerError) return diff --git a/gateway/handler/handler_test.go b/gateway/handler/handler_test.go index 3efb821..75608f0 100644 --- a/gateway/handler/handler_test.go +++ b/gateway/handler/handler_test.go @@ -14,11 +14,11 @@ import ( "github.com/stretchr/testify/require" ) -type store struct { +type mockStore struct { err error } -func (s *store) InsertETRuntimeData(*inverter.ETRuntimeData) error { +func (s *mockStore) InsertDataFrame(*inverter.ETDataFrame) error { return s.err } @@ -90,7 +90,7 @@ func TestHandler(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - mockStore := store{err: tc.storeErr} + mockStore := mockStore{err: tc.storeErr} handler := handler.New(&mockStore) req := httptest.NewRequest(tc.httpMethod, tc.path, strings.NewReader(tc.body)) rec := httptest.NewRecorder() diff --git a/gateway/store/store.go b/gateway/store/store.go index 385ba55..f542997 100644 --- a/gateway/store/store.go +++ b/gateway/store/store.go @@ -15,10 +15,10 @@ func NewSQL(db *sqlx.DB) *PostgresStore { return &PostgresStore{db: db} } -const insertSql = `INSERT INTO et_runtime_data (timestamp, pv1_voltage, pv1_current, pv1_power, pv2_voltage, pv2_current, pv2_power, pv_power, pv2_mode, pv1_mode, on_grid_l1_voltage, on_grid_l1_current, on_grid_l1_frequency, on_grid_l1_power, on_grid_l2_voltage, on_grid_l2_current, on_grid_l2_frequency, on_grid_l2_power, on_grid_l3_voltage, on_grid_l3_current, on_grid_l3_frequency, on_grid_l3_power, grid_mode, total_inverter_power, active_power, reactive_power, apparent_power, backup_l1_voltage, backup_l1_current, backup_l1_frequency, load_mode_l1, backup_l1_power, backup_l2_voltage, backup_l2_current, backup_l2_frequency, load_mode_l2, backup_l2_power, backup_l3_voltage, backup_l3_current, backup_l3_frequency, load_mode_l3, backup_l3_power, load_l1, load_l2, load_l3, backup_load, load, ups_load, temperature_air, temperature_module, temperature, bus_voltage, nbus_voltage, battery_voltage, battery_current, battery_mode, warning_code, safety_country_code, work_mode, operation_code, energy_generation_total, energy_generation_today, energy_export_total, energy_export_total_hours, energy_export_today, energy_import_total, energy_import_today, energy_load_total, energy_load_day, battery_charge_total, battery_charge_today, battery_discharge_total, battery_discharge_today, house_consumption, created_at) VALUES (:timestamp, :pv1_voltage, :pv1_current, :pv1_power, :pv2_voltage, :pv2_current, :pv2_power, :pv_power, :pv2_mode, :pv1_mode, :on_grid_l1_voltage, :on_grid_l1_current, :on_grid_l1_frequency, :on_grid_l1_power, :on_grid_l2_voltage, :on_grid_l2_current, :on_grid_l2_frequency, :on_grid_l2_power, :on_grid_l3_voltage, :on_grid_l3_current, :on_grid_l3_frequency, :on_grid_l3_power, :grid_mode, :total_inverter_power, :active_power, :reactive_power, :apparent_power, :backup_l1_voltage, :backup_l1_current, :backup_l1_frequency, :load_mode_l1, :backup_l1_power, :backup_l2_voltage, :backup_l2_current, :backup_l2_frequency, :load_mode_l2, :backup_l2_power, :backup_l3_voltage, :backup_l3_current, :backup_l3_frequency, :load_mode_l3, :backup_l3_power, :load_l1, :load_l2, :load_l3, :backup_load, :load, :ups_load, :temperature_air, :temperature_module, :temperature, :bus_voltage, :nbus_voltage, :battery_voltage, :battery_current, :battery_mode, :warning_code, :safety_country_code, :work_mode, :operation_code, :energy_generation_total, :energy_generation_today, :energy_export_total, :energy_export_total_hours, :energy_export_today, :energy_import_total, :energy_import_today, :energy_load_total, :energy_load_day, :battery_charge_total, :battery_charge_today, :battery_discharge_total, :battery_discharge_today, :house_consumption, NOW());` +const insertSql = `INSERT INTO et_runtime_data (timestamp, pv1_voltage, pv1_current, pv1_power, pv2_voltage, pv2_current, pv2_power, pv_power, pv2_mode, pv1_mode, on_grid_l1_voltage, on_grid_l1_current, on_grid_l1_frequency, on_grid_l1_power, on_grid_l2_voltage, on_grid_l2_current, on_grid_l2_frequency, on_grid_l2_power, on_grid_l3_voltage, on_grid_l3_current, on_grid_l3_frequency, on_grid_l3_power, grid_mode, total_inverter_power, active_power, reactive_power, apparent_power, backup_l1_voltage, backup_l1_current, backup_l1_frequency, load_mode_l1, backup_l1_power, backup_l2_voltage, backup_l2_current, backup_l2_frequency, load_mode_l2, backup_l2_power, backup_l3_voltage, backup_l3_current, backup_l3_frequency, load_mode_l3, backup_l3_power, load_l1, load_l2, load_l3, backup_load, load, ups_load, temperature_air, temperature_module, temperature, bus_voltage, nbus_voltage, battery_voltage, battery_current, battery_mode, warning_code, safety_country_code, work_mode, operation_code, energy_generation_total, energy_generation_today, energy_export_total, energy_export_total_hours, energy_export_today, energy_import_total, energy_import_today, energy_load_total, energy_load_day, battery_charge_total, battery_charge_today, battery_discharge_total, battery_discharge_today, house_consumption, meter_test_status, meter_comm_status, active_power_l1, active_power_l2, active_power_l3, active_power_total, reactive_power_total, meter_power_factor1, meter_power_factor2, meter_power_factor3, meter_power_factor, meter_frequency, meter_energy_export_total, meter_energy_import_total, meter_active_power1, meter_active_power2, meter_active_power3, meter_active_power_total, meter_reactive_power1, meter_reactive_power2, meter_reactive_power3, meter_reactive_power_total, meter_apparent_power1, meter_apparent_power2, meter_apparent_power3, meter_apparent_power_total, meter_software_version, created_at) VALUES (:timestamp, :pv1_voltage, :pv1_current, :pv1_power, :pv2_voltage, :pv2_current, :pv2_power, :pv_power, :pv2_mode, :pv1_mode, :on_grid_l1_voltage, :on_grid_l1_current, :on_grid_l1_frequency, :on_grid_l1_power, :on_grid_l2_voltage, :on_grid_l2_current, :on_grid_l2_frequency, :on_grid_l2_power, :on_grid_l3_voltage, :on_grid_l3_current, :on_grid_l3_frequency, :on_grid_l3_power, :grid_mode, :total_inverter_power, :active_power, :reactive_power, :apparent_power, :backup_l1_voltage, :backup_l1_current, :backup_l1_frequency, :load_mode_l1, :backup_l1_power, :backup_l2_voltage, :backup_l2_current, :backup_l2_frequency, :load_mode_l2, :backup_l2_power, :backup_l3_voltage, :backup_l3_current, :backup_l3_frequency, :load_mode_l3, :backup_l3_power, :load_l1, :load_l2, :load_l3, :backup_load, :load, :ups_load, :temperature_air, :temperature_module, :temperature, :bus_voltage, :nbus_voltage, :battery_voltage, :battery_current, :battery_mode, :warning_code, :safety_country_code, :work_mode, :operation_code, :energy_generation_total, :energy_generation_today, :energy_export_total, :energy_export_total_hours, :energy_export_today, :energy_import_total, :energy_import_today, :energy_load_total, :energy_load_day, :battery_charge_total, :battery_charge_today, :battery_discharge_total, :battery_discharge_today, :house_consumption, :meter_test_status, :meter_comm_status, :active_power_l1, :active_power_l2, :active_power_l3, :active_power_total, :reactive_power_total, :meter_power_factor1, :meter_power_factor2, :meter_power_factor3, :meter_power_factor, :meter_frequency, :meter_energy_export_total, :meter_energy_import_total, :meter_active_power1, :meter_active_power2, :meter_active_power3, :meter_active_power_total, :meter_reactive_power1, :meter_reactive_power2, :meter_reactive_power3, :meter_reactive_power_total, :meter_apparent_power1, :meter_apparent_power2, :meter_apparent_power3, :meter_apparent_power_total, :meter_software_version, NOW());` -func (s *PostgresStore) InsertETRuntimeData(runtimeData *inverter.ETRuntimeData) error { - if _, err := s.db.NamedExec(insertSql, runtimeData); err != nil { +func (s *PostgresStore) InsertDataFrame(frame *inverter.ETDataFrame) error { + if _, err := s.db.NamedExec(insertSql, frame); err != nil { return fmt.Errorf("error inserting data: %s", err) } diff --git a/inverter/types.go b/inverter/types.go index ef79490..125522f 100644 --- a/inverter/types.go +++ b/inverter/types.go @@ -138,35 +138,40 @@ type ETRuntimeData struct { } type ETMeterData struct { - ComMode int `json:"com_mode"` - RSSI int `json:"rssi"` - ManufactureCode int `json:"manufacture_code"` - MeterTestStatus int `json:"meter_test_status"` - MeterCommStatus int `json:"meter_comm_status"` - ActivePowerL1 Power `json:"active_power_l1"` - ActivePowerL2 Power `json:"active_power_l2"` - ActivePowerL3 Power `json:"active_power_l3"` - ActivePowerTotal Power `json:"active_power_total"` - ReactivePowerTotal int `json:"reactive_power_total"` - MeterPowerFactor1 float64 `json:"meter_power_factor1"` - MeterPowerFactor2 float64 `json:"meter_power_factor2"` - MeterPowerFactor3 float64 `json:"meter_power_factor3"` - MeterPowerFactor float64 `json:"meter_power_factor"` - MeterFrequency Frequency `json:"meter_frequency"` - EnergyExportTotal Power `json:"energy_export_total"` - EnergyImportTotal Power `json:"energy_import_total"` - MeterActivePower1 Power `json:"meter_active_power1"` - MeterActivePower2 Power `json:"meter_active_power2"` - MeterActivePower3 Power `json:"meter_active_power3"` - MeterActivePowerTotal Power `json:"meter_active_power_total"` - MeterReactivePower1 int `json:"meter_reactive_power1"` - MeterReactivePower2 int `json:"meter_reactive_power2"` - MeterReactivePower3 int `json:"meter_reactive_power3"` - MeterReactivePowerTotal int `json:"meter_reactive_power_total"` - MeterApparentPower1 int `json:"meter_apparent_power1"` - MeterApparentPower2 int `json:"meter_apparent_power2"` - MeterApparentPower3 int `json:"meter_apparent_power3"` - MeterApparentPowerTotal int `json:"meter_apparent_power_total"` - MeterType int `json:"meter_type"` - MeterSoftwareVersion int `json:"meter_software_version"` + ComMode int `json:"com_mode" db:"-"` + RSSI int `json:"-" db:"-"` + ManufactureCode int `json:"manufacture_code" db:"-"` + MeterTestStatus int `json:"meter_test_status" db:"meter_test_status"` + MeterCommStatus int `json:"meter_comm_status" db:"meter_comm_status"` + ActivePowerL1 Power `json:"active_power_l1" db:"active_power_l1"` + ActivePowerL2 Power `json:"active_power_l2" db:"active_power_l2"` + ActivePowerL3 Power `json:"active_power_l3" db:"active_power_l3"` + ActivePowerTotal Power `json:"active_power_total" db:"active_power_total"` + ReactivePowerTotal int `json:"reactive_power_total" db:"reactive_power_total"` + MeterPowerFactor1 float64 `json:"meter_power_factor1" db:"meter_power_factor1"` + MeterPowerFactor2 float64 `json:"meter_power_factor2" db:"meter_power_factor2"` + MeterPowerFactor3 float64 `json:"meter_power_factor3" db:"meter_power_factor3"` + MeterPowerFactor float64 `json:"meter_power_factor" db:"meter_power_factor"` + MeterFrequency Frequency `json:"meter_frequency" db:"meter_frequency"` + EnergyExportTotal Power `json:"meter_energy_export_total" db:"meter_energy_export_total"` + EnergyImportTotal Power `json:"meter_energy_import_total" db:"meter_energy_import_total"` + MeterActivePower1 Power `json:"meter_active_power1" db:"meter_active_power1"` + MeterActivePower2 Power `json:"meter_active_power2" db:"meter_active_power2"` + MeterActivePower3 Power `json:"meter_active_power3" db:"meter_active_power3"` + MeterActivePowerTotal Power `json:"meter_active_power_total" db:"meter_active_power_total"` + MeterReactivePower1 int `json:"meter_reactive_power1" db:"meter_reactive_power1"` + MeterReactivePower2 int `json:"meter_reactive_power2" db:"meter_reactive_power2"` + MeterReactivePower3 int `json:"meter_reactive_power3" db:"meter_reactive_power3"` + MeterReactivePowerTotal int `json:"meter_reactive_power_total" db:"meter_reactive_power_total"` + MeterApparentPower1 int `json:"meter_apparent_power1" db:"meter_apparent_power1"` + MeterApparentPower2 int `json:"meter_apparent_power2" db:"meter_apparent_power2"` + MeterApparentPower3 int `json:"meter_apparent_power3" db:"meter_apparent_power3"` + MeterApparentPowerTotal int `json:"meter_apparent_power_total" db:"meter_apparent_power_total"` + MeterType int `json:"meter_type" db:"-"` + MeterSoftwareVersion int `json:"meter_software_version" db:"meter_software_version"` +} + +type ETDataFrame struct { + *ETRuntimeData + *ETMeterData }