简体   繁体   中英

Why is Pyserial readline output not updating Kivy Label from Triggerred event?

I am getting the output from a scale okay using Pyserial. So I decided to read all the output to a Kivy Label to make the program more user friendly. At first the minimal example was good enough, whereby the user just clicked a button to see the output in 20 counter intervals. But now it is necessary to automate the whole process by first receiving the Output, then triggering a secondary event that checks for a stable Output before updating a Sqlite db. But one problem has occurred:

1] The Label does not update with the change in the scales output. This stems from the serial.readline() method that for some reason does not update also.
Some of my Python code:

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()

I have tried binding the output to the text of the Label object. That did not make a difference.

Can someone please give me insight into why the readline method is not updating with a change in the scales output?

So I decided to post my updated GetOutput function with the solution.
Solution is resetting the input buffer using PySerial built in serial.reset_input_buffer() method.
From the documentation:

Flush input buffer, discarding all its contents.
Changed in version 3.0: renamed from flushInput()

Code:

    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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM