I3status-rust: Temperature block returning errors

Created on 3 Sep 2020  ·  13Comments  ·  Source: greshake/i3status-rust

Hello,
I think one of the latest commits introduced a regression in the temperature block, which is now returning an error on my system while unwrapping here: https://github.com/greshake/i3status-rust/blob/master/src/blocks/battery.rs#L364

Here is the output of running i3status-rs manually:

❯❯❯ i3status-rs ~/.config/i3/top.toml
{"version": 1, "click_events": true}
[[{"background":"#000000","color":"#dc322f","full_text":" Error in block 'temperature': sensors output is invalid ","separator":false,"separator_block_width":0}]


Error in block 'temperature': sensors output is invalid
thread 'battery' panicked at 'called `Result::unwrap()` on an `Err` value: "SendError(..)"', src/blocks/battery.rs:364:30
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

And here is my block config:

[[block]]                                                                                                                                                                                              
block = "temperature"
collapsed = false
interval = 10
good = 40
idle = 60
info = 80
warning = 90
chip = "*-isa-*"
format = "{average}°"

I am on Ubuntu bionic (18.04) and I have lm-sensors installed and working:

❯❯❯ sensors
coretemp-isa-0000
Adapter: ISA adapter
Package id 0:  +44.0°C  (high = +100.0°C, crit = +100.0°C)
Core 0:        +43.0°C  (high = +100.0°C, crit = +100.0°C)
Core 1:        +44.0°C  (high = +100.0°C, crit = +100.0°C)
Core 2:        +43.0°C  (high = +100.0°C, crit = +100.0°C)
Core 3:        +44.0°C  (high = +100.0°C, crit = +100.0°C)
wontfix

Most helpful comment

If anyone else have the same issue and cannot upgrade lm-sensors accordingly, here is a poor's man custom implementation:

[[block]]
block = "custom"
cycle = ["sensors |grep Package |awk '{print $4}' |sed 's#+##g' |sed 's#C##g'"]                                                                                                                        
interval = 10

It's ugly, but it does the job :)

All 13 comments

Looks like it's just the temperature block taking down the bar than a bug in the battery block. Try switching around the order of the blocks in your config to see if that is true.

Can you show me the output of sensors --help?

I have moved the block around in multiple places and I am getting the same issue..

Here is the output of sensors --help:

❯❯❯ sensors --help 
Usage: sensors [OPTION]... [CHIP]...
  -c, --config-file     Specify a config file
  -h, --help            Display this help text
  -s, --set             Execute `set' statements (root only)
  -f, --fahrenheit      Show temperatures in degrees fahrenheit
  -A, --no-adapter      Do not show adapter for each chip
      --bus-list        Generate bus statements for sensors.conf
  -u                    Raw output
  -v, --version         Display the program version

Use `-' after `-c' to read the config file from stdin.
If no chips are specified, all chip info will be printed.
Example chip names:
    lm78-i2c-0-2d   *-i2c-0-2d
    lm78-i2c-0-*    *-i2c-0-*
    lm78-i2c-*-2d   *-i2c-*-2d
    lm78-i2c-*-*    *-i2c-*-*
    lm78-isa-0290   *-isa-0290
    lm78-isa-*  *-isa-*
    lm78-*

❯❯❯  sensors --version
sensors version 3.4.0 with libsensors version 3.4.0

Also, I made a typo in the title, let me fix it. There is nothing wrong with the battery block as you said, it is the temperature one.

811 changed the command that is run by the temperature block. Unfortunately it looks like the version of the sensors command shipped with 18.04 is too old. Are you able to update to the latest LTS release?

Newer versions have the -j flag:

>sensors --help
Usage: sensors [OPTION]... [CHIP]...
  -c, --config-file     Specify a config file
  -h, --help            Display this help text
  -s, --set             Execute `set' statements (root only)
  -f, --fahrenheit      Show temperatures in degrees fahrenheit
  -A, --no-adapter      Do not show adapter for each chip
      --bus-list        Generate bus statements for sensors.conf
  -u                    Raw output
  -j                    Json output
  -v, --version         Display the program version

Use `-' after `-c' to read the config file from stdin.
If no chips are specified, all chip info will be printed.
Example chip names:
    lm78-i2c-0-2d   *-i2c-0-2d
    lm78-i2c-0-*    *-i2c-0-*
    lm78-i2c-*-2d   *-i2c-*-2d
    lm78-i2c-*-*    *-i2c-*-*
    lm78-isa-0290   *-isa-0290
    lm78-isa-*  *-isa-*
    lm78-*

>sensors --version
sensors version 3.6.0 with libsensors version 3.6.0

Unfortunately I am not able to update to lm-sensors 3.6 and libsensor5 as Bionic does not ship them and I cannot really go and upgrade to 20.04 now :(

https://launchpad.net/ubuntu/+source/lm-sensors

And I have the same issue with the weather block.. curl is too old on Bionic as well.

Unfortunately there's nothing we can really do here apart from ask you to upgrade :(

It has been years since I've used Ubuntu but would Backports allow you to install the newer versions of curl and lm-sensors on 18.04? https://help.ubuntu.com/community/UbuntuBackports

(I'll close the issue but feel free to continue discussion)

I'll try to find some time and see if I can update libsensors through backports. I have searched a bit but I did not find the package, but it was not a deep search.

Thanks for the help understanding why this is happening.

Just FYI, I can't find backported package and I believe the problem comes from the fact the lm-sensors 3.6 wants a new version of libc6, not available in Bionic.

If anyone else have the same issue and cannot upgrade lm-sensors accordingly, here is a poor's man custom implementation:

[[block]]
block = "custom"
cycle = ["sensors |grep Package |awk '{print $4}' |sed 's#+##g' |sed 's#C##g'"]                                                                                                                        
interval = 10

It's ugly, but it does the job :)

ugh, i'm also affected by this. it's not _too_ painful to revert 2f223d734, here's the approximate diff you want:

click to expand

diff --git a/src/blocks/temperature.rs b/src/blocks/temperature.rs
index c7f9eef39..892366b3b 100644
--- a/src/blocks/temperature.rs
+++ b/src/blocks/temperature.rs
@@ -1,4 +1,4 @@
-use std::collections::{BTreeMap, HashMap};
+use std::collections::BTreeMap;
 use std::process::Command;
 use std::time::Duration;

@@ -41,7 +41,6 @@ pub struct Temperature {
     maximum_warning: i64,
     format: FormatTemplate,
     chip: Option<String>,
-    inputs: Option<Vec<String>>,
 }

 #[derive(Deserialize, Debug, Default, Clone)]
@@ -169,17 +168,13 @@ impl ConfigBlock for Temperature {
             format: FormatTemplate::from_string(&block_config.format)
                 .block_error("temperature", "Invalid format specified for temperature")?,
             chip: block_config.chip,
-            inputs: block_config.inputs,
         })
     }
 }

