package meter import ( "fmt" "net/http" "net/http/cookiejar" "strings" "time" "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/util" "github.com/evcc-io/evcc/util/request" ) func init() { registry.Add("tq-em420", NewTqEm420FromConfig) } type TqEm420Data struct { SmartMeter struct { ConfigurationID string `json:"configuration_id"` Status string `json:"status"` Timestamp struct { Seconds float64 `json:"seconds"` Nanos float64 `json:"nanos"` } `json:"timestamp"` Values struct { ActiveEnergyP float64 `json:"active_energy_+"` ActiveEnergyL1P float64 `json:"active_energy_+_L1"` ActiveEnergyL2P float64 `json:"active_energy_+_L2"` ActiveEnergyL3P float64 `json:"active_energy_+_L3"` ActiveEnergyM float64 `json:"active_energy_-"` ActiveEnergyL1M float64 `json:"active_energy_-_L1"` ActiveEnergyL2M float64 `json:"active_energy_-_L2"` ActiveEnergyL3M float64 `json:"active_energy_-_L3"` ActivePowerP float64 `json:"active_power_+"` ActivePowerL1P float64 `json:"active_power_+_L1"` ActivePowerL2P float64 `json:"active_power_+_L2"` ActivePowerL3P float64 `json:"active_power_+_L3"` ActivePowerM float64 `json:"active_power_-"` ActivePowerL1M float64 `json:"active_power_-_L1"` ActivePowerL2M float64 `json:"active_power_-_L2"` ActivePowerL3M float64 `json:"active_power_-_L3"` ApparentEnergyP float64 `json:"apparent_energy_+"` ApparentEnergyL1P float64 `json:"apparent_energy_+_L1"` ApparentEnergyL2P float64 `json:"apparent_energy_+_L2"` ApparentEnergyL3P float64 `json:"apparent_energy_+_L3"` ApparentEnergyM float64 `json:"apparent_energy_-"` ApparentEnergyL1M float64 `json:"apparent_energy_-_L1"` ApparentEnergyL2M float64 `json:"apparent_energy_-_L2"` ApparentEnergyL3M float64 `json:"apparent_energy_-_L3"` ApparentPowerP float64 `json:"apparent_power_+"` ApparentPowerL1P float64 `json:"apparent_power_+_L1"` ApparentPowerL2P float64 `json:"apparent_power_+_L2"` ApparentPowerL3P float64 `json:"apparent_power_+_L3"` ApparentPowerM float64 `json:"apparent_power_-"` ApparentPowerL1M float64 `json:"apparent_power_-_L1"` ApparentPowerL2M float64 `json:"apparent_power_-_L2"` ApparentPowerL3M float64 `json:"apparent_power_-_L3"` CurrentL1 float64 `json:"current_L1"` CurrentL2 float64 `json:"current_L2"` CurrentL3 float64 `json:"current_L3"` PowerFactor float64 `json:"power_factor"` PowerFactorL1 float64 `json:"power_factor_L1"` PowerFactorL2 float64 `json:"power_factor_L2"` PowerFactorL3 float64 `json:"power_factor_L3"` ReactiveEnergyP float64 `json:"reactive_energy_+"` ReactiveEnergyL1P float64 `json:"reactive_energy_+_L1"` ReactiveEnergyL2P float64 `json:"reactive_energy_+_L2"` ReactiveEnergyL3P float64 `json:"reactive_energy_+_L3"` ReactiveEnergyM float64 `json:"reactive_energy_-"` ReactiveEnergyL1M float64 `json:"reactive_energy_-_L1"` ReactiveEnergyL2M float64 `json:"reactive_energy_-_L2"` ReactiveEnergyL3M float64 `json:"reactive_energy_-_L3"` ReactivePowerP float64 `json:"reactive_power_+"` ReactivePowerL1P float64 `json:"reactive_power_+_L1"` ReactivePowerL2P float64 `json:"reactive_power_+_L2"` ReactivePowerL3P float64 `json:"reactive_power_+_L3"` ReactivePowerM float64 `json:"reactive_power_-"` ReactivePowerL1M float64 `json:"reactive_power_-_L1"` ReactivePowerL2M float64 `json:"reactive_power_-_L2"` ReactivePowerL3M float64 `json:"reactive_power_-_L3"` SupplyFrequency float64 `json:"supply_frequency"` VoltageL1 float64 `json:"voltage_L1"` VoltageL2 float64 `json:"voltage_L2"` VoltageL3 float64 `json:"voltage_L3"` } `json:"values"` } `json:"smart-meter"` } type TqEM420 struct { dataG func() (TqEm420Data, error) } // NewTqEm420FromConfig creates a new configurable meter func NewTqEm420FromConfig(other map[string]any) (api.Meter, error) { cc := struct { URI string Token string Device string Cache time.Duration }{ Cache: time.Second, } if err := util.DecodeOther(other, &cc); err != nil { return nil, err } log := util.NewLogger("tq-em420").Redact(cc.Token) client := request.NewHelper(log) client.Jar, _ = cookiejar.New(nil) base := util.DefaultScheme(strings.TrimRight(cc.URI, "/"), "http") dataG := util.Cached(func() (TqEm420Data, error) { var res TqEm420Data headers := map[string]string{ "Accept": "application/json", "Authorization": "Bearer " + cc.Token, } req, err := request.New(http.MethodGet, fmt.Sprintf("%s/api/json/"+cc.Device+"/values/smart-meter", base), nil, headers) if err == nil { err = client.DoJSON(req, &res) } return res, err }, cc.Cache) if _, err := dataG(); err != nil { return nil, err } m := &TqEM420{ dataG: dataG, } return m, nil } func (m *TqEM420) CurrentPower() (float64, error) { res, err := m.dataG() return (res.SmartMeter.Values.ActivePowerP - res.SmartMeter.Values.ActivePowerM) / 1e3, err } var _ api.MeterEnergy = (*TqEM420)(nil) func (m *TqEM420) TotalEnergy() (float64, error) { res, err := m.dataG() return res.SmartMeter.Values.ActiveEnergyP / 1e6, err } var _ api.PhaseCurrents = (*TqEM420)(nil) func (m *TqEM420) Currents() (float64, float64, float64, error) { res, err := m.dataG() if err != nil { return 0, 0, 0, err } return res.SmartMeter.Values.CurrentL1 / 1e3, res.SmartMeter.Values.CurrentL2 / 1e3, res.SmartMeter.Values.CurrentL3 / 1e3, nil } func (m *TqEM420) Voltages() (float64, float64, float64, error) { res, err := m.dataG() if err != nil { return 0, 0, 0, err } return res.SmartMeter.Values.VoltageL1 / 1e3, res.SmartMeter.Values.VoltageL2 / 1e3, res.SmartMeter.Values.VoltageL3 / 1e3, nil }