You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
5.0 KiB
Bash

#!/usr/bin/env bash
# govee.sh - small CLI wrapper for Govee "control device" API
# Requirements: curl, jq, uuidgen (or openssl)
# Usage examples at bottom.
API_BASE="${GOVEE_API_BASE:-https://openapi.api.govee.com}"
CONTROL_ENDPOINT="${API_BASE}/router/api/v1/device/control"
#API_KEY="${GOVEE_API_KEY:-}"
API_KEY="933194fa-d341-4362-b371-de290cb99a58"
mySKU="H6110"
myID="20:11:A4:C1:38:9B:CB:54"
if [[ -z "$API_KEY" ]]; then
echo "ERROR: Set GOVEE_API_KEY environment variable (export GOVEE_API_KEY=xxxx)"
exit 2
fi
get_info() {
local entry="router/api/v1/user/devices"
json=$(curl -s -k ${API_BASE}/${entry} \
-H "Content-Type: application/json" \
-H "Govee-API-Key: ${API_KEY}")
sku=$(echo "$json" | jq -r ".data[].sku")
device=$(echo "$json" | jq -r ".data[].device")
}
# helpers
uuid() {
if command -v uuidgen >/dev/null 2>&1; then
uuidgen
else
# fallback
date +%s%N | sha1sum | cut -c1-32
fi
}
# convert hex/rrggbb or r,g,b to integer (0..16777215)
rgb_to_int() {
local in="$1"
if [[ "$in" =~ ^#?[0-9A-Fa-f]{6}$ ]]; then
# hex
in="${in#'#'}"
printf "%d\n" "$((0x$in))"
return
fi
# r,g,b
IFS=',' read -r r g b <<< "$in"
r=${r:-0}; g=${g:-0}; b=${b:-0}
# validate numeric
for val in "$r" "$g" "$b"; do
if ! [[ "$val" =~ ^[0-9]+$ ]] || (( val < 0 )) || (( val > 255 )); then
echo "ERR" # caller should handle
return 1
fi
done
echo $(( (r << 16) + (g << 8) + b ))
}
# build and send the control request
_govee_control() {
local sku="$1"; shift
local device="$1"; shift
local type="$1"; shift
local instance="$1"; shift
local value="$1"
local reqid
reqid="$(uuid)"
local body
body=$(jq -n \
--arg rid "$reqid" \
--arg sku "$sku" \
--arg device "$device" \
--arg type "$type" \
--arg instance "$instance" \
--argjson value "$value" \
'{requestId:$rid, payload: { sku:$sku, device:$device, capability: { type:$type, instance:$instance, value:$value } } }')
curl -sS -X POST "$CONTROL_ENDPOINT" \
-H "Content-Type: application/json" \
-H "Govee-API-Key: $API_KEY" \
-d "$body"
}
print_usage() {
cat <<EOF
Usage: govee.sh <command> [options]
Commands:
power <sku> <device_id> <on|off> Turn device on or off
toggle <sku> <device_id> <instance> <0|1>
brightness <sku> <device_id> <0..100> Set brightness (range depends on device)
color_rgb <sku> <device_id> <hex|r,g,b> Set RGB color (hex like ff8800 or "255,100,0")
temp_k <sku> <device_id> <kelvin> Set color temperature (e.g. 2700)
mode <sku> <device_id> <instance> <value> Set a mode or scene by numeric value
raw Accepts raw JSON payload from stdin and sends it
Examples:
./govee.sh power H605C "64:09:C5:32:37:36:2D:13" on
./govee.sh brightness H605C "64:09:C5:32:37:36:2D:13" 50
./govee.sh color_rgb H605C "64:09:C5:32:37:36:2D:13" ff0088
./govee.sh color_rgb H605C "64:09:C5:32:37:36:2D:13" 255,0,136
Note: You must know device SKU and device id (from /user/devices endpoint).
EOF
}
if (( $# == 0 )); then
print_usage
exit 1
fi
### cmd="$1"; shift
cmdline=""
while [ -n "$1" ]; do
case "$1" in
--sku) mySKU="$2"; shift 2;;
--dev|--id) myID="$2"; shift 2;;
-c|--cmd) cmd="$2"; shift 2;;
*) break;;
esac
done
case "$cmd" in
po*)
# args: sku device on|off
sku="$mySKU"; device="$myID"; state="$1"
if [[ -z "$sku" || -z "$device" || -z "$state" ]]; then print_usage; exit 1; fi
if [[ "$state" == "on" ]]; then val=1; else val=0; fi
_govee_control "$sku" "$device" "devices.capabilities.on_off" "powerSwitch" "$val" | jq .
;;
to*)
# sku device instance 0|1
sku="$mySKU"; device="$myID"; instance="$1"; val="$2"
_govee_control "$sku" "$device" "devices.capabilities.toggle" "$instance" "$val" | jq .
;;
br*)
sku="$mySKU"; device="$myID"; val="$1"
if [[ -z "$val" ]]; then print_usage; exit 1; fi
_govee_control "$sku" "$device" "devices.capabilities.range" "brightness" "$val" | jq .
;;
co*)
sku="$mySKU"; device="$myID"; color="$1"
if [[ -z "$color" ]]; then print_usage; exit 1; fi
rgbint=$(rgb_to_int "$color") || { echo "Bad color"; exit 1; }
_govee_control "$sku" "$device" "devices.capabilities.color_setting" "colorRgb" "$rgbint" | jq .
;;
te*)
sku="$mySKU"; device="$myID"; kelvin="$1"
if [[ -z "$kelvin" ]]; then print_usage; exit 1; fi
_govee_control "$sku" "$device" "devices.capabilities.color_setting" "colorTemperatureK" "$kelvin" | jq .
;;
mo*)
sku="$mySKU"; device="$myID"; instance="$1"; val="$2"
_govee_control "$sku" "$device" "devices.capabilities.mode" "$instance" "$val" | jq .
;;
raw)
# read raw payload JSON from stdin (should include payload object)
body=$(cat -)
if [[ -z "$body" ]]; then echo "Provide JSON on stdin"; exit 1; fi
curl -sS -X POST "$CONTROL_ENDPOINT" \
-H "Content-Type: application/json" \
-H "Govee-API-Key: $API_KEY" \
-d "$body" | jq .
;;
*)
print_usage
exit 1
;;
esac