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.