firehol/netdata

View on GitHub
src/go/plugin/go.d/modules/w1sensor/collect.go

Summary

Maintainability
A
0 mins
Test Coverage
// SPDX-License-Identifier: GPL-3.0-or-later

package w1sensor

import (
    "bufio"
    "errors"
    "fmt"
    "io/fs"
    "os"
    "path/filepath"
    "strconv"
    "strings"
)

const precision = 10

func (w *W1sensor) collect() (map[string]int64, error) {
    des, err := os.ReadDir(w.SensorsPath)
    if err != nil {
        return nil, err
    }

    mx := make(map[string]int64)
    seen := make(map[string]bool)

    for _, de := range des {
        if !de.IsDir() {
            continue
        }
        if !isW1sensorDir(de.Name()) {
            w.Debugf("'%s' is not a w1sensor directory, skipping it", filepath.Join(w.SensorsPath, de.Name()))
            continue
        }

        filename := filepath.Join(w.SensorsPath, de.Name(), "w1_slave")

        temp, err := readW1sensorTemperature(filename)
        if err != nil {
            if errors.Is(err, fs.ErrNotExist) {
                w.Debugf("'%s' doesn't have 'w1_slave', skipping it", filepath.Join(w.SensorsPath, de.Name()))
                continue
            }
            return nil, fmt.Errorf("failed to read temperature from '%s': %w", filename, err)
        }

        seen[de.Name()] = true
        if !w.seenSensors[de.Name()] {
            w.addSensorChart(de.Name())

        }

        mx[fmt.Sprintf("w1sensor_%s_temperature", de.Name())] = temp
    }

    for id := range w.seenSensors {
        if !seen[id] {
            delete(w.seenSensors, id)
            w.removeSensorChart(id)
        }
    }

    if len(mx) == 0 {
        return nil, errors.New("no w1 sensors found")
    }

    return mx, nil
}

func readW1sensorTemperature(filename string) (int64, error) {
    file, err := os.Open(filename)
    if err != nil {
        return 0, err
    }
    defer func() { _ = file.Close() }()

    sc := bufio.NewScanner(file)
    sc.Scan()
    // The second line displays the retained values along with a temperature in milli degrees Centigrade after t=.
    sc.Scan()

    _, tempStr, ok := strings.Cut(strings.TrimSpace(sc.Text()), "t=")
    if !ok {
        return 0, errors.New("no temperature found")
    }

    v, err := strconv.ParseInt(tempStr, 10, 64)
    if err != nil {
        return 0, err
    }

    return int64(float64(v) / 1000 * precision), nil
}

func isW1sensorDir(dirName string) bool {
    // Supported family members
    // Based on linux/drivers/w1/w1_family.h and w1/slaves/w1_therm.c
    for _, px := range []string{
        "10-", // W1_THERM_DS18S20
        "22-", // W1_THERM_DS1822
        "28-", // W1_THERM_DS18B20
        "3b-", // W1_THERM_DS1825
        "42-", // W1_THERM_DS28EA00
    } {
        if strings.HasPrefix(dirName, px) {
            return true
        }
    }
    return false
}