Kivy - Метка для отображения данных датчика в реальном времени - PullRequest
0 голосов
/ 24 сентября 2018

Я хотел бы создать две метки в Kivy, которые будут обновлять свой текст данными датчиков с датчиков температуры.

Датчики температуры подключены к Arduino, который каждые две секунды печатает свои значения в последовательном формате в следующем примере:

A 82,4 (в строке 1)

B 80,6 (в строке 2)

A / B включается в каждый отпечаток в качестве идентификатора, который Python может подобрать для различения между ними.

Проблема заключается в импорте этих данных в python и прикреплении их к меткам.

Вот существующий .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 - это две метки, которые яхотелось бы обновиться от датчиков.

1 Ответ

0 голосов
/ 25 сентября 2018

Это вполне возможно.Но вам не хватает нескольких вещей.

Вы пытаетесь подключиться к последовательному порту после запуска вашего приложения, которое не будет работать, так как ваше приложение будет остановлено, когда вы приедете туда.Вместо этого вы хотите выполнить эту часть, пока ваше приложение работает.Я бы сделал попытку / кроме подключения к arduino в 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")

тогда, вы хотите проверить сообщения в методе обновления, но вы не хотите блокировать, так что вы толькопрочитайте объем данных, ожидающих в буфере.

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

затем вы выполняете обработку, я предполагаю, что ваши данные выглядят примерно так:

A value
B value

в таком случае вы можетепроанализируйте его и обновите соответствующую переменную, что-то вроде:

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

сделает работу, это немного упрощенно, так как предполагает, что вы всегда получаете полные строки, но это может быть улучшено позже, если необходимо (и этомне кажется, этого достаточно для многих случаев).

Теперь нам нужно убедиться, что наши метки замечают изменения значений, для этого kivy использует properties, которые являются более умными атрибутами, вам нужночтобы объявить их в классе приложения.

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

Теперь вы можете сделать так, чтобы ваше обновление отображало значение напрямую через экземпляр приложения.

<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}
...