nicer plot
This commit is contained in:
1 parent
624ff1da42
commit
1275e5a821
2 files changed
+72
-14
No files matched your search
@@ -25,6 +25,8 @@ type store struct {
|
||||
history []sample
|
||||
}
|
||||
|
||||
const maxHistoryPoints = 10000
|
||||
|
||||
type sample struct {
|
||||
at time.Time
|
||||
value int
|
||||
@@ -42,6 +44,11 @@ func (s *store) set(v int) {
|
||||
now := time.Now()
|
||||
s.updatedAt = now
|
||||
s.history = append(s.history, sample{at: now, value: v})
|
||||
s.trimHistoryLocked(now)
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *store) trimHistoryLocked(now time.Time) {
|
||||
cutoff := now.Add(-12 * time.Hour)
|
||||
keep := s.history[:0]
|
||||
for _, point := range s.history {
|
||||
@@ -49,8 +56,10 @@ func (s *store) set(v int) {
|
||||
keep = append(keep, point)
|
||||
}
|
||||
}
|
||||
if len(keep) > maxHistoryPoints {
|
||||
keep = keep[len(keep)-maxHistoryPoints:]
|
||||
}
|
||||
s.history = keep
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *store) snapshot() (int, time.Time, []sample) {
|
||||
@@ -63,6 +72,7 @@ func (s *store) snapshot() (int, time.Time, []sample) {
|
||||
func main() {
|
||||
secret := os.Getenv("WRITE_SECRET")
|
||||
addr := os.Getenv("ADDR")
|
||||
chartMax := 0
|
||||
if cfg, err := loadConfig("config.json"); err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
log.Fatalf("load config: %v", err)
|
||||
@@ -74,6 +84,9 @@ func main() {
|
||||
if addr == "" {
|
||||
addr = cfg.Addr
|
||||
}
|
||||
if cfg.ChartMaxWatts > 0 {
|
||||
chartMax = cfg.ChartMaxWatts
|
||||
}
|
||||
}
|
||||
if secret == "" {
|
||||
log.Fatal("WRITE_SECRET is required")
|
||||
@@ -83,8 +96,9 @@ func main() {
|
||||
}
|
||||
|
||||
app := &server{
|
||||
secret: secret,
|
||||
store: &store{},
|
||||
secret: secret,
|
||||
chartMax: chartMax,
|
||||
store: &store{},
|
||||
}
|
||||
|
||||
log.Printf("listening on %s", addr)
|
||||
@@ -92,13 +106,15 @@ func main() {
|
||||
}
|
||||
|
||||
type server struct {
|
||||
secret string
|
||||
store *store
|
||||
secret string
|
||||
chartMax int
|
||||
store *store
|
||||
}
|
||||
|
||||
type config struct {
|
||||
WriteSecret string `json:"write_secret"`
|
||||
Addr string `json:"addr"`
|
||||
WriteSecret string `json:"write_secret"`
|
||||
Addr string `json:"addr"`
|
||||
ChartMaxWatts int `json:"chart_max_watts"`
|
||||
}
|
||||
|
||||
func loadConfig(path string) (config, error) {
|
||||
@@ -143,17 +159,17 @@ func (s *server) handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||
if err := page.Execute(w, map[string]any{
|
||||
"Watts": watts,
|
||||
"UpdatedAt": updatedLabel,
|
||||
"HistoryChart": buildHistoryChart(history),
|
||||
"HistoryChart": buildHistoryChart(history, s.chartMax),
|
||||
}); err != nil {
|
||||
http.Error(w, "render error", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func buildHistoryChart(history []sample) template.HTML {
|
||||
func buildHistoryChart(history []sample, maxWatts int) template.HTML {
|
||||
const (
|
||||
width = 640
|
||||
height = 220
|
||||
padL = 52
|
||||
padL = 72
|
||||
padR = 18
|
||||
padT = 18
|
||||
padB = 42
|
||||
@@ -164,10 +180,13 @@ func buildHistoryChart(history []sample) template.HTML {
|
||||
}
|
||||
|
||||
minV, maxV := 0, history[0].value
|
||||
if maxWatts > 0 {
|
||||
maxV = maxWatts
|
||||
}
|
||||
start := history[0].at
|
||||
end := history[len(history)-1].at
|
||||
for _, point := range history[1:] {
|
||||
if point.value > maxV {
|
||||
if maxWatts <= 0 && point.value > maxV {
|
||||
maxV = point.value
|
||||
}
|
||||
if point.at.Before(start) {
|
||||
@@ -193,6 +212,12 @@ func buildHistoryChart(history []sample) template.HTML {
|
||||
for _, point := range history {
|
||||
x := float64(padL) + plotW*point.at.Sub(start).Seconds()/span.Seconds()
|
||||
y := float64(height-padB) - plotH*(float64(point.value-minV)/float64(maxV-minV))
|
||||
if y < float64(padT) {
|
||||
y = float64(padT)
|
||||
}
|
||||
if y > float64(height-padB) {
|
||||
y = float64(height - padB)
|
||||
}
|
||||
points = append(points, fmt.Sprintf("%.1f,%.1f", x, y))
|
||||
lastX, lastY = x, y
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user