Skip to content

Commit

Permalink
Provide option to override SEMP vendor id (evcc-io#1406)
Browse files Browse the repository at this point in the history
  • Loading branch information
DerAndereAndi authored Aug 22, 2021
1 parent fde9613 commit 1dc2845
Showing 1 changed file with 42 additions and 25 deletions.
67 changes: 42 additions & 25 deletions hems/semp/semp.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const (
sempController = "Sunny Home Manager"
sempBaseURLEnv = "SEMP_BASE_URL"
sempGateway = "urn:schemas-simple-energy-management-protocol:device:Gateway:1"
sempDeviceId = "F-28081973-%.12x-00" // 6 bytes
sempDeviceId = "F-%s-%.12x-00" // 6 bytes
sempSerialNumber = "%s-%d"
sempCharger = "EVCharger"
basePath = "/semp"
Expand All @@ -44,6 +44,7 @@ type SEMP struct {
closeC chan struct{}
doneC chan struct{}
controllable bool
vid string
did []byte
uid string
hostURI string
Expand All @@ -54,9 +55,12 @@ type SEMP struct {
// New generates SEMP Gateway listening at /semp endpoint
func New(conf map[string]interface{}, site core.SiteAPI, cache *util.Cache, httpd *server.HTTPd) (*SEMP, error) {
cc := struct {
VendorID string
DeviceID string
AllowControl bool
}{}
}{
VendorID: "28081973",
}

if err := util.DecodeOther(conf, &cc); err != nil {
return nil, err
Expand All @@ -67,22 +71,33 @@ func New(conf map[string]interface{}, site core.SiteAPI, cache *util.Cache, http
return nil, err
}

if len(cc.VendorID) != 8 {
return nil, fmt.Errorf("invalid vendor id: %v", cc.VendorID)
}

var did []byte
if cc.DeviceID == "" {
did, err = uniqueDeviceID()
} else {
did, err = hex.DecodeString(cc.DeviceID)

}

if err != nil || len(did) != 6 {
return nil, fmt.Errorf("invalid device id: %v", cc.DeviceID)
}

s := &SEMP{
doneC: make(chan struct{}),
log: util.NewLogger("semp"),
cache: cache,
site: site,
uid: uid.String(),
vid: cc.VendorID,
did: did,
controllable: cc.AllowControl,
}

if len(cc.DeviceID) > 0 {
s.did, err = hex.DecodeString(cc.DeviceID)
if err != nil || len(s.did) != 6 {
return nil, fmt.Errorf("invalid device id: %v", cc.DeviceID)
}
}

// find external port
_, port, err := net.SplitHostPort(httpd.Addr)
if err == nil {
Expand Down Expand Up @@ -320,30 +335,32 @@ func (s *SEMP) serialNumber(id int) string {
return fmt.Sprintf(sempSerialNumber, ser, id)
}

// deviceID creates a 6-bytes device id from machine id plus device number
func (s *SEMP) deviceID(id int) string {
// uniqueDeviceID creates a 6-bytes base device id from machine id
func uniqueDeviceID() ([]byte, error) {
bytes := 6
if s.did == nil {
mid, err := machineid.ProtectedID("evcc-semp")
if err != nil {
panic(err)
}

b, err := hex.DecodeString(mid)
if err != nil {
panic(err)
}
mid, err := machineid.ProtectedID("evcc-semp")
if err != nil {
return nil, err
}

for i, v := range b {
b[i%bytes] += v
}
b, err := hex.DecodeString(mid)
if err != nil {
return nil, err
}

s.did = b[:bytes]
for i, v := range b {
b[i%bytes] += v
}

return b[:bytes], nil
}

// deviceID combines base device id with device number
func (s *SEMP) deviceID(id int) string {
// numerically add device number
did := append([]byte{0, 0}, s.did...)
return fmt.Sprintf(sempDeviceId, ^uint64(0xffff<<48)&(binary.BigEndian.Uint64(did)+uint64(id)))
return fmt.Sprintf(sempDeviceId, s.vid, ^uint64(0xffff<<48)&(binary.BigEndian.Uint64(did)+uint64(id)))
}

func (s *SEMP) deviceInfo(id int, lp core.LoadPointAPI) DeviceInfo {
Expand Down

0 comments on commit 1dc2845

Please sign in to comment.