为什么 Pyserial readline 输出不从 Triggerred 事件更新 Kivy 标签?
Why is Pyserial readline output not updating Kivy Label from Triggerred event?
我正在使用 Pyserial 从一个比例尺获得输出。所以我决定将所有输出读取到 Kivy 标签中,以使程序更加用户友好。起初,最小的例子已经足够好了,用户只需点击一个按钮就可以看到 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
方法没有随着天平输出的变化而更新吗?
所以我决定 post 我更新的 GetOutput
功能与解决方案。
解决方案是使用 serial.reset_input_buffer()
内置的 PySerial
方法重置输入缓冲区。
来自文档:
Flush input buffer, discarding all its contents.
Changed in version 3.0: renamed from 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()
我正在使用 Pyserial 从一个比例尺获得输出。所以我决定将所有输出读取到 Kivy 标签中,以使程序更加用户友好。起初,最小的例子已经足够好了,用户只需点击一个按钮就可以看到 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
方法没有随着天平输出的变化而更新吗?
所以我决定 post 我更新的 GetOutput
功能与解决方案。
解决方案是使用 serial.reset_input_buffer()
内置的 PySerial
方法重置输入缓冲区。
来自文档:
Flush input buffer, discarding all its contents.
Changed in version 3.0: renamed from 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()