ca36b15af1
- Python CLI (click): discover, status, on/off/toggle, brightness, temperature, info - mDNS discovery via zeroconf for automatic light detection - Shared config at ~/.config/elgato-cli/config.json - KDE Plasma 6 plasmoid with system tray icon, power/brightness/temperature controls - Plasmoid uses XMLHttpRequest directly to light API (no CLI dependency) - Unit tests for API client with mocked HTTP responses
151 lines
4.8 KiB
QML
151 lines
4.8 KiB
QML
import QtQuick
|
|
import org.kde.plasma.plasmoid
|
|
import org.kde.plasma.core as PlasmaCore
|
|
|
|
PlasmoidItem {
|
|
id: root
|
|
|
|
// State
|
|
property bool lightOn: false
|
|
property int lightBrightness: 50
|
|
property int lightTemperature: 200 // mired
|
|
property bool lightReachable: false
|
|
property string lightHost: ""
|
|
property int lightPort: 9123
|
|
|
|
// Resolve host: widget config > shared CLI config
|
|
function resolveHost() {
|
|
var cfgHost = Plasmoid.configuration.lightHost || ""
|
|
var cfgPort = Plasmoid.configuration.lightPort || 9123
|
|
|
|
if (cfgHost !== "") {
|
|
root.lightHost = cfgHost
|
|
root.lightPort = cfgPort
|
|
return
|
|
}
|
|
|
|
// Try reading shared CLI config
|
|
var xhr = new XMLHttpRequest()
|
|
var configPath = StandardPaths.writableLocation(StandardPaths.GenericConfigLocation) + "/../elgato-cli/config.json"
|
|
// Use home dir approach
|
|
try {
|
|
xhr.open("GET", "file://" + StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.config/elgato-cli/config.json", false)
|
|
xhr.send()
|
|
if (xhr.status === 200 || xhr.readyState === XMLHttpRequest.DONE) {
|
|
var config = JSON.parse(xhr.responseText)
|
|
if (config.host) {
|
|
root.lightHost = config.host
|
|
root.lightPort = config.port || 9123
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.log("Elgato: Could not read shared config:", e)
|
|
}
|
|
}
|
|
|
|
function baseUrl() {
|
|
return "http://" + root.lightHost + ":" + root.lightPort + "/elgato"
|
|
}
|
|
|
|
function fetchState() {
|
|
if (root.lightHost === "") return
|
|
|
|
var xhr = new XMLHttpRequest()
|
|
xhr.open("GET", baseUrl() + "/lights")
|
|
xhr.timeout = 3000
|
|
xhr.onreadystatechange = function() {
|
|
if (xhr.readyState !== XMLHttpRequest.DONE) return
|
|
if (xhr.status === 200) {
|
|
var data = JSON.parse(xhr.responseText)
|
|
var light = data.lights[0]
|
|
root.lightOn = light.on === 1
|
|
root.lightBrightness = light.brightness
|
|
root.lightTemperature = light.temperature
|
|
root.lightReachable = true
|
|
} else {
|
|
root.lightReachable = false
|
|
}
|
|
}
|
|
xhr.onerror = function() { root.lightReachable = false }
|
|
xhr.send()
|
|
}
|
|
|
|
function setLightState(payload) {
|
|
if (root.lightHost === "") return
|
|
|
|
var xhr = new XMLHttpRequest()
|
|
xhr.open("PUT", baseUrl() + "/lights")
|
|
xhr.setRequestHeader("Content-Type", "application/json")
|
|
xhr.onreadystatechange = function() {
|
|
if (xhr.readyState !== XMLHttpRequest.DONE) return
|
|
if (xhr.status === 200) {
|
|
var data = JSON.parse(xhr.responseText)
|
|
var light = data.lights[0]
|
|
root.lightOn = light.on === 1
|
|
root.lightBrightness = light.brightness
|
|
root.lightTemperature = light.temperature
|
|
root.lightReachable = true
|
|
} else {
|
|
root.lightReachable = false
|
|
}
|
|
}
|
|
xhr.onerror = function() { root.lightReachable = false }
|
|
xhr.send(JSON.stringify({numberOfLights: 1, lights: [payload]}))
|
|
}
|
|
|
|
function toggleLight() {
|
|
setLightState({
|
|
on: root.lightOn ? 0 : 1,
|
|
brightness: root.lightBrightness,
|
|
temperature: root.lightTemperature
|
|
})
|
|
}
|
|
|
|
function setBrightness(val) {
|
|
setLightState({
|
|
on: root.lightOn ? 1 : 0,
|
|
brightness: val,
|
|
temperature: root.lightTemperature
|
|
})
|
|
}
|
|
|
|
function setTemperature(val) {
|
|
setLightState({
|
|
on: root.lightOn ? 1 : 0,
|
|
brightness: root.lightBrightness,
|
|
temperature: val
|
|
})
|
|
}
|
|
|
|
// Polling timer
|
|
Timer {
|
|
id: pollTimer
|
|
interval: Plasmoid.configuration.pollInterval || 3000
|
|
running: true
|
|
repeat: true
|
|
triggeredOnStart: true
|
|
onTriggered: root.fetchState()
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
resolveHost()
|
|
fetchState()
|
|
}
|
|
|
|
// Tray icon
|
|
compactRepresentation: CompactRepresentation {}
|
|
|
|
// Popup
|
|
fullRepresentation: FullRepresentation {}
|
|
|
|
// Prefer status area
|
|
Plasmoid.status: root.lightReachable ? PlasmaCore.Types.ActiveStatus : PlasmaCore.Types.PassiveStatus
|
|
preferredRepresentation: compactRepresentation
|
|
toolTipMainText: "Elgato Key Light"
|
|
toolTipSubText: {
|
|
if (root.lightHost === "") return "Not configured"
|
|
if (!root.lightReachable) return "Unreachable"
|
|
return (root.lightOn ? "On" : "Off") + " - " + root.lightBrightness + "% - " + Math.round(1000000 / root.lightTemperature) + "K"
|
|
}
|
|
}
|