我正在使用Pyserial从比例尺获得输出。因此,我决定将所有输出读取到Kivy Label,以使程序更易于使用。最初,最小的示例足够好,用户只需单击一个按钮即可以20个计数器间隔查看输出。但是现在有必要通过首先接收输出,然后触发一个辅助事件来自动化整个过程,该事件在更新Sqlite数据库之前将检查输出是否稳定。但是发生了一个问题:1]标签不会随着刻度输出的变化而更新。这源于serial.readline()
方法,由于某种原因它也不会更新。我的一些Python代码:
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty, ObjectProperty,BooleanProperty,NumericProperty
from kivy.clock import Clock
from kivy.core.window import Window
import serial, re, time, string, random
import plyer
Builder.load_string("""
#:set cereal None
<CerealOutput>:
Label:
text: root.portname
pos_hint: {'top': 0.79, 'right': 0.8}
size_hint: [0.6, 0.19]
color: (1,1,1,1)
Label:
id: milk
text: root.scale_output if root.scale_output != "" else "Scale Output"
pos_hint: {'top': 0.6, 'right': 0.8}
size_hint: [0.6, 0.2]
color: (1,1,1,1)
canvas.before:
Color:
rgb: (0.43, 0.43, 0.43, 1)
Rectangle:
pos: self.pos
size: self.size
Button:
text: "Exit"
pos_hint: {'top': 0.2, 'right': 0.98}
size_hint: [0.17, 0.18]
on_release: root.weigh_tick.cancel() if root.weigh_tick != None else ""
Button:
text: "Get Serial"
pos_hint: {'top': 0.3, 'right': 0.8}
size_hint: [0.6, 0.2]
on_press:
cereal = root.ccereal
root.GetCereal() if cereal == None or cereal.isOpen() == False else root.weight_ticker()
""")
class CerealOutput(FloatLayout):
portname = StringProperty('')
the = ObjectProperty(None) # App object
ccereal = ObjectProperty(None)
mythread = ObjectProperty(None)
bowl = ObjectProperty(None)
go = BooleanProperty(True)
weigh_tick = ObjectProperty(None)
weigh_tme = NumericProperty() # Weigh time numerical
scale_output = StringProperty('')
is_shift = BooleanProperty(False)
def __init__(self, **kwargs):
super(CerealOutput, self).__init__(**kwargs)
self.the = App.get_running_app()
self.bowl = self.ids.milk
def GetCereal(self):
ser = serial.Serial(port='/dev/ttyUSB0',baudrate=9600,bytesize=serial.EIGHTBITS)
self.ccereal = ser
if self.ccereal.isOpen():
self.portname = self.ccereal.name
else:
self.ccereal.open()
self.portname = self.ccereal.name
self.weight_ticker()
def GetOutput(self, cereal):
if cereal.isOpen() and cereal != None:
if self.weigh_tme > 0:
try:
bb = cereal.readline()
t = ''.join(random.choice(string.ascii_letters) for x in range(5))
self.scale_output = re.sub('[GSTUkg,\s]', '', bb.decode('latin-1'))
#Q only gets text after each read is finished. Why?
#S Threading; Interval read; Other
#UI imbed visible progress on each read
#Errors, Test if port exists, Unicode byte read error: How to solve
print(self.scale_output, bb, t)
self.weigh_tick()
self.weigh_tme -= 1
except serial.SerialException:
self.weigh_tme = 0
print("Port not open")
else:
self.weigh_tick.cancel() # cancel event
print("Finished")
else:
self.GetCereal()
def weight_ticker(self):
self.weigh_tme = 1000
self.weigh_tick = Clock.create_trigger(lambda dt: self.GetOutput(self.ccereal), 1)
self.weigh_tick()
class PorridgeApp(App):
def build(self):
return CerealOutput()
def on_stop(self):
if App.get_running_app().root.ccereal != None:
App.get_running_app().root.ccereal.close()
def on_pause(self):
if App.get_running_app().root.ccereal != None:
App.get_running_app().root.ccereal.close()
pass
if __name__=='__main__':
PorridgeApp().run()
我已经尝试将输出绑定到Label对象的文本。那并没有改变。
有人可以告诉我为什么readline
方法没有随着刻度输出的变化而更新吗?
因此,我决定将解决方案发布到更新的GetOutput
函数中。解决方法是使用PySerial
方法内置的serial.reset_input_buffer()
重置输入缓冲区。从文档中:
刷新输入缓冲区,丢弃其所有内容。在版本3.0中更改:从flushInput()重命名
代码:
def GetOutput(self):
if self.ccereal.isOpen() and self.ccereal != None:
if self.weigh_tme > 0:
try:
self.stable = self.ccereal.readline().decode('latin-1')[:2]
self.scale_output = re.sub('[GSTUkg,\s]', '',self.ccereal.readline().decode('latin-1'))
self.ccereal.reset_input_buffer() #flush the input buffer
self.weigh_tme -= 1
self.weigh_tick()
except serial.SerialException as e:
self.weigh_tme = 0
print("Port not open","Unicode errror")
except TypeError as e:
self.ccereal.close()
except UnicodeDecodeError as e:
print("Unicode error")
else:
print(self.scale_output)
else:
#self.weigh_tick.cancel() # cancel event
self.weight_ticker()
print("Finished")
else:
self.GetCereal()