HEMS: add "smartgrid" session logging (#25907)

This commit is contained in:
andig 2025-12-12 18:29:31 +01:00 • committed by GitHub
parent 73f468e4c5
commit 381573b0eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 915 additions and 215 deletions

View file

@ -17,12 +17,14 @@ var (
sessions Sessions
)
func Init() error {
err := db.Instance.AutoMigrate(new(Session))
if err == nil {
err = db.Instance.Find(&sessions).Error
}
return err
func init() {
db.Register(func() error {
if err := db.Instance.AutoMigrate(new(Session)); err != nil {
return err
}
return db.Instance.Find(&sessions).Error
})
}
// NewStore creates a session store

View file

@ -1,17 +0,0 @@
package session
import (
"testing"
"github.com/stretchr/testify/assert"
"golang.org/x/text/language"
"golang.org/x/text/message"
)
func TestFormatValue(t *testing.T) {
mp := message.NewPrinter(language.Make("en"))
f := 1.2345
assert.Equal(t, "1.234", formatValue(mp, f, 3))
assert.Equal(t, "1.234", formatValue(mp, &f, 3))
}

View file

@ -2,20 +2,11 @@ package session
import (
"context"
"encoding/csv"
"fmt"
"io"
"reflect"
"strings"
"time"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util/locale"
"github.com/fatih/structs"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
"golang.org/x/text/message"
"golang.org/x/text/number"
csvutil "github.com/evcc-io/evcc/util/csv"
)
// Session is a single charging session
@ -42,112 +33,9 @@ type Sessions []Session
var _ api.CsvWriter = (*Sessions)(nil)
func (t *Sessions) writeHeader(ctx context.Context, ww *csv.Writer) error {
localizer := locale.Localizer
if val := ctx.Value(locale.Locale).(string); val != "" {
localizer = i18n.NewLocalizer(locale.Bundle, val, locale.Language)
}
var row []string
for _, f := range structs.Fields(Session{}) {
csv := f.Tag("csv")
if csv == "-" {
continue
}
caption, err := localizer.Localize(&locale.Config{
MessageID: "sessions.csv." + strings.ToLower(f.Name()),
})
if err != nil {
if csv != "" {
caption = csv
} else {
caption = f.Name()
}
}
row = append(row, caption)
}
return ww.Write(row)
}
func formatValue(mp *message.Printer, value any, digits int) string {
if rv := reflect.ValueOf(value); rv.Kind() == reflect.Pointer && rv.IsNil() {
return ""
}
switch v := value.(type) {
case float64:
return mp.Sprint(number.Decimal(v, number.NoSeparator(), number.MaxFractionDigits(digits)))
case *float64:
return mp.Sprint(number.Decimal(*v, number.NoSeparator(), number.MaxFractionDigits(digits)))
case time.Time:
if v.IsZero() {
return ""
}
return v.Local().Format("2006-01-02 15:04:05")
default:
return fmt.Sprintf("%v", value)
}
}
func (t *Sessions) writeRow(ww *csv.Writer, mp *message.Printer, r Session) error {
var row []string
for _, f := range structs.Fields(r) {
if f.Tag("csv") == "-" {
continue
}
digits := 3
if format := f.Tag("format"); format == "int" {
digits = 0
}
val := formatValue(mp, f.Value(), digits)
row = append(row, val)
}
return ww.Write(row)
}
// WriteCsv implements the api.CsvWriter interface
func (t *Sessions) WriteCsv(ctx context.Context, w io.Writer) error {
if _, err := w.Write([]byte{0xEF, 0xBB, 0xBF}); err != nil {
return err
}
// get context language
lang := locale.Language
if language, ok := ctx.Value(locale.Locale).(string); ok && language != "" {
lang = language
}
tag, err := language.Parse(lang)
if err != nil {
return err
}
ww := csv.NewWriter(w)
// set separator according to locale
if b, _ := tag.Base(); b.String() == language.German.String() {
ww.Comma = ';'
}
if err := t.writeHeader(ctx, ww); err != nil {
return err
}
mp := message.NewPrinter(tag)
for _, r := range *t {
if err := t.writeRow(ww, mp, r); err != nil {
return err
}
}
ww.Flush()
return ww.Error()
return csvutil.WriteStructSlice(ctx, w, t, csvutil.Config{
I18nPrefix: "sessions.csv",
})
}