HomeAssistant: detect units (BC) (#26439)
This commit is contained in:
parent
708d600db4
commit
b045f17b94
3 changed files with 62 additions and 28 deletions
|
|
@ -7,6 +7,7 @@ import (
|
|||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -59,19 +60,19 @@ func (c *Connection) GetStates() ([]StateResponse, error) {
|
|||
}
|
||||
|
||||
// GetState retrieves the state of an entity
|
||||
func (c *Connection) GetState(entity string) (string, error) {
|
||||
func (c *Connection) GetState(entity string) (StateResponse, error) {
|
||||
var res StateResponse
|
||||
uri := fmt.Sprintf("%s/api/states/%s", c.instance.URI(), url.PathEscape(entity))
|
||||
|
||||
if err := c.GetJSON(uri, &res); err != nil {
|
||||
return "", err
|
||||
return res, err
|
||||
}
|
||||
|
||||
if res.State == "unknown" || res.State == "unavailable" {
|
||||
return "", api.ErrNotAvailable
|
||||
return res, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
return res.State, nil
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetIntState retrieves the state of an entity as int64
|
||||
|
|
@ -81,9 +82,9 @@ func (c *Connection) GetIntState(entity string) (int64, error) {
|
|||
return 0, err
|
||||
}
|
||||
|
||||
value, err := strconv.ParseInt(state, 10, 64)
|
||||
value, err := strconv.ParseInt(state.State, 10, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid numeric state '%s' for entity %s: %w", state, entity, err)
|
||||
return 0, fmt.Errorf("invalid numeric state '%s' for entity %s: %w", state.State, entity, err)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
|
|
@ -96,12 +97,17 @@ func (c *Connection) GetFloatState(entity string) (float64, error) {
|
|||
return 0, err
|
||||
}
|
||||
|
||||
value, err := strconv.ParseFloat(state, 64)
|
||||
value, err := strconv.ParseFloat(state.State, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid numeric state '%s' for entity %s: %w", state, entity, err)
|
||||
return 0, fmt.Errorf("invalid numeric state '%s' for entity %s: %w", state.State, entity, err)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
scale, err := state.scale()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("%w for entity %s", err, entity)
|
||||
}
|
||||
|
||||
return scale * value, nil
|
||||
}
|
||||
|
||||
// GetBoolState retrieves the state of an entity as boolean
|
||||
|
|
@ -111,8 +117,8 @@ func (c *Connection) GetBoolState(entity string) (bool, error) {
|
|||
return false, err
|
||||
}
|
||||
|
||||
state = strings.ToLower(state)
|
||||
switch state {
|
||||
res := strings.ToLower(state.State)
|
||||
switch res {
|
||||
case "on", "true", "1", "active", "yes":
|
||||
return true, nil
|
||||
case "off", "false", "0", "inactive", "no":
|
||||
|
|
@ -122,6 +128,20 @@ func (c *Connection) GetBoolState(entity string) (bool, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// GetTimeState retrieves the state of an entity as time
|
||||
func (c *Connection) GetTimeState(entity string) (time.Time, error) {
|
||||
state, err := c.GetState(entity)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
if ts, err := strconv.ParseInt(state.State, 10, 64); err == nil {
|
||||
return time.Unix(ts, 0), nil
|
||||
}
|
||||
|
||||
return time.Parse(time.RFC3339, state.State)
|
||||
}
|
||||
|
||||
// chargeStatusMap maps Home Assistant states to EVCC charge status
|
||||
var chargeStatusMap = map[string]api.ChargeStatus{
|
||||
// Status C - Charging
|
||||
|
|
@ -166,7 +186,7 @@ func (c *Connection) GetChargeStatus(entity string) (api.ChargeStatus, error) {
|
|||
return api.StatusNone, err
|
||||
}
|
||||
|
||||
if status, ok := chargeStatusMap[strings.ToLower(strings.TrimSpace(state))]; ok {
|
||||
if status, ok := chargeStatusMap[strings.ToLower(strings.TrimSpace(state.State))]; ok {
|
||||
return status, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
package homeassistant
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type StateResponse struct {
|
||||
EntityId string `json:"entity_id"`
|
||||
State string `json:"state"`
|
||||
|
|
@ -9,3 +14,26 @@ type StateResponse struct {
|
|||
FriendlyName string `json:"friendly_name"`
|
||||
} `json:"attributes"`
|
||||
}
|
||||
|
||||
func (state StateResponse) scale() (float64, error) {
|
||||
if unit, ok := strings.CutSuffix(state.Attributes.UnitOfMeasurement, "W"); ok {
|
||||
switch unit {
|
||||
case "":
|
||||
case "k":
|
||||
return 1e3, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("invalid unit '%s'", state.Attributes.UnitOfMeasurement)
|
||||
}
|
||||
} else if unit, ok := strings.CutSuffix(state.Attributes.UnitOfMeasurement, "Wh"); ok {
|
||||
switch unit {
|
||||
case "":
|
||||
return 1e-3, nil
|
||||
case "k":
|
||||
case "M":
|
||||
return 1e3, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("invalid unit '%s'", state.Attributes.UnitOfMeasurement)
|
||||
}
|
||||
}
|
||||
return 1, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package vehicle
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
|
|
@ -66,7 +65,7 @@ func NewHomeAssistantVehicleFromConfig(other map[string]any) (api.Vehicle, error
|
|||
soc: cc.Sensors.Soc,
|
||||
}
|
||||
|
||||
// prepare optional feature functions with concise names
|
||||
// optional features
|
||||
var (
|
||||
limitSoc func() (int64, error)
|
||||
status func() (api.ChargeStatus, error)
|
||||
|
|
@ -101,7 +100,7 @@ func NewHomeAssistantVehicleFromConfig(other map[string]any) (api.Vehicle, error
|
|||
climater = func() (bool, error) { return conn.GetBoolState(cc.Sensors.Climater) }
|
||||
}
|
||||
if cc.Sensors.FinishTime != "" {
|
||||
finish = func() (time.Time, error) { return res.finishTime(cc.Sensors.FinishTime) }
|
||||
finish = func() (time.Time, error) { return conn.GetTimeState(cc.Sensors.FinishTime) }
|
||||
}
|
||||
if cc.Services.Start != "" && cc.Services.Stop != "" {
|
||||
enable = func(enable bool) error { return res.enable(cc.Services.Start, cc.Services.Stop, enable) }
|
||||
|
|
@ -133,19 +132,6 @@ func (v *HomeAssistant) Soc() (float64, error) {
|
|||
return v.conn.GetFloatState(v.soc)
|
||||
}
|
||||
|
||||
func (v *HomeAssistant) finishTime(entity string) (time.Time, error) {
|
||||
s, err := v.conn.GetState(entity)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
if ts, err := strconv.ParseInt(s, 10, 64); err == nil {
|
||||
return time.Unix(ts, 0), nil
|
||||
}
|
||||
|
||||
return time.Parse(time.RFC3339, s)
|
||||
}
|
||||
|
||||
func (v *HomeAssistant) enable(on, off string, enable bool) error {
|
||||
if enable {
|
||||
return v.conn.CallSwitchService(on, true)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue