Une bonne grosse pause dans un démon Python

Bonjour,

Je réfléchi à implémenter une bonne grosse pause (qui pourrait durer des semaines …) dans un démon Python. Vous feriez ça comment svp ?

Actuellement le principe de base du démon repose sur l’écoute permanente d’un serveur websocket et j’aimerais voir s’il n’est pas possible de suspendre cette connexion tant qu’une condition n’est pas satisfaite au niveau du plugin.

Le premier problème va être d’aller récupérer ce paramètre (qui va changer) mais sans redémarrer le démon donc ce n’est pas un paramètre à passer au moment du deamon_start(). Dans la suite je parle de parametre

Le deuxième problème c’est la bonne façon de faire cette boucle de vérification ?
Sachant que les actions actuelles du démon sont lancés par asyncio.get_event_loop().run_until_complete(run())

def main():
    while True:
        if parametre != 1:
        sleep 60   
    asyncio.get_event_loop().run_until_complete(run())

ça pourrait aller ? Mais il faudra aussi dans run() trouver le moyen de vérifier ce parametre pour revenir dans le main et attendre à nouveau qu’il passe à 1 …

Merci :slight_smile:

Salut,

Je suis un peu perplexe sur le « des semaines », je ne comprend pas le use case du coup je me dis qu’il y a p-e erreur sur l’approche globale?
c’est quoi le but?


sinon attention, ne jamais faire de sleep pur dans une « boucle async » mais plutôt await asyncio.sleep(60) pour laisser la main.

j’ai dans ma tête de proposer un nouveau template démon (en plus de celui qui existe) en full asyncio qui je pense est, la plupart du temps, moins lourd que d’ouvrir de multiple thread (dans le cas dans démon d’un plugin jeedom); mais ca fait déjà des mois que j’y pense sans avoir/prendre le temps de le faire…

Salut,

Faire une erreur, moi, non jamais :innocent: :rofl:

Comme je le disais, le démon écoute en permanence un serveur websocket tier pour blitzortung.

Et comme c’est franchement inutile et consommateur de ressources d’écouter un truc en sachant qu’il y a très peu de chance pour que ça arrive, je me dis qu’il pourrait être malin de rajouter un paramètre (disons le risque d’Orage issu d’un autre plugin) pour que le démon stop sa connexion au serveur tant qu’il n’y a pas le moindre risque d’orage dans la région. D’où la possibilité que ce soit pendant des semaines …

ok noté merci

Du coup qu’en penses-tu ?

je pense pas que ca soit tellement un problème de garder le websocket ouvert :slight_smile:


pour le moment tu as un socket ouvert pour pouvoir envoyer des ordres au démon ou pas?
pcq sinon tu vas avoir besoin de ca pour que le plugin puisse envoyer l’ordre d’ouvrir ou fermer le websocket donc échanger un websocket contre un autre ca va pas changer grand chose

Bonjour,

Voir du côté des event

ça pourrait donner un truc comme ça :

async def main():
  my_event=asyncio.Event()
  ...
  asyncio.get_event_loop().run_until_complete(run(my_event))
  ...

async def run(my_event):
  ....
  while True:
     my_event.wait()
     ...

Et quelque part ailleurs :

  my_event.set() # pour déploquer run()

  my_event.clear() # pour le remettre en attente

Franchement si, je parle d’une connexion websocket entre Jeedom (client) et un serveur distant (blitzortung) qui envoi des données de façon massive tout le temps.
Il serait donc mieux que cette connexion ne soit pas maintenu active pour rien et utiliser un moyen pour exécuter le websockets.connect quand c’est nécessaire.

Non, j’utilise juste la base du plugin template et j’ai ajouté l’appel à la fonction main dans listen

def listen():
	jeedom_socket.open()
	try:
		while 1:
			time.sleep(0.5)
			main()
	except KeyboardInterrupt:
		shutdown()

@tomdom, merci … pour une première lecture j’ai rien compris, je vais prendre le temps de re-relire et explorer ce que tu indiques

du coup je ne comprend plus:

du coup il envoi des données ou pas? :upside_down_face:

sinon tu peux pas filtrer au niveau blitzortung lui demander que les infos utiles pour la région?

Mince je pensais avoir été clair mais c’est pas le cas apparemment :laughing:

Oui le serveur envoi des données en permanance car ça remonte dès qu’il y a un impact dans le monde.

Il n’y a apparemment pas de moyen de filtrage en amont malheuresement sinon j’aurais commencé par là.

Et c’est pourquoi j’aimerais que le client (le démon) stop sa connexion websocket s’il n’y a pas vraiment lieu de récupérer quelque chose parce qu’il n’y aurait aucun risque d’orage dans sa région. A ce moment là pas besoin de laisser le websocket à l’écoute pour rien. On se fou des impacts au Brésil si rien n’est annoncé en Belgique et donc ça consomme des ressources de traitement Python pour rien.

