Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .SRCINFO
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.0.1
3.0.2
24 changes: 12 additions & 12 deletions docs/coolercontrol-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand All @@ -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**:
```
Expand Down Expand Up @@ -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,
Expand All @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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**:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
78 changes: 39 additions & 39 deletions docs/developer-guide.md
Original file line number Diff line number Diff line change
@@ -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

---
Expand All @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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

---
Expand Down Expand Up @@ -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_<PID>.txt`)

### API Endpoints Used
Expand Down Expand Up @@ -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

---
Expand Down Expand Up @@ -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

---
Expand All @@ -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

---
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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:**
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -745,20 +745,20 @@ 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 |

#### Internal Helpers (16 functions)

```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
```
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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:**
Expand Down Expand Up @@ -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)
6 changes: 3 additions & 3 deletions docs/display-modes.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,15 +403,15 @@ 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
6. `send_image_to_lcd()` → LCD upload

#### 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
Expand Down Expand Up @@ -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;
Expand Down
Loading
Loading