]> git.vanrenterghem.biz Git - elgato-keylight-script.git/blob - keylights.sh
Remove error logging function in favour of die
[elgato-keylight-script.git] / keylights.sh
1 #!/bin/bash
2 #set -x
3 set -o nounset
4 set -Eeuo pipefail
6 trap destroy SIGINT SIGTERM ERR EXIT
8 # Settings
9 temp_file="/tmp/elgatokeylights"
10 script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P)
11 icon="${script_dir}/assets/elgato.png"
13 # Declarations
14 declare -i silent=0
15 declare -i pretty=0
16 declare action="usage"
17 declare target=""
18 declare -A lights
19 declare lights_json
20 declare call="curl --silent --show-error --location --header 'Accept: application/json' --request"
21 declare devices="/elgato/lights"
22 declare accessory_info="/elgato/accessory-info"
23 declare settings="/elgato/lights/settings"
25 if [ ! -r "${icon}" ]; then icon=sunny; fi
27 notify() {
28     if [ $silent -eq 0 ]; then
29         notify-send -i "$icon" "Key Light Controller" "$1"
30     fi
31 }
33 die() {
34     echo >&2 -e "${1-}"
35     exit "${2-1}"
36 }
38 destroy() {
39     code=$?
40     rm "$temp_file" 2>/dev/null
42     exit ${code}
43 }
45 usage() {
46     cat <<EOF
47 Usage: $(basename "${BASH_SOURCE[0]}") [-h] [-l] [-p] [-s] [-v] <action>
49 Elgato Lights controller. Works for Key Light and Key Light Air.
51 Available actions:
52     list        List available lights
53     status      Get state of lights
54     on          Turn all lights on
55     off         Turn all lights off
56     temperature  Set temperature level (260-470)
57     brightness  Set brightness level (0-100)
58     increase    Increases brightness by 10
59     decrease    Decreases brightness by 10
61 Available options:
63 -h, --help      Print this help and exit
64 -p, --pretty    Pretty print console output
65 -v, --verbose   Print script debug info
66 -f, --flag      Some flag description
67 -s, --silent    Supress notifications
68 EOF
69     exit
70 }
72 parse_params() {
73     # default values of variables set from params
75     while :; do
76         case "${1-}" in
77         -h | --help) usage ;;
78         -p | --pretty) pretty=1;;
79         -v | --verbose) set -x ;;
80         -s | --silent) silent=1 ;;
81         -t | --target) target=1 
82             target="${2-""}"
83             shift
84             ;;
85         -?*) die "Unknown option: $1" ;;
86         *) break ;;
87         esac
88         shift
89     done
91     args=("$@")
93     # check required params and arguments
94     declare -A actions=([help]=1 [list]=1)
95     [[ ${#args[@]} -ne 1 ]] && die "Incorrect action count, 1 allowed"
97     [[ ($silent -eq 1) && ($pretty -eq 1) ]] && die "Cannot use silent and pretty options simultaneously"
98     
99     [[ -n "${actions[${args[0]}]}" ]] && action="${args[0]}"
100     
101     return 0
104 dependencies() {
105     for var in "$@"; do
106         if ! command -v $var &>/dev/null; then
107             die "Dependency $var was not found, please install and try again"
108         fi
109     done
113 produce_json() {
114     declare json
115     for l in "${!lights[@]}"; do
116         json+="${lights[$l]},"
117     done
119     lights_json="[${json%,}]"
122 print_json() {
123     if [[ $pretty -eq 1 ]]; then
124         echo "$1"|jq '.' 
125     else
126         echo "$1"|jq -c -M '.'
127     fi
128     
129     exit 0
132 print_status() {
133     die "To be implemented"
136 set_state() {
137     new_state=$1
138     die "To be implemented"
142 find_lights() {
143     # Scan the network for Elgato devices
144     avahi-browse -d local _elg._tcp --resolve -t | grep -v "^\+" >"$temp_file"
146     # Declaration for json type forcing
147     declare device="N/A"
148     declare hostname="N/A"
149     declare manufacturer="N/A"
150     declare ip="N/A"
151     declare -i port=0
152     declare mac="N/A"
153     declare sku="N/A"
155     while read -r line; do
157         # Gather information about the light
158         if [[ ($line == =*) && ($line =~ IPv4[[:space:]](.+)[[:space:]]_elg) ]]; then
159             device=$(eval echo "${BASH_REMATCH[1]}") # eval to strip whitespace
160         elif [[ $line =~ hostname.+\[(.+)\] ]]; then hostname=${BASH_REMATCH[1]};
161         elif [[ $line =~ address.+\[(.+)\] ]]; then ip=${BASH_REMATCH[1]};
162         elif [[ $line =~ port.+\[(.+)\] ]]; then port=${BASH_REMATCH[1]};
163         elif [[ $line =~ txt.+\[(.+)\] ]]; then
164             txt=$(eval echo "${BASH_REMATCH[1]}") # eval to strip single and double quotes
166             if [[ $txt =~ mf=([^[[:space:]]*]*) ]]; then manufacturer=${BASH_REMATCH[1]}; fi
167             if [[ $txt =~ id=([^[[:space:]]*]*) ]]; then mac=${BASH_REMATCH[1]}; fi
168             if [[ $txt =~ md=.+[[:space:]]([^[[:space:]]*]*)[[:space:]]id= ]]; then sku=${BASH_REMATCH[1]}; fi
170             
171             # Get information from the light
172             declare cfg="{}"
173             declare url="{}"
174             declare info="{}"
175             declare light="{}"
176             if [[ ! (-z $ip) && ! (-z $port) ]]; then
177                 url="http://$ip:$port"
178                 cfg=$(eval "${call} GET ${url}${settings}") > /dev/null
179                 info=$(eval "${call} GET ${url}${accessory_info}") > /dev/null
180                 light=$(eval "${call} GET ${url}${devices}") > /dev/null
181             fi
182             # Store the light as json
183             lights["$ip"]=$( jq -n \
184                     --arg dev "$device" \
185                     --arg hn "$hostname" \
186                     --arg ip "$ip" \
187                     --arg port "$port" \
188                     --arg mf "$manufacturer" \
189                     --arg mac "$mac" \
190                     --arg sku "$sku" \
191                     --arg url "$url" \
192                     --argjson light "$light" \
193                     --argjson cfg "$cfg" \
194                     --argjson info "$info" \
195                     '{device: $dev, manufacturer: $mf, hostname: $hn, url: $url, ip: $ip, 
196                     port: $port, mac: $mac, sku: $sku, light: $light, settings: $cfg, info: $info}' )
197             
198             # Reset for next light
199             declare {device,hostname,manufacturer,url,ip,mac,protocol,sku,cfg}="N/A"
200             declare port=0
201         fi
202     done <"$temp_file"
205 # Manage user parameters
206 parse_params "$@"
208 # Make sure dependencies are installed
209 dependencies avahi-browse curl notify-send jq
211 find_lights
213 # Fail if we cannot find lights
214 [[ ${#lights[@]} -eq 0 ]] && die "No lights found" 2
216 produce_json
218 # Dispatch actions
219 [[ $action == "usage" ]] && usage
220 [[ $action == "list" ]] && print_json "${lights_json}"
221 [[ $action == "status" ]] && status
222 [[ $action == "on" ]] && set_state 1
223 [[ $action == "off" ]] && set_state 0