Kivy-显示实时传感器数据的标签 [英] Kivy - Label to display real-time Sensor Data

查看:142
本文介绍了Kivy-显示实时传感器数据的标签的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Kivy中创建两个标签,使用来自温度传感器的传感器数据更新其文本.

I would like to create two labels in Kivy that update their text with sensor data from temp sensors.

温度传感器连接到Arduino,每两秒钟左右以示例格式将其值打印到串行:

Temp sensors are connected to an Arduino, which prints their values to serial in the example format every two seconds or so:

A 82.4 (第1行)

B 80.6 (第2行)

A/B包含在每个打印物中,作为python可以用来区分两者的标识符.

The A/B is included in each print as an identifier that python could pick up to differentiate between the two.

问题是将这些数据导入python并将其附加到标签上.

The issue is importing this data into python and attaching it to labels.

这是现有的.py:

import kivy

kivy.require('1.10.0')

from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.stacklayout import StackLayout
from kivy.uix.button import Button
from kivy.clock import Clock
from kivy.properties import StringProperty, NumericProperty, ObjectProperty
from digitalclock import DigitalClock
from kivy.animation import Animation

import serial
import time
import opc


class IntroScreen(Screen):
    pass


class ContScreen(Screen):
    pass


class ScreenManagement(ScreenManager):
    pass


#Disregard this, a timer is included in layout
class Timer(Label):
    a = NumericProperty()  # seconds

    def __init__(self, root, instance, duration, bg_color, **kwargs):
        super(Timer, self).__init__(**kwargs)
        self.obj = instance
        self.a = duration
        self.root = root

        self.obj.disabled = True    # disable widget/button
        self.obj.background_color = bg_color
        self.root.add_widget(self)  # add Timer/Label widget to screen, 'cont'

    def animation_complete(self, animation, widget):
        self.root.remove_widget(widget)  # remove Timer/Label widget to screen, 'cont'
        self.obj.background_color = [1, 1, 1, 1]    # reset to default colour
        self.obj.disabled = False   # enable widget/button

    def start(self):
        Animation.cancel_all(self)  # stop any current animations
        self.anim = Animation(a=0, duration=self.a)
        self.anim.bind(on_complete=self.animation_complete)
        self.anim.start(self)

    def on_a(self, instance, value):
        self.text = str(round(value, 1))


class Status(FloatLayout):
    _change = StringProperty()
    _tnd = ObjectProperty(None)

    def update(self, *args):
        self.time = time.asctime()
        self._change = str(self.time)
        self._tnd.text = str(self.time)
        print (self._change)

#Here is where I start referencing Serial Comms, this line is to identify where
#to *send* commands to via a separate identifier.
bone = serial.Serial('/dev/ttyACM0', 9600)


class XGApp(App):
    time = StringProperty()
    sensor1 = NumericProperty(0)
    sensor2 = NumericProperty(0)

    def update(self, *args):
        self.time = str(time.asctime())
    arduino = self.arduino
    data = arduino.read(arduino.inWaiting())
    for line in data.split('\n'):
        try:
            sensor, value = line.strip().split(' ')
        except:
            print("parse error!")
            continue
        if sensor == 'A':
            self.sensor1 = float(value)
        elif sensor == 'B':
            self.sensor2 = float(value)
        else:
            print("unknown data! {}".format(line))

    def build(self):
        try:
            self.arduino = serial.Serial('/dev/ttyACM0', 9600)
        except Exception as e: print(e)

        Clock.schedule_interval(self.update, 1)
        return Builder.load_file("main.kv")


xApp = XGApp()

if __name__ == "__main__":

    xApp.run()

和.kv:

