diff --git a/.SRCINFO b/.SRCINFO
index bcc031c..48b7419 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,6 +1,6 @@
pkgbase = coolerdash
- pkgdesc = Monitor telemetry data on an AIO liquid cooler with an integrated LCD display
- pkgver = 2.2.6
+ pkgdesc = Plug-in for CoolerControl that extends the LCD functionality with additional features
+ pkgver = 3.0.0
pkgrel = 1
url = https://github.com/damachine/coolerdash
install = coolerdash.install
@@ -10,11 +10,6 @@ pkgbase = coolerdash
makedepends = make
makedepends = pkg-config
makedepends = git
- depends = cairo
- depends = coolercontrol
- depends = jansson
- depends = libcurl-gnutls
- depends = ttf-roboto
provides = coolerdash-git
conflicts = coolerdash-git
replaces = coolerdash-git
diff --git a/.github/workflows/install.yml b/.github/workflows/install.yml
index 6be6128..b4dd5fd 100644
--- a/.github/workflows/install.yml
+++ b/.github/workflows/install.yml
@@ -23,35 +23,35 @@ jobs:
- distro: "ubuntu:24.04"
name: "Ubuntu 24.04 LTS"
pre_install: "apt-get update"
- install_deps: "apt-get install -y sudo systemd libcairo2-dev libcurl4-openssl-dev build-essential pkg-config libjansson-dev fonts-roboto file"
+ install_deps: "apt-get install -y sudo systemd libcairo2-dev libcurl4-openssl-dev build-essential pkg-config libjansson-dev libsodium-dev fonts-roboto file"
- distro: "debian:13"
name: "Debian 13 (Trixie)"
pre_install: "apt-get update"
- install_deps: "apt-get install -y sudo systemd libcairo2-dev libcurl4-openssl-dev build-essential pkg-config libjansson-dev fonts-roboto file"
+ install_deps: "apt-get install -y sudo systemd libcairo2-dev libcurl4-openssl-dev build-essential pkg-config libjansson-dev libsodium-dev fonts-roboto file"
# Fedora family (independent from RHEL)
- distro: "fedora:42"
name: "Fedora 42"
pre_install: "dnf update -y"
- install_deps: "dnf install -y sudo systemd cairo-devel libcurl-devel gcc make pkg-config jansson-devel google-roboto-fonts file"
+ install_deps: "dnf install -y sudo systemd cairo-devel libcurl-devel gcc make pkg-config jansson-devel libsodium-devel google-roboto-fonts file"
# RHEL/CentOS family (RHEL-compatible)
- distro: "quay.io/centos/centos:stream9"
name: "CentOS Stream 9 (RHEL 9 compatible)"
pre_install: "dnf update -y && dnf install -y epel-release && dnf config-manager --set-enabled crb && dnf makecache"
- install_deps: "dnf install -y sudo systemd cairo-devel libcurl-devel gcc make pkg-config jansson-devel google-roboto-fonts file"
+ install_deps: "dnf install -y sudo systemd cairo-devel libcurl-devel gcc make pkg-config jansson-devel libsodium-devel google-roboto-fonts file"
# openSUSE family
- distro: "opensuse/tumbleweed"
name: "openSUSE Tumbleweed"
pre_install: "zypper refresh"
- install_deps: "zypper install -y tar sudo systemd cairo-devel libcurl-devel gcc make pkg-config libjansson-devel google-roboto-fonts file"
+ install_deps: "zypper install -y tar sudo systemd cairo-devel libcurl-devel gcc make pkg-config libjansson-devel libsodium-devel google-roboto-fonts file"
- distro: "opensuse/leap:16.0"
name: "openSUSE Leap 16.0"
pre_install: "zypper refresh"
- install_deps: "zypper install -y sudo systemd cairo-devel libcurl-devel gcc make pkg-config libjansson-devel google-roboto-fonts file"
+ install_deps: "zypper install -y sudo systemd cairo-devel libcurl-devel gcc make pkg-config libjansson-devel libsodium-devel google-roboto-fonts file"
container:
image: ${{ matrix.distro }}
@@ -156,22 +156,6 @@ jobs:
echo "⚠️ Manual page not found"
fi
- # Check systemd helperd service
- if [ -f "/tmp/install-test/usr/lib/systemd/system/coolerdash-helperd.service" ]; then
- echo "✅ Systemd helperd service installed"
- else
- echo "❌ Systemd helperd service not found"
- exit 1
- fi
-
- # Check systemd startup-delay drop-in
- if [ -f "/tmp/install-test/etc/systemd/system/cc-plugin-coolerdash.service.d/startup-delay.conf" ]; then
- echo "✅ Systemd startup-delay drop-in installed"
- else
- echo "❌ Systemd startup-delay drop-in not found"
- exit 1
- fi
-
# Check udev rules
if [ -f "/tmp/install-test/usr/lib/udev/rules.d/99-coolerdash.rules" ]; then
echo "✅ Udev rules installed"
@@ -205,7 +189,7 @@ jobs:
- name: Setup Arch Linux
run: |
pacman -Syu --noconfirm
- pacman -S --noconfirm cairo libcurl-gnutls gcc make pkg-config jansson ttf-roboto sudo systemd file
+ pacman -S --noconfirm cairo libcurl-gnutls gcc make pkg-config jansson libsodium ttf-roboto sudo systemd file
- name: Test make install on Arch
run: |
@@ -233,22 +217,6 @@ jobs:
exit 1
fi
- # Check systemd helperd service
- if [ -f "/tmp/install-test/usr/lib/systemd/system/coolerdash-helperd.service" ]; then
- echo "✅ Systemd helperd service installed"
- else
- echo "❌ Systemd helperd service not found"
- exit 1
- fi
-
- # Check systemd startup-delay drop-in
- if [ -f "/tmp/install-test/etc/systemd/system/cc-plugin-coolerdash.service.d/startup-delay.conf" ]; then
- echo "✅ Systemd startup-delay drop-in installed"
- else
- echo "❌ Systemd startup-delay drop-in not found"
- exit 1
- fi
-
# Check udev rules
if [ -f "/tmp/install-test/usr/lib/udev/rules.d/99-coolerdash.rules" ]; then
echo "✅ Udev rules installed"
diff --git a/Makefile b/Makefile
index d91ab85..6eacab4 100644
--- a/Makefile
+++ b/Makefile
@@ -110,41 +110,41 @@ install-deps:
case $$DISTRO in \
arch) \
printf "$(GREEN)Installing dependencies for Arch Linux/Manjaro...$(RESET)\n"; \
- $(SUDO) pacman -S --needed cairo libcurl-gnutls gcc make pkg-config ttf-roboto jansson || { \
+ $(SUDO) pacman -S --needed cairo libcurl-gnutls gcc make pkg-config ttf-roboto jansson || { \
printf "$(RED)Error installing dependencies!$(RESET)\n"; \
- printf "$(YELLOW)Please run manually:$(RESET) $(SUDO) pacman -S cairo libcurl-gnutls gcc make pkg-config ttf-roboto jansson\n"; \
+ printf "$(YELLOW)Please run manually:$(RESET) $(SUDO) pacman -S cairo libcurl-gnutls gcc make pkg-config ttf-roboto jansson\n"; \
exit 1; \
}; \
;; \
debian) \
printf "$(GREEN)Installing dependencies for Ubuntu/Debian...$(RESET)\n"; \
- $(SUDO) apt update && $(SUDO) apt install -y libcairo2-dev libcurl4-openssl-dev gcc make pkg-config fonts-roboto libjansson-dev || { \
+ $(SUDO) apt update && $(SUDO) apt install -y libcairo2-dev libcurl4-openssl-dev gcc make pkg-config fonts-roboto libjansson-dev || { \
printf "$(RED)Error installing dependencies!$(RESET)\n"; \
- printf "$(YELLOW)Please run manually:$(RESET) $(SUDO) apt install libcairo2-dev libcurl4-openssl-dev gcc make pkg-config fonts-roboto libjansson-dev\n"; \
+ printf "$(YELLOW)Please run manually:$(RESET) $(SUDO) apt install libcairo2-dev libcurl4-openssl-dev gcc make pkg-config fonts-roboto libjansson-dev\n"; \
exit 1; \
}; \
;; \
fedora) \
printf "$(GREEN)Installing dependencies for Fedora...$(RESET)\n"; \
- $(SUDO) dnf install -y cairo-devel libcurl-devel gcc make pkg-config google-roboto-fonts jansson-devel || { \
+ $(SUDO) dnf install -y cairo-devel libcurl-devel gcc make pkg-config google-roboto-fonts jansson-devel || { \
printf "$(RED)Error installing dependencies!$(RESET)\n"; \
- printf "$(YELLOW)Please run manually:$(RESET) $(SUDO) dnf install cairo-devel libcurl-devel gcc make pkg-config google-roboto-fonts jansson-devel\n"; \
+ printf "$(YELLOW)Please run manually:$(RESET) $(SUDO) dnf install cairo-devel libcurl-devel gcc make pkg-config google-roboto-fonts jansson-devel\n"; \
exit 1; \
}; \
;; \
rhel) \
printf "$(GREEN)Installing dependencies for RHEL/CentOS...$(RESET)\n"; \
- $(SUDO) yum install -y cairo-devel libcurl-devel gcc make pkg-config google-roboto-fonts jansson-devel || { \
+ $(SUDO) yum install -y cairo-devel libcurl-devel gcc make pkg-config google-roboto-fonts jansson-devel || { \
printf "$(RED)Error installing dependencies!$(RESET)\n"; \
- printf "$(YELLOW)Please run manually:$(RESET) $(SUDO) yum install cairo-devel libcurl-devel gcc make pkg-config google-roboto-fonts jansson-devel\n"; \
+ printf "$(YELLOW)Please run manually:$(RESET) $(SUDO) yum install cairo-devel libcurl-devel gcc make pkg-config google-roboto-fonts jansson-devel\n"; \
exit 1; \
}; \
;; \
opensuse) \
printf "$(GREEN)Installing dependencies for openSUSE...$(RESET)\n"; \
- $(SUDO) zypper install -y cairo-devel libcurl-devel gcc make pkg-config google-roboto-fonts libjansson-devel || { \
+ $(SUDO) zypper install -y cairo-devel libcurl-devel gcc make pkg-config google-roboto-fonts libjansson-devel || { \
printf "$(RED)Error installing dependencies!$(RESET)\n"; \
- printf "$(YELLOW)Please run manually:$(RESET) $(SUDO) zypper install cairo-devel libcurl-devel gcc make pkg-config google-roboto-fonts libjansson-devel\n"; \
+ printf "$(YELLOW)Please run manually:$(RESET) $(SUDO) zypper install cairo-devel libcurl-devel gcc make pkg-config google-roboto-fonts libjansson-devel\n"; \
exit 1; \
}; \
;; \
@@ -284,10 +284,6 @@ install: check-deps $(TARGET)
@install -m644 $(MANIFEST) "$(DESTDIR)/etc/coolercontrol/plugins/coolerdash/manifest.toml"
@sed -i 's/{{VERSION}}/$(VERSION)/g' "$(DESTDIR)/etc/coolercontrol/plugins/coolerdash/manifest.toml"
@sed -i 's/{{VERSION}}/$(VERSION)/g' "$(DESTDIR)/etc/coolercontrol/plugins/coolerdash/ui/index.html"
- @install -Dm644 etc/systemd/cc-plugin-coolerdash.service.d/startup-delay.conf "$(DESTDIR)/etc/systemd/system/cc-plugin-coolerdash.service.d/startup-delay.conf"
- @install -Dm644 etc/systemd/coolerdash-helperd.service "$(DESTDIR)/usr/lib/systemd/system/coolerdash-helperd.service"
- @printf " $(GREEN)Drop-in:$(RESET) $(DESTDIR)/etc/systemd/system/cc-plugin-coolerdash.service.d/startup-delay.conf\n"
- @printf " $(GREEN)Service:$(RESET) $(DESTDIR)/usr/lib/systemd/system/coolerdash-helperd.service\n"
@printf " $(GREEN)Binary:$(RESET) $(DESTDIR)/usr/libexec/coolerdash/coolerdash\n"
@printf " $(GREEN)Config JSON:$(RESET) $(DESTDIR)/etc/coolercontrol/plugins/coolerdash/config.json\n"
@printf " $(GREEN)Web UI:$(RESET) $(DESTDIR)/etc/coolercontrol/plugins/coolerdash/ui/index.html\n"
@@ -324,8 +320,11 @@ install: check-deps $(TARGET)
@printf "$(YELLOW)Next steps:$(RESET)\n"
@if [ "$(REALOS)" = "yes" ]; then \
$(SUDO) systemctl daemon-reload 2>/dev/null || true; \
- $(SUDO) systemctl enable --now coolerdash-helperd.service 2>/dev/null || true; \
$(SUDO) systemctl restart coolercontrold.service 2>/dev/null || true; \
+ $(SUDO) systemctl restart cc-plugin-coolerdash.service 2>/dev/null || true; \
+ $(SUDO) systemctl stop coolerdash-helperd.service 2>/dev/null || true; \
+ $(SUDO) systemctl disable coolerdash-helperd.service 2>/dev/null || true; \
+ $(SUDO) rm -f /usr/lib/systemd/system/coolerdash-helperd.service; \
fi
@printf " $(PURPLE)Reload systemd:$(RESET) systemctl daemon-reload\n"
@printf " $(PURPLE)Restart CoolerControl:$(RESET) systemctl restart coolercontrold.service\n"
diff --git a/PKGBUILD b/PKGBUILD
index 2381770..eb65be8 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -1,20 +1,18 @@
# Maintainer: damachin3 (damachine3 at proton dot me)
# Website: https://github.com/damachine/coolerdash
-
# This PKGBUILD is for building the coolerdash package from local source.
# It assumes the source code is already present in the current directory.
-
pkgname=coolerdash
pkgver=$(cat VERSION)
pkgrel=1
provides=('coolerdash-git')
replaces=('coolerdash-git')
conflicts=('coolerdash-git')
-pkgdesc="Monitor telemetry data on an AIO liquid cooler with an integrated LCD display"
+pkgdesc="Plug-in for CoolerControl that extends the LCD functionality with additional features"
arch=('x86_64')
url="https://github.com/damachine/coolerdash"
license=('MIT')
-depends=('cairo' 'coolercontrol' 'jansson' 'libcurl-gnutls' 'ttf-roboto')
+depends=()
makedepends=('gcc' 'make' 'pkg-config' 'git')
optdepends=()
backup=('etc/coolercontrol/plugins/coolerdash/config.json')
@@ -56,9 +54,6 @@ build() {
cp -a etc/applications/coolerdash.desktop "${srcdir}/etc/applications/"
cp -a etc/icons/coolerdash.svg "${srcdir}/etc/icons/"
cp -a etc/udev/rules.d/99-coolerdash.rules "${srcdir}/etc/udev/rules.d/"
- mkdir -p "${srcdir}/etc/systemd/cc-plugin-coolerdash.service.d"
- cp -a etc/systemd/coolerdash-helperd.service "${srcdir}/etc/systemd/"
- cp -a etc/systemd/cc-plugin-coolerdash.service.d/startup-delay.conf "${srcdir}/etc/systemd/cc-plugin-coolerdash.service.d/"
}
check() {
@@ -96,8 +91,6 @@ package() {
install -Dm644 "${srcdir}/etc/applications/coolerdash.desktop" "${pkgdir}/usr/share/applications/coolerdash.desktop"
install -Dm644 "${srcdir}/etc/udev/rules.d/99-coolerdash.rules" "${pkgdir}/usr/lib/udev/rules.d/99-coolerdash.rules"
install -Dm644 "${srcdir}/etc/icons/coolerdash.svg" "${pkgdir}/usr/share/icons/hicolor/scalable/apps/coolerdash.svg"
- install -Dm644 "${srcdir}/etc/systemd/coolerdash-helperd.service" "${pkgdir}/usr/lib/systemd/system/coolerdash-helperd.service"
- install -Dm644 "${srcdir}/etc/systemd/cc-plugin-coolerdash.service.d/startup-delay.conf" "${pkgdir}/etc/systemd/system/cc-plugin-coolerdash.service.d/startup-delay.conf"
install -Dm644 "${srcdir}/LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
}
diff --git a/VERSION b/VERSION
index bda8fbe..4a36342 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.2.6
+3.0.0
diff --git a/aur/.SRCINFO b/aur/.SRCINFO
index b584a40..19868c7 100644
--- a/aur/.SRCINFO
+++ b/aur/.SRCINFO
@@ -1,6 +1,6 @@
pkgbase = coolerdash-git
- pkgdesc = Monitor telemetry data on an AIO liquid cooler with an integrated LCD display
- pkgver =
+ pkgdesc = Plug-in for CoolerControl that extends the LCD functionality with additional features
+ pkgver =
pkgrel = 1
url = https://github.com/damachine/coolerdash
install = coolerdash.install
diff --git a/aur/PKGBUILD b/aur/PKGBUILD
index a08dfc4..73f0ccc 100644
--- a/aur/PKGBUILD
+++ b/aur/PKGBUILD
@@ -1,13 +1,12 @@
# Maintainer: damachin3 (damachine3 at proton dot me)
# Website: https://github.com/damachine/coolerdash
-
pkgname=coolerdash-git
pkgver=
pkgrel=1
provides=('coolerdash')
replaces=('coolerdash')
conflicts=('coolerdash')
-pkgdesc="Monitor telemetry data on an AIO liquid cooler with an integrated LCD display"
+pkgdesc="Plug-in for CoolerControl that extends the LCD functionality with additional features"
arch=('x86_64')
url="https://github.com/damachine/coolerdash"
license=('MIT')
@@ -77,8 +76,6 @@ package() {
install -Dm644 "${srcdir}/${pkgname}/etc/applications/coolerdash.desktop" "${pkgdir}/usr/share/applications/coolerdash.desktop"
install -Dm644 "${srcdir}/${pkgname}/etc/udev/rules.d/99-coolerdash.rules" "${pkgdir}/usr/lib/udev/rules.d/99-coolerdash.rules"
install -Dm644 "${srcdir}/${pkgname}/etc/icons/coolerdash.svg" "${pkgdir}/usr/share/icons/hicolor/scalable/apps/coolerdash.svg"
- install -Dm644 "${srcdir}/${pkgname}/etc/systemd/coolerdash-helperd.service" "${pkgdir}/usr/lib/systemd/system/coolerdash-helperd.service"
- install -Dm644 "${srcdir}/${pkgname}/etc/systemd/cc-plugin-coolerdash.service.d/startup-delay.conf" "${pkgdir}/etc/systemd/system/cc-plugin-coolerdash.service.d/startup-delay.conf"
install -Dm644 "${srcdir}/${pkgname}/LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
}
diff --git a/aur/coolerdash.install b/aur/coolerdash.install
index 1142640..5d8c117 100644
--- a/aur/coolerdash.install
+++ b/aur/coolerdash.install
@@ -40,39 +40,36 @@ post_install() {
udevadm trigger --subsystem-match=usb
fi
- # Migrate helperd from /etc to /usr/lib
+ # Remove legacy helperd service (no longer part of this project)
rm -f /etc/systemd/system/multi-user.target.wants/coolerdash-helperd.service
rm -f /etc/systemd/system/coolerdash-helperd.service
+ rm -f /usr/lib/systemd/system/coolerdash-helperd.service
systemctl daemon-reload
- # Enable helperd
- if systemctl list-unit-files coolerdash-helperd.service | grep -q coolerdash-helperd; then
- systemctl enable --now coolerdash-helperd.service || echo "Note: coolerdash-helperd.service failed. Enable manually."
- fi
-
# Restart CoolerControl
if systemctl list-unit-files coolercontrold.service | grep -q coolercontrold; then
systemctl restart coolercontrold.service || echo "Note: CoolerControl restart failed."
fi
+ # Restart plugin service
+ if systemctl list-unit-files cc-plugin-coolerdash.service | grep -q cc-plugin-coolerdash; then
+ systemctl restart cc-plugin-coolerdash.service || echo "Note: Plugin restart failed."
+ fi
+
echo "================================================================"
echo "CoolerDash installed successfully."
echo "================================================================"
}
post_upgrade() {
- # Migrate helperd from /etc to /usr/lib
+ # Remove legacy helperd service (no longer part of this project)
rm -f /etc/systemd/system/multi-user.target.wants/coolerdash-helperd.service
rm -f /etc/systemd/system/coolerdash-helperd.service
+ rm -f /usr/lib/systemd/system/coolerdash-helperd.service
systemctl daemon-reload
- # Enable helperd
- if systemctl list-unit-files coolerdash-helperd.service | grep -q coolerdash-helperd; then
- systemctl enable --now coolerdash-helperd.service || echo "Note: coolerdash-helperd.service failed. Enable manually."
- fi
-
# Restart plugin
if systemctl list-unit-files cc-plugin-coolerdash.service | grep -q cc-plugin-coolerdash; then
systemctl restart cc-plugin-coolerdash.service || echo "Note: Plugin restart failed."
diff --git a/coolerdash.install b/coolerdash.install
index 1142640..5d8c117 100644
--- a/coolerdash.install
+++ b/coolerdash.install
@@ -40,39 +40,36 @@ post_install() {
udevadm trigger --subsystem-match=usb
fi
- # Migrate helperd from /etc to /usr/lib
+ # Remove legacy helperd service (no longer part of this project)
rm -f /etc/systemd/system/multi-user.target.wants/coolerdash-helperd.service
rm -f /etc/systemd/system/coolerdash-helperd.service
+ rm -f /usr/lib/systemd/system/coolerdash-helperd.service
systemctl daemon-reload
- # Enable helperd
- if systemctl list-unit-files coolerdash-helperd.service | grep -q coolerdash-helperd; then
- systemctl enable --now coolerdash-helperd.service || echo "Note: coolerdash-helperd.service failed. Enable manually."
- fi
-
# Restart CoolerControl
if systemctl list-unit-files coolercontrold.service | grep -q coolercontrold; then
systemctl restart coolercontrold.service || echo "Note: CoolerControl restart failed."
fi
+ # Restart plugin service
+ if systemctl list-unit-files cc-plugin-coolerdash.service | grep -q cc-plugin-coolerdash; then
+ systemctl restart cc-plugin-coolerdash.service || echo "Note: Plugin restart failed."
+ fi
+
echo "================================================================"
echo "CoolerDash installed successfully."
echo "================================================================"
}
post_upgrade() {
- # Migrate helperd from /etc to /usr/lib
+ # Remove legacy helperd service (no longer part of this project)
rm -f /etc/systemd/system/multi-user.target.wants/coolerdash-helperd.service
rm -f /etc/systemd/system/coolerdash-helperd.service
+ rm -f /usr/lib/systemd/system/coolerdash-helperd.service
systemctl daemon-reload
- # Enable helperd
- if systemctl list-unit-files coolerdash-helperd.service | grep -q coolerdash-helperd; then
- systemctl enable --now coolerdash-helperd.service || echo "Note: coolerdash-helperd.service failed. Enable manually."
- fi
-
# Restart plugin
if systemctl list-unit-files cc-plugin-coolerdash.service | grep -q cc-plugin-coolerdash; then
systemctl restart cc-plugin-coolerdash.service || echo "Note: Plugin restart failed."
diff --git a/docs/config-guide.md b/docs/config-guide.md
index a3276f8..097f56a 100644
--- a/docs/config-guide.md
+++ b/docs/config-guide.md
@@ -25,22 +25,27 @@ Configure connection to the CoolerControl daemon API.
```json
"daemon": {
"address": "http://localhost:11987",
- "password": "coolAdmin"
+ "password": "",
+ "password_encrypted": "enc:v1:..."
}
```
### Settings
- **`address`**: API endpoint URL (default: `http://localhost:11987`)
-- **`password`**: API authentication password (default: `coolAdmin`)
+- **`password_encrypted`**: Encrypted API password (standard field)
+- **`password`**: Legacy plaintext fallback; will be auto-migrated to `password_encrypted`
### HTTPS Example
```json
"daemon": {
"address": "https://192.168.1.100:11987",
- "password": "mySecurePassword123"
+ "password": "",
+ "password_encrypted": "enc:v1:..."
}
```
+> If `password` is set in plaintext, CoolerDash reads it once and rewrites the config with `password_encrypted` automatically.
+
---
## File Paths
@@ -187,12 +192,13 @@ Controls the safe area percentage used for rendering content (determines margin/
Display layout and spacing configuration. All positioning is now calculated dynamically from display dimensions.
### Example Configuration
-```ini
-[layout]
-bar_height=24
-bar_width=98
-bar_gap=12
-bar_border=2.0
+```json
+"layout": {
+ "bar_height": 24,
+ "bar_width": 98,
+ "bar_gap": 12,
+ "bar_border": 2.0
+}
```
### Settings
diff --git a/docs/coolercontrol-api.md b/docs/coolercontrol-api.md
index 786cd26..3f929ea 100644
--- a/docs/coolercontrol-api.md
+++ b/docs/coolercontrol-api.md
@@ -1050,7 +1050,7 @@ Program exit
struct Config {
// CoolerControl connection
char daemon_address[256]; // e.g., "http://127.0.0.1:11987"
- char daemon_password[128]; // CCAdmin password
+ char daemon_password[128]; // Decrypted CCAdmin password in memory
// Display settings
uint16_t display_width; // e.g., 640 (auto-detected if 0)
diff --git a/docs/developer-guide.md b/docs/developer-guide.md
index 8f6e6f3..5ff474c 100644
--- a/docs/developer-guide.md
+++ b/docs/developer-guide.md
@@ -17,10 +17,6 @@
7. [Rendering Pipeline](#rendering-pipeline)
8. [Function Reference](#function-reference)
9. [Development Guidelines](#development-guidelines)
-10. [Testing & Debugging](#testing--debugging)
-
----
-
## Project Overview
### Purpose
@@ -31,7 +27,7 @@ CoolerDash extends the LCD functionality of [CoolerControl](https://gitlab.com/c
- **Real-time Temperature Monitoring:** CPU/GPU sensor data via CoolerControl REST API
- **Adaptive Display Rendering:** Automatic circular/rectangular display detection
-- **Customizable UI:** Full color/layout/font configuration via INI file
+- **Customizable UI:** Full color/layout/font configuration via JSON
- **Secure Session Management:** HTTP Basic Auth with cookie-based session persistence
- **Efficient Caching:** One-time device information retrieval at startup
- **Systemd Integration:** Native service management with automatic startup
@@ -111,7 +107,7 @@ coolerdash/
│ ├── coolercontrol/plugins/coolerdash/config.json # User configuration
│ └── systemd/coolerdash.service
├── docs/ # Documentation
-│ ├── config.md # Configuration guide
+│ ├── config-guide.md # Configuration guide
│ ├── devices.md # Supported hardware
│ └── developer-guide.md # This file
├── Makefile # Build system
@@ -231,7 +227,7 @@ LIBS = $(shell pkg-config --libs cairo jansson libcurl) -lm
typedef struct {
// Daemon connection
char daemon_address[256]; // CoolerControl API URL
- char daemon_password[128]; // API password
+ char daemon_password[128]; // Decrypted API password (runtime)
// File paths
char paths_images[PATH_MAX]; // Shutdown image directory
@@ -591,10 +587,10 @@ double safe_y = params.safe_content_margin * config->display_height;
**Configuration Override (v1.96+):**
-```ini
-[display]
-# Manual override (recommended for testing/troubleshooting)
-shape = auto # or "rectangular" or "circular"
+```json
+"display": {
+ "shape": "auto"
+}
```
### Temperature Bar Rendering
@@ -676,7 +672,7 @@ int calculate_temp_fill_width(float temp, int max_width, float max_temp) {
```c
daemon_address = "http://localhost:11987"
-daemon_password = "coolAdmin"
+daemon_password = "" // Loaded from daemon.password_encrypted or legacy daemon.password
display_width = 0 // auto-detected from API
display_refresh_interval = 2.5
lcd_brightness = 80
@@ -686,7 +682,7 @@ lcd_brightness = 80
```json
{
- "daemon": { "address": "...", "password": "..." },
+ "daemon": { "address": "...", "password_encrypted": "enc:v1:..." },
"display": { "width": 0, "height": 0, "brightness": 80, "mode": "dual" },
"layout": { "bar_height": 30, "label_size": 18, "value_size": 24 },
"font": { "face": "Roboto" },
@@ -1109,8 +1105,8 @@ systemctl status coolercontrold
# Test API manually
curl -u CCAdmin:coolAdmin -X POST http://localhost:11987/login
-# Check config password
-grep daemon_password /etc/coolercontrol/plugins/coolerdash/config.json
+# Check encrypted password field
+grep 'password_encrypted\|password' /etc/coolercontrol/plugins/coolerdash/config.json
```
---
diff --git a/etc/coolercontrol/plugins/coolerdash/config.json b/etc/coolercontrol/plugins/coolerdash/config.json
index 62195fc..5570cde 100644
--- a/etc/coolercontrol/plugins/coolerdash/config.json
+++ b/etc/coolercontrol/plugins/coolerdash/config.json
@@ -2,8 +2,9 @@
"_comment": "CoolerDash Plugin Configuration - All values with defaults",
"daemon": {
- "address": "http://localhost:11987",
- "password": "coolAdmin"
+ "address": "https://localhost:11987",
+ "access_token": "",
+ "tls_skip_verify": 1
},
"paths": {
diff --git a/etc/coolercontrol/plugins/coolerdash/ui/index.html b/etc/coolercontrol/plugins/coolerdash/ui/index.html
index b1cdc73..5c59aff 100644
--- a/etc/coolercontrol/plugins/coolerdash/ui/index.html
+++ b/etc/coolercontrol/plugins/coolerdash/ui/index.html
@@ -582,13 +582,13 @@
-
Image Paths
+
Connection (Expert)
- Shutdown Image
- Image displayed when daemon stops (Default: /etc/coolercontrol/plugins/coolerdash/shutdown.png)
-
+ Accept Self-Signed TLS Certificate CC 4.0
+ Enable when using https:// with a self-signed certificate (e.g. localhost HTTPS in CC 4.0)
+
+ No — verify certificate (secure default)
+ Yes — skip verification (self-signed)
+
+
+
+ LCD Channel Name
+ LCD channel name used in CoolerControl API (Default: lcd)
+
Backup & Restore
@@ -1067,8 +1083,8 @@
System Environment
- Save
- Reset
+ Save & Restart
+ Reset to Defaults
@@ -1083,8 +1099,10 @@
System Environment
// ===== FACTORY DEFAULT CONFIGURATION =====
const FACTORY_DEFAULTS = {
daemon: {
- address: "http://localhost:11987",
- password: "coolAdmin"
+ address: "https://localhost:11987",
+ access_token: "",
+ tls_skip_verify: 1,
+ channel_name: "lcd"
},
paths: {
image_shutdown: "/etc/coolercontrol/plugins/coolerdash/shutdown.png"
@@ -1253,29 +1271,60 @@
System Environment
window.runPluginScript = function(mainFunction) { mainFunction(); };
}
+ // ===== AUTH HELPER =====
+ function buildAuthHeaders(token, extraHeaders) {
+ var headers = extraHeaders || {};
+ if (token) {
+ headers['Authorization'] = 'Bearer ' + token;
+ }
+ return headers;
+ }
+
// ===== SENSOR DISCOVERY =====
- async function discoverSensors(apiAddress, password) {
+ async function discoverSensors(apiAddress, token) {
try {
- const headers = { 'Content-Type': 'application/json' };
- if (password) {
- headers['Authorization'] = 'Basic ' + btoa('admin:' + password);
+ let devicesArr = [];
+ let statusDevices = [];
+
+ if (typeof getDevices === 'function') {
+ // CC iframe: use cc-plugin-lib (postMessage)
+ devicesArr = (await getDevices(true)) || [];
+ if (typeof getStatus === 'function') {
+ const st = await getStatus(true);
+ if (Array.isArray(st)) {
+ statusDevices = st;
+ } else if (st && Array.isArray(st.devices)) {
+ statusDevices = st.devices;
+ } else if (st instanceof Map) {
+ statusDevices = [...st.values()];
+ }
+ }
+ } else {
+ // Standalone: direct fetch
+ const devRes = await fetch(apiAddress + '/devices', {
+ headers: buildAuthHeaders(token)
+ });
+ const devData = devRes.ok ? await devRes.json() : { devices: [] };
+ devicesArr = devData.devices || [];
+
+ const statusRes = await fetch(apiAddress + '/status', {
+ method: 'POST',
+ headers: buildAuthHeaders(token, { 'Content-Type': 'application/json' }),
+ body: '{}'
+ });
+ if (statusRes.ok) {
+ const statusData = await statusRes.json();
+ statusDevices = statusData.devices || [];
+ }
}
- // GET /devices for device names
- const devRes = await fetch(apiAddress + '/devices', { headers: password ? { 'Authorization': headers['Authorization'] } : {} });
- const devData = devRes.ok ? await devRes.json() : { devices: [] };
const deviceNames = {};
- for (const dev of (devData.devices || [])) {
+ for (const dev of devicesArr) {
if (dev.uid) deviceNames[dev.uid] = dev.name || dev.uid;
}
- // POST /status for current sensor data
- const statusRes = await fetch(apiAddress + '/status', { method: 'POST', headers, body: '{}' });
- if (!statusRes.ok) return;
- const statusData = await statusRes.json();
-
const sensors = [];
- for (const dev of (statusData.devices || [])) {
+ for (const dev of statusDevices) {
const uid = dev.uid || '';
const devName = deviceNames[uid] || uid;
const lastStatus = Array.isArray(dev.status_history) && dev.status_history.length > 0
@@ -1523,7 +1572,6 @@
System Environment
var eSensorId = escapeHtml(sensorId);
var eLabel = escapeHtml(sc.label || '');
- // Sanitize all numeric values to break taint chain
var eFontSize = Number(sc.font_size_temp) || 0;
var eOffsetX = Number(sc.offset_x) || 0;
var eOffsetY = Number(sc.offset_y) || 0;
@@ -1687,16 +1735,13 @@
System Environment
var safeName = sensorId.replace(/[^a-zA-Z0-9]/g, '_');
var sc = {};
- // Threshold/offset fields (sanitize: numbers stay numbers, strings get escaped)
var fields = section.querySelectorAll('.sensor-field');
for (var f = 0; f < fields.length; f++) {
var field = fields[f].getAttribute('data-field');
if (field) {
if (field === 'label') {
- // Label is the only string field - store as-is (escaped on render)
sc[field] = String(fields[f].value || '');
} else {
- // All other fields are numeric - force to number
sc[field] = Number(fields[f].value) || 0;
}
}
@@ -1715,11 +1760,11 @@
System Environment
// ===== DEVICE DETECTION =====
var lastApiAddress = '';
- var lastApiPassword = '';
+ var lastApiToken = '';
- async function fetchDeviceInfo(apiAddress, password) {
+ async function fetchDeviceInfo(apiAddress, token) {
lastApiAddress = apiAddress;
- lastApiPassword = password;
+ lastApiToken = token;
var loadingEl = document.getElementById('device-loading');
var contentEl = document.getElementById('device-panel-content');
@@ -1730,23 +1775,56 @@
System Environment
errorEl.style.display = 'none';
try {
- var headers = {};
- if (password) {
- headers['Authorization'] = 'Basic ' + btoa('admin:' + password);
+ var devices = [];
+ // 1. Try getDevices() via postMessage. Timeout guards against early resolve.
+ if (typeof getDevices === 'function') {
+ try {
+ var _devTimeout = new Promise(function(res) { setTimeout(function() { res([]); }, 3000); });
+ devices = (await Promise.race([getDevices(true), _devTimeout])) || [];
+ } catch (e) { devices = []; }
+ }
+ // 2. Standalone fallback: direct fetch (blocked in CC iframe).
+ if (devices.length === 0 && window.parent === window) {
+ try {
+ var response = await fetch(apiAddress + '/devices', {
+ headers: buildAuthHeaders(token)
+ });
+ if (response.ok) {
+ var data = await response.json();
+ devices = data.devices || [];
+ }
+ } catch (fetchErr) {
+ throw new Error('API unreachable: ' + fetchErr.message +
+ ' \u2014 Check CoolerControl address and token.');
+ }
}
- var response = await fetch(apiAddress + '/devices', { headers: headers });
- if (!response.ok) throw new Error('HTTP ' + response.status);
- var data = await response.json();
- var devices = data.devices || [];
+ // Find Liquidctl device with LCD channel.
var found = null;
for (var i = 0; i < devices.length; i++) {
var dev = devices[i];
- var dtype = dev.type || '';
+ var dtype = dev.d_type || dev.type || '';
if (dtype === 'Liquidctl') {
- var lcdInfo = dev.info && dev.info.channels && dev.info.channels.lcd && dev.info.channels.lcd.lcd_info;
- if (lcdInfo && lcdInfo.screen_width > 0 && lcdInfo.screen_height > 0) {
+ // channels is a Map (postMessage) or plain object (REST) — handle both.
+ var channels = dev.info && dev.info.channels;
+ var lcdInfo = null;
+ if (channels) {
+ var channelVals = (channels instanceof Map)
+ ? Array.from(channels.values())
+ : Object.values(channels);
+ for (var c = 0; c < channelVals.length; c++) {
+ var ch = channelVals[c];
+ if (ch && ch.lcd_info &&
+ ch.lcd_info.screen_width > 0 &&
+ ch.lcd_info.screen_height > 0) {
+ lcdInfo = ch.lcd_info;
+ break;
+ }
+ }
+ }
+ if (lcdInfo) {
found = dev;
+ found._lcdInfo = lcdInfo;
break;
}
}
@@ -1760,29 +1838,25 @@
System Environment
document.getElementById('device-name').textContent = name;
document.getElementById('device-uid').textContent = uid;
- var firmware = (found.lc_info && found.lc_info.firmware_version) || '\u2014';
+ // lc_info not sent via postMessage; fall back to driver_info.version.
+ var firmware = (found.lc_info && found.lc_info.firmware_version)
+ || (found.info && found.info.driver_info && found.info.driver_info.version)
+ || '\u2014';
document.getElementById('device-firmware').textContent = firmware;
var liquidctlVer = (found.info && found.info.driver_info && found.info.driver_info.version) || '\u2014';
document.getElementById('device-liquidctl').textContent = liquidctlVer;
- var width = 0, height = 0;
- var channels = found.info && found.info.channels;
- if (channels) {
- for (var chKey in channels) {
- if (channels.hasOwnProperty(chKey) && channels[chKey].lcd_info) {
- width = channels[chKey].lcd_info.screen_width || 0;
- height = channels[chKey].lcd_info.screen_height || 0;
- break;
- }
- }
- }
+ var lcdI = found._lcdInfo;
+ var width = lcdI ? (lcdI.screen_width || 0) : 0;
+ var height = lcdI ? (lcdI.screen_height || 0) : 0;
var resEl = document.getElementById('device-resolution');
var shapeEl = document.getElementById('device-shape');
if (width > 0 && height > 0) {
resEl.textContent = width + ' \u00D7 ' + height + ' px';
- var isCircular = name.includes('Kraken') && (width > 240 || height > 240);
+ // Kraken displays are circular.
+ var isCircular = name.includes('Kraken') || (width === height && width >= 240);
shapeEl.textContent = isCircular ? 'Circular' : 'Rectangular';
} else {
resEl.textContent = 'Not available';
@@ -1809,47 +1883,58 @@
System Environment
document.getElementById('device-status').innerHTML =
'
Detection failed';
document.getElementById('device-error-text').textContent =
- 'Could not connect to CoolerControl API (' + error.message + ').';
+ error.message || 'Failed to connect to CoolerControl API. Check API address and token.';
contentEl.style.display = 'block';
errorEl.style.display = 'block';
}
}
function refreshDeviceInfo() {
- fetchDeviceInfo(lastApiAddress, lastApiPassword);
+ fetchDeviceInfo(lastApiAddress, lastApiToken);
}
- async function fetchSystemInfo(apiAddress, password) {
+ async function fetchSystemInfo(apiAddress, token) {
try {
- var headers = {};
- if (password) {
- headers['Authorization'] = 'Basic ' + btoa('admin:' + password);
- }
-
- var healthRes = await fetch(apiAddress + '/health', { headers: headers });
- if (healthRes.ok) {
- var health = await healthRes.json();
- var ccVersion = (health.details && health.details.version) || '\u2014';
- document.getElementById('sys-cc-version').textContent = ccVersion;
+ var devices = [];
+ // 1. Try getDevices() via postMessage (CC4 iframe).
+ if (typeof getDevices === 'function') {
+ try {
+ var _sysTimeout = new Promise(function(res) { setTimeout(function() { res([]); }, 3000); });
+ devices = (await Promise.race([getDevices(true), _sysTimeout])) || [];
+ } catch (e) { devices = []; }
}
-
- var devRes = await fetch(apiAddress + '/devices', { headers: headers });
- if (devRes.ok) {
- var data = await devRes.json();
- var devices = data.devices || [];
- var kernel = '';
- for (var i = 0; i < devices.length; i++) {
- var drvType = devices[i].info && devices[i].info.driver_info && devices[i].info.driver_info.drv_type;
- var ver = devices[i].info && devices[i].info.driver_info && devices[i].info.driver_info.version;
- if (drvType === 'Kernel' && ver) {
- kernel = ver;
- break;
+ // 2. Standalone fallback: direct fetch (blocked in CC iframe).
+ if (devices.length === 0 && window.parent === window) {
+ try {
+ var healthRes = await fetch(apiAddress + '/health', {
+ headers: buildAuthHeaders(token)
+ });
+ if (healthRes.ok) {
+ var health = await healthRes.json();
+ var ccVersion = (health.details && health.details.version) || '\u2014';
+ document.getElementById('sys-cc-version').textContent = ccVersion;
}
+ var devRes = await fetch(apiAddress + '/devices', {
+ headers: buildAuthHeaders(token)
+ });
+ devices = devRes.ok ? ((await devRes.json()).devices || []) : [];
+ } catch (fetchErr) {
+ console.warn('System info direct fetch failed:', fetchErr);
}
- if (kernel) {
- document.getElementById('sys-kernel').textContent = kernel;
+ }
+
+ var kernel = '';
+ for (var i = 0; i < devices.length; i++) {
+ var drvType = devices[i].info && devices[i].info.driver_info && devices[i].info.driver_info.drv_type;
+ var ver = devices[i].info && devices[i].info.driver_info && devices[i].info.driver_info.version;
+ if (drvType === 'Kernel' && ver) {
+ kernel = ver;
+ break;
}
}
+ if (kernel) {
+ document.getElementById('sys-kernel').textContent = kernel;
+ }
} catch (error) {
console.warn('System info fetch failed:', error);
}
@@ -2025,9 +2110,8 @@
System Environment
for (var sf = 0; sf < slotFields.length; sf++) {
var slotValue = config.display && config.display[slotFields[sf]];
if (slotValue) {
- // Ensure value is a string (fix legacy numeric corruption)
slotValue = String(slotValue);
- // Reject pure numeric values (corrupt from old parseFloat bug)
+ // reject corrupt numeric values (legacy parseFloat bug)
if (/^\d+$/.test(slotValue)) {
slotValue = slotDefaults[slotFields[sf]] || 'cpu';
config.display[slotFields[sf]] = slotValue;
@@ -2076,10 +2160,8 @@
System Environment
var config = buildConfig();
try {
await writeConfigToFile(config);
- requestRestartAfterSave(1000);
+ requestRestartAfterSave(500);
await savePluginConfig(config);
- alert("Configuration saved! Plugin will restart.");
- setTimeout(function() { window.close(); }, 300);
} catch (error) {
console.error("Save failed:", error);
alert("Save failed: " + error.message);
@@ -2108,13 +2190,19 @@
System Environment
async function restartPluginDaemon(config) {
try {
- var apiAddress = (config.daemon && config.daemon.address) || 'http://localhost:11987';
- var password = (config.daemon && config.daemon.password) || '';
- var headers = { 'Content-Type': 'application/json' };
- if (password) headers['Authorization'] = 'Basic ' + btoa('admin:' + password);
-
- var response = await fetch(apiAddress + '/plugins/coolerdash/restart', { method: 'POST', headers: headers });
- if (!response.ok) console.warn("Could not restart plugin automatically");
+ if (typeof restart === 'function') {
+ // CC iframe: use cc-plugin-lib (postMessage).
+ restart();
+ } else {
+ // Standalone: direct API.
+ var apiAddress = (config.daemon && config.daemon.address) || 'https://localhost:11987';
+ var token = (config.daemon && config.daemon.access_token) || '';
+ var response = await fetch(apiAddress + '/plugins/coolerdash/restart', {
+ method: 'POST',
+ headers: buildAuthHeaders(token, { 'Content-Type': 'application/json' })
+ });
+ if (!response.ok) console.warn("Could not restart plugin automatically (HTTP " + response.status + ")");
+ }
} catch (error) {
console.error("Plugin restart failed:", error);
}
@@ -2142,15 +2230,20 @@
System Environment
}
}
+ // CC 4.0: Bearer token auth — no /login call needed
+ async function loginToCoolerControl(apiAddress, token) {
+ return true;
+ }
+
async function writeConfigToFile(config) {
try {
- var apiAddress = (config.daemon && config.daemon.address) || 'http://localhost:11987';
- var password = (config.daemon && config.daemon.password) || '';
+ var apiAddress = (config.daemon && config.daemon.address) || 'https://localhost:11987';
+ var token = (config.daemon && config.daemon.access_token) || '';
- if (password) {
+ if (token) {
var response = await fetch(apiAddress + '/plugins/coolerdash/config', {
method: 'PUT',
- headers: { 'Content-Type': 'application/json', 'Authorization': 'Basic ' + btoa('admin:' + password) },
+ headers: buildAuthHeaders(token, { 'Content-Type': 'application/json' }),
body: JSON.stringify(config, null, 2)
});
if (response.ok) return true;
@@ -2170,13 +2263,18 @@
System Environment
}
async function resetConfig() {
+ if (!confirm('Reset all settings to factory defaults?')) return;
try {
- await writeConfigToFile(FACTORY_DEFAULTS);
- populateForm(FACTORY_DEFAULTS);
- requestRestartAfterSave(1000);
- await savePluginConfig(FACTORY_DEFAULTS);
- alert('Reset to factory defaults! Plugin will restart.');
- setTimeout(function() { window.close(); }, 300);
+ var currentConfig = buildConfig();
+ var resetDefaults = JSON.parse(JSON.stringify(FACTORY_DEFAULTS));
+ // Keep current access_token for API access during reset
+ if (currentConfig.daemon && currentConfig.daemon.access_token) {
+ resetDefaults.daemon.access_token = currentConfig.daemon.access_token;
+ }
+ await writeConfigToFile(resetDefaults);
+ populateForm(resetDefaults);
+ requestRestartAfterSave(500);
+ await savePluginConfig(resetDefaults);
} catch (error) {
console.error("Reset failed:", error);
alert('Reset failed: ' + error.message);
@@ -2227,7 +2325,7 @@
System Environment
// Deep merge sensor configs (skip corrupt numeric keys)
for (var id in sensors) {
if (!sensors.hasOwnProperty(id)) continue;
- // Remove corrupt numeric sensor IDs from old parseFloat bug
+ // remove corrupt numeric sensor IDs (old parseFloat bug)
if (/^\d+$/.test(id)) continue;
var defaults = merged.sensors[id] || getDefaultSensorConfig(id);
merged.sensors[id] = Object.assign({}, defaults, sensors[id]);
@@ -2240,7 +2338,7 @@
System Environment
}
}
- // Sanitize corrupt numeric slot values (from old parseFloat bug)
+ // sanitize corrupt numeric slot values (old parseFloat bug)
var slotDefaults = { sensor_slot_up: 'cpu', sensor_slot_mid: 'liquid', sensor_slot_down: 'gpu' };
for (var slotKey in slotDefaults) {
if (merged.display && merged.display[slotKey] !== undefined) {
@@ -2284,11 +2382,11 @@
System Environment
populateForm(config);
// Detect device and discover sensors from CoolerControl API
- var apiAddr = (config.daemon && config.daemon.address) || 'http://localhost:11987';
- var apiPass = (config.daemon && config.daemon.password) || '';
- fetchDeviceInfo(apiAddr, apiPass);
- fetchSystemInfo(apiAddr, apiPass);
- discoverSensors(apiAddr, apiPass);
+ var apiAddr = (config.daemon && config.daemon.address) || 'https://localhost:11987';
+ var apiToken = (config.daemon && config.daemon.access_token) || '';
+ fetchDeviceInfo(apiAddr, apiToken);
+ fetchSystemInfo(apiAddr, apiToken);
+ discoverSensors(apiAddr, apiToken);
} catch (error) {
console.error("Init failed:", error);
if (DEFAULT_CONFIG) populateForm(DEFAULT_CONFIG);
diff --git a/etc/systemd/cc-plugin-coolerdash.service.d/startup-delay.conf b/etc/systemd/cc-plugin-coolerdash.service.d/startup-delay.conf
deleted file mode 100644
index 3b9aee6..0000000
--- a/etc/systemd/cc-plugin-coolerdash.service.d/startup-delay.conf
+++ /dev/null
@@ -1,2 +0,0 @@
-[Service]
-ExecStartPre=/bin/sleep 10
diff --git a/etc/systemd/coolerdash-helperd.service b/etc/systemd/coolerdash-helperd.service
deleted file mode 100644
index bd8fe81..0000000
--- a/etc/systemd/coolerdash-helperd.service
+++ /dev/null
@@ -1,15 +0,0 @@
-[Unit]
-Description=CoolerDash helper daemon
-BindsTo=coolercontrold.service
-PartOf=coolercontrold.service
-After=coolercontrold.service
-
-[Service]
-Type=simple
-ExecStart=/bin/sleep infinity
-ExecStop=/usr/libexec/coolerdash/coolerdash --shutdown
-TimeoutStopSec=3
-Restart=no
-
-[Install]
-WantedBy=multi-user.target
diff --git a/openapi-spec.json b/openapi-spec.json
index daac9c4..194fe90 100644
--- a/openapi-spec.json
+++ b/openapi-spec.json
@@ -1,4599 +1 @@
-{
- "openapi": "3.1.0",
- "info": {
- "title": "CoolerControl Daemon API",
- "summary": "CoolerControl Rest Endpoints",
- "description": "Basic OpenAPI documentation for the CoolerControl Daemon API",
- "contact": {
- "name": "CoolerControl",
- "url": "https://coolercontrol.org"
- },
- "license": {
- "name": "GPL3+",
- "identifier": "GPL3+"
- },
- "version": "2.2.1"
- },
- "paths": {
- "/handshake": {
- "get": {
- "tags": [
- "base"
- ],
- "summary": "Handshake",
- "description": "A simple endpoint to verify the connection",
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
-
- }
- }
- }
- }
- }
- }
- },
- "/health": {
- "get": {
- "tags": [
- "base"
- ],
- "summary": "Health Check",
- "description": "Returns a Health Check Status.",
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HealthCheck"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- }
- },
- "/logs": {
- "get": {
- "tags": [
- "base"
- ],
- "summary": "Daemon Logs",
- "description": "This returns all recent main daemon logs as raw text",
- "responses": {
- "200": {
- "description": "plain text",
- "content": {
- "text/plain; charset=utf-8": {
-
- }
- }
- }
- }
- }
- },
- "/acknowledge": {
- "post": {
- "tags": [
- "base"
- ],
- "summary": "Acknowledge Log Issues",
- "description": "This acknowledges existing log warnings and errors, and sets a timestamp of when this occurred",
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- }
- },
- "/shutdown": {
- "post": {
- "tags": [
- "base"
- ],
- "summary": "Shutdown Daemon",
- "description": "Sends a cancellation signal to shut the daemon down. When the daemon is running as a systemd or initrc service, it is automatically restarted.",
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/login": {
- "post": {
- "tags": [
- "auth"
- ],
- "summary": "Login",
- "description": "The endpoint used to create a login session.",
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "BasicAuth": []
- }
- ]
- }
- },
- "/verify-session": {
- "post": {
- "tags": [
- "auth"
- ],
- "summary": "Verify Session Auth",
- "description": "Verifies that the current session is still authenticated",
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/set-passwd": {
- "post": {
- "tags": [
- "auth"
- ],
- "summary": "Set Admin Password",
- "description": "Stores a new Admin password.",
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- },
- {
- "BasicAuth": []
- }
- ]
- }
- },
- "/logout": {
- "post": {
- "tags": [
- "auth"
- ],
- "summary": "Logout",
- "description": "Logout and invalidate the current session.",
- "responses": {
- "200": {
- "description": "no content"
- }
- }
- }
- },
- "/thinkpad-fan-control": {
- "put": {
- "tags": [
- "device"
- ],
- "summary": "ThinkPad Fan Control",
- "description": "Enables/Disabled Fan Control for ThinkPads, if acpi driver is present.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ThinkPadFanControlRequest"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/devices": {
- "get": {
- "tags": [
- "device"
- ],
- "summary": "All Devices",
- "description": "Returns a list of all detected devices and their associated information.",
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/DevicesResponse"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- }
- },
- "/devices/{device_uid}/settings": {
- "get": {
- "tags": [
- "device"
- ],
- "summary": "All Device Settings",
- "description": "Returns all the currently applied settings for the given device. It returns the Config Settings model, which includes all possibilities for each channel.",
- "parameters": [
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/SettingsResponse"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- }
- },
- "/devices/{device_uid}/settings/{channel_name}/manual": {
- "put": {
- "tags": [
- "device"
- ],
- "summary": "Device Channel Manual",
- "description": "Applies a fan duty to a specific device channel.",
- "parameters": [
- {
- "in": "path",
- "name": "channel_name",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- },
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/SettingManualRequest"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/devices/{device_uid}/settings/{channel_name}/profile": {
- "put": {
- "tags": [
- "device"
- ],
- "summary": "Device Channel Profile",
- "description": "Applies a Profile to a specific device channel.",
- "parameters": [
- {
- "in": "path",
- "name": "channel_name",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- },
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/SettingProfileUID"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/devices/{device_uid}/settings/{channel_name}/lcd": {
- "put": {
- "tags": [
- "device"
- ],
- "summary": "Device Channel LCD",
- "description": "Applies LCD Settings to a specific device channel.",
- "parameters": [
- {
- "in": "path",
- "name": "channel_name",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- },
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/LcdSettings"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/devices/{device_uid}/settings/{channel_name}/lcd/images": {
- "get": {
- "tags": [
- "device"
- ],
- "summary": "Retrieve Device Channel LCD",
- "description": "Retrieves the currently applied LCD Image file.",
- "parameters": [
- {
- "in": "path",
- "name": "channel_name",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- },
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- },
- "put": {
- "tags": [
- "device"
- ],
- "summary": "Update Device Channel LCD Settings",
- "description": "Used to apply LCD settings that contain images.",
- "parameters": [
- {
- "in": "path",
- "name": "channel_name",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- },
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- },
- "post": {
- "tags": [
- "device"
- ],
- "summary": "Process Device Channel LCD Image",
- "description": "This takes and image file and processes it for optimal use by the specified device channel. This is useful for a UI Preview and is used internally before applying the image to the device.",
- "parameters": [
- {
- "in": "path",
- "name": "channel_name",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- },
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/devices/{device_uid}/settings/{channel_name}/lighting": {
- "put": {
- "tags": [
- "device"
- ],
- "summary": "Device Channel Lighting",
- "description": "Applies Lighting Settings (RGB) to a specific device channel.",
- "parameters": [
- {
- "in": "path",
- "name": "channel_name",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- },
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/LightingSettings"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/devices/{device_uid}/settings/{channel_name}/pwm": {
- "put": {
- "tags": [
- "device"
- ],
- "summary": "Device Channel PWM Mode",
- "description": "Applies PWM Mode to a specific device channel.",
- "parameters": [
- {
- "in": "path",
- "name": "channel_name",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- },
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/SettingPWMMode"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/devices/{device_uid}/settings/{channel_name}/reset": {
- "put": {
- "tags": [
- "device"
- ],
- "summary": "Device Channel Reset",
- "description": "Resents the specific device channel settings to not-set/device default.",
- "parameters": [
- {
- "in": "path",
- "name": "channel_name",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- },
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/devices/{device_uid}/asetek690": {
- "patch": {
- "tags": [
- "device"
- ],
- "summary": "Device AseTek690",
- "description": "Set the driver type for liquidctl AseTek cooler. This is needed to set Legacy690Lc or Modern690Lc device driver type.",
- "parameters": [
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/AseTek690Request"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- }
- },
- "/status": {
- "post": {
- "tags": [
- "status"
- ],
- "summary": "Retrieve Status",
- "description": "Returns the status of all devices with the selected filters from the request body",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/StatusRequest"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/StatusResponse"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- }
- },
- "/profiles": {
- "get": {
- "tags": [
- "profile"
- ],
- "summary": "Retrieve Profile List",
- "description": "Returns a list of all the persisted Profiles.",
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ProfilesDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- },
- "put": {
- "tags": [
- "profile"
- ],
- "summary": "Update Profile",
- "description": "Updates the Profile with the given properties. Dependent on the Profile UID.",
- "requestBody": {
- "description": "Profile Settings",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Profile"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- },
- "post": {
- "tags": [
- "profile"
- ],
- "summary": "Create Profile",
- "description": "Creates the given Profile",
- "requestBody": {
- "description": "Profile Settings",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Profile"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/profiles/{profile_uid}": {
- "delete": {
- "tags": [
- "profile"
- ],
- "summary": "Delete Profile",
- "description": "Deletes the Profile with the given Profile UID",
- "parameters": [
- {
- "in": "path",
- "name": "profile_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/profiles/order": {
- "post": {
- "tags": [
- "profile"
- ],
- "summary": "Save Profile Order",
- "description": "Saves the order of Profiles as given.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ProfilesDto"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- }
- },
- "/functions": {
- "get": {
- "tags": [
- "function"
- ],
- "summary": "Retrieve Function List",
- "description": "Returns a list of all the persisted Functions.",
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/FunctionsDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- },
- "put": {
- "tags": [
- "function"
- ],
- "summary": "Update Function",
- "description": "Updates the Function with the given properties. Dependent on the Function UID.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Function"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- },
- "post": {
- "tags": [
- "function"
- ],
- "summary": "Create Function",
- "description": "Creates the given Function",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Function"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/functions/{function_uid}": {
- "delete": {
- "tags": [
- "function"
- ],
- "summary": "Delete Function",
- "description": "Deletes the Function with the given Function UID",
- "parameters": [
- {
- "in": "path",
- "name": "function_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/functions/order": {
- "post": {
- "tags": [
- "function"
- ],
- "summary": "Save Function Order",
- "description": "Saves the order of the Functions as given.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/FunctionsDto"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- }
- },
- "/custom-sensors": {
- "get": {
- "tags": [
- "custom-sensor"
- ],
- "summary": "Retrieve Custom Sensor List",
- "description": "Returns a list of all the persisted Custom Sensors.",
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CustomSensorsDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- },
- "put": {
- "tags": [
- "custom-sensor"
- ],
- "summary": "Update Custom Sensor",
- "description": "Updates the Custom Sensor with the given properties. Dependent on the Custom Sensor ID.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CustomSensor"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- },
- "post": {
- "tags": [
- "custom-sensor"
- ],
- "summary": "Create Custom Sensor",
- "description": "Creates the given Custom Sensor",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CustomSensor"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/custom-sensors/{custom_sensor_id}": {
- "get": {
- "tags": [
- "custom-sensor"
- ],
- "summary": "Retrieve Custom Sensor",
- "description": "Retrieves the Custom Sensor with the given Custom Sensor ID",
- "parameters": [
- {
- "in": "path",
- "name": "custom_sensor_id",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CustomSensor"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- },
- "delete": {
- "tags": [
- "custom-sensor"
- ],
- "summary": "Delete Custom Sensor",
- "description": "Deletes the Custom Sensor with the given Custom Sensor UID",
- "parameters": [
- {
- "in": "path",
- "name": "custom_sensor_id",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/custom-sensors/order": {
- "post": {
- "tags": [
- "custom-sensor"
- ],
- "summary": "Save Custom Sensor Order",
- "description": "Saves the order of the Custom Sensors as given.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CustomSensorsDto"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- }
- },
- "/modes": {
- "get": {
- "tags": [
- "mode"
- ],
- "summary": "Retrieve Mode List",
- "description": "Returns a list of all the persisted Modes.",
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ModesDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- },
- "put": {
- "tags": [
- "mode"
- ],
- "summary": "Update Mode",
- "description": "Updates the Mode with the given properties.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/UpdateModeDto"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- },
- "post": {
- "tags": [
- "mode"
- ],
- "summary": "Create Mode",
- "description": "Creates a Mode with the given name, based on the currently applied settings.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CreateModeDto"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ModeDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/modes/{mode_uid}": {
- "get": {
- "tags": [
- "mode"
- ],
- "summary": "Retrieve Mode",
- "description": "Retrieves the Mode with the given Mode UID",
- "parameters": [
- {
- "in": "path",
- "name": "mode_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ModeDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- },
- "delete": {
- "tags": [
- "mode"
- ],
- "summary": "Delete Mode",
- "description": "Deletes the Mode with the given Mode UID",
- "parameters": [
- {
- "in": "path",
- "name": "mode_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/modes/{mode_uid}/duplicate": {
- "post": {
- "tags": [
- "mode"
- ],
- "summary": "Duplicate Mode",
- "description": "Duplicates the Mode and it's settings from the given Mode UID and returns the new Mode.",
- "parameters": [
- {
- "in": "path",
- "name": "mode_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ModeDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/modes/{mode_uid}/settings": {
- "put": {
- "tags": [
- "mode"
- ],
- "summary": "Update Mode Device Settings",
- "description": "Updates the Mode with the given Mode UID device settings to what is currently applied, and returns the Mode with it's new settings.",
- "parameters": [
- {
- "in": "path",
- "name": "mode_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ModeDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/modes-active": {
- "get": {
- "tags": [
- "mode"
- ],
- "summary": "Retrieve Active Modes",
- "description": "Returns the active and previously active Mode UIDs.",
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ActiveModesDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- }
- },
- "/modes-active/{mode_uid}": {
- "post": {
- "tags": [
- "mode"
- ],
- "summary": "Activate Mode",
- "description": "Activates the Mode with the given Mode UID. This applies all of this Mode's device settings.",
- "parameters": [
- {
- "in": "path",
- "name": "mode_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/modes/order": {
- "post": {
- "tags": [
- "mode"
- ],
- "summary": "Save Mode Order",
- "description": "Saves the order of the Modes as given.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ModeOrderDto"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/settings": {
- "get": {
- "tags": [
- "setting"
- ],
- "summary": "CoolerControl Settings",
- "description": "Returns the current CoolerControl settings.",
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CoolerControlSettingsDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- },
- "patch": {
- "tags": [
- "setting"
- ],
- "summary": "Update CoolerControl Settings",
- "description": "Applies only the given properties.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CoolerControlSettingsDto"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/settings/devices": {
- "get": {
- "tags": [
- "setting"
- ],
- "summary": "CoolerControl All Device Settings",
- "description": "Returns the current CoolerControl device settings for all devices.",
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CoolerControlAllDeviceSettingsDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- }
- },
- "/settings/devices/{device_uid}": {
- "get": {
- "tags": [
- "setting"
- ],
- "summary": "CoolerControl Device Settings",
- "description": "Returns the current CoolerControl device settings for the given device UID.",
- "parameters": [
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CoolerControlDeviceSettingsDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- },
- "put": {
- "tags": [
- "setting"
- ],
- "summary": "Update CoolerControl Device Settings",
- "description": "Updates the CoolerControl device settings for the given device UID.",
- "parameters": [
- {
- "in": "path",
- "name": "device_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "requestBody": {
- "description": "General Device Settings for `CoolerControl`",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CoolerControlDeviceSettings"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/settings/ui": {
- "get": {
- "tags": [
- "setting"
- ],
- "summary": "CoolerControl UI Settings",
- "description": "Returns the current CoolerControl UI Settings.",
- "responses": {
- "200": {
- "description": "plain text",
- "content": {
- "text/plain; charset=utf-8": {
-
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- },
- "put": {
- "tags": [
- "setting"
- ],
- "summary": "Update CoolerControl UI Settings",
- "description": "Updates and persists the CoolerControl UI settings.",
- "requestBody": {
- "content": {
- "text/plain; charset=utf-8": {
-
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- }
- },
- "/alerts": {
- "get": {
- "tags": [
- "alert"
- ],
- "summary": "Retrieve Alert List",
- "description": "Returns a list of all the persisted Alerts.",
- "responses": {
- "200": {
- "description": "",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/AlertsDto"
- }
- }
- }
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- }
- },
- "put": {
- "tags": [
- "alert"
- ],
- "summary": "Update Alert",
- "description": "Updates the Alert with the given properties. Dependent on the Alert UID.",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/AlertDto"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- },
- "post": {
- "tags": [
- "alert"
- ],
- "summary": "Create Alert",
- "description": "Creates the given Alert",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/AlertDto"
- }
- }
- },
- "required": true
- },
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/alerts/{alert_uid}": {
- "delete": {
- "tags": [
- "alert"
- ],
- "summary": "Delete Alert",
- "description": "Deletes the Alert with the given Alert UID",
- "parameters": [
- {
- "in": "path",
- "name": "alert_uid",
- "required": true,
- "schema": {
- "type": "string"
- },
- "style": "simple"
- }
- ],
- "responses": {
- "200": {
- "description": "no content"
- },
- "400": {
- "description": "Bad Request. The request is invalid"
- },
- "401": {
- "description": "Unauthorized. Invalid credentials were provided."
- },
- "403": {
- "description": "Forbidden. Insufficient permissions."
- },
- "404": {
- "description": "Whatever you're looking for, it's not here."
- },
- "500": {
- "description": "An internal error has occurred."
- },
- "502": {
- "description": "Bad Gateway. An error has occurred with an external library."
- }
- },
- "security": [
- {
- "CookieAuth": []
- }
- ]
- }
- },
- "/sse/logs": {
- "get": {
- "tags": [
- "sse"
- ],
- "summary": "Log Server Sent Events",
- "description": "Subscribes and returns the Server Sent Events for a Log stream"
- }
- },
- "/sse/status": {
- "get": {
- "tags": [
- "sse"
- ],
- "summary": "Recent Status Server Sent Events",
- "description": "Subscribes and returns the Server Sent Events for a Status stream"
- }
- },
- "/sse/modes": {
- "get": {
- "tags": [
- "sse"
- ],
- "summary": "Activated Mode Events",
- "description": "Subscribes and returns the Server Sent Events for a ModeActivated stream"
- }
- },
- "/sse/alerts": {
- "get": {
- "tags": [
- "sse"
- ],
- "summary": "Alert Events",
- "description": "Subscribes and returns Events for when an Alert State has changed"
- }
- }
- },
- "components": {
- "securitySchemes": {
- "CookieAuth": {
- "type": "apiKey",
- "in": "cookie",
- "name": "cc",
- "description": "The private session cookie used for authentication."
- },
- "BasicAuth": {
- "type": "http",
- "scheme": "basic",
- "bearerFormat": "",
- "description": "HTTP Basic authentication, mostly used to generate a secure authentication cookie."
- }
- },
- "schemas": {
- "ActiveModesDto": {
- "type": "object",
- "properties": {
- "current_mode_uid": {
- "type": [
- "string",
- "null"
- ]
- },
- "previous_mode_uid": {
- "type": [
- "string",
- "null"
- ]
- }
- }
- },
- "AlertDto": {
- "type": "object",
- "required": [
- "channel_source",
- "max",
- "min",
- "name",
- "uid"
- ],
- "properties": {
- "channel_source": {
- "$ref": "#/components/schemas/ChannelSource"
- },
- "max": {
- "type": "number",
- "format": "double"
- },
- "min": {
- "type": "number",
- "format": "double"
- },
- "name": {
- "type": "string"
- },
- "state": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/AlertState"
- },
- {
- "type": "null"
- }
- ]
- },
- "uid": {
- "type": "string"
- }
- }
- },
- "AlertLog": {
- "type": "object",
- "required": [
- "message",
- "name",
- "state",
- "timestamp",
- "uid"
- ],
- "properties": {
- "message": {
- "type": "string"
- },
- "name": {
- "type": "string"
- },
- "state": {
- "$ref": "#/components/schemas/AlertState"
- },
- "timestamp": {
- "type": "string",
- "format": "date-time"
- },
- "uid": {
- "type": "string"
- }
- }
- },
- "AlertPath": {
- "type": "object",
- "required": [
- "alert_uid"
- ],
- "properties": {
- "alert_uid": {
- "type": "string"
- }
- }
- },
- "AlertState": {
- "type": "string",
- "enum": [
- "Active",
- "Inactive"
- ]
- },
- "AlertsDto": {
- "type": "object",
- "required": [
- "alerts",
- "logs"
- ],
- "properties": {
- "alerts": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/AlertDto"
- }
- },
- "logs": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/AlertLog"
- }
- }
- }
- },
- "AseTek690Request": {
- "type": "object",
- "required": [
- "is_legacy690"
- ],
- "properties": {
- "is_legacy690": {
- "type": "boolean"
- }
- }
- },
- "BaseDriver": {
- "type": "string",
- "enum": [
- "Aquacomputer",
- "Legacy690Lc",
- "Modern690Lc",
- "Hydro690Lc",
- "HydroPro",
- "AsusRyujin",
- "AuraLed",
- "CommanderCore",
- "CommanderPro",
- "Coolit",
- "CorsairHidPsu",
- "Ddr4Temperature",
- "VengeanceRgb",
- "HydroPlatinum",
- "Kraken2",
- "KrakenX3",
- "KrakenZ3",
- "MockKrakenZ3",
- "MpgCooler",
- "EvgaPascal",
- "RogTuring",
- "NzxtEPsu",
- "RgbFusion2",
- "SmartDevice",
- "SmartDevice2",
- "H1V2",
- "MsiAcpiEc",
- "NotSupported"
- ]
- },
- "CSPath": {
- "type": "object",
- "required": [
- "custom_sensor_id"
- ],
- "properties": {
- "custom_sensor_id": {
- "type": "string"
- }
- }
- },
- "ChannelInfo": {
- "type": "object",
- "required": [
- "lcd_modes",
- "lighting_modes"
- ],
- "properties": {
- "label": {
- "type": [
- "string",
- "null"
- ]
- },
- "lcd_info": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/LcdInfo"
- },
- {
- "type": "null"
- }
- ]
- },
- "lcd_modes": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/LcdMode"
- }
- },
- "lighting_modes": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/LightingMode"
- }
- },
- "speed_options": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/SpeedOptions"
- },
- {
- "type": "null"
- }
- ]
- }
- }
- },
- "ChannelMetric": {
- "type": "string",
- "enum": [
- "Temp",
- "Duty",
- "Load",
- "RPM",
- "Freq"
- ]
- },
- "ChannelSource": {
- "description": "A source for displaying sensor data that is related to a particular channel. This is like `TempSource` but not limited to temperature sensors. (Load, Duty, etc.)",
- "type": "object",
- "required": [
- "channel_metric",
- "channel_name",
- "device_uid"
- ],
- "properties": {
- "channel_metric": {
- "$ref": "#/components/schemas/ChannelMetric"
- },
- "channel_name": {
- "description": "The internal name for this channel source. NOT the Label.",
- "type": "string"
- },
- "device_uid": {
- "description": "The associated device uid containing current values",
- "type": "string"
- }
- }
- },
- "ChannelStatus": {
- "type": "object",
- "required": [
- "name"
- ],
- "properties": {
- "duty": {
- "type": [
- "number",
- "null"
- ],
- "format": "double"
- },
- "freq": {
- "type": [
- "integer",
- "null"
- ],
- "format": "uint32",
- "minimum": 0
- },
- "name": {
- "type": "string"
- },
- "pwm_mode": {
- "type": [
- "integer",
- "null"
- ],
- "format": "uint8",
- "minimum": 0
- },
- "rpm": {
- "type": [
- "integer",
- "null"
- ],
- "format": "uint32",
- "minimum": 0
- },
- "watts": {
- "type": [
- "number",
- "null"
- ],
- "format": "double"
- }
- }
- },
- "CoolerControlAllDeviceSettingsDto": {
- "type": "object",
- "required": [
- "devices"
- ],
- "properties": {
- "devices": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/CoolerControlDeviceSettingsDto"
- }
- }
- }
- },
- "CoolerControlDeviceSettings": {
- "description": "General Device Settings for `CoolerControl`",
- "type": "object",
- "required": [
- "disable",
- "disable_channels",
- "name"
- ],
- "properties": {
- "disable": {
- "description": "All communication with this device will be avoided if disabled",
- "type": "boolean"
- },
- "disable_channels": {
- "description": "A list of channels to disable communication with.",
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "name": {
- "description": "The device name for this setting. Helpful after blacklisting(disabling) devices.",
- "type": "string"
- }
- }
- },
- "CoolerControlDeviceSettingsDto": {
- "type": "object",
- "required": [
- "disable",
- "disable_channels",
- "name",
- "uid"
- ],
- "properties": {
- "disable": {
- "type": "boolean"
- },
- "disable_channels": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "name": {
- "type": "string"
- },
- "uid": {
- "type": "string"
- }
- }
- },
- "CoolerControlSettingsDto": {
- "type": "object",
- "properties": {
- "apply_on_boot": {
- "type": [
- "boolean",
- "null"
- ]
- },
- "compress": {
- "type": [
- "boolean",
- "null"
- ]
- },
- "drivetemp_suspend": {
- "type": [
- "boolean",
- "null"
- ]
- },
- "hide_duplicate_devices": {
- "type": [
- "boolean",
- "null"
- ]
- },
- "liquidctl_integration": {
- "type": [
- "boolean",
- "null"
- ]
- },
- "no_init": {
- "type": [
- "boolean",
- "null"
- ]
- },
- "poll_rate": {
- "type": [
- "number",
- "null"
- ],
- "format": "double"
- },
- "startup_delay": {
- "type": [
- "integer",
- "null"
- ],
- "format": "uint16",
- "minimum": 0
- },
- "thinkpad_full_speed": {
- "type": [
- "boolean",
- "null"
- ]
- }
- }
- },
- "CreateModeDto": {
- "type": "object",
- "required": [
- "name"
- ],
- "properties": {
- "name": {
- "type": "string"
- }
- }
- },
- "CustomSensor": {
- "type": "object",
- "required": [
- "cs_type",
- "id",
- "mix_function",
- "sources"
- ],
- "properties": {
- "cs_type": {
- "$ref": "#/components/schemas/CustomSensorType"
- },
- "file_path": {
- "type": [
- "string",
- "null"
- ]
- },
- "id": {
- "description": "ID MUST be unique, as `temp_name` must be unique.",
- "type": "string"
- },
- "mix_function": {
- "$ref": "#/components/schemas/CustomSensorMixFunctionType"
- },
- "sources": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/CustomTempSourceData"
- }
- }
- }
- },
- "CustomSensorMixFunctionType": {
- "type": "string",
- "enum": [
- "Min",
- "Max",
- "Delta",
- "Avg",
- "WeightedAvg"
- ]
- },
- "CustomSensorType": {
- "type": "string",
- "enum": [
- "Mix",
- "File"
- ]
- },
- "CustomSensorsDto": {
- "type": "object",
- "required": [
- "custom_sensors"
- ],
- "properties": {
- "custom_sensors": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/CustomSensor"
- }
- }
- }
- },
- "CustomTempSourceData": {
- "type": "object",
- "required": [
- "temp_source",
- "weight"
- ],
- "properties": {
- "temp_source": {
- "$ref": "#/components/schemas/TempSource"
- },
- "weight": {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- }
- }
- },
- "DeviceChannelPath": {
- "type": "object",
- "required": [
- "channel_name",
- "device_uid"
- ],
- "properties": {
- "channel_name": {
- "type": "string"
- },
- "device_uid": {
- "type": "string"
- }
- }
- },
- "DeviceDto": {
- "type": "object",
- "required": [
- "d_type",
- "info",
- "name",
- "type_index",
- "uid"
- ],
- "properties": {
- "d_type": {
- "$ref": "#/components/schemas/DeviceType"
- },
- "info": {
- "$ref": "#/components/schemas/DeviceInfo"
- },
- "lc_info": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/LcInfo"
- },
- {
- "type": "null"
- }
- ]
- },
- "name": {
- "type": "string"
- },
- "type_index": {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "uid": {
- "type": "string"
- }
- }
- },
- "DeviceInfo": {
- "description": "Needed Device info per device",
- "type": "object",
- "required": [
- "channels",
- "driver_info",
- "lighting_speeds",
- "profile_max_length",
- "profile_min_length",
- "temp_max",
- "temp_min",
- "temps"
- ],
- "properties": {
- "channels": {
- "type": "object",
- "additionalProperties": {
- "$ref": "#/components/schemas/ChannelInfo"
- }
- },
- "driver_info": {
- "$ref": "#/components/schemas/DriverInfo"
- },
- "lighting_speeds": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "model": {
- "type": [
- "string",
- "null"
- ]
- },
- "profile_max_length": {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "profile_min_length": {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "temp_max": {
- "description": "The maximum temp to use for Profiles for this device",
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "temp_min": {
- "description": "The minimum temp to use for Profiles for this device",
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "temps": {
- "type": "object",
- "additionalProperties": {
- "$ref": "#/components/schemas/TempInfo"
- }
- },
- "thinkpad_fan_control": {
- "description": "When present, then this is a `ThinkPad` device. True or False indicates whether Fan control is enabled for the kernel module and changing values is possible",
- "type": [
- "boolean",
- "null"
- ]
- }
- }
- },
- "DevicePath": {
- "type": "object",
- "required": [
- "device_uid"
- ],
- "properties": {
- "device_uid": {
- "type": "string"
- }
- }
- },
- "DeviceStatusDto": {
- "type": "object",
- "required": [
- "d_type",
- "status_history",
- "type_index",
- "uid"
- ],
- "properties": {
- "d_type": {
- "$ref": "#/components/schemas/DeviceType"
- },
- "status_history": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/Status"
- }
- },
- "type_index": {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "uid": {
- "type": "string"
- }
- }
- },
- "DeviceType": {
- "type": "string",
- "enum": [
- "CPU",
- "GPU",
- "Liquidctl",
- "Hwmon",
- "CustomSensors"
- ]
- },
- "DevicesResponse": {
- "type": "object",
- "required": [
- "devices"
- ],
- "properties": {
- "devices": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/DeviceDto"
- }
- }
- }
- },
- "DriverInfo": {
- "description": "Device Driver Information",
- "type": "object",
- "required": [
- "drv_type",
- "locations"
- ],
- "properties": {
- "drv_type": {
- "$ref": "#/components/schemas/DriverType"
- },
- "locations": {
- "description": "If available various paths used to access the device. This can include paths like the kernel device path, hwmon path, HID path, or PCI Bus ID",
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "name": {
- "description": "If available the kernel driver name or liquidctl driver class.",
- "type": [
- "string",
- "null"
- ]
- },
- "version": {
- "description": "If available the driver's version. For kernel-based drivers this is the current kernel version. For liquidctl-based drivers this is the liquidctl version. For Nvidia-based drivers this is the version of the installed nvidia proprietary drivers.",
- "type": [
- "string",
- "null"
- ]
- }
- }
- },
- "DriverType": {
- "description": "The Driver Type, or source of the driver actively being used for this device.",
- "type": "string",
- "enum": [
- "Kernel",
- "Liquidctl",
- "NVML",
- "NvidiaCLI",
- "CoolerControl"
- ]
- },
- "Function": {
- "type": "object",
- "required": [
- "duty_maximum",
- "duty_minimum",
- "f_type",
- "name",
- "uid"
- ],
- "properties": {
- "deviance": {
- "description": "The temperature deviance threshold in degrees",
- "type": [
- "number",
- "null"
- ],
- "format": "double"
- },
- "duty_maximum": {
- "description": "The maximum duty change to apply",
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "duty_minimum": {
- "description": "The minimum duty change to apply",
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "f_type": {
- "description": "The type of this function",
- "$ref": "#/components/schemas/FunctionType"
- },
- "name": {
- "description": "The user given name for this function",
- "type": "string"
- },
- "only_downward": {
- "description": "Whether to apply settings only on the way down",
- "type": [
- "boolean",
- "null"
- ]
- },
- "response_delay": {
- "description": "The response delay in seconds",
- "type": [
- "integer",
- "null"
- ],
- "format": "uint8",
- "minimum": 0
- },
- "sample_window": {
- "description": "The sample window this function should use, particularly applicable to moving averages",
- "type": [
- "integer",
- "null"
- ],
- "format": "uint8",
- "minimum": 0
- },
- "uid": {
- "description": "The Unique identifier for this function",
- "type": "string"
- }
- }
- },
- "FunctionPath": {
- "type": "object",
- "required": [
- "function_uid"
- ],
- "properties": {
- "function_uid": {
- "type": "string"
- }
- }
- },
- "FunctionType": {
- "type": "string",
- "enum": [
- "Identity",
- "Standard",
- "ExponentialMovingAvg"
- ]
- },
- "FunctionsDto": {
- "type": "object",
- "required": [
- "functions"
- ],
- "properties": {
- "functions": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/Function"
- }
- }
- }
- },
- "HealthCheck": {
- "type": "object",
- "required": [
- "current_timestamp",
- "description",
- "details",
- "links",
- "status",
- "system"
- ],
- "properties": {
- "current_timestamp": {
- "type": "string",
- "format": "date-time"
- },
- "description": {
- "type": "string"
- },
- "details": {
- "$ref": "#/components/schemas/HealthDetails"
- },
- "links": {
- "type": "object",
- "additionalProperties": {
- "type": "string"
- }
- },
- "status": {
- "type": "string"
- },
- "system": {
- "$ref": "#/components/schemas/SystemDetails"
- }
- }
- },
- "HealthDetails": {
- "type": "object",
- "required": [
- "errors",
- "liquidctl_connected",
- "memory_mb",
- "pid",
- "uptime",
- "version",
- "warnings"
- ],
- "properties": {
- "errors": {
- "type": "integer",
- "format": "uint",
- "minimum": 0
- },
- "liquidctl_connected": {
- "type": "boolean"
- },
- "memory_mb": {
- "type": "number",
- "format": "double"
- },
- "pid": {
- "type": "integer",
- "format": "uint32",
- "minimum": 0
- },
- "uptime": {
- "type": "string"
- },
- "version": {
- "type": "string"
- },
- "warnings": {
- "type": "integer",
- "format": "uint",
- "minimum": 0
- }
- }
- },
- "LcInfo": {
- "description": "Specific Liquidctl device information",
- "type": "object",
- "required": [
- "driver_type",
- "unknown_asetek"
- ],
- "properties": {
- "driver_type": {
- "description": "An Enum representation of the various Liquidctl driver classes",
- "$ref": "#/components/schemas/BaseDriver"
- },
- "firmware_version": {
- "description": "The detected firmware version at initialization",
- "type": [
- "string",
- "null"
- ]
- },
- "unknown_asetek": {
- "description": "An indicator for needed user input to determine actual asetek690lc device",
- "type": "boolean"
- }
- }
- },
- "LcdCarouselSettings": {
- "description": "Settings for the LCD Carousel.\n\nThis can be used to have a carousel of images (static or gif), of sensor data, or a combination of both.",
- "type": "object",
- "required": [
- "interval"
- ],
- "properties": {
- "images_path": {
- "description": "The absolute path directory location for images for the carousel. All applicable images present are processed when the setting is applied.",
- "type": [
- "string",
- "null"
- ]
- },
- "interval": {
- "description": "The interval in seconds (2-900) in which to change images in the carousel.",
- "type": "integer",
- "format": "uint64",
- "minimum": 0
- }
- }
- },
- "LcdInfo": {
- "description": "Specific LCD Screen info",
- "type": "object",
- "required": [
- "max_image_size_bytes",
- "screen_height",
- "screen_width"
- ],
- "properties": {
- "max_image_size_bytes": {
- "type": "integer",
- "format": "uint32",
- "minimum": 0
- },
- "screen_height": {
- "type": "integer",
- "format": "uint32",
- "minimum": 0
- },
- "screen_width": {
- "type": "integer",
- "format": "uint32",
- "minimum": 0
- }
- }
- },
- "LcdMode": {
- "type": "object",
- "required": [
- "brightness",
- "colors_max",
- "colors_min",
- "frontend_name",
- "image",
- "name",
- "orientation",
- "type_"
- ],
- "properties": {
- "brightness": {
- "type": "boolean"
- },
- "colors_max": {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "colors_min": {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "frontend_name": {
- "type": "string"
- },
- "image": {
- "type": "boolean"
- },
- "name": {
- "type": "string"
- },
- "orientation": {
- "type": "boolean"
- },
- "type_": {
- "$ref": "#/components/schemas/LcdModeType"
- }
- }
- },
- "LcdModeType": {
- "type": "string",
- "enum": [
- "None",
- "Liquidctl",
- "Custom"
- ]
- },
- "LcdSettings": {
- "type": "object",
- "required": [
- "colors",
- "mode"
- ],
- "properties": {
- "brightness": {
- "description": "The LCD brightness (0-100%)",
- "type": [
- "integer",
- "null"
- ],
- "format": "uint8",
- "minimum": 0
- },
- "carousel": {
- "anyOf": [
- {
- "$ref": "#/components/schemas/LcdCarouselSettings"
- },
- {
- "type": "null"
- }
- ]
- },
- "colors": {
- "description": "a list of RGB tuple values, eg [(20,20,120), (0,0,255)]",
- "type": "array",
- "items": {
- "type": "array",
- "items": [
- {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- }
- ],
- "maxItems": 3,
- "minItems": 3
- }
- },
- "image_file_processed": {
- "description": "The LCD Image processed file path location, where the preprocessed image is located.",
- "type": [
- "string",
- "null"
- ]
- },
- "mode": {
- "description": "The Lcd mode name",
- "type": "string"
- },
- "orientation": {
- "description": "The LCD Image orientation (0,90,180,270)",
- "type": [
- "integer",
- "null"
- ],
- "format": "uint16",
- "minimum": 0
- },
- "temp_source": {
- "description": "A temp source for displaying a temperature.",
- "anyOf": [
- {
- "$ref": "#/components/schemas/TempSource"
- },
- {
- "type": "null"
- }
- ]
- }
- }
- },
- "LightingMode": {
- "type": "object",
- "required": [
- "backward_enabled",
- "frontend_name",
- "max_colors",
- "min_colors",
- "name",
- "speed_enabled",
- "type_"
- ],
- "properties": {
- "backward_enabled": {
- "type": "boolean"
- },
- "frontend_name": {
- "type": "string"
- },
- "max_colors": {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "min_colors": {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "name": {
- "type": "string"
- },
- "speed_enabled": {
- "type": "boolean"
- },
- "type_": {
- "$ref": "#/components/schemas/LightingModeType"
- }
- }
- },
- "LightingModeType": {
- "type": "string",
- "enum": [
- "None",
- "Liquidctl",
- "Custom"
- ]
- },
- "LightingSettings": {
- "type": "object",
- "required": [
- "colors",
- "mode"
- ],
- "properties": {
- "backward": {
- "description": "run backwards or not",
- "type": [
- "boolean",
- "null"
- ]
- },
- "colors": {
- "description": "a list of RGB tuple values, eg [(20,20,120), (0,0,255)]",
- "type": "array",
- "items": {
- "type": "array",
- "items": [
- {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- }
- ],
- "maxItems": 3,
- "minItems": 3
- }
- },
- "mode": {
- "description": "The lighting mode name",
- "type": "string"
- },
- "speed": {
- "description": "The speed to set",
- "type": [
- "string",
- "null"
- ]
- }
- }
- },
- "ModeDto": {
- "type": "object",
- "required": [
- "device_settings",
- "name",
- "uid"
- ],
- "properties": {
- "device_settings": {
- "type": "array",
- "items": {
- "type": "array",
- "items": [
- {
- "type": "string"
- },
- {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/Setting"
- }
- }
- ],
- "maxItems": 2,
- "minItems": 2
- }
- },
- "name": {
- "type": "string"
- },
- "uid": {
- "type": "string"
- }
- }
- },
- "ModeOrderDto": {
- "type": "object",
- "required": [
- "mode_uids"
- ],
- "properties": {
- "mode_uids": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- },
- "ModePath": {
- "type": "object",
- "required": [
- "mode_uid"
- ],
- "properties": {
- "mode_uid": {
- "type": "string"
- }
- }
- },
- "ModesDto": {
- "type": "object",
- "required": [
- "modes"
- ],
- "properties": {
- "modes": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/ModeDto"
- }
- }
- }
- },
- "Profile": {
- "description": "Profile Settings",
- "type": "object",
- "required": [
- "function_uid",
- "member_profile_uids",
- "name",
- "p_type",
- "uid"
- ],
- "properties": {
- "function_uid": {
- "description": "The function uid to apply to this profile",
- "type": "string"
- },
- "member_profile_uids": {
- "description": "The profiles that make up the mix profile",
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "mix_function_type": {
- "description": "The function to mix the members with if this is a Mix Profile",
- "anyOf": [
- {
- "$ref": "#/components/schemas/ProfileMixFunctionType"
- },
- {
- "type": "null"
- }
- ]
- },
- "name": {
- "description": "The User given name for this Profile",
- "type": "string"
- },
- "p_type": {
- "description": "The profile type",
- "$ref": "#/components/schemas/ProfileType"
- },
- "speed_fixed": {
- "description": "The fixed duty speed to set. eg: 20 (%)",
- "type": [
- "integer",
- "null"
- ],
- "format": "uint8",
- "minimum": 0
- },
- "speed_profile": {
- "description": "The profile temp/duty speeds to set. eg: [(20.0, 50), (25.7, 80)]",
- "type": [
- "array",
- "null"
- ],
- "items": {
- "type": "array",
- "items": [
- {
- "type": "number",
- "format": "double"
- },
- {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- }
- ],
- "maxItems": 2,
- "minItems": 2
- }
- },
- "temp_source": {
- "description": "The associated temperature source",
- "anyOf": [
- {
- "$ref": "#/components/schemas/TempSource"
- },
- {
- "type": "null"
- }
- ]
- },
- "uid": {
- "description": "The Unique Identifier for this Profile",
- "type": "string"
- }
- }
- },
- "ProfileMixFunctionType": {
- "type": "string",
- "enum": [
- "Min",
- "Max",
- "Avg"
- ]
- },
- "ProfilePath": {
- "type": "object",
- "required": [
- "profile_uid"
- ],
- "properties": {
- "profile_uid": {
- "type": "string"
- }
- }
- },
- "ProfileType": {
- "type": "string",
- "enum": [
- "Default",
- "Fixed",
- "Graph",
- "Mix"
- ]
- },
- "ProfilesDto": {
- "type": "object",
- "required": [
- "profiles"
- ],
- "properties": {
- "profiles": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/Profile"
- }
- }
- }
- },
- "Setting": {
- "description": "Setting is a passed struct used to store applied Settings to a device channel Usually only one specific lighting or speed setting is applied at a time.",
- "type": "object",
- "required": [
- "channel_name"
- ],
- "properties": {
- "channel_name": {
- "type": "string"
- },
- "lcd": {
- "description": "Settings for LCD screens",
- "anyOf": [
- {
- "$ref": "#/components/schemas/LcdSettings"
- },
- {
- "type": "null"
- }
- ]
- },
- "lighting": {
- "description": "Settings for lighting",
- "anyOf": [
- {
- "$ref": "#/components/schemas/LightingSettings"
- },
- {
- "type": "null"
- }
- ]
- },
- "profile_uid": {
- "description": "The Profile UID that applies to this device channel",
- "type": [
- "string",
- "null"
- ]
- },
- "pwm_mode": {
- "description": "the current `pwm_mode` to set for hwmon devices, eg: 1",
- "type": [
- "integer",
- "null"
- ],
- "format": "uint8",
- "minimum": 0
- },
- "reset_to_default": {
- "description": "Used to set hwmon & nvidia channels back to their default 'automatic' values.",
- "type": [
- "boolean",
- "null"
- ]
- },
- "speed_fixed": {
- "description": "The fixed duty speed to set. eg: 20 (%)",
- "type": [
- "integer",
- "null"
- ],
- "format": "uint8",
- "minimum": 0
- }
- }
- },
- "SettingManualRequest": {
- "type": "object",
- "required": [
- "speed_fixed"
- ],
- "properties": {
- "speed_fixed": {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- }
- }
- },
- "SettingPWMMode": {
- "type": "object",
- "required": [
- "pwm_mode"
- ],
- "properties": {
- "pwm_mode": {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- }
- }
- },
- "SettingProfileUID": {
- "type": "object",
- "required": [
- "profile_uid"
- ],
- "properties": {
- "profile_uid": {
- "type": "string"
- }
- }
- },
- "SettingsResponse": {
- "type": "object",
- "required": [
- "settings"
- ],
- "properties": {
- "settings": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/Setting"
- }
- }
- }
- },
- "SpeedOptions": {
- "type": "object",
- "required": [
- "fixed_enabled",
- "manual_profiles_enabled",
- "max_duty",
- "min_duty",
- "profiles_enabled"
- ],
- "properties": {
- "fixed_enabled": {
- "description": "If this is false, it means the fans are not controllable, but viewable.",
- "type": "boolean"
- },
- "manual_profiles_enabled": {
- "description": "This enables software-profiles for device-internal temperatures External temperatures must always be software-profiles and are not handled by this property",
- "type": "boolean"
- },
- "max_duty": {
- "description": "The maximum fan duty for this speed channel",
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "min_duty": {
- "description": "The minimum fan duty for this speed channel",
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- },
- "profiles_enabled": {
- "description": "If (temp, duty) profiles are supported by the device natively or not (device-internal temps)",
- "type": "boolean"
- }
- }
- },
- "Status": {
- "description": "A Model which contains various applicable device statuses",
- "type": "object",
- "required": [
- "channels",
- "temps",
- "timestamp"
- ],
- "properties": {
- "channels": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/ChannelStatus"
- }
- },
- "temps": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/TempStatus"
- }
- },
- "timestamp": {
- "type": "string",
- "format": "date-time"
- }
- }
- },
- "StatusRequest": {
- "type": "object",
- "properties": {
- "all": {
- "type": [
- "boolean",
- "null"
- ]
- },
- "since": {
- "type": [
- "string",
- "null"
- ],
- "format": "date-time"
- }
- }
- },
- "StatusResponse": {
- "type": "object",
- "required": [
- "devices"
- ],
- "properties": {
- "devices": {
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/DeviceStatusDto"
- }
- }
- }
- },
- "SystemDetails": {
- "type": "object",
- "required": [
- "name"
- ],
- "properties": {
- "name": {
- "type": "string"
- }
- }
- },
- "TempInfo": {
- "type": "object",
- "required": [
- "label",
- "number"
- ],
- "properties": {
- "label": {
- "type": "string"
- },
- "number": {
- "type": "integer",
- "format": "uint8",
- "minimum": 0
- }
- }
- },
- "TempSource": {
- "type": "object",
- "required": [
- "device_uid",
- "temp_name"
- ],
- "properties": {
- "device_uid": {
- "description": "The associated device uid containing current temp values",
- "type": "string"
- },
- "temp_name": {
- "description": "The internal name for this Temperature Source. NOT the `TempInfo` Label.",
- "type": "string"
- }
- }
- },
- "TempStatus": {
- "type": "object",
- "required": [
- "name",
- "temp"
- ],
- "properties": {
- "name": {
- "type": "string"
- },
- "temp": {
- "type": "number",
- "format": "double"
- }
- }
- },
- "ThinkPadFanControlRequest": {
- "type": "object",
- "required": [
- "enable"
- ],
- "properties": {
- "enable": {
- "type": "boolean"
- }
- }
- },
- "UpdateModeDto": {
- "type": "object",
- "required": [
- "name",
- "uid"
- ],
- "properties": {
- "name": {
- "type": "string"
- },
- "uid": {
- "type": "string"
- }
- }
- }
- }
- },
- "tags": [
- {
- "name": "base",
- "description": "Foundational endpoints for this API"
- },
- {
- "name": "auth",
- "description": "Authentication"
- },
- {
- "name": "device",
- "description": "Device Interaction"
- },
- {
- "name": "status",
- "description": "Device Status"
- },
- {
- "name": "profile",
- "description": "Profiles"
- },
- {
- "name": "function",
- "description": "Functions"
- },
- {
- "name": "custom-sensor",
- "description": "Custom Sensors"
- },
- {
- "name": "mode",
- "description": "Modes"
- },
- {
- "name": "setting",
- "description": "Settings"
- },
- {
- "name": "alert",
- "description": "Alerts"
- },
- {
- "name": "sse",
- "description": "Server Side Events"
- }
- ]
-}
+{"openapi":"3.1.0","info":{"title":"CoolerControl Daemon API","summary":"CoolerControl Rest Endpoints","description":"Basic OpenAPI documentation for the CoolerControl Daemon API","contact":{"name":"CoolerControl","url":"https://coolercontrol.org"},"license":{"name":"GPL3+","identifier":"GPL3+"},"version":"4.0.0"},"paths":{"/handshake":{"get":{"tags":["base"],"summary":"Handshake","description":"A simple endpoint to verify the connection"}},"/health":{"get":{"tags":["base"],"summary":"Health Check","description":"Returns a Health Check Status.","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthCheck"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/logs":{"get":{"tags":["base"],"summary":"Daemon Logs","description":"This returns all recent main daemon logs as raw text","responses":{"200":{"description":"plain text","content":{"text/plain; charset=utf-8":{}}}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/acknowledge":{"post":{"tags":["base"],"summary":"Acknowledge Log Issues","description":"This acknowledges existing log warnings and errors, and sets a timestamp of when this occurred","responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/shutdown":{"post":{"tags":["base"],"summary":"Shutdown Daemon","description":"Sends a cancellation signal to shut the daemon down. When the daemon is running as a systemd or initrc service, it is automatically restarted.","responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]}]}},"/login":{"post":{"tags":["auth"],"summary":"Login","description":"The endpoint used to create a login session.","responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"BasicAuth":[]}]}},"/verify-session":{"post":{"tags":["auth"],"summary":"Verify Session Auth","description":"Verifies that the current session is still authenticated","responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]}]}},"/set-passwd":{"post":{"tags":["auth"],"summary":"Set Admin Password","description":"Stores a new Admin password.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPasswdRequest"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[],"BasicAuth":[]}]}},"/logout":{"post":{"tags":["auth"],"summary":"Logout","description":"Logout and invalidate the current session.","responses":{"200":{"description":"no content"}},"security":[{"CookieAuth":[]}]}},"/tokens":{"get":{"tags":["auth"],"summary":"List Access Tokens","description":"Returns a list of all access tokens (without hashes).","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenListResponse"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]}]},"post":{"tags":["auth"],"summary":"Create Access Token","description":"Creates a new access token for external service authentication. The raw token is only returned once.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTokenRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTokenResponse"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]}]}},"/tokens/{token_id}":{"delete":{"tags":["auth"],"summary":"Delete Access Token","description":"Deletes the access token with the given ID.","parameters":[{"in":"path","name":"token_id","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]}]}},"/thinkpad-fan-control":{"put":{"tags":["device"],"summary":"ThinkPad Fan Control","description":"Enables/Disabled Fan Control for ThinkPads, if acpi driver is present.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThinkPadFanControlRequest"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/devices":{"get":{"tags":["device"],"summary":"All Devices","description":"Returns a list of all detected devices and their associated information.","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevicesResponse"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/devices/{device_uid}/settings":{"get":{"tags":["device"],"summary":"All Device Settings","description":"Returns all the currently applied settings for the given device. It returns the Config Settings model, which includes all possibilities for each channel.","parameters":[{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsResponse"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/devices/{device_uid}/settings/{channel_name}/manual":{"put":{"tags":["device"],"summary":"Device Channel Manual","description":"Applies a fan duty to a specific device channel.","parameters":[{"in":"path","name":"channel_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingManualRequest"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/devices/{device_uid}/settings/{channel_name}/profile":{"put":{"tags":["device"],"summary":"Device Channel Profile","description":"Applies a Profile to a specific device channel.","parameters":[{"in":"path","name":"channel_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingProfileUID"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/devices/{device_uid}/settings/{channel_name}/lcd":{"put":{"tags":["device"],"summary":"Device Channel LCD","description":"Applies LCD Settings to a specific device channel.","parameters":[{"in":"path","name":"channel_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LcdSettings"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/devices/{device_uid}/settings/{channel_name}/lcd/images":{"get":{"tags":["device"],"summary":"Retrieve Device Channel LCD","description":"Retrieves the currently applied LCD Image file.","parameters":[{"in":"path","name":"channel_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"put":{"tags":["device"],"summary":"Update Device Channel LCD Settings","description":"Used to apply LCD settings that contain images.","parameters":[{"in":"path","name":"channel_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"query","name":"log","schema":{"type":["boolean","null"],"default":null},"style":"form"}],"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"post":{"tags":["device"],"summary":"Process Device Channel LCD Image","description":"This takes and image file and processes it for optimal use by the specified device channel. This is useful for a UI Preview and is used internally before applying the image to the device.","parameters":[{"in":"path","name":"channel_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/devices/{device_uid}/settings/{channel_name}/lcd/shutdown-image":{"put":{"tags":["device"],"summary":"Set LCD Shutdown Image","description":"Upload and save an LCD image that will be applied to the device when the daemon shuts down.","parameters":[{"in":"path","name":"channel_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"delete":{"tags":["device"],"summary":"Clear LCD Shutdown Image","description":"Remove the saved LCD shutdown image for the given device channel.","parameters":[{"in":"path","name":"channel_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/devices/{device_uid}/settings/{channel_name}/lighting":{"put":{"tags":["device"],"summary":"Device Channel Lighting","description":"Applies Lighting Settings (RGB) to a specific device channel.","parameters":[{"in":"path","name":"channel_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LightingSettings"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/devices/{device_uid}/settings/{channel_name}/pwm":{"put":{"tags":["device"],"summary":"DEPRECATED: Device Channel PWM Mode","description":"DEPRECATED: Applies PWM Mode to a specific device channel.","parameters":[{"in":"path","name":"channel_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingPWMMode"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/devices/{device_uid}/settings/{channel_name}/reset":{"put":{"tags":["device"],"summary":"Device Channel Reset","description":"Resents the specific device channel settings to not-set/device default.","parameters":[{"in":"path","name":"channel_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/devices/{device_uid}/asetek690":{"patch":{"tags":["device"],"summary":"Device AseTek690","description":"Set the driver type for liquidctl AseTek cooler. This is needed to set Legacy690Lc or Modern690Lc device driver type.","parameters":[{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AseTek690Request"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/status":{"get":{"tags":["status"],"summary":"Retrieve Status","description":"Returns the status of all devices and their channels, returning only the most recent status by default.","parameters":[{"in":"query","name":"all","schema":{"type":["boolean","null"],"default":null},"style":"form"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"post":{"tags":["status"],"summary":"Retrieve Status","description":"Returns the status of all devices and their channels,with the selected filters from the request body. This endpoint has the most options available for retrieving all statuses.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusResponse"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/status/{device_uid}":{"get":{"tags":["status"],"summary":"Retrieve Device Status","description":"Returns the status of all channels for a specific device, returning only the most recent status by default.","parameters":[{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"query","name":"all","schema":{"type":["boolean","null"],"default":null},"style":"form"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceStatusDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/status/{device_uid}/channels/{channel_name}":{"get":{"tags":["status"],"summary":"Retrieve Device Channel Status","description":"Returns the status of a specific channel for a specific device, returning only the most recent status by default.","parameters":[{"in":"path","name":"channel_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"query","name":"all","schema":{"type":["boolean","null"],"default":null},"style":"form"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceChannelStatusDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/profiles":{"get":{"tags":["profile"],"summary":"Retrieve Profile List","description":"Returns a list of all the persisted Profiles.","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilesDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"put":{"tags":["profile"],"summary":"Update Profile","description":"Updates the Profile with the given properties. Dependent on the Profile UID.","requestBody":{"description":"Profile Settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"post":{"tags":["profile"],"summary":"Create Profile","description":"Creates the given Profile","requestBody":{"description":"Profile Settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/profiles/{profile_uid}":{"delete":{"tags":["profile"],"summary":"Delete Profile","description":"Deletes the Profile with the given Profile UID","parameters":[{"in":"path","name":"profile_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/profiles/order":{"post":{"tags":["profile"],"summary":"Save Profile Order","description":"Saves the order of Profiles as given.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilesDto"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/functions":{"get":{"tags":["function"],"summary":"Retrieve Function List","description":"Returns a list of all the persisted Functions.","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunctionsDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"put":{"tags":["function"],"summary":"Update Function","description":"Updates the Function with the given properties. Dependent on the Function UID.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Function"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"post":{"tags":["function"],"summary":"Create Function","description":"Creates the given Function","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Function"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/functions/{function_uid}":{"delete":{"tags":["function"],"summary":"Delete Function","description":"Deletes the Function with the given Function UID","parameters":[{"in":"path","name":"function_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/functions/order":{"post":{"tags":["function"],"summary":"Save Function Order","description":"Saves the order of the Functions as given.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunctionsDto"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/custom-sensors":{"get":{"tags":["custom-sensor"],"summary":"Retrieve Custom Sensor List","description":"Returns a list of all the persisted Custom Sensors.","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomSensorsDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"put":{"tags":["custom-sensor"],"summary":"Update Custom Sensor","description":"Updates the Custom Sensor with the given properties. Dependent on the Custom Sensor ID.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomSensor"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"post":{"tags":["custom-sensor"],"summary":"Create Custom Sensor","description":"Creates the given Custom Sensor","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomSensor"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/custom-sensors/{custom_sensor_id}":{"get":{"tags":["custom-sensor"],"summary":"Retrieve Custom Sensor","description":"Retrieves the Custom Sensor with the given Custom Sensor ID","parameters":[{"in":"path","name":"custom_sensor_id","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomSensor"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"delete":{"tags":["custom-sensor"],"summary":"Delete Custom Sensor","description":"Deletes the Custom Sensor with the given Custom Sensor UID","parameters":[{"in":"path","name":"custom_sensor_id","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/custom-sensors/order":{"post":{"tags":["custom-sensor"],"summary":"Save Custom Sensor Order","description":"Saves the order of the Custom Sensors as given.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomSensorsDto"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/modes":{"get":{"tags":["mode"],"summary":"Retrieve Mode List","description":"Returns a list of all the persisted Modes.","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModesDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"put":{"tags":["mode"],"summary":"Update Mode","description":"Updates the Mode with the given properties.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateModeDto"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"post":{"tags":["mode"],"summary":"Create Mode","description":"Creates a Mode with the given name, based on the currently applied settings.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateModeDto"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModeDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/modes/{mode_uid}":{"get":{"tags":["mode"],"summary":"Retrieve Mode","description":"Retrieves the Mode with the given Mode UID","parameters":[{"in":"path","name":"mode_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModeDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"delete":{"tags":["mode"],"summary":"Delete Mode","description":"Deletes the Mode with the given Mode UID","parameters":[{"in":"path","name":"mode_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/modes/{mode_uid}/duplicate":{"post":{"tags":["mode"],"summary":"Duplicate Mode","description":"Duplicates the Mode and it's settings from the given Mode UID and returns the new Mode.","parameters":[{"in":"path","name":"mode_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModeDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/modes/{mode_uid}/settings":{"put":{"tags":["mode"],"summary":"Update Mode Device Settings","description":"Updates the Mode with the given Mode UID device settings to what is currently applied, and returns the Mode with it's new settings.","parameters":[{"in":"path","name":"mode_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModeDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/modes-active":{"get":{"tags":["mode"],"summary":"Retrieve Active Modes","description":"Returns the active and previously active Mode UIDs.","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveModesDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/modes-active/{mode_uid}":{"post":{"tags":["mode"],"summary":"Activate Mode","description":"Activates the Mode with the given Mode UID. This applies all of this Mode's device settings.","parameters":[{"in":"path","name":"mode_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/modes/order":{"post":{"tags":["mode"],"summary":"Save Mode Order","description":"Saves the order of the Modes as given.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModeOrderDto"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/settings":{"get":{"tags":["setting"],"summary":"CoolerControl Settings","description":"Returns the current CoolerControl settings.","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoolerControlSettingsDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"patch":{"tags":["setting"],"summary":"Update CoolerControl Settings","description":"Applies only the given properties.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoolerControlSettingsDto"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/settings/devices":{"get":{"tags":["setting"],"summary":"CoolerControl All Device Settings","description":"Returns the current CoolerControl device settings for all devices.","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoolerControlAllDeviceSettingsDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/settings/devices/{device_uid}":{"get":{"tags":["setting"],"summary":"CoolerControl Device Settings","description":"Returns the current CoolerControl device settings for the given device UID.","parameters":[{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoolerControlDeviceSettingsDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"put":{"tags":["setting"],"summary":"Update CoolerControl Device Settings","description":"Updates the CoolerControl device settings for the given device UID.","parameters":[{"in":"path","name":"device_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"requestBody":{"description":"Device Specific settings that generally apply to how the application deals with the device.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CCDeviceSettings"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/settings/ui":{"get":{"tags":["setting"],"summary":"CoolerControl UI Settings","description":"Returns the current CoolerControl UI Settings.","responses":{"200":{"description":"plain text","content":{"text/plain; charset=utf-8":{}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]}]},"put":{"tags":["setting"],"summary":"Update CoolerControl UI Settings","description":"Updates and persists the CoolerControl UI settings.","requestBody":{"content":{"text/plain; charset=utf-8":{}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]}]}},"/plugins":{"get":{"tags":["plugins"],"summary":"CoolerControl Plugins","description":"Returns the current list of active CoolerControl plugins.","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PluginsDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]}]}},"/plugins/lib/cc-plugin-lib.js":{"get":{"tags":["plugins"],"summary":"CoolerControl Plugin UI Library","description":"Returns the CoolerControl plugin UI library for plugins to use in their UI code.","responses":{"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}}}},"/plugins/{plugin_id}/config":{"get":{"tags":["plugins"],"summary":"CoolerControl Plugin Config","description":"Returns the current CoolerControl plugin config for the given plugin ID.","parameters":[{"in":"path","name":"plugin_id","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"plain text","content":{"text/plain; charset=utf-8":{}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]}]},"put":{"tags":["plugins"],"summary":"Update CoolerControl Plugin Config","description":"Updates the CoolerControl plugin config for the given plugin ID.","parameters":[{"in":"path","name":"plugin_id","required":true,"schema":{"type":"string"},"style":"simple"}],"requestBody":{"content":{"text/plain; charset=utf-8":{}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]}]}},"/plugins/{plugin_id}/ui":{"get":{"tags":["plugins"],"summary":"CoolerControl Plugin UI Check","description":"Returns if the CoolerControl plugin has a UI or not.","parameters":[{"in":"path","name":"plugin_id","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasUiDto"}}}}},"security":[{"CookieAuth":[]}]}},"/plugins/{plugin_id}/ui/{file_name}":{"get":{"tags":["plugins"],"summary":"CoolerControl Plugin UI","description":"Returns the CoolerControl plugin UI file for the given plugin ID.","parameters":[{"in":"path","name":"file_name","required":true,"schema":{"type":"string"},"style":"simple"},{"in":"path","name":"plugin_id","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]}]}},"/alerts":{"get":{"tags":["alert"],"summary":"Retrieve Alert List","description":"Returns a list of all the persisted Alerts.","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertsDto"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"put":{"tags":["alert"],"summary":"Update Alert","description":"Updates the Alert with the given properties. Dependent on the Alert UID.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertDto"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"post":{"tags":["alert"],"summary":"Create Alert","description":"Creates the given Alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertDto"}}},"required":true},"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/alerts/{alert_uid}":{"delete":{"tags":["alert"],"summary":"Delete Alert","description":"Deletes the Alert with the given Alert UID","parameters":[{"in":"path","name":"alert_uid","required":true,"schema":{"type":"string"},"style":"simple"}],"responses":{"200":{"description":"no content"},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/detect":{"get":{"tags":["detect"],"summary":"Detect Hardware","description":"Run Super-I/O hardware detection and return results without loading modules.","responses":{"200":{"description":"Response for GET/POST /detect","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetectResponse"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]},"post":{"tags":["detect"],"summary":"Detect Hardware and Load Modules","description":"Run Super-I/O hardware detection and optionally load kernel modules.","requestBody":{"description":"Request body for POST /detect","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetectRequest"}}},"required":true},"responses":{"200":{"description":"Response for GET/POST /detect","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetectResponse"}}}},"400":{"description":"Bad Request. The request is invalid"},"401":{"description":"Unauthorized. Invalid credentials were provided."},"403":{"description":"Forbidden. Insufficient permissions."},"404":{"description":"Whatever you're looking for, it's not here."},"500":{"description":"An internal error has occurred."},"429":{"description":"Too Many Requests. Login attempts have been rate limited."},"502":{"description":"Bad Gateway. An error has occurred with an external library."}},"security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/sse/logs":{"get":{"tags":["sse"],"summary":"Log Server Sent Events","description":"Subscribes and returns the Server Sent Events for a Log stream","security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/sse/status":{"get":{"tags":["sse"],"summary":"Recent Status Server Sent Events","description":"Subscribes and returns the Server Sent Events for a Status stream","security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/sse/modes":{"get":{"tags":["sse"],"summary":"Activated Mode Events","description":"Subscribes and returns the Server Sent Events for a ModeActivated stream","security":[{"CookieAuth":[]},{"BearerAuth":[]}]}},"/sse/alerts":{"get":{"tags":["sse"],"summary":"Alert Events","description":"Subscribes and returns Events for when an Alert State has changed","security":[{"CookieAuth":[]},{"BearerAuth":[]}]}}},"components":{"securitySchemes":{"CookieAuth":{"type":"apiKey","in":"cookie","name":"cc","description":"The private session cookie used for authentication."},"BasicAuth":{"type":"http","scheme":"basic","bearerFormat":"","description":"HTTP Basic authentication, mostly used to generate a secure authentication cookie."},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"cc_
","description":"Bearer token authentication for external services."}},"schemas":{"ActiveModesDto":{"type":"object","properties":{"current_mode_uid":{"type":["string","null"]},"previous_mode_uid":{"type":["string","null"]}}},"AlertDto":{"type":"object","properties":{"channel_source":{"$ref":"#/components/schemas/ChannelSource"},"desktop_notify":{"description":"Toggle a desktop notification when this alert enters an `Active` state. (true by default)","type":"boolean","default":true},"desktop_notify_audio":{"description":"Toggle whether the desktop notification attempts to play an audio sound\n when this alert enters an `Active` state.\n Note: only applies when `desktop_notify` is enabled.","type":"boolean","default":false},"desktop_notify_recovery":{"description":"Toggle a desktop notification when this alert enters an `Inactive` state.","type":"boolean","default":true},"max":{"type":"number","format":"double"},"min":{"type":"number","format":"double"},"name":{"type":"string"},"shutdown_on_activation":{"description":"Toggle whether to issue a system shutdown when this Alert enters an `Active` state.\n Duration of the alert before shutdown is determined by `shutdown_active_duration`.","type":"boolean","default":false},"state":{"anyOf":[{"$ref":"#/components/schemas/AlertState"},{"type":"null"}]},"uid":{"type":"string"},"warmup_duration":{"description":"Time in seconds throughout which the alert condition must hold before the alert is activated","type":"number","format":"double"}},"required":["uid","name","channel_source","min","max","warmup_duration"]},"AlertLog":{"type":"object","properties":{"message":{"type":"string"},"name":{"type":"string"},"state":{"$ref":"#/components/schemas/AlertState"},"timestamp":{"type":"string","format":"date-time"},"uid":{"type":"string"}},"required":["uid","name","state","message","timestamp"]},"AlertPath":{"type":"object","properties":{"alert_uid":{"type":"string"}},"required":["alert_uid"]},"AlertState":{"oneOf":[{"type":"string","enum":["Active","Inactive"]},{"description":"Alert condition was satisfied at the stored time\n but the duration threshold has not been reached.","type":"object","properties":{"WarmUp":{"type":"string","format":"date-time"}},"additionalProperties":false,"required":["WarmUp"]},{"description":"Represents an error state. e.g. when one of the components in the alert isn't found.","type":"string","const":"Error"}]},"AlertsDto":{"type":"object","properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/AlertDto"}},"logs":{"type":"array","items":{"$ref":"#/components/schemas/AlertLog"}}},"required":["alerts","logs"]},"AseTek690Request":{"type":"object","properties":{"is_legacy690":{"type":"boolean"}},"required":["is_legacy690"]},"BaseDriver":{"type":"string","enum":["Aquacomputer","Legacy690Lc","Modern690Lc","Hydro690Lc","HydroPro","AsusRyujin","AuraLed","CommanderCore","CommanderPro","Coolit","CorsairHidPsu","Ddr4Temperature","VengeanceRgb","HydroPlatinum","Kraken2","KrakenX3","KrakenZ3","MockKrakenZ3","MpgCooler","EvgaPascal","RogTuring","NzxtEPsu","RgbFusion2","SmartDevice","SmartDevice2","H1V2","MsiAcpiEc","LianLiUni","NotSupported"]},"CCChannelSettings":{"type":"object","properties":{"disabled":{"type":"boolean"},"extension":{"description":"Specialized settings (extensions) that apply to a specific device channel.","anyOf":[{"$ref":"#/components/schemas/ChannelExtensions"},{"type":"null"}]},"label":{"type":["string","null"]}},"required":["disabled"]},"CCDeviceSettings":{"description":"Device Specific settings that generally apply to how the application deals with the device.","type":"object","properties":{"channel_settings":{"description":"A list of channels specific settings, including disable and extension settings.","type":"object","additionalProperties":{"$ref":"#/components/schemas/CCChannelSettings"}},"disable":{"description":"All communication with this device will be avoided if disabled","type":"boolean"},"extensions":{"description":"Specialized settings (extensions) that apply to a specific device.","allOf":[{"$ref":"#/components/schemas/DeviceExtensions"}]},"name":{"description":"The device name for this setting. Helpful after blacklisting(disabling) devices.","type":"string"}},"required":["name","disable","extensions","channel_settings"]},"CSPath":{"type":"object","properties":{"custom_sensor_id":{"type":"string"}},"required":["custom_sensor_id"]},"ChannelExtensionNames":{"description":"Channel extension names that signal which `ChannelExtensions` are applicable\n for a particular device channel.","type":"string","enum":["AutoHWCurve","AmdRdnaGpu"]},"ChannelExtensions":{"description":"Device Channel specific settings\n This is used to store specialized settings (extensions) that apply to a specific device channel.","anyOf":[{"description":"Whether to use the device channel's internal hardware fan curve functionality.","type":"object","properties":{"auto_hw_curve_enabled":{"type":"boolean"}},"required":["auto_hw_curve_enabled"]},{"description":"Whether to use the AMDGPU RDNA3/4 features.\n It allows the device to run at zero RPM when the temperature is below a certain threshold.","type":"object","properties":{"hw_fan_curve_enabled":{"description":"Whether to use the internal HW Curve feature, instead of setting regular\n flat curves. Using this reduces functionality.","type":"boolean"}},"required":["hw_fan_curve_enabled"]}]},"ChannelInfo":{"type":"object","properties":{"label":{"type":["string","null"]},"lcd_info":{"anyOf":[{"$ref":"#/components/schemas/LcdInfo"},{"type":"null"}]},"lcd_modes":{"type":"array","items":{"$ref":"#/components/schemas/LcdMode"}},"lighting_modes":{"type":"array","items":{"$ref":"#/components/schemas/LightingMode"}},"speed_options":{"anyOf":[{"$ref":"#/components/schemas/SpeedOptions"},{"type":"null"}]}},"required":["lighting_modes","lcd_modes"]},"ChannelMetric":{"type":"string","enum":["Temp","Duty","Load","RPM","Freq"]},"ChannelSource":{"description":"A source for displaying sensor data that is related to a particular channel.\n This is like `TempSource` but not limited to temperature sensors. (Load, Duty, etc.)","type":"object","properties":{"channel_metric":{"$ref":"#/components/schemas/ChannelMetric"},"channel_name":{"description":"The internal name for this channel source. NOT the Label.","type":"string"},"device_uid":{"description":"The associated device uid containing current values","type":"string"}},"required":["device_uid","channel_name","channel_metric"]},"ChannelStatus":{"type":"object","properties":{"duty":{"type":["number","null"],"format":"double"},"freq":{"type":["integer","null"],"format":"uint32","minimum":0},"name":{"type":"string"},"pwm_mode":{"type":["integer","null"],"format":"uint8","maximum":255,"minimum":0},"rpm":{"type":["integer","null"],"format":"uint32","minimum":0},"watts":{"type":["number","null"],"format":"double"}},"required":["name"]},"CoolerControlAllDeviceSettingsDto":{"type":"object","properties":{"devices":{"type":"array","items":{"$ref":"#/components/schemas/CoolerControlDeviceSettingsDto"}}},"required":["devices"]},"CoolerControlDeviceSettingsDto":{"type":"object","properties":{"channel_settings":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/CCChannelSettings"}},"disable":{"type":"boolean"},"extensions":{"$ref":"#/components/schemas/DeviceExtensions"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["uid","name","disable","extensions","channel_settings"]},"CoolerControlSettingsDto":{"type":"object","properties":{"allow_unencrypted":{"description":"Allow unencrypted HTTP connections from non-localhost addresses","type":["boolean","null"]},"apply_on_boot":{"type":["boolean","null"]},"compress":{"type":["boolean","null"]},"drivetemp_suspend":{"type":["boolean","null"]},"hide_duplicate_devices":{"type":["boolean","null"]},"liquidctl_integration":{"type":["boolean","null"]},"no_init":{"type":["boolean","null"]},"origins":{"description":"Custom origins to allow in CORS (for reverse proxy setups)","type":["array","null"],"items":{"type":"string"}},"poll_rate":{"type":["number","null"],"format":"double"},"protocol_header":{"description":"Header to check for proxy client protocol (e.g., \"X-Forwarded-Proto\")","type":["string","null"]},"startup_delay":{"type":["integer","null"],"format":"uint16","maximum":65535,"minimum":0},"thinkpad_full_speed":{"type":["boolean","null"]}}},"CreateModeDto":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]},"CreateTokenRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time"},"label":{"type":"string"}},"required":["label"]},"CreateTokenResponse":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"id":{"type":"string"},"label":{"type":"string"},"token":{"type":"string"}},"required":["id","label","token","created_at"]},"CustomSensor":{"type":"object","properties":{"children":{"description":"The Custom Sensor's children, if any.\n\n Each Custom Sensor is either a child, parent, or standalone, not a combination of those.\n Custom Sensors are limited to 1 level of hierarchy. This removes the possibility\n of circular references.\n\n The children and parents vectors are managed and filled internally. For GET endpoints,\n they provide this information for clients. For POST or PUT endpoints,\n any values here are essentially ignored.","type":"array","default":[],"items":{"type":"string"}},"cs_type":{"$ref":"#/components/schemas/CustomSensorType"},"file_path":{"type":["string","null"]},"id":{"description":"ID MUST be unique, as `temp_name` must be unique.","type":"string"},"mix_function":{"$ref":"#/components/schemas/CustomSensorMixFunctionType"},"offset":{"type":["integer","null"],"format":"int8","maximum":127,"minimum":-128},"parents":{"description":"The Custom Sensor's parents, if any. See `children` for more details.","type":"array","default":[],"items":{"type":"string"}},"sources":{"type":"array","items":{"$ref":"#/components/schemas/CustomTempSourceData"}}},"required":["id","cs_type","mix_function","sources"]},"CustomSensorMixFunctionType":{"type":"string","enum":["Min","Max","Delta","Avg","WeightedAvg"]},"CustomSensorType":{"type":"string","enum":["Mix","File","Offset"]},"CustomSensorsDto":{"type":"object","properties":{"custom_sensors":{"type":"array","items":{"$ref":"#/components/schemas/CustomSensor"}}},"required":["custom_sensors"]},"CustomTempSourceData":{"type":"object","properties":{"temp_source":{"$ref":"#/components/schemas/TempSource"},"weight":{"type":"integer","format":"uint8","maximum":255,"minimum":0}},"required":["temp_source","weight"]},"DetectRequest":{"description":"Request body for POST /detect","type":"object","properties":{"load_modules":{"type":"boolean","default":false}}},"DetectResponse":{"description":"Response for GET/POST /detect","type":"object","properties":{"blacklisted":{"type":"array","items":{"type":"string"}},"detected_chips":{"type":"array","items":{"$ref":"#/components/schemas/DetectedChipDto"}},"environment":{"$ref":"#/components/schemas/EnvironmentDto"},"skipped":{"type":"array","items":{"$ref":"#/components/schemas/SkippedDriverDto"}}},"required":["detected_chips","skipped","blacklisted","environment"]},"DetectedChipDto":{"type":"object","properties":{"address":{"type":"string"},"base_address":{"type":"string"},"driver":{"type":"string"},"features":{"type":"array","items":{"type":"string"}},"module_status":{"type":"string"},"name":{"type":"string"}},"required":["name","driver","address","base_address","features","module_status"]},"DeviceChannelPath":{"type":"object","properties":{"channel_name":{"type":"string"},"device_uid":{"type":"string"}},"required":["device_uid","channel_name"]},"DeviceChannelStatusDto":{"type":"object","properties":{"status_history":{"type":"array","items":{"$ref":"#/components/schemas/Status"}}},"required":["status_history"]},"DeviceDto":{"type":"object","properties":{"d_type":{"$ref":"#/components/schemas/DeviceType"},"info":{"$ref":"#/components/schemas/DeviceInfo"},"lc_info":{"anyOf":[{"$ref":"#/components/schemas/LcInfo"},{"type":"null"}]},"name":{"type":"string"},"type_index":{"type":"integer","format":"uint8","maximum":255,"minimum":0},"uid":{"type":"string"}},"required":["name","d_type","type_index","uid","info"]},"DeviceExtensions":{"description":"Device specific extension settings\n This is used to store specialized settings (extensions) that apply to a specific device.\n More than one of these settings can be applied at a time.","type":"object","properties":{"delay_millis":{"description":"The delay in milliseconds to force between applying settings to this device.\n This is to help with communication issues with some devices that may not handle\n multiple settings applied in quick succession. (The driver does not always handle this)","type":"integer","format":"uint16","maximum":65535,"minimum":0},"direct_access":{"description":"Whether to enable Direct Access for the liquidctl driver,\n which will cause liquidctl to ignore the `HWMon` kernel driver","type":"boolean"}},"required":["direct_access","delay_millis"]},"DeviceInfo":{"description":"Needed Device info per device","type":"object","properties":{"channels":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ChannelInfo"}},"driver_info":{"$ref":"#/components/schemas/DriverInfo"},"lighting_speeds":{"type":"array","items":{"type":"string"}},"model":{"type":["string","null"]},"profile_max_length":{"type":"integer","format":"uint8","maximum":255,"minimum":0},"profile_min_length":{"type":"integer","format":"uint8","maximum":255,"minimum":0},"temp_max":{"description":"The absolute maximum temp to use for Profiles for this device","type":"integer","format":"uint8","maximum":255,"minimum":0},"temp_min":{"description":"The absolute minimum temp to use for Profiles for this device","type":"integer","format":"uint8","maximum":255,"minimum":0},"temps":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/TempInfo"}},"thinkpad_fan_control":{"description":"When present, then this is a `ThinkPad` device. True or False indicates whether Fan control\n is enabled for the kernel module and changing values is possible","type":["boolean","null"]}},"required":["channels","temps","lighting_speeds","temp_min","temp_max","profile_max_length","profile_min_length","driver_info"]},"DevicePath":{"type":"object","properties":{"device_uid":{"type":"string"}},"required":["device_uid"]},"DeviceStatusDto":{"type":"object","properties":{"d_type":{"$ref":"#/components/schemas/DeviceType"},"status_history":{"description":"Status history wrapped in Arc for O(1) cloning for serialization","type":"array","items":{"$ref":"#/components/schemas/Status"}},"type_index":{"type":"integer","format":"uint8","maximum":255,"minimum":0},"uid":{"type":"string"}},"required":["d_type","type_index","uid","status_history"]},"DeviceType":{"type":"string","enum":["CPU","GPU","Liquidctl","Hwmon","CustomSensors","ServicePlugin"]},"DevicesResponse":{"type":"object","properties":{"devices":{"type":"array","items":{"$ref":"#/components/schemas/DeviceDto"}}},"required":["devices"]},"DriverInfo":{"description":"Device Driver Information","type":"object","properties":{"drv_type":{"$ref":"#/components/schemas/DriverType"},"locations":{"description":"If available various paths used to access the device.\n This can include paths like the kernel device path, hwmon path, HID path, or PCI Bus ID","type":"array","items":{"type":"string"}},"name":{"description":"If available the kernel driver name or liquidctl driver class.","type":["string","null"]},"version":{"description":"If available the driver's version.\n For kernel-based drivers this is the current kernel version.\n For liquidctl-based drivers this is the liquidctl version.\n For Nvidia-based drivers this is the version of the installed nvidia proprietary drivers.","type":["string","null"]}},"required":["drv_type","locations"]},"DriverType":{"description":"The Driver Type, or source of the driver actively being used for this device.","type":"string","enum":["Kernel","Liquidctl","NVML","NvidiaCLI","CoolerControl","External"]},"EnvironmentDto":{"type":"object","properties":{"has_dev_port":{"type":"boolean"},"is_container":{"type":"boolean"}},"required":["is_container","has_dev_port"]},"Function":{"type":"object","properties":{"deviance":{"description":"The temperature deviance threshold in degrees","type":["number","null"],"format":"double"},"duty_maximum":{"description":"The maximum duty change (step size) to apply\n A duty maximum of `0` indicates a fixed step size. Use `duty_minimum` to set the step size.\n Previously `duty_maximum`.","type":"integer","format":"uint8","maximum":255,"minimum":0},"duty_minimum":{"description":"The minimum duty change (step size) to apply\n Previously `duty_minimum`.","type":"integer","format":"uint8","maximum":255,"minimum":0},"f_type":{"description":"The type of this function","allOf":[{"$ref":"#/components/schemas/FunctionType"}]},"name":{"description":"The user given name for this function","type":"string"},"only_downward":{"description":"Whether to apply settings only on the way down","type":["boolean","null"]},"response_delay":{"description":"The response delay in seconds","type":["integer","null"],"format":"uint8","maximum":255,"minimum":0},"sample_window":{"description":"The sample window this function should use, particularly applicable to moving averages","type":["integer","null"],"format":"uint8","maximum":255,"minimum":0},"step_size_max_decreasing":{"description":"The maximum step size to apply when decreasing.\n A value of `0` indicates a fixed step size. Use `step_size_minimum_decreasing` to set the step size.","type":"integer","format":"uint8","maximum":255,"minimum":0},"step_size_min_decreasing":{"description":"The minimum step size to apply when decreasing.\n A value of `0` indicates a symmetric step size. Use `duty_minimum` to set the step size.","type":"integer","format":"uint8","maximum":255,"minimum":0},"threshold_hopping":{"description":"Whether to temporarily bypass thresholds when fan speed remains unchanged for 30+ seconds to meet curve target.","type":"boolean"},"uid":{"description":"The Unique identifier for this function","type":"string"}},"required":["uid","name","f_type","duty_minimum","duty_maximum","step_size_min_decreasing","step_size_max_decreasing","threshold_hopping"]},"FunctionPath":{"type":"object","properties":{"function_uid":{"type":"string"}},"required":["function_uid"]},"FunctionType":{"type":"string","enum":["Identity","Standard","ExponentialMovingAvg"]},"FunctionsDto":{"type":"object","properties":{"functions":{"type":"array","items":{"$ref":"#/components/schemas/Function"}}},"required":["functions"]},"HasUiDto":{"type":"object","properties":{"has_ui":{"type":"boolean"}},"required":["has_ui"]},"HealthCheck":{"type":"object","properties":{"description":{"type":"string"},"current_timestamp":{"type":"string","format":"date-time"},"details":{"$ref":"#/components/schemas/HealthDetails"},"links":{"type":"object","additionalProperties":{"type":"string"}},"status":{"type":"string"},"system":{"$ref":"#/components/schemas/SystemDetails"}},"required":["status","description","current_timestamp","details","system","links"]},"HealthDetails":{"type":"object","properties":{"errors":{"type":"integer","format":"uint","minimum":0},"liquidctl_connected":{"type":"boolean"},"memory_mb":{"type":"number","format":"double"},"pid":{"type":"integer","format":"uint32","minimum":0},"uptime":{"type":"string"},"version":{"type":"string"},"warnings":{"type":"integer","format":"uint","minimum":0}},"required":["uptime","version","pid","memory_mb","warnings","errors","liquidctl_connected"]},"LcInfo":{"description":"Specific Liquidctl device information","type":"object","properties":{"driver_type":{"description":"An Enum representation of the various Liquidctl driver classes","allOf":[{"$ref":"#/components/schemas/BaseDriver"}]},"firmware_version":{"description":"The detected firmware version at initialization","type":["string","null"]},"unknown_asetek":{"description":"An indicator for needed user input to determine actual asetek690lc device","type":"boolean"}},"required":["driver_type","unknown_asetek"]},"LcdCarouselSettings":{"description":"Settings for the LCD Carousel.\n\n This can be used to have a carousel of images (static or gif), of sensor data,\n or a combination of both.","type":"object","properties":{"images_path":{"description":"The absolute path directory location for images for the carousel. All applicable images\n present are processed when the setting is applied.","type":["string","null"]},"interval":{"description":"The interval in seconds (2-900) in which to change images in the carousel.","type":"integer","format":"uint64","minimum":0}},"required":["interval"]},"LcdImageUpdateQuery":{"type":"object","properties":{"log":{"type":["boolean","null"],"default":null}}},"LcdInfo":{"description":"Specific LCD Screen info","type":"object","properties":{"max_image_size_bytes":{"type":"integer","format":"uint32","minimum":0},"screen_height":{"type":"integer","format":"uint32","minimum":0},"screen_width":{"type":"integer","format":"uint32","minimum":0}},"required":["screen_width","screen_height","max_image_size_bytes"]},"LcdMode":{"type":"object","properties":{"brightness":{"type":"boolean"},"colors_max":{"type":"integer","format":"uint8","maximum":255,"minimum":0},"colors_min":{"type":"integer","format":"uint8","maximum":255,"minimum":0},"frontend_name":{"type":"string"},"image":{"type":"boolean"},"name":{"type":"string"},"orientation":{"type":"boolean"},"type_":{"$ref":"#/components/schemas/LcdModeType"}},"required":["name","frontend_name","brightness","orientation","image","colors_min","colors_max","type_"]},"LcdModeName":{"type":"string","enum":["none","liquid","image","temp","carousel"]},"LcdModeType":{"type":"string","enum":["None","Liquidctl","Custom"]},"LcdSettings":{"type":"object","properties":{"brightness":{"description":"The LCD brightness (0-100%)","type":["integer","null"],"format":"uint8","maximum":255,"minimum":0},"carousel":{"anyOf":[{"$ref":"#/components/schemas/LcdCarouselSettings"},{"type":"null"}]},"colors":{"description":"a list of RGB tuple values, eg [(20,20,120), (0,0,255)]","type":"array","items":{"type":"array","items":[{"type":"integer","format":"uint8","maximum":255,"minimum":0},{"type":"integer","format":"uint8","maximum":255,"minimum":0},{"type":"integer","format":"uint8","maximum":255,"minimum":0}],"maxItems":3,"minItems":3}},"image_file_processed":{"description":"The LCD Image processed file path location, where the preprocessed image is located.","type":["string","null"]},"mode":{"description":"The Lcd mode name","allOf":[{"$ref":"#/components/schemas/LcdModeName"}]},"orientation":{"description":"The LCD Image orientation (0,90,180,270)","type":["integer","null"],"format":"uint16","maximum":65535,"minimum":0},"temp_source":{"description":"A temp source for displaying a temperature.","anyOf":[{"$ref":"#/components/schemas/TempSource"},{"type":"null"}]}},"required":["mode","colors"]},"LightingMode":{"type":"object","properties":{"backward_enabled":{"type":"boolean"},"frontend_name":{"type":"string"},"max_colors":{"type":"integer","format":"uint8","maximum":255,"minimum":0},"min_colors":{"type":"integer","format":"uint8","maximum":255,"minimum":0},"name":{"type":"string"},"speed_enabled":{"type":"boolean"},"type_":{"$ref":"#/components/schemas/LightingModeType"}},"required":["name","frontend_name","min_colors","max_colors","speed_enabled","backward_enabled","type_"]},"LightingModeType":{"type":"string","enum":["None","Liquidctl","Custom"]},"LightingSettings":{"type":"object","properties":{"backward":{"description":"run backwards or not","type":["boolean","null"]},"colors":{"description":"a list of RGB tuple values, eg [(20,20,120), (0,0,255)]","type":"array","items":{"type":"array","items":[{"type":"integer","format":"uint8","maximum":255,"minimum":0},{"type":"integer","format":"uint8","maximum":255,"minimum":0},{"type":"integer","format":"uint8","maximum":255,"minimum":0}],"maxItems":3,"minItems":3}},"mode":{"description":"The lighting mode name","type":"string"},"speed":{"description":"The speed to set","type":["string","null"]}},"required":["mode","colors"]},"ModeDto":{"type":"object","properties":{"device_settings":{"type":"array","items":{"type":"array","items":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/Setting"}}],"maxItems":2,"minItems":2}},"name":{"type":"string"},"uid":{"type":"string"}},"required":["uid","name","device_settings"]},"ModeOrderDto":{"type":"object","properties":{"mode_uids":{"type":"array","items":{"type":"string"}}},"required":["mode_uids"]},"ModePath":{"type":"object","properties":{"mode_uid":{"type":"string"}},"required":["mode_uid"]},"ModesDto":{"type":"object","properties":{"modes":{"type":"array","items":{"$ref":"#/components/schemas/ModeDto"}}},"required":["modes"]},"PluginDto":{"type":"object","properties":{"description":{"type":["string","null"]},"address":{"type":"string"},"id":{"type":"string"},"path":{"type":"string"},"privileged":{"type":"boolean"},"service_type":{"type":"string"},"url":{"type":["string","null"]},"version":{"type":["string","null"]}},"required":["id","service_type","address","privileged","path"]},"PluginPath":{"type":"object","properties":{"plugin_id":{"type":"string"}},"required":["plugin_id"]},"PluginUiPath":{"type":"object","properties":{"file_name":{"type":"string"},"plugin_id":{"type":"string"}},"required":["plugin_id","file_name"]},"PluginsDto":{"type":"object","properties":{"plugins":{"type":"array","items":{"$ref":"#/components/schemas/PluginDto"}}},"required":["plugins"]},"Profile":{"description":"Profile Settings","type":"object","properties":{"function_uid":{"description":"The function uid to apply to this profile","type":"string"},"member_profile_uids":{"description":"The profiles that make up the mix profile","type":"array","items":{"type":"string"}},"mix_function_type":{"description":"The function to mix the members with if this is a Mix Profile","anyOf":[{"$ref":"#/components/schemas/ProfileMixFunctionType"},{"type":"null"}]},"name":{"description":"The User given name for this Profile","type":"string"},"offset_profile":{"description":"The graph offset to apply to the associated member profile\n This can also be used as a static offset when there is only one duty/offset pair.","type":["array","null"],"items":{"type":"array","items":[{"type":"integer","format":"uint8","maximum":255,"minimum":0},{"type":"integer","format":"int8","maximum":127,"minimum":-128}],"maxItems":2,"minItems":2}},"p_type":{"description":"The profile type","allOf":[{"$ref":"#/components/schemas/ProfileType"}]},"speed_fixed":{"description":"The fixed duty speed to set. eg: 20 (%)","type":["integer","null"],"format":"uint8","maximum":255,"minimum":0},"speed_profile":{"description":"The profile temp/duty speeds to set. eg: [(20.0, 50), (25.7, 80)]","type":["array","null"],"items":{"type":"array","items":[{"type":"number","format":"double"},{"type":"integer","format":"uint8","maximum":255,"minimum":0}],"maxItems":2,"minItems":2}},"temp_max":{"description":"The maximum temp for this profile","type":["number","null"],"format":"double"},"temp_min":{"description":"The minimum temp for this profile","type":["number","null"],"format":"double"},"temp_source":{"description":"The associated temperature source","anyOf":[{"$ref":"#/components/schemas/TempSource"},{"type":"null"}]},"uid":{"description":"The Unique Identifier for this Profile","type":"string"}},"required":["uid","p_type","name","function_uid","member_profile_uids"]},"ProfileMixFunctionType":{"type":"string","enum":["Min","Max","Avg","Diff","Sum"]},"ProfilePath":{"type":"object","properties":{"profile_uid":{"type":"string"}},"required":["profile_uid"]},"ProfileType":{"type":"string","enum":["Default","Fixed","Graph","Mix","Overlay"]},"ProfilesDto":{"type":"object","properties":{"profiles":{"type":"array","items":{"$ref":"#/components/schemas/Profile"}}},"required":["profiles"]},"SetPasswdRequest":{"type":"object","properties":{"current_password":{"type":"string"}},"required":["current_password"]},"Setting":{"description":"Setting is used to store applied Settings to a device channel.\n These are the general core settings that apply to a wide range of device and channel types.\n Specialized settings are stored in `DeviceExtensions` and `ChannelExtensions`.\n Only one specific lighting or speed setting is applied to a specific channel at a time.","type":"object","properties":{"channel_name":{"type":"string"},"lcd":{"description":"Settings for LCD screens","anyOf":[{"$ref":"#/components/schemas/LcdSettings"},{"type":"null"}]},"lighting":{"description":"Settings for lighting","anyOf":[{"$ref":"#/components/schemas/LightingSettings"},{"type":"null"}]},"profile_uid":{"description":"The Profile UID that applies to this device channel","type":["string","null"]},"reset_to_default":{"description":"Used to set hwmon & nvidia channels back to their default 'automatic' values.","type":["boolean","null"]},"speed_fixed":{"description":"The fixed duty speed to set. eg: 20 (%)","type":["integer","null"],"format":"uint8","maximum":255,"minimum":0}},"required":["channel_name"]},"SettingManualRequest":{"type":"object","properties":{"speed_fixed":{"type":"integer","format":"uint8","maximum":255,"minimum":0}},"required":["speed_fixed"]},"SettingPWMMode":{"type":"object","properties":{"pwm_mode":{"type":"integer","format":"uint8","maximum":255,"minimum":0}},"required":["pwm_mode"]},"SettingProfileUID":{"type":"object","properties":{"profile_uid":{"type":"string"}},"required":["profile_uid"]},"SettingsResponse":{"type":"object","properties":{"settings":{"type":"array","items":{"$ref":"#/components/schemas/Setting"}}},"required":["settings"]},"SkippedDriverDto":{"type":"object","properties":{"driver":{"type":"string"},"preferred":{"type":"string"},"reason":{"type":"string"}},"required":["driver","reason","preferred"]},"SpeedOptions":{"type":"object","properties":{"extension":{"description":"If present, then this channel has special settings that are applicable.","anyOf":[{"$ref":"#/components/schemas/ChannelExtensionNames"},{"type":"null"}]},"fixed_enabled":{"description":"True if manual fan speed control is supported; if false, speeds are read-only (monitoring only).","type":"boolean"},"max_duty":{"description":"The maximum fan duty for this speed channel","type":"integer","format":"uint8","maximum":255,"minimum":0},"min_duty":{"description":"The minimum fan duty for this speed channel","type":"integer","format":"uint8","maximum":255,"minimum":0}},"required":["min_duty","max_duty","fixed_enabled"]},"Status":{"description":"A Model which contains various applicable device statuses","type":"object","properties":{"channels":{"type":"array","items":{"$ref":"#/components/schemas/ChannelStatus"}},"temps":{"type":"array","items":{"$ref":"#/components/schemas/TempStatus"}},"timestamp":{"type":"string","format":"date-time"}},"required":["timestamp","temps","channels"]},"StatusQuery":{"type":"object","properties":{"all":{"type":["boolean","null"],"default":null}}},"StatusRequest":{"type":"object","properties":{"all":{"type":["boolean","null"]},"since":{"type":["string","null"],"format":"date-time"}}},"StatusResponse":{"type":"object","properties":{"devices":{"type":"array","items":{"$ref":"#/components/schemas/DeviceStatusDto"}}},"required":["devices"]},"SystemDetails":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]},"TempInfo":{"type":"object","properties":{"label":{"type":"string"},"number":{"type":"integer","format":"uint8","maximum":255,"minimum":0}},"required":["label","number"]},"TempSource":{"type":"object","properties":{"device_uid":{"description":"The associated device uid containing current temp values","type":"string"},"temp_name":{"description":"The internal name for this Temperature Source. NOT the `TempInfo` Label.","type":"string"}},"required":["temp_name","device_uid"]},"TempStatus":{"type":"object","properties":{"name":{"type":"string"},"temp":{"type":"number","format":"double"}},"required":["name","temp"]},"ThinkPadFanControlRequest":{"type":"object","properties":{"enable":{"type":"boolean"}},"required":["enable"]},"TokenInfo":{"type":"object","properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"id":{"type":"string"},"label":{"type":"string"},"last_used":{"type":["string","null"],"format":"date-time"}},"required":["id","label","created_at"]},"TokenListResponse":{"type":"object","properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/TokenInfo"}}},"required":["tokens"]},"TokenPath":{"type":"object","properties":{"token_id":{"type":"string"}},"required":["token_id"]},"UpdateModeDto":{"type":"object","properties":{"name":{"type":"string"},"uid":{"type":"string"}},"required":["uid","name"]}}},"tags":[{"name":"base","description":"Foundational endpoints for this API"},{"name":"auth","description":"Authentication"},{"name":"device","description":"Device Interaction"},{"name":"status","description":"Device Status"},{"name":"profile","description":"Profiles"},{"name":"function","description":"Functions"},{"name":"custom-sensor","description":"Custom Sensors"},{"name":"mode","description":"Modes"},{"name":"setting","description":"Settings"},{"name":"alert","description":"Alerts"},{"name":"sse","description":"Server Side Events"},{"name":"plugins","description":"Plugins"}]}
\ No newline at end of file
diff --git a/packaging/coolerdash.spec b/packaging/coolerdash.spec
index cbf5d86..2376432 100644
--- a/packaging/coolerdash.spec
+++ b/packaging/coolerdash.spec
@@ -78,14 +78,12 @@ fi
if [ -f /etc/coolercontrol/plugins/coolerdash/config.json ]; then
chmod 666 /etc/coolercontrol/plugins/coolerdash/config.json
fi
-# Migrate helperd from /etc to /usr/lib
+# Remove legacy helperd service (no longer part of this project)
rm -f /etc/systemd/system/multi-user.target.wants/coolerdash-helperd.service
rm -f /etc/systemd/system/coolerdash-helperd.service
+rm -f /usr/lib/systemd/system/coolerdash-helperd.service
if command -v systemctl >/dev/null 2>&1; then
systemctl daemon-reload
- if systemctl list-unit-files coolerdash-helperd.service | grep -q coolerdash-helperd; then
- systemctl enable --now coolerdash-helperd.service || echo "Note: coolerdash-helperd.service failed. Enable manually."
- fi
if systemctl is-active --quiet coolercontrold.service; then
systemctl restart coolercontrold.service || echo "Note: CoolerControl restart failed."
fi
@@ -93,6 +91,7 @@ fi
%preun
if command -v systemctl >/dev/null 2>&1; then
+ # Stop legacy helperd if still present from old installation
if systemctl list-unit-files coolerdash-helperd.service | grep -q coolerdash-helperd; then
systemctl stop --no-block coolerdash-helperd.service
systemctl disable coolerdash-helperd.service
@@ -155,9 +154,6 @@ fi
/usr/share/applications/coolerdash.desktop
/usr/share/icons/hicolor/scalable/apps/coolerdash.svg
/usr/lib/udev/rules.d/99-coolerdash.rules
-/usr/lib/systemd/system/coolerdash-helperd.service
-%dir /etc/systemd/system/cc-plugin-coolerdash.service.d
-/etc/systemd/system/cc-plugin-coolerdash.service.d/startup-delay.conf
%changelog
* %(date "+%a %b %d %Y") damachine - %{version}-1
diff --git a/packaging/debian/install b/packaging/debian/install
index e0b4112..7c7725b 100644
--- a/packaging/debian/install
+++ b/packaging/debian/install
@@ -12,5 +12,3 @@ usr/share/man/man1/coolerdash.1
usr/share/applications/coolerdash.desktop
usr/share/icons/hicolor/scalable/apps/coolerdash.svg
usr/lib/udev/rules.d/99-coolerdash.rules
-usr/lib/systemd/system/coolerdash-helperd.service
-etc/systemd/system/cc-plugin-coolerdash.service.d/startup-delay.conf
diff --git a/packaging/debian/postinst b/packaging/debian/postinst
index f95df70..d5245f2 100755
--- a/packaging/debian/postinst
+++ b/packaging/debian/postinst
@@ -8,16 +8,14 @@ case "$1" in
chmod 666 /etc/coolercontrol/plugins/coolerdash/config.json
fi
- # Migrate helperd from /etc to /usr/lib
+ # Remove legacy helperd service (no longer part of this project)
rm -f /etc/systemd/system/multi-user.target.wants/coolerdash-helperd.service
rm -f /etc/systemd/system/coolerdash-helperd.service
+ rm -f /usr/lib/systemd/system/coolerdash-helperd.service
# Enable services
if command -v systemctl >/dev/null 2>&1; then
systemctl daemon-reload
- if systemctl list-unit-files coolerdash-helperd.service | grep -q coolerdash-helperd; then
- systemctl enable --now coolerdash-helperd.service || echo "Note: coolerdash-helperd.service failed. Enable manually."
- fi
if systemctl is-active --quiet coolercontrold.service; then
systemctl restart coolercontrold.service || echo "Note: CoolerControl restart failed."
fi
diff --git a/packaging/debian/prerm b/packaging/debian/prerm
index 72eb55c..29ad999 100755
--- a/packaging/debian/prerm
+++ b/packaging/debian/prerm
@@ -5,6 +5,7 @@ case "$1" in
remove|upgrade|deconfigure)
# Stop services
if command -v systemctl >/dev/null 2>&1; then
+ # Stop legacy helperd if still present from old installation
if systemctl list-unit-files coolerdash-helperd.service | grep -q coolerdash-helperd; then
systemctl stop --no-block coolerdash-helperd.service
systemctl disable coolerdash-helperd.service
diff --git a/src/device/config.c b/src/device/config.c
index 464615d..ebbab3f 100644
--- a/src/device/config.c
+++ b/src/device/config.c
@@ -70,9 +70,10 @@ static void set_daemon_defaults(Config *config)
{
SAFE_STRCPY(config->daemon_address, "http://localhost:11987");
}
- if (config->daemon_password[0] == '\0')
+ /* tls_skip_verify: 0 from memset = verify peer (secure default) */
+ if (config->channel_name[0] == '\0')
{
- SAFE_STRCPY(config->daemon_password, "");
+ SAFE_STRCPY(config->channel_name, "lcd");
}
}
@@ -91,8 +92,7 @@ static void set_paths_defaults(Config *config)
}
if (config->paths_image_shutdown[0] == '\0')
{
- SAFE_STRCPY(config->paths_image_shutdown,
- "/etc/coolercontrol/plugins/coolerdash/shutdown.png");
+ SAFE_STRCPY(config->paths_image_shutdown, "/etc/coolercontrol/plugins/coolerdash/shutdown.png");
}
}
@@ -645,13 +645,32 @@ static void load_daemon_from_json(json_t *root, Config *config)
}
}
- json_t *password = json_object_get(daemon, "password");
- if (password && json_is_string(password) && json_string_length(password) > 0)
+ json_t *access_token = json_object_get(daemon, "access_token");
+ if (access_token && json_is_string(access_token) && json_string_length(access_token) > 0)
{
- const char *value = json_string_value(password);
+ const char *value = json_string_value(access_token);
if (value)
{
- SAFE_STRCPY(config->daemon_password, value);
+ SAFE_STRCPY(config->access_token, value);
+ }
+ }
+
+ json_t *tls_skip = json_object_get(daemon, "tls_skip_verify");
+ if (tls_skip)
+ {
+ if (json_is_boolean(tls_skip))
+ config->tls_skip_verify = json_boolean_value(tls_skip) ? 1 : 0;
+ else if (json_is_integer(tls_skip))
+ config->tls_skip_verify = (json_integer_value(tls_skip) != 0) ? 1 : 0;
+ }
+
+ json_t *channel = json_object_get(daemon, "channel_name");
+ if (channel && json_is_string(channel) && json_string_length(channel) > 0)
+ {
+ const char *value = json_string_value(channel);
+ if (value)
+ {
+ SAFE_STRCPY(config->channel_name, value);
}
}
}
diff --git a/src/device/config.h b/src/device/config.h
index 0f8e6b7..f0b340d 100644
--- a/src/device/config.h
+++ b/src/device/config.h
@@ -92,7 +92,9 @@ typedef struct Config
{
// Daemon configuration
char daemon_address[CONFIG_MAX_STRING_LEN];
- char daemon_password[CONFIG_MAX_PASSWORD_LEN];
+ char access_token[CONFIG_MAX_STRING_LEN]; /**< Bearer token for CoolerControl API authentication */
+ int tls_skip_verify; /**< 1 = accept self-signed TLS certificates */
+ char channel_name[32]; /**< LCD channel name, default: "lcd" */
// Paths configuration
char paths_images[CONFIG_MAX_PATH_LEN];
diff --git a/src/main.c b/src/main.c
index 5e5de32..4cfbec0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -646,7 +646,7 @@ static int initialize_config_and_instance(const char *config_path,
*/
static int initialize_coolercontrol_services(const Config *config)
{
- if (!init_coolercontrol_session(config))
+ if (!init_coolercontrol_session())
{
log_message(LOG_ERROR, "CoolerControl session initialization failed");
fprintf(stderr,
@@ -654,7 +654,8 @@ static int initialize_coolercontrol_services(const Config *config)
"Please check:\n"
" - Is coolercontrold running? (systemctl status coolercontrold)\n"
" - Is the daemon running on %s?\n"
- " - Is the password correct in configuration?\n"
+ " - Is access_token set in config.json?\n"
+ " (CoolerControl UI -> Settings -> Access Protection -> Access Tokens)\n"
" - Are network connections allowed?\n",
config->daemon_address);
fflush(stderr);
@@ -665,11 +666,11 @@ static int initialize_coolercontrol_services(const Config *config)
{
log_message(LOG_ERROR, "Failed to initialize device cache");
fprintf(stderr,
- "Error: CoolerControl session could not be initialized\n"
+ "Error: CoolerControl device cache could not be initialized\n"
"Please check:\n"
" - Is coolercontrold running? (systemctl status coolercontrold)\n"
" - Is the daemon running on %s?\n"
- " - Is the password correct in configuration?\n"
+ " - Is access_token set in config.json?\n"
" - Are network connections allowed?\n",
config->daemon_address);
return -1;
diff --git a/src/srv/cc_conf.c b/src/srv/cc_conf.c
index 7ff25ec..cb5a2ca 100644
--- a/src/srv/cc_conf.c
+++ b/src/srv/cc_conf.c
@@ -387,10 +387,12 @@ static int parse_liquidctl_data(const char *json, char *lcd_uid,
/**
* @brief Configure CURL options for device cache request.
+ * @details Sets URL, write callback, timeout, auth headers and TLS.
*/
static void configure_device_cache_curl(CURL *curl, const char *url,
http_response *chunk,
- struct curl_slist **headers)
+ struct curl_slist **headers,
+ const Config *config)
{
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(
@@ -400,7 +402,10 @@ static void configure_device_cache_curl(CURL *curl, const char *url,
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L);
*headers = curl_slist_append(NULL, "accept: application/json");
+ *headers = cc_apply_auth_to_curl(*headers, config);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *headers);
+
+ cc_apply_tls_to_curl(curl, config);
}
/**
@@ -533,7 +538,7 @@ static int initialize_device_cache(const Config *config)
chunk.capacity = 4096;
struct curl_slist *headers = NULL;
- configure_device_cache_curl(curl, url, &chunk, &headers);
+ configure_device_cache_curl(curl, url, &chunk, &headers, config);
int success = 0;
if (curl_easy_perform(curl) == CURLE_OK)
diff --git a/src/srv/cc_main.c b/src/srv/cc_main.c
index c39930e..b9554a6 100644
--- a/src/srv/cc_main.c
+++ b/src/srv/cc_main.c
@@ -8,14 +8,11 @@
*/
/**
- * @brief Session management, authentication, LCD image upload.
- * @details HTTP client for CoolerControl REST API.
+ * @brief Session management, authentication and LCD image upload via CoolerControl REST API.
*/
-// Define POSIX constants
#define _POSIX_C_SOURCE 200112L
-// Include necessary headers
// cppcheck-suppress-begin missingIncludeSystem
#include
#include
@@ -25,15 +22,11 @@
#include
// cppcheck-suppress-end missingIncludeSystem
-// Include project headers
#include "../device/config.h"
#include "cc_conf.h"
#include "cc_main.h"
-/**
- * @brief Initialize HTTP response buffer with specified capacity.
- * @details Allocates memory for HTTP response data with proper initialization.
- */
+/** Allocate and initialise an HTTP response buffer. */
int cc_init_response_buffer(http_response *response, size_t initial_capacity)
{
if (!response || initial_capacity == 0 ||
@@ -56,10 +49,7 @@ int cc_init_response_buffer(http_response *response, size_t initial_capacity)
return 1;
}
-/**
- * @brief Cleanup HTTP response buffer and free memory.
- * @details Properly frees allocated memory and resets buffer state.
- */
+/** Free an HTTP response buffer and reset its state. */
void cc_cleanup_response_buffer(http_response *response)
{
if (!response)
@@ -76,30 +66,18 @@ void cc_cleanup_response_buffer(http_response *response)
response->capacity = 0;
}
-/**
- * @brief Structure to hold CoolerControl session state.
- * @details Contains the CURL handle, cookie jar path, and session
- * initialization status.
- */
+/** CoolerControl session state (CURL handle, init flag). */
typedef struct
{
CURL *curl_handle;
- char cookie_jar[CC_COOKIE_SIZE];
int session_initialized;
} CoolerControlSession;
-/**
- * @brief Global CoolerControl session state.
- * @details Holds the state of the CoolerControl session, including the CURL
- * handle and session initialization status.
- */
+/** Global session instance. */
static CoolerControlSession cc_session = {
- .curl_handle = NULL, .cookie_jar = {0}, .session_initialized = 0};
+ .curl_handle = NULL, .session_initialized = 0};
-/**
- * @brief Reallocate response buffer if needed.
- * @details Grows buffer capacity using exponential growth strategy.
- */
+/** Grow response buffer using exponential strategy. */
static int reallocate_response_buffer(http_response *response,
size_t required_size)
{
@@ -125,11 +103,7 @@ static int reallocate_response_buffer(http_response *response,
return 1;
}
-/**
- * @brief Callback for libcurl to write received data into a buffer.
- * @details This function is called by libcurl to write the response data into a
- * dynamically allocated buffer with automatic reallocation when needed.
- */
+/** libcurl write callback — appends received data to an http_response buffer. */
size_t write_callback(const void *contents, size_t size, size_t nmemb,
http_response *response)
{
@@ -152,10 +126,7 @@ size_t write_callback(const void *contents, size_t size, size_t nmemb,
return realsize;
}
-/**
- * @brief Validate snprintf result for buffer overflow.
- * @details Checks if snprintf truncated output.
- */
+/** Check snprintf result for truncation. */
static int validate_snprintf(int written, size_t buffer_size, char *buffer)
{
if (written < 0 || (size_t)written >= buffer_size)
@@ -167,353 +138,83 @@ static int validate_snprintf(int written, size_t buffer_size, char *buffer)
}
/**
- * @brief Build login URL and credentials for CoolerControl session.
- * @details Constructs the login URL and username:password string from config.
- */
-static int build_login_credentials(const Config *config, char *login_url,
- size_t url_size, char *userpwd,
- size_t pwd_size)
-{
- int written_url =
- snprintf(login_url, url_size, "%s/login", config->daemon_address);
- if (!validate_snprintf(written_url, url_size, login_url))
- return 0;
-
- int written_pwd =
- snprintf(userpwd, pwd_size, "CCAdmin:%s", config->daemon_password);
- if (!validate_snprintf(written_pwd, pwd_size, userpwd))
- return 0;
-
- return 1;
-}
-
-/**
- * @brief Configure CURL for CoolerControl login request.
- * @details Sets up all CURL options including authentication, headers and SSL.
+ * @brief Apply TLS verification options to a CURL handle.
+ * @details Uses tls_skip_verify flag for self-signed certs; verifies peer
+ * when daemon_address starts with "https://".
*/
-static struct curl_slist *configure_login_curl(CURL *curl, const Config *config,
- const char *login_url,
- const char *userpwd)
+void cc_apply_tls_to_curl(CURL *curl, const Config *config)
{
- curl_easy_setopt(curl, CURLOPT_URL, login_url);
- curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
- curl_easy_setopt(curl, CURLOPT_USERPWD, userpwd);
- curl_easy_setopt(curl, CURLOPT_POST, 1L);
- curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
-
- // Set HTTP headers for login request
- struct curl_slist *headers = NULL;
- headers = curl_slist_append(headers, "User-Agent: CoolerDash/1.0");
- headers = curl_slist_append(headers, "Accept: application/json");
- headers = curl_slist_append(headers, "Content-Type: application/json");
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
-
- // Enable SSL verification for HTTPS
- if (strncmp(config->daemon_address, "https://", 8) == 0)
+ if (!curl || !config)
+ return;
+ if (config->tls_skip_verify)
+ {
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
+ }
+ else if (strncmp(config->daemon_address, "https://", 8) == 0)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
}
-
- return headers;
}
/**
- * @brief Check login response status.
- * @details Validates CURL result and HTTP response code.
+ * @brief Append Authorization Bearer header if access_token is configured.
+ * @details Returns the (possibly extended) header list.
*/
-static int is_login_successful(CURLcode res, long response_code)
+struct curl_slist *cc_apply_auth_to_curl(struct curl_slist *headers,
+ const Config *config)
{
- return (res == CURLE_OK && (response_code == 200 || response_code == 204));
+ if (!config || config->access_token[0] == '\0')
+ return headers;
+
+ char auth_header[CC_AUTH_HEADER_SIZE];
+ int written = snprintf(auth_header, sizeof(auth_header),
+ "Authorization: Bearer %s", config->access_token);
+ if (written > 0 && (size_t)written < sizeof(auth_header))
+ headers = curl_slist_append(headers, auth_header);
+ return headers;
}
/**
- * @brief Initializes the CoolerControl session (CURL setup and login).
- * @details This function initializes the CURL library, sets up the session
- * cookie jar, constructs the login URL and credentials, and performs a login to
- * the CoolerControl API.
+ * @brief Initialise a CoolerControl session (CURL setup + Bearer token auth).
*/
-int init_coolercontrol_session(const Config *config)
+int init_coolercontrol_session(void)
{
curl_global_init(CURL_GLOBAL_DEFAULT);
cc_session.curl_handle = curl_easy_init();
if (!cc_session.curl_handle)
return 0;
- int written_cookie =
- snprintf(cc_session.cookie_jar, sizeof(cc_session.cookie_jar),
- "/tmp/coolerdash_cookie_%d.txt", getpid());
- if (written_cookie < 0 ||
- (size_t)written_cookie >= sizeof(cc_session.cookie_jar))
- {
- cc_session.cookie_jar[sizeof(cc_session.cookie_jar) - 1] = '\0';
- }
-
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_COOKIEJAR,
- cc_session.cookie_jar);
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_COOKIEFILE,
- cc_session.cookie_jar);
-
- char login_url[CC_URL_SIZE];
- char userpwd[CC_USERPWD_SIZE];
- if (!build_login_credentials(config, login_url, sizeof(login_url), userpwd,
- sizeof(userpwd)))
- return 0;
-
- struct curl_slist *headers =
- configure_login_curl(cc_session.curl_handle, config, login_url, userpwd);
-
- CURLcode res = curl_easy_perform(cc_session.curl_handle);
- long response_code = 0;
- curl_easy_getinfo(cc_session.curl_handle, CURLINFO_RESPONSE_CODE,
- &response_code);
-
- memset(userpwd, 0, sizeof(userpwd));
-
- if (headers)
- curl_slist_free_all(headers);
-
- if (is_login_successful(res, response_code))
- {
- cc_session.session_initialized = 1;
- return 1;
- }
-
- log_message(LOG_ERROR, "Login failed: CURL code %d, HTTP code %ld", res,
- response_code);
- return 0;
+ cc_session.session_initialized = 1;
+ log_message(LOG_STATUS, "CoolerControl session initialized (Bearer token auth)");
+ return 1;
}
-/**
- * @brief Checks if the CoolerControl session is initialized.
- * @details This function returns whether the session has been successfully
- * initialized and is ready for use.
- */
+/** Returns 1 if the CoolerControl session is ready for use. */
int is_session_initialized(void) { return cc_session.session_initialized; }
-/**
- * @brief Cleans up and terminates the CoolerControl session.
- * @details This function performs cleanup of the CURL handle, removes the
- * cookie jar file, and marks the session as uninitialized.
- */
+/** Release all CURL resources. */
void cleanup_coolercontrol_session(void)
{
static int cleanup_done = 0;
if (cleanup_done)
return;
- int all_cleaned = 1;
-
- // Clean up CURL handle
if (cc_session.curl_handle)
{
curl_easy_cleanup(cc_session.curl_handle);
cc_session.curl_handle = NULL;
}
- // Perform global CURL cleanup
curl_global_cleanup();
- // Remove cookie jar file
- if (unlink(cc_session.cookie_jar) != 0)
- {
- all_cleaned = 0;
- }
-
- // Mark session as uninitialized
cc_session.session_initialized = 0;
-
- // Set cleanup flag only if all operations succeeded
- if (all_cleaned)
- {
- cleanup_done = 1;
- }
-}
-
-/**
- * @brief Add a string field to multipart form with error checking.
- * @details Helper function to add a named string field to curl_mime form.
- */
-static int add_mime_field(curl_mime *form, const char *field_name,
- const char *field_value)
-{
- curl_mimepart *field = curl_mime_addpart(form);
- if (!field)
- {
- log_message(LOG_ERROR, "Failed to create %s field", field_name);
- return 0;
- }
-
- CURLcode result = curl_mime_name(field, field_name);
- if (result != CURLE_OK)
- {
- log_message(LOG_ERROR, "Failed to set %s field name: %s", field_name,
- curl_easy_strerror(result));
- return 0;
- }
-
- result = curl_mime_data(field, field_value, CURL_ZERO_TERMINATED);
- if (result != CURLE_OK)
- {
- log_message(LOG_ERROR, "Failed to set %s field data: %s", field_name,
- curl_easy_strerror(result));
- return 0;
- }
-
- return 1;
-}
-
-/**
- * @brief Add image file to multipart form with error checking.
- * @details Adds the image file field with proper MIME type and validation.
- */
-static int add_image_file_field(curl_mime *form, const char *image_path)
-{
- curl_mimepart *field = curl_mime_addpart(form);
- if (!field)
- {
- log_message(LOG_ERROR, "Failed to create image field");
- return 0;
- }
-
- CURLcode result = curl_mime_name(field, "images[]");
- if (result != CURLE_OK)
- {
- log_message(LOG_ERROR, "Failed to set image field name: %s",
- curl_easy_strerror(result));
- return 0;
- }
-
- result = curl_mime_filedata(field, image_path);
- if (result != CURLE_OK)
- {
- struct stat file_stat;
- if (stat(image_path, &file_stat) == 0)
- {
- log_message(LOG_ERROR, "Failed to set image file data: %s",
- curl_easy_strerror(result));
- }
- return 0;
- }
-
- result = curl_mime_type(field, "image/png");
- if (result != CURLE_OK)
- {
- log_message(LOG_ERROR, "Failed to set image MIME type: %s",
- curl_easy_strerror(result));
- return 0;
- }
-
- return 1;
-}
-
-/**
- * @brief Build multipart form for LCD image upload.
- * @details Constructs the complete multipart form with mode, brightness,
- * orientation and image fields.
- */
-static curl_mime *build_lcd_upload_form(const Config *config,
- const char *image_path)
-{
- curl_mime *form = curl_mime_init(cc_session.curl_handle);
- if (!form)
- {
- log_message(LOG_ERROR, "Failed to initialize multipart form");
- return NULL;
- }
-
- // Add mode field
- if (!add_mime_field(form, "mode", "image"))
- {
- curl_mime_free(form);
- return NULL;
- }
-
- // Add brightness field
- char brightness_str[8];
- snprintf(brightness_str, sizeof(brightness_str), "%d",
- config->lcd_brightness);
- if (!add_mime_field(form, "brightness", brightness_str))
- {
- curl_mime_free(form);
- return NULL;
- }
-
- // Add orientation field
- char orientation_str[8];
- snprintf(orientation_str, sizeof(orientation_str), "%d",
- config->lcd_orientation);
- if (!add_mime_field(form, "orientation", orientation_str))
- {
- curl_mime_free(form);
- return NULL;
- }
-
- // Add image file
- if (!add_image_file_field(form, image_path))
- {
- curl_mime_free(form);
- return NULL;
- }
-
- return form;
-}
-
-/**
- * @brief Configure CURL for LCD image upload request.
- * @details Sets up URL, form data, SSL and response handling.
- */
-static struct curl_slist *configure_lcd_upload_curl(const Config *config,
- const char *upload_url,
- curl_mime *form,
- http_response *response)
-{
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_URL, upload_url);
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_MIMEPOST, form);
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_CUSTOMREQUEST, "PUT");
-
- // Enable SSL verification for HTTPS
- if (strncmp(config->daemon_address, "https://", 8) == 0)
- {
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_SSL_VERIFYPEER, 1L);
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_SSL_VERIFYHOST, 2L);
- }
-
- // Set write callback
- curl_easy_setopt(
- cc_session.curl_handle, CURLOPT_WRITEFUNCTION,
- (size_t (*)(const void *, size_t, size_t, void *))write_callback);
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_WRITEDATA, response);
-
- // Add headers
- struct curl_slist *headers = NULL;
- headers = curl_slist_append(headers, "User-Agent: CoolerDash/1.0");
- headers = curl_slist_append(headers, "Accept: application/json");
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_HTTPHEADER, headers);
-
- return headers;
-}
-
-/**
- * @brief Cleanup CURL options after LCD upload.
- * @details Resets all CURL options set during the upload request.
- */
-static void cleanup_lcd_upload_curl(void)
-{
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_MIMEPOST, NULL);
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_CUSTOMREQUEST, NULL);
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_WRITEFUNCTION, NULL);
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_WRITEDATA, NULL);
- curl_easy_setopt(cc_session.curl_handle, CURLOPT_HTTPHEADER, NULL);
+ cleanup_done = 1;
}
-/**
- * @brief Validate upload request parameters.
- * @details Checks all required parameters for LCD upload.
- */
-static int validate_upload_params(const char *image_path,
- const char *device_uid)
+/** Return 1 if parameters and session state are valid for an LCD upload. */
+static int validate_upload_params(const char *image_path, const char *device_uid)
{
if (!cc_session.curl_handle || !image_path || !device_uid ||
!cc_session.session_initialized)
@@ -524,10 +225,7 @@ static int validate_upload_params(const char *image_path,
return 1;
}
-/**
- * @brief Check LCD upload response.
- * @details Validates CURL result and HTTP response code for LCD upload.
- */
+/** Return 1 if the CURL result and HTTP code indicate a successful upload. */
static int check_upload_response(CURLcode res, long http_response_code,
const http_response *response)
{
@@ -545,52 +243,85 @@ static int check_upload_response(CURLcode res, long http_response_code,
}
/**
- * @brief Sends an image to the LCD display.
- * @details This function uploads an image to the LCD display using a multipart
- * HTTP PUT request.
+ * @brief CC 4.0: PUT JSON body with image_file_processed path to the LCD settings endpoint.
+ * @details CoolerControl reads the file directly — no multipart serialisation needed.
*/
-int send_image_to_lcd(const Config *config, const char *image_path,
- const char *device_uid)
+static int send_image_via_json(const Config *config, const char *image_path,
+ const char *device_uid)
{
- if (!validate_upload_params(image_path, device_uid))
- return 0;
-
char upload_url[CC_URL_SIZE];
- snprintf(upload_url, sizeof(upload_url),
- "%s/devices/%s/settings/lcd/lcd/images?log=false",
- config->daemon_address, device_uid);
+ int written = snprintf(upload_url, sizeof(upload_url),
+ "%s/devices/%s/settings/%s/lcd?log=false",
+ config->daemon_address, device_uid,
+ config->channel_name);
+ if (!validate_snprintf(written, sizeof(upload_url), upload_url))
+ return 0;
- curl_mime *form = build_lcd_upload_form(config, image_path);
- if (!form)
+ /* Build JSON body - path is a plain filesystem path, no special chars */
+ char json_body[1024];
+ written = snprintf(json_body, sizeof(json_body),
+ "{\"mode\":\"image\",\"brightness\":%d,"
+ "\"orientation\":%d,"
+ "\"image_file_processed\":\"%s\",\"colors\":[]}",
+ config->lcd_brightness, config->lcd_orientation,
+ image_path);
+ if (!validate_snprintf(written, sizeof(json_body), json_body))
return 0;
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_URL, upload_url);
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_CUSTOMREQUEST, "PUT");
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_POSTFIELDS, json_body);
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_POSTFIELDSIZE,
+ (long)strlen(json_body));
+
+ cc_apply_tls_to_curl(cc_session.curl_handle, config);
+
http_response response = {0};
if (!cc_init_response_buffer(&response, 4096))
- {
- log_message(LOG_ERROR, "Failed to initialize response buffer");
- curl_mime_free(form);
return 0;
- }
- struct curl_slist *headers =
- configure_lcd_upload_curl(config, upload_url, form, &response);
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_WRITEFUNCTION,
+ (size_t (*)(const void *, size_t, size_t, void *))write_callback);
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_WRITEDATA, &response);
+
+ struct curl_slist *headers = NULL;
+ headers = curl_slist_append(headers, "User-Agent: CoolerDash/1.0");
+ headers = curl_slist_append(headers, "Accept: application/json");
+ headers = curl_slist_append(headers, "Content-Type: application/json");
+ headers = cc_apply_auth_to_curl(headers, config);
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_HTTPHEADER, headers);
CURLcode res = curl_easy_perform(cc_session.curl_handle);
- long http_response_code = -1;
- curl_easy_getinfo(cc_session.curl_handle, CURLINFO_RESPONSE_CODE,
- &http_response_code);
+ long http_code = -1;
+ curl_easy_getinfo(cc_session.curl_handle, CURLINFO_RESPONSE_CODE, &http_code);
- int success = check_upload_response(res, http_response_code, &response);
+ int success = check_upload_response(res, http_code, &response);
cc_cleanup_response_buffer(&response);
if (headers)
curl_slist_free_all(headers);
- curl_mime_free(form);
- cleanup_lcd_upload_curl();
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_CUSTOMREQUEST, NULL);
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_POSTFIELDS, NULL);
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_POSTFIELDSIZE, 0L);
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_WRITEFUNCTION, NULL);
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_WRITEDATA, NULL);
+ curl_easy_setopt(cc_session.curl_handle, CURLOPT_HTTPHEADER, NULL);
return success;
}
+/**
+ * @brief Upload a PNG image to the device LCD via JSON body (CC 4.0).
+ */
+int send_image_to_lcd(const Config *config, const char *image_path,
+ const char *device_uid)
+{
+ if (!validate_upload_params(image_path, device_uid))
+ return 0;
+
+ return send_image_via_json(config, image_path, device_uid);
+}
+
/**
* @brief Blocking wrapper for `send_image_to_lcd` with timeout and retries.
* @details Temporarily sets CURLOPT_TIMEOUT and CURLOPT_CONNECTTIMEOUT on the
@@ -614,7 +345,6 @@ int send_image_to_lcd_blocking(const Config *config, const char *image_path,
for (attempt = 0; attempt < retries; attempt++)
{
- // Set conservative timeouts for shutdown path
curl_easy_setopt(cc_session.curl_handle, CURLOPT_TIMEOUT,
(long)timeout_seconds);
curl_easy_setopt(cc_session.curl_handle, CURLOPT_CONNECTTIMEOUT,
@@ -628,7 +358,7 @@ int send_image_to_lcd_blocking(const Config *config, const char *image_path,
attempt + 1, retries);
}
- // Restore to no timeout (behaviour prior to explicit shutdown upload)
+ /* restore: no timeout (default) */
curl_easy_setopt(cc_session.curl_handle, CURLOPT_TIMEOUT, 0L);
curl_easy_setopt(cc_session.curl_handle, CURLOPT_CONNECTTIMEOUT, 0L);
diff --git a/src/srv/cc_main.h b/src/srv/cc_main.h
index bf86801..ae217b9 100644
--- a/src/srv/cc_main.h
+++ b/src/srv/cc_main.h
@@ -8,40 +8,30 @@
*/
/**
- * @brief Session management, authentication, LCD image upload.
- * @details HTTP client for CoolerControl REST API.
+ * @brief Session management, authentication and LCD image upload via CoolerControl REST API.
*/
#ifndef CC_MAIN_H
#define CC_MAIN_H
-// Include necessary headers
// cppcheck-suppress-begin missingIncludeSystem
#include
#include
+#include
// cppcheck-suppress-end missingIncludeSystem
-// Include project headers
#include "../device/config.h"
-
-// Basic constants
-#define CC_COOKIE_SIZE 512
#define CC_UID_SIZE 128
#define CC_URL_SIZE 512
-#define CC_USERPWD_SIZE 128
+#define CC_AUTH_HEADER_SIZE 320 /**< "Authorization: Bearer " (24) + token (256) + null */
// Maximum safe allocation size to prevent overflow
#define CC_MAX_SAFE_ALLOC_SIZE (SIZE_MAX / 2)
// Forward declarations to reduce compilation dependencies
struct Config;
-struct curl_slist;
-/**
- * @brief Response buffer for libcurl HTTP operations.
- * @details Structure to hold HTTP response data with dynamic memory management
- * for effiziente Datensammlung.
- */
+/** Dynamic response buffer for libcurl HTTP operations. */
typedef struct http_response
{
char *data;
@@ -49,61 +39,37 @@ typedef struct http_response
size_t capacity;
} http_response;
-/**
- * @brief Initialize HTTP response buffer with specified capacity.
- * @details Allocates memory for HTTP response data with proper initialization.
- */
+/** Allocate and initialise an HTTP response buffer. */
int cc_init_response_buffer(http_response *response, size_t initial_capacity);
-/**
- * @brief Cleanup HTTP response buffer and free memory.
- * @details Properly frees allocated memory and resets buffer state.
- */
+/** Free an HTTP response buffer and reset its state. */
void cc_cleanup_response_buffer(http_response *response);
-/**
- * @brief Callback for libcurl to write received data into a buffer.
- * @details This function is used by libcurl to store incoming HTTP response
- * data into a dynamically allocated buffer.
- */
+/** libcurl write callback — appends received data to an http_response buffer. */
size_t write_callback(const void *contents, size_t size, size_t nmemb,
http_response *response);
/**
- * @brief Initializes a CoolerControl session and authenticates with the daemon
- * using configuration.
- * @details Must be called before any other CoolerControl API function. Sets up
- * CURL session and performs authentication.
+ * @brief Initialise CURL session for the CoolerControl daemon (Bearer token auth).
*/
-int init_coolercontrol_session(const struct Config *config);
+int init_coolercontrol_session(void);
-/**
- * @brief Returns whether the session is initialized.
- * @details Checks if the session is ready for communication with the
- * CoolerControl daemon.
- */
+/** Returns 1 if the CoolerControl session is ready for use. */
int is_session_initialized(void);
-/**
- * @brief Cleans up and terminates the CoolerControl session.
- * @details Frees all resources and closes the session, including CURL cleanup
- * and cookie file removal.
- */
+/** Release all CURL resources. */
void cleanup_coolercontrol_session(void);
/**
- * @brief Sends an image directly to the LCD of the CoolerControl device.
- * @details Uploads an image to the LCD display using a multipart HTTP PUT
- * request with brightness and orientation settings.
+ * @brief Upload a PNG image to the device LCD via JSON body.
*/
int send_image_to_lcd(const struct Config *config, const char *image_path,
const char *device_uid);
/**
- * @brief Blocking variant of `send_image_to_lcd` with timeout and retries.
- * @details Used for shutdown path to ensure the image upload completes
- * synchronously. Sets temporary CURLOPT_TIMEOUT/CURLOPT_CONNECTTIMEOUT for
- * the duration of the operation and restores defaults afterwards.
+ * @brief Blocking variant of send_image_to_lcd with timeout and retry support.
+ * @details Sets CURLOPT_TIMEOUT/CURLOPT_CONNECTTIMEOUT for the duration of
+ * the upload, then restores defaults. Used on the shutdown path.
*/
int send_image_to_lcd_blocking(const struct Config *config,
const char *image_path,
@@ -111,4 +77,18 @@ int send_image_to_lcd_blocking(const struct Config *config,
int timeout_seconds,
int retries);
+/**
+ * @brief Configure SSL verification on a CURL handle.
+ * @details Disables peer/host check when tls_skip_verify is set;
+ * enables full verification for https:// addresses.
+ */
+void cc_apply_tls_to_curl(CURL *curl, const struct Config *config);
+
+/**
+ * @brief Append an Authorization: Bearer header to a curl_slist if a token is configured.
+ * @details Returns the (possibly extended) list; caller owns it.
+ */
+struct curl_slist *cc_apply_auth_to_curl(struct curl_slist *headers,
+ const struct Config *config);
+
#endif // CC_MAIN_H
diff --git a/src/srv/cc_sensor.c b/src/srv/cc_sensor.c
index e9f9603..558b93c 100644
--- a/src/srv/cc_sensor.c
+++ b/src/srv/cc_sensor.c
@@ -316,9 +316,8 @@ static void configure_status_request(CURL *curl, const char *url,
curl_easy_setopt(curl, CURLOPT_USERAGENT, "CoolerDash/1.0");
curl_easy_setopt(curl, CURLOPT_POST, 1L);
- // POST data for status request
- const char *post_data =
- "{\"all\":false,\"since\":\"1970-01-01T00:00:00.000Z\"}";
+ /* all=false: only current status, no historical data */
+ const char *post_data = "{\"all\":false}";
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
}
@@ -360,15 +359,12 @@ static int get_sensor_data_from_api(const Config *config,
configure_status_request(curl, url, &response);
- if (strncmp(config->daemon_address, "https://", 8) == 0)
- {
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
- }
+ cc_apply_tls_to_curl(curl, config);
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "accept: application/json");
headers = curl_slist_append(headers, "content-type: application/json");
+ headers = cc_apply_auth_to_curl(headers, config);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
int result = 0;