]> git.vanrenterghem.biz Git - elgato-keylight-script.git/blobdiff - keylights.sh
Update documentation structure
[elgato-keylight-script.git] / keylights.sh
index f98675469fd387b73bcdc0f2e416241c6732fc34..cfd20b6a8c541b40a795becae5ad9fc4687bab44 100755 (executable)
@@ -12,9 +12,12 @@ declare -i silent=0
 declare -i pretty=0
 declare action="usage"
 declare target='.'
+declare limit=""
 declare format="json"
 declare -A lights
 declare lights_json
+declare full_json
+declare simple_json
 declare flat_json
 declare call='curl --silent --show-error --location --header "Accept: application/json" --request'
 declare devices="/elgato/lights"
@@ -42,7 +45,7 @@ destroy() {
 
 usage() {
     cat <<EOF
-Usage: $(basename "${BASH_SOURCE[0]}") [-h] [-f <value>] [-l] [-p] [-s] [-t <value>][-v] [--<option>] [--<option> <value>] <action>
+Usage: $(basename "${BASH_SOURCE[0]}") [-h] [-f <value>] [-l <value>] [-p] [-s] [-t <value>][-v] [--<option>] [--<option> <value>] <action>
 
 Elgato Lights controller. Works for Key Light and Key Light Air.
 
@@ -51,14 +54,15 @@ Available actions:
     status      Get state of lights
     on          Turn all lights on
     off         Turn all lights off
-    temperature  Set temperature level (260-470)
+    temperature Set temperature level (260-470)
     brightness  Set brightness level (0-100)
     increase    Increases brightness by 10
     decrease    Decreases brightness by 10
 
 Available formats:
     json        Renders output as JSON (default)
-    flat        Renders output as flattened JSON with .(dot) notation JSON (default)
+    simple      Renders output as JSON array of single level objects with subarrays as .(dot) notation JSON
+    flat        Renders output as fully flattened single level JSON with .(dot) notation JSON
     html        Renders output as basic html table
     csv         Renders output as csv
     table       Renders output as a printed table
@@ -67,12 +71,13 @@ Available formats:
 
 Available options:
 
--h, --help      Print this help and exit
--f  --format    Set output format
--p, --pretty    Pretty print console output
--s, --silent    Supress notifications
--t, --target    Only perform action on devices where value matches filter
--v, --verbose   Print script debug info
+-h, --help               Print this help and exit
+-f, --format             Set output format
+-l, --limit <list>       Limit top level output fields to the specified comma separated list
+-p, --pretty             Pretty print console output
+-s, --silent             Supress notifications
+-t, --target <filter>    Only perform action on devices where value matches filter
+-v, --verbose            Print script debug info
 EOF
     exit
 }
@@ -87,6 +92,10 @@ parse_params() {
             format="${2-}"
             shift
             ;;
+        -l | --limit)
+            limit=$(eval echo "\| {${2-}} ")
+            shift
+            ;;
         -p | --pretty) pretty=1 ;;
         -v | --verbose) set -x ;;
         -s | --silent) silent=1 ;;
@@ -139,59 +148,123 @@ default_light_properties() {
 }
 
 produce_json() {
-    t=$(eval echo "'[.[] | select($target)]'")
+    t=$(eval echo "'[.[] $limit| select($target)]'")
+    f=$(eval echo "'[.[] | select($target)]'")
 
     lights_json=$(echo "${lights[@]}" | jq -c -s "$t")
+    full_json=$(echo "${lights[@]}" | jq -c -s "$f")
+    simple_json=$(echo "${lights_json}" | jq -c '.[] | reduce ( tostream | select(length==2) | .[0] |= [join(".")] ) as [$p,$v] ({}; setpath($p; $v)) ')
+    simple_json=$(echo "${simple_json}" | jq -c -s '.') # slurp it to make it an array
+    flat_json=$(echo "${lights_json}" | jq -c -s '.[] | reduce ( tostream | select(length==2) | .[0] |= [join(".")] ) as [$p,$v] ({}; setpath($p; $v)) ')
+
 }
 
 output() {
-    data=${1-}
-    type=${2-"$format"}
 
     # Mange user requested output format
     case $format in
-    json | flat) print_json "$data" ;;
-    table) print_json "$data" ;;
-    csv) print_csv "$data" ;;
-    pair) print_pair "$data" ;;
-    html) print_html "$data" ;;
-    -?*) die "Unknown output format (-f/--format): $type" ;;
+    json) print_json "$lights_json" ;;
+    simple) print_json "$simple_json" ;;
+    flat) print_json "$flat_json" ;;
+    table) print_structured '@tsv' ;;
+    csv) print_structured '@csv' ;;
+    pair) print_structured 'pairs' ;;
+    html) print_html ;;
+    -?*) die "Unknown output format (-f/--format): $format" ;;
     esac
 }
 
 print_json() {
-    # TODO: Evaluate adding jq filtering as filter argument
-    query=""
-
-    # Deconstruct json and assemble in flattened with .(dot) notation
-    if [[ $format == "flat" ]]; then
-        query='reduce ( tostream | select(length==2) | .[0] |= [join(".")] ) as [$p,$v] ({}; setpath($p; $v))'
-    else
-        query='.'
-    fi
 
     # Manage pretty printing
     if [[ $pretty -eq 1 ]]; then
-        echo "${1-}" | jq "$query"
+        echo "${1-}" | jq '.'
     else
-        echo "${1-}" | jq -c -M "$query"
+        echo "${1-}" | jq -c -M '.'
     fi
 
     exit 0
 }
 
