Почему вывод Pyserial readline не обновляет метку Kivy из события Triggerred? - PullRequest
0 голосов
/ 06 октября 2019

Я получаю вывод из шкалы в порядке, используя 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 не обновляется при изменении выходных данных весов?

1 Ответ

0 голосов
/ 14 ноября 2019

Поэтому я решил опубликовать обновленную функцию 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()
...