/
temperature_probe.go
161 lines (142 loc) · 3.94 KB
/
temperature_probe.go
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package hardware
import (
"encoding/binary"
"encoding/hex"
"fmt"
"strconv"
"time"
"github.com/rs/zerolog/log"
"periph.io/x/periph/conn/onewire"
"periph.io/x/periph/conn/physic"
"periph.io/x/periph/devices/ds18b20"
"periph.io/x/periph/experimental/host/netlink"
)
var probes = make(map[string]*TemperatureProbe)
// TemperatureProbe holds data that represents a physical temperature probe
// PhysAddr -> The Hex address of the probe on the filesystem
// Address -> The unsigned int value for the readings
// Reading -> The actual reading as a Physic.Temperature
type TemperatureProbe struct {
PhysAddr string
Address onewire.Address
ReadingRaw physic.Temperature
Updated time.Time
}
// UpdateTemperature Set the temperature on the Temperature Probe from a string
func (t *TemperatureProbe) UpdateTemperature(newTemp string) error {
return t.ReadingRaw.Set(newTemp)
}
// Reading The current temperature reading for the probe
func (t *TemperatureProbe) Reading() string {
if t == nil {
return ""
}
return t.ReadingRaw.String()
}
// GetTemperature -> Get the probe object for a physical address
func GetTemperature(physAddr string) *TemperatureProbe {
return probes[physAddr]
}
// GetProbes -> Get all the probes
func GetProbes() []*TemperatureProbe {
values := make([]*TemperatureProbe, len(probes))
i := 0
for _, v := range probes {
values[i] = v
i++
}
return values
}
// ReadAddresses -> Update the TemperatureProbes with the current value from the device
func ReadAddresses(oneBus *netlink.OneWire, messages *chan string) {
for _, probe := range probes {
defer func() {
if err := recover(); err != nil {
log.Error().Msgf("Error reading temperature for %v", probe.PhysAddr)
}
}()
// init ds18b20
sensor, _ := ds18b20.New(oneBus, probe.Address, 10)
err := ds18b20.ConvertAll(oneBus, 10)
if err != nil {
log.Error().Err(err).Msgf("Failed to update probe %v", probe.PhysAddr)
continue
}
temp, err := sensor.LastTemp()
if err != nil {
log.Error().Err(err).Msgf("Failed to get the last temp for %v", probe.PhysAddr)
continue
}
probe := probes[probe.PhysAddr]
probe.Updated = time.Now()
probe.ReadingRaw = temp
if messages != nil {
*messages <- fmt.Sprintf("Reading device %v: %v", probe.PhysAddr, temp)
}
}
}
// ReadTemperatures Read the temperatures on an infinite ticker loop
func ReadTemperatures(m *chan string, quit chan struct{}) {
if m != nil {
defer close(*m)
}
log.Info().Msgf("Reading temps.")
oneBus, err := netlink.New(001)
if err != nil {
log.Printf("Could not open Netlink host: %v", err)
}
defer oneBus.Close()
// get 1wire address
addresses, _ := oneBus.Search(false)
log.Info().Msgf("Reading temps from %v devices.", len(addresses))
for _, address := range addresses {
a := strconv.FormatUint(uint64(address), 16)
for len(a) < 16 {
// O(n²) but since digits is expected to run for a few loops, it doesn't
// matter.
a = "0" + a
}
addrBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(addrBytes, uint64(address))
physAddr := "" + hex.EncodeToString(addrBytes[0:1]) + "-" + hex.EncodeToString(reverse(addrBytes[1:7]))
log.Info().Msgf("Found %v", physAddr)
probes[physAddr] = &TemperatureProbe{
PhysAddr: physAddr,
Address: address,
}
}
duration, err := time.ParseDuration("5s")
if err != nil {
log.Fatal().Err(err)
}
ticker := time.NewTicker(duration)
for {
select {
case <-ticker.C:
ReadAddresses(oneBus, m)
case <-quit:
ticker.Stop()
log.Info().Msg("Stop")
return
}
}
}
// LogTemperatures -> Write the Temperatures to standard output
func LogTemperatures(messages chan string) {
for {
for message := range messages {
log.Info().Msg(message)
}
}
}
// SetProbe -> Used to set a probe in the master list
func SetProbe(probe *TemperatureProbe) {
probes[probe.PhysAddr] = probe
}
func reverse(arr []byte) []byte {
for i := 0; i < len(arr)/2; i++ {
j := len(arr) - i - 1
arr[i], arr[j] = arr[j], arr[i]
}
return arr
}