Page 1 sur 1

Carte relais KC868 protocole TCP

Publié : 31 déc. 2019, 09:04
par ramirez22
Bonjour,

J'ai fais l'acquisition d'une carte 16 relais / 8 entrées sur Ethernet (Kincony).
J'ai téléchargé pas mal de doc ici, mais ils utilisent systématiquement les applicatifs qu'ils mettent à disposition et c'est pas facile d'en extraire l'essentiel (pour moi du moins).
Je pensais qu'une "simple" commande "http:// etc" suffirait à piloter la bête, mais que nenni !

En creusant un peu, je crois comprendre qu'il faut envoyer directement des trames TCP/IP.
Un petit coup de Wireshark donne quelques infos. Je me suis basé sur cette source pour faire le tri des données :
http://arsene.perez-mas.pagesperso-orange.fr/index.html.

Voici une trame d'envoi d'un ordre (je ne parle pas des acquittements pour l'instant, on verra plus tard si on arrive à quelque chose). J'ai indiqué entre () la taille en octet.
Entête de liaison :
MAC source (6o)
MAC destination (6o)
Type de protocole (2o) : IPv4
Paquet IPv4 (20o) : IPv4, protocole TCP, pas de vérification de checksum, IP source, IP destination
Paquet TCP (20o) : Port source, port destination, Nro séquence, Nro Acquit, flags, fenetre, checksum (non vérifié)
Et enfin les données (19o), qui correspondent à l'ordre à exécuter
RELAY-SET-1,1,1 (pour activer le relais 1).

Tout ça pour demander au final: comment envoyer les données (RELAY...) via domoticz ?

Etant "codeur du dimanche", si vous voulez/pouvez m'aider, je veux bien un coup de main, mais il va falloir être patient : je comprends vite mais faut expliquer longtemps :D

Au secours, vous êtes mon seul espoir ... (bon j'en rajoute OK, je sors...)

Re: Carte relais KC868 protocole TCP

Publié : 01 janv. 2020, 19:44
par ramirez22
Bonjour et meilleurs voeux !

Quelques éléments de réponses pour ceux qui se trouveraient dans la même situation.
Il est possible de communiquer de manière unidirectionnelle avec la carte (par de retour d'état) avec un script :

Code : Tout sélectionner

#!/bin/bash
echo -n RELAY-SET-1,1,1|nc adresse_ip port -N
Evidemment, remplacer adress_ip et port par vos valeurs :roll:
Le -N à la fin permet de fermer le socket de connexion ouvert par le script. Sinon, le premier ordre ne se terminera pas et les autres ne seront pas transmis.

Pour l'instant, j'ai créé les relais sur des dummy devices dont les actions ON et OFF sont associées à des scripts. L'inconvénient de cette méthode, c'est que l'on a pas le retour d'info. Si un problème est survenu, on ne le saura pas. L'état réel étant dissocié de l'état "mémorisé" par Domoticz, on peut se retrouver dans des situations problématiques.

De plus, pour ma part, comme il s'agit d'un système d'arrosage, je souhaite réaliser un "arrêt d'urgence" en cas de pilotage "à la main" de la pompe sans avoir au préalable ouvert une vanne. Et dans ce cas, je suis obligé d'exécuter le script directement dans les événements.

La liste des commandes utilisables sont dans les liens que j'ai indiqué dans mon post précédent. Je continue de creuser.

A+

Re: Carte relais KC868 protocole TCP

Publié : 02 janv. 2020, 12:27
par ramirez22
Bon, j'avance petit à petit.

Je rencontre quelques problèmes lorsque je veux réaliser plusieurs actions simultanément, par exemple si l'activation d'un relais doit en actionner un autre (cas d'un arrosage : l'activation d'une zone d'arrosage doit activer également la pompe).

Ceci doit être du fait que le socket (ou la carte) est occupé(e) par la première transaction. Du coup, la seconde ne passe pas. Si je mets une tempo, les 2 ordres sont bien exécutés.

Partant de là, il y a plusieurs possibilités :
- soit gérer par Domoticz les timings,
- soit envoyer les ordres de pilotages multiples
- soit développer un plugin pour la gestion de cette carte :lol:

l'un dans l'autre, ça va être casse-tête pour moi ...

Re: Carte relais KC868 protocole TCP

Publié : 18 mars 2020, 13:44
par ramirez22
Bonjour.
J'espère que tout le monde va bien dans le contexte actuel.
J'ai continué un peu mes investigations pour faire fonctionner cette carte.
Je suis parti sur un script Python avec les socket TCP, puisque c'est la méthode pour dialoguer avec cette carte. Je ne suis pas passé par Lua car luasocket n'est pas porté sous Lua5.2 (et je ne sais pas compiler). De plus, je n'utilise pas json car je trouve qu'il y a un délai de latence trop important.

A chaque appel, une trame d'initialisation est émise afin de s'assurer que la carte est bien en condition de fonctionner. La valeur passée au script correspond à la modification à apporter aux sorties. Par exemple, si les 8 sorties ont une valeur décimale de 129 (sortie 1 et 8 activées), et que la valeur passée est -128, il ne restera que la sortie 1 d'activée (valeur décimale 1).
La valeur 128 seule ne doit jamais être activée (comme il s'agit de la gestion d'un arrosage, il s'agit de la sortie de la pompe. Si aucune vanne est ouverte, ça craind !
Si la valeur 0 est passée, cela coupe la totalité des sorties.

Bref, voilà mon script python :

Code : Tout sélectionner

#!/usr/bin/python
# Script gérant la communication avec la carte relais KinCony

# ----- Import ------
import socket
import select
import sys

# ----- Variables Globales -----
port = 4196                     # KC868-H8's port
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)

# ----- Connexion au serveur TCP KinCony -----
socket_relais = socket.socket(socket.AF_INET,socket.SOCK_STREAM)    #Ebable ipv4 tcp/ip protocol
socket_relais.connect((host,port))
if debug == True:
        print('Connexion carte KinCony')                            #Connect with Server

# ----- 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))  #Send Initialization Command-1
attente_reponse = True
while attente_reponse:
        try:
                # Vérification de réception de quelque chose
                test = select.select([socket_relais], [], [], 1)
        except select.error:
                # Gestion des erreurs
                print('Erreur controle reception Init 1 carte Kincony')
                socket_relais.close()
                sys.exit()
        else:
                # Traitement en cas de reception de donnees
                msg_recu = socket_relais.recv(1024).decode()
                if debug == True:
                        print('Réception Init 1: ' + msg_recu)
                attente_reponse = False

# 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 carte : ' + msg_recu)
        socket_relais.close()
        sys.exit()

# ----- 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))         #Send Initialization Command-2
attente_reponse = True
while attente_reponse:
        try:
                # Vérification de réception de quelque chose
                test = select.select([socket_relais], [], [], 1)
        except select.error:
                # Gestion des erreurs
                print('Erreur controle reception Init 2 carte KinCony')
                socket_relais.close()
                sys.exit()
        else:
                #traitement en cas de reception de donnees
                msg_recu = socket_relais.recv(1024).decode()
                if debug == True:
                        print('Réception Init 2: ' + msg_recu)
                attente_reponse = False

# 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 carte')
        print(msg_recu)
        socket_relais.close()
        sys.exit()

# ----- Si la valeur transmise est égale à 0, RAZ des sortie -----
if valeur_passee == '0':
        if debug == True:
                print('Valeur tansmise = 0 : RAZ sorties')
        commande_tcp = 'RELAY-SET_ALL-1,0,0'
        if debug == True:
                print('Commande TCP: ' + commande_tcp)
        socket_relais.sendto(commande_tcp.encode(),(host,port))
# ----- 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))
        attente_reponse = True
        while attente_reponse:
                try:
                        # Vérification de réception de quelque chose
                        test = select.select([socket_relais], [], [], 1)
                except select.error:
                        # Gestion des erreurs
                        print('Erreur controle réception état sorties')
                        socket_relais.close()
                        sys.exit()
                else:
                        # Traitement en cas de réception de données
                        msg_recu = socket_relais.recv(1024).decode()
                        attente_reponse = False
        # 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')
                print(msg_recu)
                socket_relais.close()
                sys.exit()
        # 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))
        if debug == True:
                print('Valeur a appliquer: ' + commande_relais)
        if commande_relais == '128' or commande_relais == '-128':
                print('Valeur interdite (pompe seule)')
                socket_relais.close()
                sys.exit()
        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))
time.sleep(0.5)
socket_relais.close()                                               #DisConnect Socket

Le script fonctionne très bien depuis la console.
Je l'appelle depuis un script Lua avec trigger sur modif de variable (uservariables['Relais_arrosage']), qui est modifiée par chaque interrupteur via un json

json:

Code : Tout sélectionner

Code ON : http://192.168.1.32:8080/json.htm?type=command&param=updateuservariable&vname=Relais_arrosage&vtype=0&vvalue=1
Code OFF : http://192.168.1.32:8080/json.htm?type=command&param=updateuservariable&vname=Relais_arrosage&vtype=0&vvalue=-1

Les autres interrupteurs ont respectivement les valeurs (positives pour ON et négatives pour OFF) : 2, 4, 8, 16, 32, 64 et 128 pour la pompe (il s'agit simplement du 'poids' décimal de chaque bit du mot de sortie)
Lua:

Code : Tout sélectionner

commandArray = {}
    -- Gestion de la carte KinCony
    -- Si 'Relais_arrosage' == 0, il s'agit d'un arrêt général et le script python doit traiter cela comme tel
    IP_KinCony1 = '192.168.1.33'
    print("KinCony:Lancement du traitement de la IP "..IP_KinCony1)
    commande = ('python3 /home/pi/relais.py '..uservariables['Relais_arrosage']..' 192.168.1.33')
    print (commande)
    os.execute(commande)
return commandArray
En résumé : Lorsque j'appuie sur un interrupteur, la variable est modifiée, le script Lua est appelé, il transmet les info au script python et tout va bien.
Sauf que ...
1 - Je n'ai évidemment pas les log python dans le journal de domoticz. C'est pas le plus grave, je pense créer un log spécifique
2 - Si je crée cette séquence, j'ai une désynchronisation : acivation d'une vanne, activation de la pompe, désactivation de la vanne. En effet, la vanne s'active (pas de problème), la pompe s'actionne (elle peut car une vanne est ouverte), mais la vanne ne se coupe pas car on se retrouve dans un cas de figure interdit (pompe seule). Or Domoticz m'affiche bien la vanne désactivée. Je pourrais modifier le script pour que la vanne ET la pompe soient coupées. La sécurité fonctionnerait, mais la désynchronisation resterait d'actualité.

Je souhaiterais que mon scrypt Python puisse renvoyer une info à Lua (typiquement, l'état des sorties) pour que je puisse ensuite traiter l'affichage des état des interrupteurs.

Pouvez-vous m'aider SVP ?

Questions subsidiaires :
1 - Dans mon code Lua, dès qu'une variable utilisateur est mise à jour, mon script s'exécute. Pour l'instant, je n'ai qu'une variable utilisateur, mais à terme, j'en aurai peut-être plus. J'ai vu que pour les trigger sur changement d'état Device, il fallait tester chaque Device pour sortir au plus vite du script et ne traiter que le juste nécessaire. Comment faire cela avec les variables utilisateur ?
2 - Si vous voyez un autre moyen plus simple et réactif de faire fonctionner ma carte, je suis preneur de conseil et pistes diverses.

Cdt,
Ramirez22

Re: Carte relais KC868 protocole TCP

Publié : 19 mars 2020, 10:47
par ramirez22
Bonjour,

Bon, j'ai décidé de passer par du Json tout compte fait, afin de récupérer l'état des sorties et de synchroniser Domoticz avec le matériel. Cela génère un délai de chargement de 1 à 2 secondes du script mais tant pis.

Du coup, j'ai un autre problème qui apparait !

L'action sur un bouton déclenche mon script python (je ne passe plus par Lua). Les modifications sont apportées à mes sorties, je lis l'état de celles-ci et je lance une commande Json :

Code : Tout sélectionner

json.htm?type=command&param=switchlight&idx=' + idx + '&switchcmd=' + action
avec idx = l'idx de l'interrupteur que je veux mettre à jour et action = On ou Off en fonction de l'état de ma sortie et ce, pour chaque sortie (8 en tout).

Evidemment, à chaque mise à jour, 8 nouvelles instances du script sont appelées (8 'actions' sur les interrupteurs), avec les mise à jour de domoticz, qui re-crée de nouvelles mise à jour, de nouvelles instances ... ce qu'on appelle une réaction en chaine !

HELP ! Comment empêcher cela (si c'est possible) !

Cdt,
Ramirez.

Re: Carte relais KC868 protocole TCP

Publié : 19 mars 2020, 12:01
par ramirez22
Bon ben je crois que j'ai trouvé une solution.

Avec la fonction Json suivante :

Code : Tout sélectionner

json.htm?type=command&param=udevice&idx=' + idx + '&nvalue=' + action
avec idx = idx et action = 0 ou 1 en fonction de l'état,
l'interrupteur semble mis à jour sans déclencher le script associé.

Je lance un test de plus grande envergure et je vous tiens au courant :D

Re: Carte relais KC868 protocole TCP

Publié : 19 mars 2020, 18:58
par ramirez22
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 :lol:
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&param=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 :D ), et n'hésitez pas à formuler des remarques.

Cdt,
Ramirez22