- Работа с ком портом питоне
- Доступ к портам с использованием WinApi и dll из Python
- или взлет на рожденном ползать
- Библиотека pyserial
- Введение
- Примеры
- Инициализировать последовательное устройство
- Читать из последовательного порта
- Проверьте, какие последовательные порты доступны на вашем компьютере
- Синтаксис
- Параметры
- Примечания
- Модуль heapq
- Перенаправление данных из COM-порта в Web
Работа с ком портом питоне
Продолжаю осваивать питон
Накропал скрипт для лога данных с сенсора в БД
Железка определяется как
Из неприятных минусов — железка перезагружается. Помогите побороть эту бяку.
Когда работает эта программа то перезагружается, а если просто minicom натравить — то не перезагружается?
Где-то эти прекрасные макароны:
и этот тред я уже видел.
а китайская хитрая железяка. перезагружается
Я думаю, что проблема где-то тут. На неё документация есть? Софт с ней какой идёт? Попробуй реверсни и посмотри как с ней работают.
Железка -суровый китайский самопал. Документации нет, софта нет. Населена роботами. Вот она если что. mysku.ru/blog/taobao/40456.html Ребут идет именно по запуску скрипта. Гугл показывает аналогичную проблему с ардуиной, но там хардварное решение -тупо воткнуть конденсатор между пинами
начни с устранения причин перезагрузки.
скорость работы устройство действительно 9600?
вообще если какой тулой вообще посмотреть чё с порта приходит — на какой скорости?
может твой скрипт ненароком просто вычитывает тоны не формата — чисто для себя попробуй посмотреть чё в s = ser.readline() приходит и печатай для себя.
Чтение никак не должно влиять на работу железки. Может у тебя там коротит чего? Питание проверяй. Попробуй конденсатор микрофарад на 100 воткнуть между плюсом и минусом питания, если в железке нет такого. Можно больше.
long — в моём питоне такого нет.
Я бы так написал:
Попробуй выяснить, после какого вызова происходит ресет.
У меня он происходил про открытии порта.
Я не спец по железкам. Но она выдает в csv данные. В виде строки данных через запятую.
По крайней мере я так понял. Если можешь подскажи чем и как посмотреть чем плюется железка.
Я в ардуинке тоже сталкивался. Судя по всему оно на ser.open() ресетится.
Ты уже проверил что с программами типа minicom всё нормально работает и не резетится? И лишь только с твоей программой так.
А если чего-нибудь туда послать, тоже ресетится?
крч у питона же интерактивная среда есть
если вручную подключаешься то всё видимо ок?
попробуй ну просто счётчик числа прочитаных строк воткнуть и посмотреть после скольки рвёться соединение например.
(в порядке мозгового шторма)может вообще там у железки после некоторого обьёма ответа какие буферы сыпятся вот и ресетиться — али ещё какие глюки с «таймингами» и действительно попробуй какой «обычной»(т.е обще используемой в таковых задачах) тулзой посмотреть программно свою железку «по разговарий» с ней может до чего и уговоришь
Проверил. оно ресетится на всем что пробовал: CuteCOM, SerialPlot
Проверил — ресетится оно по открытию порта.
Самый неприятный открытый момент — при чтении порта он сначала отдает кривые данные.
Соответсвенно вижу 2 варианта.
1. бесконечный цикл чтения данных и отбор нужных 2. вызов таки по крону, фильтрация медианой пачки считанных данных.
Сейчас пытаюсь сделать регистрацию на qq (китайский месенджер) чтоб достать продавца
после скольки рвёться соединение например
tsya.ru (я не придираюсь, просто этот сайт поможет)
А железяка дороговата. 157 баксов за такое — перебор если по мне.
А найди аналоги дешевле.
Самому спаять. Там в принципе ничего сложного.
в принципе да, но я вон уже пару дней мучаюсь с тупым подключением готовой железки к компу.
Короче, сделал я чтоб не перезапускался. правда велосипед еще тот.
Скрипт запустил в бесконечный цикл чтения т.е. открытие порта происходит всего 1 раз. а чтобы оно постоянно висело, запустил его через supervisor
Из неприятных минусов — железка перезагружается.
ну так правильно, ты же подключаешся, у меня ардуино так же себя ведет
правильно-неправильно. но мне такое поведение вредно.
Доступ к портам с использованием WinApi и dll из Python
или взлет на рожденном ползать
Предыдущие реализации на Питоне аналога проприетарного софта, оказались вполне ничего себе, т. е. все работает, и все похоже на Excel, а значит endusers будут довольны-). Дальнейший простор для полета фантазии немного сдерживается невозможностью доступа к более детальным настройкам портов из стандартных модулей. Но оказывается в Питоне есть такая изумительная вещь как доступ к WinApi функциям, что расширяет перспективы чуть ли не до Cpp-шных. Причем это касается не только портов, а еще кучи всяких вещей. Список и краткое описание поддерживаемых WinApi функций для Питона здесь-
docs.activestate.com/activepython/3.3/pywin32/win32file.html, прорва примеров на Nullege здесь — nullege.com/codes/search/win32file и здесь www.programcreek.com/python/index/1133/win32file, ну и как это принято в Питоне избавление от несовершенства модулей — доступ к WinApi функциям, осуществляется через модуль-) — win32file,- соответственно — pip install win32file.
Вот например как может выглядеть настройка и работа Com порта —
сначала понятно импортируем модуль:
import win32file
hFile = win32file.CreateFile(«COM2», win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0,None,win32file.OPEN_EXISTING, 0,None)
тут разница в названиях — стандартным предшествует ‘win32file.’, и вместо NULL – None
(в названии порта кавычки верхние см. рис. и комменты).
Далее аналогично стандартным процедурам, например в Visual Studo — структура настройки — создаем:
comDCB = win32file.DCB()
comDCB.ByteSize = 8
comDCB.Parity = win32file.NOPARITY
comDCB.StopBits = win32file.ONESTOPBIT
comDCB.BaudRate = 9600
записываем:
win32file.SetCommState(hFile,comDCB)
рамер входного/выходного буфера:
win32file.SetupComm(hFile, 4096, 4096)
вот например маска(1) по приему первого байта, то чего нет в стандартном модуле pyserial:
win32file.SetCommMask(hFile, 1)
win32file.WaitCommEvent(hFile, None)
ну и чтение и запись-
buff=’пишем чего-нибудь-)’
не забываем, что передаем поток байт — переконвертируем строку в массив байт:
ttt=bytearray(buff, encoding=’cp1251′)
win32file.WriteFile(hFile,ttt,None)
ждем эвента по приему первого байта и читаем 19 байт:
win32file.WaitCommEvent(hFile, None)
win32file.ReadFile(hFile, 19)
ну и закрыть:
win32file.CloseHandle(hFile)
C LPT все немного по-другому, хотя и можно создать хэндл как показано выше — запись и чтение в файл повидимому приведет к обращению к стандартному драйверу и невозможности записи без получения ‘ASK’ от ‘принтера’. Поэтому, как мне кажется, более удобное — широко известное решение — inpout32.dll.
Для возни с параллельным портом я использую следующий гипердевайс-
по мотивам того, который был представлен на pcports — www.kernelchip.ru/pcports/PS005.php Повторять мне было лень, я сделал проще — задействованы два регистра из трех — чтения нет(регистр Status не задействован). Питание светодиодов счетверенного семисегментного индикатора от высокого состояния одного порта и низкого состояния другого. Такая схема дает возможность использовать динамическую индикацию и оценить быстродействие разных способов вывода через порт, но… не будем забегать вперед-) Итак, пока просто выведем циферку скажем ‘7’ на второй индикатор:
from ctypes import windll
p = windll.LoadLibrary(«C:\Python34\DLLs\inpout32.dll»)
p.Out32(890, 9)
p.Out32(888, 241)
(в названии пути кавычки верхние см. рис. и комменты)
функция возвращает 1 — типа все нормально-)
тут только одно тонкое место, часть выводов в регистре ‘Control’ инвертирована — ru.wikipedia.org/wiki/Параллельный_порт и это надо учитывать.
Ну и в заключение небольшой сравнительный тест результаты которого меня просто поразили. Две аналогичные программы — на старом VC6 и на Python — функционально это динамическая индикация через LPT порт. В VC6 в обработчике таймера производится пересчет(преобразование) числа в первом окошке в семисегментный код, во втором окне — задается время переключения (таймера). Запуск преобразования кнопка ‘Start indicate’, остановка — ‘Stop’.
Библиотека pyserial
Введение
Примеры
Инициализировать последовательное устройство
Читать из последовательного порта
Инициализировать последовательное устройство
читать один байт с последовательного устройства
читать заданное количество байтов из последовательного устройства
прочитать одну строку из последовательного устройства.
читать данные с последовательного устройства, пока что-то записывается поверх него.
Проверьте, какие последовательные порты доступны на вашем компьютере
Чтобы получить список доступных последовательных портов, используйте
в командной строке или
из оболочки Python.
Синтаксис
Параметры
Примечания
Научим основам Python и Data Science на практике
Это не обычный теоритический курс, а онлайн-тренажер, с практикой на примерах рабочих задач, в котором вы можете учиться в любое удобное время 24/7. Вы получите реальный опыт, разрабатывая качественный код и анализируя реальные данные.
Модуль heapq
Введение Примеры Самые большие и маленькие предметы в коллекции Для того, чтобы найти самые большие предметы в коллекции, heapq модуль имеет функцию под названием nlargest , мы передаем его два аргумента, то первый из
Перенаправление данных из COM-порта в Web
Недавно на хабре была статья «Отображаем данные из Serial в Chrome Application» о том, как красиво представить данные, отправляемые Arduin-кой в Serial. По-моему, ребята предложили очень красивое решение, которое с одной стороны выглядит достаточно простым, а с другой позволяет получить прекрасный результат с минимумом усилий.
В комментариях к статье было высказано сожаление о том, что такое решение не заработает под Firefox-ом и высказана идея, что «можно еще написать простенький веб-сервер с выдачей html на основе этой штуки». Меня эта идея «зацепила», быстрый поиск в google готового решения не выдал, и я решил реализовать идею сам. И вот, что из этого вышло.
Предупреждение! Предлагаемое решение ни в коем случае нельзя рассматривать как законченное. В отличие от Serial Projector от Амперки — это концепт, демонстрация возможного подхода, работающий прототип и не более того.
Некоторое время назад я делал проект, в котором использовал встроенные в Android-смартфон акселерометры для управления сервами, подключёнными к Arduino. Тогда для этих целей я воспользовался проектами Scripting Layer for Android (SL4A) и RemoteSensors. Оказывается, в стандартную библиотеку python-а входит пакет BaseHTTPServer, с помощью которого поднять веб-сервис на питоне — это задача на пару строчек кода.
Под рукой не было никаких датчиков для Arduino, поэтому в качестве источника отображаемой информации я воспользовался встроенным в Arduino Uno внутренним термометром. Насколько я понимаю, он не очень точный и совсем не предназначен для измерения температуры окружающей среды, но для прототипирования вполне сойдёт.
После недолгого гугления возник вот такой скетч для ардуинки:
Этот скетч открывает COM-порт, настраивает его на скорость 115200 бод и затем каждую секунду пишет в него текущее значение встроенного термометра. (Не спрашивайте меня, в каких единицах выдаётся температура — для описываемой задачи это не важно). Поскольку значение меняется не очень активно, для лучшей видимости изменения данных перед температурой выводится номер строки.
Для проверки того, что веб-сервер будет отдавать наружу только целые строки, а не их части по мере чтения из COM-порта, строка
была заменена на
т.е. сформированная строка выводится в последовательный порт не целиком, а посимвольно, с паузами в 200 мс.
Для начала был написан совсем простенький прототип веб-сервера (ниже он разобран по частям):
Разберём скрипт по частям.
Поскольку это прототип, то все основные параметры работы (имя COM-порта, его скорость, а также номер TCP-порта, на котором будет работать веб-сервер) указаны прямо в исходном тексте:
Разумеется, можно организовать чтение этих параметров из командной строки. Например, с помощью модуля argparse это делается очень быстро, просто и гибко.
В данном же случае пользователям Windows надо в диспетчере устройств узнать имя COM-порта, к которому подключена Arduin-ка. У меня это был ‘COM6’. Пользователям других операционок надо использовать средства своих ОС. У меня совсем нет опыта работы с MacOS и в Linux-е я с COM-портами тоже не работал, но там, скорее всего, это будет что-нибудь типа «/dev/ttySn».
Далее идёт определение глобальной переменной, к которой будет привязан экземпляр класса Serial, отвечающего в питоне за работу с COM-портом:
создаётся веб-сервер, который будет слушать запросы на заданном порту WEB_SERVER_PORT. А обрабатывать эти запросы будет экземпляр класса Handler, описанный ниже.
Следующие строки — это небольшой «хак», позволяющий вывести IP-адрес, на котором собственно работает запущенный веб-сервер:
Насколько я понял, не существует иного способа узнать этот IP. А как без этого знания мы будем обращаться из браузера к нашему серверу?
Поэтому приходится открывать сокет и подключаться к сайту гугла, чтобы из атрибутов уже этого сокета извлечь информацию о собственном IP-адресе.
Чуть ниже происходит открытие COM-порта и собственно запуск веб-сервера:
Затем следует описание класса, который отвечает за обработку полученных запущенным веб-сервером запросов:
Это наследник встроенного в модуль BaseHTTPServer класса, в котором достаточно переопределить только метод do_GET
Поскольку, это ещё пока прототип, то сервер будет «рад» любому запросу — какой бы URL у него не запросили, он будет отдавать клиенту все данные читаемые из COM-порта. Поэтому в Handler.do_GET он сразу отвечает кодом успеха и нужными заголовками:
после чего запускается бесконечный цикл, в котором происходит попытка чтения целой строчки из COM-порта и, если эта попытка оказалась успешной, передача её веб-клиенту:
В проекте, который был взят за основу, этот бесконечный цикл был «завёрнут» в блок try … except, с помощью которого предполагалось аккуратно обрабатывать разрыв соединения. Возможно, в Android-е (базовый проект разрабатывался под него) это и работает нормально, но у меня под Windows XP так не вышло — при разрыве соединения возникало какое-то другое исключение, которое я так и не научился перехватывать. Но, к счастью, это не мешало веб-серверу работать нормально и принимать следующие запросы.
Функция получения целой строки из COM-порта работает по тому же принципу, что и у создателей Serial Projector:
- есть некоторый глобальный буфер, в котором хранится всё, что прочитано из COM-порта
- при каждом обращении к функции она пытается прочитать что-нибудь из COM-порта
- если ей это удаётся, то
- она добавляет только что прочитанное к указанному глобальному буферу
- пытается поделить глобальный буфер максимум на две части символом конца строки
- если и это ей удаётся, то первую часть она возвращает в вызвавшую процедуру, а вторую часть использует в качестве нового значения глобального буфера
- если в COM-порту нет новых данных или не найден символ конца строки, то функция возвращает None:
В результате получилось так:
Видно, что в браузере появляются строчки, читаемые из COM-порта. Я ничего не понимаю в веб-фронтенде: JavaScript, Ajax, CSS и DOM — это для меня тёмный лес. Но мне кажется, что для программистов, создающих веб-интерфейсы, этого должно быть вполне достаточно, чтобы преобразовать этот вывод в такую же красивую картинку, что выдаёт Serial Projector от Амперки. По-моему, задача сводится к тому, чтобы создать javascript-сценарий, который обращается к веб-серверу, читает из него поток и последнюю прочитанную строчку выводит в нужное место веб-страницы.
На всякий случай я решил подстраховаться и попытался сделать первое приближение своими силами. Не очень глубокий поиск в гугле подсказал, что вообще-то для таких целей, по крайней мере, раньше использовали WebSockets или Server-Sent Events. Я нашел, как мне показалось, неплохой учебник по использованию Server-Sent Events и решил использовать эту технологию.
Примечание! Похоже, это не самое лучшее решение, потому что эта технология не заработала ни в Internet Explorer 8, ни в браузере, встроенном в Android 2.3.5. Но она заработала хотя бы в Firefox 39.0, поэтому я не стал «копать» дальше.
Почитав указанный учебник, а также ещё один на русском языке, я взял за основу проект simpl.info/eventsource.
С точки зрения питоновского скрипта изменения под Server-Sent Events совершенно незначительные:
- надо заменить тип отдаваемых клиенту данных:
строчку
а также перед прочитанной из COM-порта строчкой вставить префикс «data: » и добавить ещё один символ перевода строки:
строки
Всё остальное могло бы, наверное, остаться без изменений, но…
Сперва я создал файл index.html вот такого содержания:
Самые интересные в нём — это строка
которая формирует место для вывода очередной строчки из COM-порта, и javascript-сценарий
который собственно и занимается чтением потока из веб-сервера и выводом прочитанной информации в указанное место.
Я предполагал открывать этот файл в браузере, например, с диска или с какого-нибудь другого веб-сервера, но это не сработало: при открытии страницы с диска javascript-сценарий однократно обращался к запущенному питоновскому веб-серверу и тут же разрывал соединение. Я не понял, почему так происходит, и предположил, что это, возможно, какое-то проявление защиты браузера от различных атак. Наверное, ему не нравится, что сама страница открыта с одного источника, а сценарий считывает данные из другого источника.
Поэтому было принято решение поменять питоновский веб-сервер так, чтобы он отдавал и эту html-страницу. Тогда бы получилось, что и страница, и поток считываются из одного источника. Не знаю, то ли моё предположение насчёт безопасности оказалось верным, то ли ещё что, но при такой реализации всё заработало как надо.
Поменять, разумеется, надо только класс-обработчик запросов Handler:
В данном варианте предполагается, что веб-сервер будет отвечать только на два запроса: ‘/index.html’ (отдавая html-код страницы) и ‘/get_serial’ (отдавая бесконечный поток строк, считываемых из COM-порта). На все остальные запросы он будет отвечать кодом 404.
Поскольку index.html отдаётся питоновским веб-сервером, то его можно слегка изменить, указав вместо абсолютного адреса потока строк из COM-порта относительный:
строку
В итоге получилось вот так:
На этом я решил остановиться. Как мне кажется, оформить страницу красиво — это уже должно быть совсем просто. Но я не владею ни HTML, ни CSS, поэтому пусть это сделает кто-нибудь другой. Я видел свою задачу в том, чтобы показать, что сделать веб-сервис, отдающий данные из COM-порта, вроде бы, совсем не сложно.
Все исходники можно взять на гитхабе.
Ещё раз повторюсь: представленный код — это не законченное решение, которое можно «пускать в продакшен». Это только прототип, который показывает принципиальный подход к решению задачи.
Над чем тут ещё можно поработать:
- во-первых, чтение данных из COM-порта в питоновском скрипте сделано очень «топорно» — по сути дела происходит постоянный поллинг «а нет ли чего свеженького?». Такой подход, разумеется, нагружает процессор и одно ядро на моём компьютере занято на 100%.
В качестве решения можно использовать блокирующее чтение с таймаутом. Для этого достаточно при открытии COM-порта качестве таймаута указать ненулевое значение (в секундах), например: