Après plusieurs essais, je suis arrivé à quelque chose de pas trop mal (de mon point de vue).
Histoire d'en faire profiter la communauté, voici les éléments de réponse que j'ai trouvé. Si vous avez des optimisations à proposer, n'hésitez surtout pas : j'ai découvert le Python à l'occasion de ce projet et je patauge encore un peu
J'ai fais une mesure à la louche du temps d'exécution du script, avec requests, il s'exécute en 2.9 secondes, avec urllib3, je descend à moins de 1 seconde. Ce temps d'exécution est essentiellement dû au temps de chargement des imports (avant, sans faire la mise à jour de Domoticz, c'était quasi instantané). Le tout sur un raspberry-pi 3 + SSD sous stretch.
Voici le script "final" décortiqué (il suffit de coller les parties les unes après les autres pour le reconstituer).
Code : Tout sélectionner
# ----- Import ------
import socket
import select
import sys
import json
import urllib3
import time
# ----- Variables Globales -----
port = 4196 # Port KC868-H8
debug = True # Augmente les logs pour debuggage
valeur_relais = 0 # Valeur décimale réelle des 8 relais
valeur_passee = sys.argv[1] # Valeur a affecter aux relais (paramètre 1 du script Python)
host = str(sys.argv[2]) # Adresse de la carte (paramètre 2 du script Python)
if debug == True:
print ('Valeur passée = ' + valeur_passee)
print ('Adresse IP = ' + host)
Rien de bien compliqué là dessus, les import qui vont bien et quelques déclarations.
Code : Tout sélectionner
# ----- Connexion au serveur TCP KinCony -----
socket_relais = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # Protocole tcp/ip v4
socket_relais.settimeout(2) # Timeout de 2 secondes
socket_relais.connect((host,port))
if debug == True:
print('Connexion carte KinCony')
# ----- Initialisation communication : message 1 -----
commande_tcp = 'RELAY-SCAN_DEVICE-NOW'
if debug == True:
print('Commande TCP: ' + commande_tcp)
socket_relais.sendto(commande_tcp.encode(),(host,port)) # Envoi Initialisation 1
# Traitement des donnees reçues
msg_recu = socket_relais.recv(1024).decode()
if debug == True:
print('Réception Init 1: ' + msg_recu)
# Est-ce que le message reçu est conforme ?
if 'OK' in msg_recu:
if debug == True:
print('Init 1 OK')
else:
print('Erreur Initialisation 1: ' + msg_recu)
socket_relais.close()
sys.exit()
# Traiter la gestion de l'affichage de Domoticz ainsi que le log
# ----- Initialisation communication : message 2 -----
commande_tcp = 'RELAY-TEST-NOW'
if debug == True:
print('Commande TCP: ' + commande_tcp)
socket_relais.sendto(commande_tcp.encode(),(host,port)) # Envoi Initialisation 2
#traitement des donnees reçues
msg_recu = socket_relais.recv(1024).decode()
if debug == True:
print('Réception Init 2: ' + msg_recu)
# Est-ce que le message reçu est conforme ?
if 'HOST-TEST-START' in msg_recu:
if debug == True:
print('Init 2 OK')
else:
print('Erreur Initialisation 2: ' + msg_recu)
socket_relais.close()
sys.exit()
# Traiter la gestion de l'affichage de Domoticz ainsi que le log
Initialisation de la carte selon la doc constructeur. Le fait de le faire à chaque transmission permet de s'affranchir d'une perte d'alimentation sur la carte de sortie qui aurait réinitialisé l'état du module de communication.
Code : Tout sélectionner
# ----- Si la valeur transmise est égale à 0, RAZ des sortie -----
if valeur_passee == '0':
if debug == True:
print('Valeur tansmise = 0 : RAZ sorties')
commande_relais = '0'
# Sinon, calcul de la valeur à transmettre
else:
# Récupération de l'état des sorties
commande_tcp = 'RELAY-STATE-1'
if debug == True:
print('Commande TCP: ' + commande_tcp)
socket_relais.sendto(commande_tcp.encode(),(host,port))
# Traitement des données reçues
msg_recu = socket_relais.recv(1024).decode()
# Est-ce que le message reçu est conforme
if 'OK' in msg_recu:
if debug == True:
print('Réception état des sorties: ' + msg_recu)
else:
print('Erreur réception état des sorties: ' + msg_recu)
socket_relais.close()
sys.exit()
# Traiter la gestion de l'affichage de Domoticz ainsi que le log
# Extraction de la valeur de l'état des sorties
fin_valeur = msg_recu.find(',OK', 14)
valeur_relais = (msg_recu[14:fin_valeur]).split(',')[1]
if debug == True:
print('Valeur relais D0 : ' + valeur_relais)
# Calcul de la valeur à transmettre à la carte
commande_relais = str(int(valeur_relais) + int(valeur_passee))
Là, on rentre dans le vif du sujet, à savoir le traitement des valeurs transmises. Si la valeur = 0, on efface toutes les sorties. Sinon, on calcule la valeur à transmettre à la carte en fonction de son état précédent.
Code : Tout sélectionner
# ----- Pilotage de la carte -----
if debug == True:
print('Valeur a appliquer: ' + commande_relais)
if commande_relais == '128' or commande_relais == '-128':
print('Valeur interdite (pompe seule)')
commande_relais = '0'
commande_tcp = 'RELAY-SET_ALL-1,0,' + commande_relais
if debug == True:
print('Commande TCP: ' + commande_tcp)
socket_relais.sendto(commande_tcp.encode(),(host,port)) # Envoi commande de pilotage des sorties
Si seule la sortie de la pompe est activée, on annule tout car il y a un risque pour la pompe et le matériel (une sécurité type soupape de décharge est prévue dans mon cas, mais ça fait pas de mal de mettre une sécurité soft en plus d'une sécurité hard).
Code : Tout sélectionner
# ----- Mise à jour de Domoticz -----
r_http = urllib3.PoolManager()
etat_sortie = format(int(commande_relais),"08b") # convertit commande_relais en binaire
if debug == True:
print('Etat sorties: ' + etat_sortie)
liste_des_idx = ['1', '2', '3', '4', '5', '6', '7', '8'] # Liste des idx à mettre à jour, dans l'ordre
numero_de_bit = 7 # lecture des bits de la chaine dant l'ordre inverse (bit 0 à droite, bit 7 à gauche)
for idx in liste_des_idx:
if debug == True:
print('IDX en cours : ' + idx)
print('Numéro de bit en cours : ' + str(numero_de_bit))
print('Etat du bit en cours : ' + str(etat_sortie[numero_de_bit]))
commande_json = 'http://192.168.1.32:8080/json.htm?type=command¶m=udevice&idx=' + idx + '&nvalue=' + eta$
if debug == True:
print(commande_json)
# Envoi de la commande json
requete_json = r_http.request('GET', commande_json)
if debug == True:
print(requete_json.data)
if '"OK"' in str(requete_json.data):
if debug == True:
print('Envoi trame mise à jour Domoticz OK')
else:
print('Erreur envoi trame mise à jour Domoticz')
# Traiter la gestion de l'erreur, de l'affichage de Domoticz ainsi que le log
numero_de_bit = numero_de_bit - 1
#----- Fermeture de la connexion TCP -----
socket_relais.close()
Enfin, on met à jour les interrupteurs de Domoticz. En effet, si seule la pompe se retrouvait activée, le script aurait tout coupé et Domoticz aurait continué son petit bonhomme de chemin en pensant que la pompe était toujours activée. J'aurais pu traiter que la pompe, mais j'ai préféré mettre l'ensemble des valeurs afin d'être sûr que Domoticz sera toujours conforme à la réalité (sous réserve que la carte renvoie une info fiable).
Au niveau de chaque interrupteur, un appel du script :
Code : Tout sélectionner
Action ON : script:///home/pi/domoticz/scripts/python/relais.py 1 192.168.1.33
Action OFF : script:///home/pi/domoticz/scripts/python/relais.py -1 192.168.1.33
Sauf pour l'arrêt général où seul l'action OFF à 0 est programmé
Avec comme valeur les poids binaire de chaque sortie (1, 2, 4, 8, 16, 32, 64 et 128) en positif pour l'activation et en négatif pour la désactivation.
Il y a encore quelques trucs à améliorer, mais pour l'instant, cela correspond à mon besoin:
- Gestion du deuxième "mot" de sorties (pour l'instant, je ne gère que 8 sorties, ma carte en possède 16)
- Gestion des entrées (8 entrées Tout-ou-Rien)
- Ramener les Logs sous Domoticz (avec json, ça devrait le faire)
- Gestion d'une remise à zéro globale de la carte et de Domoticz (si coupure de courant au niveau de la carte, les sorties sont toutes coupées et Domoticz et donc désynchronisé. Peut-être un trigger basé sur le temps ...).
- Gestion de la perte de communication lors d'un scénario type cycle d'arrosage (est-ce que réinitialise tout et je recommence, est-ce que je reprends là ou je m'étais arrêté ...)
J'espère sincèrement que cela pourra aider quelqu'un qui pourrait être amené à utiliser le même type de matériel. Ces cartes sont bon marché, il en existe une multitude de modèles (2, 4, 8, 16 et 32 sorties relais inverseur (1 contact), avec ou sans entrées TOR, Ethernet ou Wifi ...).
Je vais essayer de continuer à développer sur cette carte les points ci-dessus. Je mettrai à jour ce post en fonction de mes résultats, si ça peut servir ...
Encore une fois, merci au forum pour l'aide qu'il m'a apporté (bon, OK, je me sent un peu seul sur ce post, mais je me suis pas mal inspiré sur d'autres posts

), et n'hésitez pas à formuler des remarques.
Cdt,
Ramirez22