Я написал веб-приложение, которое взаимодействует с последовательным устройством на /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)