Skip to content

Commit

Permalink
Tasmota: fix meter config (evcc-io#3459)
Browse files Browse the repository at this point in the history
  • Loading branch information
thierolm authored May 22, 2022
1 parent 820047d commit b814afb
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 74 deletions.
57 changes: 48 additions & 9 deletions charger/tasmota.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
// Tasmota charger implementation
type Tasmota struct {
conn *tasmota.Connection
channel int
standbypower float64
}

Expand All @@ -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
}
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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:
Expand Down
9 changes: 3 additions & 6 deletions meter/tasmota.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
50 changes: 3 additions & 47 deletions meter/tasmota/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand All @@ -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},
Expand Down Expand Up @@ -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
}
12 changes: 1 addition & 11 deletions templates/definition/meter/tasmota.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ products:
group: switchsockets
params:
- name: usage
choice: ["pv"]
choice: ["grid", "pv", "battery"]
- name: host
- name: user
required: false
Expand All @@ -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)
17 changes: 16 additions & 1 deletion templates/docs/meter/tasmota_0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

0 comments on commit b814afb

Please sign in to comment.