Kogotok
Kogotok
522 просмотров1 комментариев

SIM800-USB управление реле по исходящему звонку.

Здесь уже были статьи по управлению сценариями “умного” дома через звонки модема, который подключается через навесной монтаж или GPIO колодку.

Теперь разберем еще одно устройство, которое подключается напрямую к USB разъему.

Давайте сразу проясним, что управление критической инфраструктурой через обычный дозвон не является безопасным.

SIP телефония легко имитирует подделку любых номеров, операторы связи не препятствуют блокировке подмен номеров звонящих, а утекающие данные из многочисленных приложений в вашем телефоне могут с легкостью навести социального инженера на взлом важной для вас инфраструктуры. Квартиры - нет, гаражи - нет.

Только общественная инфраструктура, датчики, телеметрия - все то что не ведет к поломке, прямому ущербу или потенциальной угрозе людям.

Данный пример работы с GSM модемом является образовательным материалом для легкого входа в IOT процессы.

Нацеливаться будем на то, чтобы не ограничивать себя подключением к определенному номеру USB порта и сначала в коде проведем анализ подключенных устройств, выделив нам нужный порт USB.

Исходим из того, что вы уже подключили умное реле к своей репке или проделали действия для подготовки среды к запуску скриптов (речь про PHP).

Ну или добро пожаловать:

https://repka-pi.ru/blog/post/81

Некоторые комментарии по коду.

В первой части кода мы проверяем через команду lsusb количество шин и устройств, которое нам выдает система.

Вторым шагом проходим все USB устройства и в описании ищем нужный нам драйвер ch341

udevadm info -a -n /dev/ttyUSB0

Нашли? Отлично. Оно нам и нужно.

Первая команда AT для общения с модемом - это инициализации модема.

Далее следует набор тестовых запросов на идентификатор оборудованя IMEI, название оператора и качество связи. Выводим это все в терминал для своего спокоствия, чтобы убедиться, что подключение к сети состоялось.

Могут быть проблемы с сим картами, которые не относятся к тарифам для работы с модемами.

Один из вариантов это приобрести сим карту с тарифом умные вещи. Он есть у всех операторов. Такие карты гарантированно работают с данным модемом.

Также существуют недокументированные возможности в виде команды AT+SIMEI=<13цифр IMEI смартфона>, но это противозаконно, я об этом только слышал, никогда не делал и вам не советую.

Далее создаем неблокирующее чтение порта и отлавливаем знак перевода строки (enter).

Отловили строку, проверили на условие в цикле, если это то что нам нужно, например звонок, то сверяем номера из списка и производим нужные действия - в данном примере происходит открытие реле.
Напомню из предыдущего поста, что управление реле происходит через создание текстовых файлов папке /var/www/html.

Также пишем два log файла, один с номерами звонящих, второй файл пишет все команды обмена между терминалом sim800.

Для новичков как стартануть.

Открываем терминал на репке

пишем

sudo nano /var/www/html/read_usb_modem.php

Далее копируем текст скрипта(внизу статьи) и вставляем в окно терминала

Далее ctrl+X … (Save?) Y … Enter

SIM800-USB вставлен в USB порт? Запускаем, набираем в терминале

php read_usb_modem.php

Видим что Bus 002 отображает подключенный usb модем

далее скрипт пробегается по всем шинам и выбирает DEV = /dev/ttUSB0

модем стартует, показвает нам IMEI номер устройства, сеть оператора и качество связи.

Качество до 10 - слабенько, но работать будет, все что от 14 и выше можно расслабиться.

Если говорить про возможности SIM800, то у него есть функция работы с пакетными данными через GPRS, например подключение к http/https ресурсам, использование get, post запросов.

Иногда get/post запросы будут забирать управление терминалом - в момент установления пакетной сессии и обращения к вебсерверу, наш код в этот момент попадает в таймаут, небольшой до 40 секунд, но в этот интервал могут быть какие-то критические ожидания, учитывайте это.

Гораздо эффективнее реализовать протокол MQTT, он более легковесный, быстро переключается после звонков и менее требователен к качеству связи.
В целом конечно работа с пакетными данными является в 99% случаях надежной и успешной, но я бы отнес этот канал связи как резервный и использовал бы при отсутствии основного.

