kivyMD TCPModbus 应用程序无法从服务器读取数据的问题

问题描述 投票:0回答:2

我根据老师的视频课程程序创建了一个应用程序。事实证明我遇到了一些问题,给我返回了以下异常,我非常感谢您的关注:

Error during data status reading.
Error during data setpoint reading.
Error during data tempOven reading.
Error during data tempOven reading.
Error during data tempOven reading.

我知道这是一个理论脚本,但如果你们可以在计算机上运行,我会很感激,因为我手工复制了老师的脚本,但它根本不起作用,尽管它没有错误。只要我在这里发布代码,我就会继续在这里写它的概述,并且文件将是 3 个(kivyMD .kv、main.py 和 datacards)。应用程序的外观是这样的: 这些问题恰好在下面的页面上触发(数据采集),因为连接步骤成功。

从主程序开始,此代码实例化 MDApp,然后实例化 Screen。它有一个按钮,如图所示1,用于连接。连接方法本身实例化时钟调度程序,以最终更新保持卡和线圈卡。

from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
from datacard import CardCoil, CardHoldingRegister, CardInputRegister
from pyModbusTCP.client import ModbusClient
from kivymd.uix.snackbar import Snackbar
from kivy.clock import Clock

class MyWidget(MDScreen):
    """
    Contructor
    """
    def __init__(self,tags,**kwargs):
        self._clientMOD= ModbusClient()
        super().__init__(**kwargs)
        self._tags=tags 
        self._ev=[]   #pt4 min 58
        for tag in self._tags:
            if tag["type"]=="input":
                self.ids.modbus_data.add_widget(CardInputRegister(tag,self._clientMOD))
            elif tag["type"]== "holding":
                self.ids.modbus_data.add_widget(CardHoldingRegister(tag,self._clientMOD))
            elif tag["type"]=="coil":
                self.ids.modbus_data.add_widget(CardCoil(tag,self._clientMOD))
    
    def connect(self):
        if self.ids.bt_con.text== "CONNECT":
            try:
                self.ids.bt_con.text= "DISCONNECT"
                self._clientMOD.host= self.ids.hostname.text
                self._clientMOD.port = int(self.ids.port.text)
                self._clientMOD.open()
                Snackbar(text="Connected succesfully",bg_color=(0,1,0,1)).open()
                self._ev=[]
                for card in self.ids.modbus_data.children:
                    if card.tag['type'] == "holding" or card.tag['type']== "coil":
                        self._ev.append(Clock.schedule_once(card.update_card))
                    else:
                        self._ev.append(Clock.schedule_interval(card.update_card,1))
            except Exception as e:
                print("Erro de conexao com servidor: ", e.args)  
        else:
            self.ids.bt_con.text="CONNECT"
            for event in self._ev:
                event.cancel()
                self._clientMOD.close()
            Snackbar(text="Disconnected",bg_color=(1,0,0,1)).open()


class BasicApp(MDApp):

    
    __tags=  [{'name':'tempOven','description':'Oven Tempture','unit':'ºC','address':1000,'type':"input"},
              {'name':'setpoint','description':'Desired Tempture','unit':'ºC','address':2000,'type': "holding"},
              {'name':'status','description':'Actuator state','address':1000,'type':"coil"},

    ]
    def build(self):
        self.theme_cls.primary_palette= "Orange"
        self.theme_cls.primary_hue= "700"
        self.theme_cls.accent_palette="Orange"
         
        return MyWidget(self.__tags)

if __name__=='__main__':
    BasicApp().run()

第二个文件和下一步是数据卡模块。其目标是定义 2 个类(MDcard 类)和 3 个不同的 MDcard 子类。实际上,这三者代表了 Mbus 功能保持、输入或线圈之间的方法差异。他们的目标是与服务器交互:

from kivymd.uix.card import MDCard,MDCard
from pyModbusTCP.client import ModbusClient

class DataCard(MDCard):             
    title= "Data Card"
    def __init__(self,tag,mbusClient,**kwargs):
        self.tag= tag                                          
        self.title=self.tag['description']          
        self._mbusclient = mbusClient
        super().__init__(**kwargs)  

    def update_card(self,dt):
        try:
            if self._mbusclient.is_open():
                self.set_data(self._read_data(self.tag['address'],1)[0])
        except Exception as e:
            print("Error during data",self.tag['name'] ,"reading.")

    def write_card(self):
        try:
            if self._mbusclient.is_open():
                self._write_data_fcn(self.tag['address'],self._get_data())
        except Exception as e:
            print("Error during data" ,self.tag['name'] ,"writting.")
    
class CardHoldingRegister(DataCard):
    def __init__(self,tag,mbusClient,**kwargs):
        super().__init__(tag,mbusClient,**kwargs)
        self._read_data=self._mbusclient.read_holding_registers
        self._write_data_fcn= self._mbusclient.write_single_register
    
    def set_data(self, data):
        self.ids.textfield.text= str(data)

    def get_data(self):
        return int(self.ids.textfield.text)
        

class CardInputRegister(DataCard):
    def __init__(self,tag,mbusClient,**kwargs):
        super().__init__(tag,mbusClient,**kwargs)
        self._read_data= self._mbusclient.read_input_registers
    
    def set_data(self, data):
        self.ids.label.text= str(data)
    

class CardCoil(DataCard):
    def __init__(self,tag,mbusClient,**kwargs):
        super().__init__(tag,mbusClient,**kwargs)
        self._read_data= self._mbusclient.read_coils
        self._write_data_fcn= self._mbusclient.write_single_coil

    
    def set_data(self, data):
        self.ids.switch.active= data    #True / False
    
    def get_data(self):
        return self.ids.switch.active                      #RETURN = ajuste

最后,我们有了 kivy .kv 模块,它与 datacrd 模块对话(例如,当你想在 MDcard 盒子上显示服务器和客户端之间的数据交换时)并与主要模块(例如连接和 MD)对话

#:kivy 1.11.1
<MyWidget>:
    MDBoxLayout:
        orientation:'vertical'
        MDTopAppBar:
            title: "Informatica industrial"
        MDBottomNavigation:
            panel_color: app.theme_cls.accent_color
            text_color_normal:0.4,0.4,0.4,1
            text_color_active:0.8,0.8,0.8,1
            MDBottomNavigationItem:
                name:"config"
                text:"CONFIGURATION"
                icon: "cog"
                MDBoxLayout:
                    orientation: 'vertical'
                    padding: "20p"
                    spacing: "50dp"
                    Image:
                        source:"imgs/modbus.png"
                        pos_hint: {"center_x":0.5,"center_y":0.5}   
                        size_hint: {1,0.2}    
                    MDTextField:
                        id:hostname
                        text:"127.0.0.1"
                        hint_text: "IP Address"
                        size_hint: {0.3, None}
                        height: "60dp"        #tentatativa e erro
                        pos_hint: {"center_x":0.5,"center_y":0.5}
                    MDTextField:
                        id:port
                        text:"502"
                        hint_text: "Port"
                        size_hint: {0.3, None}
                        height: "60dp"       
                        pos_hint: {"center_x":0.5,"center_y":0.4}                        
                    MDRoundFlatIconButton:
                        id: bt_con
                        text:"CONNECT"
                        icon:'connection'
                        pos_hint:{"center_x":0.5,"center_y":0.3} 
                        on_release: root.connect()
                   
            MDBottomNavigationItem:
                name:"data"
                text:"DADOS" 
                icon:"chart-donut"
                ScrollView:
                    size_hint: (1,None)
                    size: 800,600     #define o tamanho como o da janela 800x600
                    bar_pos_y: 'left'
                    bard_width: 20
                    effect_cls: 'ScrollEffect'
                    MDStackLayout:
                        id: modbus_data
                        size_hint: (1, None)
                        padding: 0.05*600,"150dp"
                        spacing: (800/5 - 2*0.05*800)/3
                        adaptive_height: True

<DataCard>:
    orientation: 'vertical'
    padding: '10dp'
    size_hint:None,None
    size: 600/5 , "90dp"
    pos_hint:{"center_x": 0.5, "center_y":0.5}
    MDLabel:
        text: root.title 
        size_hint_y: None
        height:self.texture_size[1]
        pos_hint: {'top':1} 
    MDSeparator:
        height: "1dp"

<CardHoldingRegister>:
    MDTextField:
        id:textfield
        helper_text: "Pressione Enter para enviar os dados"
        helper_text_mode:'persistent'
        multiline: False
        on_text_validate: root.write_card

<CardInputRegister>:
    MDLabel:
        id:label

<CardCoil>:
    MDSwitch:
        id: switch
    

如果问题太长,我很抱歉,但仅此而已。如果您愿意,我可以将我所基于的 Youtube 播放列表留在此处 (https://www.youtube.com/watch?v=DqO-KJXv6UE&list=PLDBnf2G73PkBqYVoxUoGQe7htYYE4fIsX&index=20)。老师还分享了服务器模块,可以在上面的 Youtube 链接上下载(在视频说明上)。我很感激任何类型的提示,我预先感谢你们。

kivymd modbus modbus-tcp scada pymodbustcp
2个回答
1
投票

根据 文档

ModbusClient.is_open
是一个布尔值(不是函数)。这意味着尝试将其用作函数
if self._mbusclient.is_open()
将触发您所看到的异常。

要修复,请将

if self._mbusclient.is_open()
替换为
if self._mbusclient.is_open
(即删除
()
。我不保证这是唯一的问题:-)...


0
投票

无需 PC 即可使用该功能,可以将 apk 与 google colabs 进行转换。

"
from kivymd.app import MDApp
from kivymd.uix.label import MDLabel
from pymodbus.client import ModbusTcpClient as ModbusClient
from pymodbus.exceptions import ConnectionException
from kivy.clock import Clock

class MainApp(MDApp):
    def build(self):
        self.label = MDLabel(halign="center")
        try:
            self.client = ModbusClient('192.168.18.107', port=502)
            connection = self.client.connect()

            if not connection:
                raise ConnectionException("Falha ao conectar com o dispositivo Modbus")

            # Agenda a leitura da variável para acontecer a cada 1 segundo
            Clock.schedule_interval(self.read_modbus_variable, 1)
        except ConnectionException as e:
            self.label.text = str(e)
        except Exception as e:
            self.label.text = f"Erro ao inicializar o Modbus: {e}"

        return self.label

    def read_modbus_variable(self, dt):
        try:
            # Ler a variável desejada
            response = self.client.read_holding_registers(1, 1)
            if not response.isError():
                valor = response.registers[0]
                texto = f"Valor lido: {valor}"
            else:
                texto = "Erro na leitura do registro"
            self.label.text = texto
        except ConnectionException as e:
            self.label.text = "Falha na conexão com o dispositivo Modbus"
        except Exception as e:
            self.label.text = f"Falha ao ler o Modbus: {e}"

    def on_stop(self):
        # Desconectar quando o aplicativo for fechado
        try:
            if self.client:
                self.client.close()
        except Exception as e:
            print(f"Erro ao fechar a conexão Modbus: {e}")

MainApp().run()
"
© www.soinside.com 2019 - 2024. All rights reserved.