-
-
Save zkarj735/6bfdb0a6311d17c3a8b86e9a31df2e5d to your computer and use it in GitHub Desktop.
Philips Hue light control from the command line
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# ARG_OPTIONAL_SINGLE([switch],[],[Switch 'on' or 'off']) | |
# ARG_OPTIONAL_SINGLE([rgb],[],[RGB triplet (0-255)]) | |
# ARG_OPTIONAL_SINGLE([temp],[],[Colour temperature (2000-6500)K]) | |
# ARG_OPTIONAL_SINGLE([dim],[],[Dimming level (1-100)]) | |
# ARG_POSITIONAL_INF([lights],[Lights to set],[1]) | |
# ARG_HELP([Allows control of Philips Hue lights via Hue Bridge]) | |
# ARGBASH_GO() | |
# needed because of Argbash --> m4_ignore([ | |
### START OF CODE GENERATED BY Argbash v2.9.0 one line above ### | |
# Argbash is a bash code generator used to get arguments parsing right. | |
# Argbash is FREE SOFTWARE, see https://argbash.io for more info | |
# Generated online by https://argbash.io/generate | |
die() | |
{ | |
local _ret="${2:-1}" | |
test "${_PRINT_HELP:-no}" = yes && print_help >&2 | |
echo "$1" >&2 | |
exit "${_ret}" | |
} | |
begins_with_short_option() | |
{ | |
local first_option all_short_options='h' | |
first_option="${1:0:1}" | |
test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0 | |
} | |
# THE DEFAULTS INITIALIZATION - POSITIONALS | |
_positionals=() | |
_arg_lights=('' ) | |
# THE DEFAULTS INITIALIZATION - OPTIONALS | |
_arg_switch= | |
_arg_rgb= | |
_arg_temp= | |
_arg_dim= | |
print_help() | |
{ | |
printf '%s\n' "Allows control of Philips Hue lights via Hue Bridge" | |
printf 'Usage: %s [--switch <arg>] [--rgb <arg>] [--temp <arg>] [--dim <arg>] [-h|--help] <lights-1> [<lights-2>] ... [<lights-n>] ...\n' "$0" | |
printf '\t%s\n' "<lights>: Lights to set" | |
printf '\t%s\n' "--switch: Switch 'on' or 'off' (no default)" | |
printf '\t%s\n' "--rgb: RGB triplet (0-255) (no default)" | |
printf '\t%s\n' "--temp: Colour temperature (2000-6500)K (no default)" | |
printf '\t%s\n' "--dim: Dimming level (1-100) (no default)" | |
printf '\t%s\n' "-h, --help: Prints help" | |
} | |
parse_commandline() | |
{ | |
_positionals_count=0 | |
while test $# -gt 0 | |
do | |
_key="$1" | |
case "$_key" in | |
--switch) | |
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 | |
_arg_switch="$2" | |
shift | |
;; | |
--switch=*) | |
_arg_switch="${_key##--switch=}" | |
;; | |
--rgb) | |
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 | |
_arg_rgb="$2" | |
shift | |
;; | |
--rgb=*) | |
_arg_rgb="${_key##--rgb=}" | |
;; | |
--temp) | |
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 | |
_arg_temp="$2" | |
shift | |
;; | |
--temp=*) | |
_arg_temp="${_key##--temp=}" | |
;; | |
--dim) | |
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 | |
_arg_dim="$2" | |
shift | |
;; | |
--dim=*) | |
_arg_dim="${_key##--dim=}" | |
;; | |
-h|--help) | |
print_help | |
exit 0 | |
;; | |
-h*) | |
print_help | |
exit 0 | |
;; | |
*) | |
_last_positional="$1" | |
_positionals+=("$_last_positional") | |
_positionals_count=$((_positionals_count + 1)) | |
;; | |
esac | |
shift | |
done | |
} | |
handle_passed_args_count() | |
{ | |
local _required_args_string="'lights'" | |
test "${_positionals_count}" -ge 1 || _PRINT_HELP=yes die "FATAL ERROR: Not enough positional arguments - we require at least 1 (namely: $_required_args_string), but got only ${_positionals_count}." 1 | |
} | |
assign_positional_args() | |
{ | |
local _positional_name _shift_for=$1 | |
_positional_names="_arg_lights " | |
_our_args=$((${#_positionals[@]} - 1)) | |
for ((ii = 0; ii < _our_args; ii++)) | |
do | |
_positional_names="$_positional_names _arg_lights[$((ii + 1))]" | |
done | |
shift "$_shift_for" | |
for _positional_name in ${_positional_names} | |
do | |
test $# -gt 0 || break | |
eval "$_positional_name=\${1}" || die "Error during argument parsing, possibly an Argbash bug." 1 | |
shift | |
done | |
} | |
parse_commandline "$@" | |
handle_passed_args_count | |
assign_positional_args 1 "${_positionals[@]}" | |
# OTHER STUFF GENERATED BY Argbash | |
### END OF CODE GENERATED BY Argbash (sortof) ### ]) | |
# [ <-- needed because of Argbash | |
# ----- EDIT THESE --------------------------- | |
hak="Qn74cB7YlKursSzMYyPL4pr5oLWxayBqhKyjFD10" | |
hba="192.168.1.15" | |
# -------------------------------------------- | |
burl="https://${hba}/clip/v2/resource/light" | |
function get_id() { | |
local filter='.data[] | select(.metadata.name == "'"$light"'") | .id' | |
local dev_id=$(curl --request GET -ks --header "hue-application-key: $hak" "${burl}" | jq -r "$filter") | |
echo "$dev_id" | |
} | |
function get_colour() { | |
r_srgb="$(echo "scale=4; ${rgb[0]} / 255" | bc)" | |
g_srgb="$(echo "scale=4; ${rgb[1]} / 255" | bc)" | |
b_srgb="$(echo "scale=4; ${rgb[2]} / 255" | bc)" | |
# Linearise RGB | |
if [ 1 -eq "$(echo "${r_srgb} < 0.04045" | bc)" ]; then | |
r_lin=$( echo "${r_srgb}" | awk '{print $1 / 12.92};') | |
else | |
r_lin=$( echo "${r_srgb}" | awk '{print (($1 + 0.055) / 1.055) ^ 2.4};' ) | |
fi | |
if [ 1 -eq "$(echo "${g_srgb} < 0.04045" | bc)" ]; then | |
g_lin=$( echo "${g_srgb}" | awk '{print $1 / 12.92};') | |
else | |
g_lin=$( echo "${g_srgb}" | awk '{print (($1 + 0.055) / 1.055) ^ 2.4};' ) | |
fi | |
if [ 1 -eq "$(echo "${b_srgb} < 0.04045" | bc)" ]; then | |
b_lin=$( echo "${b_srgb}" | awk '{print $1 / 12.92};') | |
else | |
b_lin=$( echo "${b_srgb}" | awk '{print (($1 + 0.055) / 1.055) ^ 2.4};' ) | |
fi | |
# Calculate XYZ | |
x_cie=$( echo "${r_lin} ${g_lin} ${b_lin}" | awk '{print $1 * 0.4124 + $2 * 0.3576 + $3 * 0.1805};') | |
y_cie=$( echo "${r_lin} ${g_lin} ${b_lin}" | awk '{print $1 * 0.2126 + $2 * 0.7152 + $3 * 0.0722};') | |
z_cie=$( echo "${r_lin} ${g_lin} ${b_lin}" | awk '{print $1 * 0.0193 + $2 * 0.1192 + $3 * 0.9505};') | |
json="\"color\":{\"xy\":{\"x\":$x_cie,\"y\":$y_cie}}" | |
echo $json | |
} | |
# Fetch valid light IDs | |
ids=() | |
for light in "${_arg_lights[@]}"; do | |
light_id=$(get_id) | |
if [ "$light_id" != "" ]; then | |
ids+=("$light_id") | |
fi | |
done | |
# Validate parameters given | |
# No valid lights | |
if [ "${#ids[@]}" = "0" ]; then | |
echo "No valid lights given." | |
exit 1 | |
fi | |
# Switch must be on or off | |
if [ "$_arg_switch" != "" ]; then | |
if [ "$_arg_switch" != "on" ] && [ "$_arg_switch" != "off" ]; then | |
echo "--switch must be 'on' or 'off'." | |
exit 1 | |
fi | |
fi | |
# Validate RGB triplet | |
if [ "$_arg_rgb" != "" ]; then | |
IFS=',' read -ra rgb <<< "$_arg_rgb" | |
if [ "${#rgb[@]}" != "3" ]; then | |
echo "--rgb must supply 3 comma-separated values" | |
exit 1 | |
fi | |
for c in "${rgb[@]}"; do | |
if ! [[ $c =~ ^[0-9]+$ ]]; then | |
echo "--rgb must supply 3 comma separated numbers, e.g. --rgb 100,255,0" | |
exit 1 | |
fi | |
if [[ $c -lt 0 || $c -gt 255 ]]; then | |
echo "--rgb must supply 3 comma separated values in the range 0-255" | |
exit 1 | |
fi | |
done | |
fi | |
# Temp must be in the range 2000-6500 | |
if [ "$_arg_temp" != "" ]; then | |
if ! [[ $_arg_temp =~ ^[0-9]+$ ]]; then | |
echo "--temp must be an integer in the range 2000-6500" | |
exit 1 | |
fi | |
if [[ $_arg_temp -lt 2000 ]] || [[ $_arg_temp -gt 6500 ]]; then | |
echo "--temp must be in the range 2000-6500" | |
exit 1 | |
fi | |
fi | |
# Dimming must be in the range 0-100 | |
if [ "$_arg_dim" != "" ]; then | |
if ! [[ $_arg_dim =~ ^[0-9]+$ ]]; then | |
echo "-- dim must be an interger in the range 0-100" | |
exit 1 | |
fi | |
if [[ $_arg_dim -lt 0 ]] || [[ $_arg_dim -gt 100 ]]; then | |
echo "--dim must be in the range 0-100" | |
exit 1 | |
fi | |
fi | |
# Build up JSON actions | |
# Switch on or off | |
if [ "$_arg_switch" != "" ]; then | |
json="${json}\"on\":{\"on\":" | |
if [ "$_arg_switch" = "on" ]; then | |
json="${json}true" | |
else | |
json="${json}false" | |
fi | |
json="${json}}" | |
fi | |
# RGB | |
if [ "$_arg_rgb" != "" ]; then | |
if [ "$json" != "" ]; then | |
json="${json}," | |
fi | |
json="${json}$(get_colour)" | |
fi | |
# Temperature | |
if [ "$_arg_temp" != "" ]; then | |
if [ "$json" != "" ]; then | |
json="${json}," | |
fi | |
mirek=$(echo "scale=0; 1000000 / ${_arg_temp}" | bc) | |
json="${json}\"color_temperature\":{\"mirek\":${mirek}}" | |
fi | |
# Dimming | |
if [ "$_arg_dim" != "" ]; then | |
if [ "$json" != "" ]; then | |
json="${json}," | |
fi | |
json="${json}\"dimming\":{\"brightness\":${_arg_dim}}" | |
fi | |
# Wrap the json in an object | |
json="{${json}}" | |
# Finally, iterate over the lights and action each | |
for id in "${ids[@]}"; do | |
url="${burl}/${id}" | |
curl --request PUT -ks --data "${json}" --header "hue-application-key: $hak" "${url}" > /dev/null | |
done | |
# ] <-- needed because of Argbash |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment