Fritz: provide AIN dropdown (#29529)

This commit is contained in:
andig 2026-05-01 13:29:53 +02:00 • committed by GitHub
parent 6f89d00aef
commit fa5137668a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 98 additions and 0 deletions

View file

@ -0,0 +1,83 @@
package smarthome
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"slices"
"strings"
"github.com/evcc-io/evcc/meter/fritz"
"github.com/evcc-io/evcc/server/service"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
"github.com/evcc-io/evcc/util/transport"
"github.com/samber/lo"
)
func init() {
mux := http.NewServeMux()
mux.HandleFunc("GET /devices", getDevices)
service.Register("fritz", mux)
}
func getDevices(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
uri := strings.TrimRight(q.Get("uri"), "/")
user := q.Get("user")
password := q.Get("password")
if uri == "" || user == "" || password == "" {
jsonError(w, http.StatusBadRequest, errors.New("missing uri, user or password"))
return
}
log := util.NewLogger("fritz").Redact(password)
helper := request.NewHelper(log)
helper.Client.Transport = request.NewTripper(log, transport.Insecure())
settings := fritz.Settings{URI: uri, User: user, Password: password}
sid, err := settings.GetSessionID(helper)
if err != nil {
jsonError(w, http.StatusBadRequest, err)
return
}
if sid == "0000000000000000" {
jsonError(w, http.StatusUnauthorized, errors.New("invalid user or password"))
return
}
req, _ := request.New(http.MethodGet,
fmt.Sprintf("%s/api/v0/smarthome/overview/devices", uri), nil, map[string]string{
"Authorization": "AVM-SID " + sid,
}, request.AcceptJSON,
)
var devices []Device
if err := helper.DoJSON(req, &devices); err != nil {
jsonError(w, http.StatusBadRequest, err)
return
}
ains := lo.Map(devices, func(d Device, _ int) string {
return d.AIN
})
slices.Sort(ains)
w.Header().Set("Cache-control", "max-age=60")
jsonWrite(w, ains)
}
func jsonWrite(w http.ResponseWriter, data any) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(data)
}
func jsonError(w http.ResponseWriter, status int, err error) {
w.WriteHeader(status)
jsonWrite(w, util.ErrorAsJson(err))
}

View file

@ -1,5 +1,15 @@
package smarthome
// Device represents a smarthome device from the /devices endpoint
type Device struct {
UID string `json:"UID"`
AIN string `json:"ain"`
Name string `json:"name"`
ProductName string `json:"productName"`
ProductCategory string `json:"productCategory"`
IsConnected bool `json:"isConnected"`
}
// Unit represents a smarthome unit with its interfaces
type Unit struct {
GroupUID string `json:"groupUid,omitempty"`

View file

@ -83,6 +83,7 @@ func jsonHandler(h http.Handler) http.Handler {
}
func jsonWrite(w http.ResponseWriter, data any) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(data)
}

View file

@ -25,6 +25,7 @@ params:
required: true
- name: ain
required: true
service: fritz/devices?uri={uri}&user={user}&password={password}
- name: firmware82
advanced: true
type: bool

View file

@ -27,6 +27,7 @@ params:
required: true
- name: ain
required: true
service: fritz/devices?uri={uri}&user={user}&password={password}
- name: firmware82
advanced: true
type: bool

View file

@ -14,6 +14,7 @@ params:
required: true
- name: ain
required: true
service: fritz/devices?uri={uri}&user={user}&password={password}
render: |
type: fritzdect
uri: {{ .uri }}

View file

@ -128,6 +128,7 @@ func getServices(w http.ResponseWriter, req *http.Request) {
// jsonWrite writes a JSON response
func jsonWrite(w http.ResponseWriter, data any) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(data)
}