Funktion beenden

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
__deets__
User
Beiträge: 14535
Registriert: Mittwoch 14. Oktober 2015, 14:29

Code: Alles auswählen

import uasyncio
import random


async def ir_system(callback):
    while True:
        await uasyncio.sleep(3)
        # eines von zwei Kommandos, addr egal
        callback(random.choice([1, 2]), None)


def callback(queue, val, _addr):
    # Notwending, um die queue zu awaiten
    uasyncio.create_task(queue.put(val))


async def task1():
    while True:
        print("task1")
        await uasyncio.sleep(1)


async def task2():
    while True:
        print("task2")
        await uasyncio.sleep(1)


async def dispatcher(queue):
    task = None
    while True:
        command = await queue.get()
        if task:
            task.cancel()
        coro = task1() if command == 1 else task2()
        task = uasyncio.create_task(coro)


async def main():
    command_queue = uasyncio.Queue()
    # Simuliert das IR-System von dir, der callback
    # muss die queue kennen, also benutze ich lambda
    uasyncio.create_task(ir_system(lambda val, addr : callback(command_queue, val, addr)))

    # verteilt die events auf die beiden tasks
    await dispatcher(command_queue)


# main guard
if __name__ == '__main__':
    uasyncio.run(main())
So klappt das. Die einzige Huerde ist das einfuegen in die Queue als asyncio-Task zu machen, weil die das natuerlich braucht, eigentlich macht man ja await q.put(..), aber da der callback synchron ist, muss man das als Task laufen lassen.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Danke. Aber wenn ich den Code 1:1 übernehme, dann kommt folgende Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "<stdin>", line 51, in <module>
  File "uasyncio/core.py", line 1, in run
  File "uasyncio/core.py", line 1, in run_until_complete
  File "uasyncio/core.py", line 1, in run_until_complete
  File "<stdin>", line 40, in main
  File "uasyncio/__init__.py", line 1, in __getattr__
AttributeError: Queue
__deets__
User
Beiträge: 14535
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das Programm ist notgedrungen auf dem Mac entstanden, und mit einem uasyncio-Emulationspaket. Da war die drin, und ich bin auf die gekommen wegen https://github.com/peterhinch/micropyth ... d#35-queue

Fuer deine Plattform findet sich das wohl hier: https://github.com/peterhinch/micropyth ... s/queue.py - er will, dass man das primitives Paket installiert. Musst du dann eben noch machen.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Nein das geht leider nicht zu installieren.
__deets__
User
Beiträge: 14535
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist bedauerlich, denn bei mir geht das immer problemlos. Dann kann man wohl nix machen.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Es geht im übrigen um den Raspberry Pico.

Aber es muss sich doch ein Weg finden, wie man eine Methode wieder beendet.
__deets__
User
Beiträge: 14535
Registriert: Mittwoch 14. Oktober 2015, 14:29

Habe ich dir gezeigt. Das ist der Weg. Wenn du die dazu notwendigen Schritte nicht gehen kannst oder willst, erzeugt das keine magische Alternative, die dir vorher nur verschwiegen wurde.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

OK wenn es nicht zu installieren geht ist es schade.
Trotzdem vielen dank.
__deets__
User
Beiträge: 14535
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da es bei mir problemlos(*) moeglich ist, Pakete auf meine micropython-basierten Controller zu packen, wuerde ich dazu raten, daran zu arbeiten.

* es ist manchmal schon etwas nervig, aber eigentlich muss man die dateien am Ende nur draufkopieren mit ampy zB.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Jetzt habe ich die `Queue` Klassen direkt durch copy & paste eingefügt. Jetzt erkennt er auch Queue().

Wenn ich das richtig deute, funktioniert das ganze so, in der main-Klasse wird in uasyncio der Aufruf zum IR-System gemacht (in meinen Fall `ir = NEC_16(Pin(16, Pin.IN), callback)`) damit uasyncio weiß, das die callback-Methode zum asyncio gehört.
Anschließend wird in der main-Methode noch die Methode dispatcher aufgerufen und auch eine Instanz von Queue() übergeben.
In der Methode `dispatcher` wird mit `await queue.get()` ausgewertet, ob ein Befehl ausgeführt wurde? Dann wird geprüft ob task1 oder task2 ausgeführt werden soll.

Die Methoden callack kann ich mit meiner übersetzen und die Methode ir_system ist mit dem Befehl `ir = NEC_16(Pin(16, Pin.IN), callback)` gleichzusetzen.

Ist das so in etwa richtig?
__deets__
User
Beiträge: 14535
Registriert: Mittwoch 14. Oktober 2015, 14:29

Hm. Sind schon einige Fehlannahmen/Bezeichnungen dabei. Es gibt keine Klasse. Und der callback gehört genau nicht zum asyncio. Aber er delegiert den Queue.put Aufruf daran.

Versuch es umzubauen, zeig, was du hast, und man kann dazu Stellung beziehen.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Mit `Queue` Klassen meinte ich, das ich die Module in /lib eingefügt habe.

Jetzt habe ich das Programm umgebaut, so dass es jetzt keinen Fehler ergibt.

Jetzt muss ich nur noch versuchen die jeweiligen Methoden zum starten und zum beenden bringen.

Warum starte ich die Methode `dispatcher` und die `ir_system` in main gleichzeitig?

Code: Alles auswählen

async def ir_system(callback):
    ir = NEC_16(Pin(16, Pin.IN), callback)

def callback(queue, data, addr, ctrl):
    if data > 0:  # NEC protocol sends repeat codes.
        print('Data {:05x} Addr {:04x}'.format(data, addr))
        uasyncio.create_task(queue.put(val))

