handler: Wire in Postgres store
This commit is contained in:
parent
72b0a690a6
commit
baa8ba7479
|
@ -31,7 +31,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
store := store.NewSQL(db)
|
store := store.NewSQL(db)
|
||||||
handler := handler.NewHandler(store)
|
handler := handler.New(store)
|
||||||
srv := http.Server{
|
srv := http.Server{
|
||||||
ReadTimeout: time.Second * 3,
|
ReadTimeout: time.Second * 3,
|
||||||
WriteTimeout: time.Second * 3,
|
WriteTimeout: time.Second * 3,
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.netflux.io/rob/solar-toolkit/inverter"
|
"git.netflux.io/rob/solar-toolkit/inverter"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const timestampMinimumYear = 2022
|
||||||
|
|
||||||
type Store interface {
|
type Store interface {
|
||||||
InsertETRuntimeData(*inverter.ETRuntimeData) error
|
InsertETRuntimeData(*inverter.ETRuntimeData) error
|
||||||
}
|
}
|
||||||
|
@ -14,8 +19,47 @@ type Handler struct {
|
||||||
store Store
|
store Store
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(store Store) *Handler { return &Handler{store: store} }
|
func New(store Store) *Handler { return &Handler{store: store} }
|
||||||
|
|
||||||
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.URL.Path != "/gateway/et_runtime_data" {
|
||||||
|
http.Error(w, "endpoint not found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("could not read body: %v", err)
|
||||||
|
http.Error(w, "unexpected error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var runtimeData inverter.ETRuntimeData
|
||||||
|
err = json.Unmarshal(body, &runtimeData)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("could not unmarshal body: %v", err)
|
||||||
|
http.Error(w, "unexpected error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if runtimeData.Timestamp.Year() < timestampMinimumYear {
|
||||||
|
log.Printf("invalid timestamp: %v", runtimeData.Timestamp)
|
||||||
|
http.Error(w, "invalid data", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = h.store.InsertETRuntimeData(&runtimeData); err != nil {
|
||||||
|
log.Printf("error storing data: %v", err)
|
||||||
|
http.Error(w, "unexpected error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("content-type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write([]byte("OK\n"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
package handler_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.netflux.io/rob/solar-toolkit/gateway/handler"
|
||||||
|
"git.netflux.io/rob/solar-toolkit/inverter"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
type store struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *store) InsertETRuntimeData(*inverter.ETRuntimeData) error {
|
||||||
|
return s.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
httpMethod string
|
||||||
|
path string
|
||||||
|
body string
|
||||||
|
storeErr error
|
||||||
|
wantStatusCode int
|
||||||
|
wantBody string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "method not allowed",
|
||||||
|
httpMethod: http.MethodGet,
|
||||||
|
path: "/gateway/et_runtime_data",
|
||||||
|
wantStatusCode: http.StatusMethodNotAllowed,
|
||||||
|
wantBody: "method not allowed\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "method not allowed",
|
||||||
|
httpMethod: http.MethodPost,
|
||||||
|
path: "/gateway/foo",
|
||||||
|
wantStatusCode: http.StatusNotFound,
|
||||||
|
wantBody: "endpoint not found\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid payload",
|
||||||
|
httpMethod: http.MethodPost,
|
||||||
|
path: "/gateway/et_runtime_data",
|
||||||
|
body: `{`,
|
||||||
|
wantStatusCode: http.StatusInternalServerError,
|
||||||
|
wantBody: "unexpected error\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid timestamp",
|
||||||
|
httpMethod: http.MethodPost,
|
||||||
|
path: "/gateway/et_runtime_data",
|
||||||
|
body: `{"timestamp": "1970-01-01T00:00:00Z"}`,
|
||||||
|
wantStatusCode: http.StatusBadRequest,
|
||||||
|
wantBody: "invalid data\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "store error",
|
||||||
|
httpMethod: http.MethodPost,
|
||||||
|
path: "/gateway/et_runtime_data",
|
||||||
|
body: `{"timestamp": "2022-01-01T00:00:00Z"}`,
|
||||||
|
storeErr: errors.New("boom"),
|
||||||
|
wantStatusCode: http.StatusInternalServerError,
|
||||||
|
wantBody: "unexpected error\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK",
|
||||||
|
httpMethod: http.MethodPost,
|
||||||
|
path: "/gateway/et_runtime_data",
|
||||||
|
body: `{"timestamp": "2022-01-01T00:00:00Z"}`,
|
||||||
|
wantStatusCode: http.StatusOK,
|
||||||
|
wantBody: "OK\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
mockStore := store{err: tc.storeErr}
|
||||||
|
handler := handler.New(&mockStore)
|
||||||
|
req := httptest.NewRequest(tc.httpMethod, tc.path, strings.NewReader(tc.body))
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(rec, req)
|
||||||
|
resp := rec.Result()
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
assert.Equal(t, tc.wantStatusCode, resp.StatusCode)
|
||||||
|
|
||||||
|
if tc.wantBody != "" {
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tc.wantBody, string(body))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
DROP TABLE et_runtime_data;
|
|
@ -0,0 +1,78 @@
|
||||||
|
CREATE TABLE et_runtime_data (
|
||||||
|
timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||||
|
pv1_voltage DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
pv1_current DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
pv1_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
pv2_voltage DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
pv2_current DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
pv2_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
pv_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
pv2_mode INT NOT NULL DEFAULT 0,
|
||||||
|
pv1_mode INT NOT NULL DEFAULT 0,
|
||||||
|
on_grid_l1_voltage DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
on_grid_l1_current DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
on_grid_l1_frequency DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
on_grid_l1_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
on_grid_l2_voltage DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
on_grid_l2_current DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
on_grid_l2_frequency DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
on_grid_l2_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
on_grid_l3_voltage DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
on_grid_l3_current DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
on_grid_l3_frequency DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
on_grid_l3_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
grid_mode INT NOT NULL DEFAULT 0,
|
||||||
|
total_inverter_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
active_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
reactive_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
apparent_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
backup_l1_voltage DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
backup_l1_current DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
backup_l1_frequency DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
load_mode_l1 INT NOT NULL DEFAULT 0,
|
||||||
|
backup_l1_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
backup_l2_voltage DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
backup_l2_current DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
backup_l2_frequency DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
load_mode_l2 INT NOT NULL DEFAULT 0,
|
||||||
|
backup_l2_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
backup_l3_voltage DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
backup_l3_current DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
backup_l3_frequency DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
load_mode_l3 INT NOT NULL DEFAULT 0,
|
||||||
|
backup_l3_power DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
load_l1 DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
load_l2 DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
load_l3 DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
backup_load DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
load DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
ups_load DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
temperature_air DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
temperature_module DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
temperature DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
bus_voltage DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
nbus_voltage DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
battery_voltage DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
battery_current DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
battery_mode INT NOT NULL DEFAULT 0,
|
||||||
|
warning_code INT NOT NULL DEFAULT 0,
|
||||||
|
safety_country_code INT NOT NULL DEFAULT 0,
|
||||||
|
work_mode INT NOT NULL DEFAULT 0,
|
||||||
|
operation_code INT NOT NULL DEFAULT 0,
|
||||||
|
energy_generation_total DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
energy_generation_today DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
energy_export_total DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
energy_export_total_hours DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
energy_export_today DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
energy_import_total DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
energy_import_today DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
energy_load_total DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
energy_load_day DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
battery_charge_total DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
battery_charge_today DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
battery_discharge_total DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
battery_discharge_today DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||||
|
house_consumption DOUBLE PRECISION NOT NULL DEFAULT 0.0
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX index_et_runtime_data_on_timestamp ON et_runtime_data (timestamp);
|
|
@ -1,6 +1,8 @@
|
||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"git.netflux.io/rob/solar-toolkit/inverter"
|
"git.netflux.io/rob/solar-toolkit/inverter"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
)
|
)
|
||||||
|
@ -13,6 +15,12 @@ func NewSQL(db *sqlx.DB) *PostgresStore {
|
||||||
return &PostgresStore{db: db}
|
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) 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);`
|
||||||
|
|
||||||
func (s *PostgresStore) InsertETRuntimeData(runtimeData *inverter.ETRuntimeData) error {
|
func (s *PostgresStore) InsertETRuntimeData(runtimeData *inverter.ETRuntimeData) error {
|
||||||
|
if _, err := s.db.NamedExec(insertSql, runtimeData); err != nil {
|
||||||
|
return fmt.Errorf("error inserting data: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,81 +58,81 @@ type DeviceInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ETRuntimeData struct {
|
type ETRuntimeData struct {
|
||||||
Timestamp time.Time `json:"timestamp"`
|
Timestamp time.Time `json:"timestamp" db:"timestamp"`
|
||||||
PV1Voltage Voltage `json:"pv1_voltage"`
|
PV1Voltage Voltage `json:"pv1_voltage" db:"pv1_voltage"`
|
||||||
PV1Current Current `json:"pv1_current"`
|
PV1Current Current `json:"pv1_current" db:"pv1_current"`
|
||||||
PV1Power Power `json:"pv1_power"`
|
PV1Power Power `json:"pv1_power" db:"pv1_power"`
|
||||||
PV2Voltage Voltage `json:"pv2_voltage"`
|
PV2Voltage Voltage `json:"pv2_voltage" db:"pv2_voltage"`
|
||||||
PV2Current Current `json:"pv2_current"`
|
PV2Current Current `json:"pv2_current" db:"pv2_current"`
|
||||||
PV2Power Power `json:"pv2_power"`
|
PV2Power Power `json:"pv2_power" db:"pv2_power"`
|
||||||
PVPower Power `json:"pv_power"`
|
PVPower Power `json:"pv_power" db:"pv_power"`
|
||||||
PV2Mode byte `json:"pv2_mode"`
|
PV2Mode byte `json:"pv2_mode" db:"pv2_mode"`
|
||||||
PV1Mode byte `json:"pv1_mode"`
|
PV1Mode byte `json:"pv1_mode" db:"pv1_mode"`
|
||||||
OnGridL1Voltage Voltage `json:"on_grid_l1_voltage"`
|
OnGridL1Voltage Voltage `json:"on_grid_l1_voltage" db:"on_grid_l1_voltage"`
|
||||||
OnGridL1Current Current `json:"on_grid_l1_current"`
|
OnGridL1Current Current `json:"on_grid_l1_current" db:"on_grid_l1_current"`
|
||||||
OnGridL1Frequency Frequency `json:"on_grid_l1_frequency"`
|
OnGridL1Frequency Frequency `json:"on_grid_l1_frequency" db:"on_grid_l1_frequency"`
|
||||||
OnGridL1Power Power `json:"on_grid_l1_power"`
|
OnGridL1Power Power `json:"on_grid_l1_power" db:"on_grid_l1_power"`
|
||||||
OnGridL2Voltage Voltage `json:"on_grid_l2_voltage"`
|
OnGridL2Voltage Voltage `json:"on_grid_l2_voltage" db:"on_grid_l2_voltage"`
|
||||||
OnGridL2Current Current `json:"on_grid_l2_current"`
|
OnGridL2Current Current `json:"on_grid_l2_current" db:"on_grid_l2_current"`
|
||||||
OnGridL2Frequency Frequency `json:"on_grid_l2_frequency"`
|
OnGridL2Frequency Frequency `json:"on_grid_l2_frequency" db:"on_grid_l2_frequency"`
|
||||||
OnGridL2Power Power `json:"on_grid_l2_power"`
|
OnGridL2Power Power `json:"on_grid_l2_power" db:"on_grid_l2_power"`
|
||||||
OnGridL3Voltage Voltage `json:"on_grid_l3_voltage"`
|
OnGridL3Voltage Voltage `json:"on_grid_l3_voltage" db:"on_grid_l3_voltage"`
|
||||||
OnGridL3Current Current `json:"on_grid_l3_current"`
|
OnGridL3Current Current `json:"on_grid_l3_current" db:"on_grid_l3_current"`
|
||||||
OnGridL3Frequency Frequency `json:"on_grid_l3_frequency"`
|
OnGridL3Frequency Frequency `json:"on_grid_l3_frequency" db:"on_grid_l3_frequency"`
|
||||||
OnGridL3Power Power `json:"on_grid_l3_power"`
|
OnGridL3Power Power `json:"on_grid_l3_power" db:"on_grid_l3_power"`
|
||||||
GridMode int `json:"grid_mode"`
|
GridMode int `json:"grid_mode" db:"grid_mode"`
|
||||||
TotalInverterPower Power `json:"total_inverter_power"`
|
TotalInverterPower Power `json:"total_inverter_power" db:"total_inverter_power"`
|
||||||
ActivePower Power `json:"active_power"`
|
ActivePower Power `json:"active_power" db:"active_power"`
|
||||||
ReactivePower int `json:"reactive_power"`
|
ReactivePower int `json:"reactive_power" db:"reactive_power"`
|
||||||
ApparentPower int `json:"apparent_power"`
|
ApparentPower int `json:"apparent_power" db:"apparent_power"`
|
||||||
BackupL1Voltage Voltage `json:"backup_l1_voltage"`
|
BackupL1Voltage Voltage `json:"backup_l1_voltage" db:"backup_l1_voltage"`
|
||||||
BackupL1Current Current `json:"backup_l1_current"`
|
BackupL1Current Current `json:"backup_l1_current" db:"backup_l1_current"`
|
||||||
BackupL1Frequency Frequency `json:"backup_l1_frequency"`
|
BackupL1Frequency Frequency `json:"backup_l1_frequency" db:"backup_l1_frequency"`
|
||||||
LoadModeL1 int `json:"load_mode_l1"`
|
LoadModeL1 int `json:"load_mode_l1" db:"load_mode_l1"`
|
||||||
BackupL1Power Power `json:"backup_l1_power"`
|
BackupL1Power Power `json:"backup_l1_power" db:"backup_l1_power"`
|
||||||
BackupL2Voltage Voltage `json:"backup_l2_voltage"`
|
BackupL2Voltage Voltage `json:"backup_l2_voltage" db:"backup_l2_voltage"`
|
||||||
BackupL2Current Current `json:"backup_l2_current"`
|
BackupL2Current Current `json:"backup_l2_current" db:"backup_l2_current"`
|
||||||
BackupL2Frequency Frequency `json:"backup_l2_frequency"`
|
BackupL2Frequency Frequency `json:"backup_l2_frequency" db:"backup_l2_frequency"`
|
||||||
LoadModeL2 int `json:"load_mode_l2"`
|
LoadModeL2 int `json:"load_mode_l2" db:"load_mode_l2"`
|
||||||
BackupL2Power Power `json:"backup_l2_power"`
|
BackupL2Power Power `json:"backup_l2_power" db:"backup_l2_power"`
|
||||||
BackupL3Voltage Voltage `json:"backup_l3_voltage"`
|
BackupL3Voltage Voltage `json:"backup_l3_voltage" db:"backup_l3_voltage"`
|
||||||
BackupL3Current Current `json:"backup_l3_current"`
|
BackupL3Current Current `json:"backup_l3_current" db:"backup_l3_current"`
|
||||||
BackupL3Frequency Frequency `json:"backup_l3_frequency"`
|
BackupL3Frequency Frequency `json:"backup_l3_frequency" db:"backup_l3_frequency"`
|
||||||
LoadModeL3 int `json:"load_mode_l3"`
|
LoadModeL3 int `json:"load_mode_l3" db:"load_mode_l3"`
|
||||||
BackupL3Power Power `json:"backup_l3_power"`
|
BackupL3Power Power `json:"backup_l3_power" db:"backup_l3_power"`
|
||||||
LoadL1 Power `json:"load_l1"`
|
LoadL1 Power `json:"load_l1" db:"load_l1"`
|
||||||
LoadL2 Power `json:"load_l2"`
|
LoadL2 Power `json:"load_l2" db:"load_l2"`
|
||||||
LoadL3 Power `json:"load_l3"`
|
LoadL3 Power `json:"load_l3" db:"load_l3"`
|
||||||
BackupLoad Power `json:"backup_load"`
|
BackupLoad Power `json:"backup_load" db:"backup_load"`
|
||||||
Load Power `json:"load"`
|
Load Power `json:"load" db:"load"`
|
||||||
UPSLoad int `json:"ups_load"`
|
UPSLoad int `json:"ups_load" db:"ups_load"`
|
||||||
TemperatureAir Temp `json:"temperature_air"`
|
TemperatureAir Temp `json:"temperature_air" db:"temperature_air"`
|
||||||
TemperatureModule Temp `json:"temperature_module"`
|
TemperatureModule Temp `json:"temperature_module" db:"temperature_module"`
|
||||||
Temperature Temp `json:"temperature"`
|
Temperature Temp `json:"temperature" db:"temperature"`
|
||||||
FunctionBit int `json:"-"`
|
FunctionBit int `json:"-" db:"-"`
|
||||||
BusVoltage Voltage `json:"bus_voltage"`
|
BusVoltage Voltage `json:"bus_voltage" db:"bus_voltage"`
|
||||||
NBusVoltage Voltage `json:"nbus_voltage"`
|
NBusVoltage Voltage `json:"nbus_voltage" db:"nbus_voltage"`
|
||||||
BatteryVoltage Voltage `json:"battery_voltage"`
|
BatteryVoltage Voltage `json:"battery_voltage" db:"battery_voltage"`
|
||||||
BatteryCurrent Current `json:"battery_current"`
|
BatteryCurrent Current `json:"battery_current" db:"battery_current"`
|
||||||
BatteryMode int `json:"battery_mode"`
|
BatteryMode int `json:"battery_mode" db:"battery_mode"`
|
||||||
WarningCode int `json:"warning_code"`
|
WarningCode int `json:"warning_code" db:"warning_code"`
|
||||||
SafetyCountryCode int `json:"safety_country_code"`
|
SafetyCountryCode int `json:"safety_country_code" db:"safety_country_code"`
|
||||||
WorkMode int `json:"work_mode"`
|
WorkMode int `json:"work_mode" db:"work_mode"`
|
||||||
OperationCode int `json:"operation_code"`
|
OperationCode int `json:"operation_code" db:"operation_code"`
|
||||||
ErrorCodes int `json:"-"`
|
ErrorCodes int `json:"-" db:"-"`
|
||||||
EnergyGenerationTotal Energy `json:"energy_generation_total"`
|
EnergyGenerationTotal Energy `json:"energy_generation_total" db:"energy_generation_total"`
|
||||||
EnergyGenerationToday Energy `json:"energy_generation_today"`
|
EnergyGenerationToday Energy `json:"energy_generation_today" db:"energy_generation_today"`
|
||||||
EnergyExportTotal Energy `json:"energy_export_total"`
|
EnergyExportTotal Energy `json:"energy_export_total" db:"energy_export_total"`
|
||||||
EnergyExportTotalHours int `json:"energy_export_total_hours"`
|
EnergyExportTotalHours int `json:"energy_export_total_hours" db:"energy_export_total_hours"`
|
||||||
EnergyExportToday Energy `json:"energy_export_today"`
|
EnergyExportToday Energy `json:"energy_export_today" db:"energy_export_today"`
|
||||||
EnergyImportTotal Energy `json:"energy_import_total"`
|
EnergyImportTotal Energy `json:"energy_import_total" db:"energy_import_total"`
|
||||||
EnergyImportToday Energy `json:"energy_import_today"`
|
EnergyImportToday Energy `json:"energy_import_today" db:"energy_import_today"`
|
||||||
EnergyLoadTotal Energy `json:"energy_load_total"`
|
EnergyLoadTotal Energy `json:"energy_load_total" db:"energy_load_total"`
|
||||||
EnergyLoadDay Energy `json:"energy_load_day"`
|
EnergyLoadDay Energy `json:"energy_load_day" db:"energy_load_day"`
|
||||||
BatteryChargeTotal int `json:"battery_charge_total"`
|
BatteryChargeTotal int `json:"battery_charge_total" db:"battery_charge_total"`
|
||||||
BatteryChargeToday int `json:"battery_charge_today"`
|
BatteryChargeToday int `json:"battery_charge_today" db:"battery_charge_today"`
|
||||||
BatteryDischargeTotal int `json:"battery_discharge_total"`
|
BatteryDischargeTotal int `json:"battery_discharge_total" db:"battery_discharge_total"`
|
||||||
BatteryDischargeToday int `json:"battery_discharge_today"`
|
BatteryDischargeToday int `json:"battery_discharge_today" db:"battery_discharge_today"`
|
||||||
DiagStatusCode int `json:"-"`
|
DiagStatusCode int `json:"-" db:"-"`
|
||||||
HouseConsumption Power `json:"house_consumption"`
|
HouseConsumption Power `json:"house_consumption" db:"house_consumption"`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue