Keywords: Mode: All keywords (AND) |
Sat Oct 07, 2017 10:46
|
birnbacs: I have solved the above and some other problems and would like to share the outcome. The script below will
* work on FreeBSD (like FreeNAS 9)
* support different ESSD commands for account balance and expiration date (like Aldi Talk)
* accept character encodings with German umlauts
* fix some misleading debug output
German users: check out the smsd.config file with German provider settings in this forum.
#!/usr/local/bin/bash
###########################################################################
# Global settings:
get_balance_after=5 # 1 = get the balance after at least one message is sent.
max_age=24 # an integer for hours, 0 = disable periodic checking.
alert_balance=5 # an integer for "euros".
alert_expiration=14 # an integer for days.
# set to "" for no notification
alert_to="491771401303"
###########################################################################
# Device depended settings:
# Comment out the next command if a DEVICENAME setting should be taken from
# the name of this file (which can be a symbolic link). For example:
# /var/spool/sms/regular_run/GSM1.sh
#DEVICENAME="GSM1"
[ -z "$DEVICENAME" ] && tmp=${0##*/} && DEVICENAME=${tmp%%.*}
balance_file="/var/spool/sms/stats/${DEVICENAME}.balance"
counter_file="/var/spool/sms/stats/${DEVICENAME}.counter"
get_balance_flagfile="/var/spool/sms/stats/get.${DEVICENAME}.balance"
regular_run_cmdfile="/var/spool/sms/regular_run/${DEVICENAME}.cmdfile"
regular_run_statfile="$2"
outgoing="/var/spool/sms/outgoing"
###########################################################################
# START OF OPERATOR SPECIFIC SETTINGS
# If more than one modem is used and they have different operator specific
# settings, move this section to the files for each modem and include the
# file here using the following command:
# . /var/spool/sms/regular_run/${DEVICENAME}.operator_settings.sh
# The USSD commands to output to the modem
# several commands may be concatenated with "\n"
# first command should be for balance, optional second for expiration date
ussd_command="AT+CUSD=1,\"*100#\",15\nAT+CUSD=1,\"*102#\",15"
# This is an example result for the query:
# 2010-05-09 14:16:11,5, GSM1: CMD: AT+CUSD=1,"*100#": OK +CUSD: 2, ...
# ... "Liittym�si saldo on 22.36 EUR. Puheaikasi vanhenee 27.04.2011.",15
# Defines how balance can be found from the result:
balance_prefix="Ihr Guthaben beträgt: "
# Defines how the balance amount part ends (NOT the radix symbol):
balance_suffix=" ."
# Defines how the expiration date can be found.
# With an empty setting the expiration is not checked.
balance_expiration="endet am "
# Helper function for converting date from the answer to the format yyyy-mm-dd
# Modify this if necessary.
extract_expiration()
{
# datestamp to format yyyy-mm-dd
echo "${1:6:4}-${1:3:2}-${1:0:2}"
}
: <<COMMENTBLOCK
Example 2:
..."Balance subscription is EUR 22.36. Your allotted time expires 04/27/2011."
balance_prefix="EUR "
balance_suffix="."
balance_expiration="expires "
Command in extract_expiration(): echo "${1:6:4}-${1:0:2}-${1:3:2}"
Example 3:
..."The balance is 34.84 B. & valid until 26/07/10 "
balance_prefix="is "
balance_suffix="."
balance_expiration="until "
Command in extract_expiration(): echo "20${1:6:2}-${1:3:2}-${1:0:2}"
Example 4:
...Ihr Restguthaben ist CHF 18,87
balance_prefix="CHF "
balance_suffix=","
balance_expiration=""
COMMENTBLOCK
# END OF OPERATOR SPECIFIC SETTINGS
###########################################################################
substr()
{
local string=$1
local prefix=$2
local suffix=$3
local ppref=${string%${prefix}*}
# Changed 2010-11-02:
if [[ "$ppref" == *${prefix}* ]]
then
string=${string//\"/}
local position=$(echo | awk '{
print index("'"${string}"'", "'"${prefix}"'")
}')
if [ $position -gt 0 ]; then
ppref=${string:0:$(($position - 1))}
fi
fi
# -------------------
local ssuff=${string#*${suffix}}
local nopref=${string#${ppref}${prefix}}
echo ${nopref%${suffix}${ssuff}}
}
#--------------------------------------------------------------------------
date2stamp()
{
case `uname` in
FreeBSD)
if [ ${#1} -gt 10 ]; then
date -juf "%Y-%m-%d %H:%M:%S" "$1" +%s
else
date -juf "%Y-%m-%d" "$1" +%s
fi
;;
Darwin)
date -juf "%Y-%m-%d %H:%M:%S" "$1" +%s
;;
*)
date --utc --date "$1" +%s
;;
esac
}
#--------------------------------------------------------------------------
dateDiff()
{
local sec=0
case $1 in
-s) sec=1; shift;;
-m) sec=60; shift;;
-h) sec=3600; shift;;
-d) sec=86400; shift;;
*) sec=86400;;
esac
local dte1=$(date2stamp "$1")
local dte2=$(date2stamp "$2")
local diffSec=$((dte2-dte1))
echo $((diffSec/sec))
}
###########################################################################
test -e "$counter_file" || exit 1
# triggering balance based on number of SMSes sent requires stats: in smsd.conf place
# stats = <directory of this script>
messages=$(formail -zx ${DEVICENAME}: < "$counter_file")
if [ "$1" = "PRE_RUN" ]; then
get_balance=0
# Get the balance if it was requested:
[ -w "$get_balance_flagfile" ] && get_balance=1 && \
unlink "$get_balance_flagfile"
if [ -r "$balance_file" ]; then
# Get the balance if a defined number of messages were sent.
messagesb=$(formail -zx Messages: < "$balance_file")
[ $(($messages - $messagesb)) -ge $get_balance_after ] && get_balance=1
else
# Get the balance because the previous value is not known.
get_balance=1
fi
# Check the age of the last query if necessary:
if [ $get_balance = 0 ] && [ $max_age -gt 0 ]; then
last_query=$(formail -zx Last_query: < "$balance_file")
age=$(dateDiff -h "$last_query" "$(date +"%Y-%m-%d %T")")
[ $age -ge $max_age ] && get_balance=1
fi
# NOTE: option -e necessary for bash on FreeBSD to process '\n' between commands
[ $get_balance -gt 0 ] && echo -e "$ussd_command" > "$regular_run_cmdfile"
else
# 2011-06-29: Check that USSD command is found:
result=""
if [ -r "$regular_run_statfile" ]; then
tmp=${ussd_command%%"\n"*} # throw away all but first ussd command
tmp=${tmp//\"/\\\"} # escape double quotes
tmp=${tmp//\*/\\*} # escape asterisks
# concatenate responses and check if it contains the first command
result=$(tr -d "\n\r" < "$regular_run_statfile" | grep "$tmp")
fi
if [ -n "$result" ]; then
balance_low=-1 # Initial value means unknown.
balance=-1
balance_alerted=""
expiration_low=-1
expiration=-1
expiration_alerted=""
sms_alert=""
current_alert=""
# 2010-11-02: Change Ctrl-B to $
result=$(echo "${result//$'\x02'/$}")
# Check that required words exists:
if [[ "$result" == *${balance_prefix}* ]] && \
[[ "$result" == *${balance_suffix}* ]]
then
# Get the balance and check it:
balance=$(substr "$result" "$balance_prefix" "$balance_suffix")
balance_low=0
if [ $(expr "$balance" + 1 2> /dev/null) ]; then
[ $balance -le $alert_balance ] && balance_low=1
else
#echo "Error while parsing an integer: $balance"
echo "Balance $balance is above warning threshold $alert_balance"
fi
else
echo "Error while parsing the answer (balance): $result"
fi
# Get the expiration date if defined, and check it:
if [ -n "$balance_expiration" ]; then
if [[ "$result" == *${balance_expiration}* ]]; then
expiration_low=0
expiration=$(substr "$result" "$balance_expiration" "")
expiration=$(extract_expiration "$expiration")
expiration=$(dateDiff -d "$(date +"%Y-%m-%d")" "$expiration")
echo "time until expiration in days is $expiration days"
[ $expiration -le $alert_expiration ] && expiration_low=1
else
echo "Error while parsing the answer (expiration): $result"
fi
fi
if [ -e "$balance_file" ]; then
# Get previous values:
current_alert=$(formail -zx Current_alert: < "$balance_file")
balance_alerted=$(formail -zx Balance_alerted: < "$balance_file")
expiration_alerted=$(formail -zx Expiration_alerted: < "$balance_file")
fi
balance_gone_low=0 # added 2010-11-03
# If not yet alerted and the balance has gone low, alert now:
if [ -z "$balance_alerted" ] && [ $balance_low = 1 ]; then
balance_gone_low=1
balance_alerted=$(date +"%Y-%m-%d %T")
tmp="The balance has gone low ($balance)."
echo "$tmp" # This message goes to the smsd.log
[ -z "$sms_alert" ] && sms_alert="Alert:"
sms_alert="${sms_alert} ${tmp}"
# If the expiration is already alerted, but the issue is still active,
# include it in the message:
if [ -n "$expiration_alerted" ] && [ $expiration_low = 1 ]; then
sms_alert="${sms_alert} The expiration is also near ($expiration days)."
fi
fi
# Remove an outdated alert:
[ -n "$balance_alerted" ] && [ $balance_low = 0 ] && balance_alerted=""
# If not yet alerted and the expiration is near, alert now:
if [ -z "$expiration_alerted" ] && [ $expiration_low = 1 ]; then
expiration_alerted=$(date +"%Y-%m-%d %T")
tmp="The expiration is near ($expiration days)."
echo "$tmp" # This message goes to the smsd.log
[ -z "$sms_alert" ] && sms_alert="Alert:"
sms_alert="${sms_alert} ${tmp}"
# If the balance is already alerted, but the issue is still active,
# include it in the message:
if [ -n "$balance_alerted" ] && [ $balance_low = 1 ]; then
if [ $balance_gone_low -eq 0 ]; then
sms_alert="${sms_alert} The balance is also low ($balance)."
fi
fi
fi
# Remove an outdated alert:
[ -n "$expiration_alerted" ] && [ $expiration_low = 0 ] && \
expiration_alerted=""
[ -z "$balance_alerted" ] && [ -z "$expiration_alerted" ] && \
current_alert=""
if [ -n "$sms_alert" ] && [ -n "$alert_to" ]; then
# Send the SMS:
FILE=$(mktemp /tmp/alert_XXXXXX)
echo "To: $alert_to" >> $FILE
echo "" >> $FILE
echo "$DEVICENAME $sms_alert" >> $FILE
FILE2=$(mktemp "${outgoing}/send_XXXXXX")
mv $FILE "$FILE2"
fi
# Save the details:
DATE=$(date +"%Y-%m-%d %T")
echo "Last_query: $DATE" > "$balance_file"
[ -n "$sms_alert" ] && current_alert="${DATE}, $sms_alert"
[ -n "$current_alert" ] && \
echo "Current_alert: $current_alert" >> "$balance_file"
echo "Messages: $messages" >> "$balance_file"
echo "Balance: $balance" >> "$balance_file"
[ -n "$balance_expiration" ] && \
echo "Expiration: $expiration" >> "$balance_file"
[ -n "$balance_alerted" ] && \
echo "Balance_alerted: $balance_alerted" >> "$balance_file"
[ -n "$expiration_alerted" ] && \
echo "Expiration_alerted: $expiration_alerted" >> "$balance_file"
#echo "" >> "$balance_file"
#echo "$result" >> "$balance_file"
fi
fi
exit 0
Enjoy!
|
Fri Sep 22, 2017 20:40
|
birnbacs: As a second channel for secure data delivery. A mail message is sent to a recipient, comprising zip-encoded material. The password is then send via SMS.
|
Thu Sep 21, 2017 18:40
|
birnbacs: Is there a way of running more than one script per device regularly?
In my setup I need a different USSD command argument for balance (*100#) and lease time (*102#). The way I understand the script it gets run a first time for outputting the command to regular_run_cmdfile and a second time when it picks up the answer from regular_run_statfile. In other words I cannot simply add another USSD command to the existing file and expect it to work.
|
Thu Sep 21, 2017 18:30
|
birnbacs: I got this script to run on a FreeBSD system (FreeNAS, really) and have some amendments to the script to suggest. Please kindly consider this:
* the message "error parsing an integer" seems incorrect. The echo statement is executed when the current balance is above the warning threshold, which is good. I replaced the message with "Balance $balance is above warning threshold $alert_balance"
* FreeBSD requies the same format for the date() builtin function as Darwin (tehy are both based on BSD), so I extended the date2stamp() routine by another case statement.
* the inline explanation for balance_suffix is misleading as it may understood as indicating the radix (the sign between major and minor money quantities, e.g. between Euros and Euro-cents). I suggest this explanation:
# Defines how the balance amount part ends (NOT the radix)
* some documentation for making the script work might also be valuable to others:
+ file <DEVICE>.counter must exist and contain "<DEVICE>: <n>"
+ file <DEVICE>.balance causes trouble if it does not contain a line "<DEVICE>: <n>"
|
Thu Sep 21, 2017 13:21
|
birnbacs:
birnbacs,
The response is hexadecimal representation of UCS2 encoding. Use a modem setting ussd_convert = 1 to decode it.
You could just handle the expiration manually, as it does not change all the time.
I found a solution to problem 1 and it is embarrassingly straightforward:
GSM1.sh now contains the line
ussd_command="AT+CUSD=1,\"*100#\",15
|
Thu Sep 21, 2017 07:30
|
birnbacs:
birnbacs,
The response is hexadecimal representation of UCS2 encoding. Use a modem setting ussd_convert = 1 to decode it.
You could just handle the expiration manually, as it does not change all the time.
Thanks Keke,
I will work on problems 2 and 3 as soon as I get there, I am sure I will find a solution.
I am still blocked by problem #1 though. Do you have any idea on fixing the problems issuing the USSD command?
|
Thu Sep 21, 2017 06:06
|
birnbacs:
birnbacs,
The response is hexadecimal representation of UCS2 encoding. Use a modem setting ussd_convert = 1 to decode it.
You could just handle the expiration manually, as it does not change all the time.
Thanks a ton but this did not make much differende. GSM1.balance still reads:
Last_query: 2017-09-21 08:05:31
Messages:
Balance: -1
2017-09-21 08:05:31,5, GSM1: CMD: AT+CUSD=1,"*100#": OK +CME ERROR: 258 (Phone is busy)
|
Wed Sep 20, 2017 08:01
|
birnbacs: All,
I have a language problem and a provider problem and your help solving them will be much appreciated.
My modem is a ZTE MF112, my provider is the German e-plus. When querying the prepaid balance using
AT+CUSD=1,"*100#"
I get error 258 (device busy). This is true for both smsd via GSM1.sh and a direct AT-command based conversation with the modem.
However, I can get an answer by requesting the German character set in a third argument (15) to CUSD:
AT+CUSD=1,"*100#",15
+CUSD: 0,"00490068007200200047007500740068006100620065006E0020006200650074007200E400670074003A00200039002C003700370020002E",72
This can be decoded to "Ihr Guthaben beträgt: 9,77 ."
Questions:
1.) what is a good way of splicing the extra argument in? The proposed GSM1.sh does not appear to support this. Maybe there is a general AT command I could use for setting the character set in all modem responses?
2.) the answer is funny in that it contains '00' as every second byte, potentially making decoding fail. Any thoughts on this?
3.) the response does not yield the remaining time for using the SIM card. For this I need to use *102#. A sample answer would then be (after removing zeroes and decoding): "Das aktuelle Aktivitätszeitfenster Ihrer SIM-Karte endet am 24.08.2018 und kann durch weitere Aufladungen verlängert werden." Nice and clean.
I could configure a first script for balance (say GSM1.sh) and a second one (GSM2.sh) for time. Can anybody think of a more elegant way to check both figures in one go?
Kind regards
birnbacs
|