All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oshi.hardware.platform.linux.LinuxSensors Maven / Gradle / Ivy

There is a newer version: 4.15.102
Show newest version
/**
 * MIT License
 *
 * Copyright (c) 2010 - 2020 The OSHI Project Contributors: https://github.com/oshi/oshi/graphs/contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package oshi.hardware.platform.linux;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import oshi.annotation.concurrent.ThreadSafe;
import oshi.hardware.common.AbstractSensors;
import oshi.util.ExecutingCommand;
import oshi.util.FileUtil;
import oshi.util.ParseUtil;

/**
 * Sensors from WMI or Open Hardware Monitor
 */
@ThreadSafe
final class LinuxSensors extends AbstractSensors {

    // Possible sensor types. See sysfs documentation for others, e.g. current
    private static final String TEMP = "temp";
    private static final String FAN = "fan";
    private static final String VOLTAGE = "in";
    private static final String[] SENSORS = { TEMP, FAN, VOLTAGE };

    // Base HWMON path, adds 0, 1, etc. to end for various sensors
    private static final String HWMON = "hwmon";
    private static final String HWMON_PATH = "/sys/class/hwmon/" + HWMON;
    // Base THERMAL_ZONE path, adds 0, 1, etc. to end for temperature sensors
    private static final String THERMAL_ZONE = "thermal_zone";
    private static final String THERMAL_ZONE_PATH = "/sys/class/thermal/" + THERMAL_ZONE;

    // Initial test to see if we are running on a Pi
    private static final boolean IS_PI = queryCpuTemperatureFromVcGenCmd() > 0;

    // Map from sensor to path. Built by constructor, so thread safe
    private final Map sensorsMap = new HashMap<>();

    /**
     * 

* Constructor for LinuxSensors. *

*/ LinuxSensors() { if (!IS_PI) { populateSensorsMapFromHwmon(); // if no temperature sensor is found in hwmon, try thermal_zone if (!this.sensorsMap.containsKey(TEMP)) { populateSensorsMapFromThermalZone(); } } } /* * Iterate over all hwmon* directories and look for sensor files, e.g., * /sys/class/hwmon/hwmon0/temp1_input */ private void populateSensorsMapFromHwmon() { for (String sensor : SENSORS) { // Final to pass to anonymous class final String sensorPrefix = sensor; // Find any *_input files in that path getSensorFilesFromPath(HWMON_PATH, sensor, f -> { try { return f.getName().startsWith(sensorPrefix) && f.getName().endsWith("_input") && FileUtil.getIntFromFile(f.getCanonicalPath()) > 0; } catch (IOException e) { return false; } }); } } /* * Iterate over all thermal_zone* directories and look for sensor files, e.g., * /sys/class/thermal/thermal_zone0/temp */ private void populateSensorsMapFromThermalZone() { getSensorFilesFromPath(THERMAL_ZONE_PATH, TEMP, f -> f.getName().equals(TEMP)); } /** * Find all sensor files in a specific path and adds them to the hwmonMap * * @param sensorPath * A string containing the sensor path * @param sensor * A string containing the sensor * @param sensorFileFilter * A FileFilter for detecting valid sensor files */ private void getSensorFilesFromPath(String sensorPath, String sensor, FileFilter sensorFileFilter) { int i = 0; while (Paths.get(sensorPath + i).toFile().isDirectory()) { String path = sensorPath + i; File dir = new File(path); File[] matchingFiles = dir.listFiles(sensorFileFilter); if (matchingFiles != null && matchingFiles.length > 0) { this.sensorsMap.put(sensor, String.format("%s/%s", path, sensor)); } i++; } } @Override public double queryCpuTemperature() { if (IS_PI) { return queryCpuTemperatureFromVcGenCmd(); } String tempStr = this.sensorsMap.get(TEMP); if (tempStr != null) { long millidegrees = 0; if (tempStr.contains(HWMON)) { // First attempt should be CPU temperature at index 1, if available millidegrees = FileUtil.getLongFromFile(String.format("%s1_input", tempStr)); // Should return a single line of millidegrees Celsius if (millidegrees > 0) { return millidegrees / 1000d; } // If temp1_input doesn't exist, iterate over temp2..temp6_input // and average long sum = 0; int count = 0; for (int i = 2; i <= 6; i++) { millidegrees = FileUtil.getLongFromFile(String.format("%s%d_input", tempStr, i)); if (millidegrees > 0) { sum += millidegrees; count++; } } if (count > 0) { return sum / (count * 1000d); } } else if (tempStr.contains(THERMAL_ZONE)) { // If temp2..temp6_input doesn't exist, try thermal_zone0 millidegrees = FileUtil.getLongFromFile(tempStr); // Should return a single line of millidegrees Celsius if (millidegrees > 0) { return millidegrees / 1000d; } } } return 0d; } /** * Retrieves temperature from Raspberry Pi * * @return The temperature on a Pi, 0 otherwise */ private static double queryCpuTemperatureFromVcGenCmd() { String tempStr = ExecutingCommand.getFirstAnswer("vcgencmd measure_temp"); // temp=50.8'C if (tempStr.startsWith("temp=") && tempStr.endsWith("'C")) { return ParseUtil.parseDoubleOrDefault(tempStr.replaceAll("\\^[0-9]+(\\.[0-9]{1,4})?$", ""), 0d); } return 0d; } @Override public int[] queryFanSpeeds() { if (!IS_PI) { String fanStr = this.sensorsMap.get(FAN); if (fanStr != null) { List speeds = new ArrayList<>(); int fan = 1; for (;;) { String fanPath = String.format("%s%d_input", fanStr, fan); if (!new File(fanPath).exists()) { // No file found, we've reached max fans break; } // Should return a single line of RPM speeds.add(FileUtil.getIntFromFile(fanPath)); // Done reading data for current fan, read next fan fan++; } int[] fanSpeeds = new int[speeds.size()]; for (int i = 0; i < speeds.size(); i++) { fanSpeeds[i] = speeds.get(i); } return fanSpeeds; } } return new int[0]; } @Override public double queryCpuVoltage() { if (IS_PI) { return queryCpuVoltageFromVcGenCmd(); } String voltageStr = this.sensorsMap.get(VOLTAGE); if (voltageStr != null) { // Should return a single line of millivolt return FileUtil.getIntFromFile(String.format("%s1_input", voltageStr)) / 1000d; } return 0d; } /** * Retrieves voltage from Raspberry Pi * * @return The temperature on a Pi, 0 otherwise */ private static double queryCpuVoltageFromVcGenCmd() { // For raspberry pi String voltageStr = ExecutingCommand.getFirstAnswer("vcgencmd measure_volts core"); // volt=1.20V if (voltageStr.startsWith("volt=") && voltageStr.endsWith("V")) { return ParseUtil.parseDoubleOrDefault(voltageStr.replaceAll("\\^[0-9]+(\\.[0-9]{1,4})?$", ""), 0d); } return 0d; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy