#!/usr/bin/env bash # # Tradfri command line client # # tradfri [] # # files (all relative to script location): # # tradfri.rc: gateway configuration # aliases.rc: device aliases # # refs: # https://github.com/glenndehaan/ikea-tradfri-coap-docs # https://openthread.io/reference/group/api-coap set -euo pipefail THISFILE=$(readlink -f "$0") BASEDIR=$(dirname "$THISFILE") ALIASESFILE="$BASEDIR/aliases.rc" CONFIGFILE="$BASEDIR/tradfri.rc" TF_GATEWAYIP="" TF_GATEWAYCODE="" TF_USERNAME="" TF_PRESHARED_KEY="" function writeconfig() { printf 'TF_GATEWAYIP=%s TF_GATEWAYCODE=%s TF_USERNAME=%s TF_PRESHARED_KEY=%s ' "$TF_GATEWAYIP" "$TF_GATEWAYCODE" "$TF_USERNAME" "$TF_PRESHARED_KEY" > "$CONFIGFILE" } [ ! -f "$CONFIGFILE" ] && ( writeconfig log_info "Update config in '$CONFIGFILE'" exit 255 ) # shellcheck disable=SC1090 source "$CONFIGFILE" [ "x$TF_GATEWAYIP" == "x" ] || [ "x$TF_GATEWAYCODE" == "x" ] && ( log_info "Update config in '$CONFIGFILE'" exit 255 ) TF_URL="coaps://$TF_GATEWAYIP:5684" # create username [ "x$TF_USERNAME" == "x" ] && ( TF_USERNAME=$(uuidgen | sed 's/.*-//') writeconfig ) [ -f "$ALIASESFILE" ] && source "$ALIASESFILE" # SUPPORT function tf_login() { # Login in and print reply on stdout coap-client -m post -u "Client_identity" -k "$TF_GATEWAYCODE" -e "{\"9090\":\"$TF_USERNAME\"}" "$TF_URL/15011/9063" exit # TODO: This doesn't work and still don't know why. # It should log in and save key in config file automatically... res=$(coap-client -m post -u "Client_identity" -k "$TF_GATEWAYCODE" -e "{\"9090\":\"$TF_USERNAME\"}" "$TF_URL/15011/9063") TF_PRESHARED_KEY=$(echo "$res" | jq -r '.["9091"]') if [ "x$TF_PRESHARED_KEY" == "x" ]; then log_err "Error loggin in." exit 254 fi log_info "Firmware %s\n" $(echo "$res" | jq -r '.["9029"]') writeconfig } function tf_keys() { sed 's|"3300"|Motion Sensor|' \ | sed 's|"3311"|Light Bulb|' \ | sed 's|"3312"|Plug|' \ | sed 's|"15015"|Blind|' \ | sed 's|"9001"|Name|' \ | sed 's|"9002"|Creation date|' \ | sed 's|"9003"|Instance ID|' \ | sed 's|"5712"|Transition Time|' \ | sed 's|"5850"|On/Off|' \ | sed 's|"5851"|Brightness|' \ | sed 's|"9018"|Accessory Link (Remote)|' \ | sed 's|"9039"|Scene ID|' \ | sed 's|"9058"|Scene Active State|' \ | sed 's|"9057"|Device Index ID|' \ | sed 's|"9068"|Is Scene Predefined|' \ | sed 's|"15013"|Light Settings|' \ | sed 's|"5706"|Color HEX String|' \ | sed 's|"5707"|Hue|' \ | sed 's|"5708"|Saturation|' \ | sed 's|"5709"|colorX|' \ | sed 's|"5710"|colorY|' \ | sed 's|"5711"|Color Temperature|' \ | sed 's|"5712"|Transition Time|' \ | sed 's|"5850"|On/Off|' \ | sed 's|"5851"|Brightness|' \ | sed 's|"5850"|On/Off|' \ | sed 's|"5851"|Brightness|' \ | sed 's|"5536"|Position|' } function tf_get() { raw=${1:-""} echo "$raw" if [ "$raw" == "-r" ]; then shift coap-client -m get -u "$TF_USERNAME" -k "$TF_PRESHARED_KEY" $@ else coap-client -m get -u "$TF_USERNAME" -k "$TF_PRESHARED_KEY" $@ | jq . fi } function tf_put() { coap-client -m put -u "$TF_USERNAME" -k "$TF_PRESHARED_KEY" "$@" } function get_alias_by_id() { # $1: device id # returns alias name(s) grep "$1" aliases.rc | sed "s/^\([^=]*\).*/\1/" } function parse_alias() { # $1: id or alias # returns id # script panic on invalid alias TF_DEVICEID="$1" if ! [[ $TF_DEVICEID =~ '^[0-9]+$' ]] ; then # this if is not execute because if alias is not set, the scripts will # panic (as per 'set' at start) if [[ ${!TF_DEVICEID} == "" ]]; then log_err "Light alias '%s' is not defined" "$TF_DEVICEID" exit 1 fi TF_DEVICEID=${!TF_DEVICEID} fi } # COMMANDS ################################################################################ ## info : Gateway details function info() { tf_get "$TF_URL/15011/15012" | tf_keys } ################################################################################ ## endpoints : debug function endpoints() { tf_get -r "$TF_URL/.well-known/core" } ################################################################################ ## devicelist : List devices function devicelist() { tf_get "$TF_URL/15001" } ################################################################################ ## deviceinfo : Device info function deviceinfo() { tf_get "$TF_URL/15001/$1" | tf_keys } ################################################################################ ## light : on/off light function light() { local TF_DEVICEID local STATUS TF_DEVICEID="$1" STATUS="$2" [ "$STATUS" == "on" ] && STATUS="254" [ "$STATUS" == "off" ] && STATUS="0" tf_put -e '{ "3311": [{ "5851": '$STATUS' }] }' "$TF_URL/15001/$TF_DEVICEID" } # RUNTIME ################################################################################ ## help : Print help function help() { local exename exename=$(basename "$THISFILE") printf "Usage:\n\n%s [options]\n\n" "$exename" printf "commands:\n" awk ' BEGIN { FS="\t" } /^###+$/{ print "" } match($0, /^## (.*)/) { gsub(/ : /, "\t", $0) } match($0, /^## (.*)/) { cmd=substr($1,4,RLENGTH) if (cmd ~ /^\s+$/) { printf " \t%s\n", $2; } else { printf " %s\n\t%s\n", cmd, $2; } } ' \ "$THISFILE" echo } function log_err() { fmt=$1; shift # shellcheck disable=SC2059 # the var IS the format printf "[E] $fmt\n" "$@" #>/dev/stderr } function log_info() { fmt=$1; shift # shellcheck disable=SC2059 # the var IS the format printf "[I] $fmt\n" "$@" } # Input is thecmd($1) function _is_command { grep "^## \w\w*" "$THISFILE" | sed 's|## \(\w*\).*|\1|' | grep "^$1$" > /dev/null } # MAIN # login [ "x$TF_PRESHARED_KEY" == "x" ] && ( tf_login ) cmd=${1:-help} [ $# -gt 0 ] && shift if _is_command "$cmd" then $cmd "$@" else help fi