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 …
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…
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 …
je pense pas que ca soit tellement un problème de garder le websocket ouvert
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
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
Mince je pensais avoir été clair mais c’est pas le cas apparemment
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.
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().
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 … ?
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 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.
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
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