summaryrefslogtreecommitdiffstats
path: root/src/go/plugin/go.d/modules/sensors/collect.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/go/plugin/go.d/modules/sensors/collect.go')
-rw-r--r--src/go/plugin/go.d/modules/sensors/collect.go179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/go/plugin/go.d/modules/sensors/collect.go b/src/go/plugin/go.d/modules/sensors/collect.go
new file mode 100644
index 000000000..46e900ad0
--- /dev/null
+++ b/src/go/plugin/go.d/modules/sensors/collect.go
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package sensors
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+type sensorStats struct {
+ chip string
+ feature string
+ subfeature string
+ value string
+}
+
+func (s *sensorStats) String() string {
+ return fmt.Sprintf("chip:%s feat:%s subfeat:%s value:%s", s.chip, s.feature, s.subfeature, s.value)
+}
+
+const (
+ sensorTypeTemp = "temperature"
+ sensorTypeVoltage = "voltage"
+ sensorTypePower = "power"
+ sensorTypeHumidity = "humidity"
+ sensorTypeFan = "fan"
+ sensorTypeCurrent = "current"
+ sensorTypeEnergy = "energy"
+)
+
+const precision = 1000
+
+func (s *Sensors) collect() (map[string]int64, error) {
+ bs, err := s.exec.sensorsInfo()
+ if err != nil {
+ return nil, err
+ }
+
+ if len(bs) == 0 {
+ return nil, errors.New("empty response from sensors")
+ }
+
+ sensors, err := parseSensors(bs)
+ if err != nil {
+ return nil, err
+ }
+ if len(sensors) == 0 {
+ return nil, errors.New("no sensors found")
+ }
+
+ mx := make(map[string]int64)
+ seen := make(map[string]bool)
+
+ for _, sn := range sensors {
+ // TODO: Most likely we need different values depending on the type of sensor.
+ if !strings.HasSuffix(sn.subfeature, "_input") {
+ s.Debugf("skipping non input sensor: '%s'", sn)
+ continue
+ }
+
+ v, err := strconv.ParseFloat(sn.value, 64)
+ if err != nil {
+ s.Debugf("parsing value for sensor '%s': %v", sn, err)
+ continue
+ }
+
+ if sensorType(sn) == "" {
+ s.Debugf("can not find type for sensor '%s'", sn)
+ continue
+ }
+
+ if minVal, maxVal, ok := sensorLimits(sn); ok && (v < minVal || v > maxVal) {
+ s.Debugf("value outside limits [%d/%d] for sensor '%s'", int64(minVal), int64(maxVal), sn)
+ continue
+ }
+
+ key := fmt.Sprintf("sensor_chip_%s_feature_%s_subfeature_%s", sn.chip, sn.feature, sn.subfeature)
+ key = snakeCase(key)
+ if !s.sensors[key] {
+ s.sensors[key] = true
+ s.addSensorChart(sn)
+ }
+
+ seen[key] = true
+
+ mx[key] = int64(v * precision)
+ }
+
+ for k := range s.sensors {
+ if !seen[k] {
+ delete(s.sensors, k)
+ s.removeSensorChart(k)
+ }
+ }
+
+ return mx, nil
+}
+
+func snakeCase(n string) string {
+ return strings.ToLower(strings.ReplaceAll(n, " ", "_"))
+}
+
+func sensorLimits(sn sensorStats) (minVal float64, maxVal float64, ok bool) {
+ switch sensorType(sn) {
+ case sensorTypeTemp:
+ return -127, 1000, true
+ case sensorTypeVoltage:
+ return -400, 400, true
+ case sensorTypeCurrent:
+ return -127, 127, true
+ case sensorTypeFan:
+ return 0, 65535, true
+ default:
+ return 0, 0, false
+ }
+}
+
+func sensorType(sn sensorStats) string {
+ switch {
+ case strings.HasPrefix(sn.subfeature, "temp"):
+ return sensorTypeTemp
+ case strings.HasPrefix(sn.subfeature, "in"):
+ return sensorTypeVoltage
+ case strings.HasPrefix(sn.subfeature, "power"):
+ return sensorTypePower
+ case strings.HasPrefix(sn.subfeature, "humidity"):
+ return sensorTypeHumidity
+ case strings.HasPrefix(sn.subfeature, "fan"):
+ return sensorTypeFan
+ case strings.HasPrefix(sn.subfeature, "curr"):
+ return sensorTypeCurrent
+ case strings.HasPrefix(sn.subfeature, "energy"):
+ return sensorTypeEnergy
+ default:
+ return ""
+ }
+}
+
+func parseSensors(output []byte) ([]sensorStats, error) {
+ var sensors []sensorStats
+
+ sc := bufio.NewScanner(bytes.NewReader(output))
+
+ var chip, feat string
+
+ for sc.Scan() {
+ text := sc.Text()
+ if text == "" {
+ chip, feat = "", ""
+ continue
+ }
+
+ switch {
+ case strings.HasPrefix(text, " ") && chip != "" && feat != "":
+ parts := strings.Split(text, ":")
+ if len(parts) != 2 {
+ continue
+ }
+ subfeat, value := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])
+ sensors = append(sensors, sensorStats{
+ chip: chip,
+ feature: feat,
+ subfeature: subfeat,
+ value: value,
+ })
+ case strings.HasSuffix(text, ":") && chip != "":
+ feat = strings.TrimSpace(strings.TrimSuffix(text, ":"))
+ default:
+ chip = text
+ feat = ""
+ }
+ }
+
+ return sensors, nil
+}