View Javadoc
1   /*
2    * Copyright 2021-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.hardware.platform.unix.openbsd;
6   
7   import static oshi.util.Memoizer.defaultExpiration;
8   import static oshi.util.Memoizer.memoize;
9   
10  import java.util.ArrayList;
11  import java.util.List;
12  import java.util.function.Supplier;
13  
14  import oshi.annotation.concurrent.ThreadSafe;
15  import oshi.hardware.common.AbstractSensors;
16  import oshi.util.ExecutingCommand;
17  import oshi.util.ParseUtil;
18  import oshi.util.tuples.Triplet;
19  
20  /**
21   * Sensors
22   */
23  @ThreadSafe
24  final class OpenBsdSensors extends AbstractSensors {
25  
26      private final Supplier<Triplet<Double, int[], Double>> tempFanVolts = memoize(OpenBsdSensors::querySensors,
27              defaultExpiration());
28  
29      @Override
30      public double queryCpuTemperature() {
31          return tempFanVolts.get().getA();
32      }
33  
34      @Override
35      public int[] queryFanSpeeds() {
36          return tempFanVolts.get().getB();
37      }
38  
39      @Override
40      public double queryCpuVoltage() {
41          return tempFanVolts.get().getC();
42      }
43  
44      private static Triplet<Double, int[], Double> querySensors() {
45          double volts = 0d;
46          List<Double> cpuTemps = new ArrayList<>();
47          List<Double> allTemps = new ArrayList<>();
48          List<Integer> fanRPMs = new ArrayList<>();
49          for (String line : ExecutingCommand.runNative("systat -ab sensors")) {
50              String[] split = ParseUtil.whitespaces.split(line);
51              if (split.length > 1) {
52                  if (split[0].contains("cpu")) {
53                      if (split[0].contains("temp0")) {
54                          cpuTemps.add(ParseUtil.parseDoubleOrDefault(split[1], Double.NaN));
55                      } else if (split[0].contains("volt0")) {
56                          volts = ParseUtil.parseDoubleOrDefault(split[1], 0d);
57                      }
58                  } else if (split[0].contains("temp0")) {
59                      allTemps.add(ParseUtil.parseDoubleOrDefault(split[1], Double.NaN));
60                  } else if (split[0].contains("fan")) {
61                      fanRPMs.add(ParseUtil.parseIntOrDefault(split[1], 0));
62                  }
63              }
64          }
65          // Prefer cpu temps
66          double temp = cpuTemps.isEmpty() ? listAverage(allTemps) : listAverage(cpuTemps);
67          // Collect all fans
68          int[] fans = new int[fanRPMs.size()];
69          for (int i = 0; i < fans.length; i++) {
70              fans[i] = fanRPMs.get(i);
71          }
72          return new Triplet<>(temp, fans, volts);
73      }
74  
75      private static double listAverage(List<Double> doubles) {
76          double sum = 0d;
77          int count = 0;
78          for (Double d : doubles) {
79              if (!d.isNaN()) {
80                  sum += d;
81                  count++;
82              }
83          }
84          return count > 0 ? sum / count : 0d;
85      }
86  }