#! /bin/bash

# DESCRIPTION:
#   Handling Hikvision PTZ-cameras sequences.
#   Additionally:
#   - get ds18b20 sensor value over SSH,
#   - saving pictures to FTP.
#   This is only a local "proof of conept" for testing and debugging.
#
# DEPENDENCIES:
#   - curl
#   - sshpass
#
# PARAMETERS:
#   1: "qn" - execution without pauses
#   2: custom configuration file path
#
# FUNCTIONS:
#

#######################################
# Print message and add to log.
# Globals:
#   logs
# Arguments:
#   1: message to print and logging
#######################################
addtologs() {
  echo "$(date +'%Y.%m.%d-%H:%M:%S') $1" | tee -a "${logs}"
}

#######################################
# Waiting for press [ENTER].
# Globals:
#   None
# Arguments:
#   None
#######################################
execpause() {
  read -r -p "Press [ENTER] to continue... "
}

#######################################
# Exit procedure.
# Globals:
#   show
# Arguments:
#   None
#######################################
execquite() {
  addtologs "execution time is $(($(date +%s)-time)) seconds, exit"
  if [ "${show}" != "qn" ]; then
    execpause
  fi
  exit
}

#######################################
# Error exit procedure with Telegram notification.
# Globals:
#   telegramapiurl
#   telegramchatid
# Arguments:
#   1: message to print and logging
#######################################
execerror() {
  addtologs "error: $1"
  curl -s -X POST "${telegramapiurl}/sendMessage" \
    -d "chat_id=${telegramchatid}" \
    -d "text=$(basename -s .sh "$0") error: $1" \
    >> /dev/null 2>&1
  execquite
}

#######################################
# Parsing config file and creating global vars.
# Globals:
#   None
# Arguments:
#   None
#######################################
getconfig() {
  logs=$(grep "logs=" "${conf}" | cut -d= -f2)
  camuser=$(grep "camuser=" "${conf}" | cut -d= -f2)
  campass=$(grep "campass=" "${conf}" | cut -d= -f2)
  camaddr=$(grep "camaddr=" "${conf}" | cut -d= -f2)
  camport=$(grep "camport=" "${conf}" | cut -d= -f2)
  ftpuser=$(grep "ftpuser=" "${conf}" | cut -d= -f2)
  ftppass=$(grep "ftppass=" "${conf}" | cut -d= -f2)
  ftpaddr=$(grep "ftpaddr=" "${conf}" | cut -d= -f2)
  ftpport=$(grep "ftpport=" "${conf}" | cut -d= -f2)
  ftppath=$(grep "ftppath=" "${conf}" | cut -d= -f2)
  tmpuser=$(grep "tmpuser=" "${conf}" | cut -d= -f2)
  tmppass=$(grep "tmppass=" "${conf}" | cut -d= -f2)
  tmpaddr=$(grep "tmpaddr=" "${conf}" | cut -d= -f2)
  tmpport=$(grep "tmpport=" "${conf}" | cut -d= -f2)
  tmpnode=$(grep "tmpnode=" "${conf}" | cut -d= -f2)
  telegramapiurl=$(grep "telegramapiurl=" "${conf}" | cut -d= -f2)
  telegramchatid=$(grep "telegramchatid=" "${conf}" | cut -d= -f2)
}

#######################################
# Get ds18b20 sensor value over SSH.
# Globals:
#   tmpaddr
#   tmpport
#   tmpuser
#   tmppass
#   tmpnode
# Arguments:
#   None
# return:
#   temperature in Celsius
#######################################
getairtmp() {
  temp=$(sshpass -p "${tmppass}" \
    ssh "${tmpuser}@${tmpaddr}" -p "${tmpport}" \
    -o StrictHostKeyChecking=no -o ConnectTimeout=10 \
    "cat /sys/bus/w1/devices/${tmpnode}/temperature" \
  ) && temp=$((temp / 1000))
  if [ -n "${temp}" ]; then
    addtologs "getairtmp: air temperature now is ${temp}'C" > /dev/null
    echo "${temp}"
  else
    execerror "getairtmp: air temperature now is ${temp}'C"
  fi
}

