Skip to content

Commit

Permalink
Add TQ-EM 2xx/3xx meter (#3174)
Browse files Browse the repository at this point in the history
Co-authored-by: premultiply <dev@foo.bar>
  • Loading branch information
andig and premultiply authored Apr 17, 2022
1 parent 904eca0 commit 631706c
Show file tree
Hide file tree
Showing 7 changed files with 239 additions and 2 deletions.
2 changes: 0 additions & 2 deletions meter/discovergy.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,6 @@ func matchesIdentifier(id string, m discovergy.Meter) bool {
return id == m.MeterID || id == m.SerialNumber || id == m.FullSerialNumber
}

var _ api.Meter = (*Discovergy)(nil)

func (m *Discovergy) CurrentPower() (float64, error) {
res, err := m.dataG()
return m.scale * float64(res.Values.Power) / 1e3, err
Expand Down
160 changes: 160 additions & 0 deletions meter/tq-em.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package meter

import (
"errors"
"fmt"
"net/http"
"net/http/cookiejar"
"net/url"
"strings"
"time"

"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/provider"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
)

func init() {
registry.Add("tq-em", NewTqEmFromConfig)
}

type tqemData struct {
Authentication *bool
Serial string
Obis1_4_0 float64 `json:"1-0:1.4.0*255"`
Obis1_8_0 float64 `json:"1-0:1.8.0*255"`
Obis2_4_0 float64 `json:"1-0:2.4.0*255"`
Obis2_8_0 float64 `json:"1-0:2.8.0*255"`
Obis13_4_0 float64 `json:"1-0:13.4.0*255"`
Obis14_4_0 float64 `json:"1-0:14.4.0*255"`
Obis21_4_0 float64 `json:"1-0:21.4.0*255"`
Obis21_8_0 float64 `json:"1-0:21.8.0*255"`
Obis22_4_0 float64 `json:"1-0:22.4.0*255"`
Obis22_8_0 float64 `json:"1-0:22.8.0*255"`
Obis31_4_0 *float64 `json:"1-0:31.4.0*255"` // optional currents
Obis32_4_0 float64 `json:"1-0:32.4.0*255"`
Obis33_4_0 float64 `json:"1-0:33.4.0*255"`
Obis41_4_0 float64 `json:"1-0:41.4.0*255"`
Obis41_8_0 float64 `json:"1-0:41.8.0*255"`
Obis42_4_0 float64 `json:"1-0:42.4.0*255"`
Obis42_8_0 float64 `json:"1-0:42.8.0*255"`
Obis51_4_0 *float64 `json:"1-0:51.4.0*255"` // optional currents
Obis52_4_0 float64 `json:"1-0:52.4.0*255"`
Obis53_4_0 float64 `json:"1-0:53.4.0*255"`
Obis61_4_0 float64 `json:"1-0:61.4.0*255"`
Obis61_8_0 float64 `json:"1-0:61.8.0*255"`
Obis62_4_0 float64 `json:"1-0:62.4.0*255"`
Obis62_8_0 float64 `json:"1-0:62.8.0*255"`
Obis71_4_0 *float64 `json:"1-0:71.4.0*255"` // optional currents
Obis72_4_0 float64 `json:"1-0:72.4.0*255"`
Obis73_4_0 float64 `json:"1-0:73.4.0*255"`
}

type TqEm struct {
dataG func() (tqemData, error)
scale float64
}

//go:generate go run ../cmd/tools/decorate.go -f decorateTqEm -b api.Meter -t "api.MeterCurrent,Currents,func() (float64, float64, float64, error)"

// NewTqEmFromConfig creates a new configurable meter
func NewTqEmFromConfig(other map[string]interface{}) (api.Meter, error) {
cc := struct {
URI string
Password string
Cache time.Duration
}{
Cache: time.Second,
}

if err := util.DecodeOther(other, &cc); err != nil {
return nil, err
}

log := util.NewLogger("tq-em").Redact(cc.Password)

client := request.NewHelper(log)
client.Jar, _ = cookiejar.New(nil)

base := util.DefaultScheme(strings.TrimRight(cc.URI, "/"), "http")

// get serial number
var meter tqemData

uri := fmt.Sprintf("%s/start.php", base)
err := client.GetJSON(uri, &meter)
if err != nil {
return nil, err
}

if meter.Serial == "" {
return nil, errors.New("no serial")
}

dataG := provider.Cached(func() (tqemData, error) {
var res tqemData

uri := fmt.Sprintf("%s/mum-webservice/data.php", base)
err := client.GetJSON(uri, &res)

if err == nil && res.Serial == "" {
data := url.Values{
"login": {meter.Serial},
"password": {cc.Password},
}

var req *http.Request
req, err = request.New(http.MethodPost, fmt.Sprintf("%s/start.php", base), strings.NewReader(data.Encode()), request.URLEncoding)

if err == nil {
_, err = client.DoBody(req)
}

if err == nil {
err = client.GetJSON(uri, &res)
}
}

if err == nil && res.Serial == "" {
err = errors.New("authentication failed")
}

return res, err
}, cc.Cache)

m := &TqEm{
dataG: dataG,
}

res, err := dataG()
if err != nil {
return nil, err
}

if res.Obis31_4_0 != nil {
return decorateTqEm(m, m.currents), nil
}

return m, nil
}

func (m *TqEm) CurrentPower() (float64, error) {
res, err := m.dataG()
return res.Obis1_4_0 - res.Obis2_4_0, err
}

var _ api.MeterEnergy = (*TqEm)(nil)

func (m *TqEm) TotalEnergy() (float64, error) {
res, err := m.dataG()
return res.Obis1_8_0 / 1e3, err
}

func (m *TqEm) currents() (float64, float64, float64, error) {
res, err := m.dataG()
if err != nil {
return 0, 0, 0, err
}
return *res.Obis31_4_0, *res.Obis51_4_0, *res.Obis71_4_0, nil
}
35 changes: 35 additions & 0 deletions meter/tq-em_decorators.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions templates/definition/meter/tq-em.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
template: tq-em
products:
- brand: TQ
description:
generic: Energy Manager EM2xx
- brand: TQ
description:
generic: Energy Manager EM3xx
params:
- name: usage
choice: ["grid"]
- name: host
- name: port
default: 80
- name: password
render: |
type: tq-em
uri: http://{{ .host }}:{{ .port }}
password: {{ .password }}
12 changes: 12 additions & 0 deletions templates/docs/meter/tq-em_0.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
product:
brand: TQ
description: Energy Manager EM2xx
render:
- usage: grid
default: |
type: template
template: tq-em
usage: grid
host: 192.0.2.2 # IP-Adresse oder Hostname
port: 80 # Port # Optional
password: # Passwort des Benutzerkontos (bei führenden Nullen bitte in einfache Hochkommata setzen) # Optional
12 changes: 12 additions & 0 deletions templates/docs/meter/tq-em_1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
product:
brand: TQ
description: Energy Manager EM3xx
render:
- usage: grid
default: |
type: template
template: tq-em
usage: grid
host: 192.0.2.2 # IP-Adresse oder Hostname
port: 80 # Port # Optional
password: # Passwort des Benutzerkontos (bei führenden Nullen bitte in einfache Hochkommata setzen) # Optional
1 change: 1 addition & 0 deletions templates/evcc.io/brands.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"Sonnenbatterie",
"Sungrow",
"Tesla",
"TQ",
"VARTA",
"Victron",
"Volkszähler"
Expand Down

0 comments on commit 631706c

Please sign in to comment.