async def test1():
    while True:
        print("methode 1 zum ausfuhren")
        await asyncio.sleep(1)
        
async def test2():
    while True:
        print("methode 2 zum ausfuhren")
        await asyncio.sleep(1)
    
def callback(data, addr, ctrl):
    if data > 0:  # NEC protocol sends repeat codes.
        print('Data {:05x} Addr {:04x}'.format(data, addr))
        print(wert[data])
      
        asyncio.run(start(wert[data]))
 
async def dispatcher(queue):
    task = None
    while True:
        command = await queue.get()
        if task:
            task.cancel()
        coro = task1() if command == 1 else task2()
        task = uasyncio.create_task(coro) 
 
async def main():
    command_queue = Queue()
    uasyncio.create_task(ir_system(lambda val, addr : callback(command_queue, val, addr)))
    await dispatcher(command_queue)


if __name__ == '__main__':
    uasyncio.run(main())
__deets__
User
Beiträge: 14535
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du brauchst ir_System nicht. Das ist meine Simulation. Und du redest von Main-Klasse. Die gibts nicht.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

OK, ich muss also in mein() den callback aufrufen mit dem Argument der queue und gleichzeitig den dipatcher() aufrufen. Wenn in callback etwas passiert wird die Methode dispatcher aufgerufen und die Daten übermittelt. Ist das richtig?
Ich weiß jetzt nur nicht wie ich in main() den 'NEC_16(Pin(16, Pin.IN), callback)' Befehl aufrugfe. Es muss ja noch die queue übergeben werden.

Code: Alles auswählen

async def test1():
    while True:
        print("methode 1 zum ausfuhren")
        await asyncio.sleep(1)
        
async def test2():
    while True:
        print("methode 2 zum ausfuhren")
        await asyncio.sleep(1)
    
def callback(queue,data, addr, ctrl):
    if data > 0:  # NEC protocol sends repeat codes.
        print('Data {:05x} Addr {:04x}'.format(data, addr))
        uasyncio.create_task(queue.put(val))
    
async def dispatcher(queue):
    task = None
    while True:
        command = await queue.get()
        if task:
            task.cancel()
        coro = task1() if command == 1 else task2()
        task = uasyncio.create_task(coro) 
 
async def main():
    command_queue = Queue()
    uasyncio.create_task(NEC_16(Pin(16, Pin.IN), callback))
    await dispatcher(command_queue)


if __name__ == '__main__':
    uasyncio.run(main())
__deets__
User
Beiträge: 14535
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich zeige doch mit dem lambda wie man einen callback baut, der die definierten zwei Argumente bekommt, UND die queue weitergibt.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ja das stimmt, aber der das die Callback-Funktion nur mit der Referenz aufgerufen werden soll 'NEC_16(Pin(16, Pin.IN), callback)' kann ich ja keine Argumente übergeben.
Oder kann ich das anders lösen?
__deets__
User
Beiträge: 14535
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nochmal: das geht genau so wie ich es vormache. Mit dem lambda.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Genau, so habe ich es auch gemacht.

Code: Alles auswählen

uasyncio.create_task(NEC_16 (lambda val, addr : callback(command_queue, val, addr)))
und die callback-Funktion

Code: Alles auswählen

def callback(queue, data, addr, ctrl):
    if data > 0:  # NEC protocol sends repeat codes.
        print('Data {:05x} Addr {:04x}'.format(data, addr))
        uasyncio.create_task(queue.put(val))
Leider funktioniert es so nicht.
__deets__
User
Beiträge: 14535
Registriert: Mittwoch 14. Oktober 2015, 14:29

“Funktioniert nicht” ist keine ordentliche Fehlermeldung.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Eine Fehlermeldung gibt es nicht, sondern wenn ich auf der Fernbedienung etwas drücke, gibt es keine Ausgabe, es müsste wenigstens eine Ausgabe erfolgen.

Kann das sein, das durch die lambda und den verbundenen Klammern für die callback-Funktion nicht die Referenz übergeben wird, sondern die Methode direkt ausgeführt wird?

Edit: hab mal den Pico neu gestartet, war wohl etwas festgefahren, jetzt kommt gibt es eine Fehlermeldung aus:

Code: Alles auswählen

Traceback (most recent call last):
  File "<stdin>", line 40, in <module>
  File "uasyncio/core.py", line 1, in run
  File "uasyncio/core.py", line 1, in run_until_complete
  File "uasyncio/core.py", line 1, in run_until_complete
  File "<stdin>", line 35, in main
TypeError: function takes 4 positional arguments but 3 were given

Code: Alles auswählen

import time
from machine import Pin
from ir_rx import NEC_16
import uasyncio
from queue import Queue

async def test1():
    while True:
        print("methode 1 zum ausfuhren")
        await asyncio.sleep(1)
        
async def test2():
    while True:
        print("methode 2 zum ausfuhren")
        await asyncio.sleep(1)
    
def callback(queue, data, addr,ctl):
    print("huhu")
    if data > 0:  # NEC protocol sends repeat codes.
        print('Data {:05x} Addr {:04x}'.format(data, addr))
        uasyncio.create_task(queue.put(val))
    
async def dispatcher(queue):
    task = None
    while True:
        command = await queue.get()
        if task:
            task.cancel()
        coro = task1() if command == 1 else task2()
        task = uasyncio.create_task(coro) 
 
async def main():
    command_queue = Queue()
   
    uasyncio.create_task(NEC_16 (lambda val, addr : callback(command_queue, val, addr)))
 #   ir = NEC_16(Pin(16, Pin.IN), callback)
    await dispatcher(command_queue)
    
if __name__ == '__main__':
    uasyncio.run(main())
  #  ir = NEC_16(Pin(16, Pin.IN), callback)

Antworten