#######################################
# Get static picture from camera and upload to FTP.
# Globals:
#   camaddr
#   camport
#   camuser
#   campass
#   ftpaddr
#   ftpport
#   ftppath
#   ftpuser
#   ftppass
# Arguments:
#   1: filename prefix
#######################################
getcamimg() {
  local name
  name=$1
  path="${ftppath}/$(date +"%Y")/$(date +"%m")/$(date +"%V")/$(date +"%d")"
  file="${ftpaddr}:${ftpport}/${path}/${name}_$(date +"%Y.%m.%d_%H-%M-%S").jpeg"
  url='Streaming/channels/101/picture?snapShotImageType=JPEG&videoResolutionWidth=1920&videoResolutionHeight=1080'
  if curl -vs "http://$camuser:$campass@$camaddr:$camport/$url" -o tmp \
    && curl -T tmp "ftp://$ftpuser:$ftppass@$file" --ftp-create-dirs; then
    addtologs "getcamimg: save photo to ftp://${file}"
    rm tmp
  else
    execerror "getcamimg: save photo to ftp://${file}"
  fi
}

#######################################
# Set message as video overlay text.
# Globals:
#   camaddr
#   camport
#   camuser
#   campass
# Arguments:
#   1: overlay text content
#######################################
setcamtxt() {
  local message=$1
  url='ISAPI/System/Video/inputs/channels/101/overlays/text'
  xml='<TextOverlayList>
       <TextOverlay>
       <id>1</id>
       <enabled>true</enabled>
       <posX>0</posX><posY>0</posY>
       <displayText>'"${message}"'</displayText>
       </TextOverlay>
     </TextOverlayList>'
  if curl -d "${xml}" -X PUT "http://$camuser:$campass@$camaddr:$camport/$url" \
    | grep -q '<statusString>OK</statusString>'; then
    addtologs "setcamtxt: ${message}"
    sleep 5
  else
    execerror "setcamtxt: ${message}"
  fi
}

#######################################
# Set camera moving to absolute position.
# Globals:
#   camaddr
#   camport
#   camuser
#   campass
# Arguments:
#   1: horisontal camera position from 0 to 3600
#   2: vertical camera position from -900 to 2700
#   3: zoom camera position from 0 to 1000
#   4: time to wait
#   5: message to print and logging
#######################################
setcampos() {
  local x=$1
  local y=$2
  local z=$3
  local t=$4
  local message=$5
  url='ISAPI/PTZCtrl/channels/101/absolute'
  xml='<PTZData>
       <AbsoluteHigh>
       <elevation>'"${y}"'</elevation>
       <azimuth>'"${x}"'</azimuth>
       <absoluteZoom>'"${z}"'</absoluteZoom>
       </AbsoluteHigh>
     </PTZData>'
  if curl -d "${xml}" -X PUT "http://$camuser:$campass@$camaddr:$camport/$url" \
    | grep -q '<statusString>OK</statusString>'; then
    addtologs "setcampos: ${message}"
    sleep "${t}"
  else
    execerror "setcampos: ${message}"
  fi
}

#######################################
# Set camera moving to direction.
# Globals:
#   camaddr
#   camport
#   camuser
#   campass
# Arguments:
#   1: acceleration of horizontal camera movement from -100 to 100
#   2: acceleration of vertical camera movement from -100 to 100
#   3: acceleration of zoom camera movement from -100 to 100
#   4: time to wait
#   5: message to print and logging
#######################################
setcammov() {
  local x=$1
  local y=$2
  local z=$3
  local t=$4
  local message=$5
  url='ISAPI/PTZCtrl/channels/101/continuous'
  xml='<PTZData>
       <pan>'"${x}"'</pan>
       <tilt>'"${y}"'</tilt>
       <zoom>'"${z}"'</zoom>
     </PTZData>'
  if curl -d "${xml}" -X PUT "http://$camuser:$campass@$camaddr:$camport/$url" \
    | grep -q '<statusString>OK</statusString>'; then
    addtologs "setcammov: ${message}"
    sleep "${t}"
  else
    execerror "setcammov: ${message}"
  fi
}

#
# VARIABLES:
#

show=$1
conf=$2
if [ -z "${conf}" ] || [ "${conf}" == "-" ]; then
  conf="$(dirname "$(realpath "$0")")/$(basename -s .sh "$0").conf"
fi

time=$(date +%s)
cd "$(dirname "$(realpath "$0")")" || execerror
if [ ! -e "${conf}" ]; then
  execerror "Not found config file: ${conf}"
else
  getconfig
