Примерно год назад мы запустили свой маленький проект с оповещениями о поломках Москвовского метро.
Самой главной проблемой в нем оказалась рассылка смс. Мы не ожидали, что проект понравится и у нас будет 1500+ регистраций. В самом лучшем случае мы расчитывали человек на 300. Этим мы были приятно удивлены.
Проблема с смс в первую очередь была из-за цены. Одна рассылка получалась примерно 3000 рублей. С учетом того, что цена 1 смс 1,5 рубля. Были времена, когда неполадки в движением поездов были каждые 3 дня, т.е. 10 поломок в месяц. 3000*10 = 30 000 рублей. Дороговато для проекта, который не финансируется.
Тут мы начали изобретать велосипед. А именно, искать тарифы с действительно безлимитными смс. В итоге мы его нашли. Стоило что-то около 600 рублей в месяц. Дальше нужно было решить вопрос с отправкой смс. И тут пришло время древней nokia 6610i, которая пылилась в шкафу как память о былой эпохе. Но ее пришлось чуть доработать, а именно подключить по uart к ноуту, чтобы отправлять задания.
Схема
Пара диодов тут нужна чтобы сбросить напряжение с 5V до ~3.4V. Падение на диодах суммарно получается 1.6V при тока 1А. Такой ток нокия потребляет только при активной работе с сетью, а большую часть времени падение на них будет около 1.5V.
Большой и толстый конденсатор нужен чтобы сглаживать потребление телефона в тот момент когда работает передатчик, и он много жрет.
А резисторы — заменяют терморезистор и пин идентификации батарейки (BSI), по которому nokia понимает что к ней подключен аккумулятор.
У нас подходящих номиналов резисторов не нашлось, поэтому собрали из того что было.
Для отправки использовалась программа gnokii, из названия которой вполне очевидно, что писалась она как раз для таких целей.
Конфиг от нашей 6610i:
[global] port = /dev/ttyUSB0
connection = dlr3p
model = 6510
Команда для отправки
echo 'text' | gnokii --sendsms number
Чтобы рассылать можно можно было не только от root, нужно выставить соответствующие права на /dev/ttyUSB0
Тут понравилось, что нам могли отвечать, и нам отвечали. Но и проблемы тут не закончились, а именно скорость: такая рассылка занимала 4 часа. Поэтому таким образом мы рассылали информацию, которая актуальна длительный период, например, про закрытие части линии на ремонт. 1 симки нам хватало примерно на 3 тысячи сообщений, т.е. на пару рассылок. Дальше нас блокировали. Мы звонили в ТП и спрашивали причины блокировки, на что нам отвечали — рассылка. Один раз нам хватило одной симки на 5 рассылок, таймауты делали побольше и меняли текст. И нам всегда везло на красивые номера — мелочь, но приятно.
А поскольку в обычном случае у нас актуальность информации составляет минут 40, рассылка в идеале должна быть за пару минут. Поэтому мы решили сделать рассылку на телефоне с Android. Главным преимуществом этого решения была скорость, правда тоже далеко не идеально. 1 смс отправлялась за 1.5 секунды, что в результате выходило примерно в 37 минут. Дальше можно было параллелить при помощи подключения еще телефона и добиться нужной скорости. Но тут нас задушил оператор, который блочил нас или посредь первой рассылки или в начале второй.
Логика приложения заключилась в периодическом получении задания с сервера. Примерно раз в несколько минут приложение обращалось на сервер за командой в формате json, которая состояла из массива телефонных номеров и текстов смс.
У нас был поток для забора команды с таймаутом, поток для рассылки смс, BrodasReceiver для запуска после загрузки. Но проект потерялся, ввиду давности, поэтому полного кода не будет. Текст смс мы урезали до максимума 1 смс — 70 символов (это для кириллицы), это делала серверная часть, но на всякий случай отправка смс была ровно на 70 символов:
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage("NUM", null, "TXT", null, null);
не забывая про права на отправку смс в манифест
<uses-permission android:name="android.permission.SEND_SMS" />
Для автозапуска после включения не забываем про права:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Прописать в манифест:
<receiver android:name=".Boot"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Код Boot:
public class Boot extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
тут запуск потока
}
}
Автозапуск на случай разрядившейся батарейки ну и других аналогичных ситуаций, вдруг после включения забуду запустить приложение. А на этом телефоне всеравно живет только это приложение, поэтому некоторое расточительство по отношению к батарейке нам не страшно.
Ну и в Activity добавляем запуск потока.
Так же разрешаем приложению доступ в интернет:
<uses-permission android:name=«android.permission.INTERNET»/>
И еще важный момент, чтобы наше приложение работало даже с выключенным дисплеем нужно вызвывать PowerManager. Иначе система будет усыплять приложение по своему желанию, для экономии заряда, и запросы будут выполняться нерегулярно.
Для этого добавляем пермишн:
<uses-permission android:name="android.permission.WAKE_LOCK" />
Дабавляем код в Activity:
PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP|
PowerManager.FULL_WAKE_LOCK| PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "");
И в поток
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
wl.acquire();
Обращение к серверу, обработка полученного json
wl.release();
Такой способ тоже не проработал долго, поскольку постоянно менять симки было не очень удобно и рационально — ценник стремительно рос и это потеряло смысл.
Дальше мы пробовали рассылать через Whatsapp, но тут номера умирали каждые 10 сообщений, а то и быстрее. А регистрация 1 номера стоила 7 рублей. Мы опять начали выходить на те-же цифры, с которых начали.
А не так давно мы сделали бота для телеграм — https://telegram.me/msk_metro, тут все так же как и с PushBullet, который мы подключили по просьбам после первого поста на хабре. Только тут мы можем удалять случайно прошедшие модерацию сообщения, а в PushBullet — нет.
Автор: Irenica