git.haldean.org sousvide / 7c0c867
New chart backend working with raw SVG output. Needed to do this to allow for drawing when the heater is on/off in the graph. Will Haldean Brown 8 years ago
3 changed file(s) with 90 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
0 package main
1
2 import (
3 "github.com/ajstarks/svgo"
4 "math"
5 "net/http"
6 )
7
8 const (
9 ImgWidth = 600
10 ImgHeight = 400
11 )
12
13 func (s *SousVide) GenerateChart2(w http.ResponseWriter, r *http.Request) {
14 if len(s.History) == 0 {
15 w.WriteHeader(http.StatusNoContent)
16 return
17 }
18
19 N := len(s.History)
20
21 maxVal := float64(0)
22 for _, h := range s.History {
23 if h.Temp > maxVal {
24 maxVal = h.Temp
25 }
26 if h.Target > maxVal {
27 maxVal = h.Target
28 }
29 }
30 maxY := 10 * math.Ceil(maxVal / 10)
31 pxPerUnitY := float64(ImgHeight) / maxY
32
33 maxX := float64(N - 1)
34 pxPerUnitX := float64(ImgWidth) / maxX
35
36 w.Header().Set("Content-type", "image/svg+xml")
37 svgs := svg.New(w)
38 svgs.Start(imgWidth, imgHeight)
39 svgs.Title("Temperature history (\u00B0C)")
40
41 // draw "metadata": heating, etc.
42 if N > 1 {
43 for i, h := range s.History {
44 if h.Heating {
45 x0 := int(float64(i) * pxPerUnitX)
46 svgs.Rect(x0, 0, int(math.Ceil(pxPerUnitX)), ImgHeight,
47 "fill:#F0F0F0")
48 }
49 }
50 }
51
52 // draw grid before data so it's under everything
53 for i := 0; i <= ImgHeight; i += int(10 * pxPerUnitY) {
54 y := ImgHeight - i
55 svgs.Line(0, y, ImgWidth, y, "stroke:#DDD; stroke-width:1")
56 }
57
58 // draw data
59 if N > 1 {
60 lastX := int(0)
61 lastTempY := int(s.History[0].Temp * pxPerUnitY)
62 lastTargetY := int(s.History[0].Target * pxPerUnitY)
63 for i, h := range s.History[1:] {
64 x := int(float64(i + 1) * pxPerUnitX)
65 tempY := int(h.Temp * pxPerUnitY)
66 targetY := int(h.Target * pxPerUnitY)
67 svgs.Line(lastX, ImgHeight - lastTempY, x, ImgHeight - tempY,
68 "stroke:#FF0000; stroke-width:2")
69 svgs.Line(lastX, ImgHeight - lastTargetY, x, ImgHeight - targetY,
70 "stroke:#0000FF; stroke-width:2")
71 lastX = x
72 lastTempY = tempY
73 lastTargetY = targetY
74 }
75 }
76
77 // draw axes last so they're on top of everything else
78 svgs.Line(0, ImgHeight, ImgWidth, ImgHeight, "stroke:#000000; stroke-width:3")
79 svgs.Line(0, 0, 0, ImgHeight, "stroke:#000000; stroke-width:3")
80 svgs.Line(ImgWidth, 0, ImgWidth, ImgHeight, "stroke:#000000; stroke-width:3")
81
82 svgs.End()
83 }
8888 })
8989
9090 http.HandleFunc("/csv", s.DumpCsv)
91
92 http.HandleFunc("/plot", s.GenerateChart)
93
91 http.HandleFunc("/plot", s.GenerateChart2)
9492 http.Handle("/", http.FileServer(http.Dir("static/")))
95
9693 log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil))
9794 }
1212 )
1313
1414 const (
15 InterruptDelay = 3 * time.Second
15 InterruptDelay = 1 * time.Second
1616 LogFile = "runlog.txt"
1717 HistoryLength = 2048
1818 LowpassSamples = 2
2222 var StubGpio = flag.Bool("stub_gpio", false, "stub GPIO calls for testing")
2323 var FakeTemp = flag.Bool("fake_temp", false, "use fake temperature values")
2424 var PidFile = flag.String("pid_file", "pid.json", "file to save PID values in")
25 var StartEnabled = flag.Bool("enabled", false, "start with heater enabled")
26 var StartTarget = flag.Float64("target", 0, "initial target temperature, in C")
2527
2628 type SousVide struct {
2729 Heating bool
175177 s.SavePid()
176178 }
177179 s.Gpio.Stub = *StubGpio
180 s.Target = Celsius(*StartTarget)
181 s.Enabled = *StartEnabled
178182
179183 err = s.InitGpio()
180184 if err != nil {