我已经在Raspberry Pi上编写了一个python脚本,用于控制大型且有些复杂的硬件。当前,使用界面是python控制台。我运行python程序,并且可以使用input("> ")
从控制台输入命令。
现在,我想向该程序添加Web界面,而我正在尝试找出正确的方法。我已经在Flask中编写了一个基本的Web UI,但是还没有找到一种将Flask接口与主脚本连接的好方法。因为服务器控制单个硬件,所以主对象(处理硬件控件)仅被实例化一次。此外,每次脚本运行(每次创建主对象)都必须进行重要的硬件配置。
Flask似乎为每个客户端会话创建了一个新线程,并且仅在该会话中持久存储变量。如何将烧瓶事件(即Web用户按下按钮)链接到主要对象中的方法?
我使用的工具错误吗?什么是正确的工具? 正确的操作方式是什么?或者,什么是垃圾邮件方式做到这一点?
编辑:链接的问题很相似,使我走到了下面的答案,但实际上并没有回答问题,以至于指向一些代码解决了那个具体的例子。我认为下面的答案会更有帮助。(当然,我有点偏见;我写了它)
我找到了解决方案,所以在这里分享。 (我想我不能回答自己的问题?)
Flask Web App系统(以及所有WSGI Web应用程序?)基于以下原理:可以在全新的环境中执行Web应用程序,而无需在创建时传递对象。我想这对 Web Apps 有意义,但是它为 Web UI 增添了很多烦人的复杂性,也就是说,Web接口旨在用于连接较大的单个实例程序。作为硬件/解决方案工程师,我倾向于需要一个Web UI来控制单个硬件。如果有比烧瓶更好的东西,请请发表评论。但是flask很不错,我现在知道可以将其用于此目的。
Flask Web Apps并非旨在自己进行“繁重的工作”。它们保持非常有限的状态(即,每个请求都触发一个新的上下文),并且如上所述,不能将对其他对象的引用传递给它。在适当的 Web App 中,全栈开发人员会将Flask连接到数据库服务器和其他此类WebDev-y系统。对于控制硬件,我们的目标是触发另一个python进程(可能是单独执行的进程)中某些任意方法的执行。
在python中,实现此执行的便捷方法是multiprocessing.managers
模块。 Managers是一种工具,可让您轻松构造Proxies,该链接将跨过程的对象链接在一起。如果您有对象bar = Bar()
,则可以生成一个<AutoProxy[get_bar]>
代理,该代理使您可以在远处操纵原始bar
对象。可能在子进程中,也可能在互联网上的另一台计算机上。这是一个例子。
server.py:
import multiprocessing.managers as m
import logging
logger = logging.getLogger()
class Bar: #First we setup a dummy class for this example.
def __init__(self):
self.text = ""
def read(self):
return str(self.text)
def write(self, string):
self.text = str(string)
logger.error("Wrote!")
logger.error(string)
bar = Bar() #On the server side we create an instance: this is the object we want to share to other processes.
m.BaseManager.register('get_bar', callable=lambda:bar) #then we register a 'get' function in the manager,
# to retrieve our object from afar. the lambda:bar is just shorthand for a function that returns the bar object.
manager = m.BaseManager(address=('', 50000), authkey=b'abc') #Then we setup the server on port 50000, with a password.
server = manager.get_server()
server.serve_forever() #Then we start the server!
client.py:
import multiprocessing.managers as m
import logging
logger = logging.getLogger()
m.BaseManager.register('get_bar') #We register this so that the Manager knows it's a valid method
manager = m.BaseManager(address=('', 50000), authkey=b'abc') #Then we setup the server connection
manager.connect() #and connect!
bar = manager.get_bar() # now we can use our 'get' method to retrieve a Proxy of the object.
所以这里有一些有趣的事情要注意。首先,我们可以从任意数量的客户端获取get_bar(),它们都将指向相同的bar
。其次,我们可以从客户端调用bar,read()和write()中的方法,而无需手握Bar
类。很整齐。
那么如何使用呢?如果您具有启用了控制台的程序,请首先将其分为两部分,即控制台及其控制的功能。将该功能包装在少数几个组成应用程序实例的对象中。修改上面的server.py
以实例化这些对象,并在Manager中使用get
方法将其托管。然后调整您的控制台界面,使其像client.py
一样连接,并使用代理代替实际的对象。最后,设置一个烧瓶应用程序,该应用程序也连接到服务器并提供Web界面。
现在您是一个真正的Web开发人员! RIP。