-
-
Notifications
You must be signed in to change notification settings - Fork 518
/
session.go
149 lines (123 loc) Β· 3.4 KB
/
session.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package db
import (
"context"
"encoding/csv"
"fmt"
"io"
"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"
)
// Session is a single charging session
type Session struct {
ID uint `json:"-" csv:"-" gorm:"primarykey"`
Created time.Time `json:"created"`
Finished time.Time `json:"finished"`
Loadpoint string `json:"loadpoint"`
Identifier string `json:"identifier"`
Vehicle string `json:"vehicle"`
Odometer float64 `json:"odometer" format:"int"`
MeterStart float64 `json:"meterStart" csv:"Meter Start (kWh)" gorm:"column:meter_start_kwh"`
MeterStop float64 `json:"meterStop" csv:"Meter Stop (kWh)" gorm:"column:meter_end_kwh"`
ChargedEnergy float64 `json:"chargedEnergy" csv:"Charged Energy (kWh)" gorm:"column:charged_kwh"`
}
// Stop stops charging session with end meter reading and due total amount
func (t *Session) Stop(chargedWh, total float64) {
if chargedEnergy := chargedWh / 1e3; chargedEnergy > t.ChargedEnergy {
t.ChargedEnergy = chargedEnergy
}
t.MeterStop = total
t.Finished = time.Now()
}
// Sessions is a list of sessions
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 (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
}
var val string
format := f.Tag("format")
switch v := f.Value().(type) {
case float64:
switch format {
case "int":
val = mp.Sprint(number.Decimal(v, number.MaxFractionDigits(0)))
default:
val = mp.Sprint(number.Decimal(v, number.MaxFractionDigits(3)))
}
case time.Time:
if !v.IsZero() {
val = v.Local().Format("2006-01-02 15:04:05")
}
default:
val = fmt.Sprintf("%v", f.Value())
}
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()
}