コード例 #1
0
ファイル: mainWidget.py プロジェクト: ThiiD/SSR
class MainWidget(FloatLayout):
    '''
    Widget principal do supervisório
    '''
    _updateWidgets = True
    _max_points = 1000
    _supernova_color = "#7D0101"
    _color_graphs = (1,0,0)
    _color_graphs_y = (0,1,0)
    _color_graphs_z = (0,0,1)

    def __init__(self, **kwargs):
        '''
        Construtor do widget principal
        '''
        super().__init__()
        self._login = ""
        self._senha = ""
        self._missao = ""
        self._apogeu = 1
        self._serverIP = kwargs.get('server_ip')
        self._port = kwargs.get('server_port')
        self._conn = ConnectSocketPopup(self._serverIP, self._port)
        self._connError = ConnectSocketPopupError()
        self._updateDB = False
        self._verifyConn = False
        self._lock = Lock
        
        #self._connect.start()
        Window.fullscreen = False
        Window.maximize()

        
        self._graphAltitude = self.DataGraph(self._max_points, self._color_graphs)
        self._graphAcelerometro = self.DataGraphAcel(self._max_points, self._color_graphs, self._color_graphs_y, self._color_graphs_z)
        self._graphGiroscopio = self.DataGraphGiro(self._max_points, self._color_graphs, self._color_graphs_y, self._color_graphs_z)
    pass

    def _startDataRead(self):
        """
        Método utilizado para configurar a conexão socket e inicializar uma thread para a leitura dos dados e atualização da interface grafica
        :param ip: ip da conexão socket
        :param port: porta para a conexao socket
        """
        try:
            self._apogeu = int(self._apogeu)
            self._port = int(self._port)
            self._serverIP = str(ip_address(self._serverIP))            
            if self._login == 'supernova' and self._senha == 'astra':
                Window.set_system_cursor("wait")
                self._connect = Cliente(self._serverIP, self._port)
                self._connect.start()
                Window.set_system_cursor("arrow")
                self._updateThread = Thread(target = self.updater)
                self._updateThread.daemon = False
                self.ids.imagem_conexao.background_normal = 'imgs/conectado.png'
                self.ids.latitude.font_size = self.ids.altitude.font_size/2
                self.ids.longitude.font_size = self.ids.altitude.font_size/2
                self.ids.graphAcelerometro.clearLabel()
                self.ids.graphGiroscopio.clearLabel()
                self.ids.graphAltitude.clearLabel()
                self._dataBase = DBHandler(self._missao)
                self._disableNewConnections()
                self._limitesGraficos()
                self.enableSwitchesAndButtons()
                self._updateThread.start()  
                self._conn.dismiss()
            else:
                self._connError.ids.erroConnect.text = "Senha incorreta!"
                self._connError.open()
                raise Exception('Senha incorreta!')

        except ValueError:
            if (type(self._apogeu) != int):
                self._connError.ids.erroConnect.text = "Selecione o apogeu!"
                self._connError.open()
            else:
                self._connError.ids.erroConnect.text = "Erro: server/port mal definidos!"
                self._connError.open()

            raise ValueError

        except ConnectionRefusedError:
            Window.set_system_cursor("arrow")
            self._connError.ids.erroConnect.text = "Falha ao conectar!"
            self._connError.open()
            raise ConnectionRefusedError        

    
    def updater(self):
        """
        Metodo que invoca as rotinas de leitura de dados, utilizando a interface e inserção dos dados no banco de dados
        """
        while self._updateWidgets:
            try:
                if self._verifyConn:
                    #Le dados
                    self.readData()

                    # Atualiza dados
                    self._updateGUI()

                    # Insere os dados no banco de dados
                    if self._updateDB:
                        self._dataBase.insertData(data = self._instDados)
                else:
                    print('Desconectado!')
            except Exception as e:
                print(f'Erro updater: {e}')

    
    def readData(self):
        """
        Método para a leitura de dados via socket
        """
        try:
            self._instDados = self._connect._method()
        except Exception as e:
            print(f'Falha ao adquirir os dados: {e}')
            raise e

    def _updateGUI(self):
        """
        Método para a atualização dos da interface gráfica
        """
        self.ids.altitude.text = str(self._instDados['Altitude'])
        self.ids.latitude.text = str("{:.15f}".format(self._instDados['Latitude']))
        self.ids.longitude.text = str("{:.15f}".format(self._instDados['Longitude']))
        self.ids.acelerometroX.text = str("{:.2f}".format(self._instDados['Acelerometro']['x']))
        self.ids.acelerometroY.text = str("{:.2f}".format(self._instDados['Acelerometro']['y']))
        self.ids.acelerometroZ.text = str("{:.1f}".format(self._instDados['Acelerometro']['z']))
        self.ids.giroscopioX.text = str(int(self._instDados['Giroscopio']['x']))
        self.ids.giroscopioY.text = str(int(self._instDados['Giroscopio']['y']))
        self.ids.giroscopioZ.text = str(int(self._instDados['Giroscopio']['z']))
        self.ids.RSSI.text = str(self._instDados['RSSI'])
        self.ids.mapa.lat = self._instDados['Latitude']
        self.ids.mapa.lon = self._instDados['Longitude']
        self.ids.mapaMarker.lat = self._instDados['Latitude']
        self.ids.mapaMarker.lon = self._instDados['Longitude']
        self.ids.mapa.do_update(1)
        self.updateBoolean()
                                                   
        # Atualiza o grafico vertical de altitude
        self.ids.graficoMedidorAltitude.size_hint = (self.ids.medidorAltitude.size_hint[0], float(self._instDados['Altitude']/(1.2*self._apogeu))*self.ids.medidorAltitude.size_hint[1]) if self._instDados['Altitude'] <= 1.2*self._apogeu else (self.ids.medidorAltitude.size_hint[0], self.ids.medidorAltitude.size_hint[1])
        # self.ids.linhaGraficoMedidorAltitude.pos = (self.ids.medidorAltitude.pos[0], self.ids.medidorAltitude.pos[1] + float(self._instDados['Altitude']/36)*self.ids.medidorAltitude.size_hint[1])

        #Atualiza o grafico de linhas de altitude
        self.ids.graphAltitude.updateGraph((self._instDados['timestamp'], self._instDados['Altitude']),0)

        # Atualiza o grafico com dados do acelerometro
        self.ids.graphAcelerometro.updateGraph((self._instDados['timestamp'], self._instDados['Acelerometro']['x']), 0)
        self.ids.graphAcelerometro.updateGraph((self._instDados['timestamp'], self._instDados['Acelerometro']['y']), 1)
        self.ids.graphAcelerometro.updateGraph((self._instDados['timestamp'], self._instDados['Acelerometro']['z']), 2)
        
        # # Atualiza o grafico com dados do giroscopio
        self.ids.graphGiroscopio.updateGraph((self._instDados['timestamp'], self._instDados['Giroscopio']['x']), 0)
        self.ids.graphGiroscopio.updateGraph((self._instDados['timestamp'], self._instDados['Giroscopio']['y']), 1)
        self.ids.graphGiroscopio.updateGraph((self._instDados['timestamp'], self._instDados['Giroscopio']['z']), 2)

        

    
    def stopRefresh(self):
        """
        Método para parar de atualizar os widgets
        """
        self._updateWidgets = False


    def _limitesGraficos(self):
        """
        Método para definir os limites dos graficos e alterar a imagem da barra de altitude.
        """
        self.ids.graphAltitude.ymax = self._apogeu*1.2
        self.ids.graphAltitude.y_ticks_major = self._apogeu*1.2/6
        if self._apogeu == 500:
            self.ids.escala.source = 'imgs/escala500.png'
        if self._apogeu == 1000:
            self.ids.escala.source = 'imgs/escala1000.png'
        if self._apogeu == 3000:
            self.ids.escala.source = 'imgs/escala3000.png'
        if self._apogeu == 5000:
            self.ids.escala.source = 'imgs/escala5000.png'
        

    def DataGraph(self, xmax, plot_color, **kwargs):
        """
        Método para a criação do grafico de Altitude
        """
        # super().__init__(**kwargs)
        plot = LinePlot(line_width = 1.5, color = plot_color)
        self.ids.graphAltitude.add_plot(plot)
        self.ids.graphAltitude.xmax = xmax
            

    def DataGraphAcel(self, xmax, plot_color, plot_color_y, plot_color_z, **kwargs):
        """
        Método para a criação do grafico com dados do acelerometro.
        """
        plot = LinePlot(line_width = 1.5, color = plot_color)
        plot2 = LinePlot(line_width = 1.5, color = plot_color_y)
        plot3 = LinePlot(line_width = 1.5, color = plot_color_z)
        self.ids.graphAcelerometro.add_plot(plot)
        self.ids.graphAcelerometro.add_plot(plot2)
        self.ids.graphAcelerometro.add_plot(plot3)        
        self.ids.graphAcelerometro.xmax = xmax

    def DataGraphGiro(self, xmax, plot_color, plot_color_y, plot_color_z, **kwargs):
        """
        Método para a criação do grafico com dados do giroscopio.
        """
        plot = LinePlot(line_width = 1.5, color = plot_color)
        plot2 = LinePlot(line_width = 1.5, color = plot_color_y)
        plot3 = LinePlot(line_width = 1.5, color = plot_color_z)
        self.ids.graphGiroscopio.add_plot(plot)
        self.ids.graphGiroscopio.add_plot(plot2)
        self.ids.graphGiroscopio.add_plot(plot3)
        self.ids.graphGiroscopio.xmax = xmax
        


    def updateBoolean(self):
        """
        Método que atualiza os estados dos LED de acordo com o acionamento de cada paraquedas.
        """
        if self._instDados['Principal Paraquedas Estabilizador'] == 1:
            self.ids.paraquedasEstabilizadorPrincipal.source = 'imgs/green_led.png'
        
        if self._instDados['Redundancia Paraquedas Estabilizador'] == 1:
            self.ids.paraquedasEstabilizadorRedundante.source = 'imgs/green_led.png'

        if self._instDados['Comercial Paraquedas Estabilizador'] == 1:
            self.ids.paraquedasEstabilizadorComercial.source = 'imgs/green_led.png'

        if self._instDados['Principal Paraquedas Principal'] == 1:
            self.ids.paraquedasPrincipal.source = 'imgs/green_led.png'

        if self._instDados['Comercial Paraquedas Principal'] == 1:
            self.ids.paraquedasPrincipalComercial.source = 'imgs/green_led.png'



    # Ativa todos os switches (torna todos os switches clicaveis)
    def enableSwitchesAndButtons(self):
        """
        Método para habilitar os switches após a conexão.
        """
        self.ids.rbf1_switch.disabled = False
        self.ids.rbf2_switch.disabled = False
        self.ids.rbf3_switch.disabled = False
        self.ids.bd_switch.disabled = False
        self.ids.bttnMarkBase.disabled = False


    # Métodos de callback para ativação de todos os switches
    def bdActivate(self, switchObject, switchValue):
        """
            Método para demonstração do estado de gravação dos dados em um Banco de Dados.
            Altera o valor de _updateDB, que diz se está ou não gravando os dados em um banco de dados. 
        """
        if switchValue:
            self.ids.bd_led.source = 'imgs/green_led.png'
            try:
                self._dataBase.conect()
            except Exception as e:
                print("Erro ao realizar a conexão com o banco de dados!")
        else:
            self.ids.bd_led.source = 'imgs/red_led.png'   

        self._updateDB = switchValue

    def rbf1Activate(self, switchObject, switchValue):
        """
        Método para demonstração do estado do Remove Before Light 1 (LED 1 ON/OFF)
        """
        if switchValue:
            self.ids.rbf1_led.source = 'imgs/green_led.png'
        else:
            self.ids.rbf1_led.source = 'imgs/red_led.png'

    def rbf2Activate(self, switchObject, switchValue):
        """
        Método para demonstração do estado do Remove Before Light 2 (LED 2 ON/OFF)
        """
        if switchValue:
            self.ids.rbf2_led.source = 'imgs/green_led.png'
        else:
            self.ids.rbf2_led.source = 'imgs/red_led.png'

    def rbf3Activate(self, switchObject, switchValue):
        """
        Método para demonstração do estado do Remove Before Light 3 (LED 3 ON/OFF)
        """
        if switchValue:
            self.ids.rbf3_led.source = 'imgs/green_led.png'
        else:
            self.ids.rbf3_led.source = 'imgs/red_led.png'

    def _markBase(self):
        """
        Método que cria um novo MapMarkerPopup para marcar a base de lançamento e desabilita o botão
        """
        marker = MapMarkerPopup(lat=self._instDados['Latitude'], lon=self._instDados['Longitude'], source='imgs/markerBase.png')
        self.ids.mapa.add_widget(marker)
        self.ids.mapa.center_on(self._instDados['Latitude'], self._instDados['Longitude'])
        self.ids.bttnMarkBase.disabled = True


    def _disableNewConnections(self):     
        """
        Método que trava os dados correspondentes a conexão
        """
        self._conn.ids.txt_ip.disabled = True
        self._conn.ids.txt_port.disabled = True
        self._conn.ids.txt_login.disabled = True
        self._conn.ids.txt_senha.disabled = True
        self._conn.ids.txt_missao.disabled = True
        self._conn.ids.txt_apogeu.disabled = True
        self._conn.ids.connButton.text = 'Desconectar'

    def _disconect(self):
        """
        Método para tratar a desconexão do supervisorio ao foguete.
        Reseta todas as configurações ao original.
        """
        self._conn.ids.txt_ip.disabled = False
        self._conn.ids.txt_port.disabled = False
        self._conn.ids.txt_login.disabled = False
        self._conn.ids.txt_senha.disabled = False
        self._conn.ids.txt_missao.disabled = False
        self._conn.ids.txt_apogeu.disabled = False
        self._conn.ids.connButton.text = 'Conectar'        
        self.ids.imagem_conexao.disabled = True
        self.ids.imagem_conexao.background_disabled_normal = 'imgs/desconectado.png'
        self._connect.disconect()
        self.ids.altitude.text = '-.-'
        self.ids.latitude.text = '-.-'
        self.ids.latitude.font_size = self.ids.altitude.font_size
        self.ids.longitude.text = '-.-'
        self.ids.longitude.font_size = self.ids.altitude.font_size
        self.ids.acelerometroX.text = '-.-'
        self.ids.acelerometroY.text = '-.-'
        self.ids.acelerometroZ.text = '-.-'
        self.ids.giroscopioX.text = '-.-'
        self.ids.giroscopioY.text = '-.-'
        self.ids.giroscopioZ.text = '-.-'
        self.ids.RSSI.text = '-.-'
        self.ids.mapa.lat = -21.778570807566982
        self.ids.mapa.lon = -43.373106180550764
        self.ids.mapaMarker.lat = -21.778570807566982
        self.ids.mapaMarker.lon = -43.373106180550764
        self.ids.mapa.do_update(1)
        self.ids.paraquedasEstabilizadorPrincipal.source = 'imgs/red_led.png'
        self.ids.paraquedasEstabilizadorRedundante.source = 'imgs/red_led.png'
        self.ids.paraquedasEstabilizadorComercial.source = 'imgs/red_led.png'
        self.ids.paraquedasPrincipal.source = 'imgs/red_led.png'
        self.ids.paraquedasPrincipalComercial.source = 'imgs/red_led.png'
        self.ids.rbf1_switch.active = False
        self.ids.rbf2_switch.active = False
        self.ids.rbf3_switch.active = False
        self.ids.bd_switch.active = False
        self.ids.rbf1_switch.disabled = True
        self.ids.rbf2_switch.disabled = True
        self.ids.rbf3_switch.disabled = True
        self.ids.bd_switch.disabled = True
        self.ids.bttnMarkBase.disabled = True
        self.ids.escala.source = 'imgs/escalaZerada.png'
        self.ids.graficoMedidorAltitude.size_hint = self.ids.medidorAltitude.size_hint[0], 0
        self.ids.graphAltitude.clearPlots()
        self.ids.graphAltitude.clearLabel()
        self.ids.graphAcelerometro.clearPlots()
        self.ids.graphAcelerometro.clearLabel()
        self.ids.graphGiroscopio.clearPlots()
        self.ids.graphGiroscopio.clearLabel()
        self._conn.dismiss()
        #self._updateThread.terminate() 

    def clickConnection(self):
        """
        Método que verifica se está sendo feita a conexão ou desconexão e chama o método correspondente.
        """
        self._verifyConn = not self._verifyConn
        try:
            if self._verifyConn:
                self._startDataRead()
            else:
                self._disconect()                
        except:
            self._verifyConn = not self._verifyConn
            print('Falha ao conectar! verifyConn não alterado.')