-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcylinder.go
More file actions
140 lines (120 loc) · 3.26 KB
/
Copy pathcylinder.go
File metadata and controls
140 lines (120 loc) · 3.26 KB
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
package main
import (
"context"
"encoding/json"
"io"
"log"
"math"
"os"
"sync"
"github.com/fsnotify/fsnotify"
)
// The purpose of this file is to store the base weight (tare)
// and full weight of the propane cylinder. The empty/full
// weight is used to calculate the percentage remaining as
// read from the scale
const cylinderFile = "cylinder.json"
type Cylinder struct {
TareWeight float64 `json:"tareweight"`
FullWeight float64 `json:"fullweight"`
// This is to take into consideration
// additional weight on the scale, like
// the regulator, hose, and safety chain
ExtraWeight float64 `json:"extraweight"`
}
var (
cylinder Cylinder
cylinderMu sync.RWMutex
)
func LoadCylinderData() {
log.Println("Loading current cylinder info")
jsonFile, err := os.Open(cylinderFile)
if err != nil {
log.Println(err)
return
}
defer jsonFile.Close()
byteValue, err := io.ReadAll(jsonFile)
if err != nil {
log.Printf("Failed to read cylinder data: %s\n", err)
return
}
var c Cylinder
if err := json.Unmarshal(byteValue, &c); err != nil {
log.Printf("Failed to parse cylinder data: %s\n", err)
return
}
cylinderMu.Lock()
cylinder = c
cylinderMu.Unlock()
}
// GetCylinderData returns a copy of the currently loaded cylinder settings
func GetCylinderData() Cylinder {
cylinderMu.RLock()
defer cylinderMu.RUnlock()
return cylinder
}
// SaveCylinderData writes the given cylinder settings to cylinder.json and
// updates the in-memory copy used for calculations
func SaveCylinderData(c Cylinder) error {
data, err := json.MarshalIndent(c, "", " ")
if err != nil {
return err
}
if err := os.WriteFile(cylinderFile, data, 0644); err != nil {
return err
}
cylinderMu.Lock()
cylinder = c
cylinderMu.Unlock()
return nil
}
// WatchCylinderData watches cylinder.json on disk and reloads it into memory
// whenever it changes, so edits made outside the web page (or by the web
// page's handler writing the file directly) are picked up automatically.
func WatchCylinderData(ctx context.Context) func() error {
return func() error {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return err
}
defer watcher.Close()
if err := watcher.Add(cylinderFile); err != nil {
return err
}
for {
select {
case <-ctx.Done():
return nil
case event, ok := <-watcher.Events:
if !ok {
return nil
}
if event.Has(fsnotify.Write) || event.Has(fsnotify.Create) {
LoadCylinderData()
}
// Some editors/writers replace the file instead of writing
// in place, which drops the watch and needs it re-added.
if event.Has(fsnotify.Remove) || event.Has(fsnotify.Rename) {
_ = watcher.Add(cylinderFile)
LoadCylinderData()
}
case err, ok := <-watcher.Errors:
if !ok {
return nil
}
log.Printf("cylinder.json watcher error: %v", err)
}
}
}
}
// Gives us the percentage remaining for the given weight, taking into
// consideration the full and tare weight of the cylinder, plus any extra
// weight that might be on the scale
func (c Cylinder) CalcRemaining(currentWeight float64) float64 {
cur := GetCylinderData()
base := cur.FullWeight - cur.TareWeight + cur.ExtraWeight
adjusted := currentWeight - cur.TareWeight + cur.ExtraWeight
delta := math.Round((adjusted / base) * 100)
return delta
}