Ankündigung

Einklappen
Keine Ankündigung bisher.

Plugins programmieren

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Plugins programmieren

    Irgendwie fehlt mir der Einstieg bzw. der Zusammenhang zwischen den Plugins und dem Hauptprozess.

    Wenn ein Plugin zyklisch aufgerufen werden soll, bzw. im Plugin bestimmte Routinen zyklisch ablaufen sollen und Werte an items übergeben werden soll wie stelle ich das an?
    In meinem Fall möchte ich eine TCP/Telnet Verbindung öffnen die auch ständig offen bleiben kann.
    Danach dann (in Abhänigkeit von KNX-Telegrammen) Befehle an die gleiche senden und die Antwort auswerten.
    Ich muss also das Plugin (oder eine subroutine) aufrufen und bestimmte Parameter übergeben um den Befehl zuzuordnen und die Antwort dann wieder zurücksenden.

    Die Kommunikation zwischen Python und TCP funktioniert (als kleines Script) aber mir fehlt irgendwie die Übergabe an smarthome.py bzw. das grundsätzliche Verständnis wie Plugins realisiert werden können.

    Grüße
    Umgezogen? Ja! ... Fertig? Nein!
    Baustelle 2.0 !

    #2
    Hallo Mirko,

    Zitat von JuMi2006 Beitrag anzeigen
    Wenn ein Plugin zyklisch aufgerufen werden soll, bzw. im Plugin bestimmte Routinen zyklisch ablaufen sollen und Werte an items übergeben werden soll wie stelle ich das an?
    mit sh.scheduler.add
    Siehe z.B. https://github.com/mknx/smarthome/bl...init__.py#L255

    Zitat von JuMi2006 Beitrag anzeigen
    In meinem Fall möchte ich eine TCP/Telnet Verbindung öffnen die auch ständig offen bleiben kann.
    Wenn das Intervall länger ist und es ingesamt nicht so Zeitkritisch, würde ich die Verbindung an Deiner Stelle neu aufbauen.

    Bei Fragen oder Codefeedback kannst Du gerne auf mich zukommen.

    Bis bald

    Marcus

    Kommentar


      #3
      Ich kämpf mich mal so durch...hab mir das Luxtronic als Vorlage genommen und versuche mal so langsam Python zu verstehen.

      Ich versuche dann mal detaillierte Fragen zu formulieren.

      Grüße
      Umgezogen? Ja! ... Fertig? Nein!
      Baustelle 2.0 !

      Kommentar


        #4
        Gestern hat es dann doch noch einen größeren Klick gemacht (hoffe ich). Also ich verstehe das jetzt folgendermaßen:

        Das Plugin wird (wie auch immer) erstmal initialisiert.

        Mit sh.scheduler.add übergebe ich dem scheduler eine Einstiegs-Funktion/Methode im Plugin und ein bestimmtes Intervall.

        Die Funktion/Methode update_item wird immer dann ausgeführt wenn sich ein item (von außen?) ändert -> Visu,KNX etc.

        Nehmen wir an ich habe ein item dass durch ein xyz-Plugin geschrieben wird, so würde gleichzeitig (und ohne weiteres zutun?) das KNX-Plugin mir die Rückmeldung auf den Bus senden (sofern ich knx_listen/_send definiert habe) ?


        Grüße
        Umgezogen? Ja! ... Fertig? Nein!
        Baustelle 2.0 !

        Kommentar


          #5
          Zitat von JuMi2006 Beitrag anzeigen
          Mit sh.scheduler.add übergebe ich dem scheduler eine Einstiegs-Funktion/Methode im Plugin und ein bestimmtes Intervall.
          ja stimmt. Genauer: zum initialisieren wird __init__ aufgerufen. run wird bei dem Start des Plugins aufgerufen. Mit dem scheduler.add kann man periodisch eine Methode ausführen.

          Zitat von JuMi2006 Beitrag anzeigen
          Die Funktion/Methode update_item wird immer dann ausgeführt wenn sich ein item (von außen?) ändert -> Visu,KNX etc.
          fast, jedes Item ruft eine Pluginmethod parse_item auf, sofern sie vorhanden ist. Wenn das Item über Updates benachrichtigt werden möchte, returned es eine Methode. Diese heißt in der Regel update_item.

          Zitat von JuMi2006 Beitrag anzeigen
          Nehmen wir an ich habe ein item dass durch ein xyz-Plugin geschrieben wird, so würde gleichzeitig (und ohne weiteres zutun?) das KNX-Plugin mir die Rückmeldung auf den Bus senden (sofern ich knx_listen/_send definiert habe) ?
          ja, das ist korrekt.

          Bis bald

          Marcus

          Kommentar


            #6
            O.K. ... ich glaub der große Knoten ist geplatzt.

            Gibt es eine Möglichkeit eine Variable zu definieren die die gesamte Laufzeit von sh.py überlebt?

            Ich möchte die Anzahl der auszulesenden Werte ermitteln und dann hochzählen so dass bei z.B. 5 Werten verteilt auf 5 Minuten jede Minute ein anderer Wert ausgelesen wird.
            Umgezogen? Ja! ... Fertig? Nein!
            Baustelle 2.0 !

            Kommentar


              #7
              Plugins programmieren

              Alle Variablen die du im Plugin mit self.variablenname setzt sind Instanzvariablen und können beim nächsten Aufruf einer Methode wieder mit self.variablenname abgefragt werden. Geht natürlich nur in Klassenmethoden die als ersten Parameter self übergeben bekommen.
              Mit freundlichen Grüßen
              Niko Will

              Logiken und Schnittstelle zu anderen Systemen: smarthome.py - Visualisierung: smartVISU
              - Gira TS3 - iPhone & iPad - Mobotix T24 - ekey - Denon 2313 - Russound C5 (RIO over TCP Plugin) -

              Kommentar


                #8
                o.k. nächste Frage ... Wie übergebe ich den Wert eines item ?

                PHP-Code:
                    def refresh_parameters(self):
                        
                self.refresh_id 1
                        
                        
                for p in self._parameter:
                            
                request p
                            
                if self.refresh_id == self.id:
                                
                answer self._request(request8)
                                
                logger.info("eBus: Parameter/Refresh {0}/{1}".format(self.id,self.refresh_id))
                                return 
                answer
                            
                else:
                                
                self.refresh_id +=1
                                logger
                .info("eBus: Parameter/Refresh {0}/{1}".format(self.id,self.refresh_id)) 
                Ich durchlaufe self._parameter um beim dritten Durchlauf eben das dritte Element abzufragen ... die Schleife und das drumherum funktioniert. Ich bekomme auch eine Antwort (answer).

                Diese Antwort möchte ich jetzt dem item zuweisen und hier stehe ich auf dem Schlauch.
                Also irgendwie muss ich doch "answer" dem item zuweisen können ... so ganz blick ich da noch nicht durch.
                Umgezogen? Ja! ... Fertig? Nein!
                Baustelle 2.0 !

                Kommentar


                  #9
                  ganz kurz: item(answer)

                  Kommentar


                    #10
                    Ich habs jetzt so gelöst:

                    self._parameter[p](answer, 'eBus')

                    Ist aber das gleiche ... mann das macht aber heute oft "klick"

                    Kann ich den scheduler innerhalb eines Plugins (nach dem init) überschreiben oder gibt dass dann im Laufe der Zeit endlos viele Einträge?
                    Umgezogen? Ja! ... Fertig? Nein!
                    Baustelle 2.0 !

                    Kommentar


                      #11
                      Zitat von JuMi2006 Beitrag anzeigen
                      Kann ich den scheduler innerhalb eines Plugins (nach dem init) überschreiben oder gibt dass dann im Laufe der Zeit endlos viele Einträge?
                      Ja, am besten nimmst Du dafür scheduler.change('IDNAME', ...).

                      Bis bald

                      Marcus

                      Kommentar


                        #12
                        So...mein erstes Plugin steht ... mehr oder weniger.

                        Wie kombiniere ich nun mein ebus-Plugin mit dem knx-Plugin?
                        Ich hab folgendes item angelegt:
                        Code:
                        [ebusd]
                            [[mode]]
                                type = num
                                knx_dpt = 1
                                knx_send = 8/7/100
                                knx_listen = 8/6/100
                                comment = Heizkreis - Betriebsart
                                ebusd_type = "set"
                                ebusd_cmd = "cir2 mode"
                        Über das CLI kann ich auch mit "update ebusd.mode=1" in diesem Fall die Betriebsart ändern. Bei einem späteren zyklischen Auslesen ist alles korrekt,
                        Ich sehe im Log auch den Erfolg:
                        Code:
                        2013-05-20 12:43:22,915 SmartHome.py DEBUG    ebusd.mode = 1 via CLI 192.168.2.29 -- item.py:_update:214
                        2013-05-20 12:43:22,924 SmartHome.py INFO     eBus: called to refresh item: ebusd.mode -- __init__.py:update_item:157
                        2013-05-20 12:43:22,928 SmartHome.py DEBUG    eBus: set parameter: value:1 cmd:cir2 mode -- __init__.py:set_parameter:78
                        2013-05-20 12:43:23,073 SmartHome.py DEBUG    eBus: request: set cir2 mode 1 >>><<< answer:  ACK -- __init__.py:_request:73
                        2013-05-20 12:43:23,078 SmartHome.py DEBUG    eBus: command:set cir2 mode 1 -- __init__.py:set_parameter:81
                        2013-05-20 12:43:23,085 SmartHome.py DEBUG    eBus: answer:ACK -- __init__.py:set_parameter:82
                        So weit so gut. Nun dachte ich dass ein einfaches senden einer "1" auf 8/7/100 das gleiche macht und ich mit 8/6/100 das item lesen kann - geht aber nicht.

                        Grüße

                        Hier noch mein erstes Plugin:
                        PHP-Code:
                        #!/usr/bin/env python
                        # vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab
                        #########################################################################
                        # Copyright 2012-2013 KNX-User-Forum e.V.       https://knx-user-forum.de/
                        #########################################################################
                        #  This file is part of SmartHome.py.   http://smarthome.sourceforge.net/
                        #
                        #  SmartHome.py is free software: you can redistribute it and/or modify
                        #  it under the terms of the GNU General Public License as published by
                        #  the Free Software Foundation, either version 3 of the License, or
                        #  (at your option) any later version.
                        #
                        #  SmartHome.py is distributed in the hope that it will be useful,
                        #  but WITHOUT ANY WARRANTY; without even the implied warranty of
                        #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
                        #  GNU General Public License for more details.
                        #
                        #  You should have received a copy of the GNU General Public License
                        #  along with SmartHome.py. If not, see <http://www.gnu.org/licenses/>.
                        #########################################################################

                        import sys
                        import logging
                        import socket
                        import threading
                        import struct
                        import time
                        import datetime

                        logger 
                        logging.getLogger('')

                        class 
                        ebusex(Exception):
                            
                        pass

                        class ebusBase():

                            
                        def __init__(selfhostport=8888):
                                
                        self.host host
                                self
                        .port int(port)
                                
                        self._sock False
                                self
                        .is_connected False
                                self
                        ._connection_attempts 0
                                self
                        ._connection_errorlog 60
                                self
                        ._params = []
                                
                        self._attrs = []

                            
                        def connect(self):
                                try:
                                    
                        self._sock socket.socket(socket.AF_INETsocket.SOCK_STREAM)
                                    
                        self._sock.settimeout(2)
                                    
                        self._sock.connect((self.hostself.port))
                                
                        except Exceptione:
                                    
                        self._connection_attempts -= 1
                                    
                        if self._connection_attempts <= 0:
                                        
                        logger.error('eBus: could not connect to {0}:{1}: {2}'.format(self.hostself.porte))
                                        
                        self._connection_attempts self._connection_errorlog
                                    
                        return
                                
                        logger.info('eBus: connected to {0}:{1}'.format(self.hostself.port))
                                
                        self.is_connected True
                                self
                        ._connection_attempts 0

                            def close
                        (self):
                                
                        self.is_connected False
                                
                        try:
                                    
                        self._sock.close()
                                    
                        self._sock False
                                except
                        :
                                    
                        pass

                            def _request
                        (selfrequest):
                                
                        self._sock.send(request)
                                
                        answer self._sock.recv(1024)
                                
                        logger.debug("eBus: request: {0} >>><<< answer: {1}".format(request,answer[:-2])) #### [:-2] entfernt Zeilenumbruch/letzte 2 Zeichen
                                
                        answer answer.replace(" """### Remove whitespaces
                                
                        return answer[:-2]
                                    
                            
                        def set_parameter(self,cmd,item):
                                
                        logger.debug("eBus: set parameter: value:{0} cmd:{1}".format(item,cmd))
                                
                        request "set " cmd " " str(item)
                                
                        answer self._request(request)
                                
                        logger.debug("eBus: command:{0}".format(request))
                                
                        logger.debug("eBus: answer:{0}".format(answer))
                                
                            
                        def refresh_attributes(self):
                                
                        self.refresh_id 1
                                
                                
                        for cmds in self._attribute:
                                    if 
                        cmds[0] == "cycle":
                                        
                        request cmds[0] + " " cmds[1]     #build command
                                    
                        else:
                                        
                        request "get" " " cmds[1]     #build command
                                        
                                    
                        if self.refresh_id == self.id:
                                        
                        answer self._request(request)
                                        
                        #logger.debug("eBus: Parameter/Refresh {0}/{1}".format(self.id,self.refresh_id))
                                        
                        self._attribute[cmds](answer'eBus''refresh')   #according to item(answer)
                                        
                        return answer
                                    
                        else:
                                        
                        self.refresh_id +=1
                             
                                    
                        class eBus(ebusBase):
                            
                        _parameter = {}
                            
                        _attribute = {}
                            
                        alive True
                            
                            def __init__
                        (selfsmarthomehostport=8888cycle=30):
                                
                        ebusBase.__init__(selfhostport)
                                
                        self._sh smarthome
                                self
                        ._cycle int(cycle)
                                
                        self.connect()
                                
                        self.id 1
                                self
                        .refresh_id 0

                            def run
                        (self):
                                
                        self.alive True
                                new_cycle 
                        self._cycle/int(len(self._attribute))
                                
                        logger.debug("eBus: cycle = {0} seconds".format(new_cycle)) 
                                
                        self._sh.scheduler.add('eBus'self._refreshcycle=new_cycle)
                                

                            
                        def stop(self):
                                
                        self.alive False

                            def _refresh
                        (self):
                                
                                if 
                        not self.is_connected:
                                    return
                                
                        start time.time()
                                if 
                        len(self._attribute) > 0:
                                    
                        #logger.debug("eBus: attributes: {0}".format(self._attribute))
                                    
                        val self.refresh_attributes()
                                    
                        #logger.debug("eBus: refreshed value {0}".format(val))

                                
                        if self.id >= len(self._attribute):
                                    
                        self.id 1
                                
                        else:
                                    
                        self.id += 1
                                
                        #logger.debug("eBus: next cycle-id: {0}".format(self.id))
                                
                                
                        cycletime time.time() - start
                                
                        #logger.debug("eBus: number of attributes {0}".format(len(self._attribute)))
                                #logger.debug("cycle takes {0} seconds".format(cycletime))

                            
                        def parse_item(selfitem):
                                
                                if 
                        'ebusd_type' in item.conf:                                           # Attribute und Parameter werden regelmäßig ausgelesen
                                    
                        ebus_type item.conf['ebusd_type']
                                    
                        ebus_cmd item.conf['ebusd_cmd']                                   # Wert hinter "ebusd_cmd = "
                                    
                        self._attribute[ebus_type,ebus_cmd] = item                          # makes array 
                                    
                        logger.debug("eBus: new set = item:{0} type:{1} cmd:{2}".format(item,ebus_type,ebus_cmd))
                                    return 
                        self.update_item
                                        
                                    
                            def update_item
                        (selfitemcaller=Nonesource=None):
                                if 
                        caller != 'eBus':
                                    
                        logger.info("eBus: called to refresh item: {0}".format(item))
                                    
                        self.set_parameter(item.conf['ebusd_cmd'], item()) 
                        Umgezogen? Ja! ... Fertig? Nein!
                        Baustelle 2.0 !

                        Kommentar


                          #13
                          Hallo Mirko,

                          ja sauber. Das ging ja fix.

                          Möchtest Du es zu github hinzufügen? Wenn ja, schicke mir Doch bitte Deinen github-Account und ein kleine Anleitung was es macht/braucht/kann.


                          Eine klein Anmerkung: ich würde die Item Keywords mit ebus_ starten lassen und nicht mit eibusd_ sieht für mich konsistenter aus.

                          Wenn Du auf KNX read requests antworten möchtest, dann muss Du noch das `knx_reply` Attribute setzen.

                          Bis bald

                          Marcus

                          Kommentar


                            #14
                            Ja github kommt wenn die Bugs weg sind.

                            Ich hab folgendes Problem:

                            Wenn ich das item via CLI "update ebusd.mode=1" update dann wird das Plugin ausgeführt und die 1 an den ebusd übergeben. Also korrekt. Natürlich nur wenn das item vorher einen anderen Wert hatte.

                            Code:
                            2013-05-20 14:42:22,919 SmartHome.py INFO     eBus: called to refresh item: ebusd.mode -- __init__.py:update_item:157
                            2013-05-20 14:42:22,923 SmartHome.py DEBUG    eBus: set parameter: value:1 cmd:cir2 mode -- __init__.py:set_parameter:78
                            2013-05-20 14:42:23,051 SmartHome.py DEBUG    eBus: request: set cir2 mode 1 >>><<< answer:  ACK -- __init__.py:_request:73
                            2013-05-20 14:42:23,055 SmartHome.py DEBUG    eBus: command:set cir2 mode 1 -- __init__.py:set_parameter:81
                            2013-05-20 14:42:23,059 SmartHome.py DEBUG    eBus: answer:ACK -- __init__.py:set_parameter:82
                            2013-05-20 14:42:23,065 SmartHome.py DEBUG    0.0.0 set 8/7/100 to 1 -- __init__.py:parse_telegram:160
                            Wenn ich das item via KNX mit der CometVisu ändere erhalte ich im Log "0.0.1 set 8/7/100 to 1 -- __init__.pyarse_telegram:160". Soweit korrekt.
                            Nach meinem Verständnis müsste doch aber jetzt auch das Plugin aufgerufen werden ? Auch hier gehen wir davon aus dass das item vorher einen anderen Wert hat.

                            Code:
                            2013-05-20 14:45:01,373 SmartHome.py DEBUG    0.0.1 set 8/7/100 to 1 -- __init__.py:parse_telegram:160
                            Müsste hier nicht auch mein "eBus: called to refresh item: ebusd.mode" auftauchen ?

                            Danke für den knx_reply Hinweis:
                            Ein Lesen der knx_reply erzeugt dann den Aufruf:
                            Code:
                            2013-05-20 14:54:23,378 SmartHome.py DEBUG    0.0.0 read 8/6/100 -- __init__.py:parse_telegram:178
                            2013-05-20 14:54:23,417 SmartHome.py DEBUG    0.0.0 set 8/6/100 to False -- __init__.py:parse_telegram:165
                            2013-05-20 14:54:23,422 SmartHome.py DEBUG    ebusd.mode = 0 via KNX 0.0.0 -- item.py:_update:214
                            2013-05-20 14:54:23,429 SmartHome.py INFO     eBus: called to refresh item: ebusd.mode -- __init__.py:update_item:157
                            2013-05-20 14:54:23,434 SmartHome.py DEBUG    eBus: set parameter: value:0 cmd:cir2 mode -- __init__.py:set_parameter:78
                            2013-05-20 14:54:23,575 SmartHome.py DEBUG    eBus: request: set cir2 mode 0 >>><<< answer:  ACK -- __init__.py:_request:73
                            2013-05-20 14:54:23,579 SmartHome.py DEBUG    eBus: command:set cir2 mode 0 -- __init__.py:set_parameter:81
                            2013-05-20 14:54:23,583 SmartHome.py DEBUG    eBus: answer:ACK -- __init__.py:set_parameter:82
                            Natürlich soll er das item damit aber nicht auf "0" setzen. Irgendwo hab ich da noch nen schweren Denkfehler.

                            Code:
                            [ebusd]
                                [[mode]]
                                    type = num
                                    knx_dpt = 1
                                    knx_send = 8/7/100
                                    knx_listen = 8/6/100
                                    knx_reply = 8/6/100
                                    comment = Heizkreis - Betriebsart
                                    ebusd_type = "set"
                                    ebusd_cmd = "cir2 mode"
                            Grüße

                            P.S.:
                            Die Keywords ergeben sich durch den ebusd der dafür benötigt wird. Es fehlt dann eh noch ein script zur automatischen Generierung der item.conf.
                            Umgezogen? Ja! ... Fertig? Nein!
                            Baustelle 2.0 !

                            Kommentar


                              #15
                              Hallo Mirko,

                              ja, wenn sich das Item ändert dann wird auch Dein Plugin aufgerufen.

                              Die Zeile '0.0.0 set 8/7/100 to 1' kommt vom KNX-Plugin, und hat erst einmal nichts mit dem Item zu tun.
                              In Deinem Log müsste 'ebusd.mode = 1 via...' CLI bzw. KNX auftauchen, das sehe ich bei Deinen Schnipseln aber nicht.
                              Wenn das auftaucht, wird auch Dein Plugin aufgerufen.

                              Zwei Dinge bzgl. Deiner Konfig würde ich überdenken:

                              Code:
                              type = num
                                      knx_dpt = 1
                              tpye num ist für Zahlen gedacht. DPT 1 ist ein Bool. type = bool wäre hier passender.

                              Code:
                                      knx_send = 8/7/100
                                      knx_listen = 8/6/100
                                      knx_reply = 8/6/100
                              listen ist ja für eingehende Änderungen. send für den Status. Daher würde ich reply mit der selben Adresse wie den Status erwarten.
                              also
                              Code:
                                      knx_send = 8/7/100
                                      knx_listen = 8/6/100
                                      knx_reply = 8/[COLOR="Red"]7[/COLOR]/100
                              Bis bald

                              Marcus

                              Kommentar

                              Lädt...
                              X