IdentifiantMot de passe
Loading...
Mot de passe oubli� ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les r�ponses en temps r�el, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Enregistrer des donn�es Compteurs avec pyModbusTCP dans MySQL


Sujet :

Python

  1. #1
    Membre confirm�
    Homme Profil pro
    Dessinateur industriel
    Inscrit en
    F�vrier 2021
    Messages
    90
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 41
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activit� : Dessinateur industriel
    Secteur : Industrie

    Informations forums :
    Inscription : F�vrier 2021
    Messages : 90
    Par d�faut Enregistrer des donn�es Compteurs avec pyModbusTCP dans MySQL
    Bonjour,
    Je fait un applicatif de suivi de consommations de compteurs d'eau qui va tourner sur un serveur local Linux (RPI ou �quivalent).
    J'ai d�couvert le PHP et r�alis� l'interface utilisateur et jusqu'� maintenant j'ai simul� des index compteurs manuellement dans MySQL. J'aimerai donc passer � la partie la plus importante : Communiquer avec le mat�riel (compteurs) et r�cup�rer leurs valeurs d' "index".
    Ces index compteurs sont dans un automate programmable qui est client Modbus TCP et me permet de lire les valeurs (Ce que je fait sans soucis depuis mon PC avec ModbusDoctor)

    La fr�quence "d'acquisition" est d�finie par l'utilisateur 15, 30, 45 min et stock�e dans une table MySQL.
    L'adresse IP, le port de l'automate et le registre Modbus du compteur 1 sont eux aussi d�fini par l'utilisateur et stock�s dans une table.
    Il y a m�me plusieurs compteurs, donc � chaque fois IP, Port, Registre... Chaque compteur � un ID unique

    Pour la partie communication, j'ai trouv� la librairie pyModbus :
    Exemple lecture de registres : https://pymodbustcp.readthedocs.io/e..._register.html
    Exemple Tache cyclique : https://pymodbustcp.readthedocs.io/e..._schedule.html
    Et un dernier adapt� � mon besoin mais fait pour une application de domotique : https://github.com/DomoticX/domoticz-modbus
    mais je n'ai aucune id�e de comment adapter ces exemples � mon projet :

    1. 1) Lire la "fr�quence d'acquisition" dans la base de donn�es.
    2. 2) Se connecter aux �quipements et r�cup�rer les index dans les bons registres
    3. 3) Ins�rer les valeurs dans MySQL en lien avec leur ID.
    4. 4) Faire en sorte que cela tourne en tache de fond pour se reproduire � la bonne fr�quence d'acquisition


    Je part de 0, je ne suis pas du m�tier (dessinateur industriel / automaticien), j'ai d�couvert html, php et mysql sur ce projet, j'en arrive � Python mais cette fois j'ai besoin d'un (gros) coup de pouce pour me montrer le bon chemin � suivre.
    Merci de votre aide.

  2. #2
    Expert �minent
    Homme Profil pro
    Architecte technique retrait�
    Inscrit en
    Juin 2008
    Messages
    21 772
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activit� : Architecte technique retrait�
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 772
    Par d�faut
    Salut,

    Citation Envoy� par makimax Voir le message
    Je part de 0, je ne suis pas du m�tier (dessinateur industriel / automaticien), j'ai d�couvert html, php et mysql sur ce projet, j'en arrive � Python mais cette fois j'ai besoin d'un (gros) coup de pouce pour me montrer le bon chemin � suivre.
    Si on ne dispose pas des �quipements, on ne pourra pas tester...

    Si on ne peut pas tester, on devra se contenter de faire une lecture (intelligente � d�faut d'active) des diff�rents articles trouv�s ici ou l� et des documentations et vous pousser du code � tester.

    Et si vous ne savez pas trop programmer, �a ne va pas �tre facile de r�cup�rer les informations pertinentes pour comprendre ce qu'il se passe (parce qu'on ne se d�place pas!).

    Le mieux serait de trouver un club d'informatique dans votre localit� pour �changer de vive voix avec des qui pourront se d�placer au cas o�...

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre confirm�
    Homme Profil pro
    Dessinateur industriel
    Inscrit en
    F�vrier 2021
    Messages
    90
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 41
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activit� : Dessinateur industriel
    Secteur : Industrie

    Informations forums :
    Inscription : F�vrier 2021
    Messages : 90
    Par d�faut
    Citation Envoy� par wiztricks Voir le message
    Salut,
    Si on ne dispose pas des �quipements, on ne pourra pas tester... - W
    Il n'y a pas n�cessairement besoin d'�quipement, moi m�me j'avance dans mon projet sans le mat�riel, j'ai juste un Apache + MySQL et un Simulateur Modbus.

    Si on ne peut pas tester, on devra se contenter de faire une lecture (intelligente � d�faut d'active) des diff�rents articles trouv�s ici ou l� et des documentations et vous pousser du code � tester.
    C'est justement cela que je cherche, des propositions de morceaux de code d'ici ou l�.

    Et si vous ne savez pas trop programmer, �a ne va pas �tre facile ...
    Je suis assez d�brouillard, la preuve en ayant fait le frontend en partant de 0 et ne connaissant ni html, ni php, ni mySQL.

    Je sais qu'il faut que je commence par un script qui se lance au d�marrage, qui se connecte � la base de donn�es et qui fait un SELECT des param�tres pour l'�tape suivante (r�cup�rer la fr�quence d'acquisition et les diff�rentes adresses des compteurs � r�cup�rer).
    D�j� si quelqu'un peut me guider comment commencer cela. La connexion � la base, je le fait pour l'utilisateur dans un fichier php, j'imagine qu'il faut reprendre cette partie. Et ensuite les requ�tes de SELECT, je saurais les faire puisque j'en ai aussi en PDO en PHP, mais j'imagine que ce n'est pas �crit de la m�me fa�on.

    Ensuite, cela sera l'�tape de connexion, je m'inspirerai des exemples cit�s.

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ing�nieur d�veloppement logiciels
    Inscrit en
    F�vrier 2006
    Messages
    12 850
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activit� : Ing�nieur d�veloppement logiciels
    Secteur : A�ronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : F�vrier 2006
    Messages : 12 850
    Billets dans le blog
    1
    Par d�faut
    Bonjour
    Citation Envoy� par makimax Voir le message
    D�j� si quelqu'un peut me guider comment commencer cela. La connexion � la base, je le fait pour l'utilisateur dans un fichier php, j'imagine qu'il faut reprendre cette partie. Et ensuite les requ�tes de SELECT, je saurais les faire puisque j'en ai aussi en PDO en PHP, mais j'imagine que ce n'est pas �crit de la m�me fa�on.
    Les m�canismes d'interrogation d'une bdd MySQL (ou Postgres ou n'importe quelle autre) se font toujours de la m�me fa�on
    • on cr�e une instance connexion � partir d'une librairie d�di�e � interfacer le langage. Cette instance re�oit les divers param�tres comme le nom de la bdd, le login, le mot de passe, etc.
    • cette instance (un objet) une fois connect�e poss�de une fonction de cr�ation de curseur. Un curseur c'est l'outil d�di� au requ�tage SQL. Donc on cr�e le curseur (c'est bien souvent curs=connect.cursor(), "connect" �tant l'instance de connexion). Et ce curseur pourra ensuite envoyer des requ�tes SQL (curs.execute(requete)). Et pour la s�lection, ce sera un curs.execute("select ...") suivi d'un res=curs.fetchone() si la requ�te ne renvoie qu'un r�sultat ou res=curs.fetchall() si elle en renvoie plusieurs. Certaines librairies bdd poss�dent m�me parfois des outils o� la requ�te est claqu�e dans un dictionnaire (si la table contient "nom", "prenom" alors le r�sultat est claqu� dans un dico contenant une clef "nom" et une clef "prenom" ce qui est ensuite assez pratique pour le manipuler)
    • quand on a fini de manipuler, on ferme le curseur et quand on a fini de travailler sur la bdd on ferme la connexion


    Bon le souci c'est que je suis plus sp�cialis� dans Postgres donc je ne connais pas trop les librairies Python/MySQL (il y a souvent beaucoup de librairies d�di�es � une m�me technologie donc il faut essayer de taper dans celle destin�e � survivre) mais j'ai trouv� cette page qui parle de pymysql avec diff�rents exemples. Et comme on peut voir "python36" dans certaines copies d'�cran cela signifie que le truc n'est pas super vieux.

    En fait, Python c'est un peu comme une grosse pieuve. D'un c�t� un tentacule pour modbus, un autre tentacule pour MySQL et lui au centre il r�cup�re tout �a et fait sa salade. Puis il renvoie le r�sultat soit sur un autre support (mail, fichier, etc) soit �a repart dans MySQL. Avec possibilit� ensuite d'enrichissement. Si par exemple tu inclus le module configparser (qui permet de lire et d'�crire un fichier type ".ini") alors tu pourras y mettre tes param�tres de connexion ce qui t'�vite de le mettre en dur dans ton code. Donc un 3� tentacule qui commence par r�cup�rer les infos du ini et qui sont alors utilis�es par le tentacule MySQL etc etc etc.
    Plus tu s�pares bien les choses plus �a sera pratique � maintenir et � faire �voluler si demain les technos changent...
    Mon Tutoriel sur la programmation �Python�
    Mon Tutoriel sur la programmation �Shell�
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les diff�rentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Membre confirm�
    Homme Profil pro
    Dessinateur industriel
    Inscrit en
    F�vrier 2021
    Messages
    90
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 41
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activit� : Dessinateur industriel
    Secteur : Industrie

    Informations forums :
    Inscription : F�vrier 2021
    Messages : 90
    Par d�faut
    Merci Sve@r, je vais tenter de ce c�t� ! je ne pensait pas qu'il fallait une librairie pour mySQL, donc PyMySQL dans un premier temps et suivre les exemples pour lire une valeur dans une table.
    claqu� dans un dico contenant une clef "nom" et une clef "prenom" ce qui est ensuite assez pratique pour le manipuler
    Cela ressemble �norm�ment au php, avec le FetchAll(FETCH ASSOC) qui "claque" la r�ponse dans un Array, donc tr�s pratique.

    Merci pour le conseil de bien dissocier les �tapes, je suis dans cette optique aussi, encore faut-il que je r�ussisse chacune individuellement ^^.

    Citation Envoy� par wiztricks Voir le message
    Salut,
    Le mieux serait de trouver un club d'informatique dans votre localit� pour �changer de vive voix avec des qui pourront se d�placer au cas o�...
    J'ai un FabLab � proximit� mais je n'y ai jamais mis les pieds, je ne sais pas si c'est le genre de projet qui peut �tre aborder. Je vais essayer de les contacter.

  6. #6
    Expert �minent
    Homme Profil pro
    Architecte technique retrait�
    Inscrit en
    Juin 2008
    Messages
    21 772
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activit� : Architecte technique retrait�
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 772
    Par d�faut
    Citation Envoy� par makimax Voir le message
    Il n'y a pas n�cessairement besoin d'�quipement, moi m�me j'avance dans mon projet sans le mat�riel, j'ai juste un Apache + MySQL et un Simulateur Modbus.
    Vous croyez que tout le monde a ce genre de trucs install� sur son PC et sait s'en servir juste parce qu'il sait programmer avec Python?

    Citation Envoy� par makimax Voir le message
    Je suis assez d�brouillard, la preuve en ayant fait le frontend en partant de 0 et ne connaissant ni html, ni php, ni mySQL.

    Je sais qu'il faut que je commence par un script qui se lance au d�marrage, qui se connecte � la base de donn�es et qui fait un SELECT des param�tres pour l'�tape suivante
    Mouais, si vous aviez pris l'initiative de chercher avec les mots clefs "python mysql" vous auriez trouv� la documentation de biblioth�ques qui permettent de... et les exemples qui vont avec.

    En g�n�ral, l'utilisation des bases de donn�es depuis Python se fait avec une interface assez homog�ne bas�e sur la biblioth�que sqlite3 (qui est standard).
    Tous les bons tutos ont un chapitre qui explique comment �� marche.

    Citation Envoy� par makimax Voir le message
    C'est justement cela que je cherche, des propositions de morceaux de code d'ici ou l�.
    Il y en a plein sur Internet! (et vous en avez trouv�).

    Apr�s le soucis est de comprendre ce qu'ils font et de voir en quoi ils sont int�ressants pour faire ce que vous voulez vous (et on n'est pas dans votre t�te donc on ne sait pas vraiment trier).

    Je sais qu'il faut que je commence par un script qui se lance au d�marrage, qui se connecte � la base de donn�es et qui fait un SELECT des param�tres pour l'�tape suivante (r�cup�rer la fr�quence d'acquisition et les diff�rentes adresses des compteurs � r�cup�rer).

    Citation Envoy� par makimax Voir le message
    D�j� si quelqu'un peut me guider comment commencer cela. La connexion � la base, je le fait pour l'utilisateur dans un fichier php, j'imagine qu'il faut reprendre cette partie. Et ensuite les requ�tes de SELECT, je saurais les faire puisque j'en ai aussi en PDO en PHP, mais j'imagine que ce n'est pas �crit de la m�me fa�on.

    Ensuite, cela sera l'�tape de connexion, je m'inspirerai des exemples cit�s.
    Si vous n'avez que la connexion � la base comme probl�me, vous savez qu'il n'est pas insoluble. Vous pouvez commencer le reste en simulant la r�cup�ration de l'identifiant par une simple saisie clavier... et revisiter l'aspect BDD plus tard.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ing�nieur d�veloppement logiciels
    Inscrit en
    F�vrier 2006
    Messages
    12 850
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activit� : Ing�nieur d�veloppement logiciels
    Secteur : A�ronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : F�vrier 2006
    Messages : 12 850
    Billets dans le blog
    1
    Par d�faut
    Citation Envoy� par makimax Voir le message
    Merci pour le conseil de bien dissocier les �tapes, je suis dans cette optique aussi, encore faut-il que je r�ussisse chacune individuellement ^^.
    Python poss�de un m�canisme assez int�ressant permettant de tester ses propres modules individuellement afin de les valider : la variable "__name__".

    Un module c'est un truc qui fait un travail et que l'on peut importer ensuite dans son programme. On a alors acc�s � la (ou les) fonctions du module. Ce module �a peut-�tre un simple script ou m�me un dossier.

    Imaginons que tu veuilles cr�er un module de math que tu appelles "math.py" dont le code pourrait �tre le suivant
    Code python : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    #!/usr/bin/env python3
    # coding: utf-8
     
    def carre(n): return n*n

    Tu veux maintenant v�rifier que ton script "math.py" et surtout sa fonction "carre" fonctionne. Tu pourrais rajouter en fin de script print(carre(5)).
    Le souci, c'est que d�s que ton module "math.py" sera import�, le print() sera ex�cut� ce qui est au minimum d�rangeant.

    Pour �viter ce souci tout en voulant garder ton test unitaire, tu rajoutes en fin de script
    Code python : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    if __name__ == "__main__":
    	print(carre(5))
    	... (tes autres tests éventuels)
    # if

    Cette variable interne Python "__name__" a un comportement diff�rent selon l'utilisation du script. Si le script est import�, alors elle prend le nom de l'import comme contenu. Mais si le script est directement ex�cut�, alors elle prend la string "__main__".
    Donc tu veux tester ton module, tu appelles python3 math.py et tu verras tous tes tests se faire et tu pourras corriger ce qui ne va pas. Puis ton module �tant fiabils�, il peut alors �tre import� dans ton programme sans souci et sans que les tests ne soient fait de nouveau.

    Et pour l'utilisation de ton module, te suffit de mettre import math dans un programme pour que ce programme ait acc�s � la fonction "carre()" sous le nom math.carre(). Ou alors from math import carre ou m�me from math import * et l� les fonctions du fichier "math.py" sont directement import�es dans l'espace de nom de ton code donc "carre()" se nomme alors directement carre() (plus attrayant mais aussi plus dangereux si plusieurs modules distincts ont des fonctions de m�me nom). Et l� enfin le projet commence � s'articuler...
    Mon Tutoriel sur la programmation �Python�
    Mon Tutoriel sur la programmation �Shell�
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les diff�rentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    Expert �minent
    Homme Profil pro
    Architecte technique retrait�
    Inscrit en
    Juin 2008
    Messages
    21 772
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activit� : Architecte technique retrait�
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 772
    Par d�faut
    Salut,

    Citation Envoy� par Sve@r Voir le message
    Et l� enfin le projet commence � s'articuler...
    D�couper le probl�me en fonctions qui r�alisent les diff�rentes �tapes mentionn�es telles que:
    1) Lire la "fr�quence d'acquisition" dans la base de donn�es.
    2) Se connecter aux �quipements et r�cup�rer les index dans les bons registres
    3) Ins�rer les valeurs dans MySQL en lien avec leur ID.
    4) Faire en sorte que cela tourne en tache de fond pour se reproduire � la bonne fr�quence d'acquisition
    quitte � simuler certaines qui paraissent difficiles comme r�cup�rer la fr�quence d'acquisition par le retour d'une constante ou le choix al�atoire dans une liste ou l'�criture des valeurs par des "print" simples permet d'avancer c�t� "structure" et "articulation".

    Comme on part de rien... on peut tout avoir dans un m�me script et tester le bon d�roulement de la s�quence des op�rations.

    Apr�s on peut ajouter de la viande autour de ce squelette en �toffant une op�ration particuli�re. Il pourra alors �tre utile de d�couper la fonction initiale en sous fonctions.

    Une fois satisfait du r�sultat voir comment pousser la chose dans un module (mais ce n'est pas n�cessaire) en ouvrant un tuto qui raconte comment �� marche pour isoler ce tas l� du reste qui est en chantier...

    Et comme on a pris le soin de d�couper son probl�me, en cas de difficult�s on pourra plus facilement demander de l'aide en postant un code qui permet de le reproduire (sans avoir � palabrer sur le contexte puisque le code suffit) apr�s avoir cherch� sur Internet.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  9. #9
    Membre confirm�
    Homme Profil pro
    Dessinateur industriel
    Inscrit en
    F�vrier 2021
    Messages
    90
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 41
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activit� : Dessinateur industriel
    Secteur : Industrie

    Informations forums :
    Inscription : F�vrier 2021
    Messages : 90
    Par d�faut
    Merci � vous deux pour vos conseils,

    J'ai install� la librairie pyMySQL et tent� la connexion � la base de donn�e et une requ�te simple avec print du r�sultat. Cela � fonctionner du premier coup. Je pouvais en effet consid�r� que c'�tait bon d'avance et simuler pour passer la suite j'ai souhait� d�marr� sur une partie en th�orie simple.

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import pymysql.cursors
     
    # Connect to the database
    connection = pymysql.connect(host='127.0.0.1',
                                 user='root',
                                 password='',
                                 database='database',
                                 charset='utf8mb4',
                                 cursorclass=pymysql.cursors.DictCursor)
     
    with connection:
        with connection.cursor() as cursor:
            # Read a single record
            sql = "SELECT `dev_id`, `dev_name` FROM `devicestatus` WHERE `dev_used`= 1"
            cursor.execute(sql,)
            result = cursor.fetchall()
            print(result)
    J'obtient un r�sultat sous cette forme :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    [{'dev_id': 7, 'dev_name': 'Compteur 07'}, {'dev_id': 8, 'dev_name': 'Compteur 08'}, {'dev_id': 9, 'dev_name': 'Compteur 09'}, {'dev_id': 10, 'dev_name': 'Compteur 10'}, {'dev_id': 11, 'dev_name': 'Compteur 11'}, {'dev_id': 12, 'dev_name': 'Compteur 12'}]
    J'ai install� la librairie pyModbus. J'ai d�marr� un soft qui simule un �quipement modbus et saisie une valeur dans le registre 100. Pour v�rifier que cela fonctionne avant de me lancer dans python, j'ai tester de lire ce registre avec l'utilitaire client : ModbusDoctor, de ce c�t�, c'�tait bon j'ai r�cup�r� ma valeur 123 dans le registre 100.
    J'ai r�cup�r� des examples de script pour faire un "ReadHoldingRegisters" avec python et je n'ai eu que des erreurs. J'ai fini par r�ussir en rempla�ant l'utilitaire simulateur par un soft d'automate gratuit que j'ai pass� en simulation (MachineExpertBasic) et ensuite c'�tait bon. J'ai pu r�cup�rer ma valeur 123 de ce registre 100.

    Avec le bout de script, je r�cup�re une 'liste' (si je ne me trompe pas sur le terme) avec � l'int�rieur des entier de 16bits. Si j'ai demand� une lecture du registre 100 et d'une longueur de 2, j'ai donc [123, 0] en r�sultat. Dans mon cas la valeur d'index du compteur est un mot de 32bit non sign�, j'ai donc trouv� un bout de code qui remet en forme le r�sultat lorsqu'il utilise les 2 int.

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    from pymodbus.constants import Endian
    from pymodbus.payload import BinaryPayloadDecoder
    from pymodbus.client.sync import ModbusTcpClient
     
    def validator(instance):
        if not instance.isError():
            '''.isError() implemented in pymodbus 1.4.0 and above.'''
            decoder = BinaryPayloadDecoder.fromRegisters(
                instance.registers,
                byteorder=Endian.Big, wordorder=Endian.Little
            )   
            return format(decoder.decode_32bit_uint())
     
        else:
            # Error handling.
            print("There isn't the registers, Try again.")
            return None
     
    # Paramètres pour la connexion au matériel Modbus TCP
    Setting_TCP_IP = '127.0.0.1'
    Setting_TCP_PORT = 502
    Setting_Device_ID = 1
     
    # Connexion au matériel Modbus TCP
    client = ModbusTcpClient(host=Setting_TCP_IP, port=Setting_TCP_PORT, auto_open=True, auto_close=True, timeout=2)  # Specify the port.
    connection = client.connect()
     
    # Paramètres pour la lecture des registres du matériel Modbus TCP
    Setting_Register_Number = 100
    Register_Count = 2
     
     
    if connection:
        request = client.read_holding_registers(Setting_Register_Number, Register_Count, unit=1)  # Specify the unit.
        # Afficher le résultat décodé en Entier de 32 Bits non signé
        data = validator(request)
        print(data)
        # Afficher le résultat brut
        result = request.registers
        print(result)
     
        client.close()
     
    else:
        print('Connection lost, Try again')
    Si je simule un index de 777777, j'otiens les 'print' suivant :
    Le premier est d�cod�., le second non, c'est la liste des 2 uint16

    j'ai donc pour le moment deux parties (mysql et modbus), aucun lien entre elles mais le but c'est que le r�sultat de la requ�te en partie 1 sert de param�tres pour la r�cup�ration d'index en partie 2.

    Si j'ai bien saisie vos remarques sur le scindement des fonctions, j'aurais donc une 1�re fonction connexion, une 2de pour la requ�te pour avoir la liste des compteurs et de leur param�tres et registres � aller chercher, puis une boucle pour chaque compteur : 3� fonction : la lecture en utilisant les param�tres et registres, 4� fonction : �crire dans la base de donn�es fin de boucle

    Dans un example de code qui m'int�resse il utilise par exemple : self.address, ou sefl.port, l� ou moi je met address

  10. #10
    Expert �minent
    Homme Profil pro
    Architecte technique retrait�
    Inscrit en
    Juin 2008
    Messages
    21 772
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activit� : Architecte technique retrait�
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 772
    Par d�faut
    Salut,

    Citation Envoy� par makimax Voir le message
    Si j'ai bien saisie vos remarques sur le scindement des fonctions, j'aurais donc une 1�re fonction connexion, une 2de pour la requ�te pour avoir la liste des compteurs et de leur param�tres et registres � aller chercher, puis une boucle pour chaque compteur : 3� fonction : la lecture en utilisant les param�tres et registres, 4� fonction : �crire dans la base de donn�es fin de boucle
    Vous n'�tes pas oblig� de d�couper votre code en "fonctions" et le garder comme une seule s�quence d'instructions.

    On essaie juste de vous sugg�rer de "bonnes pratiques"... ouvrir un tuto. pour apprendre les bases en fait partie. Et si vous ne voulez pas vous y appliquer, c'est votre choix. Mais au plus votre code deviendra "compliqu�" au plus il sera difficile de vous aider... d'autant qu'il sera visible que vous ne vous �tes pas donn� les moyens de vos ambitions.

    Citation Envoy� par makimax Voir le message
    Dans un example de code qui m'int�resse il utilise par exemple : self.address, ou sefl.port, l� ou moi je met address
    self.port est un attribut d'instance, port est une variable,... c'est dans tous les tutos.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  11. #11
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ing�nieur d�veloppement logiciels
    Inscrit en
    F�vrier 2006
    Messages
    12 850
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activit� : Ing�nieur d�veloppement logiciels
    Secteur : A�ronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : F�vrier 2006
    Messages : 12 850
    Billets dans le blog
    1
    Par d�faut
    Citation Envoy� par makimax Voir le message
    Si j'ai bien saisie vos remarques sur le scindement des fonctions, j'aurais donc une 1�re fonction connexion, une 2de pour la requ�te pour avoir la liste des compteurs et de leur param�tres et registres � aller chercher, puis une boucle pour chaque compteur : 3� fonction : la lecture en utilisant les param�tres et registres, 4� fonction : �crire dans la base de donn�es fin de boucle
    Il s'agit de scinder les domaines, pas les fonctions. Les fonctions ne sont que des outils de travail.
    Si par exemple dans le domaine bdd il est n�cessaire de s�parer "connexion" de "requ�tage" (parce que par exemple il y aura plusieurs requ�tes mais une seule connexion) alors oui s�parer les deux est utile. Sinon �a ne l'est pas.

    Citation Envoy� par makimax Voir le message
    Dans un example de code qui m'int�resse il utilise par exemple : self.address, ou sefl.port, l� ou moi je met address
    Probablement que l'exemple en question est bas� sur les objets et les classes...
    Mon Tutoriel sur la programmation �Python�
    Mon Tutoriel sur la programmation �Shell�
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les diff�rentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  12. #12
    Expert �minent
    Homme Profil pro
    Architecte technique retrait�
    Inscrit en
    Juin 2008
    Messages
    21 772
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activit� : Architecte technique retrait�
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 772
    Par d�faut
    Citation Envoy� par Sve@r Voir le message
    Il s'agit de scinder les domaines, pas les fonctions. Les fonctions ne sont que des outils de travail.
    Ce sont plut�t des abstractions que le programmeur cr�e pour effectuer son travail qui n'est pas d'�crire un programme (�� c'est le r�sultat) mais de programmer sa construction en identifiant chaque �tape et les informations n�cessaires en entr�e et � r�cup�rer en sortie (pour faire la suite).

    Et ce qui est important, c'est la coh�rence dans l'enchainement des op�rations.

    La grosse diff�rence entre le d�butant (qui d�bute) est qu'il se focalise sur les petits bouts pour essayer de les assembler ensuite. C'est une d�marche du bas vers le haut, car on essaie de structurer un tas de boue comme on peut.

    A l'oppos�, si on d�coupe chaque �tape en fonction avec passage de param�tres et retour, on se focalise sur le flux d'informations qui doit �tre produit � chaque �tape sans trop se pr�occuper du d�tail (mais il faut avoir une id�e de la difficult� du "d�tail" en question).

    Par exemple, je peux �crire:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    db_cnx = db_open(...)
    dev_unit = 1
    records = db_query(db_cnx, dev_unit)
    Et r�aliser ces fonctions lights:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    def db_open():
          return None
    def db_query(cnx, dev_unit):
          return 1, 2, 3
    On a la structure et le flux d'informations et on peut produire des donn�es r�cup�r�es dans "records" qui seront utilisables pour la suite.

    A d�faut, on se retrouve avec des tas de lignes de code � raccorder les uns aux autres avec des jointures d�gueulasses.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  13. #13
    Membre confirm�
    Homme Profil pro
    Dessinateur industriel
    Inscrit en
    F�vrier 2021
    Messages
    90
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 41
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activit� : Dessinateur industriel
    Secteur : Industrie

    Informations forums :
    Inscription : F�vrier 2021
    Messages : 90
    Par d�faut
    J'ai avanc� en suivant quelques tutos et exemples mais cela ne correspond pas totalement � ce que je souhaiterais.
    Dans le code suivant je me connecte � la base de donn�es puis r�cup�re les infos des devices Modbus, puis dans une boucle je r�cup�re les valeurs des registres, les convertis en 32bit et le insert un par un dans la base de donn�e et recommence en boucle a une fr�quence d�finie

    J'aurai pr�f�r� que la communication / lecture des valeurs en modbus se fasse de facon r�guli�re et assez rapidement, mais que l'envoi dans la base de donn�es se fasse � une autre fr�quence. L'id�e est d'avoir en m�moire une valeur r�cente et de n'enregistrer celle-ci que toutes les X minutes.
    Dois-je sortir l'envoi en base de donn�es de la boucle

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    import time
    import pymysql.cursors
    from pymodbus.constants import Endian
    from pymodbus.payload import BinaryPayloadDecoder
    from threading import Thread, Lock
    from pyModbusTCP.client import ModbusClient
     
    # connect database
    sqlconnection = pymysql.connect(host='127.0.0.1',
                                 user='root',
                                 password='',
                                 database='database',
                                 charset='utf8mb4',
                                 cursorclass=pymysql.cursors.DictCursor)
     
    # read devices informations (ID, IP, Port, Register address)
    with sqlconnection:
        with sqlconnection.cursor() as cursor:
     
            sql = "SELECT `dev_id`, H0.hw_address, H0.hw_port FROM `devicestatus` LEFT JOIN `hardware` H0 ON H0.hw_id = devicestatus.dev_hw_id WHERE H0.hw_enabled = 1 AND devicestatus.dev_used = 1 ORDER BY H0.hw_address, dev_name"
            cursor.execute(sql,)
            result = cursor.fetchall()
            #print(result)
            #exemple : [{'dev_id': 7, 'hw_address': '192.168.100.202', 'hw_port': 502}, {'dev_id': 8, 'hw_address': '192.168.100.202', 'hw_port': 502}, {'dev_id': 9, 'hw_address': '192.168.100.202', 'hw_port': 502}, {'dev_id': 10, 'hw_address': '192.168.100.202', 'hw_port': 502}, {'dev_id': 11, 'hw_address': '192.168.100.202', 'hw_port': 502}, {'dev_id': 12, 'hw_address': '192.168.100.202', 'hw_port': 502}]
     
     
    # set global variables
    regs = []
    sf_value = 0
     
     
    # init a thread lock
    regs_lock = Lock()
     
     
    # modbus polling thread
    def polling_thread():
        global regs
     
     
        # polling loop
        while True:
     
     
            REGISTER_ADDRESS = 98 #First device is at address %MW100, i dont' understand why i need to do -2
     
            # For each dictionnary of the list, "extract" each value of element : information useful to launch Modbus requests, one per device.
            for val in result:
     
                # set modbusTCP variables :
                DEV_ID = val['dev_id']
                SERVER_HOST = val['hw_address']
                SERVER_PORT = val['hw_port']
                SERVER_ID = 1
                REGISTER_ADDRESS = REGISTER_ADDRESS + 2 # to read %MD100 %MD102 %MD104 ...
                REGISTER_COUNT = 2
                print("Target :", SERVER_HOST, SERVER_PORT, REGISTER_ADDRESS)
     
                client = ModbusClient(host=SERVER_HOST, port=int(SERVER_PORT), unit_id=int(SERVER_ID), auto_open=True, auto_close=True, timeout=2)
     
                # keep TCP open
                if not client.is_open():
                    client.open()
                # do modbus reading on socket
                reg_read = client.read_holding_registers(REGISTER_ADDRESS, REGISTER_COUNT)
     
     
                # if read is ok, store result in regs (with thread lock synchronization)
                if reg_read:
                    # decode the 2 registers into a 32 bit integer
                    decoder = BinaryPayloadDecoder.fromRegisters(reg_read, byteorder=Endian.Big, wordorder=Endian.Little)
                    sf_value = decoder.decode_32bit_int()
     
                    with regs_lock:
                        regs = sf_value
                        print("dev_ID:", DEV_ID, "Valeur:", regs)
                        # To do : insert each data into sql table
     
                        # connect database
                        sqlconnection = pymysql.connect(host='127.0.0.1',
                                                     user='root',
                                                     password='',
                                                     database='database',
                                                     charset='utf8mb4',
                                                     cursorclass=pymysql.cursors.DictCursor)
                        with sqlconnection:
                            with sqlconnection.cursor() as cursor:
                                sql = "INSERT INTO `meter` (`meter_devlog_id`,`meter_value`,`meter_usage`) VALUES (%s, %s, %s)"
                                cursor.execute(sql, ('23', regs, 0))
                            sqlconnection.commit()
            # 1s before next polling
            time.sleep(5)
     
     
    # start polling thread
    tp = Thread(target=polling_thread)
    # set daemon: polling thread will exit if main thread exit
    tp.daemon = True
    tp.start()
     
    # display loop (in main thread)
    while True:
        # print regs (with thread lock synchronization)
        with regs_lock:
            #print(regs)
            print(" ici mettre l'envoi en base de données plutôt que dans la tâche de fond")
        # 1s before next print
        time.sleep(10)
    Merci de votre aide.

  14. #14
    Expert �minent
    Homme Profil pro
    Architecte technique retrait�
    Inscrit en
    Juin 2008
    Messages
    21 772
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activit� : Architecte technique retrait�
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 772
    Par d�faut
    Citation Envoy� par makimax Voir le message
    J'aurai pr�f�r� que la communication / lecture des valeurs en modbus se fasse de facon r�guli�re et assez rapidement, mais que l'envoi dans la base de donn�es se fasse � une autre fr�quence. L'id�e est d'avoir en m�moire une valeur r�cente et de n'enregistrer celle-ci que toutes les X minutes.
    Vous pourriez stockez vos donn�es dans une liste/tableau plut�t que de les �crire imm�diatement en base. Elles pourraient �tre enregistr�es s'il y en a assez ou au bout d'un certain temps.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  15. #15
    Membre confirm�
    Homme Profil pro
    Dessinateur industriel
    Inscrit en
    F�vrier 2021
    Messages
    90
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 41
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activit� : Dessinateur industriel
    Secteur : Industrie

    Informations forums :
    Inscription : F�vrier 2021
    Messages : 90
    Par d�faut
    Citation Envoy� par wiztricks Voir le message
    Vous pourriez stockez vos donn�es dans une liste/tableau plut�t que de les �crire imm�diatement en base. Elles pourraient �tre enregistr�es s'il y en a assez ou au bout d'un certain temps.

    - W
    Merci j'ai tent� cette piste et cela fonctionne bien, la boucle lit les valeurs modbus en t�che de fond et met � jour un tableau lui m�me r�initialis� ensuite.
    A une fr�quence d�fini j'envoi les valeurs du tableau qui sont bien les derni�res valeurs modbus les plus � jour.

    Je n'ai pas cr�� de fonction mais est-ce normal de devoir remettre une connexion � la base de donn�es, si je ne la mets pas j'ai une erreur qui dit qu'elle est ferm�e

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    import time
    import pymysql.cursors
    from pymodbus.constants import Endian
    from pymodbus.payload import BinaryPayloadDecoder
    from threading import Thread, Lock
    from pyModbusTCP.client import ModbusClient
     
    # connect database
    sqlconnection = pymysql.connect(host='127.0.0.1',
                                 user='root',
                                 password='',
                                 database='database',
                                 charset='utf8mb4',
                                 cursorclass=pymysql.cursors.DictCursor)
     
    # read devices informations (ID, IP, Port, Register address)
    with sqlconnection:
        with sqlconnection.cursor() as cursor:
     
            sql = "SELECT `dev_id`, H0.hw_address, H0.hw_port FROM `devicestatus` LEFT JOIN `hardware` H0 ON H0.hw_id = devicestatus.dev_hw_id WHERE H0.hw_enabled = 1 AND devicestatus.dev_used = 1 ORDER BY H0.hw_address, dev_name"
            cursor.execute(sql,)
            result = cursor.fetchall()
            #print(result)
            #exemple : [{'dev_id': 7, 'hw_address': '192.168.100.202', 'hw_port': 502}, {'dev_id': 8, 'hw_address': '192.168.100.202', 'hw_port': 502}, {'dev_id': 9, 'hw_address': '192.168.100.202', 'hw_port': 502}, {'dev_id': 10, 'hw_address': '192.168.100.202', 'hw_port': 502}, {'dev_id': 11, 'hw_address': '192.168.100.202', 'hw_port': 502}, {'dev_id': 12, 'hw_address': '192.168.100.202', 'hw_port': 502}]
     
     
    # set global variables
    regs = []
    decoded_value = 0
     
     
    # init a thread lock
    regs_lock = Lock()
     
     
    # modbus polling thread
    def polling_thread():
        global regs
     
     
        # polling loop
        while True:
     
            # purger le dictionnaire :
            regs = []
     
            # définir le registre de départ :
            REGISTER_ADDRESS = 100 #Start register address
     
            # For each list of the dictionnary, "extract" each value of element : information useful to launch Modbus requests, one per device.
            for val in result:
     
                # purger la liste :
                resultat = {}
     
                # set modbusTCP variables :
                READ_DEV_ID = val['dev_id']
                SERVER_HOST = val['hw_address']
                SERVER_PORT = val['hw_port']
                SERVER_ID = 1
                REGISTER_COUNT = 2
                #print("Target :", SERVER_HOST, SERVER_PORT, REGISTER_ADDRESS)
     
                client = ModbusClient(host=SERVER_HOST, port=int(SERVER_PORT), unit_id=int(SERVER_ID), auto_open=True, auto_close=True, timeout=2)
     
                # keep TCP open
                if not client.is_open():
                    client.open()
                # do modbus reading on socket
                reg_read = client.read_holding_registers(REGISTER_ADDRESS, REGISTER_COUNT)
     
     
                # if read is ok, store result in regs (with thread lock synchronization)
                if reg_read:
                    # decode the 2 registers into a 32 bit integer
                    decoder = BinaryPayloadDecoder.fromRegisters(reg_read, byteorder=Endian.Big, wordorder=Endian.Little)
                    decoded_value = decoder.decode_32bit_int()
     
                    # On mets à jour la liste
                    resultat['dev_id'] = READ_DEV_ID
                    resultat['meter_value'] = decoded_value
     
                    with regs_lock:
                        # On ajoute la liste au dictionnaire
                        regs.append(resultat)
                        #print(regs)
     
                REGISTER_ADDRESS = REGISTER_ADDRESS + 2 # Increment registrer address for next read
     
            # 1s before next polling
            time.sleep(1)
     
     
    # start polling thread
    tp = Thread(target=polling_thread)
    # set daemon: polling thread will exit if main thread exit
    tp.daemon = True
    tp.start()
     
    # display loop (in main thread)
    while True:
        # print regs (with thread lock synchronization)
        with regs_lock:
            print("Données à envoyer en base de données : ")
            #print(regs)
     
            # For each list of the dictionnary, "extract" each value of element :
            for val2 in regs:
                print('dev_id', val2['dev_id'], ':', val2['meter_value'])
     
                # connect database
                sqlconnection = pymysql.connect(host='127.0.0.1',
                                             user='root',
                                             password='',
                                             database='database',
                                             charset='utf8mb4',
                                             cursorclass=pymysql.cursors.DictCursor)
                with sqlconnection:
                    with sqlconnection.cursor() as cursor:
                        sql = "INSERT INTO `meter` (`meter_devlog_id`,`meter_value`,`meter_usage`) VALUES (%s, %s, %s)"
                        cursor.execute(sql, (val2['dev_id'], val2['meter_value'], 0))
                    sqlconnection.commit()
     
            #print(" --- Données de la boucle en tâche de fond : ")
        # 1s before next print
        time.sleep(3)

  16. #16
    Expert �minent
    Homme Profil pro
    Architecte technique retrait�
    Inscrit en
    Juin 2008
    Messages
    21 772
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activit� : Architecte technique retrait�
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 772
    Par d�faut
    Citation Envoy� par makimax Voir le message
    Je n'ai pas cr�� de fonction mais est-ce normal de devoir remettre une connexion � la base de donn�es, si je ne la mets pas j'ai une erreur qui dit qu'elle est ferm�e
    C'est le comportement normal du with... que l'on constate avec un simple fichier:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> f = open('test.dat')
    >>> f.closed
    False
    >>> with f:
    ...     pass
    ...
    >>> f.closed
    True
    >>>
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. sauvegarde des donn�es d'un formulaire dans mysql avec php
    Par MC BAO dans le forum PHP & Base de donn�es
    R�ponses: 2
    Dernier message: 28/07/2017, 16h31
  2. R�ponses: 8
    Dernier message: 17/02/2016, 17h14
  3. R�ponses: 2
    Dernier message: 23/04/2009, 11h16
  4. Enregistrement des donn�es d'un formulaire dans SharePoint
    Par fanfan49 dans le forum SharePoint
    R�ponses: 1
    Dernier message: 06/06/2007, 23h12
  5. R�ponses: 2
    Dernier message: 14/05/2007, 09h40

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo