Skip to content

Commit

Permalink
Bluelink: fix handling of stamps (evcc-io#2936)
Browse files Browse the repository at this point in the history
  • Loading branch information
andig authored Mar 19, 2022
1 parent 37f4a56 commit 6787bd4
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 62 deletions.
23 changes: 12 additions & 11 deletions vehicle/bluelink/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,15 @@ func NewIdentity(log *util.Logger, config Config) *Identity {
config: config,
}

// fetch updated stamps
updateStamps(log, config.CCSPApplicationID)

return v
}

// Credits to https://openwb.de/forum/viewtopic.php?f=5&t=1215&start=10#p11877

func (v *Identity) stamp() string {
return Stamps.New(v.config.CCSPApplicationID)
}

func (v *Identity) getDeviceID() (string, error) {
stamp, err := Stamps[v.config.CCSPApplicationID].Get()
if err != nil {
return "", err
}

uniID, _ := uuid.NewUUID()
data := map[string]interface{}{
"pushRegId": "1",
Expand All @@ -79,7 +75,7 @@ func (v *Identity) getDeviceID() (string, error) {
"ccsp-service-id": v.config.CCSPServiceID,
"Content-type": "application/json;charset=UTF-8",
"User-Agent": "okhttp/3.10.0",
"Stamp": v.stamp(),
"Stamp": stamp,
}

var resp struct {
Expand Down Expand Up @@ -362,6 +358,11 @@ func (v *Identity) Login(user, password, language string) (err error) {

// Request decorates requests with authorization headers
func (v *Identity) Request(req *http.Request) error {
stamp, err := Stamps[v.config.CCSPApplicationID].Get()
if err != nil {
return err
}

token, err := v.Token()
if err != nil {
return err
Expand All @@ -373,7 +374,7 @@ func (v *Identity) Request(req *http.Request) error {
"ccsp-application-id": v.config.CCSPApplicationID,
"offset": "1",
"User-Agent": "okhttp/3.10.0",
"Stamp": v.stamp(),
"Stamp": stamp,
} {
req.Header.Set(k, v)
}
Expand Down
92 changes: 41 additions & 51 deletions vehicle/bluelink/stamps.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,72 +15,62 @@ const (
HyundaiAppID = "014d2225-8495-4735-812d-2616334fd15d"
)

// StampsRegistry collects stamps for a single brand
type StampsRegistry map[string]*StampCollection

type StampCollection struct {
Stamps []string
Generated time.Time
Frequency float64
}

var Stamps = StampsRegistry{
KiaAppID: nil,
HyundaiAppID: nil,
type stampCollection struct {
mu sync.Mutex
log *util.Logger
AppID, Brand string
Stamps []string
Generated time.Time
Frequency float64
updated time.Time
}

var (
mu sync.Mutex
updater map[string]struct{} = make(map[string]struct{})

client = request.NewHelper(util.NewLogger("http"))
brands = map[string]string{
KiaAppID: "kia",
HyundaiAppID: "hyundai",

Stamps = map[string]*stampCollection{
KiaAppID: {log: util.NewLogger("kia"), AppID: KiaAppID, Brand: "kia"},
HyundaiAppID: {log: util.NewLogger("hyundai"), AppID: HyundaiAppID, Brand: "hyundai"},
}
)

func download(log *util.Logger, id, brand string) {
var res StampCollection
uri := fmt.Sprintf("https://raw.githubusercontent.com/neoPix/bluelinky-stamps/master/%s-%s.v2.json", brand, id)
// New creates a new stamp
func (c *stampCollection) Get() (string, error) {
c.mu.Lock()
defer c.mu.Unlock()

length := float64(len(c.Stamps))
position := float64(time.Since(c.Generated).Milliseconds()) / c.Frequency

// download
if position >= 0.9*length {
if time.Since(c.updated) > 15*time.Minute {
c.log.TRACE.Printf("retry stamps download, last attempt: %v", c.updated)
if err := c.download(); err != nil {
return "", err
}
}

if err := client.GetJSON(uri, &res); err != nil {
log.ERROR.Println(err)
return
length = float64(len(c.Stamps))
position = float64(time.Since(c.Generated).Milliseconds()) / c.Frequency
}

mu.Lock()
Stamps[id] = &res
mu.Unlock()
}

// updateStamps updates stamps according to https://github.com/Hacksore/bluelinky/pull/144
func updateStamps(log *util.Logger, id string) {
if _, ok := updater[id]; ok {
return
if position >= length {
position = length - 1
}

updater[id] = struct{}{}
download(log, id, brands[id])

go func() {
for range time.NewTicker(24 * time.Hour).C {
download(log, id, brands[id])
}
}()
return c.Stamps[int64(position+5*rand.Float64())], nil
}

// New creates a new stamp
func (s StampsRegistry) New(id string) string {
mu.Lock()
defer mu.Unlock()
// updateStamps updates stamps according to https://github.com/Hacksore/bluelinky/pull/144
func (c *stampCollection) download() error {
c.updated = time.Now()

source := s[id]
if source == nil {
panic(id)
}
uri := fmt.Sprintf("https://raw.githubusercontent.com/neoPix/bluelinky-stamps/master/%s-%s.v2.json", c.Brand, c.AppID)

position := float64(time.Since(source.Generated).Milliseconds()) / source.Frequency
if err := client.GetJSON(uri, &c); err != nil {
return fmt.Errorf("failed to download stamps: %w", err)
}

return source.Stamps[int64(position+5*rand.Float64())]
return nil
}

0 comments on commit 6787bd4

Please sign in to comment.