Ankündigung

Einklappen
Keine Ankündigung bisher.

Plugins programmieren

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

  • callidomus
    antwortet
    Du lernst schnell dazu, junger Padawan.


    Zitat von JuMi2006 Beitrag anzeigen
    Also wie geht das jetzt mit der Reaktion im Plugin auf read-requests ?
    Dazu musst Du eine kleine Logik schreiben, die auf knx_reply hört. Die kann dann mit groupwrite(ga, data, dpt) einen Wert senden.

    Aber ich denke das ist eigentlich nicht nötig. Ich würde lieber die Polling-Frequenz des Plugins erhöhen.

    Bis bald

    Marcus

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    So nun haben wir ja die erste Hürde geschafft

    knx_send = die Rückmeldeadresse auf die der Wert vom "Aktor" gesendet wird
    knx_listen = die Adresse auf die der "Aktor" hört
    knx_reply = die Rückmeldeadresse auf der "Aktor" mit einem read mit response antwortet


    Also wie geht das jetzt mit der Reaktion im Plugin auf read-requests ?

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    o.k. also gehe ich mal Funktion für Funktion durch.

    Das Plugin soll auf bestimmte GAs hören und dann deren Wert verarbeiten (über TCP senden).

    Welches Keyword muss jetzt die GA haben damit das Plugin aufgerufen wird?

    knx_ listen, send oder reply ?

    Danke für deine Geduld, aber python und smarthome.py ist erst der dritte Tag für mich.

    EDIT: Erledigt, jetzt hab ich es
    Code:
    [ebusd]
        [[mode]]
            type = num
            knx_dpt = 5
            knx_send = 8/6/100
            knx_listen = 8/7/100
            knx_reply = 8/6/100
            comment = Heizkreis - Betriebsart
            ebusd_type = "set"
            ebusd_cmd = "cir2 mode"

    Einen Kommentar schreiben:


  • callidomus
    antwortet
    Zitat von JuMi2006 Beitrag anzeigen
    Kommt ein Lesetelegramm für ein bestimmtes item so soll der entsprechende Wert aktuell über TCP ausgelesen werden und auf den Bus gesendet werden (das ist noch nicht implementiert, habe ich aber in meinem WireGate-Plugin so gelöst.)
    Das kann das Plugin nicht so einfach, es gibt einen Weg dazu später mehr.

    Zitat von JuMi2006 Beitrag anzeigen
    Damit ich auch über den aktuellen Status immer auf dem laufenden bin trage ich bei item zusätzlich die Adresse knx_listen ein. Auf dieser höre ich auf Statusänderungen und aktualisiere ggf. das item....

    Für mich stellt sich die Frage ob sich smarthome.py jetzt eher als Taster oder Aktor versteht.
    Wer ist den für den aktuellen Status verantwortlich? Ich denke in diesem Fall SH.py und ist daher Aktor. Das wiederspricht dann aber dem Satz mit knx_listen. Das listen dient zu Steuerung (durch Sensoren).

    knx_reply ist im Endeffekt mit dem Read-Flag von KNX vergleichbar.

    Zitat von JuMi2006 Beitrag anzeigen
    Edit: Das mit den DPTs ist mir klar. Das war einfach die Faulheit da ich über DPT 1.001 auch 1,2,3,4,5 übertragen bekomme, das muss ich mal ändern.
    Das KNX-Plugin liefert für DPT 1 nur True/False zurück.

    Bis bald

    Marcus

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Also noch mal langsam sonst komm ich durcheinander

    Ich versuche mal das Konzept zu beschreiben was am Ende rauskommen soll.

    Das Plugin soll auf bestimmte GAs hören und dann deren Wert verarbeiten (über TCP senden).
    Das Plugin läuft regelmäßig von allein und fragt bestimmte Werte per TCP ab. Diese Werte werden bei den bestimmten items hinterlegt und bei Änderung auf den Bus gesendet.
    Kommt ein Lesetelegramm für ein bestimmtes item so soll der entsprechende Wert aktuell über TCP ausgelesen werden und auf den Bus gesendet werden (das ist noch nicht implementiert, habe ich aber in meinem WireGate-Plugin so gelöst.)

    Im aktuellen Beispiel sind die 8/6/x-Adressen die Rückmeldeadressen. Wenn ich einen Wert ändern will (vom Taster oder per Visu) sende ich diesen auf 8/7/x.
    Das Plugin muss also auf die 8/7/x Adressen hören und Rückmeldungen/Status an 8/6/x senden. Das Plugin ist also ein klassischer Aktor.

    Nun komm ich mit der Bezeichnung der knx_xxxx hier nicht ganz klar.

    Vergleiche ich das Plugin/smarthome.py/Visu mit einem Schalter und Aktor so wird doch beim Drücken eines Tasters folgendes ausgelöst:
    - vom Schalter wird ein Telegramm an den Aktor gesendet (GA = knx_send)
    - der Aktor sendet darauf hin eine Rückmeldung (GA = knx_listen)

    Also sende ich via smarthome.py einen Wert auf das item, so sendet das KNX-Plugin diesen Wert an die Adresse knx_send.
    Damit ich auch über den aktuellen Status immer auf dem laufenden bin trage ich bei item zusätzlich die Adresse knx_listen ein. Auf dieser höre ich auf Statusänderungen und aktualisiere ggf. das item.
    Wenn ich nun Leseanfragen beantworten möchte muss mein item auch über knx_reply verfügen.

    Für mich stellt sich die Frage ob sich smarthome.py jetzt eher als Taster oder Aktor versteht.

    Edit: Das mit den DPTs ist mir klar. Das war einfach die Faulheit da ich über DPT 1.001 auch 1,2,3,4,5 übertragen bekomme, das muss ich mal ändern.

    Einen Kommentar schreiben:


  • callidomus
    antwortet
    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

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    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.

    Einen Kommentar schreiben:


  • callidomus
    antwortet
    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

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    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()) 

    Einen Kommentar schreiben:


  • callidomus
    antwortet
    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

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    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?

    Einen Kommentar schreiben:


  • callidomus
    antwortet
    ganz kurz: item(answer)

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    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.

    Einen Kommentar schreiben:


  • 2ndsky
    antwortet
    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.

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    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.

    Einen Kommentar schreiben:

Lädt...
X