def change_addr_LE_0xM(self, addr, new_addr): '''Function changes modbus address on LE-0xM meters :param addr (int): current address :param new_addr (int): new address :return (tuple): (1,) for success, (0,) for error ''' try: self.__stm.flush_rx_buffer() req = modbus.set_single_reg(addr, 7, new_addr) self.__stm.send_totx_buffer(req, 16) res = self.__stm.count_rx_buffer() count = int(res[1]) res = self.__stm.read_rx_buffer(count) if res[2] == req: return (1, ) else: return (0, ) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR change_addr_LE_0xM(): {}\r\n'.format(e))
def read(self): try: fh = open('config.ini', 'r') try: lines = fh.readlines() for l in lines: kv = l.strip().split('::') self.config[kv[0]] = kv[1] finally: fh.close() except IOError: if self.__usb_log: USB0.send('FATAL ERROR: Configuration file not found\r\n') fh = open('config.ini', 'w') try: lines = [] for k in self.__defConf.keys(): lines.append(k + '::' + self.__defConf[k] + '\n') fh.writelines(lines) finally: fh.close() fh = open('config.ini', 'r') try: lines = fh.readlines() for l in lines: kv = l.strip().split('::') self.config[kv[0]] = kv[1] finally: fh.close()
def __init__(self, stm32, usb_log=False): try: self.__usb_log = usb_log self.__stm = stm32 except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR __init__(): {}\r\n'.format(e))
def __sendRS485Send(self, len, val, crc=0, timeout=1): try: cmd = 'AT+RS485=SEND,{},{},{}\r'.format(len, val, crc) SER.send(cmd, 0) res = self.__SER_receive(timeout) return self.__parseRS485Send(res) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR: {}\r\n'.format(e))
def __sendRS485Flush(self, size=6000, timeout=1): try: cmd = 'AT+RS485=FLUSH,{}\r'.format(size) SER.send(cmd, 0) res = self.__SER_receive(timeout) return self.__parseRS485Flush(res) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR: {}\r\n'.format(e))
def __sendRS485Count(self, timeout=1): try: cmd = 'AT+RS485=COUNT\r' SER.send(cmd, 0) res = self.__SER_receive(timeout) return self.__parseRS485Count(res) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR: {}\r\n'.format(e))
def __SER_receive(self, timeout): try: res = '' start = time.time() while (time.time() - start < timeout): res = res + SER.read() return res except Exception as e: USB0.send('FATAL ERROR: stm32.__SER_receive(): {}\r\n'.format(e))
def set_led(self, color, state, intensity, timeout=1): try: cmd = 'AT+LED={},{},{}\r'.format(color, state, intensity) SER.send(cmd, 0) res = self.__SER_receive(timeout) if res.find('OK') != -1: return (1, ) else: return (0, ) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR: set_led(): {}\r\n'.format(e))
def write(self): try: fh = open('config.ini', 'w') try: lines = [] for k in self.config.keys(): lines.append(k + '::' + self.config[k] + '\n') fh.writelines(lines) finally: fh.close() except IOError: if self.__usb_log: USB0.send('FATAL ERROR: Configuration file not found\r\n')
def read_LE_0xM(self, addr, meterf): '''Function reads LE-0xM meter returning energy consumption in float kWh :param addr (int): meter address :return (tuple) (int): [0] -> (1,) for success, (0,) for error (tuple) (str): [1] -> ('',) hex response from the meter (tuple) (int): [2] -> (x,) decompiled address of the meter (tuple) (int): [3] -> (x,) decompiled modbus function (tuple) (int): [4] -> (x,) decompiled modbus bytes count (tuple) (int): [5] -> (x,) decompiled modbus register 0 value (tuple) (int): [6] -> (x,) decompiled modbus register 1 value (tuple) (int): [7] -> (x,) decompiled modbus register 2 value (tuple) (int): [8] -> (x,) decompiled modbus CRC-16 (tuple) (int): [9] -> (x.x,) decompiled energy consumption i kWh ''' try: self.__stm.flush_rx_buffer() req = modbus.read_hold_regs(addr, 0, 3) self.__stm.send_totx_buffer(req, 16) res = self.__stm.count_rx_buffer() count = int(res[1]) res = self.__stm.read_rx_buffer(count) if res[0] != -1 and len(res[2]) == 22: res1 = res[2] res_saddr = int(res1[0:2], 16) res_func = int(res1[2:4], 16) res_bytec = int(res1[4:6], 16) res_r0 = int(res1[6:10], 16) res_r1 = int(res1[10:14], 16) res_r2 = int(res1[14:18], 16) res_crc = int(res1[18:22], 16) return (1, res[2], res_saddr, res_func, res_bytec, \ res_r0, res_r1, res_r2, res_crc, self.__alg(res_r0, res_r1, res_r2, meterf)) else: return (0, ) if self.__usb_log: USB0.send('Read LE0xM: {}\r\n'.format(res)) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR read_LE_0xM(): {}\r\n'.format(e))
def reset_wdg(self, timeout=1): '''Function resets STM32 watchdog timer :return (tuple): ''' try: cmd = 'AT+WDG\r' SER.send(cmd, 0) res = self.__SER_receive(timeout) if res.find('OK') != -1: return (1, ) else: return (0, ) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR: reset_wdg(): {}\r\n'.format(e))
def set_wdg(self, interval, timeout=1): '''Function sets internal STM32 watchdog :param interval (int): value in seconds from 30 to 64800 (18 hours). Value -1 or 0 turns off the watchdog. :param res_timeout (float): resposne timeout :return (tuple): ''' try: cmd = 'AT+WDG=SET,{}\r'.format(interval) SER.send(cmd, 0) res = self.__SER_receive(timeout) if res.find('OK') != -1: return (1, ) else: return (0, ) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR: set_wdgt(): {}\r\n'.format(e))
def __parseRS485Flush(self, resp): try: if resp.find('OK') != -1: temp = resp.find(',') x = resp[temp + 1:] y = '' idx = 0 for ch in x: if ch != ',': y += ch idx += 1 else: break bytes_flushed = int(y) return (1, bytes_flushed) else: return (-1, ) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR: {}\r\n'.format(e))
def __parseRS485Read(self, resp): try: if resp.find('OK') != -1: temp = resp.find(',') x = resp[temp + 1:] y = '' idx = 0 for ch in x: if ch != ',': y += ch idx += 1 else: break bytes_len = int(y) x = resp[temp + 1 + idx + 1:] y = '' xc = 0 while xc < bytes_len: y += x[xc] xc += 1 bytes_val = y x = resp[temp + 1 + idx + 1 + xc + 1:] y = '' for ch in x: if ch != ',': y += ch else: break crc = y return (1, bytes_len, bytes_val, crc) else: return (-1, ) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR: {}\r\n'.format(e))
def test(self, tries=10): # test function try: USB0.send('FIF Library Test START\r\n') x = 0 while x < tries: res = self.read_LE_0xM(10) USB0.send('{}\r\n'.format(res)) time.sleep(2) #res = self.change_addr_LE_0xM(x, x+1) # testing from 1 to 10 with pushed SET button #USB0.send('{}\r\n'.format(res)) #time.sleep(2) x += 1 USB0.send('FIF Library Test STOP\r\n') except Exception as e: USB0.send('FATAL ERROR WHILE LOOP: {}\r\n'.format(e))
def send_totx_buffer(self, value, len, crc='0', res_timeout=0.5, max_tries=5, t_timeout=0.5, usb_log=True): '''Function returns number of bytes in RS485 RX buffer :param value (str): value to send in string format (bytes converted to string format) :param value (int): number of chars in value string :param crc (str): crc of value in string format (bytes converted to string format) :param res_timeout (float): response timeout :param max_tries (int): maxium tries number :param t_timeout (float): timeout between tries :param usb_log (boolean): log to USB interface :return (tuple): ''' res_c = 0 tries = 1 try: while (res_c < 1) and (tries <= max_tries): res = self.__sendRS485Send(len, value, crc, res_timeout) res_c = res[0] if res[0] != -1: if self.__usb_log: USB0.send('SEND OK: {} tries: {}\r\n'.format( res, tries)) return res + (tries, ) # -> tuple(1, message, tries) break else: time.sleep(t_timeout) tries += 1 continue else: if self.__usb_log: USB0.send( 'SEND ERROR: max {} tries were made\r\n'.format(tries)) return (-1, tries) # -> tuple(-1, tries) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR send_totx_buffer(): {}\r\n'.format(e))
def read_rx_buffer(self, size, res_timeout=0.5, max_tries=5, t_timeout=0.5, usb_log=True): '''Function reads number of bytes from RS485 RX buffer :param size (int): number of bytes to read :param res_timeout (float): response timeout :param max_tries (int): maxium tries number :param t_timeout (float): timeout between tries :param usb_log (boolean): log to USB interface :return (tuple): ''' res_c = 0 tries = 1 try: while (res_c < 1) and (tries <= max_tries): res = self.__sendRS485Read(size, res_timeout) res_c = res[0] if res[0] != -1: if self.__usb_log: USB0.send('READ OK: {} tries: {}\r\n'.format( res, tries)) return res + (tries, ) # -> tuple(1, message, tries) break else: time.sleep(t_timeout) tries += 1 continue else: if self.__usb_log: USB0.send( 'READ ERROR: max {} tries were made\r\n'.format(tries)) return (-1, tries) # -> tuple(-1, tries) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR read_rx_buffer(): {}\r\n'.format(e))
def flush_rx_buffer(self, f_size=6000, res_timeout=0.5, max_tries=5, t_timeout=0.5): '''Function flushes n bytes in RS485 RX buffer :param f_size (int): number of bytes to flush :param res_timeout (float): response timeout :param max_tries (int): maximum tries number :param t_timeout (float): timeout between tries :param usb_log (boolean): log to USB interface :return (tuple): ''' res_c = 0 tries = 1 try: while (res_c < 1) and (tries <= max_tries): res = self.__sendRS485Flush(f_size, res_timeout) res_c = res[0] if res[0] != -1: if self.__usb_log: USB0.send('FLUSH OK: {} tries: {}\r\n'.format( res, tries)) return res + (tries, ) # -> tuple(1, message, tries) break else: time.sleep(t_timeout) tries += 1 continue else: if self.__usb_log: USB0.send('FLUSH ERROR: max {} tries were made\r\n'.format( tries)) return (-1, tries) # -> tuple(-1, tries) except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR flush_rx_buffer(): {}\r\n'.format(e))
def write(self, s): USB0.send(s+'r')
import USB0 import SER import time import sys LOG_TO_USB0 = True try: import utils import stm32 import fif import config from logger import log except Exception as e: if LOG_TO_USB0: USB0.send('FATAL ERROR IMPORT: {}\r\n...ERROR'.format(e)) class USBWriter(): def write(self, s): USB0.send(s+'r') class LOGWriter(): def write(self, s): log(s+'r') sys.stdout = sys.stderr = USBWriter() log('Program Started') CONFIG = config.Config() CONFIG.read()
def test(self, tries=10): USB0.send('STM32 Library Test START\r\n') x = 0 while x < tries: res = self.flush_rx_buffer() USB0.send('{}\r\n'.format(res)) res = self.send_totx_buffer('01030000000305CB', 16) USB0.send('{}\r\n'.format(res)) res = self.count_rx_buffer() USB0.send('{}\r\n'.format(res)) count = int(res[1]) res = self.read_rx_buffer(count) USB0.send('{}\r\n'.format(res)) x += 1 time.sleep(2) USB0.send('STM32 Library Test STOP\r\n')
def modem_init(): try: global __STM __STM.set_wdg(CONF_WATCHDOG_TIMEOUT) __STM.set_led('RED','OFF',0) __STM.set_led('YELLOW','OFF',0) __STM.set_led('BLUE','OFF',0) __STM.set_led('GREEN','OFF',0) time.sleep(0.5) __STM.set_led_toggle('RED',1000,5,5) # add checking OK b sometimes LEDs are not set up except Exception as e: USB0.send('FATAL ERROR: __STM: {}\r\n'.format(e)) log('FATAL ERROR: __STM: {}\r\n'.format(e)) utils.CRLF() USB0.send('\r\n2017 (c) PySENSE RS485 SW VER: {}\r\n'.format(SW_VER)) try: s = utils.set_PORTCFG(4) if s[0]: USB0.send('Setting #PORTCFG...OK\r\n') else: USB0.send('Setting #PORTCFG...ERROR\r\n') except Exception as e: if LOG_TO_USB0: USB0.send('FATAL ERROR main.modem_init() -> set_PORTCFG(): {}...ERROR\r\n'.format(e)) log('FATAL ERROR main.modem_init() -> set_PORTCFG(): {}...ERROR\r\n'.format(e)) try: s = utils.set_STARTMODESCR(1,30) if s[0]: USB0.send('Setting #STARTMODESCR...OK\r\n') else: USB0.send('Setting #STARTMODESCR...ERROR\r\n') except Exception as e: if LOG_TO_USB0: USB0.send('FATAL ERROR main.modem_init() -> set_STARTMODESCR(): {}...ERROR\r\n'.format(e)) log('FATAL ERROR main.modem_init() -> set_STARTMODESCR(): {}...ERROR\r\n'.format(e)) try: s = utils.set_APN(CONF_APN) if s[0]: USB0.send('Setting APN:{}...OK\r\n'.format(CONF_APN)) else: USB0.send('Setting APN...ERROR\r\n') except Exception as e: if LOG_TO_USB0: USB0.send('FATAL ERROR main.MODEM_INIT() -> set_APN(): {}...ERROR\r\n'.format(e)) log('FATAL ERROR main.MODEM_INIT() -> set_APN(): {}...ERROR\r\n'.format(e)) try: s = utils.set_DWCFG(CONF_MQTT_ENDPOINT, CONF_MQTT_TOKEN) if s[0]: USB0.send('Setting DWCFG...OK\r\n') else: USB0.send('Setting DWCFG...ERROR\r\n') except Exception as e: if LOG_TO_USB0: USB0.send('FATAL ERROR main.MODEM_INIT() -> set_DWCFG(): {}...ERROR\r\n'.format(e)) log('FATAL ERROR main.MODEM_INIT() -> set_DWCFG(): {}...ERROR\r\n'.format(e)) try: s = utils.set_DWEN() if s[0]: USB0.send('Setting DWEN...OK\r\n') else: USB0.send('Setting DWEN...ERROR\r\n') except Exception as e: if LOG_TO_USB0: USB0.send('FATAL ERROR main.MODEM_INIT() -> set_DWEN(): {}...ERROR\r\n'.format(e)) log('FATAL ERROR main.MODEM_INIT() -> set_DWEN(): {}...ERROR\r\n'.format(e)) utils.mqtt_disconnect(log=True) __STM.set_led('RED','ON',100) USB0.send('\r\nAT++ INTERPRETER READY\r\n') log('modem_init() done ok')
import time import USB0 import SER import SER2 SER.set_speed('115200', '8N1') SER2.set_speed('115200', '8N1') i = 0 print('HOLA\n') while i < 3: time.sleep(1) a = USB0.send('TEST\r\n') print('HOLA\n') b = SER.send('PAULO\n') c = SER2.send('BENITO\n') i = i + 1 SER.send('END of script\n') SER2.send('END OF END\n')
import USB0 import time import stm32 try: import modbus except Exception as e: USB0.send('IMPORT ERROR: {}\r\n'.format(e)) class FIF(): def __init__(self, stm32, usb_log=False): try: self.__usb_log = usb_log self.__stm = stm32 except Exception as e: if self.__usb_log: USB0.send('FATAL ERROR __init__(): {}\r\n'.format(e)) def read_LE_0xM(self, addr, meterf): '''Function reads LE-0xM meter returning energy consumption in float kWh :param addr (int): meter address :return (tuple) (int): [0] -> (1,) for success, (0,) for error (tuple) (str): [1] -> ('',) hex response from the meter (tuple) (int): [2] -> (x,) decompiled address of the meter (tuple) (int): [3] -> (x,) decompiled modbus function
def main_loop(): in_ = '' loop_flag = True global __STM global __FIF global CONF_READ_TIMEOUT global CONF_METER_TO_READ global CONF_WATCHDOG_RESET global CONF_METERF start_read = time.time() start_wdg = time.time() try: while loop_flag: if time.time() - start_wdg > CONF_WATCHDOG_RESET: __STM.reset_wdg() start_wdg = time.time() elif time.time() - start_read > CONF_READ_TIMEOUT: #STM_GO = stm32.STM32() #FIF_GO = fif.FIF(STM_GO, usb_log=True) __STM.set_led_toggle('YELLOW',1000,1,1) utils.mqtt_connect(log=True) time.sleep(15) for m in CONF_METER_TO_READ: res = __FIF.read_LE_0xM(int(m), int(CONF_METERF[int(m)-1])) # CONF_METERF indicates phase number if res[0] != 0: utils.mqtt_send('le_0xm_{}'.format(m), res[9]) USB0.send('Meter with {} address read out correctly\r\n'.format(m)) else: USB0.send('Meter with {} address is not responding\r\n'.format(m)) time.sleep(15) time.sleep(30) utils.mqtt_disconnect(log=True) __STM.set_led('YELLOW','OFF',0) start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue elif (in_.find('AT++') == -1): in_ = in_ + USB0.read() else: if (in_.find('AT++') != -1): if (in_.find('AT++CONFIG?') != -1): # returns whole configuration CONFIG.dump() USB0.send('++CONFIG OK\r\n') in_ = '' start_read = time.time() continue if (in_.find('AT++METACH=') != -1): # command changes meter addr to new one x = in_.find('=') y = '' for ch in in_[x+1:]: if ch != ',': y += ch else: break addr = y x = in_.find(',') y = '' for ch in in_[x+1:]: if ch != '\r': y += ch else: break new_addr = y try: res = __FIF.change_addr_LE_0xM(int(addr), int(new_addr)) USB0.send('METER ADDR CHANGED: {}\r\n'.format(res)) except Exception as e: USB0.send('FATAL ERROR ++METACH: {}\r\n'.format(e)) USB0.send('++METACH OK\r\n') in_ = '' start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue if (in_.find('AT++METTR=') != -1): # command sets meters to read out x = in_.find('=') y = in_.find('\r') z = '' for ch in in_[x+1:y]: z += ch CONFIG.set('METER_TO_READ',z) CONFIG.write() CONF_METER_TO_READ = CONFIG.get('METER_TO_READ').split(',') USB0.send('METER_TO_READ -> {}\r\n'.format(CONF_METER_TO_READ)) USB0.send('++METTR OK\r\n') in_ = '' start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue if (in_.find('AT++METERF=') != -1): # command sets meters to read out x = in_.find('=') y = in_.find('\r') z = '' for ch in in_[x+1:y]: z += ch CONFIG.set('METERF',z) CONFIG.write() CONF_METERF = CONFIG.get('METERF').split(',') USB0.send('METERF -> {}\r\n'.format(CONF_METERF)) USB0.send('++METERF OK\r\n') in_ = '' start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue if (in_.find('AT++METTEST=') != -1): # command tests the meter read out x = in_.find('=') y = in_.find('\r') addr = int(in_[x+1:y]) res = __FIF.read_LE_0xM(int(addr), int(CONF_METERF[addr-1])) if res[0] != 0: USB0.send('Meter with {} address read out correctly\r\n'.format(res)) else: USB0.send('Meter with {} address is not responding\r\n'.format(res)) USB0.send('++METTEST OK\r\n') in_ = '' start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue if (in_.find('AT++READTM=') != -1): # command sets meters to read out x = in_.find('=') y = in_.find('\r') z = int(in_[x+1:y]) CONFIG.set('READ_TIMEOUT',str(z)) CONFIG.write() CONF_READ_TIMEOUT = int(CONFIG.get('READ_TIMEOUT')) USB0.send('READ_TIMEOUT -> {}\r\n'.format(CONF_READ_TIMEOUT)) USB0.send('++READTM OK\r\n') in_ = '' start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue if (in_.find('AT++STM?') != -1): USB0.send('++STM OK\r\n') in_ = '' start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue if (in_.find('AT++MQTT=CONNECT') != -1): utils.mqtt_connect(log=True) USB0.send('++STM OK\r\n') # TODO to change for ++MQTT OK in_ = '' start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue if (in_.find('AT++MQTT=DISCONNECT') != -1): utils.mqtt_disconnect(log=True) USB0.send('++STM OK\r\n') in_ = '' start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue if (in_.find('AT++DWCONN') != -1): res = utils.get_DWCONN() USB0.send('{}\r\n'.format(res[0])) USB0.send('++DWCONN OK\r\n') in_ = '' start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue if (in_.find('AT++STM=') != -1): cmd_idx = in_.find('=')+1 cmd = in_[cmd_idx:] SER.send(cmd, 1) res = utils.SER_receive(2) USB0.send('(++STM OK):' + res) in_ = '' start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue if (in_.find('AT++MODEM=') != -1): cmd_idx = in_.find('=')+1 cmd = in_[cmd_idx:] MDM.send(cmd, 1) res = utils.MDM_receive(2) USB0.send('(++MODEM OK):' + res) in_ = '' start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue if (in_.find('AT++QUIT') != -1): __STM.set_led('RED','OFF',0) USB0.send('++QUIT OK\r\n') in_ = '' loop_flag = False else: USB0.send('++OK\r\n') in_ = '' start_read = time.time() __STM.reset_wdg() start_wdg = time.time() continue else: USB0.send('MODBUS program has been closed...\r\n') except Exception as e: USB0.send('FATAL ERROR: main loop {}\r\n'.format(e)) log('FATAL ERROR: main loop {}\r\n'.format(e))
def dump(self): for k in self.config.keys(): USB0.send(('{}::{}\r\n'.format(k, self.config[k])))
res = hexlify(hexstr) + x if len(x) < 3: res = res + '00' return res.upper() else: return res.upper() else: res = hexlify(hexstr) + y if len(y) < 3: res = res + '00' return res.upper() else: return res.upper() if __name__ == '__main__': USB0.send('modbus Library Test START\r\n') i = 1 while i < 246: try: USB0.send('Read holding registers from addr: {} - {}\r\n'.format( i, read_hold_regs(i, 0, 3))) USB0.send('Set Register 6 for 186 at addr: {} - {}\r\n'.format( i, set_single_reg(i, 7, 186))) except Exception as e: USB0.send('FATAL ERROR: {}\r\n'.format(e)) i += 1 USB0.send('modbus Library Test STOP\r\n')