diff --git a/charger/tasmota.go b/charger/tasmota.go index 8b3df40d7..8783459a8 100644 --- a/charger/tasmota.go +++ b/charger/tasmota.go @@ -18,6 +18,7 @@ import ( // Tasmota charger implementation type Tasmota struct { conn *tasmota.Connection + channel int standbypower float64 } @@ -36,6 +37,7 @@ func NewTasmotaFromConfig(other map[string]interface{}) (api.Charger, error) { }{ Channel: 1, } + if err := util.DecodeOther(other, &cc); err != nil { return nil, err } @@ -45,17 +47,54 @@ func NewTasmotaFromConfig(other map[string]interface{}) (api.Charger, error) { // NewTasmota creates Tasmota charger func NewTasmota(uri, user, password string, channel int, standbypower float64) (*Tasmota, error) { - conn, err := tasmota.NewConnection(uri, user, password, channel) + conn, err := tasmota.NewConnection(uri, user, password) if err != nil { return nil, err } c := &Tasmota{ conn: conn, + channel: channel, standbypower: standbypower, } - return c, nil + err = c.channelExists(channel) + + return c, err +} + +// channelExists checks the existence of the configured relay channel interface +func (c *Tasmota) channelExists(channel int) error { + var res *tasmota.StatusSTSResponse + if err := c.conn.ExecCmd("Status 0", &res); err != nil { + return err + } + + var ok bool + switch channel { + case 1: + ok = res.StatusSTS.Power != "" || res.StatusSTS.Power1 != "" + case 2: + ok = res.StatusSTS.Power2 != "" + case 3: + ok = res.StatusSTS.Power3 != "" + case 4: + ok = res.StatusSTS.Power4 != "" + case 5: + ok = res.StatusSTS.Power5 != "" + case 6: + ok = res.StatusSTS.Power6 != "" + case 7: + ok = res.StatusSTS.Power7 != "" + case 8: + ok = res.StatusSTS.Power8 != "" + } + + if !ok { + return fmt.Errorf("invalid relay channel: %d", channel) + } + + return nil } // Enabled implements the api.Charger interface @@ -66,7 +105,7 @@ func (c *Tasmota) Enabled() (bool, error) { return false, err } - switch c.conn.Channel { + switch c.channel { case 2: return strings.ToUpper(res.StatusSTS.Power2) == "ON", err case 3: @@ -89,18 +128,18 @@ func (c *Tasmota) Enabled() (bool, error) { // Enable implements the api.Charger interface func (c *Tasmota) Enable(enable bool) error { var res tasmota.PowerResponse - on := false - cmd := fmt.Sprintf("Power%d off", c.conn.Channel) + + cmd := fmt.Sprintf("Power%d off", c.channel) if enable { - cmd = fmt.Sprintf("Power%d on", c.conn.Channel) + cmd = fmt.Sprintf("Power%d on", c.channel) } - err := c.conn.ExecCmd(cmd, &res) - if err != nil { + if err := c.conn.ExecCmd(cmd, &res); err != nil { return err } - switch c.conn.Channel { + var on bool + switch c.channel { case 2: on = strings.ToUpper(res.Power2) == "ON" case 3: diff --git a/meter/tasmota.go b/meter/tasmota.go index 416b4c8f7..9c7d65d2a 100644 --- a/meter/tasmota.go +++ b/meter/tasmota.go @@ -11,20 +11,17 @@ func init() { registry.Add("tasmota", NewTasmotaFromConfig) } -// NewTapoFromConfig creates a tapo meter from generic config +// NewTasmotaFromConfig creates a Tasmota meter from generic config func NewTasmotaFromConfig(other map[string]interface{}) (api.Meter, error) { cc := struct { URI string User string Password string - Channel int - }{ - Channel: 1, - } + }{} if err := util.DecodeOther(other, &cc); err != nil { return nil, err } - return tasmota.NewConnection(cc.URI, cc.User, cc.Password, cc.Channel) + return tasmota.NewConnection(cc.URI, cc.User, cc.Password) } diff --git a/meter/tasmota/connection.go b/meter/tasmota/connection.go index acd0d4ea2..9254caa0f 100644 --- a/meter/tasmota/connection.go +++ b/meter/tasmota/connection.go @@ -15,11 +15,10 @@ import ( type Connection struct { *request.Helper uri, user, password string - Channel int } -// NewConnection creates Tasmota charger -func NewConnection(uri, user, password string, channel int) (*Connection, error) { +// NewConnection creates a Tasmota connection +func NewConnection(uri, user, password string) (*Connection, error) { if uri == "" { return nil, errors.New("missing uri") } @@ -30,20 +29,14 @@ func NewConnection(uri, user, password string, channel int) (*Connection, error) uri: util.DefaultScheme(strings.TrimRight(uri, "/"), "http"), user: user, password: password, - Channel: channel, } c.Client.Transport = request.NewTripper(log, transport.Insecure()) - err := c.ChannelExists() - if err != nil { - return nil, err - } - return c, nil } -// ExecCmd executes a Tasmota api command and provides the response +// ExecCmd executes an api command and provides the response func (d *Connection) ExecCmd(cmd string, res interface{}) error { parameters := url.Values{ "user": []string{d.user}, @@ -80,40 +73,3 @@ func (d *Connection) TotalEnergy() (float64, error) { return float64(res.StatusSNS.Energy.Total), nil } - -// ChannelExists checks the existence of the configured relay channel interface -func (d *Connection) ChannelExists() error { - var res *StatusSTSResponse - err := d.ExecCmd("Status 0", &res) - if err != nil { - return err - } - - channelexists := false - switch d.Channel { - case 1: - channelexists = res.StatusSTS.Power != "" || res.StatusSTS.Power1 != "" - case 2: - channelexists = res.StatusSTS.Power2 != "" - case 3: - channelexists = res.StatusSTS.Power3 != "" - case 4: - channelexists = res.StatusSTS.Power4 != "" - case 5: - channelexists = res.StatusSTS.Power5 != "" - case 6: - channelexists = res.StatusSTS.Power6 != "" - case 7: - channelexists = res.StatusSTS.Power7 != "" - case 8: - channelexists = res.StatusSTS.Power8 != "" - default: - channelexists = false - } - - if !channelexists { - return errors.New("configured relay channel doesn't exist on device") - } - - return nil -} diff --git a/templates/definition/meter/tasmota.yaml b/templates/definition/meter/tasmota.yaml index 802af2254..2c759de49 100644 --- a/templates/definition/meter/tasmota.yaml +++ b/templates/definition/meter/tasmota.yaml @@ -5,7 +5,7 @@ products: group: switchsockets params: - name: usage - choice: ["pv"] + choice: ["grid", "pv", "battery"] - name: host - name: user required: false @@ -15,18 +15,8 @@ params: - name: password required: false mask: true - - name: channel - default: 1 - required: true - description: - de: Nummer des Schalt-Kanals - en: Device relay channel number - help: - de: Nummer des Schalt-Kanals (1-8), bei Geräten mit mehr als einem Schalter - en: Device relay channel number (allowed range 1-8) render: | type: tasmota uri: http://{{ .host }} user: {{ .user }} password: {{ .password }} - channel: {{ .channel }} # # relay channel (allowed range: 1-8) diff --git a/templates/docs/meter/tasmota_0.yaml b/templates/docs/meter/tasmota_0.yaml index 5cdcbc3a5..d23a9c314 100644 --- a/templates/docs/meter/tasmota_0.yaml +++ b/templates/docs/meter/tasmota_0.yaml @@ -2,6 +2,14 @@ product: description: Tasmota group: Schaltbare Steckdosen render: + - usage: grid + default: | + type: template + template: tasmota + usage: grid + host: 192.0.2.2 # IP-Adresse oder Hostname + user: # Standard-User ist admin # Optional + password: # Passwort des Benutzerkontos (bei führenden Nullen bitte in einfache Hochkommata setzen) # Optional - usage: pv default: | type: template @@ -10,4 +18,11 @@ render: host: 192.0.2.2 # IP-Adresse oder Hostname user: # Standard-User ist admin # Optional password: # Passwort des Benutzerkontos (bei führenden Nullen bitte in einfache Hochkommata setzen) # Optional - channel: 1 # Nummer des Schalt-Kanals (1-8), bei Geräten mit mehr als einem Schalter + - usage: battery + default: | + type: template + template: tasmota + usage: battery + host: 192.0.2.2 # IP-Adresse oder Hostname + user: # Standard-User ist admin # Optional + password: # Passwort des Benutzerkontos (bei führenden Nullen bitte in einfache Hochkommata setzen) # Optional