А основные функции, которые закрывает данный модем - это работа со звонками и смс, вот это нужно и обязательно использовать.

Надеюсь вам стало на шаг ближе и легче, чтобы перейти к действию и попробовать себя в управлении данным девайсом. На данный модем есть большой туториал PDF с командами и описанием, сюда его в виду объема прикрепить не могу, но вы с легкостью найдете его в поиске sim800 datasheet

Если остались вопросы, прошу в комментарии.

<?php

$start_time=time();

/*Лог создания службы sudo nano /etc/systemd/system/read_usb_modem.service

[Unit]
Description=SIM800 read com data
After=network.target


[Service]
Type=simple
Restart=always
RestartSec=1
AmbientCapabilities=CAP_SYS_RAWIO
User=root
ExecStart=/usr/bin/php  /var/www/html/read_usb_modem.php

[Install]
WantedBy=multi-user.target




//----------------------------------------------
Вот и все. Теперь мы можем запустить сервис:
sudo systemctl start read_usb_modem

И автоматически запускаться при загрузке:
sudo systemctl enable read_usb_modem
-----------------------------------------------------

Управляющие команды следующие:

этот скрипт упакован в службу сназванием read_usb_modem
	sudo systemctl start read_usb_modem
	sudo systemctl restart read_usb_modem
	sudo systemctl stop read_usb_modem
	
	
	Все что касается управления службой
	
	sudo systemctl enable read_usb_modem
	sudo systemctl disable read_usb_modem
	sudo systemctl status read_usb_modem

*/
ini_set('max_execution_time', 0);



$eol=chr(10).chr(13); //конец строки
//=======================
$dev = '';// sim 800C usb modem port

$terminal=shell_exec('lsusb');
//выводим отладочную информацию в терминал
echo $terminal;
echo "\n===============\n";
$tline=explode("\n",$terminal);

$time_relay_open=0;

$i=0;

foreach ($tline as $fdev)//проходим по всем dev устройствам в поиске нужного контроллера
{
	$terminal=shell_exec('udevadm info -a -n /dev/ttyUSB'.$i);
	
	foreach (explode("\n",$terminal) as $t2)
	{
		if (strpos(strtolower($t2),'ch341')!==false) 
		{
			$dev = '/dev/ttyUSB'.$i;// sim 800C usb modem 	
			echo $dev."\n";
			break;
		}
	}
	$i=$i+1;
}
echo "DEV=".$dev."\n";


