为什么 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()