From 3ec6fd1d1bed8a09769fe55f89692a997aa6c7cc Mon Sep 17 00:00:00 2001
From: Serge Bazanski
Date: Sat, 28 Sep 2024 07:49:03 +0200
Subject: [PATCH] succd: unify html/js data source
---
succbone/succd/http.go | 142 +++++++++++++++++++++++---------------
succbone/succd/index.html | 57 +++++++--------
2 files changed, 118 insertions(+), 81 deletions(-)
diff --git a/succbone/succd/http.go b/succbone/succd/http.go
index fd39c87..d32d274 100644
--- a/succbone/succd/http.go
+++ b/succbone/succd/http.go
@@ -50,6 +50,90 @@ func formatMbar(v float32) template.HTML {
return template.HTML(res)
}
+// apiData is the data model served to the user via HTTP/WebSockets
+type apiData struct {
+ // Safety interlocks.
+ Safety struct {
+ // Failsafe mode enabled - pirani gauge seems disconnected.
+ Failsafe bool
+ // HighPressure interlock enabled - pressure too high to run diffusion
+ // pump.
+ HighPressure bool
+ }
+ // Pirani gauge data.
+ Pirani struct {
+ // Volts read from the gauge (0-10).
+ Volts string
+ // Mbar read from the gauge, formatted as HTML.
+ Mbar template.HTML
+ // MbarFloat read from the gauge.
+ MbarFloat float32
+ }
+ // Pump state.
+ Pumps struct {
+ // RPOn means the roughing pump is turned on.
+ RPOn bool
+ // DPOn means the diffusion pump is turned on.
+ DPOn bool
+ }
+ // Pressure feedback into evacuation board.
+ Feedback struct {
+ // RoughReached is true when the system has reached a rough vacuum
+ // stage.
+ RoughReached bool
+ // HighReached is true when the system has reached a high vacuum stage.
+ HighReached bool
+ }
+ // System junk.
+ System struct {
+ // Load of the system.
+ Load string
+ // Hostname of the system.
+ Hostname string
+ }
+}
+
+// apiData returns the user data model for the current state of the system. If
+// skipSystem is set, the System subset is ignored (saves system load, and is
+// not being served via websockets).
+func (d *daemon) apiData(skipSystem bool) *apiData {
+ volts, mbar := d.pirani()
+ rp := d.rpGet()
+ dp := d.dpGet()
+ rough, high := d.vacuumStatusGet()
+ safety := d.safetyStatusGet()
+
+ var hostname, load string
+ var err error
+
+ if !skipSystem {
+ hostname, err = os.Hostname()
+ if err != nil {
+ hostname = "unknown"
+ }
+ loadB, err := os.ReadFile("/proc/loadavg")
+ load = "unknown"
+ if err == nil {
+ parts := strings.Fields(string(loadB))
+ load = strings.Join(parts[:3], " ")
+ }
+ }
+
+ ad := apiData{}
+ ad.Safety.Failsafe = safety.failsafe
+ ad.Safety.HighPressure = safety.highPressure
+ ad.Pirani.Volts = formatVolts(volts)
+ ad.Pirani.Mbar = formatMbar(mbar)
+ ad.Pirani.MbarFloat = mbar
+ ad.Pumps.RPOn = rp
+ ad.Pumps.DPOn = dp
+ ad.Feedback.RoughReached = rough
+ ad.Feedback.HighReached = high
+ ad.System.Load = load
+ ad.System.Hostname = hostname
+ return &ad
+}
+
// httpIndex is the / view.
func (d *daemon) httpIndex(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
@@ -57,33 +141,9 @@ func (d *daemon) httpIndex(w http.ResponseWriter, r *http.Request) {
return
}
- volts, mbar := d.pirani()
- rp := d.rpGet()
- dp := d.dpGet()
- safety := d.safetyStatusGet()
-
- loadB, err := os.ReadFile("/proc/loadavg")
- load := "unknown"
- if err == nil {
- parts := strings.Fields(string(loadB))
- load = strings.Join(parts[:3], " ")
- }
-
- hostname, err := os.Hostname()
- if err != nil {
- hostname = "unknown"
- }
-
- templateIndex.Execute(w, map[string]any{
- "failsafe": safety.failsafe,
- "highpressure": safety.highPressure,
- "volts": formatVolts(volts),
- "mbar": formatMbar(mbar),
- "rp": rp,
- "dp": dp,
- "hostname": hostname,
- "load": load,
- })
+ data := d.apiData(false)
+ //data.Pirani.Mbar = html.St
+ templateIndex.Execute(w, data)
}
// httpStream is the websocket clientwards data hose, returning a 10Hz update
@@ -105,33 +165,7 @@ func (d *daemon) httpStream(w http.ResponseWriter, r *http.Request) {
c.Close(websocket.StatusNormalClosure, "")
return
case <-t.C:
- // TODO(q3k): don't poll, get notified when new ADC readout is available.
- volts, mbar := d.pirani()
- rp := d.rpGet()
- dp := d.dpGet()
- rough, high := d.vacuumStatusGet()
- safety := d.safetyStatusGet()
- v := struct {
- Failsafe bool
- HighPressure bool
- Volts string
- Mbar string
- MbarFloat float32
- RPOn bool
- DPOn bool
- RoughReached bool
- HighReached bool
- }{
- Failsafe: safety.failsafe,
- HighPressure: safety.highPressure,
- Volts: formatVolts(volts),
- Mbar: string(formatMbar(mbar)),
- MbarFloat: mbar,
- RPOn: rp,
- DPOn: dp,
- RoughReached: rough,
- HighReached: high,
- }
+ v := d.apiData(true)
if err := wsjson.Write(ctx, c, v); err != nil {
klog.Errorf("Websocket write failed: %v", err)
return
diff --git a/succbone/succd/index.html b/succbone/succd/index.html
index 4d758be..e12c73a 100644
--- a/succbone/succd/index.html
+++ b/succbone/succd/index.html
@@ -59,25 +59,25 @@ td > span {
Voltage |
- {{.volts}} |
+ {{ .Pirani.Volts }} |
Pressure |
- {{.mbar}} |
+ {{ .Pirani.Mbar }} |
Thresholds |
Rough: |
- ... |
+ {{ if .Feedback.RoughReached }}OK{{ else }}NOK{{ end }} |
High: |
- ... |
+ {{ if .Feedback.HighReached }}OK{{ else }}NOK{{ end }} |
Pumps |
RP: |
- {{ if .rp }}ON{{ else }}OFF{{ end }} |
+ {{ if .Pumps.RPOn }}ON{{ else }}OFF{{ end }} |
DP: |
- {{ if .dp }}ON{{ else }}OFF{{ end }} |
+ {{ if .Pumps.DPOn }}ON{{ else }}OFF{{ end }} |
Evac Control |
@@ -96,11 +96,11 @@ td > span {
Failsafe |
- OK |
+ {{ if .Safety.Failsafe }}ON{{ else }}OFF{{ end }} |
Diffusion Pump Lockout |
- OK |
+ {{ if .Safety.HighPressure }}ON{{ else }}OFF{{ end }} |
@@ -109,7 +109,7 @@ td > span {
- {{.hostname}} | load: {{.load}} | pprof | metrics | ws ping: …
+ {{ .System.Hostname }} | load: {{ .System.Load }} | pprof | metrics | ws ping: …