fi
if [ -z "${logs}" ];then
  logs=/dev/null
elif [ ! -e "${logs}" ];then
  touch "${logs}"
fi
if ! command -v curl &> /dev/null || ! command -v sshpass &> /dev/null; then
  execerror "Not found dependencies"
fi

#
# MAIN:
#

setcamtxt "$(getairtmp)'C"
setcampos       0       0       10      5.00s     'xx >| 01 Точка - Панорама центр 1x'
sleep                                   1m
setcamtxt '' && getcamimg 'point-01' && setcamtxt "$(getairtmp)'C"
sleep                                   4m
setcampos       395     0       10      5.00s     '01 >| 02 Точка - Панорама право 1x'
setcampos       2915    0       10      5.00s     '02 >| 03 Точка - Панорама лево 1x'
sleep                                   1m
setcamtxt '' && getcamimg 'point-02' && setcamtxt "$(getairtmp)'C"
sleep                                   4m
setcammov       25      25      33      6.00s     '03 >> 04 Точка - Дорожный переход 8x'
setcampos       3060    -85     80      5.00s     '03 >| 04 Точка - Дорожный переход 8x'
sleep                                   5m
setcammov       99      99      0       2.25s     '04 >> 05 Точка - Поля 8x'
setcampos       3208    -200    80      5.00s     '04 >| 05 Точка - Поля 8x'
setcampos       3208    -200    160     5.00s     '05 >| 06 Точка - Поля 16x'
setcammov       -70     0       -33     3.00s     '06 >> 07 Точка - Поля 4x'
setcampos       3175    -200    40      5.00s     '06 >| 07 Точка - Поля 4x'
sleep                                   1m
setcamtxt '' && getcamimg 'point-04' && setcamtxt "$(getairtmp)'C"
sleep                                   4m
setcampos       2860    -200    40      5.00s     '07 >| 08 Точка - Стадион 4x'
sleep                                   1m
setcamtxt '' && getcamimg 'point-05' && setcamtxt "$(getairtmp)'C"
sleep                                   4m
setcammov       0       -44     33      1.50s     '08 >> 09 Точка - Стадион 8x'
setcampos       2860    -170    80      5.00s     '08 >| 09 Точка - Стадион 8x'
sleep                                   1m
setcammov       0       -99     0       11.5s     '09 >> 10 Точка - Въезд во двор 8x'
setcampos       2805    200     80      5.00s     '09 >| 10 Точка - Въезд во двор 8x'
sleep                                   5m
setcammov       -88     99      0       5.00s     '10 >> 11 Точка - Бассейн 8x'
setcammov       -99     88      0       2.00s     '10 >> 11 Точка - Бассейн 8x'
setcammov       -44     99      0       4.75s     '10 >> 11 Точка - Бассейн 8x'
setcampos       2510    -100    80      5.00s     '10 >| 11 Точка - Бассейн 8x'
sleep                                   1m
setcammov       -88     99      33      2.85s     '11 >> 12 Точка - Общежитие дальнее 16x'
setcampos       2415    -200    160     5.00s     '11 >| 12 Точка - Общежитие дальнее 16x'
sleep                                   1m
setcammov       66      0       0       22.5s     '12 >> 13 Точка - Общежите ближнее 16x'
setcampos       2640    -200    160     5.00s     '12 >| 13 Точка - Общежите ближнее 16x'
sleep                                   1m
setcammov       66      0       0       90.5s     '13 >> 14 Точка - Крыша магазина 4x'
setcammov       99      0       -44     3.35s     '13 >> 14 Точка - Крыша магазина 4x'
setcampos       335     -200    40      5.00s     '13 >| 14 Точка - Крыша магазина 4x'
sleep                                   1m
setcamtxt '' && getcamimg 'point-11' && setcamtxt "$(getairtmp)'C"
sleep                                   4m
setcammov       -99     0       -33     2.75s     '14 >> 15 Точка - Панорама верх 1x'
setcampos       0       -200    10      5.00s     '14 >| 15 Точка - Панорама верх 1x'
sleep                                   1m
setcamtxt '' && getcamimg 'point-12' && setcamtxt "$(getairtmp)'C"
sleep                                   4m
setcammov       0       -33     0       10.0s     '15 >> 01 Точка - Панорама центр 1x'
setcampos       0       0       10      5.00s     '15 >| 01 Точка - Панорама центр 1x'
execquite
