Как я могу создать веб-сервис pyserial?

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

Вот коммуникационный мост между приложением и pyserial:

  • Мое веб-приложение вставляет запись запроса через PHP в таблицу d_requests в MySQL. Обработанный столбец вставленной записи имеет значение 0. Идентификатор вставленной записи сохраняется в переменной $id, и приложение PHP переходит в состояние цикла, в котором оно будет постоянно проверять, равен ли столбец d_requests[processed] 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)

person Chesneycar    schedule 10.03.2011    source источник
comment
вы пробовали смотреть на node.js, у него очень быстрая система циклов, управляемая событиями, которая может обрабатывать множество подобных вещей.   -  person RobertPitt    schedule 11.03.2011


Ответы (2)


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

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

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

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

person Charles    schedule 11.03.2011
comment
Спасибо Чарльз за ваш ответ. Я посмотрю на Gearman. @RobertPitt не уверен, что node.js будет работать для моих целей, так как мне все еще нужно общаться с python (pyserial) и php. - person Chesneycar; 11.03.2011

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

person FYA    schedule 25.08.2011