Я думаю что почти у каждого найдется завалявшийся старый смартфон. В этой статье мы хотим научить тех кто интересуется как из смартфона можно сделать надежную сигнализацию для велосипеда. И не только для велосипеда но и для другого имущества. Писать код будем на Python 3 и будет возможность изменять набор функций приложения для других задач. Ну что ж делаем сигнализацию для велика на старом смартфоне.
Имеющиеся в продаже велосипедные сигнализации просто отпугивают воров громким звуком. Поэтому я решил сделать свое собственное устройство обратной связи. Первое, что пришло в голову, это разработать сигнализацию на микроконтроллере. Но потом подумал: а почему бы не использовать завалявшийся старый смартфон? Ведь у него на борту уже есть все для решения задачи: мобильный интернет, GPS для позиционирования, различные датчики для обнаружения внешних воздействий, камера и сенсорный экран. В общем вопрос с железом решен, осталось реализовать только программную часть.
TERMUX
Если вы еще не слышали о Termux, то срочно идите изучать матчасть. Termux — эмулятор терминала для операционной системы Android. Но не позволяйте слову «эмулятор» ввести вас в заблуждение, весь код запускается изначально.
Как известно, Android основан на ядре Linux. Termux добавляет к ядру минимальное окружение в виде набора утилит и интерпретатора bash. Этот набор можно легко расширить с помощью известной пользовательской команды Linux apt install _1_ ). Список пакетов достаточно обширен: от консольного редактора Vim до оконной системы X11 и среды рабочего стола Xfce.
Кроме того, всегда есть возможность написать свою программу на C или даже на ассемблере. Компилятор GCC также можно установить из пакетов. Если у вас есть привилегии суперпользователя, все становится еще интереснее: вы можете смонтировать корневой репозиторий и получить доступ к таким программам, как tcpdump или aircrack-ng. Для наших целей root-права не требуются, мы просто устанавливаем интерпретатор языка Python 3. К счастью, нужный нам пакет уже есть в репозитории.
Я рекомендую установить Termux из магазина программного обеспечения с открытым исходным кодом F-Droid. Если у вас еще нет этого магазина на вашем телефоне, перейдите на f-droid.org и загрузите соответствующее приложение. Затем на самом F-Droid в строке поиска введите Termux и установите следующие приложения: Termux, Termux:API и Termux:Widget. Если Android на вашем телефоне ниже 7-й, вам понадобится заархивированная версия. Вы можете взять это здесь. После установки запустите Termux и установите необходимые пакеты и модули Python, которые нам понадобятся. Для этого в открывшемся терминале введите следующие команды:
pkg update
pkg install termux-api
pkg install openssh
pkg install qrencode
pkg install python
pkg install pip
pip install pystun3
pystun3
в последней строке — это модуль Python, поэтому мы установили его с помощью pip install
вместо pkg install.
TERMUX:API
Командой pkg install termux-api устанавливаем поддержку Termux-API, что позволяет взаимодействовать с системой Android из командной строки: делать фото, записывать и воспроизводить звук, издавать вибросигнал, получать информацию с телефона , отображать диалоговые окна и многое другое. Чтобы изучить все возможности Termux-API, введите в командной строке termux-, дважды нажмите Tab, и вы увидите все доступные утилиты. Функционала достаточно для организации взаимодействия с пользователем с помощью всплывающих сообщений (termux-toast), диалоговых окон (termux-dialog) и уведомлений (termux-notification).
Для сигнализации нам нужна информация с датчика ускорения — акселерометра. Для этого давайте сначала посмотрим, какие датчики присутствуют в телефоне:
termux-sensor -l
В полученном списке датчиков ищите тот, в названии которого есть слово акселерометр. Например, в моем телефоне есть акселерометр BMI160 и линейное ускорение. Теперь можно попробовать прозондировать датчик следующей командой:
termux-sensor -s "BMI160 Accelerometer" -n 1
В моем случае вывод этой команды имеет следующий вид:
{
"BMI160 Accelerometer": {
"values": [
0.35223388671875,
0.20556640625,
9.873580932617188
]
}
}
ПРЕДВАРИТЕЛЬНАЯ ПОДГОТОВКА
Вы можете написать код прямо на свой телефон, установив любой текстовый редактор, например Vim или Nano. Но проще это сделать на компе и потом SSH программу на телефон. Для этого вам необходимо ввести свой SSH-ключ в файл ~/.ssh/authorized_keys.
Затем в консоли Termux запустите демон sshd, введя одноименную команду. Обратите внимание, что демон sshd прослушивает нестандартный порт 8022, поскольку у него нет привилегий суперпользователя.
Теперь вы можете получить доступ к телефону со своего ПК с помощью команды ssh _0_ -p 8022. Обратите внимание, что вы не можете указать имя пользователя, Termux примет его. Вы можете узнать IP-адрес телефона в вашей локальной сети, введя команду ifconfig в консоли Termux. Если вы пользователь Windows, используйте для входа клиент Putty. Чтобы перенести файл программы из текущей директории на компьютере в Termux, достаточно ввести в терминале на компьютере следующую команду:
cat program.py | ssh <IP-адрес телефона> -p 8022 "cat > program.py"
для Linux или такую для Windows:
set PATH=C:\путь\до\папки\putty;%PATH%
pscp -P 8022 program.py <IP-адрес телефона>
ПИШЕМ КОД
Программа состоит из двух частей:клиентской и серверной. Клиент запускается на телефоне, подключенном к велосипеду, и регулярно отправляет UDP-пакеты на сервер — телефон рядом с вами. Содержимое пакета может быть либо KNOCK, либо ALARM. После получения сообщения KNOCK сервер знает, что клиент работает правильно и у него нет проблем с сетью. В случае сообщения ALARM проигрываем заранее подготовленный файл со звуком сирены.
Итак, приступим к написанию клиентской части программы, которую назовем client_alarm.py. Во-первых, давайте импортируем необходимые модули.
#!/data/data/com.termux/files/usr/bin/env python3
import socket
import json
from subprocess import Popen, PIPE
import os
import time
from nat import nat_traversal
AVERAGE = 10
KNOCK_DELAY = 5
SENSOR_NAME = 'BMI160 Accelerometer'
ACCELEROMETER_DELAY = 20
ACCELERATION_THRESHOLD = 0.1
DELAY_AFTER_ALARM = 1
RPORT = 0
RHOST = ''
Проходим сквозь стену
NAT (преобразование сетевых адресов) — это механизм преобразования сетевых адресов, который позволяет нескольким устройствам подключаться к хостам в Интернете с использованием одного общего IP-адреса. Сегодня именно технология NAT позволяет получить доступ к глобальной сети из более чем 20 миллиардов устройств по всему миру, в то время как Интернет имеет лишь немногим более четырех миллиардов «белых» или маршрутизируемых IPv4-адресов.
NAT может быть настроен по-разному для разных провайдеров. Для подключения устройств будем использовать STUN (Session Traversal Utilities for NAT) — специальный сетевой протокол, позволяющий NAT-клиенту узнать свой внешний IP-адрес, а также метод трансляции портов во внешней сети. В этом случае за нас все сделает установленная нами ранее функция pystun3 get_ip_info().
При вызове этой функции будет сделано несколько запросов к разным адресам STUN-сервера. В ответ на запросы сервер будет возвращать информацию о том, к какому IP-адресу и порту был осуществлен доступ. Для наших целей достаточно, чтобы при доступе к определенному порту разных хостов в сети с одного и того же внутреннего порта провайдер назначал нам один и тот же внешний порт. Этот тип NAT называется ограниченным NAT. Если, с другой стороны, при доступе к разным хостам каждый раз назначаются разные внешние порты, подключение извне к этому устройству вызовет серьезные трудности. Этот тип NAT называется симметричным NAT.
Из протестированных мною операторов «Большой четверки» только «Билайн» имел симметричный NAT. Так что если вы владелец симки других операторов связи, то все должно получиться.
Итак, для прямого подключения двух телефонов пишем функцию nat_traversal.
Его можно вынести в отдельный файл nat.py,
так как эта функция будет общей для обеих программ: клиентской и серверной. Далее нужно импортировать функцию командой from nat import nat_traversal.
def nat_traversal():
from socket import socket, AF_INET, SOCK_DGRAM, timeout
import stun
import json
import os
import sys
import subprocess
import time
LPORT = 65000
LHOST = '0.0.0.0'
nat = stun.get_ip_info(LHOST, LPORT)
nat_json = json.dumps(nat)
os.system("clear")
os.system(f"echo '{nat_json}' | qrencode -t ansiutf8")
print(f"Your host parameters: {nat}")
os.system("termux-clipboard-set '' ")
print("Please, copy remote host info to your clipboard ...")
remote_nat = ''
for i in range(12):
cb = subprocess.getoutput('termux-clipboard-get')
try:
remote_nat = json.loads(cb)
if remote_nat:
break
except json.decoder.JSONDecodeError:
pass
time.sleep(5)
else:
print("Error: can't get remote host info", file=sys.stderr)
sys.exit(1)
print(f"Got remote host parameters: {remote_nat}")
fnat_type, rip, rport = remote_nat
sock = socket(AF_INET, SOCK_DGRAM)
sock.bind((LHOST, LPORT))
sock.settimeout(5)
for i in range(12):
try:
sock.sendto(b'NAT\n', (rip, rport))
sock.recv(1024)
except timeout:
pass
else:
sock.sendto(b'NAT\n', (rip, rport))
break
else:
print(f"Error: can't connect to remote host {rip}:{rport}", file=sys.stderr)
sys.exit(1)
print(f"Connection established with {rip}:{rport}")
sock.settimeout(None)
return rip, rport, sock
nat_tarversal
сначала вызывает функцию get_ip_info pystun3,
которая возвращает три значения: тип NAT, внешний IP-адрес и внешний порт, соответствующий нашему внутреннему LPORT. После определения внешнего IP-адреса и порта на обоих телефонах необходимо произвести обмен этой информацией между устройствами. Для этого выведем в консоль результат работы функции get_ip_info
в виде QR-кода.os.system('termux-wake-lock')
if RHOST and RPORT:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
else:
RHOST, RPORT, sock = nat_traversal()
def sensor_get():
one_measure = ''
while not one_measure:
for i in range(9):
one_measure += p.stdout.readline().decode('utf-8')
if one_measure == '{}\n':
one_measure = ''
break
if one_measure:
data = json.loads(one_measure)
a = data[SENSOR_NAME]['values']
return a
os.system('termux-sensor -c')
p = Popen(['/data/data/com.termux/files/usr/bin/termux-sensor', '-s', SENSOR_NAME, '-d', str(ACCELEROMETER_DELAY)], stdin=PIPE, stdout=PIPE)
a_prev = sensor_get()
print('sensor ready!')
t_prev = time.time()
while True:
try:
acceleration = 0
for i in range(AVERAGE):
a = sensor_get()
da = sum( (ai - a_prev_i)**2 for ai, a_prev_i in zip(a, a_prev))
acceleration += da
a_prev = a
acceleration /= AVERAGE
if acceleration > ACCELERATION_THRESHOLD:
sock.sendto(b'ALARM\n', (RHOST, RPORT))
print('ALARM')
time.sleep(DELAY_AFTER_ALARM)
t_cur = time.time()
if t_cur - t_prev > KNOCK_DELAY:
sock.sendto(b'KNOCK\n', (RHOST, RPORT))
print('KNOCK')
t_prev = t_cur
except KeyboardInterrupt:
break
p.send_signal(2)
sock.close()
СЕРВЕРНАЯ ЧАСТЬ
Начнем с импорта модулей и задания констант.
#!/data/data/com.termux/files/usr/bin/env python3
import threading
import socket
import time
import os
from nat import nat_traversal
LPORT = 0
LHOST = '0.0.0.0'
WAIT_FOR_KNOCK_TIME = 15
DIR_NAME = '/data/data/com.termux/files/home/alarm/'
ALARM_FILE_NAME = 'alarm_short.mp3'
LINK_LOSS_FILE_NAME = 'link_loss.mp3'
LINK_RESTORE_FILE_NAME = 'link_restored.mp3'
KNOCK_FLAG = 0
KNOCK_WARN = 1
threading.Thread:
class UDP_receive(threading.Thread):
def run(self):
global KNOCK_FLAG
while True:
data, addr = sock.recvfrom(1024)
if data == b'KNOCK\n':
print(data.decode('utf-8'), end = '')
KNOCK_FLAG = 0
sock.sendto(b'OK\n', addr)
elif data == b'ALARM\n':
print(data.decode('utf-8'), end = '')
sock.sendto(b'OK\n', addr)
os.system('termux-media-player play ' + DIR_NAME + ALARM_FILE_NAME)
else:
print('Unknown data:')
print(data.decode('utf-8'))
os.system('termux-wake-lock')
if LHOST and LPORT:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((LHOST, LPORT))
else:
RHOST, RPORT, sock = nat_traversal()
thread = UDP_receive()
thread.start()
print('Starting alarm server... ')
while True:
try:
KNOCK_FLAG = 1
time.sleep(WAIT_FOR_KNOCK_TIME )
if KNOCK_FLAG:
KNOCK_WARN = 1
print('Связь потеряна')
os.system('termux-media-player play ' + DIR_NAME + LINK_LOSS_FILE_NAME)
else:
if KNOCK_WARN:
KNOCK_WARN = 0
print('Связь установлена')
os.system('termux-media-player play ' + DIR_NAME + LINK_RESTORE_FILE_NAME)
except KeyboardInterrupt:
break
sock.close()
os.kill(thread._native_id, 15)
mkdir -p /data/data/com.termux/files/home/.shortcuts
chmod 700 -R /data/data/com.termux/files/home/.shortcuts
ВЫВОДЫ
Из этой статьи видно что Termux мощнейший инструмент для программирования смартфона. Еще одно преимущество в том что во время тревоги можно делать фото с камеры. Для этого используется скрипт termux-camera-photo.
Так же имеются скрипты termux-telephony-call, termux-sms-send с помощью которых можно получать звонок или смс соответственно.
1 comments On Делаем сигнализацию для велика на старом смартфоне
Здравствуйте, вопрос немного не по теме: как управлять старым планшетом, вернее плеером на нём из адресной строки браузера через get запросы? По идее на планшете должен быть какой-то сервер? Хотелось бы почитать статью. Спасибо.