<ContScreen>:
    FloatLayout
        orientation: 'vertical'
        padding: [10,50,10,50]
        spacing: 50

        Label:
            id: 'TempLabel1'
            text: str(app.sensor1)
            color: 1,1,1,1
            font_size: 80
            pos_hint: {'center_x':0.2, 'center_y':0.6}

        Label:
            id: 'TempLabel2'
            text: str(app.sensor1)
            color: 1,1,1,1
            font_size: 80
            pos_hint: {'center_x':0.5, 'center_y':0.6}

.kv中的

稍后:

StackLayout
        orientation: "tb-rl"
        spacing: 15

        Button:
            text: "1"
            size_hint: None, .16
            width: 225
            on_press:
                Timer(root, self, 10, [100, 0, 100, 1.75]).start()
                bone.Write('j'.encode())
                print("One Executed")

TempLabel1和TempLabel2 是我想从传感器更新的两个标签.

TempLabel1 and TempLabel2 are the two labels i'd like updated from the sensors.

推荐答案

这是完全可能的.但是您缺少一些东西.

It's totally possible. But you are missing a few things.

您正在尝试在运行应用程序后尝试连接到串行端口 ,但该操作无效,因为到达您的应用程序后该应用程序将被停止.相反,您想在应用程序运行时执行此部分.我会尝试使用try/except连接到app.build中的arduino.

You are trying to connect to the serial port after running your app, that won't work as your app will be stopped when you arrive there. Instead, you want to do this part while your app runs. I would do the try/except to connect to arduino in app.build.

def build (self):
    try:
        self.arduino = serial.Serial('/dev/ttyACM0')
    exept:
        print("unable to connect to arduino :(")

    Clock.schedule_interval(self.update, 1)
    return Builder.load_file("main.kv")

然后,您要检查update方法中的消息,但不想阻塞,因此只读取缓冲区中等待的数据量.

then, you want to check for messages in the update method, but you don't want to block, so you only read the amount of data that is waiting in the buffer.

def update(self, *args):
    arduino = self.arduino
    data = arduino.read(arduino.inWaiting())

然后您进行处理,我假设您的数据是这样的:

then you do your processing, i assume your data is something like:

A value
B value

在这种情况下,您可以解析它并更新相应的变量,例如:

in such case, you can parse it and update the corresponding variable, something like:

def update(self, *args):
    arduino = self.arduino
    data = arduino.read(arduino.inWaiting()) 
    for line in data.split('\n'):
        try:
            sensor, value = line.strip().split(' ')
        except:
            print("parse error!")
            continue
        if sensor == 'A':
            self.sensor1 = float(value)
        elif sensor == 'B':
            self.sensor2 = float(value)
        else:
            print("unknown data! {}".format(line))

将完成这项工作,这有点简单,因为它假定您总是会获得完整的阵容,但是如果需要的话可以在以后进行改进(根据我的经验,这似乎足够了).

would do the job, it's a bit simplistic, as it assumes you always get full lines, but it can be improved later if needed (and it seems enough for a lot of cases in my experience).

现在,我们需要确保我们的标签注意到值的变化,为此,kivy使用properties这是更聪明的属性,您需要在应用类上声明它们.

Now, we need to make sure that our labels notice the changes of values, for this, kivy uses properties, which are smarter attributes, you need to declare them on the app class.

class XGApp(App):
    sensor1 = NumericProperty(0)
    sensor2 = NumericProperty(0)

现在,您可以通过应用实例使更新直接显示值.

now, you can make your update display the value directly, through the app instance.

<ContScreen>:
    FloatLayout
        orientation: 'vertical'
        padding: [10,50,10,50]
        spacing: 50

        Label:
            id: 'TempLabel1'
            text: str(app.sensor1)
            color: 1,1,1,1
            font_size: 80
            pos_hint: {'center_x':0.2, 'center_y':0.6}

        Label:
            id: 'TempLabel2'
            text: str(app.sensor2)
            color: 1,1,1,1
            font_size: 80
            pos_hint: {'center_x':0.5, 'center_y':0.6}

这篇关于Kivy-显示实时传感器数据的标签的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