-print_table() {
-    bold=$(tput bold)
-    normal=$(tput sgr0)
-    message='
-    
-'
-    die "To be implemented"
+print_structured() {
+    pp=${2-$pretty}
+
+    # Handle csv and table printing
+    query="(.[0] | keys_unsorted | map(ascii_upcase)), (.[] | [.[]])|${1-@csv}"
+
+    # Handle printing as key value pairs
+    if [[ ${1} == 'pairs' ]]; then
+        query='.[] | "--------------",(to_entries[] | [.key, "=", .value] | @tsv)'
+    fi
+
+    # Manage pretty printing
+    if [[ $pp -eq 1 ]]; then
+        echo "${simple_json}" | jq --raw-output "$query" | column -t -s$'\t' | sed -e 's/"//g'
+    else
+        if [[ ${1} == 'pairs' ]]; then
+            echo "${simple_json}" | jq -r "$query" | sed -e 's/\t//g'
+        else
+            echo "${simple_json}" | jq -r "$query"
+        fi
+    fi
+}
+
+print_html() {
+    data=$(print_structured '@csv' 1)
+
+    html="
+    <table>
+    $(
+        print_header=true
+        while read d; do
+            if $print_header; then
+                echo "<tr><th>${d//,/<\/th><th>}</th></tr>"
+                print_header=false
+                continue
+            fi
+            echo "<tr><td>${d//,/</td><td>}</td></tr>"
+        done <<<"${data}"
+    )
+    </table>"
+    echo "$html"
 }
 
 set_state() {
-    new_state=$1
-    die "To be implemented"
+    declare -a data
+    readarray -t data < <(echo "${full_json}" | jq -c '.[] | {displayName, url, numberOfLights, lights}')
+    declare -a updated
+
+    x=$(echo "${1}" | tr 01 10) # "flip the bit"
+
+    for d in "${data[@]}"; do
+        query_old="[.lights[] | select(.on==${x})] | length"
+        count_found=$(echo "${d}" | jq "$query_old")
+
+        # Don't send to lights already in wanted state
+        if [[ $count_found -eq 0 ]]; then continue; fi
+
+        # Extract relevant data and create new json object
+        url=$(echo "${d}" | jq '.url')
+        dn=$(echo "${d}" | jq -r '.displayName')
+        l=$(echo "${d}" | jq -c 'del(.url, .displayName)' | jq ". | .lights[].on = ${1}")
+
+        # Send command
+        if eval "${call} PUT -d '${l}' ${url}${devices}" >/dev/null; then updated+=("$dn"); fi
+    done
+
+    # Text representation of new state
+    state="ON"
+    [[ $1 -eq 0 ]] && state="OFF"
+
+    # Send notification
+    if [[ ${#updated[*]} -gt 0 ]]; then
+        n="Turned $state ${#updated[@]} lights:\n\n"
+        for i in "${updated[@]}"; do
+            n+=$(echo "$i\n")
+        done
+        notify "$n"
+
+    fi
 }
 
 find_lights() {
@@ -258,7 +331,7 @@ find_lights() {
             '{device: $dev, manufacturer: $mf, hostname: $hn, url: $url, ipv4: $ipv4, ipv6: $ipv6, 
                 port: $port, mac: $mac, sku: $sku, settings: $cfg}')
 
-        # Store the light as json
+        # Store the light as json and merge info + light into base object
         lights["$device"]=$(echo "$info $light $json" | jq -s '. | add')
 
         # Reset for next light as we are processing the last avahi line
@@ -267,6 +340,9 @@ find_lights() {
     done
 }
 
+# Quit if script is run by root
+[[ "$EUID" -eq 0 ]] && die "Not allowed to run as root"
+
 # Manage user parameters
 parse_params "$@"
 
@@ -276,14 +352,14 @@ dependencies avahi-browse curl notify-send jq
 find_lights
 
 # Fail if we cannot find lights
-[[ ${#lights[@]} -eq 0 ]] && die "No lights found" 2
+[[ ${#lights[@]} -eq 0 ]] && die "No lights found"
 
 produce_json
 
 # Dispatch actions
 case $action in
 usage) usage ;;
-list) output "${lights_json}" ;;
+list) output ;;
 status) status ;;
 on) set_state 1 ;;
 off) set_state 0 ;;