diff --git a/.SRCINFO b/.SRCINFO index d1f1988..5ae15e2 100644 --- a/.SRCINFO +++ b/.SRCINFO @@ -1,6 +1,6 @@ pkgbase = coolerdash pkgdesc = Plug-in for CoolerControl that extends the LCD functionality with additional features - pkgver = 3.0.1 + pkgver = 3.0.2 pkgrel = 1 url = https://github.com/damachine/coolerdash install = coolerdash.install diff --git a/VERSION b/VERSION index cb2b00e..b502146 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.1 +3.0.2 diff --git a/docs/coolercontrol-api.md b/docs/coolercontrol-api.md index 0ad6161..6373841 100644 --- a/docs/coolercontrol-api.md +++ b/docs/coolercontrol-api.md @@ -24,7 +24,7 @@ The CoolerControl API integration consists of three core modules that handle all ### Purpose -CoolerDash acts as a specialized LCD client for CoolerControl, fetching temperature data and uploading rendered images to Liquidctl-compatible devices with LCD displays (e.g., NZXT Kraken Elite). +CoolerDash acts as a specialized LCD client for CoolerControl, fetching temperature data and uploading rendered images to CoolerControl-managed devices with LCD displays. ### API Endpoints Used @@ -472,7 +472,7 @@ static struct { - Reduces API overhead (every render cycle) - Improves performance and reliability -**Access Function**: `get_liquidctl_data()` +**Access Function**: `get_cached_lcd_device_data()` - Returns cached data if available - Initializes cache on first call - Thread-safe (single-threaded daemon) @@ -481,7 +481,7 @@ static struct { **Function**: `init_device_cache(const Config *config)` -**Purpose**: Fetch device list and extract Liquidctl device info +**Purpose**: Fetch device list and extract CoolerControl LCD device info **API Call**: ``` @@ -536,7 +536,7 @@ int init_device_cache(const Config *config) // Parse JSON response if (res == CURLE_OK) { - parse_liquidctl_data(response.data, + parse_lcd_device_data(response.data, device_cache.device_uid, sizeof(device_cache.device_uid), &device_cache.screen_width, @@ -556,7 +556,7 @@ int init_device_cache(const Config *config) #### 3. JSON Parsing -**Function**: `parse_liquidctl_data(const char *json, ...)` +**Function**: `parse_lcd_device_data(const char *json, ...)` **Purpose**: Extract device information from devices JSON response @@ -577,7 +577,7 @@ int init_device_cache(const Config *config) - `extract_device_name()`: Get device name - `get_lcd_info_from_device()`: Navigate JSON to lcd_info - `extract_lcd_dimensions()`: Get width/height from lcd_info -- `is_liquidctl_device()`: Check if type matches "Liquidctl" +- `has_usable_device_uid()`: Verify that the device exposes a usable UID **Error Handling**: - Validates JSON structure at each level @@ -718,7 +718,7 @@ int cc_safe_strcpy(char *restrict dest, size_t dest_size, const char *restrict s ```c // Device cache int init_device_cache(const struct Config *config); -int get_liquidctl_data(const struct Config *config, char *device_uid, +int get_cached_lcd_device_data(const struct Config *config, char *device_uid, size_t uid_size, char *device_name, size_t name_size, int *screen_width, int *screen_height); @@ -992,7 +992,7 @@ main() startup ├─→ GET /devices │ Response: Device list JSON │ - ├─→ Parse JSON, find Liquidctl device + ├─→ Parse JSON, find first LCD-capable CoolerControl device │ └─→ Cache: UID, name, width, height ↓ @@ -1182,13 +1182,13 @@ log_message(LOG_ERROR, "Login failed: CURL code %d, HTTP code %ld", res, respons **Symptom**: `init_device_cache()` returns 0 **Causes**: -- No Liquidctl device connected +- No LCD-capable CoolerControl device connected - Device not detected by CoolerControl - Wrong device type in JSON **Debugging**: ```c -log_message(LOG_ERROR, "No Liquidctl device found in API response"); +log_message(LOG_ERROR, "No LCD device found in API response"); ``` **Resolution**: @@ -1458,7 +1458,7 @@ curl -I http://127.0.0.1:11987 systemctl start coolercontrol ``` -#### Issue: "No Liquidctl device found" +#### Issue: "No LCD device found" **Check devices**: ```bash @@ -1561,7 +1561,7 @@ cat /tmp/coolerdash_cookie_*.txt The CoolerControl API integration provides a robust, efficient interface for: - **Authentication**: Cookie-based session with HTTP Basic Auth -- **Device Detection**: Automatic Liquidctl device discovery and caching +- **Device Detection**: Automatic CoolerControl LCD device discovery and caching - **Temperature Monitoring**: Real-time CPU/GPU data retrieval - **LCD Upload**: Multipart image upload with brightness/orientation control - **Error Handling**: Comprehensive validation and logging diff --git a/docs/developer-guide.md b/docs/developer-guide.md index 6764589..e3512e9 100644 --- a/docs/developer-guide.md +++ b/docs/developer-guide.md @@ -1,7 +1,7 @@ # CoolerDash Developer Documentation -**Language:** C99 | **Platform:** Linux x86-64-v3 | **License:** MIT -**Author:** damachine (damachin3@proton.me) +**Language:** C99 | **Platform:** Linux x86-64-v3 | **License:** MIT +**Author:** damachine (damachin3@proton.me) **Repository:** https://github.com/damachine/coolerdash --- @@ -25,7 +25,7 @@ ### Purpose -CoolerDash extends the LCD functionality of [CoolerControl](https://gitlab.com/coolercontrol/coolercontrol) for Linux systems, specifically targeting AIO liquid cooler LCD displays (NZXT Kraken, etc.). It provides real-time sensor visualization with customizable UI elements. +CoolerDash extends the LCD functionality of [CoolerControl](https://gitlab.com/coolercontrol/coolercontrol) for Linux systems, targeting CoolerControl-managed LCD displays such as AIO pump screens and similar supported devices. It provides real-time sensor visualization with customizable UI elements. ### Key Features @@ -141,8 +141,8 @@ coolerdash/ ### Makefile Overview -**Location:** `/Makefile` -**Build Tool:** GNU Make + GCC +**Location:** `/Makefile` +**Build Tool:** GNU Make + GCC **Standard:** C99 with strict warnings #### Key Targets @@ -164,8 +164,8 @@ CFLAGS = -Wall -Wextra -O2 -std=c99 -march=x86-64-v3 -Iinclude \ LIBS = $(shell pkg-config --libs cairo jansson libcurl) -lm ``` -**Optimization Level:** `-O2` (production), `-O0` (debug) -**Architecture:** `x86-64-v3` (AVX2/BMI2 support) +**Optimization Level:** `-O2` (production), `-O0` (debug) +**Architecture:** `x86-64-v3` (AVX2/BMI2 support) **Warnings:** All enabled (`-Wall -Wextra`) #### Build Workflow @@ -195,8 +195,8 @@ LIBS = $(shell pkg-config --libs cairo jansson libcurl) -lm ### Dependency Management -**Automatic Detection:** Makefile checks for missing dependencies via `pkg-config` -**Distribution Support:** Arch, Debian, Fedora, RHEL, openSUSE +**Automatic Detection:** Makefile checks for missing dependencies via `pkg-config` +**Distribution Support:** Arch, Debian, Fedora, RHEL, openSUSE **Fallback Behavior:** Build fails with clear error messages if deps missing --- @@ -313,8 +313,8 @@ void log_config(const Config *config); // Uses LOG_STATUS level (always visible ### CoolerControl REST API -**Base URL:** `http://localhost:11987` (configurable) -**Authentication:** HTTP Basic Auth (username: CCAdmin) +**Base URL:** `http://localhost:11987` (configurable) +**Authentication:** HTTP Basic Auth (username: CCAdmin) **Session Management:** Cookie-based (stored in `/tmp/coolerdash_cookie_.txt`) ### API Endpoints Used @@ -362,8 +362,8 @@ Response JSON: } ``` -**Implementation:** `src/srv/cc_conf.c` → `initialize_device_cache()` -**Caching:** One-time fetch at startup, stored in static struct +**Implementation:** `src/srv/cc_conf.c` → `initialize_device_cache()` +**Caching:** One-time fetch at startup, stored in static struct **Display Detection:** Kraken devices: >240x240 = circular, ≤240 = rectangular --- @@ -414,8 +414,8 @@ Response JSON: } ``` -**Implementation:** `src/srv/cc_sensor.c` → `get_temperature_data()` -**Sensor Selection:** CPU = "temp1", GPU = name contains "GPU"/"gpu" +**Implementation:** `src/srv/cc_sensor.c` → `get_temperature_data()` +**Sensor Selection:** CPU = "temp1", GPU = name contains "GPU"/"gpu" **Validation:** Temperature range -50°C to +150°C --- @@ -435,8 +435,8 @@ Form Fields: Response: 200 OK ``` -**Implementation:** `src/srv/cc_main.c` → `send_image_to_lcd()` -**Image Format:** PNG, dimensions match device LCD +**Implementation:** `src/srv/cc_main.c` → `send_image_to_lcd()` +**Image Format:** PNG, dimensions match device LCD **Multipart Construction:** CURL mime API with proper MIME types --- @@ -476,8 +476,8 @@ Response: 200 OK ### Cairo Graphics Workflow -**Library:** cairo 1.x (vector graphics) -**Output Format:** PNG image matching LCD dimensions +**Library:** cairo 1.x (vector graphics) +**Output Format:** PNG image matching LCD dimensions **Color Depth:** 24-bit RGB ### Rendering Steps @@ -513,13 +513,13 @@ Response: 200 OK ```c int is_circular_display_device(const char *device_name, int width, int height) { const int is_kraken = (strstr(device_name, "Kraken") != NULL); - + if (is_kraken) { // NZXT Kraken: >240x240 = circular, ≤240 = rectangular const int is_large_display = (width > 240 || height > 240); return is_large_display ? 1 : 0; } - + // Add other circular display brands here return 0; } @@ -552,7 +552,7 @@ This script prints a table summarizing `inscribe_used`, `safe_area`, and `safe_b ### Circular Display Rendering -**Challenge:** Circular LCD requires content within inscribed square +**Challenge:** Circular LCD requires content within inscribed square **Solution:** Apply inscribe factor 1/√2 ≈ 0.7071 to all coordinates **Mathematical Basis:** @@ -581,7 +581,7 @@ if (strcmp(config->display_shape, "rectangular") == 0) { params.inscribe_factor = M_SQRT1_2; } else { // Auto-detection fallback - int is_circular = config->force_display_circular || + int is_circular = config->force_display_circular || is_circular_display_device(device_name, width, height); params.inscribe_factor = is_circular ? M_SQRT1_2 : 1.0; } @@ -622,7 +622,7 @@ const Color *get_bar_color(float temp, float low, float medium) { int calculate_temp_fill_width(float temp, int max_width, float max_temp) { if (temp <= 0.0f) return 0; - + const float ratio = fminf(temp / max_temp, 1.0f); // Clamp to 1.0 return (int)(ratio * max_width); } @@ -745,7 +745,7 @@ static CoolerControlSession cc_session = { | Function | Purpose | Returns | |----------|---------|---------| | `init_device_cache(config)` | Fetch device info once (GET /devices) | `int` success | -| `get_liquidctl_data(config, uid, name, width, height)` | Read cached data | `int` success | +| `get_cached_lcd_device_data(config, uid, name, width, height)` | Read cached data | `int` success | | `update_config_from_device(config)` | Auto-set width/height if 0 | `int` updated | | `is_circular_display_device(name, width, height)` | Detect display shape | `int` boolean | @@ -753,12 +753,12 @@ static CoolerControlSession cc_session = { ```c initialize_device_cache() // HTTP GET + JSON parse + cache population -parse_liquidctl_data() // Extract device info from JSON +parse_lcd_device_data() // Extract device info from JSON extract_device_type_from_json() // Get "type" field extract_device_uid() // Get "uid" field extract_device_name() // Get "name" field extract_lcd_dimensions() // Get screen_width/screen_height -search_liquidctl_device() // Find first Liquidctl device in array +search_lcd_device() // Find first CoolerControl LCD device in array configure_device_cache_curl() // Setup CURL for /devices request process_device_cache_response() // Parse response + populate cache ``` @@ -917,15 +917,15 @@ int my_function(void) { char *buffer = malloc(1024); if (!buffer) return 0; - + CURL *curl = curl_easy_init(); if (!curl) { free(buffer); return 0; } - + // ... use resources ... - + // Cleanup (always reached) curl_easy_cleanup(curl); free(buffer); @@ -1103,7 +1103,7 @@ sudo systemctl restart coolerdash.service #### Issue: "Session initialization failed" -**Cause:** CoolerControl not running or wrong credentials +**Cause:** CoolerControl not running or wrong credentials **Debug:** ```bash @@ -1119,9 +1119,9 @@ grep daemon_password /etc/coolercontrol/plugins/coolerdash/config.json --- -#### Issue: "No Liquidctl devices found" +#### Issue: "No LCD devices found" -**Cause:** Device not detected or wrong type +**Cause:** Device not detected or wrong type **Debug:** ```bash @@ -1136,7 +1136,7 @@ curl http://localhost:11987/devices | jq '.devices[] | {uid, name, type}' #### Issue: "Display wrong shape (circular/rectangular)" -**Cause:** Incorrect display detection logic +**Cause:** Incorrect display detection logic **Debug:** ```bash @@ -1156,7 +1156,7 @@ coolerdash --develop # All displays treated as circular #### Issue: "Temperature values incorrect" -**Cause:** Wrong sensor selection +**Cause:** Wrong sensor selection **Debug:** ```bash @@ -1235,8 +1235,8 @@ coolerdash --verbose 2>&1 | grep -E "(Session|Temperature|Upload)" ### Contributing -**Repository:** https://github.com/damachine/coolerdash -**Issues:** https://github.com/damachine/coolerdash/issues +**Repository:** https://github.com/damachine/coolerdash +**Issues:** https://github.com/damachine/coolerdash/issues **Discussions:** https://github.com/damachine/coolerdash/discussions **Pull Request Checklist:** @@ -1277,6 +1277,6 @@ coolerdash --verbose 2>&1 | grep -E "(Session|Temperature|Upload)" --- -**Document Version:** 2.x -**Last Updated:** 2026 +**Document Version:** 2.x +**Last Updated:** 2026 **Maintained by:** damachine (damachin3@proton.me) diff --git a/docs/display-modes.md b/docs/display-modes.md index 9c624fa..e88b3fc 100644 --- a/docs/display-modes.md +++ b/docs/display-modes.md @@ -403,7 +403,7 @@ void draw_display_image(const struct Config *config) #### Dual Mode Flow: 1. `draw_dual_image()` → Entry point -2. `get_liquidctl_data()` → Device information +2. `get_cached_lcd_device_data()` → Device information 3. `get_temperature_monitor_data()` → Sensor data 4. `render_dual_display()` → Cairo rendering 5. `cairo_surface_write_to_png()` → PNG generation @@ -411,7 +411,7 @@ void draw_display_image(const struct Config *config) #### Circle Mode Flow: 1. `draw_circle_image()` → Entry point -2. `get_liquidctl_data()` → Device information +2. `get_cached_lcd_device_data()` → Device information 3. `get_temperature_monitor_data()` → Sensor data 4. `update_sensor_mode()` → Check 5s interval 5. `render_circle_display()` → Cairo rendering @@ -534,7 +534,7 @@ void draw_newmode_image(const struct Config *config) char device_name[128] = {0}; int screen_width = 0, screen_height = 0; - if (!get_liquidctl_data(config, device_uid, sizeof(device_uid), + if (!get_cached_lcd_device_data(config, device_uid, sizeof(device_uid), device_name, sizeof(device_name), &screen_width, &screen_height)) { return; diff --git a/etc/coolercontrol/plugins/coolerdash/config.json b/etc/coolercontrol/plugins/coolerdash/config.json index cb754f5..29b639a 100644 --- a/etc/coolercontrol/plugins/coolerdash/config.json +++ b/etc/coolercontrol/plugins/coolerdash/config.json @@ -12,6 +12,7 @@ "paths": { "images": "/etc/coolercontrol/plugins/coolerdash", "image_coolerdash": "/etc/coolercontrol/plugins/coolerdash/coolerdash.png", + "image_background": "", "image_shutdown": "/etc/coolercontrol/plugins/coolerdash/shutdown.png" }, @@ -21,6 +22,8 @@ "refresh_interval": 2.5, "brightness": 80, "orientation": 0, + "background_image_fit": "cover", + "background_overlay_opacity": 0.0, "width": 0, "height": 0, "shape": "auto", @@ -36,6 +39,7 @@ "bar_width": 98, "bar_gap": 12, "bar_border": 1.0, + "bar_opacity": 1.0, "bar_border_enabled": 1, "label_margin_left": 1, "label_margin_bar": 1, diff --git a/etc/coolercontrol/plugins/coolerdash/ui/index.html b/etc/coolercontrol/plugins/coolerdash/ui/index.html index c866bdd..b65e5ef 100644 --- a/etc/coolercontrol/plugins/coolerdash/ui/index.html +++ b/etc/coolercontrol/plugins/coolerdash/ui/index.html @@ -769,12 +769,33 @@