-type SensorsOutput = HashMap<String, HashMap<String, serde_json::Value>>;
-type InputReadings = HashMap<String, f64>;
-
 impl Block for Temperature {
     fn update(&mut self) -> Result<Option<Update>> {
-        let mut args = vec!["-j"];
+        let mut args = vec!["-u"];
         if let TemperatureScale::Fahrenheit = self.scale {
             args.push("-f");
         }
@@ -192,34 +187,33 @@ impl Block for Temperature {
             .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_owned())
             .unwrap_or_else(|e| e.to_string());

-        let parsed: SensorsOutput = serde_json::from_str(&output)
-            .block_error("temperature", "sensors output is invalid")?;
-
         let mut temperatures: Vec<i64> = Vec::new();
-        for (_chip, inputs) in parsed {
-            for (input_name, input_values) in inputs {
-                if let Some(ref whitelist) = self.inputs {
-                    if !whitelist.contains(&input_name) {
-                        continue;
-                    }
-                }

-                let values_parsed: InputReadings = match serde_json::from_value(input_values) {
-                    Ok(values) => values,
-                    Err(_) => continue, // probably the "Adapter" key, just ignore.
-                };
+        for line in output.lines() {
+            if line.starts_with("  temp") {
+                let rest = &line[6..]
+                    .split('_')
+                    .flat_map(|x| x.split(' '))
+                    .flat_map(|x| x.split('.'))
+                    .collect::<Vec<_>>();

-                for (value_name, value) in values_parsed {
-                    if !value_name.starts_with("temp") || !value_name.ends_with("input") {
-                        continue;
-                    }
-
-                    if value > -101f64 && value < 151f64 {
-                        temperatures.push(value as i64);
-                    } else {
-                        // This error is recoverable and therefore should not stop the program
-                        eprintln!("Temperature ({}) outside of range ([-100, 150])", value);
-                    }
+                if rest[1].starts_with("input") {
+                    match rest[2].parse::<i64>() {
+                        Ok(t) if t == 0 => Ok(()),
+                        Ok(t) if t > -101 && t < 151 => {
+                            temperatures.push(t);
+                            Ok(())
+                        }
+                        Ok(t) => {
+                            // This error is recoverable and therefore should not stop the program
+                            eprintln!("Temperature ({}) outside of range ([-100, 150])", t);
+                            Ok(())
+                        }
+                        Err(_) => Err(BlockError(
+                            "temperature".to_owned(),
+                            "failed to parse temperature as an integer".to_owned(),
+                        )),
+                    }?
                 }
             }
         }

Hmm on second look we can do better here. First check whether the system's sensors command has the json flag, and if not fall back to the old method. The only caveat is that the "inputs" config option will have no effect since implementing that doesn't look trivial.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

YodaEmbedding picture YodaEmbedding  ·  4Comments

Rikorose picture Rikorose  ·  5Comments

ammgws picture ammgws  ·  6Comments

michaelmrose picture michaelmrose  ·  4Comments

oschoudhury picture oschoudhury  ·  6Comments