如何创建 pyserial Web 服务?

发布于 2024-10-21 07:49:47 字数 5181 浏览 1 评论 0原文

我编写了一个与 /dev/ttyS02 上的串行设备交互的 Web 应用程序。 问题是我当前的消息传递和排队解决方案。请阅读下文。

这是应用程序和pyserial之间的通信桥梁:

  • 我的 Web 应用程序通过 PHP 将请求记录插入到 MySQL 中的 d_requests 表中。 插入记录的已处理列设置为 0。 插入的记录的 id 保存在 $id 变量中,并且 PHP 应用程序输入 循环状态,它将不断检查 d_requests[processed] 列是否 = 1 使用 $id 作为查找参考。

  • 我有一个 python 守护进程服务,它每秒检查一次中的记录 d_requests 表,其中已处理列 = 0。 这被认为是一个新请求。(参考源代码 - python 服务)

  • 然后,python 服务使用记录的信息通过以下方式连接到端口 pyserial。

  • 执行请求的操作。然后记录的已处理列更新为 1 其他一些字段也更新了。 这将记录标记为已处理。

  • 然后 PHP 控制块退出循环(第 1 点)并以 json 形式返回结果 结果

一些注意事项

  • 串行设备每 250 毫秒能够处理 1 个请求。
  • python 守护进程服务监视 d_requests 表以获取已处理的记录 每 1 秒列 = 0。
  • 我的 Web 应用程序与 python 守护进程服务的唯一通信是 MySQL
    DB 通过在 d_requests 表中插入请求记录。
  • 我使用 PHP 块代码每秒使用插入的 id 来查找请求以进行检查 如果已处理列已更新为 1。

我的担忧

单点故障

当守护程序服务未运行时,无法发生串行请求

极端资源使用 strong>

我预计每秒向串行设备发出大约 4-5 个请求。使用当前的实现 为了处理消息,数据库将超时工作,CPU 使用率会很高,因为 PHP 应用程序和 python 守护进程/服务将连接数据库并在数据库上执行查询,并且请求处理会出现延迟。

结论: 有没有更好的方法来改进我当前的消息传递和排队解决方案? 我认为 pyserial Web 服务在这种情况下会很好用,例如串行端口。连接到网络套接字,例如。主机:<7000>我可以通过 PHP 向其发送请求并等待 Web 服务返回的响应。不幸的是我不知道该怎么做。

有什么想法吗?

谢谢

源代码

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)

I have written a web application that interacts with a serial device on /dev/ttyS02.
The problem is my current messaging and queuing solution. Please read below.

Heres the communication bridge between the application and pyserial:

  • My web application inserts a request record via PHP into a d_requests table in MySQL.
    The inserted record's processed column is set to 0.
    The inserted record's id is saved in an $id variable and the PHP application enters a
    loop state where it will continually check if the d_requests[processed] column = 1 using
    the $id as lookup reference.

  • I have a python daemon service that checks every second for records in the
    d_requests table where the processed column = 0.
    This is considered a new request.(refer to source code - python service)

  • The python service then uses the record's information to connect to the port via
    pyserial.

  • The requested action is performed. The record's processed column is then updated to 1
    and a few other fields are updated as well.
    This marks the record as processed.

  • The PHP control block then exits the loop (Point 1.) and returns the result as json
    to the JS application.Where it is presented to the user.

Some points of note

  • The serial device is capable of processing 1 request every 250 ms.
  • The python daemon service monitors the d_requests table for records where the processed
    column = 0 every 1 second.
  • The only communication my web application has with the python daemon service is the MySQL
    DB by inserting requests records in the d_requests table.
  • I use PHP block code to lookup the request using the inserted id every second to check
    if the processed column has been updated to 1.

My Concerns

Single point of failure

When the daemon service is not running serial requests cannot take place

Extreme Resource Usage

I expect about 4-5 requests per second to a serial device. Using the current implementation
for handling messages the db will be working overtime and CPU usage will be high, since the PHP application and python daemon/service will connect and perform queries on the DB and there will be delays with the processing of requests.

Conclusion :
Is there a better way to improve my current messaging and queuing solution?
I think a pyserial web service will work great in this case, where the serial port for eg. is attached to a web socket eg. host:<7000> and I can just send a request via PHP to it and wait for the response back from the web service. Unfortunately I dont know how to do this.

Any ideas?

Thank You

Source code

python service

    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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

把梦留给海 2024-10-28 07:49:47

是否有更好的方法来改进我当前的消息传递和排队解决方案?

你打赌!它们被称为消息队列,它们非常棒。

我最喜欢的是 Gearman,它是由为我们带来 memcached 的同一团队编写的。它有 PHPPython 绑定。与其说它实际上是一个消息队列,不如说它是一个 RPC 服务。无论如何,它允许您从一个环境调用方法并在另一个环境中处理它们。

在这种情况下,您需要用 Python 编写串行接口代码,并让它以 Gearman 函数的形式公开它可以执行的所有操作。它将作为守护进程打开。您的 PHP 代码可以通过 Gearman 调用这些函数。

Is there a better way to improve my current messaging and queuing solution?

You bet! They're called message queues, and they are awesome.

My favorite is Gearman, written by the the same team that brought us memcached. It has PHP and Python bindings. It's not actually a message queue so much as an RPC service. Regardless, it will let you call methods from one of your environments and handle them in the other.

In this case, you'd want to write your serial interface code in Python, and have it expose all the things it can do as Gearman functions. It will sit open as a daemon. Your PHP code can call those functions through Gearman.

尘曦 2024-10-28 07:49:47

研究类似的需求。到目前为止发现“ser2net”和“termnetd”守护进程很有帮助。

Researching similar need. Found "ser2net" and "termnetd" daemons helpful so far.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文