как бы мало, поэтому в качестве номера я попросил записать номер 3G GSM модема на дачной точке доступа, под OpenWRT и за вечер набросал и отладил скрипт который принимает звонок, проверяет есть ли звонящий номер в локальной базе номеров, если есть - вешает трубку, и звонит на ворота.
модем с симкой в роутре так и так стоит, т.к. это альтернативный канал в интернет, поэтому из затрат - новый модем с поддержкой голоса (~300 рублей на авито можно найти, или чуть дороже) и вечер времени на написание основного тела скрипта.
+ пару вечеров на шлифовку, по мере наличия желания

дополнительно прикрутил логгирование входящих звонков и открытие ворот на почту. это больше для отладки чем для реального применения
Код: Выделить всё
root@SmartBox:~# cat /root/scripts/listen.sh
#!/bin/sh
door="+79251234567"
db="/root/scripts/numbers.db"
call_timeout=20
port="/dev/ttyUSB2"
mail_login="modem@lissyara.su"
mail_server="mx.lissyara.su"
mail_pass="super-mega-pass"
mail_rcpt="admin@lissyara.su"
script="`basename $0`"
pid_file="/tmp/$script.pid"
hostname="`uci get system.@system[0].hostname`"
response_all="/tmp/response.all.log"
response_clip="/tmp/response.clip.log"
response_tmp="/tmp/response.tmp.log"
response_call="/tmp/response.call.log"
# stub: detect port change
test -c /dev/ttyUSB3 && port="/dev/ttyUSB3"
# check process
if test -s $pid_file
then
pid=`cat $pid_file`
num_proc=`ps w | grep $pid | grep $script | wc -l`
if [ $num_proc -gt 0 ]
then
exit 0
fi
fi
# write PID
echo -n $$ > $pid_file
# log start
logger "start listen calls, callback to $door, using $port"
# clear log
echo -n > $response_all
echo -n > $response_clip
# set up modem device to translate outgoing \n into \r\n
stty -F $port 9600 -echo icanon onlcr igncr
# Open modem for reading
exec 5<$port
# and writing
exec 6>$port
#function
write2port(){
echo "$1" >&6
}
mailsend(){
/usr/bin/mailsend -f $mail_login -smtp $mail_server -auth -user $mail_login \
-pass $mail_pass -t $mail_rcpt -sub "$1" -M "`date +%Y-%m-%d` in `date +%H:%M:%S` $1" &
}
# https://habr.com/ru/articles/845034/
write2port AAAAAAAT
# allow RING message
write2port "AT+CRC=1"
# number detect (AON)
write2port "AT+CLIP=1"
# allow end call by ATH command
write2port "AT+CVHU=0"
# no last call list
#write2port "AT+CLCC=0"
#write2port "AT+CMGD=ALL"
# disable ^RSSI: in log
#write2port "AT^CURC=0" >&6
# read port in cycle
while true
do
# timeout
sleep 0.3
# check port
test -e $port || exit
# read port
read -t 1 RESPONSE <&5
echo $RESPONSE > $response_tmp
echo $RESPONSE >> $response_all
# save call. count call, if 2 or more - open door
if grep CLIP: $response_tmp
then
echo $RESPONSE >> $response_clip
if [ `grep CLIP: $response_clip | wc -l` -lt 2 ]
then
continue
fi
# extract last line
AT=`grep CLIP: $response_clip | tail -1`
# log call
echo `date +%Y-%m-%d` in `date +%H:%M:%S`: $AT >> /tmp/$script.call.log
# extract caller number from line
number=`echo $AT | awk -F '"' '{print $2}'`
# drop call
sleep 1
write2port "ATH"
# log call
logger "call from $number"
# send info
mailsend "$hostname: Call from `grep $number $db`"
# callback
if grep $number $db
then
sleep 1
# send mail to me
mailsend "$hostname: open door, by `grep $number $db`"
# log open door
logger "call to $door, open by $number"
# call to doors
write2port "ATD$door;"
sleep 2
# clear callback log
echo -n > $response_call
# wait ~8 seconds and drop call, if no response
start=`date +%s`
while true
do
# read and save answer
read -t 1 RESPONSE <&5
echo $RESPONSE >> $response_call
echo $RESPONSE >> $response_all
# check answer
if grep "CONN:1,0" $response_call
then
# log end call by answer
logger "call to $door end by answer"
# end call by answer
write2port "AT+CHUP"
# start listener
sleep 2 && sh /root/scripts/listen.sh &
exit
fi
# time in seconds
end=`date +%s`
# diff between start and end time
diff=`expr $end - $start`
# check run time
if [ $diff -gt $call_timeout ]
then
logger "call to $door end by timeout: $call_timeout seconds expired"
# end call
write2port "AT+CHUP"
# reboot modem
#sleep 2
#write2port "AT+CFUN=1"
# start listener
sleep 2 && sh /root/scripts/listen.sh &
exit
fi
done
else
# log unknown number
logger "number not found: $number"
mailsend "$hostname: number not found: $number"
echo -n > $response_call
echo -n > $response_clip
# reboot modem
#sleep 2
#write2port "AT+CFUN=1"
fi
fi
done
# delete pid
rm -f $pid_file
sh /root/scripts/listen.sh &
Код: Выделить всё
root@SmartBox:~# crontab -l
#
MAILTO=""
4 4 * * * sh /root/scripts/backup.sh
1,21,41 * * * * sh /root/scripts/ping.and.reboot.sh
* * * * * sh /root/scripts/listen.sh
Код: Выделить всё
root@SmartBox:~# cat /root/scripts/numbers.db
+79261112233 lissyara
+79264445566 nikita small
(штатный sleep не умеет интервалы менее 1 секунды)
собственно, известные баги.
1. некорректно работает pgrep, поэтому процесс приходится искать через ps. возможно свзяано с тем что замучал саму OpenWRT, надо переустанавливать, и проверять на чистую - но - лень

2. иногда модем отваливается. зависит от модема (я тестил на паре huawei, остановился на E3131, более стабильно работает, пока отваливался один раз за две недели, к сожалению разбираться возможности не было, ребутнул удалённо точку и поехал)
3. периодически, на первый гудок детектитстя предыдущий звонивший номер. поэтому трубку вешаем по второму гудку. не разобрался, вроде народ в инетах жаловался на подобную проблему но у меня никакими АТ командами это исправить не удалось. костыль, ждём второй гудок, второй детект - там номер 100% верный.
и, да, интернет по 3G нормально работает через этот же модем на порту ttyUSB0