SIM Failover Script for Data Throttling

Design

This creates a rudimentary, but stable, data plan throttle that will force a failover to SIM2 if it detects SIM1 has gone over its monthly data usage limit.  This is achieved by leveraging the data usage API available on aView.  The main benefit is the API tracks data usage across reboots, so we can accurately measure the data usage over time.

This feature is implemented using two custom scripts.  See example setup below.  Note that the user must specify their API token in the data_throttle custom script.  They can also adjust the data limit (default is 100MB) and the rollover day for the data plan (default is the first day of the month).

If the data plan limit is reached for the month, this script will force a failover to SIM2 by default.  Similarly, when the device is within/under its data plan limit for the month, this script will failback to SIM1.

Config Setup

Create a new custom script under System -> Scheduled tasks -> custom scripts, and enter in the following.  The top three lines should be adjusted to put in the users API token from aView, the desired data plan limit in bytes, and the rollover day of the month (2-digits).

Keep in mind that each user in aView only gets 100 API requests every 15 minutes, so don't adjust this interval down so low to the point that the user runs out of API queries (e.g. running this script on 100 devices every 5 minutes equals 300 requests per 15-min, which is more than the API limit).

usage_limit='100000000'   # 100MB
rollover_day='01'  # pick day of month 01-31 to choose when data plan resets
api_token='xxxxxxxxxx'
SIM_to_monitor='1'
mac=$(runt get system.mac)
intf=$(runt dump network.modem | grep intf | tail -n 1 | cut -f2 -d'=') # 18.1 or older firmware
[ -n "$intf" ] || intf=$(runt dump mm.bearer | grep intf | tail -n 1 | cut -f2 -d'=')  # 18.4 or higher firmware
[ -n "$intf" ] || intf='wwan0'  # default cellular interface

bugout() {
  accns_log w config "$@"
  exit
}

var_is_number(){
  [ -n "$1" ]  || return 1
  case $1 in
    ''|*[!0-9]*) return 1 ;;
    *) return 0 ;;
  esac
}

# Main
end_date=$(date "+%Y-%m-%d")
cur_year=$(date "+%Y")
cur_month=$(date "+%m")
if [ "$rollover_day" -lt "$(date +%d)" ]; then
  start_date="$cur_year-$cur_month-$rollover_day"
else
  case "$cur_month" in
    01)
      last_year=$((cur_year - 1))
      start_date="$last_year-12-$rollover_day"
      ;;
    02|03|04|05|06|07|08|09|10)
      last_month=$((cur_month - 1))
      start_date="$cur_year-0$last_month-$rollover_day"
      ;;
    *)
      last_month=$((cur_month - 1))
      start_date="$cur_year-$last_month-$rollover_day"
      ;;
  esac
fi

#We are monitoring SIM 1, as noted in the SIM_to_monitor variable above. If using another SIM slot, don't monitor data usage.
[ "$(sim)" = "$SIM_to_monitor" ] || exit

url="https://aview.accns.com/api/v4/devices/usage.json?auth_token=${api_token}&device_id=${mac}&start_date=${start_date}&end_date=${end_date}&interface=${intf}"

request_result=$(curl -kL -w %{http_code} -sfo /tmp/results.txt $url)

[ "$request_result" -eq '200' ] || bugout "error obtaining cellular usage from aView API ($request_result)"

upload_usage=$(grep -o "upload\":[0-9]\{1,12\}"  /tmp/results.txt | cut -f2 -d':' | awk '{s+=$1} END {print s}')
download_usage=$(grep -o "download\":[0-9]\{1,12\}" /tmp/results.txt | cut -f2 -d':' | awk '{s+=$1} END {print s}')

usage=$((upload_usage + download_usage))
var_is_number "$usage" || bugout "Usage not available from aView API ($upload_usage, $download_usage)"

if [ "$usage" -ge "$usage_limit" ]; then
  sim_slot=2
  [ "$(sim)" = 2 ] && sim_slot=1
  accns_log w config "Data usage limit exceeded ($usage out of $usage_limit bytes).  Switching to SIM slot $sim_slot."
  sim $sim_slot
fi

Create a new custom script under System -> Scheduled tasks -> custom scripts, and enter in the following. The "rollover day" should be adjusted to put in the rollover day of the month (2-digits).

#!/bin/sh

# don't check for SIM preference if the modem is not connected, as we
# may be going through our normal connection/APN-selection process
modem cli 2> /dev/null | grep -q "'connected'" || exit

# Only run this script on a certain day of the month
rollover_day='01'
current_day="$(date +%d)"
[ "$rollover_day" = "$current_day" ] || exit

# Prefer SIM slot 1.  If we're connected with SIM slot 2, switch back to slot 1
if [ "$(sim)" = 2 ]; then
  accns_log w config "Preferred SIM not detected. Switching to SIM slot 1."
  sim 1
fi
Click to copy