fix: device color MQTT encoding (#30168)

This commit is contained in:
Michael Geers 2026-05-24 11:13:05 +02:00 • committed by GitHub
parent 8e0d991455
commit cf7a95b61a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 107 additions and 26 deletions

View file

@ -3,15 +3,22 @@ package ui
import (
"maps"
"slices"
"strings"
"sync"
"github.com/evcc-io/evcc/core/keys"
"github.com/evcc-io/evcc/server/db/settings"
)
// DeviceColor is the MQTT-safe publish format (map keys would leak into topic segments).
type DeviceColor struct {
Title string `json:"title"`
Color string `json:"color"`
}
var colorsMu sync.RWMutex
// GetDeviceColors returns the persisted title→hex map (never nil).
func GetDeviceColors() map[string]string {
colorsMu.RLock()
defer colorsMu.RUnlock()
@ -20,7 +27,6 @@ func GetDeviceColors() map[string]string {
return m
}
// SaveDeviceColors persists the title→hex map.
func SaveDeviceColors(m map[string]string) error {
colorsMu.Lock()
defer colorsMu.Unlock()
@ -28,3 +34,13 @@ func SaveDeviceColors(m map[string]string) error {
maps.Copy(clean, m)
return settings.SetJson(keys.DeviceColors, clean)
}
func DeviceColorList() []DeviceColor {
m := GetDeviceColors()
list := make([]DeviceColor, 0, len(m))
for title, color := range m {
list = append(list, DeviceColor{Title: title, Color: color})
}
slices.SortFunc(list, func(a, b DeviceColor) int { return strings.Compare(a.Title, b.Title) })
return list
}

45
ui/colors_test.go Normal file
View file

@ -0,0 +1,45 @@
package ui
import (
"path/filepath"
"testing"
"github.com/evcc-io/evcc/server/db"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func setupDB(t *testing.T) {
t.Helper()
require.NoError(t, db.NewInstance("sqlite", filepath.Join(t.TempDir(), "test.db")))
}
func TestDeviceColors_RoundTrip(t *testing.T) {
setupDB(t)
in := map[string]string{"WP-SG+": "#2563EB", "Heizung": "#DC2626"}
require.NoError(t, SaveDeviceColors(in))
assert.Equal(t, in, GetDeviceColors())
}
func TestDeviceColors_EmptyWhenAbsent(t *testing.T) {
setupDB(t)
assert.Empty(t, GetDeviceColors())
}
func TestDeviceColorList_SortedAndSafe(t *testing.T) {
setupDB(t)
require.NoError(t, SaveDeviceColors(map[string]string{
"WP-SG+": "#2563EB",
"Heizung": "#DC2626",
"Carport": "#10B981",
}))
assert.Equal(t, []DeviceColor{
{Title: "Carport", Color: "#10B981"},
{Title: "Heizung", Color: "#DC2626"},
{Title: "WP-SG+", Color: "#2563EB"},
}, DeviceColorList())
}