class ModbusClientRS: def __init__(self): self.client = ModbusClient() def writeRegister(self, address, value): if self.client.is_open(): return self.client.write_single_register(address, value) return None def readRegister(self, address, value): if self.client.is_open(): self.client.read_holding_registers(address, value) def connect(self, host, port): # self.client.debug(True) self.client.host(SERVER_HOST) self.client.port(SERVER_PORT) if not self.client.is_open(): if not self.client.open(): print("unable to connect to " + SERVER_HOST + ":" + str(SERVER_PORT)) def is_open(self): return self.client.is_open() def disconnect(self): return self.client.close()
class Modbus: def __init__(self, host, port, unit): self.client = ModbusClient(host, port, unit, timeout=3) def __enter__(self): self.client.open() return self def __exit__(self, exc_type, exc_val, exc_tb): self.client.close() def toFloat(self, ushorts): bs = struct.pack('H', ushorts[0]) + struct.pack('H', ushorts[1]) return struct.unpack('f', bs) def openConnect(self): try: if not self.isOpen: self.client.open() except: self.closeConnect() def closeConnect(self): self.client.close() @property def isOpen(self): return self.client.is_open() def getValue(self, addr): return self.toFloat(self.client.read_holding_registers(addr, 2))[0] def getValues(self, tags): return [(tag, self.getValue(tag)) for tag in tags]
def test(): c = ModbusClient() # uncomment this line to see debug message # c.debug(True) # define modbus server host, port c.host(SERVER_HOST) c.port(SERVER_PORT) while True: # open or reconnect TCP to server if not c.is_open(): if not c.open(): print("unable to connect to " + SERVER_HOST + ":" + str(SERVER_PORT)) # if open() is ok, read register (modbus function 0x03) if c.is_open(): print c.write_single_register(504, intToUint16(-216)) # sleep 2s before next polling time.sleep(2)
def modbus_com(SERVER_HOST, SERVER_PORT, function_code, start_register, amount_of_registers): c = ModbusClient() c.host(SERVER_HOST) c.port(SERVER_PORT) cnt = 0 while True: # open or reconnect TCP to server if not c.is_open(): if not c.open(): print("unable to connect to " + SERVER_HOST + ":" + str(SERVER_PORT)) # if open() is ok, read register (modbus function 0x03) if c.is_open(): if function_code == "3": # Read the amount_of_registers from start_register regs = c.read_holding_registers(int(start_register), int(amount_of_registers)) # if success display registers if regs: print("reg address" + str(start_register) + "to" + str( int(start_register) + int(amount_of_registers) - 1) + ":" + str(regs)) elif function_code == "16": #Future support pass cnt += 1 if cnt >= 2: print("クライアント通信終了") c.close() break # sleep 1s before next polling time.sleep(1)
class com(object): """This class implements the modbusTCP connection functions """ def __init__(self): ''' Constructor for this class. ''' self._port = 0 def __del__(self): ''' Destructor for this class. ''' if self._port !=0: self.close() def open (self,SERVER_HOST = "192.168.0.210",SERVER_PORT = 502,SERVER_UNIT = 201): """Open modbus connection to the ComBox Args: SERVER_HOST: network address of the ComBox. Default='192.168.0.210' SERVER_PORT: modbus TCP port. Default='502' SERVER_UNIT: modbus address of the ComBox. Default='201' Returns: Boolean value True or False """ self._port = ModbusClient(SERVER_HOST, SERVER_PORT, SERVER_UNIT) if not self._port.is_open(): if not self._port.open(): print("unable to connect to " + SERVER_HOST + ":" + str(SERVER_PORT)) return self._port.is_open() def close(self): """Closes the modbusTCP connection Returns: Boolean value True or False """ self._port.close() return not self._port.is_open() def is_connected(self): """This function checks if the connection to the Schneider Conext ComBox is established and if it responds to readout commands. It requests the firmware version of the ComBox and checks for an received bitstream. Returns: Boolean value True or False return """ bitstream = self._port.read_holding_registers(0x001E, 7) # 0x001E Firmware Version str20 r if bitstream: return True else: return False
def make_summary(): SERVER_HOST = "192.168.43.239" SERVER_PORT = 502 SERVER_UNIT_ID = 2 c = ModbusClient() c.host(SERVER_HOST) c.port(SERVER_PORT) c.unit_id(SERVER_UNIT_ID) if not c.is_open(): if not c.open(): print("cannot connect ....") if c.is_open(): # read 54 registers at address 0, store result in regs list regs = c.read_input_registers(0,54) # if success change register value to float if regs: abc = [utils.decode_ieee(f) for f in utils.word_list_to_long(regs)] data = { "Power KWH" : "%0.3f"%abc[0], "Power KVAH" : "%0.3f"%abc[1], "Power KVArP" : "%0.3f"%abc[2], "Power KVArN" : "%0.3f"%abc[3], "Line Voltages V RY" : "%0.3f"%abc[4], "Line Voltages V YB" : "%0.3f"%abc[5], "Line Voltages V BR" : "%0.3f"%abc[6], "Line Current IR" : "%0.3f"%abc[7], "Line Current IY" : "%0.3f"%abc[8], "Line Current IB" : "%0.3f"%abc[9], "Active Power Consumed" : "%0.3f"%abc[10], "Reactive Power Consumed" : "%0.3f"%abc[11], "Apparent Power Consumed" : "%0.3f"%abc[12], "Phase Voltages VRN" : "%0.3f"%abc[13], "Phase Voltages VYN" : "%0.3f"%abc[14], "Phase Voltages VBN" : "%0.3f"%abc[15], "Power Factor" : "%0.3f"%abc[16], "Frequency" : "%0.3f"%abc[17], "Real Power on R" : "%0.3f"%abc[18], "Real Power on Y" : "%0.3f"%abc[19], "Real Power on B" : "%0.3f"%abc[20], "Reactive Power on R" : "%0.3f"%abc[21], "Reactive Power on Y" : "%0.3f"%abc[22], "Reactive Power on B" : "%0.3f"%abc[23], "Apparent Power on R" : "%0.3f"%abc[24], "Apparent Power on Y" : "%0.3f"%abc[25], "Apparent Power on B" : "%0.3f"%abc[26] } mydate = datetime.datetime.now() date=datetime.datetime.strftime(mydate,'%Y/%m/%d--%H:%M:%S') abc.insert(27,date) myfile = open('data.csv','a') with myfile: writer = csv.writer(myfile, delimiter=',', quoting=csv.QUOTE_ALL) writer.writerow(abc) return data
def save_data(self, name_x): SERVER_HOST = name_x SERVER_PORT = 502 c = ModbusClient() c.host(SERVER_HOST) c.port(SERVER_PORT) if not c.is_open(): if not c.open(): toast("failed") if c.is_open(): toast("connected")
def tcp_function_escrita(Porta, Endereco, BaudRate, Registrador, Valor): TCPIP_MODBUS = ModbusClient() TCPIP_MODBUS.host(Endereco) TCPIP_MODBUS.port(Porta) if not TCPIP_MODBUS.is_open(): if not TCPIP_MODBUS.open(): print('Cannot connect to the Modbus TCP/IP Server/Slave') if TCPIP_MODBUS.is_open(): TCPIP_DATA = TCPIP_MODBUS.write_single_register(Registrador, Valor) if TCPIP_DATA: print('TCP/IP successfully Write') else: print('Write Errors in TCP/IP Server/Slave')
def callback(msg): global DATA_TO_HOLDING, DATA_FROM_HOLDING, DATA_FROM_COIL, DATA_TO_COIL global start_addr, test_signal_coil, test_signal_holding global addr_num vx = msg.linear.x * 1000 vy = msg.linear.y * 1000 vz = msg.linear.z * 1000 rx = msg.angular.x * 1000 ry = msg.angular.y * 1000 rz = msg.angular.z * 1000 DATA_TO_HOLDING = [vx, vy, vz, rx, ry, rz] c = ModbusClient(host=MODBUS_SPEC['SERVER_HOST'], port=MODBUS_SPEC['SERVER_PORT']) ## polling loop # keep TCP open if not c.is_open(): c.open() #print('DATA_TO_HOLDING = %s' % (DATA_TO_HOLDING)) if DATA_TO_HOLDING is not None and len(DATA_TO_HOLDING) is not 0: if c.write_multiple_registers(MDS_ADDR_W['addr_start_holding_W'], DATA_TO_HOLDING): print('write holding ok from addr %s with list %s' % (MDS_ADDR_W['addr_start_holding_W'], DATA_TO_HOLDING)) else: print('write holding error from addr %s with list %s' % (MDS_ADDR_W['addr_start_holding_W'], DATA_TO_HOLDING)) else: print('holding data missing with %s with desired len %s' % (DATA_TO_HOLDING, MDS_ADDR_W['addr_num_holding_W'])) time.sleep(0.1)
def readValueIP(address, port, addr, reg): c = ModbusIPClient() c.host(address) c.port(int(port)) value = -1 if not c.is_open(): if not c.open(): print("Unable to connect to "+address+":"+str(port)) if c.is_open(): try: value = c.read_holding_registers(int(addr), int(reg)) except Exception as e: raise e finally: c.close() return value[0]
def tcp_function(Porta, Endereco, BaudRate, Registrador, Linhas): TCPIP_MODBUS = ModbusClient() TCPIP_MODBUS.host(Endereco) TCPIP_MODBUS.port(Porta) if not TCPIP_MODBUS.is_open(): if not TCPIP_MODBUS.open(): print('Cannot connect to the Modbus TCP/IP Server/Slave') if TCPIP_MODBUS.is_open(): TCPIP_DATA = TCPIP_MODBUS.read_input_registers(Registrador, Linhas) if TCPIP_DATA: print('TCP/IP successfully read') else: print('Read Errors in TCP/IP Server/Slave') return TCPIP_DATA
def connect(host, port): """Connects to the defined HOST AND PORT. returns the client""" c = ModbusClient() c.host(host) c.port(port) if not c.is_open(): if not c.open(): raise Exception() return c
def reader(worker, job): c = ModbusClient(host="localhost", port=502) if not c.is_open() and not c.open(): print("unable to connect to host") if c.is_open(): holdingRegisters = c.read_holding_registers(1, 4) # Imagine we've "energy" value in position 1 with two words energy = (holdingRegisters[0] << 16) | holdingRegisters[1] # Imagine we've "power" value in position 3 with two words power = (holdingRegisters[2] << 16) | holdingRegisters[3] out = {"energy": energy, "power": power} return json.dumps(out) return None
def readPDTemp(num): c = ModbusClient(host='192.168.0.4', port=502, unit_id=4, auto_open=True, auto_close=True) if c.is_open(): registerPD = None registerTemp = None else: c.open() registerPD = None registerTemp = None if num == 4: registerPD = c.read_holding_registers(reg_addr=450, reg_nb=1) registerTemp = c.read_holding_registers(reg_addr=418, reg_nb=3) elif num == 5: registerPD = c.read_holding_registers(reg_addr=451, reg_nb=1) registerTemp = c.read_holding_registers(reg_addr=421, reg_nb=3) elif num == 6: registerPD = c.read_holding_registers(reg_addr=452, reg_nb=1) registerTemp = c.read_holding_registers(reg_addr=424, reg_nb=3) else: print("system error!") param = num, round(time.time()), registerTemp[0] / 10, registerTemp[ 1] / 10, registerTemp[2] / 10, registerPD[0] if registerPD: if registerTemp: try: with conn.cursor() as cursor: cursor.execute(qry, param) conn.commit() except TypeError: print('connection error with Db. Check it.') pass else: print("reboot CAM-4 to get temperature") else: print("reboot CAM-4 to get PD") c.close() result = { 'i': param[0], 'time': param[1], 'Temp_R': param[2], 'Temp_S': param[3], 'Temp_T': param[4], 'PD': param[5] } return result
def checkConnection(host): # A simple function to check if the Modbus connection is open #...using the pyModbus.ModbusClient.is_open() method. client = ModbusClient() client.host(host) client.open() if client.is_open(): status = True else: status = False client.close() return status
def polling_thread(self): c = ModbusClient(host=self.SERVER_HOST, port=self.SERVER_PORT) # polling loop while True: # keep TCP open if not c.is_open(): if not c.open(): print("unable to connect to " + self.SERVER_HOST + ":" + str(self.SERVER_PORT)) # do modbus reading on socket if c.is_open(): print("connection") reg_list = c.read_holding_registers(0, 10) # if read is ok, store result in regs (with thread lock synchronization) if reg_list: with self.regs_lock: self.regs = list(reg_list) # 1s before next polling time.sleep(1)
def polling_thread(): global regs c = ModbusClient(host=SERVER_HOST, port=SERVER_PORT) # polling loop while True: # keep TCP open if not c.is_open(): c.open() # do modbus reading on socket reg_list = c.read_holding_registers(0, 10) # if read is ok, store result in regs (with thread lock synchronization) if reg_list: with regs_lock: regs = list(reg_list) # 1s before next polling time.sleep(1)
class Alicat(Adapter): """Alicat device (e.g. pressure controller) with a Modbus/TCP interface""" def __init__(self, ip_address): super(Alicat, self).__init__(ip_address) self.mb_client = ModbusClient(host=ip_address, timeout=5) def start(self): while True: self.mb_client.open() if self.mb_client.is_open(): break print 'Unable to connect to Alicat device at {}; retrying...'.format( self.ip_address) sleep(1) def stop(self): self.mb_client.close() def read_all(self): if self.a_ins: data = self.mb_client.read_input_registers( self.a_in_range[0], self.a_in_range[1] - self.a_in_range[0] + 1) if not data: raise ConnectionError i0 = self.a_in_range[ 0] # Starting index for looking up values from the data list for d in self.a_ins.values(): if d.length == 2: d.val = data[d.address - i0:d.address - i0 + 2] elif d.length == 1: d.val = data[d.address - i0] def write_all(self): # print 'Write outputs' if self.a_outs: data = [] for d in self.a_outs.values(): if d.length == 2: data += d.raw_array elif d.length == 1: data.append(d.raw_array) self.mb_client.write_multiple_registers(self.a_out_range[0], data)
def polling_thread(): global regs, poll_cycle c = ModbusClient(host=args.host, port=args.port, unit_id=args.unit_id) # polling loop while True: # keep TCP open if not c.is_open(): c.open() # do modbus reading on socket reg_list = c.read_holding_registers(20610,20) # if read is ok, store result in regs (with thread lock synchronization) with regs_lock: if reg_list: regs = list(reg_list) poll_cycle += 1 else: poll_cycle = 0 # 1s before next polling time.sleep(0.2)
def check_connection(self, *args): global c c = ModbusClient(host=ip_, port=int(port_), timeout=0.1, auto_open=True) """There is the bug here, as if it is false (c.is_open() = False) it doesnt show an update on the GUI debug: The c object above is constant""" if not c.is_open(): if not c.open(): self.connection_status = "Disconnected" # print("Unable to connect to " + ip_ + ":" + str(port_)) else: self.connection_status = "Connected" return self.connection_status
def polling_thread(): global regs, client client = ModbusClient(host=SERVER_HOST, port=SERVER_PORT) isOpen = False # polling loop while True: # keep TCP open if not client.is_open(): print("unable to connect to " + SERVER_HOST + ":" + str(SERVER_PORT)) client = ModbusClient(host=SERVER_HOST, port=SERVER_PORT) client.open() # do modbus reading on socket reg_list = client.read_holding_registers(0, 10) # if read is ok, store result in regs (with thread lock synchronization) if reg_list: with threadlock: regs = list(reg_list) # 1s before next polling time.sleep(1)
def send_data(): SERVER_HOST = "169.254.0.12" SERVER_PORT = 502 #this has to be 502 for tcp/ip modbus SERVER_UNIT_ID = 100 #slave id is 100 for schneider powerlogic ion 7650 #default value for ionmeter #subnet mask= 255.240.0.0 #gateway= 0.0.0.0 #Required Registers to be read :- #Va= 40166 2 registers ie. c.read_input_registers(40166,2) #power kw a = 40198 2 registers #kVAR a= 40208 2 registers #kVA a= 40218 2 registers #frequency = 40159 1 register #Ia= 40150 1 register #this function reads the float value for address and number of bits (not required) #def read_float( address, number=1): # reg_l = c.read_holding_registers(address, number ) #can change to read_input_registers just to check # if reg_l: # return [utils.decode_ieee(f) for f in utils.word_list_to_long(reg_l)] # else: # return None c = ModbusClient() c.host(SERVER_HOST) c.port(SERVER_PORT) c.unit_id(SERVER_UNIT_ID) #default slave id for schneider is 100 if not c.is_open(): if not c.open(): print("cannot connect ....") if c.is_open(): #read_holding_registers has an offset of 4000 to begin with while True: voltage_a=c.read_holding_registers(166,1)#list output for integer take voltage_a[0] #voltage_a=voltage_a[0] #print voltage_a current_a=c.read_holding_registers(150,1) #current_a=current_a[0] #print current_a real_power_a=c.read_holding_registers(208,1) #real_power_a=real_power_a[0] #print real_power_a reactive_power_a=c.read_holding_registers(218,1) #reactive_power_a=reactive_power_a[0] #print reactive_power_a apparent_power_a=c.read_holding_registers(218,1) #apparent_power_a=apparent_power_a[0] #print apparent_power_a freq=c.read_holding_registers(159,1) freq=freq[0]/10 #print freq np.array(voltage_a,dtype=float) np.array(current_a,dtype=float) np.array(real_power_a,dtype=float) np.array(reactive_power_a,dtype=float) np.array(apparent_power_a,dtype=float) np.array(freq,dtype=float) data = { "voltage_reading" : voltage_a, "current_reading" : current_a, "real_power_rating" : real_power_a, "reactive_power_rating" : reactive_power_a, "apparent_power_rating" : apparent_power_a, "frequency_reading" : freq } print (data) return data
class Storage_Data(object): def __init__(self): # self.host = input("请输入IP地址:") # self.port = int(input("请输入端口号:")) # self.username = input("请输入用户名:") # self.password = input("请输入密码:") self.host = "192.168.1.30" self.port = 2121 self.username = "******" self.password = "******" self.remote_path = "/data/mgrid/sampler/modbus_map.xml" self.__file = "./modbus_map.xml" self.__old_str = "&" self.__new_str = "-" self.equipid_list = [] self.sigid_list = [] self.reg_addr_list = [] self.name_list = [] self.__client = ModbusClient(host=self.host, port=502, debug=True, auto_open=True) self.__address = 0 self.__register = 50 self.i = 0 self.__conn = connect(host='localhost', port=3306, database="MOTTA_data", user="******", password="******", charset="utf8") self.__cur = self.__conn.cursor() self.float_data = [] # 检测获取到的数据 # 1.获取map表(xml格式) def ftp_connect(self): # 初始化FTP ftp = FTP() # 连接IP地址和端口 ftp.connect(self.host, self.port) # 输入帐号密码登录,如果匿名登录则用空串代替即可 ftp.login(self.username, self.password) # 返回FTP对象 return ftp # 2.下载xml文件 def download_file(self): # 调用ftp_connect()方法 下载文件 ftp = self.ftp_connect() # 设置缓冲块大小 bufsize = 1024 # 以写模式在本地打开文件(当前目录) fp = open("./modbus_map.xml", 'wb') # 接收服务器上文件并写入本地文件 ftp.retrbinary('RETR ' + self.remote_path, fp.write, bufsize) # 关闭文件 fp.close() # 退出FTP self.ftp_connect().quit() # -------------------------------------《处理下载的xml文件》-------------------------------------------------- # 3.替换字符串&,符串&在xml文件中属于特殊字符串,在解析获取xml文件内容时会因为字符串报错 def replace_string(self): self.download_file() # 将xml文件中的&替换成-(XML文件有五个不允许出现的特殊字符) file_data = "" # 打开下载到本地的xml文件 with open(self.__file, "r", encoding="utf-8") as f: # 遍历xml文件行 for line in f: if self.__old_str in line: # Python replace() 方法把字符串中的 old(旧字符串) 替换成 new(新字符串),如果指定第三个参数max,则替换不超过 max 次。 line = line.replace(self.__old_str, self.__new_str) file_data += line # w:打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 with open(self.__file, "w", encoding="utf-8") as f: # 替换含有$字符串的行 f.write(file_data) # 4.获取数据列表(equipid=[...] sigid=[...] reg_addr=[...] name=[...]) def get_data_list(self): self.replace_string() # 打开下载到本地的xml文档对象 dom = xmldom.parse(self.__file) # 得到文档元素对象 documentElement 属性可返回文档的根节点。 root = dom.documentElement # getElementsByTagName() 方法可返回带有指定标签名的对象的集合(是一个文档对象) document_object = root.getElementsByTagName('signal') # 遍历<signal>标签 对象集合 for item in document_object: # getAttribute()方法返回指定属性名的属性值。 equipid = item.getAttribute("equipid") # 将获取的‘equipid’属性值,存到equipid_list列表中 self.equipid_list.append(equipid) sigid = item.getAttribute("sigid") self.sigid_list.append(sigid) reg_addr = item.getAttribute("reg_addr") self.reg_addr_list.append(reg_addr) name = item.getAttribute("name") self.name_list.append(name) # -------------------------------------《IP地址和int类型的互相转换》--------------------------------------- # IP转int型 def iptoint(self, num): list = [] s = num.split(".") for temp in s: a = bin(int(temp))[2:] a = a.zfill(8) list.append(a) g = "".join(list) e = int(g, 2) return e def inttoip(self, num): s = bin(num)[2:] s = s.zfill(32) g = [] h = [] for i in range(0, 32, 8): g.append(s[i:i + 8]) for temp in g: h.append(str(int(temp, 2))) e = ".".join(h) return e # -------------------------------------《通过modbus-tcp协议获取实时数据》--------------------------------------- # 5.实时更新数据并添加到数据库(实时通过while循环反复存储) def get_realtime_data(self): # 判断是否连接成功 (否 否为真) if not self.__client.is_open() and not self.__client.open(): # 在次连接一次,没有连接上则抛出错误 raise RuntimeError('无法连接:请检查端口或IP地址是否正确') while True: # time.sleep(3) if self.__address < len(self.name_list): """ 1.改写源码(read_holding_registers):源码返回的数据为32位 协议为64位数据对不上,通过调试模式返Rx数据,返回数据为(registers, re_debug) 2.开启调试模式获re_debug """ registers, re_debug = self.__client.read_holding_registers( self.__address, self.__register) # 获取50个数据(字符串类型) # print(re_debug) str_list = re_debug.split(" ")[9:-1] a = [str_list[x:x + 4] for x in range(0, len(str_list), 4)] # print(len(a)) for x in a: b = "".join(x) # print(b) # 前面四位不动 后面四位两两交换位置(注意转浮点数时候大端小端问题) c = b[0:4] + b[-2:] + b[4:6] # print(c) # 4位16进制数 转浮点数 d = "%.2f" % struct.unpack('<f', bytes.fromhex(c))[0] # print("%d正在获取(%s)的数据: %s" % (self.i, self.name_list[self.i], d)) print(d) self.input_data(d) self.i += 1 self.__address += 50 else: self.i = 0 self.__address = 0 # time.sleep(3) break # 6.存入数据库 def input_data(self, float_data): # 将得到的浮点数数据存入到数据库 # 获取当前时间 nowTime = datetime.datetime.now() # 格式化当前时间 strTime = nowTime.strftime("%Y-%m-%d %H:%M:%S") # 逻辑删除(在drf中自定义模型,逻辑删除健,设置了默认值,但是只有通过drf存储时才会有默认值,直接在数据库中存储是不会添加默认值的) is_delete = False # divice_ip = self.iptoint(self.host) divice_ip = self.host # print(type(divice_ip)) data = [ self.equipid_list[self.i], self.sigid_list[self.i], self.reg_addr_list[self.i], self.name_list[self.i], float_data, strTime, is_delete, divice_ip ] sql_str = '''insert into tb_xmldata (equipid, sigid, reg_addr, name, float_data, data_time, is_delete, divice_ip) values(%s, %s, %s, %s, %s, %s, %s, %s);''' self.__cur.execute(sql_str, data) self.__conn.commit()
from pyModbusTCP import utils try: c = ModbusClient(host="localhost", port=502) except ValueError: print("Error with host or port params") c = ModbusClient(host="localhost", auto_open=True) if c.open(): regs_list_1 = c.read_holding_registers(0, 10) regs_list_2 = c.read_holding_registers(55, 10) c.close() while True: if c.is_open(): regs_list_1 = c.read_holding_registers(0, 10) regs_list_2 = c.read_holding_registers(55, 10) else: c.open() time.sleep(1) list_16_bits = [0x0123, 0x4567, 0x89ab, 0xcdef] # big endian sample (default) list_32_bits = utils.word_list_to_long(list_16_bits) # display "['0x1234567', '0x89abcdef']" print([hex(i) for i in list_32_bits]) # little endian sample list_32_bits = utils.word_list_to_long(list_16_bits, big_endian=False)
class AmpSwitch(object): def __init__(self, host, port=502, switches=(), debug=False): """ """ self.host = host self.port = port self.debug = debug self.switches = switches self.dev = None self.connect() def __str__(self): return "AmpSwitch(host=%s, port=%s, dev=%s>" % (self.host, self.port, self.dev) def setDebug(self, state): self.debug = state self.connect() def close(self): if self.dev is not None: self.dev.close() self.dev = None def connect(self): """ (re-) establish a connection to the device. """ if self.dev is None: self.dev = ModbusClient() self.dev.debug(self.debug) self.dev.host(self.host) self.dev.port(self.port) if self.dev.is_open(): return True ret = self.dev.open() if not ret: raise RuntimeError("failed to connect to %s:%s" % (self.host, self.port)) return True def readCoils(self): """ Return the state of all our switches. """ self.connect() regs = self.dev.read_coils(0, 16) return regs def setCoils(self, on=(), off=()): """Turn on and off a given set of switches. Argunents --------- on, off : list-like, or a single integer. Notes: ------ The off set is executed first. . There is a command to change all switchees at once, but I have not made it work yet. """ self.connect() if isinstance(on, int): on = on, if isinstance(off, int): off = off, regs0 = self.readCoils() regs1 = regs0[:] for c in off: ret = self.dev.write_single_coil(c, False) regs1[c] = False for c in on: ret = self.dev.write_single_coil(c, True) regs1[c] = True # ret = self.dev.write_multiple_registers(0, regs1) ret = self.readCoils() return ret def chooseCoil(self, n): return self.setCoils(on=n, off=list(range(16)))
class ComBox(): """This class implements functions specific to the Schneider ComBox """ def __init__(self): ''' Constructor for this class. ''' self._port = 0 def __del__(self): ''' Destructor for this class. ''' if self._port !=0: self.close() def open (self,SERVER_HOST = "192.168.0.210",SERVER_PORT = 502,SERVER_UNIT = 201): """Open modbus connection to the ComBox Args: SERVER_HOST: network address of the ComBox. Default='192.168.0.210' SERVER_PORT: modbus TCP port. Default='502' SERVER_UNIT: modbus address of the ComBox. Default='201' Returns: Boolean value True or False """ self._port = ModbusClient(SERVER_HOST, SERVER_PORT, SERVER_UNIT) if not self._port.is_open(): if not self._port.open(): print("unable to connect to " + SERVER_HOST + ":" + str(SERVER_PORT)) return self._port.is_open() def close(self): """Closes the modbusTCP connection Returns: Boolean value True or False """ self._port.close() return not self._port.is_open() def is_connected(self): """This function checks if the connection to the Schneider Conext ComBox is established and if it responds to readout commands. It requests the firmware version of the ComBox and checks for an received bitstream. Returns: Boolean value True or False return """ bitstream = self._port.read_holding_registers(0x001E, 7) # 0x001E Firmware Version str20 r if bitstream: return True else: return False def read_firmware(self): """This function reads the firmware version of the ComBox and returns it as a string. Returns: string {firmware version} """ bitstream = self._port.read_holding_registers(0x001E, 7)# 0x001E Firmware Version str20 r decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = decoder.decode_string(14) return result def read_Grid_Voltage(self): """This function reads the Grid Voltage from the ComBox and returns Volt. Returns: float {Grid Voltage in Volt} """ bitstream = self._port.read_holding_registers(0x004C, 2)# 0x004C Grid Voltage uint32 r decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result =(decoder.decode_32bit_uint())/1000.0 return result def read_Grid_Frequency(self): """This function reads the Grid Frequency from the ComBox and returns it in Hz. Returns: float {Grid Frequency in Hz} """ bitstream = self._port.read_holding_registers(0x004E, 2)# 0x004E Grid Frequency uint32 r decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result =(decoder.decode_32bit_uint())/100.0 return result
class ClientGUI: def __init__(self): self.lock = RLock() self.calibgui = None self.client = ModbusClient() self.register_values_widgets = {} self.counter = 1 self.find_thread = None self.obj_data = None self.stop_signal = False self.__build_ui() def run_ui(self): self.root.mainloop() def __build_ui(self): # ui hierarchy: # #root # connectframe # connectlabel # connectbutton # snapshotbutton # calibbuton # mainframe # registerframe # reglabel # registergridframe # ... # outputframe # outputlabel # outputtext root = Tk() self.root = root root.wm_title("RemoteSurf Modbus Client") root.protocol("WM_DELETE_WINDOW", self.__delete_window) self.font = tkFont.Font(root = root, family = "Helvetica", size = 12) connectframe = Frame(root) connectbutton = Button(connectframe, text = "Connect", command = self.__connectbutton_click) connectlabel = Label(connectframe, text = "Not connected.") calibbutton = Button(connectframe, text = "Calibrate", command = self.__calibbutton_click) homebutton = Button(connectframe, text = "Home", command = self.__homebutton_click) findbutton = Button(connectframe, text = "Find", command = self.__findbutton_click) mainframe = Frame(root) registerframe = Frame(mainframe) reglabel = Label(registerframe, text = "Set registers") registergridframe = Frame(registerframe) # outputframe = Frame(mainframe) # outputlabel = Label(outputframe, text = "Output") # vscrollbar = Scrollbar(outputframe) # hscrollbar = Scrollbar(outputframe) # outputtext = ThreadSafeConsole(outputframe, root, vscrollbar, font = self.font, wrap = NONE) connectframe.pack(side = TOP, fill = X) connectlabel.pack(side = BOTTOM, anchor = W) homebutton.pack(side = RIGHT) findbutton.pack(side = RIGHT) calibbutton.pack(side = RIGHT) connectbutton.pack(side = RIGHT) mainframe.pack(side = BOTTOM, fill = BOTH, expand = YES) registerframe.pack(side = TOP, expand = YES, anchor = W) # outputframe.pack(side = BOTTOM, fill = BOTH, expand = YES) reglabel.pack(side = TOP, anchor = CENTER) registergridframe.pack(side = BOTTOM, anchor = W) # registerframe.config(bg = "cyan") # mainframe.config(bg = "pink") # registergridframe.config(bg = "red") registergridframe.columnconfigure(0, weight = 1) registergridframe.columnconfigure(1, weight = 1) registergridframe.columnconfigure(2, weight = 1) registergridframe.columnconfigure(3, weight = 1) self.x_pad = 10 registergrid_widgets = [] titles = ["Address", "Label", "Value", ""] col = 0 for title in titles: title_label = Label(registergridframe, text = title) title_label.grid(row = 0, column = col, padx = self.x_pad) registergrid_widgets.append(title_label) col += 1 registers_data = [(500, "x"), (501, "y"), (502, "z"), (503, "A"), (504, "B"), (505, "C"), ] for i in range(len(registers_data)): reg_data = registers_data[i] row = i + 1 self.__add_register(registergridframe, reg_data, row, registergrid_widgets) # hscrollbar.config(orient = HORIZONTAL, command = outputtext.xview) # hscrollbar.pack(side = BOTTOM, fill = X) # outputtext.config(state = DISABLED, yscrollcommand = vscrollbar.set, xscrollcommand = hscrollbar.set) #must change to NORMAL before writing text programmatically # outputtext.pack(side = LEFT, fill = BOTH, expand = YES, padx = x_padding, pady = y_padding) # vscrollbar.config(command = outputtext.yview) # vscrollbar.pack(side = RIGHT, fill = Y) self.connectframe = connectframe self.connectlabel = connectlabel self.connectbutton = connectbutton self.mainframe = mainframe self.registerframe = registerframe self.reglabel = reglabel self.registergridframe = registergridframe self.calibbutton = calibbutton # self.outputframe = outputframe # self.outputlabel = outputlabel # self.vscrollbar = vscrollbar # self.hscrollbar = hscrollbar # self.outputtext = outputtext root.update() w, h = root.winfo_width(), root.winfo_height() root.minsize(w, h) x, y = MAINFRAME_POS root.geometry('%dx%d+%d+%d' % (w, h, x, y)) def __homebutton_click(self): values = { 500: 300, 501: 0, 502: 500, 503: 180, 504: 0, 505: 180, } self.set_values(values, go_to_value = False) def __add_register(self, master, data, row, widget_list): regaddresslabel = Label(master, text=str(data[0])) regaddresslabel.grid(row=row, column=0) reglabellabel = Label(master, text=data[1]) reglabellabel.grid(row=row, column=1) regvalueentry = AccessibleEntry(master, justify = RIGHT) regvalueentry.set("0") regvalueentry.grid(row=row, column=2, padx=self.x_pad) regsetbtn = Button(master, text="Set", command = self.__setbutton_click) regsetbtn.grid(row=row, column=3) widget_list.append(regaddresslabel) widget_list.append(reglabellabel) widget_list.append(regvalueentry) widget_list.append(regsetbtn) self.register_values_widgets[data[0]] = (0, regvalueentry) def __calibbutton_click(self): if not self.calibgui: self.calibgui = CalibGUI(self) def __findbutton_click(self): if self.find_thread is None: self.find_thread = Thread(target=self.__find_object) self.find_thread.start() def __find_object(self): import DataCache as DC from glob import glob from os.path import join import numpy as np from SFMSolver import SFMSolver, find_ext_params import Utils print "FINDING" np.set_printoptions(precision=3, suppress=True) files_dir = "out/2017_3_8__14_51_22/" files = glob(join(files_dir, "*.jpg")) masks = [] for f in files: m = f.replace(".jpg", "_mask.png") masks.append(m) sfm = SFMSolver(files, masks) if self.obj_data is None: imgs, kpts, points, data = sfm.calc_data_from_files_triang_simple() self.obj_data = imgs, kpts, points, data else: imgs, kpts, points, data = self.obj_data arr_calib = DC.getData("out/%s/arrangement_calib.p" % ARRANGEMENT_CALIB_DIR) ttc = arr_calib["ttc"] tor = arr_calib["tor"] if "cam_mtx" in arr_calib: print "camMtx, distcoeffs load" Utils.camMtx = arr_calib["cam_mtx"] Utils.dist_coeffs = arr_calib["dist_coeffs"] if self.stop_signal: self.stop_signal = False return for point in FIND_POINTS: values = { 500: point[0], 501: point[1], 502: point[2], 503: point[3], 504: point[4], 505: point[5], } print "set_values call" self.set_values(values, True) print "set_values return" time.sleep(0.5) CamGrabber.capture_if_no_chessboard = True CamGrabber.capture = True time.sleep(0.5) if self.stop_signal: self.stop_signal = False return find_dir = logger.outputdir files = glob("%s/*.jpg" % find_dir) print files # files_dir = "out/2017_4_5__15_57_20/" # files = glob(join(files_dir, "*.jpg")) files.sort() files = files[-len(FIND_POINTS):] results = [] for f in files: res = find_ext_params(f, imgs, kpts, points, data, tor, ttc) results.append(res) if self.stop_signal: self.stop_signal = False return for i in range(len(results)): print i, results[i] write_log((i, results[i])) result = max(results, key=lambda x: x[2]) write_log(result) values = { 500: int(result[0][0] * 10), 501: int(result[0][1] * 10), 502: int(result[0][2] * 10) + 200, 503: int(result[1][2]), 504: int(result[1][1]), 505: int(result[1][0]), } print "num inl: ", result[2] pprint(values) self.set_values(values, go_to_value=False) self.find_thread = None def __connectbutton_click(self): if self.client.is_open(): self.client.close() else: self.client.host(SERVER_HOST) self.client.port(SERVER_PORT) if self.client.open(): write_log("Connection established") self.refresh_values() self.read_robot_pos() else: write_log("ERROR: Connecting failed") self.__update_gui() def read_robot_pos(self): write_log("Reading robot position:") posdict = {} for i in range(1000, 1006): if self.client.is_open(): with self.lock: real_val_uint = self.client.read_input_registers(i)[0] real_val_holding_uint = self.client.read_holding_registers(i)[0] assert real_val_uint == real_val_holding_uint real_val_int = uintToInt16(real_val_uint) posdict[i] = real_val_int write_log("%d, %d" % (i, real_val_int)) else: write_log("ERROR: Read could not be completed, client not connected.") self.__update_gui() break write_log("Read done.") return posdict def refresh_values(self): for address in self.register_values_widgets: if self.client.is_open(): value, widget = self.register_values_widgets[address] with self.lock: real_val_uint = self.client.read_input_registers(address)[0] real_val_holding_uint = self.client.read_holding_registers(address)[0] assert real_val_uint == real_val_holding_uint real_val_int = uintToInt16(real_val_uint) widget.set(str(real_val_int)) self.register_values_widgets[address] = (real_val_int, widget) else: write_log("ERROR: Read could not be completed, client not connected.") self.__update_gui() break write_log("Refresh done.") return self.register_values_widgets def __update_gui(self): if self.client.is_open(): self.connectlabel.config(text = "Connected to: %s:%d" % (SERVER_HOST, SERVER_PORT)) self.connectbutton.config(text = "Disconnect") else: self.connectbutton.config(text = "Connect") self.connectlabel.config(text = "Not connected.") self.root.update() def __print_memory(self): self.refresh_values() write_log("Memory dump:") write_log("------------") for address in self.register_values_widgets: val, widget = self.register_values_widgets[address] write_log("%d, %d" % (address, val)) write_log("------------") def __setbutton_click(self, wait = False): if not self.client.is_open(): write_log("ERROR: Not connected to client") return # writing message counter retval = self.__write_register(COUNTER_REGISTER_OUT, self.counter) if not retval: self.__update_gui() return # writing registers for address in self.register_values_widgets: value, widget = self.register_values_widgets[address] widgetvalue_int = None try: widgetvalue_int = int(widget.get()) except ValueError: write_log("ERROR: Wrong input format in value entry for address: %d" % address) continue if value == widgetvalue_int: continue retval = self.__write_register(address, widgetvalue_int) if retval: self.register_values_widgets[address] = (widgetvalue_int, widget) else: self.__update_gui() self.refresh_values() # message counter wait if wait: global break_wait while not break_wait: with self.lock: counter = self.client.read_input_registers(COUNTER_REGISTER_IN)[0] if counter == self.counter: break time.sleep(0.1) break_wait = False # counter increment self.counter = (self.counter + 1) % 20 if PRINT_ALL_MEMORY_ON_WRITE: self.__print_memory() self.read_robot_pos() def __write_register(self, address, value): if not (-32768 <= value <= 32767): write_log("ERROR: -32768 <= value <= 32767 is false for address: %d" % address) return False widgetvalue_uint = intToUint16(value) if self.client.is_open(): with self.lock: retval = self.client.write_single_register(address, widgetvalue_uint) if retval: write_log("Register written. Address: %d, value: %d" % (address, value)) return True else: write_log("ERROR: Write failed. Address: %d, value: %d" % (address, value)) else: write_log("ERROR: client not connected.") return False def set_values(self, values, wait = True, go_to_value = True): """ :param values: dictionary of { address : value} both int :return: """ for address in values: if address not in self.register_values_widgets: continue val, widget = self.register_values_widgets[address] widget.set(str(values[address])) if go_to_value: self.__setbutton_click(wait) def __delete_window(self): CamGrabber.exit = True self.stop_signal = True self.client.close() self.root.quit()
class Modbus(): def __init__(self, smarthome, gateway_ip, gateway_port=502, gateway_id=1, update_cycle=60): logger.info("Modbus: init plugin") self._sh = smarthome self._gateway_id = int(gateway_id) self._update_cycle = int(update_cycle) self._keylist = {} #self._client = ModbusTcpClient(gateway_ip,port=gateway_port) self._client = ModbusClient(host=gateway_ip, port=gateway_port, auto_open=True, auto_close=True) self._client.unit_id(2) self._client.debug(True) if not self._client.is_open(): if not self._client.open(): logger.error("Modbus: connection to gateway can not be established") else: logger.info("Modbus: connection to gateway established") self._client.close() def run(self): self.alive = True self._sh.scheduler.add('MODBUS', self._update_values, prio=5, cycle=self._update_cycle) def stop(self): self.alive = False self._sh.scheduler.remove('MODBUS') def parse_item(self, item): if 'modbus_gateway_id' in item.conf: gateid = int(item.conf['modbus_gateway_id']) else: gateid = 1 if gateid != self._gateway_id: #logger.debug("Modbus: parse item error (gateway_id is not configured as plugin): {0}".format(item)) return None if 'modbus_cmd' not in item.conf: #logger.debug("Modbus: parse item error (modbus_cmd missing): {0}".format(item)) return None if 'modbus_scaling' not in item.conf: #logger.debug("Modbus: parse item error (modbus_scaling missing): {0}".format(item)) return None if 'modbus_register' in item.conf: logger.debug("Modbus: parse item: {0}".format(item)) register = item.conf['modbus_register'] if not register in self._keylist: self._keylist[register] = {'items': [item], 'logics': []} else: self._keylist[register]['items'].append(item) return None # return self.update_item #else: # return None def parse_logic(self, logic): pass def _update_values(self): for register in self._keylist: for item in self._keylist[register]['items']: if int(item.conf['modbus_cmd']) == 4: reg_list = self._client.read_input_registers(int(item.conf['modbus_register'])-30001, 1) logger.info("Modbus: Plain value: {}".format(str(reg_list[0]))) if reg_list is None: return None if len(reg_list) > 0: phys_value = reg_list[0] / (int(item.conf['modbus_scaling']))# * pow(10, int(item.conf['modbus_decimal'])) logger.info("Modbus: Physical value: {0}".format(phys_value)) item(phys_value, 'MODBUS', ' {0}'.format(phys_value)) elif int(item.conf['modbus_cmd']) == 6: sendvalue = int(item()*int(item.conf['modbus_scaling'])) reg_list = self._client.write_single_register(int(item.conf['modbus_register'])-40001, sendvalue) if not reg_list: logger.info("Modbus: Error writing register") def update_item(self, item, caller=None, source=None, dest=None): if caller != 'MODBUS': logger.info("update item: {0}".format(item.id())) if int(item.conf['modbus_cmd']) == 4: reg_list = self._client.read_input_registers(int(item.conf['modbus_register'])-30001, 1) logger.info("Modbus: Plain value: {}".format(str(reg_list[0]))) if reg_list is None: return None if len(reg_list) > 0: phys_value = reg_list[0] / (int(item.conf['modbus_scaling']))# * pow(10, int(item.conf['modbus_decimal'])) logger.info("Modbus: Physical value: {0}".format(phys_value)) item(phys_value, 'MODBUS', ' {0}'.format(phys_value))
help='Modbus server to raise alert <address>:[<port=502>]/<register>') parser.add_argument('authorized_hosts', nargs='*', help="list of authorized hosts") args = parser.parse_args() # Add own IP address to authorized hosts args.authorized_hosts.append(socket.gethostbyname(socket.gethostname())) # Open Modbus client if needed if args.alert is not None: adr = parse_address(args.alert) args.__dict__.update({k: adr[k] for k in ["host", "port", "register"]}) c = ModbusClient(host=args.host, port=args.port, auto_open=True) if not c.is_open(): if not c.open(): raise ConnectionError( f'cannot connect to Modbus server at {args.host}:{args.port}') # Function called for every paquet handled by the sniffer def callback(p): src = p['IP'].src dst = p['IP'].dst if src not in args.authorized_hosts: if args.alert is not None: c.write_single_register(args.register, 1) print(f"Request from {src} to {dst} detected!")
class modBusWriteRead(): def __init__(self,client_host): self.client_host = client_host self.client_port = 502 self.err_list = [] self.connect() #buradan bağlantı yapılacak; def connect(self): self.modbus_c = ModbusClient() self.modbus_c.host(self.client_host) self.modbus_c.port(self.client_port) if not self.modbus_c.is_open(): if not self.modbus_c.open(): text="unable to connect to " + self.client_host + ":" + str(self.client_port) print(text) def write_data_reg(self,address,list): if self.modbus_c.open(): if len(list)>120: sent_list = self.hazirla_dizi_to_write(list) i = 0 hedef_reg_taban = address for list_to_sent in sent_list: hedef_reg = hedef_reg_taban + (i * 120) a = self.modbus_c.write_multiple_registers(hedef_reg, list_to_sent) if a == None or a == False: self.err_list.append(False) i += 1 else: a = self.modbus_c.write_multiple_registers(address, list) if a == None or a == False: self.err_list.append(False) if len(self.err_list) > 0: self.err_list = [] pass # dikkat # print("data göndermede hata oluştu, tekrar deneyin !") def hazirla_dizi_to_write(self,d_list): # eğer gönderilecek değer 120 den büyük ise aşağıdaki fonksiyon 120 lik diziler döndürüyor r_list = [] g_list = [] i = 0 for index in range(len(d_list)): g_list.append(d_list[index]) i += 1 if i > 119: i = 0 r_list.append(g_list) g_list = [] if (len(d_list) - 1) == index and i < 119: r_list.append(g_list) return r_list def read_data_reg(self,address,reg_count,read_float=False ): # burada 16 lık ya da float olarak okunabiliyor if self.modbus_c.is_open(): if read_float == False: plc_list_int = self.modbus_c.read_holding_registers(address, reg_count) return plc_list_int elif read_float == True: plc_list_f_16=self.modbus_c.read_holding_registers(address,reg_count) if plc_list_f_16 is not None: plc_list_float=self.long_to_float(plc_list_f_16) return plc_list_float def long_to_float(self,list_16): list_float=[] list_16.reverse() list_long=utils.word_list_to_long(list_16) for any_long in list_long: list_float.append(utils.decode_ieee(any_long)) list_float.reverse() return list_float
class JointStatePublisher(): def __init__(self): ip = rospy.get_param("/robot_ip") self.c = ModbusClient(host=ip, auto_open=True, auto_close=False, port=502, debug=False, unit_id=2) rospy.init_node("joint_pos_pub") self.p = rospy.Publisher('/joint_states', JointState, queue_size=1) name = getpass.getuser() f = open( '/home/%s/catkin_ws/src/delta/arm_driver/yaml/joint_limits.yaml' % name, 'r') d = yaml.load(f) f.close() self.dP = d["PUU_limits"] self.dA = d["Angle_limits"] self.joint_states = JointState() self.joint_states.name = [ 'shoulder', 'elbow', 'wrist1', 'wrist2', 'wrist3', 'wrist4' ] def pubAngles(self): if not self.c.is_open(): if not self.c.open(): print("Unable to connect\nTrying to connect...") if self.c.is_open(): j1 = self.c.read_holding_registers(0x0168, 2) j1_a = struct.unpack('i', struct.pack('HH', j1[0], j1[1]))[0] self.j1_angle = radians(j1_a / 1000) j2 = self.c.read_holding_registers(0x016A, 2) j2_a = struct.unpack('i', struct.pack('HH', j2[0], j2[1]))[0] self.j2_angle = radians(j2_a / 1000) j3 = self.c.read_holding_registers(0x016C, 2) j3_a = struct.unpack('i', struct.pack('HH', j3[0], j3[1]))[0] self.j3_angle = radians(j3_a / 1000) j4 = self.c.read_holding_registers(0x016E, 2) j4_a = struct.unpack('i', struct.pack('HH', j4[0], j4[1]))[0] self.j4_angle = radians(j4_a / 1000) j5 = self.c.read_holding_registers(0x0150, 2) j5_a = struct.unpack('i', struct.pack('HH', j5[0], j5[1]))[0] self.j5_angle = radians(j5_a / 1000) j6 = self.c.read_holding_registers(0x0152, 2) j6_a = struct.unpack('i', struct.pack('HH', j6[0], j6[1]))[0] self.j6_angle = radians(j6_a / 1000) self.joint_states.position = [ self.j1_angle, self.j2_angle, -self.j3_angle, -self.j4_angle, -self.j5_angle, -self.j6_angle ] self.joint_states.header.stamp = rospy.Time.now() self.p.publish(self.joint_states)
class Kostal: # Class attributes GridFrequency = 0 # address 0x98 (152) TotalDCPower = 0 # address 0x64 (100) HomeFromGrid = 0 # address 0x6c (108) HomeFromPV = 0 # address 0x72 (114) # # Constructor # def __init__(self, master): self.master = master self.config = master.config self.lastUpdate = 0 # try to read the config file try: self.configConfig = master.config["config"] self.configKostal = master.config["sources"]["Kostal"] except KeyError: self.configConfig = {} self.configKostal = {} # read configuration values and initialize variables self.enabled = self.configKostal.get("enabled", False) self.host = self.configKostal.get("serverIP", None) self.port = int(self.configKostal.get("modbusPort", 1502)) self.unitID = int(self.configKostal.get("unitID", 71)) # Unload if this module is disabled or misconfigured if (not self.enabled) or (not self.host): self.master.releaseModule("lib.TWCManager.EMS", "Kostal") return None # try to open open the Modbus connection try: self.modbus = ModbusClient(host=self.host, port=self.port, unit_id=self.unitID, auto_open=True) if not self.modbus.open() is True: raise ValueError except ValueError: # if connection not possible, print error message and unload module logger.info( "ERROR connecting to inverter. Please check your configuration!" ) self.master.releaseModule("lib.TWCManager.EMS", "Kostal") else: # detected byte order (Little/Big Endian) by reading register 0x05 self.byteorder = ENDIAN_LITTLE if self.modbus.read_holding_registers(5, 1)[0] == ENDIAN_BIG: self.byteorder = ENDIAN_BIG # get basic inverter info and output informations into log inv_model = self.__readModbus(768, "String") inv_class = self.__readModbus(800, "String") inv_serial = self.__readModbus(559, "String") logger.info(inv_model + " " + inv_class + " (S/N: " + inv_serial + ") found.") # module successfully loaded update all values self.__update() # # Destructor # Makes sure that an open Modbus-Connection is gracefully closed # def __del(self): if self.modbus.is_open() is True: self.modbus.close() # # Privat Method for reading Modbus values # read registers directly from the inverter via Modbus protocol # def __readModbus(self, address, data_format="Float"): # open the Modbus connection if neccessary if not self.modbus.is_open(): self.modbus.open() # default data length is 1 ('U16') length = 1 # if we are retreiving floats, its two bytes if data_format == "Float": length = 2 # for strings its either 8, 16 or 32 byte, depending on the register elif data_format == "String": if address in [8, 14, 38, 46, 420, 428, 436, 446, 454, 517]: length = 8 elif address in [535, 559]: length = 16 else: length = 32 # read the raw data from the given Modbus address raw = self.modbus.read_holding_registers(address, length) if raw is None: return False # decode the raw_data if data_format == "U16": return int(raw[0]) elif data_format == "Float": if self.byteorder == ENDIAN_BIG: return float(utils.decode_ieee((raw[0] << 16) + raw[1])) else: return float(utils.decode_ieee((raw[1] << 16) + raw[0])) elif data_format == "String": data_string = "" for value in raw: hex_value = str(hex(value)[2:]) left = int(str(hex_value)[:2], 16) right = int(str(hex_value)[-2:], 16) data_string += chr(left) + chr(right) return str(data_string) # if all failed, return false return False # # Private Method # Update the cached values by reading them from the Modbus # def __update(self): if (int(time.time()) - self.lastUpdate) > MIN_CACHE_SECONDS: # Cache has expired. Fetch values from inverter via Modbus self.GridFrequency = self.__readModbus(152, "Float") self.TotalDCPower = self.__readModbus(100, "Float") self.HomeFromGrid = self.__readModbus(108, "Float") self.HomeFromPV = self.__readModbus(116, "Float") # set the lastUpdate variable to "now" self.lastUpdate = time.time() # # Public Method # Return the total consumption by the household # deduct charger load - if car(s) charging # def getConsumption(self): # update value if neccessary self.__update() # return the total household consumption total = self.HomeFromGrid + self.HomeFromPV logger.debug("Current Home consumption: {:.2f} W".format(total)) return float(self.HomeFromGrid + self.HomeFromPV) # # Public Method # Return the generated power by the inverter # def getGeneration(self): # update value if neccessary self.__update() # return the Solar generation power logger.debug("Current Solar generation: {:.2f} W".format( self.TotalDCPower)) return float(self.TotalDCPower)
SERVER_PORT = 502 c = ModbusClient() # uncomment this line to see debug message #c.debug(True) # define modbus server host, port c.host(SERVER_HOST) c.port(SERVER_PORT) toggle = True while True: # open or reconnect TCP to server if not c.is_open(): if not c.open(): print("unable to connect to "+SERVER_HOST+":"+str(SERVER_PORT)) # if open() is ok, write coils (modbus function 0x01) if c.is_open(): # write 4 bits in modbus address 0 to 3 print("") print("write bits") print("----------") print("") for addr in range(4): is_ok = c.write_single_coil(addr, toggle) if is_ok: print("bit #" + str(addr) + ": write to " + str(toggle)) else:
def get_points(conn, devices): for device in devices: try: cur = conn.cursor() #Get IP Address and port from database cur.execute("SELECT ip, port FROM device WHERE devID = ?", (device, )) request = cur.fetchone() ip = request[0] port = request[1] client = ModbusClient() client.host(ip) client.port(port) client_connected = True if (client.is_open() == False): if (client.open() == False): print("Unable to connect to " + ip + ":" + str(port)) client_connected = False if (client_connected == True): cur.execute( "SELECT name, address, type, pointID, mult_factor FROM device_points WHERE devID = ? AND deleted = 0", (device, )) rows = cur.fetchall() for row in rows: if (row[2] == "dig_in"): req = client.read_discrete_inputs(int(row[1]), 1) datetime_str = datetime.now().strftime( "%Y-%m-%d %H:%M:%S.%f") point_ID = row[3] value = req[0] * row[4] print(datetime_str + " | " + str(point_ID) + " | " + str(value)) cur.execute("INSERT INTO point_data VALUES (?, ?, ?)", (datetime_str, point_ID, value)) #print("Value for point " + row[0] + ": " + str(req) + datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) if (row[2] == "dig_out"): req = client.read_coils(int(row[1]), 1) datetime_str = datetime.now().strftime( "%Y-%m-%d %H:%M:%S.%f") point_ID = row[3] value = req[0] * row[4] error_code = 0 print(datetime_str + " | " + str(point_ID) + " | " + str(value)) cur.execute("INSERT INTO point_data VALUES (?, ?, ?)", (datetime_str, point_ID, value)) #print("Value for point " + row[0] + ": " + str(req) + datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) if (row[2] == "an_in"): req = client.read_input_registers(int(row[1]), 1) datetime_str = datetime.now().strftime( "%Y-%m-%d %H:%M:%S.%f") point_ID = row[3] value = req[0] * row[4] error_code = 0 print(datetime_str + " | " + str(point_ID) + " | " + str(value)) cur.execute("INSERT INTO point_data VALUES (?, ?, ?)", (datetime_str, point_ID, value)) #print("Value for point " + row[0] + ": " + str(req) + datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) if (row[2] == "an_out"): req = client.read_holding_registers(int(row[1]), 1) datetime_str = datetime.now().strftime( "%Y-%m-%d %H:%M:%S.%f") point_ID = row[3] value = req[0] * row[4] error_code = 0 print(datetime_str + " | " + str(point_ID) + " | " + str(value)) cur.execute("INSERT INTO point_data VALUES (?, ?, ?)", (datetime_str, point_ID, value)) #print("Value for point " + row[0] + ": " + str(req) + datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) print("\n") conn.commit() cur.close() client.close() except Error as e: print(e) conn.close() database = "./database/SCADADB.db" conn = create_connection(database)
class XW(): """This class implements functions specific to the Schneider ComBox """ def __init__(self): ''' Constructor for this class. ''' self._port = 0 def __del__(self): ''' Destructor for this class. ''' if self._port !=0: self.close() def open (self,SERVER_HOST = "192.168.0.210",SERVER_PORT = 502,SERVER_UNIT = 10): """Open modbus connection to the ComBox Args: SERVER_HOST: network address of the ComBox. Default='192.168.0.210' SERVER_PORT: modbus TCP port. Default='502' SERVER_UNIT: modbus address of the ComBox. Default='201' Returns: Boolean value True or False """ self._port = ModbusClient(SERVER_HOST, SERVER_PORT, SERVER_UNIT) if not self._port.is_open(): if not self._port.open(): print("unable to connect to " + SERVER_HOST + ":" + str(SERVER_PORT)) return self._port.is_open() def close(self): """Closes the modbusTCP connection Returns: Boolean value True or False """ self._port.close() return not self._port.is_open() def is_connected(self): """This function checks if the connection to the Schneider Conext XW+ is established and if it responds to readout commands. It requests the firmware version of the XW+ and checks for an received bitstream. Returns: Boolean value True or False return """ bitstream = self._port.read_holding_registers(0x001E, 7) # 0x001E Firmware Version str20 r if bitstream: return True else: return False def read_firmware(self): """This function reads the firmware version of the XW+ inverter and returns it as a string. Returns: string {firmware version} """ bitstream = self._port.read_holding_registers(0x001E, 7)# 0x001E Firmware Version str20 r decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = decoder.decode_string(14) return result def read_Grid_Voltage(self): """This function reads the Grid Voltage from the XW+ inverter and returns Volt. Returns: float {Grid Voltage in Volt} """ bitstream = self._port.read_holding_registers(0x0062, 2) # 0x0062 Grid Voltage uint32 r decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = (decoder.decode_32bit_uint()) / 1000.0 return result def read_Grid_Frequency(self): """This function reads the Grid Frequency from the XW+ inverter and returns it in Hz. Returns: float {Grid Frequency in Hz} """ bitstream = self._port.read_holding_registers(0x0061, 1) # 0x0061 Grid Frequency uint16 r decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = (decoder.decode_16bit_uint()) / 100.0 return result def read_Low_Battery_Cut_Out(self): """This function reads the Low_Battery_Cut_Out Voltage from the XW+ inverter and returns it in Volt. Returns: float {Low Battery Cut Out in Volt} """ bitstream = self._port.read_holding_registers(0x017C, 2) # 0x017C Low Battery Cut Out uint32 r/w decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = (decoder.decode_32bit_uint()) / 1000.0 return result def read_Low_Battery_Cut_Out_Delay(self): """This function reads the Low Battery Cut Out Delay from the XW+ inverter and returns it in Seconds. Returns: float {Low Battery Cut Out Delay in Seconds} """ bitstream = self._port.read_holding_registers(0x017E, 1) # 0x017E Low Battery Cut Out Delay uint16 r/w decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = (decoder.decode_16bit_uint()) / 100.0 return result def read_Inverter_Status(self): """This function reads the Inverter Status from the XW+ inverter and returns the status as a string. Returns: string {status} """ bitstream = self._port.read_holding_registers(0x007A, 1) # 0x007A Inverter Status uint16 r decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = (decoder.decode_16bit_uint()) if result == 1024: return str('Invert') elif result == 1025: return str('AC Pass Through') elif result == 1026: return str('APS Only') elif result == 1027: return str('Load Sense') elif result == 1028: return str('Inverter Disabled') elif result == 1029: return str('Load Sense Ready') elif result == 1030: return str('Engaging Inverter') elif result == 1031: return str('Invert Fault') elif result == 1032: return str('Inverter Standby') elif result == 1033: return str('Grid-Tied') elif result == 1034: return str('Grid Support') elif result == 1035: return str('Gen Support') elif result == 1036: return str('Sell-to-Grid') elif result == 1037: return str('Load Shaving') elif result == 1038: return str('Grid Frequency Stabilization') else: return str('UNKNOWN STATE!') def write_Low_Battery_Cut_Out_Delay(self, delay=0.1): """This function writes the Low Battery Cut Out Delay to the XW+ inverter and returns the value in the register. Returns: float {Low Battery Cut Out Delay in Seconds} """ delay = np.uint16(delay * 100) Upper_limit = np.uint16(100 * 190) #upper limit 60 Seconds Lower_limit = np.uint16(100 * 1)#Lower limit 1 Seconds if delay in range(Lower_limit, Upper_limit): self._port.write_single_register(0x017E, delay) else: print ('ERROR: delay value out of range!') bitstream = self._port.read_holding_registers(0x017E, 1) # 0x017E Low Battery Cut Out Delay uint16 r/w decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = (decoder.decode_16bit_uint()) / 100.0 return result def write_Low_Battery_Cut_Out(self, voltage=47): """This function writes the Low Battery Cut Out to the XW+ inverter and returns the value in the register. Returns: float {Low Battery Cut Out in Volt} """ voltage = np.uint32(voltage * 1000) Upper_limit = np.uint32(1000 * 49) #upper limit 60 Seconds Lower_limit = np.uint32(1000 * 46)#Lower limit 1 Seconds if voltage in range(Lower_limit, Upper_limit): self._port.write_multiple_registers(0x017C, [voltage, 00000]) else: print ('ERROR: delay value out of range!') bitstream = self._port.read_holding_registers(0x017C, 2) # 0x017C Low Battery Cut Out uint32 r/w decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = (decoder.decode_16bit_uint()) / 1000.0 return result def read_Load_Shave_Status(self): """This function reads the Load Shave status from the XW+ inverter and returns the state. Returns: str {Load Shave state} """ bitstream = self._port.read_holding_registers(0x01B2, 1) # 0x017E Low Battery Cut Out Delay uint16 r/w decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = (decoder.decode_16bit_uint()) if result == 0: return str('Disable') if result == 1: return str('Enable') def write_Load_Shave_Status(self, status): """This function writes the Load Shave to the XW+ inverter and returns the value in the register. Returns: str {Load Shave state} """ if status == 'enable' or status == 'Enable' or status == 'ENABLE': self._port.write_single_register(0x01B2, 1) elif status == 'disable' or status == 'Disable' or status == 'DISABLE': self._port.write_single_register(0x01B2, 0) else: print ('ERROR: Input Parameter must be: "enable" or "disable"') bitstream = self._port.read_holding_registers(0x01B2, 1) # 0x01B2 Load Shave uint16 r/w decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = (decoder.decode_16bit_uint()) if result == 0: return str('Disable') if result == 1: return str('Enable') def read_Hysteresis(self): """This function reads the Low_Battery_Cut_Out Hysteresis from the XW+ inverter and returns it in Volt. Returns: float {Low Battery Cut Out Hysteresis in Volt} """ bitstream = self._port.read_holding_registers(0x01F2, 2) # 0x017C Low Battery Cut Out Hysteresis uint32 r/w decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = (decoder.decode_32bit_uint()) / 1000.0 return result def write_Hysteresis(self, voltage=2.3): """This function writes the Low Battery Cut Out Hysteresis to the XW+ inverter and returns the value in the register. Returns: float {Low Battery Cut Out in Volt} """ voltage = np.uint32(voltage * 1000) Upper_limit = np.uint32(1000 * 5) #upper limit 5 Volt Lower_limit = np.uint32(1000 * 1)#Lower limit 1 Volt if voltage in range(Lower_limit, Upper_limit): self._port.write_multiple_registers(0x01F2, [voltage, 00000]) else: print ('ERROR: delay value out of range!') bitstream = self._port.read_holding_registers(0x01F2, 2) # 0x017C Low Battery Cut Out Hysteresis uint32 r/w decoder = BinaryPayloadDecoder.fromRegisters(bitstream) result = (decoder.decode_16bit_uint()) / 1000.0 return result
class HeatPump(): def __init__(self, ipOrHostName, portNumber, unitId, code): self.code = code self.registers = HeatPumpRegisters() self.mbClient = ModbusClient() self.mbClient.host(ipOrHostName) self.mbClient.port(portNumber) self.mbClient.unit_id(unitId) self.mbClient.open() self.outsideTemperature = HeatPumpConstants.NAN_VALUE self.currentRoomTemperature = HeatPumpConstants.NAN_VALUE self.currentExhaustFanSpeed = HeatPumpConstants.NAN_VALUE self.currentSupplyFanSpeed = HeatPumpConstants.NAN_VALUE self.airingLevelDay = HeatPumpConstants.NAN_VALUE self.airingLevelNight = HeatPumpConstants.NAN_VALUE self.powerConsumptionHeatingDay = HeatPumpConstants.NAN_VALUE self.powerConsumptionWarmWaterDay = HeatPumpConstants.NAN_VALUE return def setAiringLevelDay(self, airingLevel, code): return self._setAiringLevel(self.registers.AIRING_LEVEL_DAY.Address, airingLevel, code) def setAiringLevelNight(self, airingLevel, code): return self._setAiringLevel(self.registers.AIRING_LEVEL_NIGHT.Address, airingLevel, code) def _setAiringLevel(self, registerAddress, airingLevel, code): if int(code) != self.code: return (False, "Invalid security code") if not self.mbClient.is_open() and not self.mbClient.open(): return (False, "Unable to connect to {}:{}".format(self.mbClient.host(), self.mbClient.port())) if type(airingLevel) == str: try: airingLevel = int(airingLevel) except: raise TypeError("Could not convert {} to type 'int'".format(airingLevel)) retVal = self.mbClient.write_single_register(registerAddress, airingLevel) if not retVal: return (False, "Failed to set airing level") else: return (True, "Setting airing level successful") def readCurrentValues(self): if not self.mbClient.is_open() and not self.mbClient.open(): print ("Unable to connect to {}:{}".format(self.mbClient.host(), self.mbClient.port())) return False regVal_outsideTemperature = self.mbClient.read_input_registers(self.registers.OUTSIDE_TEMPERATURE.Address, self.registers.OUTSIDE_TEMPERATURE.SequenceSize) regVal_currentRoomTemperature = self.mbClient.read_input_registers(self.registers.CURRENT_ROOM_TEMPERATURE.Address, self.registers.CURRENT_ROOM_TEMPERATURE.SequenceSize) regVal_currentExhaustFanSpeed = self.mbClient.read_input_registers(self.registers.CURRENT_EXHAUST_FAN_SPEED.Address, self.registers.CURRENT_EXHAUST_FAN_SPEED.SequenceSize) regVal_currentSupplyFanSpeed = self.mbClient.read_input_registers(self.registers.CURRENT_SUPPLY_FAN_SPEED.Address, self.registers.CURRENT_SUPPLY_FAN_SPEED.SequenceSize) regVal_airingLevelDay = self.mbClient.read_holding_registers(self.registers.AIRING_LEVEL_DAY.Address, self.registers.AIRING_LEVEL_DAY.SequenceSize) regVal_airingLevelNight = self.mbClient.read_holding_registers(self.registers.AIRING_LEVEL_NIGHT.Address, self.registers.AIRING_LEVEL_NIGHT.SequenceSize) regVal_powerConsumptionHeatingDay = self.mbClient.read_input_registers(self.registers.POWER_CONSUMPTION_HEATING_DAY.Address, self.registers.POWER_CONSUMPTION_HEATING_DAY.SequenceSize) regVal_powerConsumptionWarmWaterDay = self.mbClient.read_input_registers(self.registers.POWER_CONSUMPTION_WARMWATER_DAY.Address, self.registers.POWER_CONSUMPTION_WARMWATER_DAY.SequenceSize) outsideTemperature = self.registers.shiftValue(regVal_outsideTemperature, self.registers.OUTSIDE_TEMPERATURE.SequenceSize) # outsideTemperature can be less than zero self.outsideTemperature = self.registers.convertSignedValue(outsideTemperature, HeatPumpConstants.MBREG_BITWIDTH) * 0.1 self.currentRoomTemperature = self.registers.shiftValue(regVal_currentRoomTemperature, self.registers.CURRENT_ROOM_TEMPERATURE.SequenceSize) * 0.1 self.currentExhaustFanSpeed = self.registers.shiftValue(regVal_currentExhaustFanSpeed, self.registers.CURRENT_EXHAUST_FAN_SPEED.SequenceSize) self.currentSupplyFanSpeed = self.registers.shiftValue(regVal_currentSupplyFanSpeed, self.registers.CURRENT_SUPPLY_FAN_SPEED.SequenceSize) self.airingLevelDay = self.registers.shiftValue(regVal_airingLevelDay, self.registers.AIRING_LEVEL_DAY.SequenceSize) self.airingLevelNight = self.registers.shiftValue(regVal_airingLevelNight, self.registers.AIRING_LEVEL_NIGHT.SequenceSize) self.powerConsumptionHeatingDay = self.registers.shiftValue(regVal_powerConsumptionHeatingDay, self.registers.POWER_CONSUMPTION_HEATING_DAY.SequenceSize) self.powerConsumptionWarmWaterDay = self.registers.shiftValue(regVal_powerConsumptionWarmWaterDay, self.registers.POWER_CONSUMPTION_WARMWATER_DAY.SequenceSize) return True
from pyModbusTCP.client import ModbusClient import time if __name__ == "__main__": host = input("\nPlease enter IP address [127.0.0.1]: ") port = input("Please enter port [502]: ") if not host: host = "172.16.143.146" if not port: port = 502 c = ModbusClient(timeout=5) c.host(host) c.port(port) print("\nTrying to connect to " + host + ":" + str(port)) if c.open(): print("Opened") print(c.is_open()) if c.close(): print("Closed") print(c.is_open())
def run_gui(): global x, y, x1, y1 # Declaring Modbus PLC print("The IP address of the PLC is:", sys.argv[1]) #Declaring the modbus client try: client = ModbusClient(host=sys.argv[1], port=502) except ValueError: print("Error with host or port number") # Declaring the colors required int he graphics. This is in RGB format BLACK = (0, 0, 0) GREY = (169, 169, 169) BLUE = (0, 0, 255) GREEN = (0, 255, 0) RED = (255, 0, 0) # Drawing the robotic arm in pygame. The one time initilization is performed to use the Pygame instance pygame.init() size = [600, 600] screen = pygame.display.set_mode(size) pygame.display.set_caption("Robotic Arm-Rishabh Das-UAH") message = pygame.font.SysFont("monospace", 15) header = pygame.font.SysFont("monospace", 30) run = True # This is the main loop that gets the current position of the robotic arm and updates the graphics after # every 100 ms while run: # ----------------------------------------------------------------------------------------- # MODBUS Section of the loop. The reading of the registers are collected fromt he PLC memory # ----------------------------------------------------------------------------------------- # check the connectivity of the TCP client to the GUI to the PLC if not client.is_open(): if not client.open(): print("Unable to Connect to " + sys.argv[1] + ":502") # Reading the registers for current lengths and the thetas theta_list = client.read_input_registers(2, reg_nb=2) length_list = client.read_holding_registers(4, reg_nb=2) # Print the list of the thetas # print(theta_list) # print(length_list) # Get the length of the arms from the MODBUS memory of the PLC to local variables length_1 = length_list[0] length_2 = length_list[1] if length_1 != 0 and length_2 != 0: ratio = (length_1 / length_2) else: print("Warning! \nArm length set to 0") if length_1 != 0: #Dulplicate arm length value length_2 = length_1 elif length_2 != 0: #Dulplicate arm length value length_1 = length_2 else: #Default Values of the Robotic arm length length_1 = 10 length_2 = 10 ratio = (length_1 / length_2) # sys.exit(0) length_2 = 250 / (ratio + 1) length_1 = 250 - length_2 if length_1 > 0 and length_2 > 0: # Get the current Theta positions of the arms from the MODBUS memory of the PLC to local variables Theta_1 = theta_list[0] Theta_2 = theta_list[0] + theta_list[1] # Calculate the coordinates calculate_coordinates(length_1, length_2, Theta_1, Theta_2) # ----------------------------------------------------------------------------------------- # This section of the loop creates the GUI of the robotic arm using the pygame library # ----------------------------------------------------------------------------------------- screen.fill(BLACK) # Drawing the robotic arm in pygame pygame.draw.line(screen, GREEN, [275, 275], [275 + x1, 275 - y1], 5) pygame.draw.line(screen, GREEN, [275 + x1, 275 - y1], [275 + x, 275 - y], 5) pygame.draw.circle(screen, BLUE, [275, 275], 7) pygame.draw.circle(screen, BLUE, [275 + round(x1), 275 - round(y1)], 7) pygame.draw.circle(screen, BLUE, [275 + round(x), 275 - round(y)], 7) # Calculate the coordinates calculate_coordinates(length_list[0], length_list[1], Theta_1, Theta_2) disp_coor1 = message.render( "(" + str(int(x1)) + "," + str(int(y1)) + ")", 1, GREEN) disp_coor2 = message.render( "(" + str(int(x)) + "," + str(int(y)) + ")", 1, GREEN) calculate_coordinates(length_1, length_2, Theta_1, Theta_2) screen.blit(disp_coor1, (275 + round(x1), 275 - round(y1))) screen.blit(disp_coor2, (275 + round(x), 275 - round(y))) #Displaying Heading title = header.render("Robotic Arm", 1, GREEN) screen.blit(title, (10, 1)) #Displaying Theta values theta1_values = message.render( "Theta first joint:" + str(theta_list[0]), 1, GREEN) theta2_values = message.render( "Theta second joint:" + str(theta_list[1]), 1, GREEN) screen.blit(theta1_values, (400, 550)) screen.blit(theta2_values, (400, 570)) # Checking if the user clicked on the close button for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() run = False sys.exit(0) pygame.display.update() #Controls the refresh rate of the robotic arm time.sleep(0.05) else: print("Invalid length! The GUI cannot be rendered!") sys.exit(0)
class AcuvimIITCPMODBUS: def __init__(self, server_host, port, unit_id): self.c = ModbusClient() self.c.host(server_host) self.c.port(port) self.c.unit_id(unit_id) self.map = self.__import_map() def __import_map(self): with open('map.json') as json_file: return json.load(json_file) def __read_16_bit(self, address): if not self.c.is_open(): self.c.open() return self.c.read_holding_registers(address, 1)[0] def __read_32_bit(self, address, number=1): if not self.c.is_open(): self.c.open() reg_l = self.c.read_holding_registers(address, number * 2) if reg_l: return [ utils.decode_ieee(f) for f in utils.word_list_to_long(reg_l) ][0] else: return None def __what_is_the_access_property(self, dict): if dict['Access Property'] == 'R': return 0 if dict['Access Property'] == 'W': return 2 else: return 1 def __get_registry(self, dict): if dict['Data Type'] == 'Word': return (self.__read_16_bit(dict["Address(D)"])) elif dict['Data Type'] == 'Float': return (self.__read_32_bit(dict["Address(D)"])) elif dict['Data Type'] == 'Dword': return (self.__read_32_bit(dict["Address(D)"])) elif dict['Data Type'] == 'int': return (self.__read_16_bit(dict["Address(D)"])) elif dict['Data Type'] == 'Bit': return (self.__read_16_bit(dict["Address(D)"])) def get_clock(self): if not self.c.is_open(): self.c.open() read_datetime = self.c.read_holding_registers(4159, 7) return datetime.datetime(read_datetime[1], read_datetime[2], read_datetime[3], read_datetime[4], read_datetime[5], read_datetime[6]) def read_value(self, parameter=None, address=None): if parameter is not None: temp_dict = list( filter(lambda d: d['Parameter'] == parameter, self.map)) if not len(temp_dict) == 0 and self.__what_is_the_access_property( temp_dict[0]) <= 1: return (self.__get_registry(temp_dict[0])) elif address is not None: temp_dict = list( filter(lambda d: d['Address(D)'] == address, self.map)) if not len(temp_dict) == 0 and self.__what_is_the_access_property( temp_dict) <= 1: return (self.__get_registry(temp_dict[0])) else: return None
# Register Addresses addr = [10, 11, 12, 13, 14, 15] # Unused Register Addresses toggle = [1, 2, 3, 4, 5, 6] # Register Values for writing ... hosts = [SERVER_HOST1, SERVER_HOST2] while True: # print("Enter Port Number ( 0 : MASTER-1 ---- 1 : MASTER2 )") HOST = int( input("Enter Port Number (MASTER-1 : 1 ***** MASTER-2 : 2 ) : ")) if (HOST == 1): print("MASTER - 1 ( IP : {0} ) is choosen.".format(SERVER_HOST1)) SERVER_HOST = SERVER_HOST1 c.host(SERVER_HOST) c.port(SERVER_PORT) if not c.is_open(): if not c.open(): print("unable to connect to " + SERVER_HOST + ":" + str(SERVER_PORT)) # if open() is ok, write coils (modbus function 0x01) if c.is_open(): # write 4 bits in modbus address 0 to 3 addr = 10 toggle = 22 is_ok = c.write_single_register(addr, toggle) if is_ok: print("Writint register to " + str(addr) + " : " + str(toggle)) else: print("Unable to write " + str(addr) + " : " + str(toggle))
class AsyncModbusClient(object): """Asyncio Modbus client.""" def __init__(self, *, queue=None, host='127.0.0.1', timeout=1): """ Set up client. ::host:: str - By default client runs on localhost. ::port:: int - Port 502 is constant for ModdbusTCP. """ self.queue = queue self.host = host self.port = 502 self.timeout = timeout self.client = ModbusClient(host=self.host, port=self.port) self.func_read_dict = { 'hr': self.client.read_holding_registers, 'c': self.client.read_coils, 'di': self.client.read_discrete_inputs, 'ir': self.client.read_input_registers, } self.func_write_dict = { 'hr': self.client.write_multiple_registers, 'c': self.client.write_multiple_coils, } self.registers_dict = {} self.reg_current_value = {} self.name_stack = [] def add_registers(self, reg_type, adr, num, name, write=False): """ Add register to the Modbus Client. ::reg_type:: str - values from 'hr', 'di', 'c' or 'ir', ::adr:: int - value starting from 0 to 65535, ::number:: int - from 1 to 2000 (AsyncModbusClient.max_number), ::name:: str - any unique name ::write:: int(0,1) - 0 for reading, 1 for writing. """ adr = mdb.validate_adr(adr) num = mdb.validate_num(num) write = mdb.validate_write(write) name = mdb.validate_name(self.name_stack, name) self.name_stack.append(name) if write: pass # Not implemented yet else: try: self.registers_dict.setdefault( self.func_read_dict[reg_type], [], ).append({ 'adr': adr, 'num': num, 'name': name, }) except Exception as err: raise ModbusClientError('Wrong modbus register type.', err) async def run_task(self): """Run asyncio client.""" executor = concurrent.futures.ThreadPoolExecutor( max_workers=1, # We can increase number # of workers if we increase queue line ) task = asyncio.create_task(self._awaitable(executor)) await task def _read_reg(self): self.read_regs = {} for func in self.registers_dict: for reg in self.registers_dict[func]: adr = reg['adr'] num = reg['num'] name = reg['name'] reg_func = func(adr, num) if name in self.read_regs: raise Exception( """Name {0} is not unique. Create unique name. """.format(name), ) self.read_regs[name] = reg_func return self.read_regs async def _awaitable(self, executor): loop = asyncio.get_event_loop() while True: if self.client.is_open(): self.reg_current_value = await loop.run_in_executor( executor, self._read_reg, ) else: self.reg_current_value = 'Lost connection with Modbus server' self.client.open() if self.queue is not None: await self.queue.put(self.reg_current_value) await asyncio.sleep(self.timeout)