J’ai été plus clair ? :slight_smile:

ah oui d’accord :sweat_smile:

SI je pars sur ce que tomdom a proposé, l’idéal, je pense, serait de déclencher ces « set » et « clear » depuis Jeedom en php (au travers d’un simple cron par exemple, ce qui simplifierait aussi la récupération de ce fameux paramètre (déclencheur du GO / NOGO au démon).

Mais comment faut-il communiquer avec le démon depuis php pour lui envoyer des messages une fois le démon démarré ? Pour le moment, vous l’avez compris, la communication est dans l’autre sens, du démon vers Jeedom avec send_immediate().

reprend la fonction listen du template de base et la doc sur les démons, j’explique comment envoyer des instructions au démon

Ah, ok je me souvenais pas que tu en avais parlé, merci je regarde ça en fin de journée :+1:

Alors j’essaye d’y aller petit bout par petit bout.

J’ai donc transformé un poil pour être aligné avec la doc :

def read_socket():
    global JEEDOM_SOCKET_MESSAGE
    if not JEEDOM_SOCKET_MESSAGE.empty():
        logging.debug("Message received in socket JEEDOM_SOCKET_MESSAGE")
        message = json.loads(jeedom_utils.stripped(JEEDOM_SOCKET_MESSAGE.get()))
        if message['apikey'] != _apikey:
            logging.error("Invalid apikey from socket : " + str(message))
            return
        try:            
            logging.info("test event")
            if message['event'] == "start":
                 logging.info("Message to start")
                 main()            
        except Exception as e:
            logging.error('Send command to demon error : '+str(e))

def listen():
	jeedom_socket.open()
	try:
		while 1:
			time.sleep(0.5)
			read_socket()
	except KeyboardInterrupt:
		shutdown()

Depuis la fonction de refresh j’appelle ta fonction sendToDaemon de cette façon : $eqLogic->sendToDaemon(array('event' => 'start'));

Le message est bien reçu mais le démon plante :

20354|[2023-08-24 19:31:38]INFO : Client connected to [127.0.0.1:41232]
20355|[2023-08-24 19:31:38]INFO : Message read from socket: b'{"event":"start","apikey":"....."}'
20356|[2023-08-24 19:31:38]INFO : Client disconnected from [127.0.0.1:41232]
20357|[2023-08-24 19:31:38]ERROR : Fatal error : sequence item 0: expected str instance, int found

La clef API apparait bien comme il faut, le event « start » sur je cherche à faire passer aussi apparemment, mais la lecture de message semble poser problème, je trouve pas la bonne façon de lui passer l’info et ne voit pas bien où il y a un int … ?

1 « J'aime »

Bon ben du coup je comprends rien, en fait ça plante avant le passage par le read_socket puisque je n’ai même pas cette ligne dans les logs : logging.debug("Message received in socket JEEDOM_SOCKET_MESSAGE")

Celle qui apparait est celle de la fonction handle(self) de jeedom.py

Je vais avoir besoin d’aide :slight_smile:

J’ai noté un rappel pour demain, plus possible ce soir

Salut,

je suis ce post depuis le début, par curiosité… Dans MyModbus bêta, j’utilise les communications dans les 2 sens (core → démon et démon → core) et je me souviens vaguement d’avoir adapté la lib jeedom.py, mais je ne sais plus quoi.
Je te suggère de regarder comment c’est fait, peut-être trouveras-tu l’inspiration ?

Je continue d’espionner ce post, si jamais tu as une question sur le principe de MyModbus.
:ninja:

Salut,

C’est la fonction stripped de jeedom.py qui pose problème ici. J’ai été voir sur jmqtt mais j’ai pas repéré de modification de cette fonction et il utilise aussi la fonction que Mips utilise en l’ayant modifiée mais pas sur le traitement de params et de ce qui envoi le payload. Du moins j’ai rien vu.

Aujourd’hui je n’aurais pas environnement de dev sous la main avant ce soir donc pas d’accès à mymodbus bêta avant ce soir mais si tu as une idée, n’hésite pas :smile:

Ah oui faut corriger la fonction sous python3

Faudrait refaire un passage sur le template pour le python

Faut corriger dans jeedom.py ? Mais quoi donc ? J’ai pas compris l’enchaînement de ce qui est fait dans cette boucle en python

Clairement intéressé pour mon plugin atvremote !

J’ai pas beaucoup fait de python et les infos sur asyncio sont pas très claires en ligne je trouve… (comment mixer deux connexions (jeedom + api constructeur) + gérer les évents des deux côtés dans un python de type daemon). Mais j’ai vu que tu le faisais déjà pour Worx donc je comptais analyser ça