master
go 112 lines 2.29 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 //go:build linux
4
5 package w1sensor
6
7 import (
8 "bufio"
9 "errors"
10 "fmt"
11 "io/fs"
12 "os"
13 "path/filepath"
14 "strconv"
15 "strings"
16 )
17
18 const precision = 10
19
20 func (c *Collector) collect() (map[string]int64, error) {
21 des, err := os.ReadDir(c.SensorsPath)
22 if err != nil {
23 return nil, err
24 }
25
26 mx := make(map[string]int64)
27 seen := make(map[string]bool)
28
29 for _, de := range des {
30 if !de.IsDir() {
31 continue
32 }
33 if !isW1sensorDir(de.Name()) {
34 c.Debugf("'%s' is not a w1sensor directory, skipping it", filepath.Join(c.SensorsPath, de.Name()))
35 continue
36 }
37
38 filename := filepath.Join(c.SensorsPath, de.Name(), "w1_slave")
39
40 temp, err := readW1sensorTemperature(filename)
41 if err != nil {
42 if errors.Is(err, fs.ErrNotExist) {
43 c.Debugf("'%s' doesn't have 'w1_slave', skipping it", filepath.Join(c.SensorsPath, de.Name()))
44 continue
45 }
46 return nil, fmt.Errorf("failed to read temperature from '%s': %w", filename, err)
47 }
48
49 seen[de.Name()] = true
50 if !c.seenSensors[de.Name()] {
51 c.addSensorChart(de.Name())
52
53 }
54
55 mx[fmt.Sprintf("w1sensor_%s_temperature", de.Name())] = temp
56 }
57
58 for id := range c.seenSensors {
59 if !seen[id] {
60 delete(c.seenSensors, id)
61 c.removeSensorChart(id)
62 }
63 }
64
65 if len(mx) == 0 {
66 return nil, errors.New("no w1 sensors found")
67 }
68
69 return mx, nil
70 }
71
72 func readW1sensorTemperature(filename string) (int64, error) {
73 file, err := os.Open(filename)
74 if err != nil {
75 return 0, err
76 }
77 defer func() { _ = file.Close() }()
78
79 sc := bufio.NewScanner(file)
80 sc.Scan()
81 // The second line displays the retained values along with a temperature in milli degrees Centigrade after t=.
82 sc.Scan()
83
84 _, tempStr, ok := strings.Cut(strings.TrimSpace(sc.Text()), "t=")
85 if !ok {
86 return 0, errors.New("no temperature found")
87 }
88
89 v, err := strconv.ParseInt(tempStr, 10, 64)
90 if err != nil {
91 return 0, err
92 }
93
94 return int64(float64(v) / 1000 * precision), nil
95 }
96
97 func isW1sensorDir(dirName string) bool {
98 // Supported family members
99 // Based on linux/drivers/w1/w1_family.h and w1/slaves/w1_therm.c
100 for _, px := range []string{
101 "10-", // W1_THERM_DS18S20
102 "22-", // W1_THERM_DS1822
103 "28-", // W1_THERM_DS18B20
104 "3b-", // W1_THERM_DS1825
105 "42-", // W1_THERM_DS28EA00
106 } {
107 if strings.HasPrefix(dirName, px) {
108 return true
109 }
110 }
111 return false
112 }