#!/bin/bash # shellcheck disable=SC2059 declare message_geofence_enter message_geofence_exit message_device_online message_device_unknown message_device_offline message_event_other signal_sender_phone_number signal_recipients_array signal_api_endpoint_full_path allow_unique_device_ids_posix_ere device_name event_type battery_level message payload="${1}" function load_config() { local this_script_call_cmd this_script_resolved_abs_path conf_file_resolved_abs_path conf_file_resolved_file_name this_script_call_cmd="${BASH_SOURCE[0]}" this_script_resolved_abs_path="$(readlink -f "${this_script_call_cmd}")" conf_file_resolved_abs_path="${this_script_resolved_abs_path}"'.conf' conf_file_resolved_file_name="$(basename "${conf_file_resolved_abs_path}")" if [[ -r "${conf_file_resolved_abs_path}" ]]; then # shellcheck source="${conf_file_resolved_abs_path}" source "${conf_file_resolved_abs_path}" fi # Optional, will use default values if not given by user : "${allow_list_events:='^(deviceOnline|deviceUnknown|geofenceEnter|geofenceExit)$'}" : "${message_event_type_not_allowed:='Event "%s" not allowed. Nothing to do.\n'}" : "${message_geofence_enter:='%s entered geofence %s.'}" : "${message_geofence_exit:='%s left geofence %s.'}" : "${message_device_online:='On %s Traccar Client app is now active.'}" : "${message_device_unknown:='On %s Traccar Client app has not checked in for 10 minutes, the app is likely off now.'}" : "${message_device_unhandled:='For %s we do not want to send a message to Signal. Nothing to do.\n'}" : "${message_event_other:='%s triggered event "%s" in Traccar server.'}" : "${allow_unique_device_ids_posix_ere:=''}" # Mandatory, user must specify : "${signal_sender_phone_number:?'Please specify the signal-cli-rest-api phone number of your sender Signal account. Place a file named '"'${conf_file_resolved_file_name}'"' next to this script (same dir) and define a variable signal_sender_phone_number='"'"'value'"'"' in it.'}" : "${signal_recipients_array:?'Please specify recipients like so: ["group.ImxvbmdpdH=","recipient.21","+18005550111","i-am-a-uuid"]. Place a file named '"'${conf_file_resolved_file_name}'"' next to this script (same dir) and define a variable signal_recipients_array='"'"'value'"'"' in it.'}" : "${signal_api_endpoint_full_path:?'Please specify the signal-cli-rest-api full URL for sending a message like so: https://fully.qualified.domain.name/v2/send. Place a file named '"'${conf_file_resolved_file_name}'"' next to this script (same dir) and define a variable signal_api_endpoint_full_path='"'"'value'"'"' in it.'}" } function get_event_data() { local device_unique_id device_unique_id="$(<<<"${payload}" jq --raw-output '.device.uniqueId')" device_name="$(<<<"${payload}" jq --raw-output '.device.name')" event_type="$(<<<"${payload}" jq --raw-output '.event.type')" # Discard event and stop any further action unless event is allow-listed if ! [[ "${event_type}" =~ ${allow_list_events} ]]; then printf -- "${message_event_type_not_allowed}" "${device_name}" exit 0 fi if [[ "${event_type}" = 'geofenceEnter' || "${event_type}" = 'geofenceExit' ]]; then battery_level="$(<<<"${payload}" jq --raw-output '.position.attributes.batteryLevel')" battery_level="$(echo "${battery_level}"' / 1' | bc)" fi if ! [[ "${device_unique_id}" =~ ${allow_unique_device_ids_posix_ere} ]]; then printf -- "${message_device_unhandled}" "${device_name}" exit 0 fi } function craft_message() { local geofence_name case "${event_type}" in 'geofenceEnter') geofence_name="$(<<<"${payload}" jq --raw-output '.geofence.name')" message="${message_geofence_enter}" message="$(printf -- "${message}" "${device_name}" "${geofence_name}" "${battery_level}")" ;; 'geofenceExit') geofence_name="$(<<<"${payload}" jq --raw-output '.geofence.name')" message="${message_geofence_exit}" message="$(printf -- "${message}" "${device_name}" "${geofence_name}" "${battery_level}")" ;; 'deviceOnline') message="${message_device_online}" message="$(printf -- "${message}" "${device_name}")" ;; 'deviceUnknown') message="${message_device_unknown}" message="$(printf -- "${message}" "${device_name}")" ;; *) message="${message_event_other}" message="$(printf -- "${message}" "${device_name}" "${event_type}")" ;; esac } function send_to_signal() { local signal_message signal_message="${1}" curl \ --silent \ --request 'POST' \ --header 'Content-Type: application/json' \ --data '{"message":"'"${signal_message}"'","number":"'"${signal_sender_phone_number}"'","recipients":'"${signal_recipients_array}"'}' \ "${signal_api_endpoint_full_path}" } load_config get_event_data craft_message send_to_signal "${message}"