succd: unify html/js data source

This commit is contained in:
Serge Bazanski 2024-09-28 07:49:03 +02:00
parent 776f7a9911
commit 3ec6fd1d1b
2 changed files with 118 additions and 81 deletions

View file

@ -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