В личных сообщениях меня попросили рассказать об опыте удаленного управления Uniden. Я действительно активно использую подобное решение. Более того, Uniden (далее просто “U”) у меня уже второй год работает только удаленно, стоит около антенны, и я не помню даже, когда его трогал руками в последний раз.
Я для начала расскажу в общем о решении и, если будут интересны детали, поясню подробно. Пишите сюда вопросы.
Я все пишу на Python. Все примеры кода на нем.
АППАРАТНАЯ ЧАСТЬ
Вот общая картинка аппаратной части решения
Увеличить
Все купил на Али. В качестве компьютера используется самый обычный одноплатный Raspberry PI 3. Связь с внешним миром по встроенному WiFi.
Для управления питанием купил USB реле. Он просто отключает/подключает один из проводов питания. Сначала опасался такого решения, но многолетний опыт показывает, что оно рабочее. Программно управлять очень просто, но конкретная реализация зависит от модели реле. Мой видится как Com порт.
Вот так им управлять. Куда уж проще!
import serial
ser = serial.Serial("COM8")
def on(ser):
ser.write(binascii.unhexlify('5501010200000059'))
def off(ser):
ser.write(binascii.unhexlify('5501010100000058'))
Для подключения к интерфейсу управления купил первый попавшийся переходник USB-COM. Соединил U с ним стандартным кабелем из комплекта U. О приложении для взаимодействия будет отдельный раздел.
У Raspberry нет микрофонного входа. Поэтому купил первую попавшуюся USB звуковую карту и подключил самым обычным звуковым кабелем.
Честно – я покупал самые дешевые компоненты и ни одна не подвела.
ПРОГРАММНАЯ ЧАСТЬ
Звук.
Чтобы звук можно было слушать удаленно поставил связку icecast2+darkice. Вот весь пакет софта для этого
sudo apt-get -y install sox libsox-fmt-all
sudo apt-get -y install darkice
sudo apt-get -y install alsa-base alsa-utils
sudo apt-get install icecast2
Darkice оцифровывает поток, а icecast организует его потоковое вещание.
Т.е. при такой реализации я могу слушать в локальной сети с помощью winamp например. Или со смартфона. В общем это обычная потоковая трансляция.
Но интересно слушать откуда угодно. Для этого я пробросил порт на WiFi точке доступа, которая смотрит в интернет, к Raspberry и закрыл трансляцию паролем. У меня такой оператор, что он мне дает динамический, но белый IP адрес. У многих моих знакомых оказывается также. Проверяйте у себя.
Т.е. я могу слушать свой U откуда угодно. Как правило, вне дома я делаю это со смартфона.
Если нужна будет информация, как я настраивал, напишите мне в личку. Там все несложно, но жаль времени сейчас выкладывать конфиги.
Управление Uniden.
По идее управлять U необязательно. Можно просто включать и слушать заранее выбранные каналы, но у управления есть следующие преимущества:
1. Возможность удаленно нажимать кнопки
2. Возможность переключения каналов в зависимости от местоположения. Особенно актуально в больших городах, где каналы делятся по географическим секторам
3. Отображение названий текущих каналов при удаленном прослушивании.
4. Запись на локальный диск передач по каналам при их активности
Сразу хочу сказать, что приложение я разрабатывал сам. Я не программист, даже любителем тяжело назвать, но Python за пару месяцев непостоянных вечерних экспериментов понять смог. Передать приложения не смогу, во первых оно не было разработано для его передачи и не запустится просто так, во-вторых оно сильно зависит от окружения. Но я готов рассказать принцип его работы в любых деталях. Покажу примеры кода для реализации.
Я управляю U двумя способами – через бот Telegram, т.к. этот канал доступен из любой точки мира (кроме, России, конечно, но решение вы найдете легко). А локально через Proscan.
Увеличить
Кстати вот тут
ProScan - Страница 4 я уже писал протокол обмена
1. Модуль взаимодействия с U
Можно разрабатывать код для взаимодействия со сканером самим, но ramelito
Форум - Об участнике ramelito (Антон, спасибо тебе большое еще раз) уже сделал все и выложил в общий доступ
https://github.com/ramelito/radcore
Код полностью рабочий. Я просто добавил выгрузку данных из него во вне и обратно через общую очередь.. Очереди/буффер реализаны стандарнтыми queue
from queue import Queue
q_send_to_Proscan = Queue(10)
q_send_to_comport = Queue(10)
Это нужно для того, чтобы данные отсылались по мере поступления и ждали свободного слота для передачи.
В нем уже реализован модуль записи активных передач.
2. Взаимодействие с Proscan.
Протокол обмена с Proscan очень простой.
Proscan подлючается с серверу и шлет команду STARTDAT 00060 PS17,VERSION=7.0,PASSWORD= = ENDDAT
Нам она не важна, просто игнорируем ее
В ответ ему надо отослать
'HTTP/1.0 200 OK\r\n\r\nUser-Agent: ProScan 10.0 \r\n\r\n’
'STARTDAT 00062 PS02,BCD396XT,VERSION=10.0,DLUL=1,AUDIO=2 ENDDAT'
После этого он будет готов принимать команды.
Ramelito реализовал запрос статуса
def get_status(self):
commands = ["GLG", "STS", "VOL", "SQL", "PWR"]
_str = b''
for command in commands:
_str += self.get_data_byte(command)
return bytes(_str)
Вот этот результат и надо постоянно отсылать в Proscan, чтобы он отображал то, что показывает сканер у себя на дисплее
status= get_status()
data = b"STARTDAT 00229 PS30 START\r" + status + b" ENDDAT"
resource.send(data)
Ввод (“виртуальные кнопки”) Proscan высылает вот так:
STARTDAT 00034 PS31 KEY,S,P ENDDAT
Вырезаем “KEY,S,P” и отправляем это в сканер. В данном примере он будет равносильно нажатию кнопки S на сканере.
Т.е. “поднимаем” любой TCP сервер и реализуем вышеприведенную логику.
Свой пример приведу в этом файле.
http://www.radioscanner.ru/uploader/2019/tctpserver.zip
Местоположение.
Для того, чтобы работало переключение каналов/групп по местоположению я записываю его (местоположение) в файл и отправляю в сканер в виде
self.serial.write("$GPRMC,092750.000,A,{},0.02,31.66,280511,,,A*43".format(gps).encode())
координаты должны быть в виде
gps = “3536.1500,N,4739.3700,E”
Я отправляю раз в минуту
Плавно перехожу к управлению через бота Телеграм. У меня есть бот Телеграм которые я использую для своих целей. Как все мы знаем в Телеграме можно передавать свои координаты. Их записываю в тот файл, откуда его берет приложение выше
@bot.message_handler(func=lambda message: True, content_types=['location'])
def default_command(message):
global longitude
global latitude
def coord_change(dd):
mnt, sec = divmod(dd * 3600, 60)
deg, mnt = divmod(mnt, 60)
return "{0:02d}{1:02d}.{2:04d}".format(int(deg), int(mnt), int(sec * 100))
rootLogger.info(message)
latitude = message.location.latitude
longitude = message.location.longitude
save_to_file(config.FILE_GPS, "{},N,{},E".format(coord_change(latitude), coord_change(longitude)))
Далее, если мне надо “нажать кнопку” через Телеграм. Мой бот просто принимает ее и отправляет как будто он Proscan клиент
def send_command_over_IP(c):
try:
conn = socket.socket()
conn.settimeout(TIMEOUT)
logging.info(" send_command_over_IP(c) connect with " + IPADRESS + ":" + str(PORTREMOTE))
conn.connect((IPADRESS, PORTREMOTE))
com = 'KEY,' + c + ',P'
conn.send(str.encode(com))
data = b""
while True:
data = conn.recv(1024)
if data:
if "OK" in str(data):
break
conn.close()
logging.info(" send_command_over_IP - row recieve: " + str(data))
response = data.decode("windows-1251")
if response:
logging.info(" send_command_over_IP: response: " + response)
return response
except socket.error as msg:
logging.info("нет ответ от Proscan - " + str(msg))
return "нет ответ от Proscan - " + str(msg)
Давайте я пока остановлюсь на этой детализации. Как я обещал, готов поделиться любыми подробностями.