Sunspec: share block reads across values on the same connection (#33011)

This commit is contained in:
andig 2026-08-20 16:40:13 +02:00 • committed by GitHub
parent 1a0a05c9ad
commit de0bac2bc8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 210 additions and 1 deletions

45
plugin/sunspec_client.go Normal file
View file

@ -0,0 +1,45 @@
package plugin
import (
"bytes"
"fmt"
"github.com/evcc-io/evcc/util/modbus"
gridx "github.com/grid-x/modbus"
)
// sunspecCachedClient dedups the holding register reads gosunspec issues on
// behalf of all sunspec values sharing a model block within one poll cycle.
type sunspecCachedClient struct {
gridx.Client
cache *modbus.Cache
}
// newSunspecCachedClient wraps client for use as gosunspec's modbus client.
func newSunspecCachedClient(client gridx.Client) *sunspecCachedClient {
return &sunspecCachedClient{Client: client, cache: modbus.NewCache(modbusBlockTTL)}
}
func (c *sunspecCachedClient) ReadHoldingRegisters(address, quantity uint16) ([]byte, error) {
key := fmt.Sprintf("%d/%d", address, quantity)
b, _, err := c.cache.Fetch(key, func() ([]byte, error) {
return c.Client.ReadHoldingRegisters(address, quantity)
})
if err != nil {
return nil, err
}
// callers unmarshal in place, hand out a copy of the shared payload
return bytes.Clone(b), nil
}
func (c *sunspecCachedClient) WriteSingleRegister(address, value uint16) ([]byte, error) {
defer c.cache.Clear()
return c.Client.WriteSingleRegister(address, value)
}
func (c *sunspecCachedClient) WriteMultipleRegisters(address, quantity uint16, value []byte) ([]byte, error) {
defer c.cache.Clear()
return c.Client.WriteMultipleRegisters(address, quantity, value)
}