diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e7e9d11d4bf243bffe4bb60b4ac1f9392297f4bf --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml diff --git a/.idea/TPBlockChain.iml b/.idea/TPBlockChain.iml new file mode 100644 index 0000000000000000000000000000000000000000..8b8c395472a5a6b3598af42086e590417ace9933 --- /dev/null +++ b/.idea/TPBlockChain.iml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="PYTHON_MODULE" version="4"> + <component name="NewModuleRootManager"> + <content url="file://$MODULE_DIR$" /> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> + <component name="PyDocumentationSettings"> + <option name="format" value="PLAIN" /> + <option name="myDocStringFormat" value="Plain" /> + </component> +</module> \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..105ce2da2d6447d11dfe32bfb846c3d5b199fc99 --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ +<component name="InspectionProjectProfileManager"> + <settings> + <option name="USE_PROJECT_PROFILE" value="false" /> + <version value="1.0" /> + </settings> +</component> \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..2d83d70ff8b2e7835f3dbc08bb4481dda6e86665 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (2)" project-jdk-type="Python SDK" /> +</project> \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..6fc7816c0da56e737083e3e383904371902517ac --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/.idea/TPBlockChain.iml" filepath="$PROJECT_DIR$/.idea/TPBlockChain.iml" /> + </modules> + </component> +</project> \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..94a25f7f4cb416c083d265558da75d457237d671 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="$PROJECT_DIR$" vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/TP2/.gitkeep b/TP2/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/TP2/Armoire5.py b/TP2/Armoire5.py new file mode 100644 index 0000000000000000000000000000000000000000..605eba6bc77ff33300ddd8780fb5c1e82b0b0656 --- /dev/null +++ b/TP2/Armoire5.py @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon Jun 22 16:40:33 2020 + +@author: chevrier6 +""" +from bitManip import * +from easymodbus.modbusClient import ModbusClient +from easymodbus.modbusClient import convert_registers_to_float + + +class AutomateException(Exception): + def __init__(self, message): + self.message = message + + +class Armoire5(): + # ici les adresse des mesure commence a ZERO (pas UN comme en java) + + def __init__(self): + self.nbCharge = 7 # de 0 a 6 + self.ipAdresse = "100.75.155.115" + self.adresseMesure = 2 + self.adresseTOR = 32000 + self.adresseMesureSecteur1 = 7 # attention vraie adresse () + self.adresseMesureSecteur2 = 8 # attention vraie adresse + + self.debutAdrCharge = 9 + self.debutAdrSource = 0 + + def okCharge(self, i): + return 0 <= i <= self.nbCharge - 1 ###########♦ MODIF + + def resetAll(self): + self.writeTOR(0) + + def resetSource(self): + for i in range(self.nbCharge): + self.setSource1(i) + + def resetCharge(self): + for i in range(self.nbCharge): + self.unsetCharge(i) + + def setCharge(self, charge: int): + if not self.okCharge(charge): + raise AutomateException("numero charge pas compris entre 0 et 6") + val = self.readTOR() + val = setBit(val, charge + self.debutAdrCharge) + self.writeTOR(val) + + def unsetCharge(self, charge): + if not self.okCharge(charge): + raise AutomateException("numero charge pas compris entre 0 et 6") + val = self.readTOR() + val = clearBit(val, charge + self.debutAdrCharge) + self.writeTOR(val) + + def toggleCharge(self, charge): + if not self.okCharge(charge): + raise AutomateException("numero charge pas compris entre 0 et 6") + val = self.readTOR() + val = toggleBit(val, charge + self.debutAdrCharge) + self.writeTOR(val) + + def setSource1(self, charge): + if not self.okCharge(charge): + raise AutomateException("numero charge pas compris entre 0 et 6") + val = self.readTOR() + val = clearBit(val, charge + self.debutAdrSource) + self.writeTOR(val) + + def setSource2(self, charge): + if not self.okCharge(charge): + raise AutomateException("numero charge pas compris entre 0 et 6") + val = self.readTOR() + val = setBit(val, charge + self.debutAdrSource) + self.writeTOR(val) + + def togglesource(self, charge): + if not self.okCharge(charge): + raise AutomateException("numero charge pas compris entre 0 et 6") + val = self.readTOR() + val = toggleBit(val, charge + self.debutAdrSource) + self.writeTOR(val) + + ################################ + + def writeTOR(self, val): + modbusclient = ModbusClient(self.ipAdresse, 502) + modbusclient.connect() + modbusclient.write_single_register(self.adresseTOR, val) + modbusclient.close() + # some tempo to wait measure to stabilize + from time import sleep + sleep(2.) + + def readTOR(self): + modbusclient = ModbusClient(self.ipAdresse, 502) + modbusclient.connect() + inputRegisters = modbusclient.read_inputregisters(self.adresseTOR, 1) + modbusclient.close() + return (int)(inputRegisters[0]) + + ############################################### + def readSecteur1(self): + addr = self.adresseMesure + (self.adresseMesureSecteur1) * 8 + return self.lireValeurAdresse(addr + 2), self.lireValeurAdresse(addr), self.lireValeurAdresse( + addr + 4), self.lireValeurAdresse(addr + 6) + + def readSecteur2(self): + addr = self.adresseMesure + (self.adresseMesureSecteur2) * 8 + return self.lireValeurAdresse(addr + 2), self.lireValeurAdresse(addr), self.lireValeurAdresse( + addr + 4), self.lireValeurAdresse(addr + 6) + + def readMesureCourant(self, source: int): + if not self.okCharge(source): + raise AutomateException("numero charge pas compris entre 0 et 6") + return self.lireValeur(source, 0) + + def readMesureTension(self, source: int): + if not self.okCharge(source): + raise AutomateException("numero charge pas compris entre 0 et 6") + return self.lireValeur(source, 2) + + def readMesurePactive(self, source: int): + if not self.okCharge(source): + raise AutomateException("numero charge pas compris entre 0 et 6") + return self.lireValeur(source, 4) + + def readMesurePreactive(self, source: int): + if not self.okCharge(source): + raise AutomateException("numero charge pas compris entre 0 et 6") + return self.lireValeur(source, 6) + + def readMesure(self, source): + return self.readMesureTension(source), self.readMesureCourant(source), self.readMesurePactive( + source), self.readMesurePreactive(source) + + def lireValeur(self, source, offset): + + addr = self.adresseMesure + (source) * 8 + offset + return self.lireValeurAdresse(addr) + + def lireValeurAdresse(self, addr): + + modbusclient = ModbusClient(self.ipAdresse, 502) + modbusclient.connect() + data = modbusclient.read_holdingregisters(addr, 2) + modbusclient.close() + res = convert_registers_to_float(data) + + return res[0] + diff --git a/TP2/Armoire6.py b/TP2/Armoire6.py new file mode 100644 index 0000000000000000000000000000000000000000..3063525959492caf4166c676316e20a795149b51 --- /dev/null +++ b/TP2/Armoire6.py @@ -0,0 +1,157 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon Jun 22 16:40:33 2020 + +@author: chevrier6 +""" +from bitManip import * +from easymodbus.modbusClient import ModbusClient +from easymodbus.modbusClient import convert_registers_to_float + +class AutomateException(Exception): + def __init__(self, message): + self.message = message + + + + + +class Armoire6(): + # ici les adresse des mesure commence a ZERO (pas UN comme en java) + + + def __init__(self): + self.nbCharge=7 # de 0 a 6 + self.ipAdresse="100.75.155.116" + self.adresseMesure=0 + self.adresseTOR=32000 + self.adresseMesureSecteur1=7 # attention vraie adresse () + self.adresseMesureSecteur2=8 # attention vraie adresse + + self.debutAdrCharge=0 + self.debutAdrSource=7 + + def okCharge(self,i): + return 0 <= i <= self.nbCharge-1 + + def resetAll(self): + self.writeTOR(0) + + def resetSource(self): + for i in range(self.nbCharge): + self.setSource1(i) + + def resetCharge(self): + for i in range(self.nbCharge): + self.unsetCharge(i) + + def setCharge(self, charge : int ): + if not self.okCharge(charge): + raise AutomateException("numero charge pas compris entre 0 et 6") + val=self.readTOR() + val=setBit(val,charge+self.debutAdrCharge) + self.writeTOR(val) + + + def unsetCharge(self,charge): + if not self.okCharge(charge): + raise AutomateException("numero charge pas compris entre 0 et 6") + val=self.readTOR() + val=clearBit(val,charge+self.debutAdrCharge) + self.writeTOR(val) + + def toggleCharge(self, charge): + if not self.okCharge(charge): + raise AutomateException("numero charge pas compris entre 0 et 6") + val = self.readTOR() + val = toggleBit(val, charge+self.debutAdrCharge) + self.writeTOR(val) + + def setSource1(self,charge): + if not self.okCharge(charge): + raise AutomateException("numero charge pas compris entre 0 et 6") + val=self.readTOR() + val=clearBit(val,charge+self.debutAdrSource) + self.writeTOR(val) + + def setSource2(self, charge): + if not self.okCharge(charge): + raise AutomateException("numero charge pas compris entre 0 et 6") + val = self.readTOR() + val = setBit(val, charge +self.debutAdrSource) + self.writeTOR(val) + + + + def togglesource(self,charge): + if not self.okCharge(charge): + raise AutomateException("numero charge pas compris entre 0 et 6") + val=self.readTOR() + val=toggleBit(val,charge+self.debutAdrSource) + self.writeTOR(val) + + ################################ + + + def writeTOR(self,val): + modbusclient =ModbusClient(self.ipAdresse,502) + modbusclient.connect() + modbusclient.write_single_register(self.adresseTOR,val) + modbusclient.close() + # some tempo to wait measure to stabilize + from time import sleep + sleep(2.) + + + def readTOR(self): + modbusclient =ModbusClient(self.ipAdresse,502) + modbusclient.connect() + inputRegisters = modbusclient.read_inputregisters(self.adresseTOR, 1) + modbusclient.close() + return (int)(inputRegisters[0]) + +############################################### + def readSecteur1(self): + from time import sleep + addr = self.adresseMesure + (self.adresseMesureSecteur1 ) * 8 + return self.lireValeurAdresse(addr + 2), self.lireValeurAdresse(addr), self.lireValeurAdresse(addr + 4), self.lireValeurAdresse(addr + 6) + def readSecteur2(self): + addr = self.adresseMesure + (self.adresseMesureSecteur2 ) * 8 + return self.lireValeurAdresse(addr+2),self.lireValeurAdresse(addr),self.lireValeurAdresse(addr+4),self.lireValeurAdresse(addr+6) + + def readMesureCourant(self,source :int): + if not self.okCharge(source): + raise AutomateException("numero charge pas compris entre 0 et 6") + return self.lireValeur(source,0 ) + def readMesureTension(self,source :int): + if not self.okCharge(source): + raise AutomateException("numero charge pas compris entre 0 et 6") + return self.lireValeur(source,2 ) + def readMesurePactive(self,source :int): + if not self.okCharge(source): + raise AutomateException("numero charge pas compris entre 0 et 6") + return self.lireValeur(source,4 ) + def readMesurePreactive(self,source :int): + if not self.okCharge(source): + raise AutomateException("numero charge pas compris entre 0 et 6") + return self.lireValeur(source,6 ) + + def readMesure(self,source): + return self.readMesureTension(source),self.readMesureCourant(source),self.readMesurePactive(source),self.readMesurePreactive(source) + + def lireValeur(self,source,offset): + + addr= self.adresseMesure + (source ) *8+offset + return self.lireValeurAdresse(addr) + def lireValeurAdresse(self,addr): + + + modbusclient =ModbusClient(self.ipAdresse,502) + modbusclient.connect() + data=modbusclient.read_holdingregisters(addr,2) + modbusclient.close() + res =convert_registers_to_float(data) + + return res[0] + + \ No newline at end of file diff --git a/TP2/__pycache__/Armoire5.cpython-38.pyc b/TP2/__pycache__/Armoire5.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc0c29328822cc7d2ab02fa499ac18483c67c216 Binary files /dev/null and b/TP2/__pycache__/Armoire5.cpython-38.pyc differ diff --git a/TP2/__pycache__/Armoire5.cpython-39.pyc b/TP2/__pycache__/Armoire5.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..750a157ccd1c8ff5791bae08ab9b2a2cd5680ab4 Binary files /dev/null and b/TP2/__pycache__/Armoire5.cpython-39.pyc differ diff --git a/TP2/__pycache__/Armoire6.cpython-38.pyc b/TP2/__pycache__/Armoire6.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b54c26efa12a459cc6a298cb10fb4044e8f975d8 Binary files /dev/null and b/TP2/__pycache__/Armoire6.cpython-38.pyc differ diff --git a/TP2/__pycache__/Armoire6.cpython-39.pyc b/TP2/__pycache__/Armoire6.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9cc62dd27f5c43adea4b6064ad935f7c989130b Binary files /dev/null and b/TP2/__pycache__/Armoire6.cpython-39.pyc differ diff --git a/TP2/__pycache__/bitManip.cpython-38.pyc b/TP2/__pycache__/bitManip.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..57fc49c64a676aabb5e2291b23cca6cb93d92c66 Binary files /dev/null and b/TP2/__pycache__/bitManip.cpython-38.pyc differ diff --git a/TP2/__pycache__/bitManip.cpython-39.pyc b/TP2/__pycache__/bitManip.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2da8f09a8e9dbcb2193a38cc1d2dfc191a8a9410 Binary files /dev/null and b/TP2/__pycache__/bitManip.cpython-39.pyc differ diff --git a/TP2/bitManip.py b/TP2/bitManip.py new file mode 100644 index 0000000000000000000000000000000000000000..2f8ceb26ce056109e127d98f179d807daf0acc0f --- /dev/null +++ b/TP2/bitManip.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon Jun 22 16:43:58 2020 + +@author: chevrier6 +""" + +###################### +def mask16(v): + "same as setBit(v,0)" + b=1 + for i in range(v): + b*=2 + return b + +# 4 next functions from https://wiki.python.org/moin/BitManipulation +# testBit() returns a nonzero result, 2**offset, if the bit at 'offset' is one. +def testBit(int_type, offset): + mask = 1 << offset + return(int_type & mask) + + # setBit() returns an integer with the bit at 'offset' set to 1. + +def setBit(int_type, offset): + mask = 1 << offset + return(int_type | mask) + + # clearBit() returns an integer with the bit at 'offset' cleared. + +def clearBit(int_type, offset): + mask = ~(1 << offset) + return(int_type & mask) + + # toggleBit() returns an integer with the bit at 'offset' inverted, 0 -> 1 and 1 -> 0. + +def toggleBit(int_type, offset): + mask = 1 << offset + return(int_type ^ mask) \ No newline at end of file diff --git a/TP2/docArmoirePython.md b/TP2/docArmoirePython.md new file mode 100644 index 0000000000000000000000000000000000000000..95dcaa37bce4bb21c22dbbf1a0cdd999900f58d4 --- /dev/null +++ b/TP2/docArmoirePython.md @@ -0,0 +1,43 @@ +# Une armoire c'est quoi ? + +- c'est un appareil électrique commandable à distance +- il dispose de 7 charges différentes (numérotées de 0 à 6) et de deux source d'alimentation +(source1 et source2) + +- chaque charge peut être en marche ou pas et soit sur source 1 soit sur source 2 indépendament des autres +- on peut connaitre des infos sur chaque charges (U,I,P,PR) et sur chaque source (i.e. le cumul des charges en marche sur la source concernée) +# Documentation code python de manipulation des armoires + + +## Prerequis logiciel + +- utilisation de la librairie EasyModbus.py +- utilisation d'un code bitManip.py + +## Code disponible + +### Note +Actuellemnt seul le code pour l'armoire 6 est opérationnel + +### Utilisation + +- charger le fichier correspondant à l'armoire à utiliser (exemple Armoire6.py) et ses dépendances + +**Méthodes** + +* Constructeur *ArmoireX()* où X vaut 6 + +* actions générales + - **resetAll**: remet tout à l'état d'origine + - **resetSource** / **resetCharge**: remet la partie source/charge à l'état d'origine + * actions sur les charges + - **setCharge** / **unsetCharge** / **toggleCharge**(*n°charge*): met sur ON/OFF/état inverse la charge. *N°charge* doit être compris entre 0 et 6 +* Actions sur les sources + - **setSource1** / **setSource2** / **togglesource**(*n°charge*): met sur l'alimentaion 1/l'alimentation 2/inverse la source. *N°charge* doit être compris entre 0 et 6 +* Actions sur les sources + +* lecture de valeurs ( +retourne une liste de valeurs [U,I,PA,PR]) + - **readSecteur1**: mesure pour la source 1 + - **readSecteur2**: mesure pour la source 2 + - **readMesure**(*n°charge*): mesure pour la charge paramètre (compris en 0 et 6) \ No newline at end of file diff --git a/TP2/easymodbus/__init__.py b/TP2/easymodbus/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5f434bb496ed6a57a145aba0d9dad799cb91861c --- /dev/null +++ b/TP2/easymodbus/__init__.py @@ -0,0 +1,3 @@ +#Only required for Python 2: +#We Make an empty file called __init__.py in the same directory as the files. +#That will signify to Python that it's "ok to import from this directory". diff --git a/TP2/easymodbus/__pycache__/__init__.cpython-38.pyc b/TP2/easymodbus/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..793146fc0b6713b49233b6cc0dc4fc92f3c85bd2 Binary files /dev/null and b/TP2/easymodbus/__pycache__/__init__.cpython-38.pyc differ diff --git a/TP2/easymodbus/__pycache__/modbusClient.cpython-38.pyc b/TP2/easymodbus/__pycache__/modbusClient.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c2e7f7cbf118af50ede25a74b3a23406cf228087 Binary files /dev/null and b/TP2/easymodbus/__pycache__/modbusClient.cpython-38.pyc differ diff --git a/TP2/easymodbus/__pycache__/modbusException.cpython-38.pyc b/TP2/easymodbus/__pycache__/modbusException.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0dee22613bc74e0574fbf40c102b00e23c6f30c1 Binary files /dev/null and b/TP2/easymodbus/__pycache__/modbusException.cpython-38.pyc differ diff --git a/TP2/easymodbus/easyModbusGUI.py b/TP2/easymodbus/easyModbusGUI.py new file mode 100644 index 0000000000000000000000000000000000000000..fedeb5e5db2ac3142f01cc62c15616630a177b71 --- /dev/null +++ b/TP2/easymodbus/easyModbusGUI.py @@ -0,0 +1,308 @@ +#!/usr/bin/env python + +import sys + +if sys.version_info[0] < 3: #The Module "Tkinter" is named "tkinter" in Python 3. + from Tkinter import * + import tkMessageBox as messagebox #We import tkMessageBos as messagebox, because thats the name in Python 3 + +else: + from tkinter import * + from builtins import int + from future.moves import tkinter + import tkinter.messagebox as messagebox +from easymodbus.modbusClient import * + +class EasyModbusGUI(Frame): + def __init__(self, master=None): + Frame.__init__(self) + master.title("EasyModbusPython Client") + self.pack() + self.createWidgets() + + + def createWidgets(self): + self.pack(fill=BOTH, expand=True) + + self.columnconfigure(1, weight=1) + self.columnconfigure(3, pad=7) + self.rowconfigure(3, weight=1) + self.rowconfigure(5, pad=7) + + #label Read operations + readOperationsLabel = Label(self, text="Read Operations", font = 15) + readOperationsLabel.config(font=15) + readOperationsLabel.grid(row = 0, column = 0) + + #Button Read Coils + self.readCoils = Button(self, text="Read Coils (FC1)", width=25, command=self.__ReadCoils) + self.readCoils.grid(row = 4, column = 0, padx = 20, pady = 6, columnspan=2) + + #Button Read Discrete Inputs + self.readDiscreteInputs = Button(self, text="Read Discrete Inputs (FC2)", width=25, command=self.__ReadDiscreteInputs) + self.readDiscreteInputs.grid(row = 5, column = 0, padx = 20, pady = 6, columnspan=2) + + #Button Read Holding Registers + self.readHoldingRegisters = Button(self, text="Read Holding Registers (FC3)", width=25, command=self.__ReadHoldingRegisters) + self.readHoldingRegisters.grid(row = 6, column = 0, padx = 20, pady = 6, columnspan=2) + + #Button Read Input Registers + self.readInputRegisters = Button(self, text="Read Input Registers (FC4)", width=25, command=self.__ReadInputRegisters) + self.readInputRegisters.grid(row = 7, column = 0, padx = 20, pady = 6, columnspan=2) + + #label for IP Addresses + label = Label(self, text="IP-Address:") + label.grid(row = 2, column = 0, sticky=W) + + #Entry for IPAddress + self.ipAddressEntry = Entry(self, width=15) + self.ipAddressEntry.insert(END, "127.0.0.1") + self.ipAddressEntry.grid(row = 3, column = 0, sticky=W) + + #label for Display Port + labelPort = Label(self, text="Port:") + labelPort.grid(row = 2, column = 1, sticky=W) + + #Text Field for Port + self.portEntry = Entry(self, width=10) + self.portEntry.insert(END, "502") + self.portEntry.grid(row = 3, column = 1, sticky=W) + + #label for Display Starting Address + labelStartingAddress = Label(self, text="Starting Address:") + labelStartingAddress.grid(row = 4, column = 3, sticky=W) + + #Text Field for starting Address + self.startingAddress = Entry(self, width=10) + self.startingAddress.insert(END, "1") + self.startingAddress.grid(row = 4, column = 4, sticky=W) + + #label for Display Number of values + labelStartingAddress = Label(self, text="Number of values:") + labelStartingAddress.grid(row = 5, column = 3, sticky=W) + + #Text Field for number of Values + self.quantity = Entry(self, width=10) + self.quantity.insert(END, "1") + self.quantity.grid(row = 5, column = 4, sticky=W) + + #label for Response from server + labelResponse = Label(self, text="Response from Server") + labelResponse.grid(row = 2, column = 5, sticky=W, padx = 10) + + #Text Field for response from server + self.response = StringVar + self.responseTextField = Text(self, width=35, height = 10) + scroll = Scrollbar(self, command=self.responseTextField.yview) + self.responseTextField.configure(yscrollcommand=scroll.set) + self.responseTextField.insert(END, "") + self.responseTextField.grid(row = 2, column = 5, rowspan=8, padx = 10) + scroll.grid(row = 3, column = 6, rowspan=5, sticky=N+S+E) + + #Empty row between Read and Write operations + self.rowconfigure(15, minsize=20) + + #label Write operations + readOperationsLabel = Label(self, text="Write Operations", font = 15) + readOperationsLabel.config(font=15) + readOperationsLabel.grid(row = 20, column = 0) + + #Label select datatye to write + datatype = Label(self, text="Select datatype to write") + datatype.grid(row = 25, column = 0, sticky=W) + + #Combobox to selct the type of variable to write + lst1 = ['Coils (bool)','Holding Registers (word)'] + self.variableDatatype = StringVar(self) + self.variableDatatype.set('Coils (bool)') + self.variableDatatype.trace('w',self.datatypeChanged) + dropdown = OptionMenu(self,self.variableDatatype,*lst1) + dropdown.grid(row = 25, column = 1,columnspan = 3, sticky=W) + + #Label select value to write + datatype = Label(self, text="Select value to write") + datatype.grid(row = 26, column = 0, sticky=W) # + + #Combobox to selct true or false in case "coils" has been selcted + lst1 = ['FALSE', 'TRUE'] + self.variableData = StringVar(self) + self.variableData.set('FALSE') + self.dropdownData = OptionMenu(self,self.variableData,*lst1) + self.dropdownData.grid(row = 26, column = 1, sticky=W) + + #TextField for the Register Values to write + self.registerValueToWrite = Entry(self, width=10) + self.registerValueToWrite.insert(END, "1") + + #label for Display startingAddress + labelStartingAddress = Label(self, text="Starting Address:") + labelStartingAddress.grid(row = 27, column = 0, sticky=W) + + #Text Field for starting Address + self.startingAddressWrite = Entry(self, width=10) + self.startingAddressWrite.insert(END, "1") + self.startingAddressWrite.grid(row = 27, column = 1, sticky=W) + + #label for Request to Server + labelResponse = Label(self, text="Request to Server") + labelResponse.grid(row = 24, column = 5, sticky=W, padx = 10) + + #Text Field containing data to write to server + self.request = StringVar + self.requestTextField = Text(self, width=35, height = 10) + scroll = Scrollbar(self, command=self.requestTextField.yview) + self.requestTextField.configure(yscrollcommand=scroll.set) + self.requestTextField.insert(END, "") + self.requestTextField.grid(row = 25, column = 5, rowspan=8, padx = 10) + scroll.grid(row = 25, column = 6, rowspan=8, sticky=N+S+E) + + #Button Add Entry to request list + self.addEntryToRequestList = Button(self, text="Add Value to \n request list", width=15, command=self.addValueToRequestList) + self.addEntryToRequestList.grid(row = 26, column = 3,columnspan = 2) + + #Button Delete Entry from request list + self.addEntryToRequestList = Button(self, text="Delete Value from \n request list", width=15, command=self.deleteValueToRequestList) + self.addEntryToRequestList.grid(row = 28, column = 3,columnspan = 2) + + + #Button Write values to server + writeValuesToServerButton = Button(self, text="Write Requested Values to Server", width=25, command=self.__writeValuesToServer) + writeValuesToServerButton.grid(row = 30, column = 0, padx = 20, pady = 6, columnspan=2) + + def addValueToRequestList(self): + if (self.variableDatatype.get() == 'Coils (bool)'): + self.requestTextField.insert(END, self.variableData.get()) + self.requestTextField.insert(END, "\n") + else: + self.requestTextField.insert(END, self.registerValueToWrite.get()) + self.requestTextField.insert(END, "\n") + + + def datatypeChanged(self,a,b,c): + self.requestTextField.delete('1.0', END) + if (self.variableDatatype.get() == 'Coils (bool)'): + self.registerValueToWrite.grid_remove() + self.dropdownData.grid(row = 26, column = 1, sticky=W) + else: + self.registerValueToWrite.grid(row = 26, column = 1, sticky=W) + self.dropdownData.grid_remove() + + def onReverse(self): + self.name.set(self.name.get()[::-1]) + + def __ReadCoils(self): + try: + modbusClient = ModbusClient(self.ipAddressEntry.get(), int(self.portEntry.get())) + if (not modbusClient.is_connected()): + modbusClient.connect() + coils = modbusClient.read_coils(int(self.startingAddress.get()) - 1, int(self.quantity.get())) + self.responseTextField.delete('1.0', END) + for coil in coils: + if (coil == FALSE): + response = "FALSE" + else: + response = "TRUE" + + self.responseTextField.insert(END, response + "\n") + except Exception as e: + messagebox.showerror('Exception Reading coils from Server', str(e)) + finally: + modbusClient.close() + + def __ReadDiscreteInputs(self): + try: + modbusClient = ModbusClient(self.ipAddressEntry.get(), int(self.portEntry.get())) + if (not modbusClient.is_connected()): + modbusClient.connect() + discrInputs = modbusClient.read_discreteinputs(int(self.startingAddress.get()) - 1, int(self.quantity.get())) + self.responseTextField.delete('1.0', END) + for inp in discrInputs: + if (inp == FALSE): + response = "FALSE" + else: + response = "TRUE" + + self.responseTextField.insert(END, response + "\n") + except Exception as e: + messagebox.showerror('Exception Reading discrete inputs from Server', str(e)) + finally: + modbusClient.close() + + def __ReadHoldingRegisters(self): + try: + modbusClient = ModbusClient(self.ipAddressEntry.get(), int(self.portEntry.get())) + if (not modbusClient.is_connected()): + modbusClient.connect() + holdingRegisters = modbusClient.read_holdingregisters(int(self.startingAddress.get()) - 1, int(self.quantity.get())) + self.responseTextField.delete('1.0', END) + for register in holdingRegisters: + + + self.responseTextField.insert(END, str(register) + "\n") + except Exception as e: + messagebox.showerror('Exception Reading holding registers from Server', str(e)) + + finally: + modbusClient.close() + + def __ReadInputRegisters(self): + try: + modbusClient = ModbusClient(self.ipAddressEntry.get(), int(self.portEntry.get())) + if (not modbusClient.is_connected()): + modbusClient.connect() + inputRegisters = modbusClient.read_inputregisters(int(self.startingAddress.get()) - 1, int(self.quantity.get())) + self.responseTextField.delete('1.0', END) + for register in inputRegisters: + + self.responseTextField.insert(END, str(register) + "\n") + + modbusClient.close() + except Exception as e: + messagebox.showerror('Exception Reading input Registers from Server', str(e)) + + def __writeValuesToServer(self): + try: + modbusClient = ModbusClient(self.ipAddressEntry.get(), int(self.portEntry.get())) + if (not modbusClient.is_connected()): + modbusClient.connect() + numberOfLines = (int(self.requestTextField.index('end').split('.')[0]) - 2) + if (self.variableDatatype.get() == 'Coils (bool)'): + if (numberOfLines > 1): + valueToWrite = list() + for i in range(1, numberOfLines+1): + textFieltValues = str(self.requestTextField.get(str(i)+".0", str(i+1)+".0")[:-1]) + if "TRUE" in textFieltValues: #String comparison contains some ""Null" symbol + valueToWrite.append(1) + else: + valueToWrite.append(0) + modbusClient.write_multiple_coils(int(self.startingAddressWrite.get()) - 1, valueToWrite) + else: + textFieltValues = str(self.requestTextField.get('1.0', END)[:-1]) + if "TRUE" in textFieltValues: #String comparison contains some ""Null" symbol + dataToSend = 1 + else: + dataToSend = 0 + modbusClient.write_single_coil(int(self.startingAddressWrite.get()) - 1, dataToSend) + else: + if (numberOfLines > 1): + valueToWrite = list() + for i in range(1, numberOfLines+1): + textFieltValues = int(self.requestTextField.get(str(i)+".0", str(i+1)+".0")[:-1]) + valueToWrite.append(textFieltValues) + modbusClient.write_multiple_registers(int(self.startingAddressWrite.get()) - 1, valueToWrite) + else: + textFieltValues = int(self.requestTextField.get('1.0', END)[:-1]) + modbusClient.write_single_register(int(self.startingAddressWrite.get()) - 1, textFieltValues) + except Exception as e: + messagebox.showerror('Exception writing values to Server', str(e)) + modbusClient.close() + + def deleteValueToRequestList(self): + numberOfLines = (int(self.requestTextField.index('end').split('.')[0]) - 2) + cursorPos = int(self.requestTextField.index(INSERT)[0]) #Find the current Cursorposition e.g. 1.0 -> First line + if (cursorPos-1 != numberOfLines): #don't delete the last line, because the last line contains only a "newline" + self.requestTextField.delete(str(cursorPos)+".0",str(cursorPos+1)+".0") #Delete the whole line using e.g. delete("1.0","2.0) deletes the first line + +root = Tk() +app = EasyModbusGUI(root) +app.mainloop() \ No newline at end of file diff --git a/TP2/easymodbus/modbusClient.py b/TP2/easymodbus/modbusClient.py new file mode 100644 index 0000000000000000000000000000000000000000..8801033441781b4ccaa90a16dbb43c2bc4889c1d --- /dev/null +++ b/TP2/easymodbus/modbusClient.py @@ -0,0 +1,1048 @@ +''' +Created on 12.09.2016 + +@author: Stefan Rossmann +''' +import importlib +import easymodbus.modbusException as Exceptions +import socket +import struct +import threading + + +class ModbusClient(object): + """ + Implementation of a Modbus TCP Client and a Modbus RTU Master + """ + + def __init__(self, *params): + """ + Constructor for Modbus RTU (serial line): + modbusClient = ModbusClient.ModbusClient('COM1') + First Parameter is the serial Port + + Constructor for Modbus TCP: + modbusClient = ModbusClient.ModbusClient('127.0.0.1', 502) + First Parameter ist the IP-Address of the Server to connect to + Second Parameter is the Port the Server listens to + """ + self.__receivedata = bytearray() + self.__transactionIdentifier = 0 + self.__unitIdentifier = 1 + self.__timeout = 5 + self.__ser = None + self.__tcpClientSocket = None + self.__connected = False + # Constructor for RTU + if len(params) == 1 & isinstance(params[0], str): + serial = importlib.import_module("serial") + self.serialPort = params[0] + self.__baudrate = 9600 + self.__parity = Parity.even + self.__stopbits = Stopbits.one + self.__transactionIdentifier = 0 + self.__ser = serial.Serial() + + # Constructor for TCP + elif (len(params) == 2) & isinstance(params[0], str) & isinstance(params[1], int): + self.__tcpClientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.__ipAddress = params[0] + self.__port = params[1] + + def connect(self): + """ + Connects to a Modbus-TCP Server or a Modbus-RTU Slave with the given Parameters + """ + if self.__ser is not None: + serial = importlib.import_module("serial") + if self.__stopbits == 0: + self.__ser.stopbits = serial.STOPBITS_ONE + elif self.__stopbits == 1: + self.__ser.stopbits = serial.STOPBITS_TWO + elif self.__stopbits == 2: + self.__ser.stopbits = serial.STOPBITS_ONE_POINT_FIVE + if self.__parity == 0: + self.__ser.parity = serial.PARITY_EVEN + elif self.__parity == 1: + self.__ser.parity = serial.PARITY_ODD + elif self.__parity == 2: + self.__ser.parity = serial.PARITY_NONE + + self.__ser = serial.Serial(self.serialPort, self.__baudrate, timeout=self.__timeout, + parity=self.__ser.parity, stopbits=self.__ser.stopbits, xonxoff=0, rtscts=0) + self.__ser.writeTimeout = self.__timeout + # print (self.ser) + if self.__tcpClientSocket is not None: + self.__tcpClientSocket.settimeout(5) + self.__tcpClientSocket.connect((self.__ipAddress, self.__port)) + + self.__connected = True + self.__thread = threading.Thread(target=self.__listen, args=()) + self.__thread.start() + + def __listen(self): + self.__stoplistening = False + self.__receivedata = bytearray() + try: + while not self.__stoplistening: + if len(self.__receivedata) == 0: + self.__receivedata = bytearray() + self.__timeout = 500 + if self.__tcpClientSocket is not None: + self.__receivedata = self.__tcpClientSocket.recv(256) + except socket.timeout: + self.__receivedata = None + + def close(self): + """ + Closes Serial port, or TCP-Socket connection + """ + if self.__ser is not None: + self.__ser.close() + if self.__tcpClientSocket is not None: + self.__stoplistening = True + self.__tcpClientSocket.shutdown(socket.SHUT_RDWR) + self.__tcpClientSocket.close() + self.__connected = False + + def read_discreteinputs(self, starting_address, quantity): + """ + Read Discrete Inputs from Master device (Function code 2) + starting_address: First discrete input to be read + quantity: Numer of discrete Inputs to be read + returns: Boolean Array [0..quantity-1] which contains the discrete Inputs + """ + self.__transactionIdentifier += 1 + if self.__ser is not None: + if self.__ser.closed: + raise Exception.SerialPortNotOpenedException("serial port not opened") + if (starting_address > 65535) | (quantity > 2000): + raise ValueError("Starting address must be 0 - 65535; quantity must be 0 - 2000") + function_code = 2 + length = 6 + transaction_identifier_lsb = self.__transactionIdentifier & 0xFF + transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8) + length_lsb = length & 0xFF + length_msb = (length & 0xFF00) >> 8 + starting_address_lsb = starting_address & 0xFF + starting_address_msb = (starting_address & 0xFF00) >> 8 + quantity_lsb = quantity & 0xFF + quantity_msb = (quantity & 0xFF00) >> 8 + if self.__ser is not None: + data = bytearray( + [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantity_msb, + quantity_lsb, 0, 0]) + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + data[6] = crcLSB + data[7] = crcMSB + self.__ser.write(data) + if quantity % 8 != 0: + bytes_to_read = 6 + int(quantity / 8) + else: + bytes_to_read = 5 + int(quantity / 8) + data = self.__ser.read(bytes_to_read) + b = bytearray(data) + data = b + if len(data) < bytes_to_read: + raise Exceptions.TimeoutError('Read timeout Exception') + if (data[1] == 0x82) & (data[2] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1] == 0x82) & (data[2] == 0x02): + raise Exceptions.starting_addressInvalidException( + "Starting address invalid or starting address + quantity invalid") + if (data[1] == 0x82) & (data[2] == 0x03): + raise Exceptions.QuantityInvalidException("quantity invalid") + if (data[1] == 0x82) & (data[2] == 0x04): + raise Exceptions.ModbusException("error reading") + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]): + raise Exceptions.CRCCheckFailedException("CRC check failed") + myList = list() + for i in range(0, quantity): + myList.append(bool((data[int(i / 8) + 3] >> int(i % 8)) & 0x1)) + return myList + else: + protocolIdentifierLSB = 0x00 + protocolIdentifierMSB = 0x00 + length_lsb = 0x06 + length_msb = 0x00 + data = bytearray( + [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB, + length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb, + starting_address_lsb, quantity_msb, quantity_lsb]) + self.__tcpClientSocket.send(data) + self.__receivedata = bytearray() + if quantity % 8 != 0: + bytes_to_read = 9 + int(quantity / 8) + else: + bytes_to_read = 8 + int(quantity / 8) + try: + while len(self.__receivedata) == 0: + pass + except Exception: + raise Exception('Read Timeout') + + data = bytearray(self.__receivedata) + + if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x02): + raise Exceptions.starting_addressInvalidException( + "Starting address invalid or starting address + quantity invalid") + if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x03): + raise Exceptions.QuantityInvalidException("quantity invalid") + if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x04): + raise Exceptions.ModbusException("error reading") + myList = list() + for i in range(0, quantity): + myList.append(bool((data[int(i / 8) + 3 + 6] >> int(i % 8)) & 0x1)) + return myList + + def read_coils(self, starting_address, quantity): + """ + Read Coils from Master device (Function code 1) + starting_address: First coil to be read + quantity: Numer of coils to be read + returns: Boolean Array [0..quantity-1] which contains the coils + """ + self.__transactionIdentifier += 1 + if self.__ser is not None: + if self.__ser.closed: + raise Exception.SerialPortNotOpenedException("serial port not opened") + if (starting_address > 65535) | (quantity > 2000): + raise ValueError("Starting address must be 0 - 65535; quantity must be 0 - 2000") + function_code = 1 + length = 6 + transaction_identifier_lsb = self.__transactionIdentifier & 0xFF + transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8) + length_lsb = length & 0xFF + length_msb = (length & 0xFF00) >> 8 + starting_address_lsb = starting_address & 0xFF + starting_address_msb = (starting_address & 0xFF00) >> 8 + quantity_lsb = quantity & 0xFF + quantity_msb = (quantity & 0xFF00) >> 8 + if self.__ser is not None: + data = bytearray( + [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantity_msb, + quantity_lsb, 0, 0]) + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + data[6] = crcLSB + data[7] = crcMSB + self.__ser.write(data) + if quantity % 8 != 0: + bytes_to_read = 6 + int(quantity / 8) + else: + bytes_to_read = 5 + int(quantity / 8) + data = self.__ser.read(bytes_to_read) + b = bytearray(data) + data = b + if len(data) < bytes_to_read: + raise Exceptions.TimeoutError('Read timeout Exception') + if (data[1] == 0x81) & (data[2] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1] == 0x81) & (data[2] == 0x02): + raise Exceptions.starting_addressInvalidException( + "Starting address invalid or starting address + quantity invalid") + if (data[1] == 0x81) & (data[2] == 0x03): + raise Exceptions.QuantityInvalidException("quantity invalid") + if (data[1] == 0x81) & (data[2] == 0x04): + raise Exceptions.ModbusException("error reading") + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]): + raise Exceptions.CRCCheckFailedException("CRC check failed") + myList = list() + for i in range(0, quantity): + myList.append(bool((data[int(i / 8) + 3] >> int(i % 8)) & 0x1)) + return myList + else: + protocolIdentifierLSB = 0x00 + protocolIdentifierMSB = 0x00 + length_lsb = 0x06 + length_msb = 0x00 + data = bytearray( + [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB, + length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb, + starting_address_lsb, quantity_msb, quantity_lsb]) + self.__tcpClientSocket.send(data) + self.__receivedata = bytearray() + if (quantity % 8 != 0): + bytes_to_read = 10 + int(quantity / 8) + else: + bytes_to_read = 9 + int(quantity / 8) + try: + while len(self.__receivedata) == 0: + pass + except Exception: + raise Exception('Read Timeout') + data = bytearray(self.__receivedata) + if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x02): + raise Exceptions.starting_addressInvalidException( + "Starting address invalid or starting address + quantity invalid") + if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x03): + raise Exceptions.QuantityInvalidException("quantity invalid") + if (data[1 + 6] == 0x82) & (data[2 + 6] == 0x04): + raise Exceptions.ModbusException("error reading") + myList = list() + for i in range(0, quantity): + myList.append(bool((data[int(i / 8) + 3 + 6] >> int(i % 8)) & 0x1)) + return myList + + def read_holdingregisters(self, starting_address, quantity): + """ + Read Holding Registers from Master device (Function code 3) + starting_address: First holding register to be read + quantity: Number of holding registers to be read + returns: Int Array [0..quantity-1] which contains the holding registers + """ + self.__transactionIdentifier += 1 + if self.__ser is not None: + if self.__ser.closed: + raise Exception.SerialPortNotOpenedException("serial port not opened") + if (starting_address > 65535) | (quantity > 125): + raise ValueError("Starting address must be 0 - 65535; quantity must be 0 - 125") + function_code = 3 + length = 6 + transaction_identifier_lsb = self.__transactionIdentifier & 0xFF + transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8) + length_lsb = length & 0xFF + length_msb = (length & 0xFF00) >> 8 + starting_address_lsb = starting_address & 0xFF + starting_address_msb = (starting_address & 0xFF00) >> 8 + quantity_lsb = quantity & 0xFF + quantity_msb = (quantity & 0xFF00) >> 8 + if self.__ser is not None: + data = bytearray( + [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantity_msb, + quantity_lsb, 0, 0]) + + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + data[6] = crcLSB + data[7] = crcMSB + + self.__ser.write(data) + bytes_to_read = 5 + int(quantity * 2) + data = self.__ser.read(bytes_to_read) + b = bytearray(data) + data = b + + if len(data) < bytes_to_read: + raise Exceptions.TimeoutError('Read timeout Exception') + if (data[1] == 0x83) & (data[2] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1] == 0x83) & (data[2] == 0x02): + raise Exceptions.starting_addressInvalidException( + "Starting address invalid or starting address + quantity invalid") + if (data[1] == 0x83) & (data[2] == 0x03): + raise Exceptions.QuantityInvalidException("quantity invalid") + if (data[1] == 0x83) & (data[2] == 0x04): + raise Exceptions.ModbusException("error reading") + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]): + raise Exceptions.CRCCheckFailedException("CRC check failed") + + myList = list() + for i in range(0, quantity): + myList.append((data[i * 2 + 3] << 8) + data[i * 2 + 4]) + return myList + else: + protocolIdentifierLSB = 0x00 + protocolIdentifierMSB = 0x00 + length_lsb = 0x06 + length_msb = 0x00 + data = bytearray( + [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB, + length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb, + starting_address_lsb, quantity_msb, quantity_lsb]) + self.__tcpClientSocket.send(data) + bytes_to_read = 9 + int(quantity * 2) + self.__receivedata = bytearray() + try: + while len(self.__receivedata) == 0: + pass + except Exception: + raise Exception('Read Timeout') + data = bytearray(self.__receivedata) + if (data[1 + 6] == 0x83) & (data[2 + 6] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1 + 6] == 0x83) & (data[2 + 6] == 0x02): + raise Exceptions.starting_addressInvalidException( + "Starting address invalid or starting address + quantity invalid") + if (data[1 + 6] == 0x83) & (data[2 + 6] == 0x03): + raise Exceptions.QuantityInvalidException("quantity invalid") + if (data[1 + 6] == 0x83) & (data[2 + 6] == 0x04): + raise Exceptions.ModbusException("error reading") + myList = list() + for i in range(0, quantity): + myList.append((data[i * 2 + 3 + 6] << 8) + data[i * 2 + 4 + 6]) + return myList + + def read_inputregisters(self, starting_address, quantity): + """ + Read Input Registers from Master device (Function code 4) + starting_address : First input register to be read + quantity: Number of input registers to be read + returns: Int Array [0..quantity-1] which contains the input registers + """ + self.__transactionIdentifier += 1 + if self.__ser is not None: + if self.__ser.closed: + raise Exception.SerialPortNotOpenedException("serial port not opened") + if (starting_address > 65535) | (quantity > 125): + raise ValueError("Starting address must be 0 - 65535 quantity must be 0 - 125") + function_code = 4 + length = 6 + transaction_identifier_lsb = self.__transactionIdentifier & 0xFF + transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8) + length_lsb = length & 0xFF + length_msb = (length & 0xFF00) >> 8 + starting_address_lsb = starting_address & 0xFF + starting_address_msb = (starting_address & 0xFF00) >> 8 + quantity_lsb = quantity & 0xFF + quantity_msb = (quantity & 0xFF00) >> 8 + if self.__ser is not None: + data = bytearray( + [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantity_msb, + quantity_lsb, 0, 0]) + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + data[6] = crcLSB + data[7] = crcMSB + + self.__ser.write(data) + bytes_to_read = 5 + int(quantity * 2) + + data = self.__ser.read(bytes_to_read) + + b = bytearray(data) + data = b + + if len(data) < bytes_to_read: + raise Exceptions.TimeoutError("Read timeout Exception") + if (data[1] == 0x84) & (data[2] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1] == 0x84) & (data[2] == 0x02): + raise Exceptions.starting_addressInvalidException( + "Starting address invalid or starting address + quantity invalid") + if (data[1] == 0x84) & (data[2] == 0x03): + raise Exceptions.QuantityInvalidException("quantity invalid") + if (data[1] == 0x84) & (data[2] == 0x04): + raise Exceptions.ModbusException("error reading") + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]): + raise Exceptions.CRCCheckFailedException("CRC check failed") + myList = list() + for i in range(0, quantity): + myList.append((data[i * 2 + 3] << 8) + data[i * 2 + 4]) + return myList + else: + protocolIdentifierLSB = 0x00 + protocolIdentifierMSB = 0x00 + length_lsb = 0x06 + length_msb = 0x00 + data = bytearray( + [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB, + length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb, + starting_address_lsb, quantity_msb, quantity_lsb]) + self.__tcpClientSocket.send(data) + bytes_to_read = 9 + int(quantity * 2) + self.__receivedata = bytearray() + try: + while len(self.__receivedata) == 0: + pass + except Exception: + raise Exception('Read Timeout') + data = bytearray(self.__receivedata) + if (data[1 + 6] == 0x84) & (data[2 + 6] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1 + 6] == 0x84) & (data[2 + 6] == 0x02): + raise Exceptions.starting_addressInvalidException( + "Starting address invalid or starting address + quantity invalid") + if (data[1 + 6] == 0x84) & (data[2 + 6] == 0x03): + raise Exceptions.QuantityInvalidException("quantity invalid") + if (data[1 + 6] == 0x84) & (data[2 + 6] == 0x04): + raise Exceptions.ModbusException("error reading") + myList = list() + for i in range(0, quantity): + myList.append((data[i * 2 + 3 + 6] << 8) + data[i * 2 + 4 + 6]) + return myList + + def write_single_coil(self, starting_address, value): + """ + Write single Coil to Master device (Function code 5) + starting_address: Coil to be written + value: Coil Value to be written + """ + self.__transactionIdentifier += 1 + if self.__ser is not None: + if self.__ser.closed: + raise Exception.SerialPortNotOpenedException("serial port not opened") + function_code = 5 + length = 6 + transaction_identifier_lsb = self.__transactionIdentifier & 0xFF + transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8) + length_lsb = length & 0xFF + length_msb = (length & 0xFF00) >> 8 + starting_address_lsb = starting_address & 0xFF + starting_address_msb = (starting_address & 0xFF00) >> 8 + if value: + valueLSB = 0x00 + valueMSB = (0xFF00) >> 8 + else: + valueLSB = 0x00 + valueMSB = (0x00) >> 8 + if self.__ser is not None: + data = bytearray( + [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, valueMSB, valueLSB, + 0, 0]) + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + data[6] = crcLSB + data[7] = crcMSB + self.__ser.write(data) + bytes_to_read = 8 + data = self.__ser.read(bytes_to_read) + b = bytearray(data) + data = b + if len(data) < bytes_to_read: + raise Exceptions.TimeoutError('Read timeout Exception') + if (data[1] == 0x85) & (data[2] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1] == 0x85) & (data[2] == 0x02): + raise Exceptions.starting_addressInvalidException("Address invalid") + if (data[1] == 0x85) & (data[2] == 0x03): + raise Exceptions.QuantityInvalidException("Value invalid") + if (data[1] == 0x85) & (data[2] == 0x04): + raise Exceptions.ModbusException("error reading") + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]): + raise Exceptions.CRCCheckFailedException("CRC check failed") + if data[1] == self.__unitIdentifier: + return True + else: + return False + else: + protocolIdentifierLSB = 0x00 + protocolIdentifierMSB = 0x00 + length_lsb = 0x06 + length_msb = 0x00 + data = bytearray( + [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB, + length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb, + starting_address_lsb, valueMSB, valueLSB]) + self.__tcpClientSocket.send(data) + bytes_to_read = 12 + self.__receivedata = bytearray() + try: + while len(self.__receivedata) == 0: + pass + except Exception: + raise Exception('Read Timeout') + data = bytearray(self.__receivedata) + if (data[1 + 6] == 0x85) & (data[2 + 6] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1 + 6] == 0x85) & (data[2 + 6] == 0x02): + raise Exceptions.starting_addressInvalidException("Address invalid") + if (data[1 + 6] == 0x85) & (data[2 + 6] == 0x03): + raise Exceptions.QuantityInvalidException("Value invalid") + if (data[1 + 6] == 0x85) & (data[2 + 6] == 0x04): + raise Exceptions.ModbusException("error reading") + + return True + + def write_single_register(self, starting_address, value): + """ + Write single Register to Master device (Function code 6) + starting_address: Register to be written + value: Register Value to be written + """ + self.__transactionIdentifier += 1 + if self.__ser is not None: + if self.__ser.closed: + raise Exception.SerialPortNotOpenedException("serial port not opened") + function_code = 6 + length = 6 + transaction_identifier_lsb = self.__transactionIdentifier & 0xFF + transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8) + length_lsb = length & 0xFF + length_msb = (length & 0xFF00) >> 8 + starting_address_lsb = starting_address & 0xFF + starting_address_msb = (starting_address & 0xFF00) >> 8 + valueLSB = value & 0xFF + valueMSB = (value & 0xFF00) >> 8 + if self.__ser is not None: + data = bytearray( + [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, valueMSB, valueLSB, + 0, 0]) + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + data[6] = crcLSB + data[7] = crcMSB + self.__ser.write(data) + bytes_to_read = 8 + data = self.__ser.read(bytes_to_read) + b = bytearray(data) + data = b + # Check for Exception + if len(data) < bytes_to_read: + raise Exceptions.TimeoutError('Read timeout Exception') + if (data[1] == 0x86) & (data[2] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1] == 0x86) & (data[2] == 0x02): + raise Exceptions.starting_addressInvalidException("Register address invalid") + if (data[1] == 0x86) & (data[2] == 0x03): + raise Exceptions.QuantityInvalidException("Invalid Register Value") + if (data[1] == 0x86) & (data[2] == 0x04): + raise Exceptions.ModbusException("error reading") + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]): + raise Exceptions.CRCCheckFailedException("CRC check failed") + + if data[1] == self.__unitIdentifier: + return True + else: + return False + else: + protocolIdentifierLSB = 0x00 + protocolIdentifierMSB = 0x00 + length_lsb = 0x06 + length_msb = 0x00 + data = bytearray( + [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB, + length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb, + starting_address_lsb, valueMSB, valueLSB]) + self.__tcpClientSocket.send(data) + bytes_to_read = 12 + self.__receivedata = bytearray() + try: + while (len(self.__receivedata) == 0): + pass + except Exception: + raise Exception('Read Timeout') + data = bytearray(self.__receivedata) + if (data[1 + 6] == 0x86) & (data[2 + 6] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1 + 6] == 0x86) & (data[2 + 6] == 0x02): + raise Exceptions.starting_addressInvalidException("Register address invalid") + if (data[1 + 6] == 0x86) & (data[2 + 6] == 0x03): + raise Exceptions.QuantityInvalidException("Invalid Register Value") + if (data[1 + 6] == 0x86) & (data[2 + 6] == 0x04): + raise Exceptions.ModbusException("error reading") + + return True + + def write_multiple_coils(self, starting_address, values): + """ + Write multiple coils to Master device (Function code 15) + starting_address : First coil to be written + values: Coil Values [0..quantity-1] to be written + """ + self.__transactionIdentifier += 1 + if self.__ser is not None: + if self.__ser.closed: + raise Exception.SerialPortNotOpenedException("serial port not opened") + function_code = 15 + length = 6 + transaction_identifier_lsb = self.__transactionIdentifier & 0xFF + transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8) + length_lsb = length & 0xFF + length_msb = (length & 0xFF00) >> 8 + starting_address_lsb = starting_address & 0xFF + starting_address_msb = (starting_address & 0xFF00) >> 8 + quantityLSB = len(values) & 0xFF + quantityMSB = (len(values) & 0xFF00) >> 8 + valueToWrite = list() + singleCoilValue = 0 + for i in range(0, len(values)): + if ((i % 8) == 0): + if i > 0: + valueToWrite.append(singleCoilValue) + singleCoilValue = 0 + + if values[i] == True: + coilValue = 1 + else: + coilValue = 0 + singleCoilValue = ((coilValue) << (i % 8) | (singleCoilValue)) + + valueToWrite.append(singleCoilValue) + if self.__ser is not None: + data = bytearray( + [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantityMSB, + quantityLSB]) + data.append(len(valueToWrite)) # Bytecount + for i in range(0, len(valueToWrite)): + data.append(valueToWrite[i] & 0xFF) + + crc = self.__calculateCRC(data, len(data), 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + data.append(crcLSB) + data.append(crcMSB) + self.__ser.write(data) + bytes_to_read = 8 + data = self.__ser.read(bytes_to_read) + b = bytearray(data) + data = b + if len(data) < bytes_to_read: + raise Exceptions.TimeoutError('Read timeout Exception') + if (data[1] == 0x8F) & (data[2] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1] == 0x8F) & (data[2] == 0x02): + raise Exceptions.starting_addressInvalidException( + "Starting address invalid or starting address + quantity invalid") + if (data[1] == 0x8F) & (data[2] == 0x03): + raise Exceptions.QuantityInvalidException("quantity invalid") + if (data[1] == 0x8F) & (data[2] == 0x04): + raise Exceptions.ModbusException("error reading") + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]): + raise Exceptions.CRCCheckFailedException("CRC check failed") + if data[1] == self.__unitIdentifier: + return True + else: + return False + else: + protocolIdentifierLSB = 0x00 + protocolIdentifierMSB = 0x00 + length_lsb = 0x06 + length_msb = 0x00 + data = bytearray( + [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB, + length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb, + starting_address_lsb, quantityMSB, quantityLSB]) + data.append(len(valueToWrite)) # Bytecount + for i in range(0, len(valueToWrite)): + data.append(valueToWrite[i] & 0xFF) + self.__tcpClientSocket.send(data) + bytes_to_read = 12 + self.__receivedata = bytearray() + try: + while (len(self.__receivedata) == 0): + pass + except Exception: + raise Exception('Read Timeout') + data = bytearray(self.__receivedata) + if (data[1] == 0x8F) & (data[2] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1] == 0x8F) & (data[2] == 0x02): + raise Exceptions.starting_addressInvalidException( + "Starting address invalid or starting address + quantity invalid") + if (data[1] == 0x8F) & (data[2] == 0x03): + raise Exceptions.QuantityInvalidException("quantity invalid") + if (data[1] == 0x8F) & (data[2] == 0x04): + raise Exceptions.ModbusException("error reading") + + return True + + def write_multiple_registers(self, starting_address, values): + """ + Write multiple registers to Master device (Function code 16) + starting_address: First register to be written + values: Register Values [0..quantity-1] to be written + """ + self.__transactionIdentifier += 1 + if self.__ser is not None: + if self.__ser.closed: + raise Exception.SerialPortNotOpenedException("serial port not opened") + function_code = 16 + length = 6 + transaction_identifier_lsb = self.__transactionIdentifier & 0xFF + transaction_identifier_msb = ((self.__transactionIdentifier & 0xFF00) >> 8) + length_lsb = length & 0xFF + length_msb = (length & 0xFF00) >> 8 + starting_address_lsb = starting_address & 0xFF + starting_address_msb = (starting_address & 0xFF00) >> 8 + quantityLSB = len(values) & 0xFF + quantityMSB = (len(values) & 0xFF00) >> 8 + valueToWrite = list() + for i in range(0, len(values)): + valueToWrite.append(values[i]) + if self.__ser is not None: + data = bytearray( + [self.__unitIdentifier, function_code, starting_address_msb, starting_address_lsb, quantityMSB, + quantityLSB]) + data.append(len(valueToWrite) * 2) # Bytecount + for i in range(0, len(valueToWrite)): + data.append((valueToWrite[i] & 0xFF00) >> 8) + data.append(valueToWrite[i] & 0xFF) + crc = self.__calculateCRC(data, len(data), 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + data.append(crcLSB) + data.append(crcMSB) + self.__ser.write(data) + bytes_to_read = 8 + data = self.__ser.read(bytes_to_read) + b = bytearray(data) + data = b + if len(data) < bytes_to_read: + raise Exceptions.TimeoutError('Read timeout Exception') + if (data[1] == 0x90) & (data[2] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1] == 0x90) & (data[2] == 0x02): + raise Exceptions.starting_addressInvalidException( + "Starting address invalid or starting address + quantity invalid") + if (data[1] == 0x90) & (data[2] == 0x03): + raise Exceptions.QuantityInvalidException("quantity invalid") + if (data[1] == 0x90) & (data[2] == 0x04): + raise Exceptions.ModbusException("error reading") + crc = self.__calculateCRC(data, len(data) - 2, 0) + crcLSB = crc & 0xFF + crcMSB = (crc & 0xFF00) >> 8 + if (crcLSB != data[len(data) - 2]) & (crcMSB != data[len(data) - 1]): + raise Exceptions.CRCCheckFailedException("CRC check failed") + if data[1] == self.__unitIdentifier: + return True + else: + return False + else: + protocolIdentifierLSB = 0x00 + protocolIdentifierMSB = 0x00 + length_lsb = 0x06 + length_msb = 0x00 + data = bytearray( + [transaction_identifier_msb, transaction_identifier_lsb, protocolIdentifierMSB, protocolIdentifierLSB, + length_msb, length_lsb, self.__unitIdentifier, function_code, starting_address_msb, + starting_address_lsb, quantityMSB, quantityLSB]) + data.append(len(valueToWrite) * 2) # Bytecount + for i in range(0, len(valueToWrite)): + data.append((valueToWrite[i] & 0xFF00) >> 8) + data.append(valueToWrite[i] & 0xFF) + + self.__tcpClientSocket.send(data) + bytes_to_read = 12 + self.__receivedata = bytearray() + try: + while len(self.__receivedata) == 0: + pass + except Exception: + raise Exception('Read Timeout') + data = bytearray(self.__receivedata) + if (data[1] == 0x90) & (data[2] == 0x01): + raise Exceptions.function_codeNotSupportedException("Function code not supported by master") + if (data[1] == 0x90) & (data[2] == 0x02): + raise Exceptions.starting_addressInvalidException( + "Starting address invalid or starting address + quantity invalid") + if (data[1] == 0x90) & (data[2] == 0x03): + raise Exceptions.QuantityInvalidException("quantity invalid") + if (data[1] == 0x90) & (data[2] == 0x04): + raise Exceptions.ModbusException("error reading") + return True + + def __calculateCRC(self, data, numberOfBytes, startByte): + crc = 0xFFFF + for x in range(0, numberOfBytes): + crc = crc ^ data[x] + for _ in range(0, 8): + if (crc & 0x0001) != 0: + crc = crc >> 1 + crc = crc ^ 0xA001 + else: + crc = crc >> 1 + return crc + + @property + def port(self): + """ + Gets the Port were the Modbus-TCP Server is reachable (Standard is 502) + """ + return self.__port + + @port.setter + def port(self, port): + """ + Sets the Port were the Modbus-TCP Server is reachable (Standard is 502) + """ + self.__port = port + + @property + def ipaddress(self): + """ + Gets the IP-Address of the Server to be connected + """ + return self.__ipAddress + + @ipaddress.setter + def ipaddress(self, ipAddress): + """ + Sets the IP-Address of the Server to be connected + """ + self.__ipAddress = ipAddress + + @property + def unitidentifier(self): + """ + Gets the Unit identifier in case of serial connection (Default = 1) + """ + return self.__unitIdentifier + + @unitidentifier.setter + def unitidentifier(self, unitIdentifier): + """ + Sets the Unit identifier in case of serial connection (Default = 1) + """ + self.__unitIdentifier = unitIdentifier + + @property + def baudrate(self): + """ + Gets the Baudrate for serial connection (Default = 9600) + """ + return self.__baudrate + + @baudrate.setter + def baudrate(self, baudrate): + """ + Sets the Baudrate for serial connection (Default = 9600) + """ + self.__baudrate = baudrate + + @property + def parity(self): + """ + Gets the of Parity in case of serial connection + """ + return self.__parity + + @parity.setter + def parity(self, parity): + """ + Sets the of Parity in case of serial connection + Example modbusClient.Parity = Parity.even + """ + self.__parity = parity + + @property + def stopbits(self): + """ + Gets the number of stopbits in case of serial connection + """ + return self.__stopbits + + @stopbits.setter + def stopbits(self, stopbits): + """ + Sets the number of stopbits in case of serial connection + Example: modbusClient.Stopbits = Stopbits.one + """ + self.__stopbits = stopbits + + @property + def timeout(self): + """ + Gets the Timeout + """ + return self.__timeout + + @timeout.setter + def timeout(self, timeout): + """ + Sets the Timeout + """ + self.__timeout = timeout + + def is_connected(self): + """ + Returns true if a connection has been established + """ + return self.__connected + + +class Parity(): + even = 0 + odd = 1 + none = 2 + + +class Stopbits(): + one = 0 + two = 1 + onePointFive = 2 + + +def convert_double_to_two_registers(doubleValue): + """ + Convert 32 Bit Value to two 16 Bit Value to send as Modbus Registers + doubleValue: Value to be converted + return: 16 Bit Register values int[] + """ + myList = list() + myList.append(int(doubleValue & 0x0000FFFF)) # Append Least Significant Word + myList.append(int((doubleValue & 0xFFFF0000) >> 16)) # Append Most Significant Word + return myList + + +def convert_float_to_two_registers(floatValue): + """ + Convert 32 Bit real Value to two 16 Bit Value to send as Modbus Registers + floatValue: Value to be converted + return: 16 Bit Register values int[] + """ + myList = list() + s = bytearray(struct.pack('<f', floatValue)) # little endian + myList.append(s[0] | (s[1] << 8)) # Append Least Significant Word + myList.append(s[2] | (s[3] << 8)) # Append Most Significant Word + + return myList + + +def convert_registers_to_double(registers): + """ + Convert two 16 Bit Registers to 32 Bit long value - Used to receive 32 Bit values from Modbus (Modbus Registers are 16 Bit long) + registers: 16 Bit Registers + return: 32 bit value + """ + returnValue = (int(registers[0]) & 0x0000FFFF) | (int((registers[1]) << 16) & 0xFFFF0000) + return returnValue + + +def convert_registers_to_float(registers): + """ + Convert two 16 Bit Registers to 32 Bit real value - Used to receive float values from Modbus (Modbus Registers are 16 Bit long) + registers: 16 Bit Registers + return: 32 bit value real + """ + b = bytearray(4) + b[0] = registers[0] & 0xff + b[1] = (registers[0] & 0xff00) >> 8 + b[2] = (registers[1] & 0xff) + b[3] = (registers[1] & 0xff00) >> 8 + returnValue = struct.unpack('<f', b) # little Endian + return returnValue + + +if __name__ == "__main__": + modbus_client = ModbusClient("192.168.178.33", 502) + modbus_client.connect() + counter = 0 + while (1): + counter = counter + 1 + modbus_client.unitidentifier = 200 + modbus_client.write_single_register(1, counter) + print(modbus_client.read_holdingregisters(1, 1)) + modbus_client.close() diff --git a/TP2/easymodbus/modbusException.py b/TP2/easymodbus/modbusException.py new file mode 100644 index 0000000000000000000000000000000000000000..af4d59459ca9474b76643fc83cbfeda03faece6e --- /dev/null +++ b/TP2/easymodbus/modbusException.py @@ -0,0 +1,110 @@ +''' +Created on 14.09.2016 + +@author: Stefan Rossmann +''' + + +class ModbusException(Exception): + ''' + classdocs + ''' + + def __init__(self, expression, message): + """ Exception to be thrown if Modbus Server returns error code "Function Code not executed (0x04)" + Attributes: + expression -- input expression in which the error occurred + message -- explanation of the error + """ + self.expression = expression + self.message = message + + +class SerialPortNotOpenedException(ModbusException): + ''' + classdocs + ''' + + def __init__(self, expression, message): + """ Exception to be thrown if serial port is not opened + Attributes: + expression -- input expression in which the error occurred + message -- explanation of the error + """ + self.expression = expression + self.message = message + + +class ConnectionException(ModbusException): + ''' + classdocs + ''' + + def __init__(self, expression, message): + """ Exception to be thrown if Connection to Modbus device failed + Attributes: + expression -- input expression in which the error occurred + message -- explanation of the error + """ + self.expression = expression + self.message = message + + +class FunctionCodeNotSupportedException(ModbusException): + ''' + classdocs + ''' + + def __init__(self, expression, message): + """ Exception to be thrown if Modbus Server returns error code "Function code not supported" + Attributes: + expression -- input expression in which the error occurred + message -- explanation of the error + """ + self.expression = expression + self.message = message + + +class QuantityInvalidException(ModbusException): + ''' + classdocs + ''' + + def __init__(self, expression, message): + """ Exception to be thrown if Modbus Server returns error code "quantity invalid" + Attributes: + expression -- input expression in which the error occurred + message -- explanation of the error + """ + self.expression = expression + self.message = message + + +class StartingAddressInvalidException(ModbusException): + ''' + classdocs + ''' + + def __init__(self, expression, message): + """ Exception to be thrown if Modbus Server returns error code "starting adddress and quantity invalid" + Attributes: + expression -- input expression in which the error occurred + message -- explanation of the error + """ + self.expression = expression + self.message = message + + +class CRCCheckFailedException(ModbusException): + ''' + classdocs + ''' + + def __init__(self, expression, message): + """ Exception to be thrown if CRC Check failed + Attributes: + expression -- input expression in which the error occurred + message -- explanation of the error + """ + self.expression = expression + self.message = message diff --git a/TP2/easymodbus/run.py b/TP2/easymodbus/run.py new file mode 100644 index 0000000000000000000000000000000000000000..84b0e76386b340c73d86d1b8ef38f25a18a3d333 --- /dev/null +++ b/TP2/easymodbus/run.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +''' +Created on 12.09.2016 + +@author: Stefan Rossmann +''' + +# @UnresolvedImport +from easymodbus.modbusClient import * +# @UnresolvedImport + +modbusClient = ModbusClient('127.0.0.1', 502) +#modbusClient = ModbusClient('COM4') +modbusClient.parity = Parity.even +modbusClient.unitidentifier = 2 +modbusClient.baudrate = 9600 +modbusClient.stopbits = Stopbits.one +modbusClient.connect() +discreteInputs = modbusClient.read_discreteinputs(0, 8) +print (discreteInputs) + +holdingRegisters = convert_registers_to_float(modbusClient.read_holdingregisters(0, 2)) +print (holdingRegisters) +inputRegisters = modbusClient.read_inputregisters(0, 8) +print (inputRegisters) +coils = modbusClient.read_coils(0, 8) +print (coils) + +modbusClient.write_single_coil(0, True) +modbusClient.write_single_register(0, 777) +modbusClient.write_multiple_coils(0, [True,True,True,True,True,False,True,True]) +modbusClient.write_multiple_registers(0, convert_float_to_two_registers(3.141517)) +modbusClient.close() \ No newline at end of file diff --git a/TP2/test5.py b/TP2/test5.py new file mode 100644 index 0000000000000000000000000000000000000000..70ef3be131ceb282098aa9ad4d4b6f2f02dec95d --- /dev/null +++ b/TP2/test5.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +""" +Seule Test est à utiliser + +@author: chevrier6 +""" + +from Armoire5 import * +# +# a=Armoire6() +# a.resetAll() +# i=0 +# a.setCharge(i) +# s=a.readMesure(i) +# print(s) +# +# def chenillard(): +# a=Armoire6() +# for i in range(a.nbCharge): +# a.setCharge(i) +# s=a.readMesure(i) +# print(s) + +def pprint(mesure): + output="U={:.2f} I={:.2f} PA={:.2f} PR={:.2f}" + return output.format(mesure[0],mesure[1],mesure[2],mesure[3]) + +def test(charge): + + a=Armoire5() + a.resetAll() + print("charge ",charge) + a.setCharge(charge) + s=a.readMesure(charge) + print(pprint(s), "\nS1" ,pprint(a.readSecteur1()),"\nS2", pprint(a.readSecteur2()),"\n") + a.setSource2(charge) + s=a.readMesure(charge) + print(pprint(s), "\nS1" ,pprint(a.readSecteur1()),"\nS2", pprint(a.readSecteur2()),"\n") + a.unsetCharge(charge) + +# +# def chenillard2(): +# a=Armoire6() +# a.resetAll() +# for i in range(a.nbCharge): +# print("charge ",i) +# a.setCharge(i) +# s=a.readMesure(i) +# print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2()) +# a.setSource2(i) +# s=a.readMesure(i) +# print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2()) +# a.unsetCharge(i) +# +# +# def chenillard3(): +# a=Armoire6() +# a.resetAll() +# for charge in range(a.nbCharge): +# print("charge ",charge) +# a.setCharge(charge) +# u,i,pa,pr=a.readMesure(charge) +# u1,i1,pa1,pr1=a.readSecteur1() +# u2,i2,pa2,pr2=a.readSecteur2() +# print((u,i,pa,pr), "S1" ,a.readSecteur1(),"S2", a.readSecteur2()) +# print(u-u1,i-i1,pa-pa1,pr-pr1) +# print(u-u2,i-i2,pa-pa2,pr-pr2) +# a.setSource2(charge) +# u,i,pa,pr=a.readMesure(charge) +# u1,i1,pa1,pr1=a.readSecteur1() +# u2,i2,pa2,pr2=a.readSecteur2() +# print((u,i,pa,pr), "S1" ,a.readSecteur1(),"S2", a.readSecteur2()) +# print(u-u1,i-i1,pa-pa1,pr-pr1) +# print(u-u2,i-i2,pa-pa2,pr-pr2) +# a.unsetCharge(charge) +# +# def chenillard2b(): +# a=Armoire6() +# a.resetAll() +# for i in range(a.nbCharge): +# print("charge ",i) +# a.toggleCharge(i) +# s=a.readMesure(i) +# print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2()) +# a.setSource2(i) +# s=a.readMesure(i) +# print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2()) +# a.unsetCharge(i) + +#chenillard2b() \ No newline at end of file diff --git a/TP2/test6.py b/TP2/test6.py new file mode 100644 index 0000000000000000000000000000000000000000..89615be8205fc2ab1109e9fac713b1f5151a06e4 --- /dev/null +++ b/TP2/test6.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +""" + + +@author: chevrier6 +""" + +from Armoire6 import * +# +# a=Armoire6() +# a.resetAll() +# i=0 +# a.setCharge(i) +# s=a.readMesure(i) +# print(s) +# +# def chenillard(): +# a=Armoire6() +# for i in range(a.nbCharge): +# a.setCharge(i) +# s=a.readMesure(i) +# print(s) + +def pprint(mesure): + output="U={:.2f} I={:.2f} PA={:.2f} PR={:.2f}" + return output.format(mesure[0],mesure[1],mesure[2],mesure[3]) + +def test(charge): + + a=Armoire6() + a.resetAll() + print("charge ",charge) + a.setCharge(charge) + s=a.readMesure(charge) + print(pprint(s), "\nS1" ,pprint(a.readSecteur1()),"\nS2", pprint(a.readSecteur2()),"\n") + a.setSource2(charge) + s=a.readMesure(charge) + print(pprint(s), "\nS1" ,pprint(a.readSecteur1()),"\nS2", pprint(a.readSecteur2()),"\n") + a.unsetCharge(charge) + + +def chenillard2(): + a=Armoire6() + a.resetAll() + for i in range(a.nbCharge): + print("charge ",i) + a.setCharge(i) + s=a.readMesure(i) + print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2()) + a.setSource2(i) + s=a.readMesure(i) + print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2()) + a.unsetCharge(i) + +# +# def chenillard3(): +# a=Armoire6() +# a.resetAll() +# for charge in range(a.nbCharge): +# print("charge ",charge) +# a.setCharge(charge) +# u,i,pa,pr=a.readMesure(charge) +# u1,i1,pa1,pr1=a.readSecteur1() +# u2,i2,pa2,pr2=a.readSecteur2() +# print((u,i,pa,pr), "S1" ,a.readSecteur1(),"S2", a.readSecteur2()) +# print(u-u1,i-i1,pa-pa1,pr-pr1) +# print(u-u2,i-i2,pa-pa2,pr-pr2) +# a.setSource2(charge) +# u,i,pa,pr=a.readMesure(charge) +# u1,i1,pa1,pr1=a.readSecteur1() +# u2,i2,pa2,pr2=a.readSecteur2() +# print((u,i,pa,pr), "S1" ,a.readSecteur1(),"S2", a.readSecteur2()) +# print(u-u1,i-i1,pa-pa1,pr-pr1) +# print(u-u2,i-i2,pa-pa2,pr-pr2) +# a.unsetCharge(charge) +# +# def chenillard2b(): +# a=Armoire6() +# a.resetAll() +# for i in range(a.nbCharge): +# print("charge ",i) +# a.toggleCharge(i) +# s=a.readMesure(i) +# print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2()) +# a.setSource2(i) +# s=a.readMesure(i) +# print(s, "S1" ,a.readSecteur1(),"S2", a.readSecteur2()) +# a.unsetCharge(i) + +#chenillard2b() \ No newline at end of file