Display Geometry

-

Shutdown Image

+

Background & Shutdown Images

+
+ + Optional PNG file used as display background behind the sensor values. Leave empty to use the configured background color. + +
Displayed on the LCD when the daemon stops. Default: /etc/coolercontrol/plugins/coolerdash/shutdown.png
+
+
+ + Default: Cover + +
+
+ + 0.0 = off, 1.0 = solid overlay using Display Background color + +
+
@@ -844,6 +865,11 @@

Shutdown Image

Default: 1.0 +
+ + 0.0 = transparent, 1.0 = fully visible + +
Default: 1 @@ -1129,6 +1155,7 @@

System Environment

tls_skip_verify: false }, paths: { + image_background: "", image_shutdown: "/etc/coolercontrol/plugins/coolerdash/shutdown.png" }, display: { @@ -1137,6 +1164,8 @@

System Environment

refresh_interval: 2.5, brightness: 80, orientation: 0, + background_image_fit: "cover", + background_overlay_opacity: 0.0, width: 0, height: 0, shape: "auto", @@ -1151,6 +1180,7 @@

System Environment

bar_width: 98, bar_gap: 12, bar_border: 1.0, + bar_opacity: 1.0, bar_border_enabled: 1, label_margin_left: 1, label_margin_bar: 1, diff --git a/src/device/config.c b/src/device/config.c index 9753fec..2211d38 100644 --- a/src/device/config.c +++ b/src/device/config.c @@ -91,6 +91,10 @@ static void set_paths_defaults(Config *config) { SAFE_STRCPY(config->paths_image_coolerdash, "/etc/coolercontrol/plugins/coolerdash/coolerdash.png"); } + if (config->paths_image_background[0] == '\0') + { + SAFE_STRCPY(config->paths_image_background, ""); + } if (config->paths_image_shutdown[0] == '\0') { SAFE_STRCPY(config->paths_image_shutdown, @@ -107,7 +111,8 @@ static void try_set_lcd_dimensions(Config *config) return; int lcd_width = 0, lcd_height = 0; - if (!get_liquidctl_data(config, NULL, 0, NULL, 0, &lcd_width, &lcd_height)) + if (!get_cached_lcd_device_data(config, NULL, 0, NULL, 0, &lcd_width, + &lcd_height)) return; if (lcd_width <= 0 || lcd_height <= 0) @@ -136,12 +141,18 @@ static void set_display_defaults(Config *config) cc_safe_strcpy(config->display_shape, sizeof(config->display_shape), "auto"); if (config->display_mode[0] == '\0') cc_safe_strcpy(config->display_mode, sizeof(config->display_mode), "dual"); + if (config->display_background_image_fit[0] == '\0') + cc_safe_strcpy(config->display_background_image_fit, + sizeof(config->display_background_image_fit), "cover"); if (config->circle_switch_interval == 0) config->circle_switch_interval = 5; if (config->display_content_scale_factor == 0.0f) config->display_content_scale_factor = 0.98f; if (config->display_inscribe_factor < 0.0f) config->display_inscribe_factor = 0.70710678f; + if (config->display_background_overlay_opacity < 0.0f || + config->display_background_overlay_opacity > 1.0f) + config->display_background_overlay_opacity = 0.0f; // Sensor slot defaults (flexible sensor assignment) if (config->sensor_slot_up[0] == '\0') @@ -170,6 +181,8 @@ static void set_layout_defaults(Config *config) // bar_border: -1 = use default (1.0), 0 = explicitly disabled, >0 = custom value if (config->layout_bar_border < 0.0f) config->layout_bar_border = 1.0f; + if (config->layout_bar_opacity < 0.0f || config->layout_bar_opacity > 1.0f) + config->layout_bar_opacity = 1.0f; // bar_border_enabled: -1 = auto (enabled), 0 = disabled, 1 = enabled if (config->layout_bar_border_enabled < 0) config->layout_bar_border_enabled = 1; // Default: enabled @@ -713,6 +726,16 @@ static void load_paths_from_json(json_t *root, Config *config) } } + json_t *image_background = json_object_get(paths, "image_background"); + if (image_background && json_is_string(image_background)) + { + const char *value = json_string_value(image_background); + if (value) + { + SAFE_STRCPY(config->paths_image_background, value); + } + } + json_t *image_shutdown = json_object_get(paths, "image_shutdown"); if (image_shutdown && json_is_string(image_shutdown)) { @@ -751,6 +774,27 @@ static void load_display_from_json(json_t *root, Config *config) config->circle_switch_interval = (uint16_t)val; } + json_t *background_fit = json_object_get(display, "background_image_fit"); + if (background_fit && json_is_string(background_fit)) + { + const char *value = json_string_value(background_fit); + if (value && (strcmp(value, "cover") == 0 || + strcmp(value, "contain") == 0 || + strcmp(value, "stretch") == 0)) + { + SAFE_STRCPY(config->display_background_image_fit, value); + } + } + + json_t *background_overlay = + json_object_get(display, "background_overlay_opacity"); + if (background_overlay && json_is_number(background_overlay)) + { + double val = json_number_value(background_overlay); + if (val >= 0.0 && val <= 1.0) + config->display_background_overlay_opacity = (float)val; + } + json_t *refresh = json_object_get(display, "refresh_interval"); if (refresh && json_is_number(refresh)) { @@ -887,6 +931,14 @@ static void load_layout_from_json(json_t *root, Config *config) config->layout_bar_gap = (uint16_t)val; } + json_t *bar_opacity = json_object_get(layout, "bar_opacity"); + if (bar_opacity && json_is_number(bar_opacity)) + { + double val = json_number_value(bar_opacity); + if (val >= 0.0 && val <= 1.0) + config->layout_bar_opacity = (float)val; + } + json_t *bar_border = json_object_get(layout, "bar_border"); if (bar_border && json_is_number(bar_border)) { @@ -1170,6 +1222,7 @@ int load_plugin_config(Config *config, const char *config_path) memset(config, 0, sizeof(Config)); config->display_inscribe_factor = -1.0f; // Sentinel for "auto" config->layout_bar_border = -1.0f; // Sentinel for "use default" + config->layout_bar_opacity = -1.0f; // Sentinel for "use default" config->layout_bar_border_enabled = -1; // Sentinel for "auto" (enabled) // Note: All colors have is_set=0 after memset, so defaults will be applied diff --git a/src/device/config.h b/src/device/config.h index e1bca7a..fc9704c 100644 --- a/src/device/config.h +++ b/src/device/config.h @@ -96,11 +96,12 @@ typedef struct Config char daemon_password[CONFIG_MAX_PASSWORD_LEN]; char access_token[CONFIG_MAX_TOKEN_LEN]; char tls_ca_cert_path[CONFIG_MAX_PATH_LEN]; - int tls_skip_verify; + int tls_skip_verify; // Paths configuration char paths_images[CONFIG_MAX_PATH_LEN]; char paths_image_coolerdash[CONFIG_MAX_PATH_LEN]; + char paths_image_background[CONFIG_MAX_PATH_LEN]; char paths_image_shutdown[CONFIG_MAX_PATH_LEN]; // Display configuration @@ -112,9 +113,11 @@ typedef struct Config int force_display_circular; char display_shape[16]; char display_mode[16]; + char display_background_image_fit[16]; uint16_t circle_switch_interval; float display_content_scale_factor; float display_inscribe_factor; + float display_background_overlay_opacity; // Sensor slot configuration (flexible sensor assignment) char sensor_slot_up[CONFIG_MAX_SENSOR_SLOT_LEN]; // "cpu", "gpu", "liquid", "none" @@ -128,6 +131,7 @@ typedef struct Config uint16_t layout_bar_height_down; // Individual bar height for lower slot uint16_t layout_bar_gap; float layout_bar_border; + float layout_bar_opacity; int layout_bar_border_enabled; // 1=enabled, 0=disabled, -1=auto (use default) uint8_t layout_bar_width; uint8_t layout_label_margin_left; diff --git a/src/main.c b/src/main.c index 1a1a196..fb3e35a 100644 --- a/src/main.c +++ b/src/main.c @@ -596,9 +596,9 @@ static void initialize_device_info(Config *config) char device_name[CONFIG_MAX_STRING_LEN] = {0}; int api_screen_width = 0, api_screen_height = 0; - if (!get_liquidctl_data(config, device_uid, sizeof(device_uid), device_name, - sizeof(device_name), &api_screen_width, - &api_screen_height)) + if (!get_cached_lcd_device_data(config, device_uid, sizeof(device_uid), + device_name, sizeof(device_name), + &api_screen_width, &api_screen_height)) { log_message(LOG_ERROR, "Could not retrieve device information"); return; @@ -701,8 +701,10 @@ int main(int argc, char **argv) if (config.paths_image_shutdown[0]) { char device_uid[128] = {0}; - if (get_liquidctl_data(&config, device_uid, sizeof(device_uid), - NULL, 0, NULL, NULL) && device_uid[0]) + if (get_cached_lcd_device_data(&config, device_uid, + sizeof(device_uid), NULL, 0, NULL, + NULL) && + device_uid[0]) { register_shutdown_image_with_cc(&config, config.paths_image_shutdown, diff --git a/src/mods/circle.c b/src/mods/circle.c index b07a5fa..24ab737 100644 --- a/src/mods/circle.c +++ b/src/mods/circle.c @@ -172,6 +172,7 @@ static void draw_single_sensor(cairo_t *cr, const struct Config *config, // Calculate vertical layout - BAR is centered const int bar_y = (config->display_height - bar_height) / 2; const int bar_x = (config->display_width - effective_bar_width) / 2; + const int bar_right = bar_x + effective_bar_width; // Temperature above the bar (10% of display height above bar) const int temp_spacing = (int)(config->display_height * 0.10); @@ -205,9 +206,13 @@ static void draw_single_sensor(cairo_t *cr, const struct Config *config, cairo_text_extents(cr, "°", °ree_ext); cairo_set_font_size(cr, slot_font_size); - // Center temperature + degree symbol as a unit - const double total_width = temp_ext.width - 4 + degree_ext.width; - double temp_x = (config->display_width - total_width) / 2.0; + // Right-align temperature + degree symbol block to the safe bar area. + const int degree_spacing = get_scaled_degree_spacing(config, params); + const double total_width = temp_ext.width + + (get_slot_is_temp(data, slot_value) + ? degree_spacing + degree_ext.width + : 0.0); + double temp_x = bar_right - total_width; double final_temp_y = temp_y; // Apply user-defined offsets from sensor config @@ -224,9 +229,6 @@ static void draw_single_sensor(cairo_t *cr, const struct Config *config, // Draw degree symbol only for temperature sensors if (get_slot_is_temp(data, slot_value)) { - const int degree_spacing = (config->display_degree_spacing > 0) - ? config->display_degree_spacing - : 16; double degree_x = temp_x + temp_ext.width + degree_spacing; double degree_y = final_temp_y - slot_font_size * 0.25; @@ -237,9 +239,10 @@ static void draw_single_sensor(cairo_t *cr, const struct Config *config, } // Draw temperature bar (centered reference point) + const double bar_alpha = config->layout_bar_opacity; // Bar background - set_cairo_color(cr, &config->layout_bar_color_background); + set_cairo_color_alpha(cr, &config->layout_bar_color_background, bar_alpha); draw_rounded_rectangle_path(cr, bar_x, bar_y, effective_bar_width, bar_height, params->corner_radius); cairo_fill(cr); @@ -247,7 +250,7 @@ static void draw_single_sensor(cairo_t *cr, const struct Config *config, // Bar border (only if enabled and thickness > 0) if (config->layout_bar_border_enabled && config->layout_bar_border > 0.0f) { - set_cairo_color(cr, &config->layout_bar_color_border); + set_cairo_color_alpha(cr, &config->layout_bar_color_border, bar_alpha); draw_rounded_rectangle_path(cr, bar_x, bar_y, effective_bar_width, bar_height, params->corner_radius); cairo_set_line_width(cr, config->layout_bar_border); @@ -260,7 +263,7 @@ static void draw_single_sensor(cairo_t *cr, const struct Config *config, if (fill_width > 0) { Color bar_color = get_slot_bar_color(config, slot_value, temp_value); - set_cairo_color(cr, &bar_color); + set_cairo_color_alpha(cr, &bar_color, bar_alpha); cairo_save(cr); draw_rounded_rectangle_path(cr, bar_x, bar_y, effective_bar_width, @@ -284,8 +287,11 @@ static void draw_single_sensor(cairo_t *cr, const struct Config *config, cairo_text_extents_t label_text_ext; cairo_text_extents(cr, label_text, &label_text_ext); - // Center label horizontally - double label_x = (config->display_width - label_text_ext.width) / 2.0; + const double left_margin_factor = + (config->layout_label_margin_left > 0) + ? (config->layout_label_margin_left / 100.0) + : 0.01; + double label_x = config->display_width * left_margin_factor; // Position label 2% from bottom double final_label_y = config->display_height - (config->display_height * 0.02); @@ -311,9 +317,7 @@ static void render_display_content(cairo_t *cr, const struct Config *config, if (!cr || !config || !data || !params) return; - // Draw main background - set_cairo_color(cr, &config->display_background_color); - cairo_paint(cr); + paint_display_background(cr, config); // Update sensor mode (check if configured interval elapsed) update_sensor_mode(config); @@ -402,8 +406,9 @@ void draw_circle_image(const struct Config *config) int screen_width = 0, screen_height = 0; const int device_available = - get_liquidctl_data(config, device_uid, sizeof(device_uid), device_name, - sizeof(device_name), &screen_width, &screen_height); + get_cached_lcd_device_data(config, device_uid, sizeof(device_uid), + device_name, sizeof(device_name), + &screen_width, &screen_height); // Get sensor data monitor_sensor_data_t data = {0}; diff --git a/src/mods/display.c b/src/mods/display.c index 30959b5..c6c1b9d 100644 --- a/src/mods/display.c +++ b/src/mods/display.c @@ -55,6 +55,164 @@ void set_cairo_color(cairo_t *cr, const Color *color) cairo_color_convert(color->b)); } +/** + * @brief Set cairo source color from Color structure with alpha. + */ +void set_cairo_color_alpha(cairo_t *cr, const Color *color, double alpha) +{ + cairo_set_source_rgba(cr, cairo_color_convert(color->r), + cairo_color_convert(color->g), + cairo_color_convert(color->b), alpha); +} + +/** + * @brief Scale a design-space X value based on display width. + */ +double scale_value_x(const ScalingParams *params, double value) +{ + if (!params) + return value; + return value * params->scale_x; +} + +/** + * @brief Scale a design-space Y value based on display height. + */ +double scale_value_y(const ScalingParams *params, double value) +{ + if (!params) + return value; + return value * params->scale_y; +} + +/** + * @brief Scale a design-space value using average display scaling. + */ +double scale_value_avg(const ScalingParams *params, double value) +{ + if (!params) + return value; + return value * ((params->scale_x + params->scale_y) / 2.0); +} + +/** + * @brief Get effective degree symbol spacing for the current display. + */ +int get_scaled_degree_spacing(const struct Config *config, + const ScalingParams *params) +{ + const double base_spacing = + (config && config->display_degree_spacing > 0) + ? (double)config->display_degree_spacing + : 16.0; + + const int scaled_spacing = (int)lround(scale_value_avg(params, base_spacing)); + return (scaled_spacing > 0) ? scaled_spacing : 1; +} + +/** + * @brief Paint a configured overlay over a loaded background image. + */ +static void paint_background_overlay(cairo_t *cr, const struct Config *config) +{ + if (config->display_background_overlay_opacity <= 0.0f) + return; + + cairo_save(cr); + cairo_set_source_rgba(cr, + cairo_color_convert(config->display_background_color.r), + cairo_color_convert(config->display_background_color.g), + cairo_color_convert(config->display_background_color.b), + config->display_background_overlay_opacity); + cairo_paint(cr); + cairo_restore(cr); +} + +/** + * @brief Paint configured background image or fallback color. + */ +void paint_display_background(cairo_t *cr, const struct Config *config) +{ + static char last_failed_path[CONFIG_MAX_PATH_LEN] = {0}; + + if (!cr || !config) + return; + + set_cairo_color(cr, &config->display_background_color); + cairo_paint(cr); + + if (config->paths_image_background[0] != '\0') + { + cairo_surface_t *background = + cairo_image_surface_create_from_png(config->paths_image_background); + + if (background && + cairo_surface_status(background) == CAIRO_STATUS_SUCCESS) + { + const int image_width = cairo_image_surface_get_width(background); + const int image_height = cairo_image_surface_get_height(background); + + if (image_width > 0 && image_height > 0) + { + double scale_x = 1.0; + double scale_y = 1.0; + double offset_x = 0.0; + double offset_y = 0.0; + + if (strcmp(config->display_background_image_fit, "contain") == 0) + { + const double scale = fmin((double)config->display_width / image_width, + (double)config->display_height / image_height); + scale_x = scale; + scale_y = scale; + offset_x = ((double)config->display_width - image_width * scale) / 2.0; + offset_y = ((double)config->display_height - image_height * scale) / 2.0; + } + else if (strcmp(config->display_background_image_fit, "stretch") == 0) + { + scale_x = (double)config->display_width / image_width; + scale_y = (double)config->display_height / image_height; + } + else + { + const double scale = fmax((double)config->display_width / image_width, + (double)config->display_height / image_height); + scale_x = scale; + scale_y = scale; + offset_x = ((double)config->display_width - image_width * scale) / 2.0; + offset_y = ((double)config->display_height - image_height * scale) / 2.0; + } + + cairo_save(cr); + cairo_translate(cr, offset_x, offset_y); + cairo_scale(cr, scale_x, scale_y); + cairo_set_source_surface(cr, background, 0.0, 0.0); + cairo_pattern_set_filter(cairo_get_source(cr), + CAIRO_FILTER_BILINEAR); + cairo_paint(cr); + cairo_restore(cr); + + paint_background_overlay(cr, config); + cairo_surface_destroy(background); + last_failed_path[0] = '\0'; + return; + } + + cairo_surface_destroy(background); + } + + if (strcmp(last_failed_path, config->paths_image_background) != 0) + { + SAFE_STRCPY(last_failed_path, config->paths_image_background); + log_message(LOG_WARNING, + "Failed to load background image, using background color: %s", + config->paths_image_background); + } + } + + return; +} + /** * @brief Calculate temperature fill width with bounds checking. */ diff --git a/src/mods/display.h b/src/mods/display.h index 09cf6ab..43cfede 100644 --- a/src/mods/display.h +++ b/src/mods/display.h @@ -105,6 +105,40 @@ double cairo_color_convert(uint8_t color_component); */ void set_cairo_color(cairo_t *cr, const Color *color); +/** + * @brief Set cairo source color from Color structure with alpha. + */ +void set_cairo_color_alpha(cairo_t *cr, const Color *color, double alpha); + +/** + * @brief Scale a design-space X value based on detected display width. + */ +double scale_value_x(const ScalingParams *params, double value); + +/** + * @brief Scale a design-space Y value based on detected display height. + */ +double scale_value_y(const ScalingParams *params, double value); + +/** + * @brief Scale a design-space value using average display scaling. + */ +double scale_value_avg(const ScalingParams *params, double value); + +/** + * @brief Get effective degree symbol spacing for the current display. + */ +int get_scaled_degree_spacing(const struct Config *config, + const ScalingParams *params); + +/** + * @brief Paint display background from optional PNG image or fallback color. + * @details If a PNG background path is configured and readable, the image is + * scaled to the current display size and painted first. Otherwise the + * configured background color is used. + */ +void paint_display_background(cairo_t *cr, const struct Config *config); + /** * @brief Calculate temperature fill width with bounds checking. * @param temp_value Current temperature value diff --git a/src/mods/dual.c b/src/mods/dual.c index d3ad658..3490435 100644 --- a/src/mods/dual.c +++ b/src/mods/dual.c @@ -66,6 +66,10 @@ static void draw_temperature_displays(cairo_t *cr, const int effective_bar_width = params->safe_bar_width; const int bar_x = (config->display_width - effective_bar_width) / 2; + const int bar_right = bar_x + effective_bar_width; + const int degree_spacing = get_scaled_degree_spacing(config, params); + const double top_temp_padding = scale_value_y(params, 8.0); + const double bottom_temp_padding = scale_value_y(params, 4.0); // Get slot configurations const char *slot_up = config->sensor_slot_up; @@ -123,17 +127,31 @@ static void draw_temperature_displays(cairo_t *cr, cairo_text_extents_t up_num_ext; cairo_text_extents(cr, up_num_str, &up_num_ext); - double up_width = (temp_up >= 100.0f) ? up_num_ext.width : up_ref_ext.width; - double up_temp_x = bar_x + (effective_bar_width - up_width) / 2.0; + double up_num_width = + (temp_up >= 100.0f) ? up_num_ext.width : up_ref_ext.width; + double up_degree_width = 0.0; - if (config->display_width == 240 && config->display_height == 240) - up_temp_x += 20; + if (get_slot_is_temp(data, slot_up)) + { + cairo_set_font_size(cr, up_font_size / 1.66); + cairo_text_extents_t up_degree_ext; + cairo_text_extents(cr, "\xC2\xB0", &up_degree_ext); + up_degree_width = up_degree_ext.width; + cairo_set_font_size(cr, up_font_size); + } + + const double up_total_width = up_num_width + + (get_slot_is_temp(data, slot_up) + ? degree_spacing + up_degree_width + : 0.0); + const double up_block_x = bar_right - up_total_width; + double up_temp_x = up_block_x + (up_num_width - up_num_ext.width) / 2.0; int offset_x_up = get_slot_offset_x(config, slot_up); if (offset_x_up != 0) up_temp_x += offset_x_up; - double up_temp_y = up_bar_y + 8 - up_font_ext.descent; + double up_temp_y = up_bar_y + top_temp_padding - up_font_ext.descent; int offset_y_up = get_slot_offset_y(config, slot_up); if (offset_y_up != 0) up_temp_y += offset_y_up; @@ -144,8 +162,7 @@ static void draw_temperature_displays(cairo_t *cr, // Draw degree symbol or unit if (get_slot_is_temp(data, slot_up)) { - const int degree_spacing = (config->display_degree_spacing > 0) ? config->display_degree_spacing : 16; - double degree_up_x = up_temp_x + up_width + degree_spacing; + double degree_up_x = up_block_x + up_num_width + degree_spacing; double degree_up_y = up_temp_y - up_num_ext.height * 0.40; cairo_set_font_size(cr, up_font_size / 1.66); cairo_move_to(cr, degree_up_x, degree_up_y); @@ -177,11 +194,27 @@ static void draw_temperature_displays(cairo_t *cr, cairo_text_extents_t down_num_ext; cairo_text_extents(cr, down_num_str, &down_num_ext); - double down_width = (temp_down >= 100.0f) ? down_num_ext.width : down_ref_ext.width; - double down_temp_x = bar_x + (effective_bar_width - down_width) / 2.0; + double down_num_width = + (temp_down >= 100.0f) ? down_num_ext.width : down_ref_ext.width; + double down_degree_width = 0.0; + + if (get_slot_is_temp(data, slot_down)) + { + cairo_set_font_size(cr, down_font_size / 1.66); + cairo_text_extents_t down_degree_ext; + cairo_text_extents(cr, "\xC2\xB0", &down_degree_ext); + down_degree_width = down_degree_ext.width; + cairo_set_font_size(cr, down_font_size); + } - if (config->display_width == 240 && config->display_height == 240) - down_temp_x += 20; + const double down_total_width = + down_num_width + + (get_slot_is_temp(data, slot_down) + ? degree_spacing + down_degree_width + : 0.0); + const double down_block_x = bar_right - down_total_width; + double down_temp_x = + down_block_x + (down_num_width - down_num_ext.width) / 2.0; int offset_x_down = get_slot_offset_x(config, slot_down); if (offset_x_down != 0) @@ -189,7 +222,8 @@ static void draw_temperature_displays(cairo_t *cr, // Use the actual bar height for positioning uint16_t effective_down_height = down_active ? bar_height_down : 0; - double down_temp_y = down_bar_y + effective_down_height - 4 + down_font_ext.ascent; + double down_temp_y = down_bar_y + effective_down_height - + bottom_temp_padding + down_font_ext.ascent; int offset_y_down = get_slot_offset_y(config, slot_down); if (offset_y_down != 0) down_temp_y += offset_y_down; @@ -200,8 +234,8 @@ static void draw_temperature_displays(cairo_t *cr, // Draw degree symbol or unit if (get_slot_is_temp(data, slot_down)) { - const int degree_spacing = (config->display_degree_spacing > 0) ? config->display_degree_spacing : 16; - double degree_down_x = down_temp_x + down_width + degree_spacing; + double degree_down_x = + down_block_x + down_num_width + degree_spacing; double degree_down_y = down_temp_y - down_num_ext.height * 0.40; cairo_set_font_size(cr, down_font_size / 1.66); cairo_move_to(cr, degree_down_x, degree_down_y); @@ -228,9 +262,10 @@ static void draw_single_temperature_bar_slot(cairo_t *cr, const float max_temp = get_slot_max_scale(config, slot_value); const int fill_width = calculate_temp_fill_width(temp_value, bar_width, max_temp); + const double bar_alpha = config->layout_bar_opacity; // Background - set_cairo_color(cr, &config->layout_bar_color_background); + set_cairo_color_alpha(cr, &config->layout_bar_color_background, bar_alpha); draw_rounded_rectangle_path(cr, bar_x, bar_y, bar_width, bar_height, params->corner_radius); cairo_fill(cr); @@ -239,7 +274,7 @@ static void draw_single_temperature_bar_slot(cairo_t *cr, if (fill_width > 0) { Color fill_color = get_slot_bar_color(config, slot_value, temp_value); - set_cairo_color(cr, &fill_color); + set_cairo_color_alpha(cr, &fill_color, bar_alpha); if (fill_width >= 16) draw_rounded_rectangle_path(cr, bar_x, bar_y, fill_width, @@ -255,7 +290,7 @@ static void draw_single_temperature_bar_slot(cairo_t *cr, if (config->layout_bar_border_enabled && config->layout_bar_border > 0.0f) { cairo_set_line_width(cr, config->layout_bar_border); - set_cairo_color(cr, &config->layout_bar_color_border); + set_cairo_color_alpha(cr, &config->layout_bar_color_border, bar_alpha); draw_rounded_rectangle_path(cr, bar_x, bar_y, bar_width, bar_height, params->corner_radius); cairo_stroke(cr); @@ -422,9 +457,7 @@ static void render_display_content(cairo_t *cr, const struct Config *config, const monitor_sensor_data_t *data, const ScalingParams *params) { - // Draw main background - set_cairo_color(cr, &config->display_background_color); - cairo_paint(cr); + paint_display_background(cr, config); cairo_select_font_face(cr, config->font_face, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); @@ -547,8 +580,9 @@ void draw_dual_image(const struct Config *config) int screen_width = 0, screen_height = 0; const bool device_available = - get_liquidctl_data(config, device_uid, sizeof(device_uid), device_name, - sizeof(device_name), &screen_width, &screen_height); + get_cached_lcd_device_data(config, device_uid, sizeof(device_uid), + device_name, sizeof(device_name), + &screen_width, &screen_height); // Render dual display with device name for circular display detection if (!render_dual_display(config, &sensor_data, device_name)) diff --git a/src/srv/cc_conf.c b/src/srv/cc_conf.c index 23c6fa3..248cad4 100644 --- a/src/srv/cc_conf.c +++ b/src/srv/cc_conf.c @@ -158,22 +158,16 @@ int is_circular_display_device(const char *device_name, int screen_width, } /** - * @brief Check if device type is a supported Liquidctl device. + * @brief Check if a device exposes a usable UID for LCD uploads. */ -static int is_liquidctl_device(const char *type_str) +static int has_usable_device_uid(const json_t *dev) { - if (!type_str) + if (!dev) return 0; - const char *liquid_types[] = {"Liquidctl"}; - const size_t num_types = sizeof(liquid_types) / sizeof(liquid_types[0]); - - for (size_t i = 0; i < num_types; i++) - { - if (strcmp(type_str, liquid_types[i]) == 0) - return 1; - } - return 0; + const json_t *uid_val = json_object_get(dev, "uid"); + return uid_val && json_is_string(uid_val) && + json_string_value(uid_val) && json_string_value(uid_val)[0] != '\0'; } /** @@ -226,11 +220,21 @@ static const json_t *get_lcd_info_from_device(const json_t *dev) if (!channels) return NULL; - const json_t *lcd_channel = json_object_get(channels, "lcd"); - if (!lcd_channel) - return NULL; + const char *channel_keys[] = {"lcd", "display", "screen"}; + const size_t key_count = sizeof(channel_keys) / sizeof(channel_keys[0]); + + for (size_t i = 0; i < key_count; i++) + { + const json_t *lcd_channel = json_object_get(channels, channel_keys[i]); + if (!lcd_channel || !json_is_object(lcd_channel)) + continue; - return json_object_get(lcd_channel, "lcd_info"); + const json_t *lcd_info = json_object_get(lcd_channel, "lcd_info"); + if (lcd_info && json_is_object(lcd_info)) + return lcd_info; + } + + return NULL; } /** @@ -258,16 +262,16 @@ static void extract_lcd_dimensions(const json_t *dev, int *width, int *height) } /** - * @brief Initialize output parameters to default values. + * @brief Initialize cached LCD output parameters to default values. */ -static void initialize_liquidctl_output_params( - char *lcd_uid, size_t uid_size, int *found_liquidctl, int *screen_width, +static void initialize_cached_lcd_output_params( + char *lcd_uid, size_t uid_size, int *found_lcd_device, int *screen_width, int *screen_height, char *device_name, size_t name_size) { if (lcd_uid && uid_size > 0) lcd_uid[0] = '\0'; - if (found_liquidctl) - *found_liquidctl = 0; + if (found_lcd_device) + *found_lcd_device = 0; if (screen_width) *screen_width = 0; if (screen_height) @@ -277,15 +281,15 @@ static void initialize_liquidctl_output_params( } /** - * @brief Extract all information from a Liquidctl device. + * @brief Extract all information from a CoolerControl LCD device. */ -static void extract_liquidctl_device_info(const json_t *dev, char *lcd_uid, - size_t uid_size, int *found_liquidctl, - int *screen_width, int *screen_height, - char *device_name, size_t name_size) +static void extract_lcd_device_info(const json_t *dev, char *lcd_uid, + size_t uid_size, int *found_lcd_device, + int *screen_width, int *screen_height, + char *device_name, size_t name_size) { - if (found_liquidctl) - *found_liquidctl = 1; + if (found_lcd_device) + *found_lcd_device = 1; extract_device_uid(dev, lcd_uid, uid_size); extract_device_name(dev, device_name, name_size); @@ -293,8 +297,9 @@ static void extract_liquidctl_device_info(const json_t *dev, char *lcd_uid, } /** - * @brief Check if a Liquidctl device has an LCD display. - * @details Verifies that lcd_info exists in info.channels.lcd path. + * @brief Check if a CoolerControl device has an LCD display. + * @details Verifies that a supported channel exposes lcd_info with valid + * screen dimensions. */ static int has_lcd_display(const json_t *dev) { @@ -311,13 +316,14 @@ static int has_lcd_display(const json_t *dev) } /** - * @brief Search for Liquidctl device with LCD in devices array. - * @details Only selects Liquidctl devices that have a valid LCD display. + * @brief Search for the first CoolerControl LCD device in devices array. + * @details Selects the first device that exposes a valid UID and LCD + * dimensions through the CoolerControl API. */ -static int search_liquidctl_device(const json_t *devices, char *lcd_uid, - size_t uid_size, int *found_liquidctl, - int *screen_width, int *screen_height, - char *device_name, size_t name_size) +static int search_lcd_device(const json_t *devices, char *lcd_uid, + size_t uid_size, int *found_lcd_device, + int *screen_width, int *screen_height, + char *device_name, size_t name_size) { const size_t device_count = json_array_size(devices); for (size_t i = 0; i < device_count; i++) @@ -327,21 +333,30 @@ static int search_liquidctl_device(const json_t *devices, char *lcd_uid, continue; const char *type_str = extract_device_type_from_json(dev); - if (!is_liquidctl_device(type_str)) + const json_t *name_val = json_object_get(dev, "name"); + const char *name = name_val ? json_string_value(name_val) : "unknown"; + + if (!has_usable_device_uid(dev)) + { + log_message(LOG_INFO, + "Skipping CoolerControl device without usable UID: %s [%s]", + name ? name : "unknown", + type_str ? type_str : "unknown type"); continue; + } if (!has_lcd_display(dev)) { - const json_t *name_val = json_object_get(dev, "name"); - const char *name = name_val ? json_string_value(name_val) : "unknown"; - log_message(LOG_INFO, "Skipping Liquidctl device without LCD: %s", - name ? name : "unknown"); + log_message(LOG_INFO, + "Skipping CoolerControl device without LCD info: %s [%s]", + name ? name : "unknown", + type_str ? type_str : "unknown type"); continue; } - extract_liquidctl_device_info(dev, lcd_uid, uid_size, found_liquidctl, - screen_width, screen_height, device_name, - name_size); + extract_lcd_device_info(dev, lcd_uid, uid_size, found_lcd_device, + screen_width, screen_height, device_name, + name_size); return 1; } @@ -351,17 +366,17 @@ static int search_liquidctl_device(const json_t *devices, char *lcd_uid, /** * @brief Parse devices JSON and extract LCD UID, display info and device name. */ -static int parse_liquidctl_data(const char *json, char *lcd_uid, - size_t uid_size, int *found_liquidctl, - int *screen_width, int *screen_height, - char *device_name, size_t name_size) +static int parse_lcd_device_data(const char *json, char *lcd_uid, + size_t uid_size, int *found_lcd_device, + int *screen_width, int *screen_height, + char *device_name, size_t name_size) { if (!json) return 0; - initialize_liquidctl_output_params(lcd_uid, uid_size, found_liquidctl, - screen_width, screen_height, device_name, - name_size); + initialize_cached_lcd_output_params(lcd_uid, uid_size, found_lcd_device, + screen_width, screen_height, + device_name, name_size); json_error_t error; json_t *root = json_loads(json, 0, &error); @@ -378,9 +393,9 @@ static int parse_liquidctl_data(const char *json, char *lcd_uid, return 0; } - int result = search_liquidctl_device(devices, lcd_uid, uid_size, - found_liquidctl, screen_width, - screen_height, device_name, name_size); + int result = search_lcd_device(devices, lcd_uid, uid_size, + found_lcd_device, screen_width, + screen_height, device_name, name_size); json_decref(root); return result; } @@ -491,13 +506,14 @@ static int process_device_cache_response(const http_response *chunk) /* Populate device name cache for ALL devices (used by sensor system) */ populate_device_name_cache(chunk->data); - int found_liquidctl = 0; - int result = parse_liquidctl_data( + int found_lcd_device = 0; + int result = parse_lcd_device_data( chunk->data, device_cache.device_uid, sizeof(device_cache.device_uid), - &found_liquidctl, &device_cache.screen_width, &device_cache.screen_height, - device_cache.device_name, sizeof(device_cache.device_name)); + &found_lcd_device, &device_cache.screen_width, + &device_cache.screen_height, device_cache.device_name, + sizeof(device_cache.device_name)); - if (result && found_liquidctl) + if (result && found_lcd_device) { device_cache.initialized = 1; device_cache.is_circular = is_circular_display_device( @@ -566,11 +582,12 @@ static int initialize_device_cache(const Config *config) } /** - * @brief Get complete Liquidctl device information from cache. + * @brief Get cached LCD device information. */ -int get_liquidctl_data(const Config *config, char *device_uid, size_t uid_size, - char *device_name, size_t name_size, int *screen_width, - int *screen_height) +int get_cached_lcd_device_data(const Config *config, char *device_uid, + size_t uid_size, char *device_name, + size_t name_size, int *screen_width, + int *screen_height) { if (!initialize_device_cache(config)) { diff --git a/src/srv/cc_conf.h b/src/srv/cc_conf.h index 678621c..745fb9d 100644 --- a/src/srv/cc_conf.h +++ b/src/srv/cc_conf.h @@ -40,13 +40,14 @@ int cc_safe_strcpy(char *restrict dest, size_t dest_size, const char *restrict src); /** - * @brief Get complete Liquidctl device information (UID, name, screen - * dimensions) from cache. - * @details Reads all LCD device information from cache (no API call). + * @brief Get cached LCD device information (UID, name, screen dimensions). + * @details Reads the selected CoolerControl LCD device information from cache + * without performing an additional API call. */ -int get_liquidctl_data(const struct Config *config, char *device_uid, - size_t uid_size, char *device_name, size_t name_size, - int *screen_width, int *screen_height); +int get_cached_lcd_device_data(const struct Config *config, char *device_uid, + size_t uid_size, char *device_name, + size_t name_size, int *screen_width, + int *screen_height); /** * @brief Initialize device information cache.