//=======================================================================================
if(strlen($dev)==0)
{	
	echo "Модем не подключен к порту usb";
	sleep(10);
	exit();
}
else
{
	exec("stty -F $dev 9600 raw -echo");

	if ($handle = fopen($dev, "r+")){
		
		read_usb_modem_add_log("-------------------------");
		fwrite($handle, "AT".$eol); //start
		sleep(2);
		fwrite($handle, "AT+CLIP=1".$eol); //АОН вкл
		sleep(5);
		fwrite($handle, "AT+GSN".$eol); //GET GSN	
		
		$prev_ord=0;//регистрация символа chr(10)
		
		$sim800_terminal="";
		$trigger_ring=0;
		
//========================================================================		
		while(1==1)
		{
			//Используем режим неблокирующего чтения
			stream_set_timeout($handle, 20);
			stream_set_read_buffer($handle, 0);
			
			stream_set_blocking($handle, false);
			
			$rx = fread($handle,1); //ждем чтения одного символа из терминалки
			usleep(10000); //10000 = 10ms
	
			
			//реле открыто более 10 секунд назад - выключаем его
			if ($time_relay_open>0 && time()-$time_relay_open>10 && file_exists(__DIR__."/relay1open.txt")==false)
			{
				$time_relay_open=0;
				$fp = fopen(__DIR__."/relay1close.txt", 'w');
				fclose($fp);
			}
//================================================================			
			if (ord($rx)==13 && $prev_ord==1) //фиксируем в терминале от sim800 перевод строки. Обрабатываем
			{
				//========================================================
				if(strpos($sim800_terminal,'AT+GSN')!==false)
				{
					$gsn_num=str_replace(array(chr(13),chr(10)),'',substr($sim800_terminal,strpos($sim800_terminal,'AT+GSN')+strlen("AT+GSN")+1,strlen($sim800_terminal)));
					if(ctype_digit($gsn_num))
					{
						echo "modem imei: ".$gsn_num."\n";
					}
					else
					{
						echo "fake imei: ".$gsn_num."\n";
					}
					
					fwrite($handle, "AT+COPS?".$eol);
					
				}
				//====================
				if(strpos($sim800_terminal,'COPS:')!==false) //запрашиваем название оператора связи
				{
					$begin_str = strpos($sim800_terminal,'"')+1;
					$end_str = strpos($sim800_terminal,'"',$begin_str);
					if (strlen($end_str)==0) $end_str=$begin_str+10;
					
					$qual=str_replace(array(chr(13),chr(10)),'',substr($sim800_terminal, $begin_str, $end_str-$begin_str));
					echo "COPS IS: ".$qual."\n";
					
					fwrite($handle, "AT+CSQ".$eol); // QUAL
				}
				//====================
				if(strpos($sim800_terminal,'CSQ:')!==false) //обрабатываем информацию о качестве связи. 0-10 так себе, 15-31 хорошо
				{
					$begin_str = strpos($sim800_terminal,"CSQ:")+5;
					$end_str = strpos($sim800_terminal,"OK",$begin_str);
					if (strlen($end_str)==0) $end_str=$begin_str+10;
					
					$qual=str_replace(array(chr(13),chr(10)),'',substr($sim800_terminal, $begin_str, $end_str-$begin_str));
					echo "QUAL IS: $qual \n";
					
				}
				
				//==============================================================
				read_usb_modem_add_log($sim800_terminal);
				
				
				//========================================================
				//+CLIP: "+79261234567",145,"",0,"",0
				if (strpos($sim800_terminal,"+CLIP:")!==false)
				{
					$str_clip = strpos($sim800_terminal,"+CLIP:")+6;
					$str_begin = strpos($sim800_terminal,'"',$str_clip)+1;
					$str_end = strpos($sim800_terminal,'"',$str_begin);
					$phone_number = str_replace("+","", substr($sim800_terminal, $str_begin, $str_end-$str_begin));
					echo "Calling number: ".$phone_number."\n";
					
					if (strlen($phone_number)>0 && (ctype_digit($phone_number)) && time()-$time_relay_open>10)
					{	
						
						if (in_array($phone_number, array("79265111111","791111111","7922111111"))) //список акцептованных номеров
						{
							fwrite($handle, "ATH0".$eol); //завершаем звонок
							
							$fp = fopen(__DIR__."/relay1open.txt", 'w');
							
							fclose($fp);
							$time_relay_open=time();
							read_usb_modem_add_call_log("phonenumber exist: ".$phone_number);//полный лог звонков
							echo "phonenumber exist: ".$phone_number."\n";
						}
						else//действия на неизвестные номера
						{
							fwrite($handle, "ATH0".$eol); //завершаем звонок
							echo "unknown phone_number: ".$phone_number."\n";
							read_usb_modem_add_call_log("unknown phone_number: ".$phone_number);//полный лог звонков
						}
						
					}
				}
				$sim800_terminal="";
			}
			else
			{
				$sim800_terminal=$sim800_terminal.$rx;
			}
			if (ord($rx)==10){$prev_ord=1;} else {$prev_ord=0;}
			
		}
		
	}
	else
	{
		echo "read.usb.modem.cant.connected.exit";
		sleep(30);
	}
}



//================================FUNC=====================================
//================================FUNC=====================================
//================================FUNC=====================================

function read_usb_modem_add_log($str)//лог терминала
{
	$f=fopen(__DIR__."/sim800_log.txt", "a");
	fwrite($f,date("Y-m-d H:i:s",time())." - ".$str."\n");
	fclose($f);
}
//====================================================================
function read_usb_modem_add_call_log($str)//лог звонков
{
	$f=fopen(__DIR__."/sim800_call_log.txt", "a");
	fwrite($f,date("Y-m-d H:i:s",time())." - ".$str."\n");
	fclose($f);
}

			
?>

Комментарии (1)

Для участия в обсуждении вы должны быть авторизованным пользователем
ukolovda
ukolovda  

https://repka-pi.ru/blog/post/81 - эта ссылка внутри статьи некорректная, вместо 81 русский текст

Навигация

ВойтиРегистрацияТемы