Как я могу создать pyserial веб-сервис? - PullRequest
0 голосов
/ 11 марта 2011

Я написал веб-приложение, которое взаимодействует с последовательным устройством на / dev / ttyS02. Проблема в моем текущем решении для обмена сообщениями и очередей. Пожалуйста, прочитайте ниже.

Вот мост связи между приложением и pyserial:

  • Мое веб-приложение вставляет запись запроса через PHP в таблицу d_requests в MySQL. Обработанный столбец вставленной записи имеет значение 0. Идентификатор вставленной записи сохраняется в переменной $ id, и приложение PHP вводит состояние цикла, где он будет постоянно проверять, если столбец d_requests [обработано] = 1, используя $ id в качестве справочной информации.

  • У меня есть служба демона python, которая каждую секунду проверяет записи в Таблица d_requests, где обработанный столбец = 0. Это считается новым запросом. (см. Исходный код - служба python)

  • Служба python затем использует информацию записи для подключения к порту через pyserial.

  • Запрошенное действие выполнено. Обработанный столбец записи затем обновляется до 1 и несколько других полей также обновляются. Это помечает запись как обработанную.

  • Блок управления PHP затем выходит из цикла (точка 1.) и возвращает результат в виде json в приложение JS. Где оно представлено пользователю.

Некоторые заметки

  • Последовательное устройство способно обрабатывать 1 запрос каждые 250 мс.
  • Служба демона python контролирует таблицу d_requests для записей, где обработано столбец = 0 каждые 1 секунду.
  • Единственное соединение, которое мое веб-приложение имеет со службой демона python, - это MySQL
    БД путем вставки записей запросов в таблицу d_requests.
  • Я использую блочный код PHP для поиска запроса, используя каждую секунду вставленный идентификатор для проверки если обработанный столбец обновлен до 1.

Мои проблемы

Одна точка отказа

Когда служба демона не работает, последовательные запросы не могут выполняться

Чрезвычайное использование ресурсов

Я ожидаю около 4-5 запросов в секунду к последовательному устройству. Используя текущую реализацию для обработки сообщений БД будет работать сверхурочно, а загрузка ЦП будет высокой, так как приложение PHP и демон / служба python будут подключаться и выполнять запросы к БД, и будут задержки с обработкой запросов.

Вывод: Есть ли лучший способ улучшить мое текущее решение для обмена сообщениями и очередей? Я думаю, что веб-сервис pyserial будет отлично работать в этом случае, когда, например, последовательный порт. подключен к веб-сокету, например. host: <7000> и я могу просто отправить ему запрос через PHP и дождаться ответа от веб-службы. К сожалению, я не знаю, как это сделать.

Есть идеи?

Спасибо

Исходный код

служба Python

    import sys, time
    from daemon import Daemon
    import MySQLdb 

#Database parameters
config = {"host":"localhost","username":"root","password":"cake","database":"mydb"}

#Check if MySQLdb library is present
try:
    conn = MySQLdb.connect(config['host'],config['username'],config['password'],config['database'])
except MySQLdb.Error, e:
    print "Error %d: %s" % (e.args[o], e.args[1])
    sys.exit(1);

#Check if pyserial library is present
try:
    import serial
except ImportError:
    print "Error,pySerial module not installed"
    sys.exit(1);

#Create DB cursor  
#cursor = conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
#Declare global variables here
class MyDaemon(Daemon): 
    def run(self):
        while True:
            time.sleep(2)
            cursor = conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
            data = ''
            try:
                cursor.execute ("""SELECT * FROM d_requests where processed = 0""")
                rows=cursor.fetchall()
                print "Waiting for requests..."
            except MySQLdb.Error as detail:
                print "MySQL Error,",detail
            if len(rows) == 0:
                cursor.close()
                print "No request found..."
                continue
            for row in rows:
                try:                
                    print "Processing request..."                   
                    ser = serial.Serial(port=row['port'],
                    baudrate = row['baud'],
                    bytesize = row['bytesize'], #8
                    parity = row['parity'], #serial.PARITY_NONE or N or C
                    stopbits = row['stopbits'], #1
                    timeout = row['wait_for_reply'], #0.5
                    xonxoff = row['sw_flowcontrol'], #0
                    rtscts = row['hw_flowcontrol']) #0                  
                    #Send command to device
                    ser.write(row['request_string'] + "\r")
                    #Read device response                   
                    data = ser.read(100)#TBD:This value needs to be changeable,not always 100 bytes
                    ser.close()
                    print "RESULT : " + data                    
                except (serial.SerialException, AttributeError, NameError) as detail:
                    data = "Error, could not open port"
                    print data                  
                except serial.SerialTimeoutException as detail:
                    data = "Error, port connection timeout" #Error ,detail
                    print data
                except:
                    data = "Error,Unexpected error"
                    print data              
                finally:
                    #ser.close()
                    try:
                        cursor.execute("""UPDATE d_requests SET processed = %s, result_string = %s WHERE id = %s""",(1,data,row['id']))
                    except MySQLdb.Error as detail:
                        print "MySQL Error,",detail
                #cursor.commit() for innoDB table engines
            cursor.close()
if __name__ == "__main__":
    daemon = MyDaemon('/tmp/daemon-example.pid')
    if len(sys.argv) == 2:
        if 'start' == sys.argv[1]:
            daemon.start()          
        elif 'stop' == sys.argv[1]:
            daemon.stop()
        elif 'restart' == sys.argv[1]:
            daemon.restart()
        elif 'foreground' == sys.argv[1]: #this runs the daemon in the foreground
            daemon.run()
        else:
            print "Unknown command"
            sys.exit(2)
        sys.exit(0)
    else:
        print "usage: %s start|stop|restart" % sys.argv[0]
        sys.exit(2)

Ответы [ 2 ]

1 голос
/ 11 марта 2011

Есть ли лучший способ улучшить мое текущее решение для обмена сообщениями и очередей?

Вы держите пари! Их называют очередями сообщений, и они потрясающие.

Мой фаворит - Gearman , написанный той же командой, которая принесла нам memcached. Имеет привязки PHP и Python . На самом деле это не очередь сообщений, а скорее служба RPC. В любом случае, это позволит вам вызывать методы из одной из ваших сред и обрабатывать их в другой.

В этом случае вы захотите написать свой код последовательного интерфейса на Python и предоставить ему все, что он может делать в качестве функций Gearman. Он будет открыт как демон. Ваш PHP-код может вызывать эти функции через Gearman.

0 голосов
/ 25 августа 2011

Исследование аналогичной необходимости.Насколько полезны демоны "ser2net" и "termnetd".

...