refactor: sensor configuration fields

Automatically round decimal values for sensor.x and .y to an integer.
Make fields optional which are not used in every sensor.
This commit is contained in:
Markus Zehnder
2025-08-24 21:18:56 +02:00
parent 98941a00fe
commit 84455e9254
6 changed files with 50 additions and 62 deletions
-2
View File
@@ -53,7 +53,6 @@ The background image and sensor definitions are taken from the default system pa
"sensor": [
{
"mode": 1,
"type": 1,
"name": "CPU temp",
"label": "cpu_temperature",
"x": 195,
@@ -67,7 +66,6 @@ The background image and sensor definitions are taken from the default system pa
},
{
"mode": 1,
"type": 1,
"name": "CPU usage",
"label": "cpu_percent",
"unit": "%",
-5
View File
@@ -31,7 +31,6 @@ Example `panel.json` with a single "fan" indicator sensor and the following (par
"id": "29d9ef2d-30b4-459d-b2b0-43cb6d4d6b41",
"itemName": "CPU usage",
"mode": 2,
"type": 1,
"direction": 1,
"label": "cpu_percent",
"value": "47.7",
@@ -39,10 +38,6 @@ Example `panel.json` with a single "fan" indicator sensor and the following (par
"y": 184,
"width": 237,
"height": 237,
"fontColor": "#ffffff",
"fontSize": 14,
"fontFamily": "default_font",
"textAlign": "left",
"minAngle": -160,
"maxAngle": 30,
"minValue": 0,
-14
View File
@@ -25,41 +25,30 @@ The background image and sensor definitions are taken from the default system pa
"sensor": [
{
"mode": 3,
"type": 2,
"name": "SSD 4 usage",
"label": "storage_ssd4_usage",
"x": 400,
"y": 45,
"direction": 1,
"value": "35",
"fontFamily": "HarmonyOS_Sans_SC_Bold",
"fontSize": 24,
"fontColor": -1,
"textAlign": "center",
"minValue": 0,
"maxValue": 100,
"pic": "progress.png"
},
{
"mode": 3,
"type": 2,
"name": "SSD 5 usage",
"label": "storage_ssd5_usage",
"x": 400,
"y": 106,
"direction": 1,
"value": "80",
"fontFamily": "HarmonyOS_Sans_SC_Bold",
"fontSize": 24,
"fontColor": -1,
"textAlign": "center",
"minValue": 0,
"maxValue": 100,
"pic": "progress.png"
},
{
"mode": 1,
"type": 2,
"name": "SSD 4 temp",
"label": "storage_ssd4_temperature",
"x": 580,
@@ -68,7 +57,6 @@ The background image and sensor definitions are taken from the default system pa
"value": "34",
"fontFamily": "HarmonyOS_Sans_SC_Bold",
"fontSize": 24,
"fontColor": -1,
"textAlign": "center",
"integerDigits": -1,
"decimalDigits": 0,
@@ -76,7 +64,6 @@ The background image and sensor definitions are taken from the default system pa
},
{
"mode": 1,
"type": 2,
"name": "SSD 5 temp",
"label": "storage_ssd5_temperature",
"x": 580,
@@ -85,7 +72,6 @@ The background image and sensor definitions are taken from the default system pa
"value": "35",
"fontFamily": "HarmonyOS_Sans_SC_Bold",
"fontSize": 24,
"fontColor": -1,
"textAlign": "center",
"integerDigits": -1,
"decimalDigits": 0,
-6
View File
@@ -31,7 +31,6 @@ Example `panel.json` with a single "pointer" indicator sensor and the following
"id": "a9d4acac-2af9-4fe0-9f69-86cd09f25696",
"itemName": "CPU dial",
"mode": 4,
"type": 1,
"direction": 1,
"label": "cpu_percent",
"value": "47.7",
@@ -39,11 +38,6 @@ Example `panel.json` with a single "pointer" indicator sensor and the following
"y": 208,
"width": 302,
"height": 302,
"fontColor": "#ffffff",
"fontSize": 14,
"fontFamily": "",
"fontWeight": "normal",
"textAlign": "left",
"minAngle": -110,
"maxAngle": 110,
"minValue": 0,
+30 -17
View File
@@ -91,8 +91,11 @@ pub fn load_custom_panel<P: AsRef<Path>>(path: P) -> anyhow::Result<Panel> {
{
sensor.pic = Some(img_path.join(pic).display().to_string());
}
if !sensor.font_family.is_empty() && !Path::new(&sensor.font_family).is_absolute() {
sensor.font_family = font_path.join(&sensor.font_family).display().to_string();
if let Some(font_family) = &sensor.font_family
&& !font_family.is_empty()
&& !Path::new(&font_family).is_absolute()
{
sensor.font_family = Some(font_path.join(font_family).display().to_string());
}
}
@@ -283,7 +286,7 @@ impl Panel {
pub struct Sensor {
/// Sensor mode: text, fan, progress, pointer
pub mode: SensorMode,
/// Sensor type. TODO verify sensor type values
/// Sensor type, _not used_.
/// - 1 Time / Date Labels
/// - 2 Windows-specific system info
/// - 3 Hardware value
@@ -293,7 +296,7 @@ pub struct Sensor {
/// - 7 system info ?
/// - 8 lm-sensor ?
#[serde(rename = "type")]
pub sensor_type: i32,
pub sensor_type: Option<i32>,
/// Label name for internal panels.
pub name: Option<String>,
/// Label name for custom panels.
@@ -312,12 +315,12 @@ pub struct Sensor {
/// Optional unit text to print after the value
#[serde(deserialize_with = "empty_string_as_none")]
pub unit: Option<String>,
/// x-position. Custom panel coordinates are stored as float!
// TODO use i32 and round from f32 in deserialization
pub x: f32,
/// y-position.
// TODO use i32 and round from f32 in deserialization
pub y: f32,
/// Rounded x-position. Custom panel coordinates are stored as float!
#[serde(deserialize_with = "f32_as_rounded_i32")]
pub x: i32,
/// Rounded y-position. Custom panel coordinates are stored as float!
#[serde(deserialize_with = "f32_as_rounded_i32")]
pub y: i32,
/// Used for pointer type
pub width: Option<i32>,
/// Used for pointer type
@@ -326,14 +329,14 @@ pub struct Sensor {
pub direction: Option<SensorDirection>,
/// Font name matching font filename without file extension.
pub font_family: String,
pub font_family: Option<String>,
/// TODO font size unit: points or pixels?
pub font_size: i32,
pub font_size: Option<i32>,
/// Font color in `#RRGGBB` notation, or -1 if not set. #ffffff = white, #ff0000 = red
pub font_color: FontColor,
pub font_color: Option<FontColor>,
/// _Not (yet) used_
pub font_weight: FontWeight,
pub text_align: TextAlign,
pub font_weight: Option<FontWeight>,
pub text_align: Option<TextAlign>,
/// Number of integer places for the sensor value.
// -1 ≈ unset ⇒ Option<i32>
@@ -429,16 +432,18 @@ pub enum TimeDateLabel {
HM3,
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum FontWeight {
#[default]
Normal,
Bold,
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum TextAlign {
#[default]
Left,
Center,
Right,
@@ -569,3 +574,11 @@ where
let option = Option::<String>::deserialize(deserializer)?;
Ok(option.and_then(|s| if s.trim().is_empty() { None } else { Some(s) }))
}
fn f32_as_rounded_i32<'de, D>(deserializer: D) -> Result<i32, D::Error>
where
D: Deserializer<'de>,
{
let rounded = f32::deserialize(deserializer).map(f32::round)?;
Ok(rounded as i32)
}
+20 -18
View File
@@ -205,15 +205,16 @@ impl PanelRenderer {
value: &str,
unit: &str,
) -> Result<(), ImageProcessingError> {
let font = self
.font_handler
.get_ttf_font_or_default(&sensor.font_family);
let font = if let Some(font_family) = &sensor.font_family {
self.font_handler.get_ttf_font_or_default(font_family)
} else {
FontHandler::default_font()
};
let font_size = sensor.font_size.unwrap_or(14) as f32;
// TODO verify pixel scaling! Is font_size point size or pixel size?
// This is still a bit off compared to the original AOOSTAR-X. Only tested with HarmonyOS_Sans_SC_Bold!
let adjustment_hack = 0.7;
let scale = font
.pt_to_px_scale(sensor.font_size as f32 * adjustment_hack)
.unwrap();
let scale = font.pt_to_px_scale(font_size * adjustment_hack).unwrap();
let text = format_value(
value,
@@ -223,12 +224,12 @@ impl PanelRenderer {
);
let size = text_size(scale, &font, &text);
// TODO verify x & y-coordinate handling
let x = match sensor.text_align {
TextAlign::Left => sensor.x as i32,
TextAlign::Center => sensor.x as i32 - (size.0 / 2) as i32,
TextAlign::Right => sensor.x as i32 - size.0 as i32,
let x = match sensor.text_align.unwrap_or_default() {
TextAlign::Left => sensor.x,
TextAlign::Center => sensor.x - (size.0 / 2) as i32,
TextAlign::Right => sensor.x - size.0 as i32,
};
let y = (sensor.y - scale.y / 2f32) as i32;
let y = (sensor.y as f32 - scale.y / 2f32) as i32;
// let y = sensor.y as i32 - (size.1 / 2) as i32;
debug!(
@@ -236,7 +237,7 @@ impl PanelRenderer {
sensor.x, sensor.y
);
let font_color = sensor.font_color.into();
let font_color = sensor.font_color.unwrap_or_default().into();
draw_text_mut(background, font_color, x, y, scale, &font, &text);
Ok(())
@@ -257,8 +258,8 @@ impl PanelRenderer {
return Err(ImageProcessingError::InvalidDirection(direction));
}
let pos_x = sensor.x as i32;
let pos_y = sensor.y as i32;
let pos_x = sensor.x;
let pos_y = sensor.y;
let pic_path = sensor.pic.as_ref().ok_or_else(|| {
ImageProcessingError::ImageLoadError("No picture specified".to_string())
@@ -385,8 +386,8 @@ impl PanelRenderer {
}
}
let pos_x = sensor.x as i32;
let pos_y = sensor.y as i32;
let pos_x = sensor.x;
let pos_y = sensor.y;
if let Some(progress_layer) = self.get_layer(SensorMode::Progress) {
PanelRenderer::paste_image(progress_layer, &processed_img, pos_x, pos_y);
@@ -420,8 +421,8 @@ impl PanelRenderer {
return Err(ImageProcessingError::InvalidDirection(direction));
}
let x_center = sensor.x as i32;
let y_center = sensor.y as i32;
let x_center = sensor.x;
let y_center = sensor.y;
let xz_x = sensor.xz_x.unwrap_or(0);
let xz_y = sensor.xz_y.unwrap_or(0);
@@ -429,6 +430,7 @@ impl PanelRenderer {
ImageProcessingError::ImageLoadError("No picture specified".to_string())
})?;
// TODO combine get image with resize
let mut pic = self
.image_cache
.get(pic_path, None)